/** * Edit or add a user subscription. * * - Accessed from ?action=admin;area=paidsubscribe;sa=modifyuser */ public function action_modifyuser() { global $context, $txt, $modSettings; require_once SUBSDIR . '/PaidSubscriptions.subs.php'; loadSubscriptions(); $context['log_id'] = isset($_REQUEST['lid']) ? (int) $_REQUEST['lid'] : 0; $context['sub_id'] = isset($_REQUEST['sid']) ? (int) $_REQUEST['sid'] : 0; $context['action_type'] = $context['log_id'] ? 'edit' : 'add'; // Setup the template. $context['sub_template'] = 'modify_user_subscription'; $context['page_title'] = $txt[$context['action_type'] . '_subscriber']; loadJavascriptFile('suggest.js', array('defer' => true)); // If we haven't been passed the subscription ID get it. if ($context['log_id'] && !$context['sub_id']) { $context['sub_id'] = validateSubscriptionID($context['log_id']); } if (!isset($context['subscriptions'][$context['sub_id']])) { fatal_lang_error('no_access', false); } $context['current_subscription'] = $context['subscriptions'][$context['sub_id']]; // Searching? if (isset($_POST['ssearch'])) { return $this->action_viewsub(); } elseif (isset($_REQUEST['save_sub'])) { checkSession(); // Work out the dates... $starttime = mktime($_POST['hour'], $_POST['minute'], 0, $_POST['month'], $_POST['day'], $_POST['year']); $endtime = mktime($_POST['hourend'], $_POST['minuteend'], 0, $_POST['monthend'], $_POST['dayend'], $_POST['yearend']); // Status. $status = $_POST['status']; // New one? if (empty($context['log_id'])) { // Find the user... require_once SUBSDIR . '/Members.subs.php'; $member = getMemberByName($_POST['name']); if (empty($member)) { fatal_lang_error('error_member_not_found'); } if (alreadySubscribed($context['sub_id'], $member['id_member'])) { fatal_lang_error('member_already_subscribed'); } // Actually put the subscription in place. if ($status == 1) { addSubscription($context['sub_id'], $member['id_member'], 0, $starttime, $endtime); } else { $details = array('id_subscribe' => $context['sub_id'], 'id_member' => $member['id_member'], 'id_group' => $member['id_group'], 'start_time' => $starttime, 'end_time' => $endtime, 'status' => $status); logSubscription($details); } } else { $subscription_status = getSubscriptionStatus($context['log_id']); // Pick the right permission stuff depending on what the status is changing from/to. if ($subscription_status['old_status'] == 1 && $status != 1) { removeSubscription($context['sub_id'], $subscription_status['id_member']); } elseif ($status == 1 && $subscription_status['old_status'] != 1) { addSubscription($context['sub_id'], $subscription_status['id_member'], 0, $starttime, $endtime); } else { $item = array('start_time' => $starttime, 'end_time' => $endtime, 'status' => $status, 'current_log_item' => $context['log_id']); updateSubscriptionItem($item); } } // Done - redirect... redirectexit('action=admin;area=paidsubscribe;sa=viewsub;sid=' . $context['sub_id']); } elseif (isset($_REQUEST['delete']) || isset($_REQUEST['finished'])) { checkSession(); // Do the actual deletes! if (!empty($_REQUEST['delsub'])) { $toDelete = array(); foreach ($_REQUEST['delsub'] as $id => $dummy) { $toDelete[] = (int) $id; } $deletes = prepareDeleteSubscriptions($toDelete); foreach ($deletes as $id_subscribe => $id_member) { removeSubscription($id_subscribe, $id_member, isset($_REQUEST['delete'])); } } redirectexit('action=admin;area=paidsubscribe;sa=viewsub;sid=' . $context['sub_id']); } // Default attributes. if ($context['action_type'] == 'add') { $context['sub'] = array('id' => 0, 'start' => array('year' => (int) strftime('%Y', time()), 'month' => (int) strftime('%m', time()), 'day' => (int) strftime('%d', time()), 'hour' => (int) strftime('%H', time()), 'min' => (int) strftime('%M', time()) < 10 ? '0' . (int) strftime('%M', time()) : (int) strftime('%M', time()), 'last_day' => 0), 'end' => array('year' => (int) strftime('%Y', time()), 'month' => (int) strftime('%m', time()), 'day' => (int) strftime('%d', time()), 'hour' => (int) strftime('%H', time()), 'min' => (int) strftime('%M', time()) < 10 ? '0' . (int) strftime('%M', time()) : (int) strftime('%M', time()), 'last_day' => 0), 'status' => 1); $context['sub']['start']['last_day'] = (int) strftime('%d', mktime(0, 0, 0, $context['sub']['start']['month'] == 12 ? 1 : $context['sub']['start']['month'] + 1, 0, $context['sub']['start']['month'] == 12 ? $context['sub']['start']['year'] + 1 : $context['sub']['start']['year'])); $context['sub']['end']['last_day'] = (int) strftime('%d', mktime(0, 0, 0, $context['sub']['end']['month'] == 12 ? 1 : $context['sub']['end']['month'] + 1, 0, $context['sub']['end']['month'] == 12 ? $context['sub']['end']['year'] + 1 : $context['sub']['end']['year'])); if (isset($_GET['uid'])) { require_once SUBSDIR . '/Members.subs.php'; // Get the latest activated member's display name. $result = getBasicMemberData((int) $_GET['uid']); $context['sub']['username'] = $result['real_name']; } else { $context['sub']['username'] = ''; } } else { $row = getPendingSubscriptions($context['log_id']); if (empty($row)) { fatal_lang_error('no_access', false); } // Any pending payments? $context['pending_payments'] = array(); if (!empty($row['pending_details'])) { $pending_details = @unserialize($row['pending_details']); foreach ($pending_details as $id => $pending) { // Only this type need be displayed. if ($pending[3] == 'payback') { // Work out what the options were. $costs = @unserialize($context['current_subscription']['real_cost']); if ($context['current_subscription']['real_length'] == 'F') { foreach ($costs as $duration => $cost) { if ($cost != 0 && $cost == $pending[1] && $duration == $pending[2]) { $context['pending_payments'][$id] = array('desc' => sprintf($modSettings['paid_currency_symbol'], $cost . '/' . $txt[$duration])); } } } elseif ($costs['fixed'] == $pending[1]) { $context['pending_payments'][$id] = array('desc' => sprintf($modSettings['paid_currency_symbol'], $costs['fixed'])); } } } // Check if we are adding/removing any. if (isset($_GET['pending'])) { foreach ($pending_details as $id => $pending) { // Found the one to action? if ($_GET['pending'] == $id && $pending[3] == 'payback' && isset($context['pending_payments'][$id])) { // Flexible? if (isset($_GET['accept'])) { addSubscription($context['current_subscription']['id'], $row['id_member'], $context['current_subscription']['real_length'] == 'F' ? strtoupper(substr($pending[2], 0, 1)) : 0); } unset($pending_details[$id]); $new_details = serialize($pending_details); // Update the entry. updatePendingSubscription($context['log_id'], $new_details); // Reload redirectexit('action=admin;area=paidsubscribe;sa=modifyuser;lid=' . $context['log_id']); } } } } $context['sub_id'] = $row['id_subscribe']; $context['sub'] = array('id' => 0, 'start' => array('year' => (int) strftime('%Y', $row['start_time']), 'month' => (int) strftime('%m', $row['start_time']), 'day' => (int) strftime('%d', $row['start_time']), 'hour' => (int) strftime('%H', $row['start_time']), 'min' => (int) strftime('%M', $row['start_time']) < 10 ? '0' . (int) strftime('%M', $row['start_time']) : (int) strftime('%M', $row['start_time']), 'last_day' => 0), 'end' => array('year' => (int) strftime('%Y', $row['end_time']), 'month' => (int) strftime('%m', $row['end_time']), 'day' => (int) strftime('%d', $row['end_time']), 'hour' => (int) strftime('%H', $row['end_time']), 'min' => (int) strftime('%M', $row['end_time']) < 10 ? '0' . (int) strftime('%M', $row['end_time']) : (int) strftime('%M', $row['end_time']), 'last_day' => 0), 'status' => $row['status'], 'username' => $row['username']); $context['sub']['start']['last_day'] = (int) strftime('%d', mktime(0, 0, 0, $context['sub']['start']['month'] == 12 ? 1 : $context['sub']['start']['month'] + 1, 0, $context['sub']['start']['month'] == 12 ? $context['sub']['start']['year'] + 1 : $context['sub']['start']['year'])); $context['sub']['end']['last_day'] = (int) strftime('%d', mktime(0, 0, 0, $context['sub']['end']['month'] == 12 ? 1 : $context['sub']['end']['month'] + 1, 0, $context['sub']['end']['month'] == 12 ? $context['sub']['end']['year'] + 1 : $context['sub']['end']['year'])); } }
/** * Removes a subscription from a user, as in removes the groups. * * @param int $id_subscribe * @param int $id_member * @param boolean $delete */ function removeSubscription($id_subscribe, $id_member, $delete = false) { global $context; $db = database(); loadSubscriptions(); // Load the user core bits. require_once SUBSDIR . '/Members.subs.php'; $member_info = getBasicMemberData($id_member, array('moderation' => true)); // Just in case of errors. if (empty($member_info)) { $db->query('', ' DELETE FROM {db_prefix}log_subscribed WHERE id_member = {int:current_member}', array('current_member' => $id_member)); return; } // Get all of the subscriptions for this user that are active - it will be necessary! $request = $db->query('', ' SELECT id_subscribe, old_id_group FROM {db_prefix}log_subscribed WHERE id_member = {int:current_member} AND status = {int:is_active}', array('current_member' => $id_member, 'is_active' => 1)); // These variables will be handy, honest ;) $removals = array(); $allowed = array(); $member = array(); $member['id_group'] = 0; $new_id_group = -1; while ($row = $db->fetch_assoc($request)) { if (!isset($context['subscriptions'][$row['id_subscribe']])) { continue; } // The one we're removing? if ($row['id_subscribe'] == $id_subscribe) { $removals = explode(',', $context['subscriptions'][$row['id_subscribe']]['add_groups']); if ($context['subscriptions'][$row['id_subscribe']]['prim_group'] != 0) { $removals[] = $context['subscriptions'][$row['id_subscribe']]['prim_group']; } $member['id_group'] = $row['old_id_group']; } else { $allowed = array_merge($allowed, explode(',', $context['subscriptions'][$row['id_subscribe']]['add_groups'])); if ($context['subscriptions'][$row['id_subscribe']]['prim_group'] != 0) { $allowed[] = $context['subscriptions'][$row['id_subscribe']]['prim_group']; $new_id_group = $context['subscriptions'][$row['id_subscribe']]['prim_group']; } } } $db->free_result($request); // Now, for everything we are removing check they defintely are not allowed it. $existingGroups = explode(',', $member_info['additional_groups']); foreach ($existingGroups as $key => $group) { if (empty($group) || in_array($group, $removals) && !in_array($group, $allowed)) { unset($existingGroups[$key]); } } // Finally, do something with the current primary group. if (in_array($member_info['id_group'], $removals)) { // If this primary group is actually allowed keep it. if (in_array($member_info['id_group'], $allowed)) { $existingGroups[] = $member_info['id_group']; } // Either way, change the id_group back. if ($new_id_group < 1) { // If we revert to the old id-group we need to ensure it wasn't from a subscription. foreach ($context['subscriptions'] as $id => $group) { // It was? Make them a regular member then! if ($group['prim_group'] == $member['id_group']) { $member['id_group'] = 0; } } $member_info['id_group'] = $member['id_group']; } else { $member_info['id_group'] = $new_id_group; } } // Crazy stuff, we seem to have our groups fixed, just make them unique $existingGroups = array_unique($existingGroups); // Update the member assignGroupsToMember($id_member, $member_info['id_group'], $existingGroups); // Disable the subscription. if (!$delete) { $db->query('', ' UPDATE {db_prefix}log_subscribed SET status = {int:not_active} WHERE id_member = {int:current_member} AND id_subscribe = {int:current_subscription}', array('not_active' => 0, 'current_member' => $id_member, 'current_subscription' => $id_subscribe)); } else { $db->query('', ' DELETE FROM {db_prefix}log_subscribed WHERE id_member = {int:current_member} AND id_subscribe = {int:current_subscription}', array('current_member' => $id_member, 'current_subscription' => $id_subscribe)); } }
/** * Return the details of the members using a certain range of IPs * except the current one * * @param string[] $ips a list of IP addresses * @param int $memID the id of the "current" member (maybe it could be retrieved with currentMemberID) */ function getMembersInRange($ips, $memID) { $db = database(); $message_members = array(); $members_in_range = array(); // Get member ID's which are in messages... $request = $db->query('', ' SELECT mem.id_member FROM {db_prefix}messages AS m INNER JOIN {db_prefix}members AS mem ON (mem.id_member = m.id_member) WHERE m.poster_ip IN ({array_string:ip_list}) GROUP BY mem.id_member HAVING mem.id_member != {int:current_member}', array('current_member' => $memID, 'ip_list' => $ips)); while ($row = $db->fetch_assoc($request)) { $message_members[] = $row['id_member']; } $db->free_result($request); // And then get the member ID's belong to other users $request = $db->query('', ' SELECT id_member FROM {db_prefix}members WHERE id_member != {int:current_member} AND member_ip IN ({array_string:ip_list})', array('current_member' => $memID, 'ip_list' => $ips)); while ($row = $db->fetch_assoc($request)) { $message_members[] = $row['id_member']; } $db->free_result($request); // Once the IDs are all combined, let's clean them up $message_members = array_unique($message_members); // And finally, fetch their names, cause of the GROUP BY doesn't like giving us that normally. if (!empty($message_members)) { require_once SUBSDIR . '/Members.subs.php'; // Get the latest activated member's display name. $members_in_range = getBasicMemberData($message_members); } return $members_in_range; }
/** * Create a post, either as new topic (id_topic = 0) or in an existing one. * * The input parameters of this function assume: * - Strings have been escaped. * - Integers have been cast to integer. * - Mandatory parameters are set. * * @package Posts * @param mixed[] $msgOptions * @param mixed[] $topicOptions * @param mixed[] $posterOptions */ function createPost(&$msgOptions, &$topicOptions, &$posterOptions) { global $user_info, $txt, $modSettings; $db = database(); // Set optional parameters to the default value. $msgOptions['icon'] = empty($msgOptions['icon']) ? 'xx' : $msgOptions['icon']; $msgOptions['smileys_enabled'] = !empty($msgOptions['smileys_enabled']); $msgOptions['attachments'] = empty($msgOptions['attachments']) ? array() : $msgOptions['attachments']; $msgOptions['approved'] = isset($msgOptions['approved']) ? (int) $msgOptions['approved'] : 1; $topicOptions['id'] = empty($topicOptions['id']) ? 0 : (int) $topicOptions['id']; $topicOptions['poll'] = isset($topicOptions['poll']) ? (int) $topicOptions['poll'] : null; $topicOptions['lock_mode'] = isset($topicOptions['lock_mode']) ? $topicOptions['lock_mode'] : null; $topicOptions['sticky_mode'] = isset($topicOptions['sticky_mode']) ? $topicOptions['sticky_mode'] : null; $topicOptions['redirect_expires'] = isset($topicOptions['redirect_expires']) ? $topicOptions['redirect_expires'] : null; $topicOptions['redirect_topic'] = isset($topicOptions['redirect_topic']) ? $topicOptions['redirect_topic'] : null; $posterOptions['id'] = empty($posterOptions['id']) ? 0 : (int) $posterOptions['id']; $posterOptions['ip'] = empty($posterOptions['ip']) ? $user_info['ip'] : $posterOptions['ip']; // We need to know if the topic is approved. If we're told that's great - if not find out. if (!$modSettings['postmod_active']) { $topicOptions['is_approved'] = true; } elseif (!empty($topicOptions['id']) && !isset($topicOptions['is_approved'])) { $request = $db->query('', ' SELECT approved FROM {db_prefix}topics WHERE id_topic = {int:id_topic} LIMIT 1', array('id_topic' => $topicOptions['id'])); list($topicOptions['is_approved']) = $db->fetch_row($request); $db->free_result($request); } // If nothing was filled in as name/email address, try the member table. if (!isset($posterOptions['name']) || $posterOptions['name'] == '' || empty($posterOptions['email']) && !empty($posterOptions['id'])) { if (empty($posterOptions['id'])) { $posterOptions['id'] = 0; $posterOptions['name'] = $txt['guest_title']; $posterOptions['email'] = ''; } elseif ($posterOptions['id'] != $user_info['id']) { require_once SUBSDIR . '/Members.subs.php'; $result = getBasicMemberData($posterOptions['id']); // Couldn't find the current poster? if (empty($result)) { trigger_error('createPost(): Invalid member id ' . $posterOptions['id'], E_USER_NOTICE); $posterOptions['id'] = 0; $posterOptions['name'] = $txt['guest_title']; $posterOptions['email'] = ''; } else { $posterOptions['name'] = $result['member_name']; $posterOptions['email'] = $result['email_address']; } } else { $posterOptions['name'] = $user_info['name']; $posterOptions['email'] = $user_info['email']; } } // It's do or die time: forget any user aborts! $previous_ignore_user_abort = ignore_user_abort(true); $new_topic = empty($topicOptions['id']); $message_columns = array('id_board' => 'int', 'id_topic' => 'int', 'id_member' => 'int', 'subject' => 'string-255', 'body' => !empty($modSettings['max_messageLength']) && $modSettings['max_messageLength'] > 65534 ? 'string-' . $modSettings['max_messageLength'] : (empty($modSettings['max_messageLength']) ? 'string' : 'string-65534'), 'poster_name' => 'string-255', 'poster_email' => 'string-255', 'poster_time' => 'int', 'poster_ip' => 'string-255', 'smileys_enabled' => 'int', 'modified_name' => 'string', 'icon' => 'string-16', 'approved' => 'int'); $message_parameters = array('id_board' => $topicOptions['board'], 'id_topic' => $topicOptions['id'], 'id_member' => $posterOptions['id'], 'subject' => $msgOptions['subject'], 'body' => $msgOptions['body'], 'poster_name' => $posterOptions['name'], 'poster_email' => $posterOptions['email'], 'poster_time' => empty($posterOptions['time']) ? time() : $posterOptions['time'], 'poster_ip' => $posterOptions['ip'], 'smileys_enabled' => $msgOptions['smileys_enabled'] ? 1 : 0, 'modified_name' => '', 'icon' => $msgOptions['icon'], 'approved' => $msgOptions['approved']); // What if we want to do anything with posts? call_integration_hook('integrate_before_create_post', array(&$msgOptions, &$topicOptions, &$posterOptions, &$message_columns, &$message_parameters)); // Insert the post. $db->insert('', '{db_prefix}messages', $message_columns, $message_parameters, array('id_msg')); $msgOptions['id'] = $db->insert_id('{db_prefix}messages', 'id_msg'); // Something went wrong creating the message... if (empty($msgOptions['id'])) { return false; } // Fix the attachments. if (!empty($msgOptions['attachments'])) { $db->query('', ' UPDATE {db_prefix}attachments SET id_msg = {int:id_msg} WHERE id_attach IN ({array_int:attachment_list})', array('attachment_list' => $msgOptions['attachments'], 'id_msg' => $msgOptions['id'])); } // What if we want to export new posts out to a CMS? call_integration_hook('integrate_create_post', array($msgOptions, $topicOptions, $posterOptions, $message_columns, $message_parameters)); // Insert a new topic (if the topicID was left empty.) if ($new_topic) { $topic_columns = array('id_board' => 'int', 'id_member_started' => 'int', 'id_member_updated' => 'int', 'id_first_msg' => 'int', 'id_last_msg' => 'int', 'locked' => 'int', 'is_sticky' => 'int', 'num_views' => 'int', 'id_poll' => 'int', 'unapproved_posts' => 'int', 'approved' => 'int', 'redirect_expires' => 'int', 'id_redirect_topic' => 'int'); $topic_parameters = array('id_board' => $topicOptions['board'], 'id_member_started' => $posterOptions['id'], 'id_member_updated' => $posterOptions['id'], 'id_first_msg' => $msgOptions['id'], 'id_last_msg' => $msgOptions['id'], 'locked' => $topicOptions['lock_mode'] === null ? 0 : $topicOptions['lock_mode'], 'is_sticky' => $topicOptions['sticky_mode'] === null ? 0 : $topicOptions['sticky_mode'], 'num_views' => 0, 'id_poll' => $topicOptions['poll'] === null ? 0 : $topicOptions['poll'], 'unapproved_posts' => $msgOptions['approved'] ? 0 : 1, 'approved' => $msgOptions['approved'], 'redirect_expires' => $topicOptions['redirect_expires'] === null ? 0 : $topicOptions['redirect_expires'], 'id_redirect_topic' => $topicOptions['redirect_topic'] === null ? 0 : $topicOptions['redirect_topic']); call_integration_hook('integrate_before_create_topic', array(&$msgOptions, &$topicOptions, &$posterOptions, &$topic_columns, &$topic_parameters)); $db->insert('', '{db_prefix}topics', $topic_columns, $topic_parameters, array('id_topic')); $topicOptions['id'] = $db->insert_id('{db_prefix}topics', 'id_topic'); // The topic couldn't be created for some reason. if (empty($topicOptions['id'])) { // We should delete the post that did work, though... $db->query('', ' DELETE FROM {db_prefix}messages WHERE id_msg = {int:id_msg}', array('id_msg' => $msgOptions['id'])); return false; } // Fix the message with the topic. $db->query('', ' UPDATE {db_prefix}messages SET id_topic = {int:id_topic} WHERE id_msg = {int:id_msg}', array('id_topic' => $topicOptions['id'], 'id_msg' => $msgOptions['id'])); // There's been a new topic AND a new post today. trackStats(array('topics' => '+', 'posts' => '+')); updateStats('topic', true); updateStats('subject', $topicOptions['id'], $msgOptions['subject']); // What if we want to export new topics out to a CMS? call_integration_hook('integrate_create_topic', array($msgOptions, $topicOptions, $posterOptions)); } else { $update_parameters = array('poster_id' => $posterOptions['id'], 'id_msg' => $msgOptions['id'], 'locked' => $topicOptions['lock_mode'], 'is_sticky' => $topicOptions['sticky_mode'], 'id_topic' => $topicOptions['id'], 'counter_increment' => 1); if ($msgOptions['approved']) { $topics_columns = array('id_member_updated = {int:poster_id}', 'id_last_msg = {int:id_msg}', 'num_replies = num_replies + {int:counter_increment}'); } else { $topics_columns = array('unapproved_posts = unapproved_posts + {int:counter_increment}'); } if ($topicOptions['lock_mode'] !== null) { $topics_columns[] = 'locked = {int:locked}'; } if ($topicOptions['sticky_mode'] !== null) { $topics_columns[] = 'is_sticky = {int:is_sticky}'; } call_integration_hook('integrate_before_modify_topic', array(&$topics_columns, &$update_parameters, &$msgOptions, &$topicOptions, &$posterOptions)); // Update the number of replies and the lock/sticky status. $db->query('', ' UPDATE {db_prefix}topics SET ' . implode(', ', $topics_columns) . ' WHERE id_topic = {int:id_topic}', $update_parameters); // One new post has been added today. trackStats(array('posts' => '+')); } // Creating is modifying...in a way. // @todo id_msg_modified needs to be set when you create a post, now this query is // the only place it does get set for post creation. Why not set it on the insert? $db->query('', ' UPDATE {db_prefix}messages SET id_msg_modified = {int:id_msg} WHERE id_msg = {int:id_msg}', array('id_msg' => $msgOptions['id'])); // Increase the number of posts and topics on the board. if ($msgOptions['approved']) { $db->query('', ' UPDATE {db_prefix}boards SET num_posts = num_posts + 1' . ($new_topic ? ', num_topics = num_topics + 1' : '') . ' WHERE id_board = {int:id_board}', array('id_board' => $topicOptions['board'])); } else { $db->query('', ' UPDATE {db_prefix}boards SET unapproved_posts = unapproved_posts + 1' . ($new_topic ? ', unapproved_topics = unapproved_topics + 1' : '') . ' WHERE id_board = {int:id_board}', array('id_board' => $topicOptions['board'])); // Add to the approval queue too. $db->insert('', '{db_prefix}approval_queue', array('id_msg' => 'int'), array($msgOptions['id']), array()); } // Mark inserted topic as read (only for the user calling this function). if (!empty($topicOptions['mark_as_read']) && !$user_info['is_guest']) { // Since it's likely they *read* it before replying, let's try an UPDATE first. if (!$new_topic) { $db->query('', ' UPDATE {db_prefix}log_topics SET id_msg = {int:id_msg} WHERE id_member = {int:current_member} AND id_topic = {int:id_topic}', array('current_member' => $posterOptions['id'], 'id_msg' => $msgOptions['id'], 'id_topic' => $topicOptions['id'])); $flag = $db->affected_rows() != 0; } if (empty($flag)) { require_once SUBSDIR . '/Topic.subs.php'; markTopicsRead(array($posterOptions['id'], $topicOptions['id'], $msgOptions['id'], 0), false); } } // If there's a custom search index, it may need updating... require_once SUBSDIR . '/Search.subs.php'; $searchAPI = findSearchAPI(); if (is_callable(array($searchAPI, 'postCreated'))) { $searchAPI->postCreated($msgOptions, $topicOptions, $posterOptions); } // Increase the post counter for the user that created the post. if (!empty($posterOptions['update_post_count']) && !empty($posterOptions['id']) && $msgOptions['approved']) { // Are you the one that happened to create this post? if ($user_info['id'] == $posterOptions['id']) { $user_info['posts']++; } updateMemberData($posterOptions['id'], array('posts' => '+')); } // They've posted, so they can make the view count go up one if they really want. (this is to keep views >= replies...) $_SESSION['last_read_topic'] = 0; // Better safe than sorry. if (isset($_SESSION['topicseen_cache'][$topicOptions['board']])) { $_SESSION['topicseen_cache'][$topicOptions['board']]--; } // Update all the stats so everyone knows about this new topic and message. updateStats('message', true, $msgOptions['id']); // Update the last message on the board assuming it's approved AND the topic is. if ($msgOptions['approved']) { updateLastMessages($topicOptions['board'], $new_topic || !empty($topicOptions['is_approved']) ? $msgOptions['id'] : 0); } // Alright, done now... we can abort now, I guess... at least this much is done. ignore_user_abort($previous_ignore_user_abort); // Success. return true; }
/** * This function actually makes all the group changes * * @return string */ public function action_groupMembership2() { global $context, $user_profile, $modSettings, $scripturl, $language; $db = database(); $memID = currentMemberID(); // Let's be extra cautious... if (!$context['user']['is_owner'] || empty($modSettings['show_group_membership'])) { isAllowedTo('manage_membergroups'); } if (!isset($_REQUEST['gid']) && !isset($_POST['primary'])) { fatal_lang_error('no_access', false); } checkSession(isset($_GET['gid']) ? 'get' : 'post'); require_once SUBSDIR . '/Membergroups.subs.php'; $old_profile =& $user_profile[$memID]; $context['can_manage_membergroups'] = allowedTo('manage_membergroups'); $context['can_manage_protected'] = allowedTo('admin_forum'); // By default the new primary is the old one. $newPrimary = $old_profile['id_group']; $addGroups = array_flip(explode(',', $old_profile['additional_groups'])); $canChangePrimary = $old_profile['id_group'] == 0 ? 1 : 0; $changeType = isset($_POST['primary']) ? 'primary' : (isset($_POST['req']) ? 'request' : 'free'); // One way or another, we have a target group in mind... $group_id = isset($_REQUEST['gid']) ? (int) $_REQUEST['gid'] : (int) $_POST['primary']; $foundTarget = $changeType == 'primary' && $group_id == 0 ? true : false; // Sanity check!! if ($group_id == 1) { isAllowedTo('admin_forum'); } // What ever we are doing, we need to determine if changing primary is possible! $groups_details = membergroupsById(array($group_id, $old_profile['id_group']), 0, true); // Protected groups require proper permissions! if ($group_id != 1 && $groups_details[$group_id]['group_type'] == 1) { isAllowedTo('admin_forum'); } foreach ($groups_details as $key => $row) { // Is this the new group? if ($row['id_group'] == $group_id) { $foundTarget = true; $group_name = $row['group_name']; // Does the group type match what we're doing - are we trying to request a non-requestable group? if ($changeType == 'request' && $row['group_type'] != 2) { fatal_lang_error('no_access', false); } elseif ($changeType == 'free' && $row['group_type'] == 2 && $old_profile['id_group'] != $row['id_group'] && !isset($addGroups[$row['id_group']])) { fatal_lang_error('no_access', false); } elseif ($changeType == 'free' && $row['group_type'] != 3 && $row['group_type'] != 2) { fatal_lang_error('no_access', false); } // We can't change the primary group if this is hidden! if ($row['hidden'] == 2) { $canChangePrimary = false; } } // If this is their old primary, can we change it? if ($row['id_group'] == $old_profile['id_group'] && ($row['group_type'] > 1 || $context['can_manage_membergroups']) && $canChangePrimary !== false) { $canChangePrimary = 1; } // If we are not doing a force primary move, don't do it automatically if current primary is not 0. if ($changeType != 'primary' && $old_profile['id_group'] != 0) { $canChangePrimary = false; } // If this is the one we are acting on, can we even act? if (!$context['can_manage_protected'] && $row['group_type'] == 1 || !$context['can_manage_membergroups'] && $row['group_type'] == 0) { $canChangePrimary = false; } } // Didn't find the target? if (!$foundTarget) { fatal_lang_error('no_access', false); } // Final security check, don't allow users to promote themselves to admin. if ($context['can_manage_membergroups'] && !allowedTo('admin_forum')) { $request = $db->query('', ' SELECT COUNT(permission) FROM {db_prefix}permissions WHERE id_group = {int:selected_group} AND permission = {string:admin_forum} AND add_deny = {int:not_denied}', array('selected_group' => $group_id, 'not_denied' => 1, 'admin_forum' => 'admin_forum')); list($disallow) = $db->fetch_row($request); $db->free_result($request); if ($disallow) { isAllowedTo('admin_forum'); } } // If we're requesting, add the note then return. if ($changeType == 'request') { $request = $db->query('', ' SELECT id_member FROM {db_prefix}log_group_requests WHERE id_member = {int:selected_member} AND id_group = {int:selected_group}', array('selected_member' => $memID, 'selected_group' => $group_id)); if ($db->num_rows($request) != 0) { fatal_lang_error('profile_error_already_requested_group'); } $db->free_result($request); // Log the request. $db->insert('', '{db_prefix}log_group_requests', array('id_member' => 'int', 'id_group' => 'int', 'time_applied' => 'int', 'reason' => 'string-65534'), array($memID, $group_id, time(), $_POST['reason']), array('id_request')); // Send an email to all group moderators etc. require_once SUBSDIR . '/Mail.subs.php'; // Do we have any group moderators? $request = $db->query('', ' SELECT id_member FROM {db_prefix}group_moderators WHERE id_group = {int:selected_group}', array('selected_group' => $group_id)); $moderators = array(); while ($row = $db->fetch_assoc($request)) { $moderators[] = $row['id_member']; } $db->free_result($request); // Otherwise this is the backup! if (empty($moderators)) { require_once SUBSDIR . '/Members.subs.php'; $moderators = membersAllowedTo('manage_membergroups'); } if (!empty($moderators)) { require_once SUBSDIR . '/Members.subs.php'; $members = getBasicMemberData($moderators, array('preferences' => true, 'sort' => 'lngfile')); foreach ($members as $member) { if ($member['notify_types'] != 4) { continue; } // Check whether they are interested. if (!empty($member['mod_prefs'])) { list(, , $pref_binary) = explode('|', $member['mod_prefs']); if (!($pref_binary & 4)) { continue; } } $replacements = array('RECPNAME' => $member['member_name'], 'APPYNAME' => $old_profile['member_name'], 'GROUPNAME' => $group_name, 'REASON' => $_POST['reason'], 'MODLINK' => $scripturl . '?action=moderate;area=groups;sa=requests'); $emaildata = loadEmailTemplate('request_membership', $replacements, empty($member['lngfile']) || empty($modSettings['userLanguage']) ? $language : $member['lngfile']); sendmail($member['email_address'], $emaildata['subject'], $emaildata['body'], null, null, false, 2); } } return $changeType; } elseif ($changeType == 'free') { // Are we leaving? if ($old_profile['id_group'] == $group_id || isset($addGroups[$group_id])) { if ($old_profile['id_group'] == $group_id) { $newPrimary = 0; } else { unset($addGroups[$group_id]); } } else { // Can we change the primary, and do we want to? if ($canChangePrimary) { if ($old_profile['id_group'] != 0) { $addGroups[$old_profile['id_group']] = -1; } $newPrimary = $group_id; } else { $addGroups[$group_id] = -1; } } } elseif ($canChangePrimary) { if ($old_profile['id_group'] != 0) { $addGroups[$old_profile['id_group']] = -1; } if (isset($addGroups[$group_id])) { unset($addGroups[$group_id]); } $newPrimary = $group_id; } // Finally, we can make the changes! foreach ($addGroups as $id => $dummy) { if (empty($id)) { unset($addGroups[$id]); } } $addGroups = implode(',', array_flip($addGroups)); // Ensure that we don't cache permissions if the group is changing. if ($context['user']['is_owner']) { $_SESSION['mc']['time'] = 0; } else { updateSettings(array('settings_updated' => time())); } updateMemberData($memID, array('id_group' => $newPrimary, 'additional_groups' => $addGroups)); return $changeType; }
} } if (empty($txnType)) { generateSubscriptionError($txt['paid_unknown_transaction_type']); } // Get the subscription and member ID amoungst others... @(list($subscription_id, $member_id) = $gatewayClass->precheck()); // Integer these just in case. $subscription_id = (int) $subscription_id; $member_id = (int) $member_id; // This would be bad... if (empty($member_id)) { generateSubscriptionError($txt['paid_empty_member']); } // Verify the member. $member_info = getBasicMemberData($member_id); // Didn't find them? if (empty($member_info)) { generateSubscriptionError(sprintf($txt['paid_could_not_find_member'], $member_id)); } // Get the subscription details. $request = $db->query('', ' SELECT cost, length, name FROM {db_prefix}subscriptions WHERE id_subscribe = {int:current_subscription}', array('current_subscription' => $subscription_id)); // Didn't find it? if ($db->num_rows($request) === 0) { generateSubscriptionError(sprintf($txt['paid_count_not_find_subscription'], $member_id, $subscription_id)); } $subscription_info = $db->fetch_assoc($request); $db->free_result($request);
/** * This function will display the contact information for the forum, as well a form to fill in. * Accessed by action=coppa */ public function action_coppa() { global $context, $modSettings, $txt; loadLanguage('Login'); loadTemplate('Register'); // No User ID?? if (!isset($_GET['member'])) { fatal_lang_error('no_access', false); } // Get the user details... require_once SUBSDIR . '/Members.subs.php'; $member = getBasicMemberData((int) $_GET['member'], array('authentication' => true)); // If doesn't exist or not pending coppa if (empty($member) || $member['is_activated'] != 5) { fatal_lang_error('no_access', false); } if (isset($_GET['form'])) { // Some simple contact stuff for the forum. $context['forum_contacts'] = (!empty($modSettings['coppaPost']) ? $modSettings['coppaPost'] . '<br /><br />' : '') . (!empty($modSettings['coppaFax']) ? $modSettings['coppaFax'] . '<br />' : ''); $context['forum_contacts'] = !empty($context['forum_contacts']) ? $context['forum_name_html_safe'] . '<br />' . $context['forum_contacts'] : ''; // Showing template? if (!isset($_GET['dl'])) { // Shortcut for producing underlines. $context['ul'] = '<u> </u>'; Template_Layers::getInstance()->removeAll(); $context['sub_template'] = 'coppa_form'; $context['page_title'] = replaceBasicActionUrl($txt['coppa_form_title']); $context['coppa_body'] = str_replace(array('{PARENT_NAME}', '{CHILD_NAME}', '{USER_NAME}'), array($context['ul'], $context['ul'], $member['member_name']), replaceBasicActionUrl($txt['coppa_form_body'])); } else { // The data. $ul = ' '; $crlf = "\r\n"; $data = $context['forum_contacts'] . $crlf . $txt['coppa_form_address'] . ':' . $crlf . $txt['coppa_form_date'] . ':' . $crlf . $crlf . $crlf . replaceBasicActionUrl($txt['coppa_form_body']); $data = str_replace(array('{PARENT_NAME}', '{CHILD_NAME}', '{USER_NAME}', '<br>', '<br />'), array($ul, $ul, $member['member_name'], $crlf, $crlf), $data); // Send the headers. header('Connection: close'); header('Content-Disposition: attachment; filename="approval.txt"'); header('Content-Type: ' . (isBrowser('ie') || isBrowser('opera') ? 'application/octetstream' : 'application/octet-stream')); header('Content-Length: ' . count($data)); echo $data; obExit(false); } } else { $context += array('page_title' => $txt['coppa_title'], 'sub_template' => 'coppa'); $context['coppa'] = array('body' => str_replace('{MINIMUM_AGE}', $modSettings['coppaAge'], replaceBasicActionUrl($txt['coppa_after_registration'])), 'many_options' => !empty($modSettings['coppaPost']) && !empty($modSettings['coppaFax']), 'post' => empty($modSettings['coppaPost']) ? '' : $modSettings['coppaPost'], 'fax' => empty($modSettings['coppaFax']) ? '' : $modSettings['coppaFax'], 'phone' => empty($modSettings['coppaPhone']) ? '' : str_replace('{PHONE_NUMBER}', $modSettings['coppaPhone'], $txt['coppa_send_by_phone']), 'id' => $_GET['member']); } }
/** * View the forum's error log. * * What it does: * - This method sets all the context up to show the error log for maintenance. * - It requires the admin_forum permission. * - It is accessed from ?action=admin;area=logs;sa=errorlog. * * @uses the Errors template and error_log sub template. */ protected function action_log() { global $scripturl, $txt, $context, $modSettings, $user_profile, $filter; // We'll escape some strings... $db = database(); require_once SUBSDIR . '/Error.subs.php'; // Templates, etc... loadLanguage('Maintenance'); loadTemplate('Errors'); // You can filter by any of the following columns: $filters = array('id_member' => $txt['username'], 'ip' => $txt['ip_address'], 'session' => $txt['session'], 'url' => $txt['error_url'], 'message' => $txt['error_message'], 'error_type' => $txt['error_type'], 'file' => $txt['file'], 'line' => $txt['line']); // Set up the filtering... if (isset($_GET['value'], $_GET['filter']) && isset($filters[$_GET['filter']])) { $filter = array('variable' => $_GET['filter'], 'value' => array('sql' => in_array($_GET['filter'], array('message', 'url', 'file')) ? base64_decode(strtr($_GET['value'], array(' ' => '+'))) : $db->escape_wildcard_string($_GET['value'])), 'href' => ';filter=' . $_GET['filter'] . ';value=' . $_GET['value'], 'entity' => $filters[$_GET['filter']]); } elseif (isset($_GET['filter']) || isset($_GET['value'])) { unset($_GET['filter'], $_GET['value']); } // Deleting, are we? $type = isset($_POST['delall']) ? 'delall' : (isset($_POST['delete']) ? 'delete' : false); $error_list = isset($_POST['delete']) ? $_POST['delete'] : null; if ($type != false) { // Make sure the session exists and is correct; otherwise, might be a hacker. checkSession(); validateToken('admin-el'); deleteErrors($type, $filter, $error_list); // Go back to where we were. if ($type == 'delete') { redirectexit('action=admin;area=logs;sa=errorlog' . (isset($_REQUEST['desc']) ? ';desc' : '') . ';start=' . $_GET['start'] . (isset($filter) ? ';filter=' . $_GET['filter'] . ';value=' . $_GET['value'] : '')); } // Go back to where we were. redirectexit('action=admin;area=logs;sa=errorlog' . (isset($_REQUEST['desc']) ? ';desc' : '')); } $num_errors = numErrors($filter); // If this filter is empty... if ($num_errors == 0 && isset($filter)) { redirectexit('action=admin;area=logs;sa=errorlog' . (isset($_REQUEST['desc']) ? ';desc' : '')); } // Clean up start. if (!isset($_GET['start']) || $_GET['start'] < 0) { $_GET['start'] = 0; } // Do we want to reverse error listing? $context['sort_direction'] = isset($_REQUEST['desc']) ? 'down' : 'up'; // Set the page listing up. $context['page_index'] = constructPageIndex($scripturl . '?action=admin;area=logs;sa=errorlog' . ($context['sort_direction'] == 'down' ? ';desc' : '') . (isset($filter) ? $filter['href'] : ''), $_GET['start'], $num_errors, $modSettings['defaultMaxMessages']); $context['start'] = $_GET['start']; $context['errors'] = array(); $logdata = getErrorLogData($_GET['start'], $context['sort_direction'], $filter); if (!empty($logdata)) { $context['errors'] = $logdata['errors']; $members = $logdata['members']; } // Load the member data. if (!empty($members)) { require_once SUBSDIR . '/Members.subs.php'; $members = getBasicMemberData($members, array('add_guest' => true)); // Go through each error and tack the data on. foreach ($context['errors'] as $id => $dummy) { $memID = $context['errors'][$id]['member']['id']; $context['errors'][$id]['member']['username'] = $members[$memID]['member_name']; $context['errors'][$id]['member']['name'] = $members[$memID]['real_name']; $context['errors'][$id]['member']['href'] = empty($memID) ? '' : $scripturl . '?action=profile;u=' . $memID; $context['errors'][$id]['member']['link'] = empty($memID) ? $txt['guest_title'] : '<a href="' . $scripturl . '?action=profile;u=' . $memID . '">' . $context['errors'][$id]['member']['name'] . '</a>'; } } // Filtering anything? if (isset($filter)) { $context['filter'] =& $filter; // Set the filtering context. if ($filter['variable'] == 'id_member') { $id = $filter['value']['sql']; loadMemberData($id, false, 'minimal'); $context['filter']['value']['html'] = '<a href="' . $scripturl . '?action=profile;u=' . $id . '">' . $user_profile[$id]['real_name'] . '</a>'; } elseif ($filter['variable'] == 'url') { $context['filter']['value']['html'] = '\'' . strtr(htmlspecialchars((substr($filter['value']['sql'], 0, 1) == '?' ? $scripturl : '') . $filter['value']['sql'], ENT_COMPAT, 'UTF-8'), array('\\_' => '_')) . '\''; } elseif ($filter['variable'] == 'message') { $context['filter']['value']['html'] = '\'' . strtr(htmlspecialchars($filter['value']['sql'], ENT_COMPAT, 'UTF-8'), array("\n" => '<br />', '<br />' => '<br />', "\t" => ' ', '\\_' => '_', '\\%' => '%', '\\\\' => '\\')) . '\''; $context['filter']['value']['html'] = preg_replace('~&lt;span class=&quot;remove&quot;&gt;(.+?)&lt;/span&gt;~', '$1', $context['filter']['value']['html']); } elseif ($filter['variable'] == 'error_type') { $context['filter']['value']['html'] = '\'' . strtr(htmlspecialchars($filter['value']['sql'], ENT_COMPAT, 'UTF-8'), array("\n" => '<br />', '<br />' => '<br />', "\t" => ' ', '\\_' => '_', '\\%' => '%', '\\\\' => '\\')) . '\''; } else { $context['filter']['value']['html'] =& $filter['value']['sql']; } } $sort = $context['sort_direction'] == 'down' ? ';desc' : ''; // What type of errors do we have and how many do we have? $context['error_types'] = array(); $context['error_types'] = fetchErrorsByType($filter, $sort); $tmp = array_keys($context['error_types']); $sum = (int) end($tmp); $context['error_types']['all'] = array('label' => $txt['errortype_all'], 'description' => isset($txt['errortype_all_desc']) ? $txt['errortype_all_desc'] : '', 'url' => $scripturl . '?action=admin;area=logs;sa=errorlog' . ($context['sort_direction'] == 'down' ? ';desc' : ''), 'is_selected' => empty($filter)); // Update the all errors tab with the total number of errors $context['error_types']['all']['label'] .= ' (' . $sum . ')'; // Finally, work out what is the last tab! if (isset($context['error_types'][$sum])) { $context['error_types'][$sum]['is_last'] = true; } else { $context['error_types']['all']['is_last'] = true; } // And this is pretty basic ;). $context['page_title'] = $txt['errlog']; $context['has_filter'] = isset($filter); $context['sub_template'] = 'error_log'; createToken('admin-el'); }
/** * This functions determines whether this is the first login of the given user. * * @package Authorization * @param int $id_member the id of the member to check for */ function isFirstLogin($id_member) { // First login? require_once SUBSDIR . '/Members.subs.php'; $member = getBasicMemberData($id_member, array('moderation' => true)); return !empty($member) && $member['last_login'] == 0; }
/** * Report for showing all the forum staff members - quite a feat! * functions ending with "Report" are responsible for generating data * for reporting. * they are all called from action_index. * never access the context directly, but use the data handling * functions to do so. */ public function action_staff() { global $txt; require_once SUBSDIR . '/Members.subs.php'; require_once SUBSDIR . '/Boards.subs.php'; require_once SUBSDIR . '/Membergroups.subs.php'; // Fetch all the board names. $boards = fetchBoardsInfo('all'); $moderators = allBoardModerators(true); $boards_moderated = array(); foreach ($moderators as $id_member => $rows) { foreach ($rows as $row) { $boards_moderated[$id_member][] = $row['id_board']; } } // Get a list of global moderators (i.e. members with moderation powers). $global_mods = array_intersect(membersAllowedTo('moderate_board', 0), membersAllowedTo('approve_posts', 0), membersAllowedTo('remove_any', 0), membersAllowedTo('modify_any', 0)); // How about anyone else who is special? $allStaff = array_merge(membersAllowedTo('admin_forum'), membersAllowedTo('manage_membergroups'), membersAllowedTo('manage_permissions'), array_keys($moderators), $global_mods); // Make sure everyone is there once - no admin less important than any other! $allStaff = array_unique($allStaff); // This is a bit of a cop out - but we're protecting their forum, really! if (count($allStaff) > 300) { fatal_lang_error('report_error_too_many_staff'); } // Get all the possible membergroups! $all_groups = getBasicMembergroupData(array('all'), array(), null, false); $groups = array(0 => $txt['full_member']); foreach ($all_groups as $row) { $groups[$row['id']] = empty($row['online_color']) ? $row['name'] : '<span style="color: ' . $row['online_color'] . '">' . $row['name'] . '</span>'; } // All the fields we'll show. $staffSettings = array('position' => $txt['report_staff_position'], 'moderates' => $txt['report_staff_moderates'], 'posts' => $txt['report_staff_posts'], 'last_login' => $txt['report_staff_last_login']); // Do it in columns, it's just easier. setKeys('cols'); // Get the latest activated member's display name. $result = getBasicMemberData($allStaff, array('moderation' => true, 'sort' => 'real_name')); foreach ($result as $row) { // Each member gets their own table!. newTable($row['real_name'], '', 'left', 'auto', 'left', 200, 'center'); // First off, add in the side key. addData($staffSettings); // Create the main data array. $staffData = array('position' => isset($groups[$row['id_group']]) ? $groups[$row['id_group']] : $groups[0], 'posts' => $row['posts'], 'last_login' => standardTime($row['last_login']), 'moderates' => array()); // What do they moderate? if (in_array($row['id_member'], $global_mods)) { $staffData['moderates'] = '<em>' . $txt['report_staff_all_boards'] . '</em>'; } elseif (isset($boards_moderated[$row['id_member']])) { // Get the names foreach ($boards_moderated[$row['id_member']] as $board) { if (isset($boards[$board])) { $staffData['moderates'][] = $boards[$board]['name']; } } $staffData['moderates'] = implode(', ', $staffData['moderates']); } else { $staffData['moderates'] = '<em>' . $txt['report_staff_no_boards'] . '</em>'; } // Next add the main data. addData($staffData); } }
/** * Builds the 'query_see_board' element for a certain member * * @package Members * @param integer $id_member a valid member id */ function memberQuerySeeBoard($id_member) { global $modSettings; $member = getBasicMemberData($id_member, array('moderation' => true)); if (empty($member['additional_groups'])) { $groups = array($member['id_group'], $member['id_post_group']); } else { $groups = array_merge(array($member['id_group'], $member['id_post_group']), explode(',', $member['additional_groups'])); } foreach ($groups as $k => $v) { $groups[$k] = (int) $v; } $groups = array_unique($groups); if (in_array(1, $groups)) { return '1=1'; } else { require_once SUBSDIR . '/Boards.subs.php'; $boards_mod = boardsModerated($id_member); $mod_query = empty($boards_mod) ? '' : ' OR b.id_board IN (' . implode(',', $boards_mod) . ')'; return '((FIND_IN_SET(' . implode(', b.member_groups) != 0 OR FIND_IN_SET(', $groups) . ', b.member_groups) != 0)' . (!empty($modSettings['deny_boards_access']) ? ' AND (FIND_IN_SET(' . implode(', b.deny_member_groups) = 0 AND FIND_IN_SET(', $groups) . ', b.deny_member_groups) = 0)' : '') . $mod_query . ')'; } }
/** * List and allow adding/entering all man rules, such as * * What it does: * - If it itches, it will be scratched. * - Yes or No are perfectly acceptable answers to almost every question. * - Men see in only 16 colors, Peach, for example, is a fruit, not a color. * * @uses sub template rules */ public function action_manrules() { global $txt, $context, $user_info, $scripturl; require_once SUBSDIR . '/PersonalMessage.subs.php'; // The link tree - gotta have this :o $context['linktree'][] = array('url' => $scripturl . '?action=pm;sa=manrules', 'name' => $txt['pm_manage_rules']); $context['page_title'] = $txt['pm_manage_rules']; $context['sub_template'] = 'rules'; // Load them... load them!! loadRules(); // Likely to need all the groups! require_once SUBSDIR . '/Membergroups.subs.php'; $context['groups'] = accessibleGroups(); // Applying all rules? if (isset($_GET['apply'])) { checkSession('get'); applyRules(true); redirectexit('action=pm;sa=manrules'); } // Editing a specific rule? if (isset($_GET['add'])) { $context['rid'] = isset($_GET['rid']) && isset($context['rules'][$_GET['rid']]) ? (int) $_GET['rid'] : 0; $context['sub_template'] = 'add_rule'; // Any known rule $js_rules = ''; foreach ($context['known_rules'] as $rule) { $js_rules .= JavaScriptEscape($rule) . ': ' . JavaScriptEscape($txt['pm_rule_' . $rule]) . ','; } $js_rules = '{' . substr($js_rules, 0, -1) . '}'; // Any known label $js_labels = ''; foreach ($context['labels'] as $label) { if ($label['id'] != -1) { $js_labels .= JavaScriptEscape($label['id'] + 1) . ': ' . JavaScriptEscape($label['name']) . ','; } } $js_labels = '{' . substr($js_labels, 0, -1) . '}'; // And all of the groups as well $js_groups = ''; foreach ($context['groups'] as $id => $title) { $js_groups .= JavaScriptEscape($id) . ': ' . JavaScriptEscape($title) . ','; } $js_groups = '{' . substr($js_groups, 0, -1) . '}'; // Oh my, we have a lot of text strings for this addJavascriptVar(array('criteriaNum' => 0, 'actionNum' => 0, 'groups' => $js_groups, 'labels' => $js_labels, 'rules' => $js_rules, 'txt_pm_readable_and' => $txt['pm_readable_and'], 'txt_pm_readable_or' => $txt['pm_readable_or'], 'txt_pm_readable_member' => $txt['pm_readable_member'], 'txt_pm_readable_group' => $txt['pm_readable_group'], 'txt_pm_readable_subject ' => $txt['pm_readable_subject'], 'txt_pm_readable_body' => $txt['pm_readable_body'], 'txt_pm_readable_buddy' => $txt['pm_readable_buddy'], 'txt_pm_readable_label' => $txt['pm_readable_label'], 'txt_pm_readable_delete' => $txt['pm_readable_delete'], 'txt_pm_readable_start' => $txt['pm_readable_start'], 'txt_pm_readable_end' => $txt['pm_readable_end'], 'txt_pm_readable_then' => $txt['pm_readable_then'], 'txt_pm_rule_not_defined' => $txt['pm_rule_not_defined'], 'txt_pm_rule_criteria_pick' => $txt['pm_rule_criteria_pick'], 'txt_pm_rule_sel_group' => $txt['pm_rule_sel_group'], 'txt_pm_rule_sel_action' => $txt['pm_rule_sel_action'], 'txt_pm_rule_label' => $txt['pm_rule_label'], 'txt_pm_rule_delete' => $txt['pm_rule_delete'], 'txt_pm_rule_sel_label' => $txt['pm_rule_sel_label']), true); // Current rule information... if ($context['rid']) { $context['rule'] = $context['rules'][$context['rid']]; $members = array(); // Need to get member names! foreach ($context['rule']['criteria'] as $k => $criteria) { if ($criteria['t'] == 'mid' && !empty($criteria['v'])) { $members[(int) $criteria['v']] = $k; } } if (!empty($members)) { require_once SUBSDIR . '/Members.subs.php'; $result = getBasicMemberData(array_keys($members)); foreach ($result as $row) { $context['rule']['criteria'][$members[$row['id_member']]]['v'] = $row['member_name']; } } } else { $context['rule'] = array('id' => '', 'name' => '', 'criteria' => array(), 'actions' => array(), 'logic' => 'and'); } // Add a dummy criteria to allow expansion for none js users. $context['rule']['criteria'][] = array('t' => '', 'v' => ''); } elseif (isset($_GET['save'])) { checkSession('post'); $context['rid'] = isset($_GET['rid']) && isset($context['rules'][$_GET['rid']]) ? (int) $_GET['rid'] : 0; // Name is easy! $ruleName = Util::htmlspecialchars(trim($_POST['rule_name'])); if (empty($ruleName)) { fatal_lang_error('pm_rule_no_name', false); } // Sanity check... if (empty($_POST['ruletype']) || empty($_POST['acttype'])) { fatal_lang_error('pm_rule_no_criteria', false); } // Let's do the criteria first - it's also hardest! $criteria = array(); foreach ($_POST['ruletype'] as $ind => $type) { // Check everything is here... if ($type == 'gid' && (!isset($_POST['ruledefgroup'][$ind]) || !isset($context['groups'][$_POST['ruledefgroup'][$ind]]))) { continue; } elseif ($type != 'bud' && !isset($_POST['ruledef'][$ind])) { continue; } // Members need to be found. if ($type == 'mid') { require_once SUBSDIR . '/Members.subs.php'; $name = trim($_POST['ruledef'][$ind]); $member = getMemberByName($name, true); if (empty($member)) { continue; } $criteria[] = array('t' => 'mid', 'v' => $member['id_member']); } elseif ($type == 'bud') { $criteria[] = array('t' => 'bud', 'v' => 1); } elseif ($type == 'gid') { $criteria[] = array('t' => 'gid', 'v' => (int) $_POST['ruledefgroup'][$ind]); } elseif (in_array($type, array('sub', 'msg')) && trim($_POST['ruledef'][$ind]) != '') { $criteria[] = array('t' => $type, 'v' => Util::htmlspecialchars(trim($_POST['ruledef'][$ind]))); } } // Also do the actions! $actions = array(); $doDelete = 0; $isOr = $_POST['rule_logic'] == 'or' ? 1 : 0; foreach ($_POST['acttype'] as $ind => $type) { // Picking a valid label? if ($type == 'lab' && (!isset($_POST['labdef'][$ind]) || !isset($context['labels'][$_POST['labdef'][$ind] - 1]))) { continue; } // Record what we're doing. if ($type == 'del') { $doDelete = 1; } elseif ($type == 'lab') { $actions[] = array('t' => 'lab', 'v' => (int) $_POST['labdef'][$ind] - 1); } } if (empty($criteria) || empty($actions) && !$doDelete) { fatal_lang_error('pm_rule_no_criteria', false); } // What are we storing? $criteria = serialize($criteria); $actions = serialize($actions); // Create the rule? if (empty($context['rid'])) { addPMRule($user_info['id'], $ruleName, $criteria, $actions, $doDelete, $isOr); } else { updatePMRule($user_info['id'], $context['rid'], $ruleName, $criteria, $actions, $doDelete, $isOr); } redirectexit('action=pm;sa=manrules'); } elseif (isset($_POST['delselected']) && !empty($_POST['delrule'])) { checkSession('post'); $toDelete = array(); foreach ($_POST['delrule'] as $k => $v) { $toDelete[] = (int) $k; } if (!empty($toDelete)) { deletePMRules($user_info['id'], $toDelete); } redirectexit('action=pm;sa=manrules'); } }
/** * Editing a membergroup. * * What it does: * - Screen to edit a specific membergroup. * - Called by ?action=admin;area=membergroups;sa=edit;group=x. * - It requires the manage_membergroups permission. * - Also handles the delete button of the edit form. * - Redirects to ?action=admin;area=membergroups. * * @uses the edit_group sub template of ManageMembergroups. */ public function action_edit() { global $context, $txt, $modSettings; $current_group_id = isset($_REQUEST['group']) ? (int) $_REQUEST['group'] : 0; if (!empty($modSettings['deny_boards_access'])) { loadLanguage('ManagePermissions'); } require_once SUBSDIR . '/Membergroups.subs.php'; // Make sure this group is editable. if (!empty($current_group_id)) { $current_group = membergroupById($current_group_id); } // Now, do we have a valid id? if (!allowedTo('admin_forum') && !empty($current_group_id) && $current_group['group_type'] == 1) { fatal_lang_error('membergroup_does_not_exist', false); } // The delete this membergroup button was pressed. if (isset($_POST['delete'])) { checkSession(); validateToken('admin-mmg'); if (empty($current_group_id)) { fatal_lang_error('membergroup_does_not_exist', false); } // Let's delete the group deleteMembergroups($current_group['id_group']); redirectexit('action=admin;area=membergroups;'); } elseif (isset($_POST['save'])) { // Validate the session. checkSession(); validateToken('admin-mmg'); if (empty($current_group_id)) { fatal_lang_error('membergroup_does_not_exist', false); } require_once SUBSDIR . '/DataValidator.class.php'; $validator = new Data_Validator(); // Cleanup the inputs! :D $validator->sanitation_rules(array('max_messages' => 'intval', 'min_posts' => 'intval|abs', 'group_type' => 'intval', 'group_desc' => 'trim|Util::htmlspecialchars', 'group_name' => 'trim|Util::htmlspecialchars', 'group_hidden' => 'intval', 'group_inherit' => 'intval', 'icon_count' => 'intval', 'icon_image' => 'trim|Util::htmlspecialchars', 'online_color' => 'trim|valid_color')); $validator->input_processing(array('boardaccess' => 'array')); $validator->validation_rules(array('boardaccess' => 'contains[allow,ignore,deny]')); $validator->validate($_POST); // Can they really inherit from this group? if ($validator->group_inherit != -2 && !allowedTo('admin_forum')) { $inherit_type = membergroupById($validator->group_inherit); } $min_posts = $validator->group_type == -1 && $validator->min_posts >= 0 && $current_group['id_group'] > 3 ? $validator->min_posts : ($current_group['id_group'] == 4 ? 0 : -1); $group_inherit = $current_group['id_group'] > 1 && $current_group['id_group'] != 3 && (empty($inherit_type['group_type']) || $inherit_type['group_type'] != 1) ? $validator->group_inherit : -2; //@todo Don't set online_color for the Moderators group? // Do the update of the membergroup settings. $properties = array('max_messages' => $validator->max_messages, 'min_posts' => $min_posts, 'group_type' => $validator->group_type < 0 || $validator->group_type > 3 || $validator->group_type == 1 && !allowedTo('admin_forum') ? 0 : $validator->group_type, 'hidden' => !$validator->group_hidden || $min_posts != -1 || $current_group['id_group'] == 3 ? 0 : $validator->group_hidden, 'id_parent' => $group_inherit, 'current_group' => $current_group['id_group'], 'group_name' => $validator->group_name, 'online_color' => $validator->online_color, 'icons' => $validator->icon_count <= 0 ? '' : min($validator->icon_count, 10) . '#' . $validator->icon_image, 'description' => $current_group['id_group'] == 1 || $validator->group_type != -1 ? $validator->group_desc : ''); updateMembergroupProperties($properties); call_integration_hook('integrate_save_membergroup', array($current_group['id_group'])); // Time to update the boards this membergroup has access to. if ($current_group['id_group'] == 2 || $current_group['id_group'] > 3) { $changed_boards = array(); $changed_boards['allow'] = array(); $changed_boards['deny'] = array(); $changed_boards['ignore'] = array(); if ($validator->boardaccess) { foreach ($validator->boardaccess as $group_id => $action) { $changed_boards[$action][] = (int) $group_id; } } foreach (array('allow', 'deny') as $board_action) { // Find all board this group is in, but shouldn't be in. detachGroupFromBoards($current_group['id_group'], $changed_boards, $board_action); // Add the membergroup to all boards that hadn't been set yet. if (!empty($changed_boards[$board_action])) { assignGroupToBoards($current_group['id_group'], $changed_boards, $board_action); } } } // Remove everyone from this group! if ($min_posts != -1) { detachDeletedGroupFromMembers($current_group['id_group']); } elseif ($current_group['id_group'] != 3) { // Making it a hidden group? If so remove everyone with it as primary group (Actually, just make them additional). if ($validator->group_hidden == 2) { setGroupToHidden($current_group['id_group']); } // Either way, let's check our "show group membership" setting is correct. validateShowGroupMembership(); } // Do we need to set inherited permissions? if ($group_inherit != -2 && $group_inherit != $_POST['old_inherit']) { require_once SUBSDIR . '/Permission.subs.php'; updateChildPermissions($group_inherit); } // Finally, moderators! $moderator_string = isset($_POST['group_moderators']) ? trim($_POST['group_moderators']) : ''; detachGroupModerators($current_group['id_group']); if ((!empty($moderator_string) || !empty($_POST['moderator_list'])) && $min_posts == -1 && $current_group['id_group'] != 3) { // Get all the usernames from the string if (!empty($moderator_string)) { $moderator_string = strtr(preg_replace('~&#(\\d{4,5}|[2-9]\\d{2,4}|1[2-9]\\d);~', '&#$1;', htmlspecialchars($moderator_string, ENT_QUOTES, 'UTF-8')), array('"' => '"')); preg_match_all('~"([^"]+)"~', $moderator_string, $matches); $moderators = array_merge($matches[1], explode(',', preg_replace('~"[^"]+"~', '', $moderator_string))); for ($k = 0, $n = count($moderators); $k < $n; $k++) { $moderators[$k] = trim($moderators[$k]); if (strlen($moderators[$k]) == 0) { unset($moderators[$k]); } } // Find all the id_member's for the member_name's in the list. if (!empty($moderators)) { $group_moderators = getIDMemberFromGroupModerators($moderators); } } else { $moderators = array(); foreach ($_POST['moderator_list'] as $moderator) { $moderators[] = (int) $moderator; } $group_moderators = array(); if (!empty($moderators)) { require_once SUBSDIR . '/Members.subs.php'; $members = getBasicMemberData($moderators); foreach ($members as $member) { $group_moderators[] = $member['id_member']; } } } // Found some? if (!empty($group_moderators)) { assignGroupModerators($current_group['id_group'], $group_moderators); } } // There might have been some post group changes. updateStats('postgroups'); // We've definitely changed some group stuff. updateSettings(array('settings_updated' => time())); // Log the edit. logAction('edited_group', array('group' => $validator->group_name), 'admin'); redirectexit('action=admin;area=membergroups'); } // Fetch the current group information. $row = membergroupById($current_group['id_group'], true); if (empty($row) || !allowedTo('admin_forum') && $row['group_type'] == 1) { fatal_lang_error('membergroup_does_not_exist', false); } $row['icons'] = explode('#', $row['icons']); $context['group'] = array('id' => $row['id_group'], 'name' => $row['group_name'], 'description' => htmlspecialchars($row['description'], ENT_COMPAT, 'UTF-8'), 'editable_name' => $row['group_name'], 'color' => $row['online_color'], 'min_posts' => $row['min_posts'], 'max_messages' => $row['max_messages'], 'icon_count' => (int) $row['icons'][0], 'icon_image' => isset($row['icons'][1]) ? $row['icons'][1] : '', 'is_post_group' => $row['min_posts'] != -1, 'type' => $row['min_posts'] != -1 ? 0 : $row['group_type'], 'hidden' => $row['min_posts'] == -1 ? $row['hidden'] : 0, 'inherited_from' => $row['id_parent'], 'allow_post_group' => $row['id_group'] == 2 || $row['id_group'] > 4, 'allow_delete' => $row['id_group'] == 2 || $row['id_group'] > 4, 'allow_protected' => allowedTo('admin_forum')); // Get any moderators for this group $context['group']['moderators'] = getGroupModerators($row['id_group']); $context['group']['moderator_list'] = empty($context['group']['moderators']) ? '' : '"' . implode('", "', $context['group']['moderators']) . '"'; if (!empty($context['group']['moderators'])) { list($context['group']['last_moderator_id']) = array_slice(array_keys($context['group']['moderators']), -1); } // Get a list of boards this membergroup is allowed to see. $context['boards'] = array(); if ($row['id_group'] == 2 || $row['id_group'] > 3) { require_once SUBSDIR . '/Boards.subs.php'; $context += getBoardList(array('override_permissions' => true, 'access' => $row['id_group'], 'not_redirection' => true)); // Include a list of boards per category for easy toggling. foreach ($context['categories'] as $category) { $context['categories'][$category['id']]['child_ids'] = array_keys($category['boards']); } } // Finally, get all the groups this could be inherited off. $context['inheritable_groups'] = getInheritableGroups($row['id_group']); call_integration_hook('integrate_view_membergroup'); $context['sub_template'] = 'edit_group'; $context['page_title'] = $txt['membergroups_edit_group']; // Use the autosuggest script when needed if ($context['group']['id'] != 3 && $context['group']['id'] != 4) { loadJavascriptFile('suggest.js', array('defer' => true)); } createToken('admin-mmg'); }
/** * Given a list of userid's for a PM, finds the member name associated with the ID * so it can be presented to the user. * * - keeps track of bcc and to names for the PM * * @package Drafts * @todo this is the same as whats in PersonalMessage.controller, when that gets refractored * this should go away and use the refractored PM subs * @param int[] $allRecipients * @param mixed[] $recipient_ids */ function draftsRecipients($allRecipients, $recipient_ids) { // Holds our results $recipients = array('to' => array(), 'bcc' => array()); require_once SUBSDIR . '/Members.subs.php'; // Get all the member names that this PM is going to $results = getBasicMemberData($allRecipients); foreach ($results as $result) { // Load the to/bcc name array $recipientType = in_array($result['id_member'], $recipient_ids['bcc']) ? 'bcc' : 'to'; $recipients[$recipientType][] = $result['real_name']; } return $recipients; }
/** * Let them see what their signature looks like before they use it like spam */ public function action_sig_preview() { global $context, $txt, $user_info; require_once SUBSDIR . '/Profile.subs.php'; loadLanguage('Profile'); loadLanguage('Errors'); $user = isset($_POST['user']) ? (int) $_POST['user'] : 0; $is_owner = $user == $user_info['id']; // @todo Temporary // Borrowed from loadAttachmentContext in Display.controller.php $can_change = $is_owner ? allowedTo(array('profile_extra_any', 'profile_extra_own')) : allowedTo('profile_extra_any'); $errors = array(); if (!empty($user) && $can_change) { require_once SUBSDIR . '/Members.subs.php'; // Get the current signature $member = getBasicMemberData($user, array('preferences' => true)); censorText($member['signature']); $member['signature'] = parse_bbc($member['signature'], true, 'sig' . $user); // And now what they want it to be $preview_signature = !empty($_POST['signature']) ? Util::htmlspecialchars($_POST['signature']) : ''; $validation = profileValidateSignature($preview_signature); // An odd check for errors to be sure if ($validation !== true && $validation !== false) { $errors[] = array('value' => $txt['profile_error_' . $validation], 'attributes' => array('type' => 'error')); } preparsecode($preview_signature); censorText($preview_signature); $preview_signature = parse_bbc($preview_signature, true, 'sig' . $user); } elseif (!$can_change) { if ($is_owner) { $errors[] = array('value' => $txt['cannot_profile_extra_own'], 'attributes' => array('type' => 'error')); } else { $errors[] = array('value' => $txt['cannot_profile_extra_any'], 'attributes' => array('type' => 'error')); } } else { $errors[] = array('value' => $txt['no_user_selected'], 'attributes' => array('type' => 'error')); } // Return the response for the template $context['xml_data']['signatures'] = array('identifier' => 'signature', 'children' => array()); if (isset($member['signature'])) { $context['xml_data']['signatures']['children'][] = array('value' => $member['signature'], 'attributes' => array('type' => 'current')); } if (isset($preview_signature)) { $context['xml_data']['signatures']['children'][] = array('value' => $preview_signature, 'attributes' => array('type' => 'preview')); } if (!empty($errors)) { $context['xml_data']['errors'] = array('identifier' => 'error', 'children' => array_merge(array(array('value' => $txt['profile_errors_occurred'], 'attributes' => array('type' => 'errors_occurred'))), $errors)); } }
/** * Choose a theme from a list. * Allows a user or administrator to pick a new theme with an interface. * * What it does: * - Can edit everyone's (u = 0), guests' (u = -1), or a specific user's. * - Uses the Themes template. (pick sub template.) * - Accessed with ?action=admin;area=theme;sa=pick. * * @uses Profile language text * @uses ManageThemes template * @todo thought so... Might be better to split this file in ManageThemes and Themes, * with centralized admin permissions on ManageThemes. */ public function action_pick() { global $txt, $context, $modSettings, $user_info, $scripturl, $settings; require_once SUBSDIR . '/Themes.subs.php'; if (!$modSettings['theme_allow'] && $settings['disable_user_variant'] && !allowedTo('admin_forum')) { fatal_lang_error('no_access', false); } loadLanguage('Profile'); loadTemplate('ManageThemes'); // Build the link tree. $context['linktree'][] = array('url' => $scripturl . '?action=theme;sa=pick;u=' . (!empty($_REQUEST['u']) ? (int) $_REQUEST['u'] : 0), 'name' => $txt['theme_pick']); $context['default_theme_id'] = $modSettings['theme_default']; $_SESSION['id_theme'] = 0; if (isset($_GET['id'])) { $_GET['th'] = $_GET['id']; } // Saving a variant cause JS doesn't work - pretend it did ;) if (isset($_POST['save'])) { // Which theme? foreach ($_POST['save'] as $k => $v) { $_GET['th'] = (int) $k; } if (isset($_POST['vrt'][$k])) { $_GET['vrt'] = $_POST['vrt'][$k]; } } // Have we made a decision, or are we just browsing? if (isset($_GET['th'])) { checkSession('get'); $_GET['th'] = (int) $_GET['th']; // Save for this user. if (!isset($_REQUEST['u']) || !allowedTo('admin_forum')) { updateMemberData($user_info['id'], array('id_theme' => (int) $_GET['th'])); // A variants to save for the user? if (!empty($_GET['vrt'])) { updateThemeOptions(array($_GET['th'], $user_info['id'], 'theme_variant', $_GET['vrt'])); cache_put_data('theme_settings-' . $_GET['th'] . ':' . $user_info['id'], null, 90); $_SESSION['id_variant'] = 0; } redirectexit('action=profile;area=theme'); } // If changing members or guests - and there's a variant - assume changing default variant. if (!empty($_GET['vrt']) && ($_REQUEST['u'] == '0' || $_REQUEST['u'] == '-1')) { updateThemeOptions(array($_GET['th'], 0, 'default_variant', $_GET['vrt'])); // Make it obvious that it's changed cache_put_data('theme_settings-' . $_GET['th'], null, 90); } // For everyone. if ($_REQUEST['u'] == '0') { updateMemberData(null, array('id_theme' => (int) $_GET['th'])); // Remove any custom variants. if (!empty($_GET['vrt'])) { deleteVariants((int) $_GET['th']); } redirectexit('action=admin;area=theme;sa=admin;' . $context['session_var'] . '=' . $context['session_id']); } elseif ($_REQUEST['u'] == '-1') { updateSettings(array('theme_guests' => (int) $_GET['th'])); redirectexit('action=admin;area=theme;sa=admin;' . $context['session_var'] . '=' . $context['session_id']); } else { // The forum's default theme is always 0 and we if (isset($_GET['th']) && $_GET['th'] == 0) { $_GET['th'] = $modSettings['theme_guests']; } updateMemberData((int) $_REQUEST['u'], array('id_theme' => (int) $_GET['th'])); if (!empty($_GET['vrt'])) { updateThemeOptions(array($_GET['th'], (int) $_REQUEST['u'], 'theme_variant', $_GET['vrt'])); cache_put_data('theme_settings-' . $_GET['th'] . ':' . (int) $_REQUEST['u'], null, 90); if ($user_info['id'] == $_REQUEST['u']) { $_SESSION['id_variant'] = 0; } } redirectexit('action=profile;u=' . (int) $_REQUEST['u'] . ';area=theme'); } } // Figure out who the member of the minute is, and what theme they've chosen. if (!isset($_REQUEST['u']) || !allowedTo('admin_forum')) { $context['current_member'] = $user_info['id']; $current_theme = $user_info['theme']; } elseif ($_REQUEST['u'] == '0') { $context['current_member'] = 0; $current_theme = 0; } elseif ($_REQUEST['u'] == '-1') { $context['current_member'] = -1; $current_theme = $modSettings['theme_guests']; } else { $context['current_member'] = (int) $_REQUEST['u']; require_once SUBSDIR . '/Members.subs.php'; $member = getBasicMemberData($context['current_member']); $current_theme = $member['id_theme']; } // Get the theme name and descriptions. list($context['available_themes'], $guest_theme) = availableThemes($current_theme, $context['current_member']); // As long as we're not doing the default theme... if (!isset($_REQUEST['u']) || $_REQUEST['u'] >= 0) { if ($guest_theme != 0) { $context['available_themes'][0] = $context['available_themes'][$guest_theme]; } $context['available_themes'][0]['id'] = 0; $context['available_themes'][0]['name'] = $txt['theme_forum_default']; $context['available_themes'][0]['selected'] = $current_theme == 0; $context['available_themes'][0]['description'] = $txt['theme_global_description']; } ksort($context['available_themes']); $context['page_title'] = $txt['theme_pick']; $context['sub_template'] = 'pick'; }
/** * Sends a personal message from the specified person to the specified people * ($from defaults to the user) * * @package PersonalMessage * @param mixed[] $recipients - an array containing the arrays 'to' and 'bcc', both containing id_member's. * @param string $subject - should have no slashes and no html entities * @param string $message - should have no slashes and no html entities * @param bool $store_outbox * @param mixed[]|null $from - an array with the id, name, and username of the member. * @param int $pm_head - the ID of the chain being replied to - if any. * @return mixed[] an array with log entries telling how many recipients were successful and which recipients it failed to send to. */ function sendpm($recipients, $subject, $message, $store_outbox = true, $from = null, $pm_head = 0) { global $scripturl, $txt, $user_info, $language, $modSettings, $webmaster_email; $db = database(); // Make sure the PM language file is loaded, we might need something out of it. loadLanguage('PersonalMessage'); // Needed for our email and post functions require_once SUBSDIR . '/Mail.subs.php'; require_once SUBSDIR . '/Post.subs.php'; // Initialize log array. $log = array('failed' => array(), 'sent' => array()); if ($from === null) { $from = array('id' => $user_info['id'], 'name' => $user_info['name'], 'username' => $user_info['username']); } else { $user_info['name'] = $from['name']; } // This is the one that will go in their inbox. $htmlmessage = Util::htmlspecialchars($message, ENT_QUOTES, 'UTF-8', true); preparsecode($htmlmessage); $htmlsubject = strtr(Util::htmlspecialchars($subject), array("\r" => '', "\n" => '', "\t" => '')); if (Util::strlen($htmlsubject) > 100) { $htmlsubject = Util::substr($htmlsubject, 0, 100); } // Make sure is an array if (!is_array($recipients)) { $recipients = array($recipients); } // Integrated PMs call_integration_hook('integrate_personal_message', array(&$recipients, &$from, &$subject, &$message)); // Get a list of usernames and convert them to IDs. $usernames = array(); foreach ($recipients as $rec_type => $rec) { foreach ($rec as $id => $member) { if (!is_numeric($recipients[$rec_type][$id])) { $recipients[$rec_type][$id] = Util::strtolower(trim(preg_replace('/[<>&"\'=\\\\]/', '', $recipients[$rec_type][$id]))); $usernames[$recipients[$rec_type][$id]] = 0; } } } if (!empty($usernames)) { $request = $db->query('pm_find_username', ' SELECT id_member, member_name FROM {db_prefix}members WHERE ' . (defined('DB_CASE_SENSITIVE') ? 'LOWER(member_name)' : 'member_name') . ' IN ({array_string:usernames})', array('usernames' => array_keys($usernames))); while ($row = $db->fetch_assoc($request)) { if (isset($usernames[Util::strtolower($row['member_name'])])) { $usernames[Util::strtolower($row['member_name'])] = $row['id_member']; } } $db->free_result($request); // Replace the usernames with IDs. Drop usernames that couldn't be found. foreach ($recipients as $rec_type => $rec) { foreach ($rec as $id => $member) { if (is_numeric($recipients[$rec_type][$id])) { continue; } if (!empty($usernames[$member])) { $recipients[$rec_type][$id] = $usernames[$member]; } else { $log['failed'][$id] = sprintf($txt['pm_error_user_not_found'], $recipients[$rec_type][$id]); unset($recipients[$rec_type][$id]); } } } } // Make sure there are no duplicate 'to' members. $recipients['to'] = array_unique($recipients['to']); // Only 'bcc' members that aren't already in 'to'. $recipients['bcc'] = array_diff(array_unique($recipients['bcc']), $recipients['to']); // Combine 'to' and 'bcc' recipients. $all_to = array_merge($recipients['to'], $recipients['bcc']); // Check no-one will want it deleted right away! $request = $db->query('', ' SELECT id_member, criteria, is_or FROM {db_prefix}pm_rules WHERE id_member IN ({array_int:to_members}) AND delete_pm = {int:delete_pm}', array('to_members' => $all_to, 'delete_pm' => 1)); $deletes = array(); // Check whether we have to apply anything... while ($row = $db->fetch_assoc($request)) { $criteria = unserialize($row['criteria']); // Note we don't check the buddy status, cause deletion from buddy = madness! $delete = false; foreach ($criteria as $criterium) { if ($criterium['t'] == 'mid' && $criterium['v'] == $from['id'] || $criterium['t'] == 'gid' && in_array($criterium['v'], $user_info['groups']) || $criterium['t'] == 'sub' && strpos($subject, $criterium['v']) !== false || $criterium['t'] == 'msg' && strpos($message, $criterium['v']) !== false) { $delete = true; } elseif (!$row['is_or']) { $delete = false; break; } } if ($delete) { $deletes[$row['id_member']] = 1; } } $db->free_result($request); // Load the membergrounp message limits. static $message_limit_cache = array(); if (!allowedTo('moderate_forum') && empty($message_limit_cache)) { $request = $db->query('', ' SELECT id_group, max_messages FROM {db_prefix}membergroups', array()); while ($row = $db->fetch_assoc($request)) { $message_limit_cache[$row['id_group']] = $row['max_messages']; } $db->free_result($request); } // Load the groups that are allowed to read PMs. // @todo move into a separate function on $permission. $allowed_groups = array(); $disallowed_groups = array(); $request = $db->query('', ' SELECT id_group, add_deny FROM {db_prefix}permissions WHERE permission = {string:read_permission}', array('read_permission' => 'pm_read')); while ($row = $db->fetch_assoc($request)) { if (empty($row['add_deny'])) { $disallowed_groups[] = $row['id_group']; } else { $allowed_groups[] = $row['id_group']; } } $db->free_result($request); if (empty($modSettings['permission_enable_deny'])) { $disallowed_groups = array(); } $request = $db->query('', ' SELECT member_name, real_name, id_member, email_address, lngfile, pm_email_notify, personal_messages,' . (allowedTo('moderate_forum') ? ' 0' : ' (receive_from = {int:admins_only}' . (empty($modSettings['enable_buddylist']) ? '' : ' OR (receive_from = {int:buddies_only} AND FIND_IN_SET({string:from_id}, buddy_list) = 0) OR (receive_from = {int:not_on_ignore_list} AND FIND_IN_SET({string:from_id}, pm_ignore_list) != 0)') . ')') . ' AS ignored, FIND_IN_SET({string:from_id}, buddy_list) != 0 AS is_buddy, is_activated, additional_groups, id_group, id_post_group FROM {db_prefix}members WHERE id_member IN ({array_int:recipients}) ORDER BY lngfile LIMIT {int:count_recipients}', array('not_on_ignore_list' => 1, 'buddies_only' => 2, 'admins_only' => 3, 'recipients' => $all_to, 'count_recipients' => count($all_to), 'from_id' => $from['id'])); $notifications = array(); while ($row = $db->fetch_assoc($request)) { // Don't do anything for members to be deleted! if (isset($deletes[$row['id_member']])) { continue; } // We need to know this members groups. $groups = explode(',', $row['additional_groups']); $groups[] = $row['id_group']; $groups[] = $row['id_post_group']; $message_limit = -1; // For each group see whether they've gone over their limit - assuming they're not an admin. if (!in_array(1, $groups)) { foreach ($groups as $id) { if (isset($message_limit_cache[$id]) && $message_limit != 0 && $message_limit < $message_limit_cache[$id]) { $message_limit = $message_limit_cache[$id]; } } if ($message_limit > 0 && $message_limit <= $row['personal_messages']) { $log['failed'][$row['id_member']] = sprintf($txt['pm_error_data_limit_reached'], $row['real_name']); unset($all_to[array_search($row['id_member'], $all_to)]); continue; } // Do they have any of the allowed groups? if (count(array_intersect($allowed_groups, $groups)) == 0 || count(array_intersect($disallowed_groups, $groups)) != 0) { $log['failed'][$row['id_member']] = sprintf($txt['pm_error_user_cannot_read'], $row['real_name']); unset($all_to[array_search($row['id_member'], $all_to)]); continue; } } // Note that PostgreSQL can return a lowercase t/f for FIND_IN_SET if (!empty($row['ignored']) && $row['ignored'] != 'f' && $row['id_member'] != $from['id']) { $log['failed'][$row['id_member']] = sprintf($txt['pm_error_ignored_by_user'], $row['real_name']); unset($all_to[array_search($row['id_member'], $all_to)]); continue; } // If the receiving account is banned (>=10) or pending deletion (4), refuse to send the PM. if ($row['is_activated'] >= 10 || $row['is_activated'] == 4 && !$user_info['is_admin']) { $log['failed'][$row['id_member']] = sprintf($txt['pm_error_user_cannot_read'], $row['real_name']); unset($all_to[array_search($row['id_member'], $all_to)]); continue; } // Send a notification, if enabled - taking the buddy list into account. if (!empty($row['email_address']) && ($row['pm_email_notify'] == 1 || $row['pm_email_notify'] > 1 && (!empty($modSettings['enable_buddylist']) && $row['is_buddy'])) && $row['is_activated'] == 1) { $notifications[empty($row['lngfile']) || empty($modSettings['userLanguage']) ? $language : $row['lngfile']][] = $row['email_address']; } $log['sent'][$row['id_member']] = sprintf(isset($txt['pm_successfully_sent']) ? $txt['pm_successfully_sent'] : '', $row['real_name']); } $db->free_result($request); // Only 'send' the message if there are any recipients left. if (empty($all_to)) { return $log; } // Track the pm count for our stats if (!empty($modSettings['trackStats'])) { trackStats(array('pm' => '+')); } // Insert the message itself and then grab the last insert id. $db->insert('', '{db_prefix}personal_messages', array('id_pm_head' => 'int', 'id_member_from' => 'int', 'deleted_by_sender' => 'int', 'from_name' => 'string-255', 'msgtime' => 'int', 'subject' => 'string-255', 'body' => 'string-65534'), array($pm_head, $from['id'], $store_outbox ? 0 : 1, $from['username'], time(), $htmlsubject, $htmlmessage), array('id_pm')); $id_pm = $db->insert_id('{db_prefix}personal_messages', 'id_pm'); // Add the recipients. if (!empty($id_pm)) { // If this is new we need to set it part of it's own conversation. if (empty($pm_head)) { $db->query('', ' UPDATE {db_prefix}personal_messages SET id_pm_head = {int:id_pm_head} WHERE id_pm = {int:id_pm_head}', array('id_pm_head' => $id_pm)); } // Some people think manually deleting personal_messages is fun... it's not. We protect against it though :) $db->query('', ' DELETE FROM {db_prefix}pm_recipients WHERE id_pm = {int:id_pm}', array('id_pm' => $id_pm)); $insertRows = array(); $to_list = array(); foreach ($all_to as $to) { $insertRows[] = array($id_pm, $to, in_array($to, $recipients['bcc']) ? 1 : 0, isset($deletes[$to]) ? 1 : 0, 1); if (!in_array($to, $recipients['bcc'])) { $to_list[] = $to; } } $db->insert('insert', '{db_prefix}pm_recipients', array('id_pm' => 'int', 'id_member' => 'int', 'bcc' => 'int', 'deleted' => 'int', 'is_new' => 'int'), $insertRows, array('id_pm', 'id_member')); } $maillist = !empty($modSettings['maillist_enabled']) && !empty($modSettings['pbe_pm_enabled']); // If they have post by email enabled, override disallow_sendBody if (!$maillist && !empty($modSettings['disallow_sendBody'])) { $message = ''; censorText($subject); } else { require_once SUBSDIR . '/Emailpost.subs.php'; pbe_prepare_text($message, $subject); } $to_names = array(); if (count($to_list) > 1) { require_once SUBSDIR . '/Members.subs.php'; $result = getBasicMemberData($to_list); foreach ($result as $row) { $to_names[] = un_htmlspecialchars($row['real_name']); } } $replacements = array('SUBJECT' => $subject, 'MESSAGE' => $message, 'SENDER' => un_htmlspecialchars($from['name']), 'READLINK' => $scripturl . '?action=pm;pmsg=' . $id_pm . '#msg' . $id_pm, 'REPLYLINK' => $scripturl . '?action=pm;sa=send;f=inbox;pmsg=' . $id_pm . ';quote;u=' . $from['id'], 'TOLIST' => implode(', ', $to_names)); // Select the right template $email_template = ($maillist && empty($modSettings['disallow_sendBody']) ? 'pbe_' : '') . 'new_pm' . (empty($modSettings['disallow_sendBody']) ? '_body' : '') . (!empty($to_names) ? '_tolist' : ''); foreach ($notifications as $lang => $notification_list) { // Using maillist functionality if ($maillist) { $sender_details = query_sender_wrapper($from['id']); $from_wrapper = !empty($modSettings['maillist_mail_from']) ? $modSettings['maillist_mail_from'] : (empty($modSettings['maillist_sitename_address']) ? $webmaster_email : $modSettings['maillist_sitename_address']); // Add in the signature $replacements['SIGNATURE'] = $sender_details['signature']; // And off it goes, looking a bit more personal $mail = loadEmailTemplate($email_template, $replacements, $lang); $reference = !empty($pm_head) ? $pm_head : null; sendmail($notification_list, $mail['subject'], $mail['body'], $from['name'], 'p' . $id_pm, false, 2, null, true, $from_wrapper, $reference); } else { // Off the notification email goes! $mail = loadEmailTemplate($email_template, $replacements, $lang); sendmail($notification_list, $mail['subject'], $mail['body'], null, 'p' . $id_pm, false, 2, null, true); } } // Integrated After PMs call_integration_hook('integrate_personal_message_after', array(&$id_pm, &$log, &$recipients, &$from, &$subject, &$message)); // Back to what we were on before! loadLanguage('index+PersonalMessage'); // Add one to their unread and read message counts. foreach ($all_to as $k => $id) { if (isset($deletes[$id])) { unset($all_to[$k]); } } if (!empty($all_to)) { updateMemberData($all_to, array('personal_messages' => '+', 'unread_messages' => '+', 'new_pm' => 1)); } return $log; }
/** * View the forum's badbehavior log. * * What it does: * - This function sets all the context up to show the badbehavior log for review. * - It requires the maintain_forum permission. * - It is accessed from ?action=admin;area=logs;sa=badbehaviorlog. * * @uses the BadBehavior template and badbehavior_log sub template. */ public function action_log() { global $scripturl, $txt, $context, $modSettings, $user_profile, $filter; $db = database(); // Check for the administrative permission to do this. isAllowedTo('admin_forum'); // Templates, etc... loadLanguage('BadBehaviorlog'); loadTemplate('BadBehavior'); // Functions we will need require_once SUBSDIR . '/BadBehavior.subs.php'; // You can filter by any of the following columns: $filters = array('id_member' => $txt['badbehaviorlog_username'], 'ip' => $txt['badbehaviorlog_ip'], 'session' => $txt['badbehaviorlog_session'], 'valid' => $txt['badbehaviorlog_key'], 'request_uri' => $txt['badbehaviorlog_request'], 'user_agent' => $txt['badbehaviorlog_agent']); // Set up the filtering... $filter = array(); if (isset($_GET['value'], $_GET['filter']) && isset($filters[$_GET['filter']])) { $filter = array('variable' => $_GET['filter'] == 'useragent' ? 'user_agent' : $_GET['filter'], 'value' => array('sql' => in_array($_GET['filter'], array('request_uri', 'user_agent')) ? base64_decode(strtr($_GET['value'], array(' ' => '+'))) : $db->escape_wildcard_string($_GET['value'])), 'href' => ';filter=' . $_GET['filter'] . ';value=' . $_GET['value'], 'entity' => $filters[$_GET['filter']]); } elseif (isset($_GET['filter']) || isset($_GET['value'])) { // Bad filter or something else going on, back to the start you go unset($_GET['filter'], $_GET['value']); redirectexit('action=admin;area=logs;sa=badbehaviorlog' . (isset($_REQUEST['desc']) ? ';desc' : '')); } // Deleting or just doing a little weeding? if (isset($_POST['delall']) || isset($_POST['delete'])) { $type = isset($_POST['delall']) ? 'delall' : 'delete'; // Make sure the session exists and the token is correct checkSession(); validateToken('admin-bbl'); $redirect = deleteBadBehavior($type, $filter); if ($redirect === 'delete') { $start = isset($_REQUEST['start']) ? (int) $_REQUEST['start'] : 0; // Go back to where we were. redirectexit('action=admin;area=logs;sa=badbehaviorlog' . (isset($_REQUEST['desc']) ? ';desc' : '') . ';start=' . $start . (!empty($filter) ? ';filter=' . $_GET['filter'] . ';value=' . $_GET['value'] : '')); } redirectexit('action=admin;area=logs;sa=badbehaviorlog' . (isset($_REQUEST['desc']) ? ';desc' : '')); } // Just how many entries are there? $num_errors = getBadBehaviorLogEntryCount($filter); // If this filter turns up empty, just return if (empty($num_errors) && !empty($filter)) { redirectexit('action=admin;area=logs;sa=badbehaviorlog' . (isset($_REQUEST['desc']) ? ';desc' : '')); } // Clean up start. $start = !isset($_GET['start']) || $_GET['start'] < 0 ? 0 : (int) $_GET['start']; // Do we want to reverse the listing? $sort = isset($_REQUEST['desc']) ? 'down' : 'up'; // Set the page listing up. $context['page_index'] = constructPageIndex($scripturl . '?action=admin;area=logs;sa=badbehaviorlog' . ($sort == 'down' ? ';desc' : '') . (!empty($filter) ? $filter['href'] : ''), $start, $num_errors, $modSettings['defaultMaxMessages']); // Find and sort out the log entries. $context['bb_entries'] = getBadBehaviorLogEntries($start, $modSettings['defaultMaxMessages'], $sort, $filter); $members = array(); foreach ($context['bb_entries'] as $member) { $members[] = $member['member']['id']; } // Load the member data so we have more information available if (!empty($members)) { require_once SUBSDIR . '/Members.subs.php'; $members = getBasicMemberData($members, array('add_guest' => true)); // Go through each entry and add the member data. foreach ($context['bb_entries'] as $id => $dummy) { $memID = $context['bb_entries'][$id]['member']['id']; $context['bb_entries'][$id]['member']['username'] = $members[$memID]['member_name']; $context['bb_entries'][$id]['member']['name'] = $members[$memID]['real_name']; $context['bb_entries'][$id]['member']['href'] = empty($memID) ? '' : $scripturl . '?action=profile;u=' . $memID; $context['bb_entries'][$id]['member']['link'] = empty($memID) ? $txt['guest_title'] : '<a href="' . $scripturl . '?action=profile;u=' . $memID . '">' . $context['bb_entries'][$id]['member']['name'] . '</a>'; } } // Filtering? if (!empty($filter)) { $context['filter'] = $filter; // Set the filtering context. if ($filter['variable'] === 'id_member') { $id = $filter['value']['sql']; loadMemberData($id, false, 'minimal'); $context['filter']['value']['html'] = '<a href="' . $scripturl . '?action=profile;u=' . $id . '">' . $user_profile[$id]['real_name'] . '</a>'; } elseif ($filter['variable'] === 'url') { $context['filter']['value']['html'] = '\'' . strtr(htmlspecialchars((substr($filter['value']['sql'], 0, 1) === '?' ? $scripturl : '') . $filter['value']['sql'], ENT_COMPAT, 'UTF-8'), array('\\_' => '_')) . '\''; } elseif ($filter['variable'] === 'headers') { $context['filter']['value']['html'] = '\'' . strtr(htmlspecialchars($filter['value']['sql'], ENT_COMPAT, 'UTF-8'), array("\n" => '<br />', '<br />' => '<br />', "\t" => ' ', '\\_' => '_', '\\%' => '%', '\\\\' => '\\')) . '\''; $context['filter']['value']['html'] = preg_replace('~&lt;span class=&quot;remove&quot;&gt;(.+?)&lt;/span&gt;~', '$1', $context['filter']['value']['html']); } else { $context['filter']['value']['html'] = $filter['value']['sql']; } } // And the standard template goodies $context['page_title'] = $txt['badbehaviorlog_log']; $context['has_filter'] = !empty($filter); $context['sub_template'] = 'badbehavior_log'; $context['sort_direction'] = $sort; $context['start'] = $start; createToken('admin-bbl'); }
/** * Returns member data for a given member id in a suggestion format used by bans * * @package Bans * @uses getBasicMemberData * @param int $id */ function getMemberData($id) { $suggestions = array(); require_once SUBSDIR . '/Members.subs.php'; $result = getBasicMemberData($id, array('moderation' => true)); if (!empty($result)) { $suggestions = array('member' => array('id' => $result['id_member'], 'name' => $result['real_name']), 'main_ip' => $result['member_ip'], 'email' => $result['email_address']); } return $suggestions; }
/** * Verify the answer to the secret question. * Accessed with sa=secret2 */ public function action_secret2() { global $txt, $context; checkSession(); validateToken('remind-sai'); // Hacker? How did you get this far without an email or username? if (empty($_REQUEST['uid'])) { fatal_lang_error('username_no_exist', false); } loadLanguage('Login'); // Get the information from the database. require_once SUBSDIR . '/Members.subs.php'; $member = getBasicMemberData((int) $_REQUEST['uid'], array('authentication' => true)); if (empty($member)) { fatal_lang_error('username_no_exist', false); } // Check if the secret answer is correct. if ($member['secret_question'] == '' || $member['secret_answer'] == '' || md5($_POST['secret_answer']) !== $member['secret_answer']) { log_error(sprintf($txt['reminder_error'], $member['member_name']), 'user'); fatal_lang_error('incorrect_answer', false); } // If it's OpenID this is where the music ends. if (!empty($member['openid_uri'])) { $context['sub_template'] = 'sent'; $context['description'] = sprintf($txt['reminder_openid_is'], $member['openid_uri']); return; } // You can't use a blank one! if (strlen(trim($_POST['passwrd1'])) === 0) { fatal_lang_error('no_password', false); } // They have to be the same too. if ($_POST['passwrd1'] != $_POST['passwrd2']) { fatal_lang_error('passwords_dont_match', false); } // Make sure they have a strong enough password. require_once SUBSDIR . '/Auth.subs.php'; $passwordError = validatePassword($_POST['passwrd1'], $member['member_name'], array($member['email_address'])); // Invalid? if ($passwordError != null) { fatal_lang_error('profile_error_password_' . $passwordError, false); } // Alright, so long as 'yer sure. require_once SUBSDIR . '/Auth.subs.php'; $sha_passwd = $_POST['passwrd1']; updateMemberData($member['id_member'], array('passwd' => validateLoginPassword($sha_passwd, '', $member['member_name'], true))); call_integration_hook('integrate_reset_pass', array($member['member_name'], $member['member_name'], $_POST['passwrd1'])); // Tell them it went fine. loadTemplate('Login'); loadJavascriptFile('sha256.js', array('defer' => true)); $context += array('page_title' => $txt['reminder_password_set'], 'sub_template' => 'login', 'default_username' => $member['member_name'], 'default_password' => $_POST['passwrd1'], 'never_expire' => false, 'description' => $txt['reminder_password_set']); createToken('login'); }
/** * This simple function gets a list of all administrators and sends them an email * to let them know a new member has joined. * Called by registerMember() function in subs/Members.subs.php. * Email is sent to all groups that have the moderate_forum permission. * The language set by each member is being used (if available). * * @param string $type types supported are 'approval', 'activation', and 'standard'. * @param int $memberID * @param string|null $member_name = null * @uses the Login language file. */ function sendAdminNotifications($type, $memberID, $member_name = null) { global $modSettings, $language, $scripturl, $user_info; $db = database(); // If the setting isn't enabled then just exit. if (empty($modSettings['notify_new_registration'])) { return; } // Needed to notify admins, or anyone require_once SUBSDIR . '/Mail.subs.php'; if ($member_name == null) { require_once SUBSDIR . '/Members.subs.php'; // Get the new user's name.... $member_info = getBasicMemberData($memberID); $member_name = $member_info['real_name']; } $groups = array(); // All membergroups who can approve members. $request = $db->query('', ' SELECT id_group FROM {db_prefix}permissions WHERE permission = {string:moderate_forum} AND add_deny = {int:add_deny} AND id_group != {int:id_group}', array('add_deny' => 1, 'id_group' => 0, 'moderate_forum' => 'moderate_forum')); while ($row = $db->fetch_assoc($request)) { $groups[] = $row['id_group']; } $db->free_result($request); // Add administrators too... $groups[] = 1; $groups = array_unique($groups); // Get a list of all members who have ability to approve accounts - these are the people who we inform. $request = $db->query('', ' SELECT id_member, lngfile, email_address FROM {db_prefix}members WHERE (id_group IN ({array_int:group_list}) OR FIND_IN_SET({raw:group_array_implode}, additional_groups) != 0) AND notify_types != {int:notify_types} ORDER BY lngfile', array('group_list' => $groups, 'notify_types' => 4, 'group_array_implode' => implode(', additional_groups) != 0 OR FIND_IN_SET(', $groups))); $current_language = $user_info['language']; while ($row = $db->fetch_assoc($request)) { $replacements = array('USERNAME' => $member_name, 'PROFILELINK' => $scripturl . '?action=profile;u=' . $memberID); $emailtype = 'admin_notify'; // If they need to be approved add more info... if ($type == 'approval') { $replacements['APPROVALLINK'] = $scripturl . '?action=admin;area=viewmembers;sa=browse;type=approve'; $emailtype .= '_approval'; } $emaildata = loadEmailTemplate($emailtype, $replacements, empty($row['lngfile']) || empty($modSettings['userLanguage']) ? $language : $row['lngfile']); // And do the actual sending... sendmail($row['email_address'], $emaildata['subject'], $emaildata['body'], null, null, false, 0); } $db->free_result($request); if (isset($current_language) && $current_language != $user_info['language']) { loadLanguage('Login'); } }
/** * Send the emails. * * - Sends off emails to all the moderators. * - Sends to administrators and global moderators. (1 and 2) * - Called by action_reporttm(), and thus has the same permission and setting requirements as it does. * - Accessed through ?action=reporttm when posting. */ public function action_reporttm2() { global $txt, $scripturl, $topic, $board, $user_info, $modSettings, $language, $context; // You must have the proper permissions! isAllowedTo('report_any'); // Make sure they aren't spamming. spamProtection('reporttm'); require_once SUBSDIR . '/Mail.subs.php'; // No errors, yet. $report_errors = Error_Context::context('report', 1); // Check their session. if (checkSession('post', '', false) != '') { $report_errors->addError('session_timeout'); } // Make sure we have a comment and it's clean. if (!isset($_POST['comment']) || Util::htmltrim($_POST['comment']) === '') { $report_errors->addError('no_comment'); } $poster_comment = strtr(Util::htmlspecialchars($_POST['comment']), array("\r" => '', "\t" => '')); if (Util::strlen($poster_comment) > 254) { $report_errors->addError('post_too_long'); } // Guests need to provide their address! if ($user_info['is_guest']) { require_once SUBSDIR . '/DataValidator.class.php'; if (!Data_Validator::is_valid($_POST, array('email' => 'valid_email'), array('email' => 'trim'))) { empty($_POST['email']) ? $report_errors->addError('no_email') : $report_errors->addError('bad_email'); } isBannedEmail($_POST['email'], 'cannot_post', sprintf($txt['you_are_post_banned'], $txt['guest_title'])); $user_info['email'] = htmlspecialchars($_POST['email'], ENT_COMPAT, 'UTF-8'); } // Could they get the right verification code? if ($user_info['is_guest'] && !empty($modSettings['guests_report_require_captcha'])) { require_once SUBSDIR . '/VerificationControls.class.php'; $verificationOptions = array('id' => 'report'); $context['require_verification'] = create_control_verification($verificationOptions, true); if (is_array($context['require_verification'])) { foreach ($context['require_verification'] as $error) { $report_errors->addError($error, 0); } } } // Any errors? if ($report_errors->hasErrors()) { return $this->action_reporttm(); } // Get the basic topic information, and make sure they can see it. $msg_id = (int) $_POST['msg']; $message = posterDetails($msg_id, $topic); if (empty($message)) { fatal_lang_error('no_board', false); } $poster_name = un_htmlspecialchars($message['real_name']) . ($message['real_name'] != $message['poster_name'] ? ' (' . $message['poster_name'] . ')' : ''); $reporterName = un_htmlspecialchars($user_info['name']) . ($user_info['name'] != $user_info['username'] && $user_info['username'] != '' ? ' (' . $user_info['username'] . ')' : ''); $subject = un_htmlspecialchars($message['subject']); // Get a list of members with the moderate_board permission. require_once SUBSDIR . '/Members.subs.php'; $moderators = membersAllowedTo('moderate_board', $board); $result = getBasicMemberData($moderators, array('preferences' => true, 'sort' => 'lngfile')); $mod_to_notify = array(); foreach ($result as $row) { if ($row['notify_types'] != 4) { $mod_to_notify[] = $row; } } // Check that moderators do exist! if (empty($mod_to_notify)) { fatal_lang_error('no_mods', false); } // If we get here, I believe we should make a record of this, for historical significance, yabber. if (empty($modSettings['disable_log_report'])) { require_once SUBSDIR . '/Messages.subs.php'; $id_report = recordReport($message, $poster_comment); // If we're just going to ignore these, then who gives a monkeys... if ($id_report === false) { redirectexit('topic=' . $topic . '.msg' . $msg_id . '#msg' . $msg_id); } } // Find out who the real moderators are - for mod preferences. require_once SUBSDIR . '/Boards.subs.php'; $real_mods = getBoardModerators($board, true); // Send every moderator an email. foreach ($mod_to_notify as $row) { // Maybe they don't want to know?! if (!empty($row['mod_prefs'])) { list(, , $pref_binary) = explode('|', $row['mod_prefs']); if (!($pref_binary & 1) && (!($pref_binary & 2) || !in_array($row['id_member'], $real_mods))) { continue; } } $replacements = array('TOPICSUBJECT' => $subject, 'POSTERNAME' => $poster_name, 'REPORTERNAME' => $reporterName, 'TOPICLINK' => $scripturl . '?topic=' . $topic . '.msg' . $msg_id . '#msg' . $msg_id, 'REPORTLINK' => !empty($id_report) ? $scripturl . '?action=moderate;area=reports;report=' . $id_report : '', 'COMMENT' => $_POST['comment']); $emaildata = loadEmailTemplate('report_to_moderator', $replacements, empty($row['lngfile']) || empty($modSettings['userLanguage']) ? $language : $row['lngfile']); // Send it to the moderator. sendmail($row['email_address'], $emaildata['subject'], $emaildata['body'], $user_info['email'], null, false, 2); } // Keep track of when the mod reports get updated, that way we know when we need to look again. updateSettings(array('last_mod_report_action' => time())); // Back to the post we reported! redirectexit('reportsent;topic=' . $topic . '.msg' . $msg_id . '#msg' . $msg_id); }
/** * This function determines the actions of the members passed in urls. * * Adding actions to the Who's Online list: * Adding actions to this list is actually relatively easy... * - for actions anyone should be able to see, just add a string named whoall_ACTION. * (where ACTION is the action used in index.php.) * - for actions that have a subaction which should be represented differently, use whoall_ACTION_SUBACTION. * - for actions that include a topic, and should be restricted, use whotopic_ACTION. * - for actions that use a message, by msg or quote, use whopost_ACTION. * - for administrator-only actions, use whoadmin_ACTION. * - for actions that should be viewable only with certain permissions, use whoallow_ACTION and * add a list of possible permissions to the $allowedActions array, using ACTION as the key. * * @param mixed[]|string $urls a single url (string) or an array of arrays, each inner array being (serialized request data, id_member) * @param string|false $preferred_prefix = false * @return mixed[]|string an array of descriptions if you passed an array, otherwise the string describing their current location. */ function determineActions($urls, $preferred_prefix = false) { global $txt, $user_info, $modSettings, $scripturl; $db = database(); if (!allowedTo('who_view')) { return array(); } loadLanguage('Who'); // Actions that require a specific permission level. $allowedActions = array('admin' => array('moderate_forum', 'manage_membergroups', 'manage_bans', 'admin_forum', 'manage_permissions', 'send_mail', 'manage_attachments', 'manage_smileys', 'manage_boards', 'edit_news'), 'ban' => array('manage_bans'), 'boardrecount' => array('admin_forum'), 'calendar' => array('calendar_view'), 'editnews' => array('edit_news'), 'mailing' => array('send_mail'), 'maintain' => array('admin_forum'), 'manageattachments' => array('manage_attachments'), 'manageboards' => array('manage_boards'), 'memberlist' => array('view_mlist'), 'moderate' => array('access_mod_center', 'moderate_forum', 'manage_membergroups'), 'optimizetables' => array('admin_forum'), 'repairboards' => array('admin_forum'), 'search' => array('search_posts'), 'setcensor' => array('moderate_forum'), 'setreserve' => array('moderate_forum'), 'stats' => array('view_stats'), 'viewErrorLog' => array('admin_forum'), 'viewmembers' => array('moderate_forum')); // Provide integration a way to add to the allowed action array call_integration_hook('integrate_whos_online_allowed', array(&$allowedActions)); if (!is_array($urls)) { $url_list = array(array($urls, $user_info['id'])); } else { $url_list = $urls; } // These are done to query these in large chunks. (instead of one by one.) $topic_ids = array(); $profile_ids = array(); $board_ids = array(); $data = array(); foreach ($url_list as $k => $url) { // Get the request parameters.. $actions = @unserialize($url[0]); if ($actions === false) { continue; } // If it's the admin or moderation center, and there is an area set, use that instead. if (isset($actions['action']) && ($actions['action'] == 'admin' || $actions['action'] == 'moderate') && isset($actions['area'])) { $actions['action'] = $actions['area']; } // Check if there was no action or the action is display. if (!isset($actions['action']) || $actions['action'] == 'display') { // It's a topic! Must be! if (isset($actions['topic'])) { // Assume they can't view it, and queue it up for later. $data[$k] = $txt['who_hidden']; $topic_ids[(int) $actions['topic']][$k] = $txt['who_topic']; } elseif (isset($actions['board'])) { // Hide first, show later. $data[$k] = $txt['who_hidden']; $board_ids[$actions['board']][$k] = $txt['who_board']; } else { $data[$k] = replaceBasicActionUrl($txt['who_index']); } } elseif ($actions['action'] == '') { $data[$k] = replaceBasicActionUrl($txt['who_index']); } else { // Viewing/editing a profile. if ($actions['action'] == 'profile') { // Whose? Their own? if (empty($actions['u'])) { require_once SUBSDIR . '/Profile.subs.php'; $memID = currentMemberID(); if ($memID == $user_info['id']) { $actions['u'] = $url[1]; } else { $actions['u'] = $memID; } } $data[$k] = $txt['who_hidden']; $profile_ids[(int) $actions['u']][$k] = $actions['action'] == 'profile' ? $txt['who_viewprofile'] : $txt['who_profile']; } elseif (($actions['action'] == 'post' || $actions['action'] == 'post2' || $actions['action'] == 'topicbyemail') && empty($actions['topic']) && isset($actions['board'])) { $data[$k] = $txt['who_hidden']; if ($actions['action'] == 'topicbyemail') { $board_ids[(int) $actions['board']][$k] = $txt['who_topicbyemail']; } else { $board_ids[(int) $actions['board']][$k] = isset($actions['poll']) ? $txt['who_poll'] : $txt['who_post']; } } elseif (isset($actions['sa']) && isset($txt['whoall_' . $actions['action'] . '_' . $actions['sa']])) { $data[$k] = $preferred_prefix && isset($txt[$preferred_prefix . $actions['action'] . '_' . $actions['sa']]) ? $txt[$preferred_prefix . $actions['action'] . '_' . $actions['sa']] : $txt['whoall_' . $actions['action'] . '_' . $actions['sa']]; } elseif (isset($txt['whoall_' . $actions['action']])) { $data[$k] = $preferred_prefix && isset($txt[$preferred_prefix . $actions['action']]) ? $txt[$preferred_prefix . $actions['action']] : replaceBasicActionUrl($txt['whoall_' . $actions['action']]); } elseif (isset($txt['whotopic_' . $actions['action']])) { // Find out what topic they are accessing. $topic = (int) (isset($actions['topic']) ? $actions['topic'] : (isset($actions['from']) ? $actions['from'] : 0)); $data[$k] = $txt['who_hidden']; $topic_ids[$topic][$k] = $txt['whotopic_' . $actions['action']]; } elseif (isset($actions['sa']) && isset($txt['whotopic_' . $actions['action'] . '_' . $actions['sa']])) { // Find out what topic they are accessing. $topic = (int) (isset($actions['topic']) ? $actions['topic'] : (isset($actions['from']) ? $actions['from'] : 0)); $data[$k] = $txt['who_hidden']; $topic_ids[$topic][$k] = $txt['whotopic_' . $actions['action'] . '_' . $actions['sa']]; } elseif (isset($txt['whopost_' . $actions['action']])) { // Find out what message they are accessing. $msgid = (int) (isset($actions['msg']) ? $actions['msg'] : (isset($actions['quote']) ? $actions['quote'] : 0)); $result = $db->query('', ' SELECT m.id_topic, m.subject FROM {db_prefix}messages AS m INNER JOIN {db_prefix}boards AS b ON (b.id_board = m.id_board) INNER JOIN {db_prefix}topics AS t ON (t.id_topic = m.id_topic' . ($modSettings['postmod_active'] ? ' AND t.approved = {int:is_approved}' : '') . ') WHERE m.id_msg = {int:id_msg} AND {query_see_board}' . ($modSettings['postmod_active'] ? ' AND m.approved = {int:is_approved}' : '') . ' LIMIT 1', array('is_approved' => 1, 'id_msg' => $msgid)); list($id_topic, $subject) = $db->fetch_row($result); $data[$k] = sprintf($txt['whopost_' . $actions['action']], $scripturl . '?topic=' . $id_topic . '.0', $subject); $db->free_result($result); if (empty($id_topic)) { $data[$k] = $txt['who_hidden']; } } elseif (allowedTo('moderate_forum') && isset($txt['whoadmin_' . $actions['action']])) { $data[$k] = $txt['whoadmin_' . $actions['action']]; } elseif (isset($allowedActions[$actions['action']])) { if (allowedTo($allowedActions[$actions['action']])) { if (isset($actions['sa']) && isset($txt['whoallow_' . $actions['action'] . '_' . $actions['sa']])) { $data[$k] = replaceBasicActionUrl($txt['whoallow_' . $actions['action'] . '_' . $actions['sa']]); } else { $data[$k] = replaceBasicActionUrl($txt['whoallow_' . $actions['action']]); } } elseif (in_array('moderate_forum', $allowedActions[$actions['action']])) { $data[$k] = $txt['who_moderate']; } elseif (in_array('admin_forum', $allowedActions[$actions['action']])) { $data[$k] = $txt['who_admin']; } else { $data[$k] = $txt['who_hidden']; } } elseif (!empty($actions['action'])) { $data[$k] = sprintf($txt['who_generic'], $actions['action']); } else { $data[$k] = $txt['who_unknown']; } } // Maybe the action is integrated into another system? if (count($integrate_actions = call_integration_hook('integrate_whos_online', array($actions))) > 0) { // Try each integraion hook with this url and see if they can fill in the details foreach ($integrate_actions as $integrate_action) { if (!empty($integrate_action)) { // Found it, all done then $data[$k] = $integrate_action; break; } } } } // Load topic names. if (!empty($topic_ids)) { require_once SUBSDIR . '/Topic.subs.php'; $topics_data = topicsList(array_keys($topic_ids)); foreach ($topics_data as $topic) { // Show the topic's subject for each of the members looking at this... foreach ($topic_ids[$topic['id_topic']] as $k => $session_text) { $data[$k] = sprintf($session_text, $scripturl . '?topic=' . $topic['id_topic'] . '.0', $topic['subject']); } } } // Load board names. if (!empty($board_ids)) { require_once SUBSDIR . '/Boards.subs.php'; $boards_list = getBoardList(array('included_boards' => array_keys($board_ids)), true); foreach ($boards_list as $board) { // Put the board name into the string for each member... foreach ($board_ids[$board['id_board']] as $k => $session_text) { $data[$k] = sprintf($session_text, $scripturl . '?board=' . $board['id_board'] . '.0', $board['board_name']); } } } // Load member names for the profile. if (!empty($profile_ids) && (allowedTo('profile_view_any') || allowedTo('profile_view_own'))) { require_once SUBSDIR . '/Members.subs.php'; $result = getBasicMemberData(array_keys($profile_ids)); foreach ($result as $row) { // If they aren't allowed to view this person's profile, skip it. if (!allowedTo('profile_view_any') && $user_info['id'] != $row['id_member']) { continue; } // Set their action on each - session/text to sprintf. foreach ($profile_ids[$row['id_member']] as $k => $session_text) { $data[$k] = sprintf($session_text, $scripturl . '?action=profile;u=' . $row['id_member'], $row['real_name']); } } } if (!is_array($urls)) { return isset($data[0]) ? $data[0] : false; } else { return $data; } }
/** * Gets the moderation log entries that match the specified parameters. * Callback for createList() in Modlog::action_log(). * * @param int $start * @param int $items_per_page * @param string $sort * @param string|null $query_string * @param mixed[] $query_params * @param int $log_type */ function list_getModLogEntries($start, $items_per_page, $sort, $query_string = '', $query_params = array(), $log_type = 1) { global $context, $scripturl, $txt, $user_info; $db = database(); $modlog_query = allowedTo('admin_forum') || $user_info['mod_cache']['bq'] == '1=1' ? '1=1' : ($user_info['mod_cache']['bq'] == '0=1' ? 'lm.id_board = 0 AND lm.id_topic = 0' : strtr($user_info['mod_cache']['bq'], array('id_board' => 'b.id_board')) . ' AND ' . strtr($user_info['mod_cache']['bq'], array('id_board' => 't.id_board'))); // Do a little bit of self protection. if (!isset($context['hoursdisable'])) { $context['hoursdisable'] = 24; } // Can they see the IP address? $seeIP = allowedTo('moderate_forum'); // Here we have the query getting the log details. $result = $db->query('', ' SELECT lm.id_action, lm.id_member, lm.ip, lm.log_time, lm.action, lm.id_board, lm.id_topic, lm.id_msg, lm.extra, mem.real_name, mg.group_name FROM {db_prefix}log_actions AS lm LEFT JOIN {db_prefix}members AS mem ON (mem.id_member = lm.id_member) LEFT JOIN {db_prefix}membergroups AS mg ON (mg.id_group = CASE WHEN mem.id_group = {int:reg_group_id} THEN mem.id_post_group ELSE mem.id_group END) LEFT JOIN {db_prefix}boards AS b ON (b.id_board = lm.id_board) LEFT JOIN {db_prefix}topics AS t ON (t.id_topic = lm.id_topic) WHERE id_log = {int:log_type} AND {raw:modlog_query}' . (!empty($query_string) ? ' AND ' . $query_string : '') . ' ORDER BY ' . $sort . ' LIMIT ' . $start . ', ' . $items_per_page, array_merge($query_params, array('reg_group_id' => 0, 'log_type' => $log_type, 'modlog_query' => $modlog_query))); // Arrays for decoding objects into. $topics = array(); $boards = array(); $members = array(); $messages = array(); $entries = array(); while ($row = $db->fetch_assoc($result)) { $row['extra'] = @unserialize($row['extra']); // Corrupt? $row['extra'] = is_array($row['extra']) ? $row['extra'] : array(); // Add on some of the column stuff info if (!empty($row['id_board'])) { if ($row['action'] == 'move') { $row['extra']['board_to'] = $row['id_board']; } else { $row['extra']['board'] = $row['id_board']; } } if (!empty($row['id_topic'])) { $row['extra']['topic'] = $row['id_topic']; } if (!empty($row['id_msg'])) { $row['extra']['message'] = $row['id_msg']; } // Is this associated with a topic? if (isset($row['extra']['topic'])) { $topics[(int) $row['extra']['topic']][] = $row['id_action']; } if (isset($row['extra']['new_topic'])) { $topics[(int) $row['extra']['new_topic']][] = $row['id_action']; } // How about a member? if (isset($row['extra']['member'])) { // Guests don't have names! if (empty($row['extra']['member'])) { $row['extra']['member'] = $txt['modlog_parameter_guest']; } else { // Try to find it... $members[(int) $row['extra']['member']][] = $row['id_action']; } } // Associated with a board? if (isset($row['extra']['board_to'])) { $boards[(int) $row['extra']['board_to']][] = $row['id_action']; } if (isset($row['extra']['board_from'])) { $boards[(int) $row['extra']['board_from']][] = $row['id_action']; } if (isset($row['extra']['board'])) { $boards[(int) $row['extra']['board']][] = $row['id_action']; } // A message? if (isset($row['extra']['message'])) { $messages[(int) $row['extra']['message']][] = $row['id_action']; } // IP Info? if (isset($row['extra']['ip_range'])) { if ($seeIP) { $row['extra']['ip_range'] = '<a href="' . $scripturl . '?action=trackip;searchip=' . $row['extra']['ip_range'] . '">' . $row['extra']['ip_range'] . '</a>'; } else { $row['extra']['ip_range'] = $txt['logged']; } } // Email? if (isset($row['extra']['email'])) { $row['extra']['email'] = '<a href="mailto:' . $row['extra']['email'] . '">' . $row['extra']['email'] . '</a>'; } // Bans are complex. if ($row['action'] == 'ban') { if (!isset($row['extra']['new']) || $row['extra']['new'] == 1) { $row['action_text'] = $txt['modlog_ac_ban']; } elseif ($row['extra']['new'] == 0) { $row['action_text'] = $txt['modlog_ac_ban_update']; } else { $row['action_text'] = $txt['modlog_ac_ban_remove']; } foreach (array('member', 'email', 'ip_range', 'hostname') as $type) { if (isset($row['extra'][$type])) { $row['action_text'] .= $txt['modlog_ac_ban_trigger_' . $type]; } } } // The array to go to the template. Note here that action is set to a "default" value of the action doesn't match anything in the descriptions. Allows easy adding of logging events with basic details. $entries[$row['id_action']] = array('id' => $row['id_action'], 'ip' => $seeIP ? $row['ip'] : $txt['logged'], 'position' => empty($row['real_name']) && empty($row['group_name']) ? $txt['guest'] : $row['group_name'], 'moderator_link' => $row['id_member'] ? '<a href="' . $scripturl . '?action=profile;u=' . $row['id_member'] . '">' . $row['real_name'] . '</a>' : (empty($row['real_name']) ? $txt['guest'] . (!empty($row['extra']['member_acted']) ? ' (' . $row['extra']['member_acted'] . ')' : '') : $row['real_name']), 'time' => standardTime($row['log_time']), 'html_time' => htmlTime($row['log_time']), 'timestamp' => forum_time(true, $row['log_time']), 'editable' => time() > $row['log_time'] + $context['hoursdisable'] * 3600, 'extra' => $row['extra'], 'action' => $row['action'], 'action_text' => isset($row['action_text']) ? $row['action_text'] : ''); } $db->free_result($result); if (!empty($boards)) { require_once SUBSDIR . '/Boards.subs.php'; $boards_info = fetchBoardsInfo(array('boards' => array_keys($boards))); foreach ($boards_info as $row) { foreach ($boards[$row['id_board']] as $action) { // Make the board number into a link - dealing with moving too. if (isset($entries[$action]['extra']['board_to']) && $entries[$action]['extra']['board_to'] == $row['id_board']) { $entries[$action]['extra']['board_to'] = '<a href="' . $scripturl . '?board=' . $row['id_board'] . '.0">' . $row['name'] . '</a>'; } elseif (isset($entries[$action]['extra']['board_from']) && $entries[$action]['extra']['board_from'] == $row['id_board']) { $entries[$action]['extra']['board_from'] = '<a href="' . $scripturl . '?board=' . $row['id_board'] . '.0">' . $row['name'] . '</a>'; } elseif (isset($entries[$action]['extra']['board']) && $entries[$action]['extra']['board'] == $row['id_board']) { $entries[$action]['extra']['board'] = '<a href="' . $scripturl . '?board=' . $row['id_board'] . '.0">' . $row['name'] . '</a>'; } } } } if (!empty($topics)) { $request = $db->query('', ' SELECT ms.subject, t.id_topic FROM {db_prefix}topics AS t INNER JOIN {db_prefix}messages AS ms ON (ms.id_msg = t.id_first_msg) WHERE t.id_topic IN ({array_int:topic_list}) LIMIT ' . count(array_keys($topics)), array('topic_list' => array_keys($topics))); while ($row = $db->fetch_assoc($request)) { foreach ($topics[$row['id_topic']] as $action) { $this_action =& $entries[$action]; // This isn't used in the current theme. $this_action['topic'] = array('id' => $row['id_topic'], 'subject' => $row['subject'], 'href' => $scripturl . '?topic=' . $row['id_topic'] . '.0', 'link' => '<a href="' . $scripturl . '?topic=' . $row['id_topic'] . '.0">' . $row['subject'] . '</a>'); // Make the topic number into a link - dealing with splitting too. if (isset($this_action['extra']['topic']) && $this_action['extra']['topic'] == $row['id_topic']) { $this_action['extra']['topic'] = '<a href="' . $scripturl . '?topic=' . $row['id_topic'] . '.' . (isset($this_action['extra']['message']) ? 'msg' . $this_action['extra']['message'] . '#msg' . $this_action['extra']['message'] : '0') . '">' . $row['subject'] . '</a>'; } elseif (isset($this_action['extra']['new_topic']) && $this_action['extra']['new_topic'] == $row['id_topic']) { $this_action['extra']['new_topic'] = '<a href="' . $scripturl . '?topic=' . $row['id_topic'] . '.' . (isset($this_action['extra']['message']) ? 'msg' . $this_action['extra']['message'] . '#msg' . $this_action['extra']['message'] : '0') . '">' . $row['subject'] . '</a>'; } } } $db->free_result($request); } if (!empty($messages)) { $request = $db->query('', ' SELECT id_msg, subject FROM {db_prefix}messages WHERE id_msg IN ({array_int:message_list}) LIMIT ' . count(array_keys($messages)), array('message_list' => array_keys($messages))); while ($row = $db->fetch_assoc($request)) { foreach ($messages[$row['id_msg']] as $action) { $this_action =& $entries[$action]; // This isn't used in the current theme. $this_action['message'] = array('id' => $row['id_msg'], 'subject' => $row['subject'], 'href' => $scripturl . '?msg=' . $row['id_msg'], 'link' => '<a href="' . $scripturl . '?msg=' . $row['id_msg'] . '">' . $row['subject'] . '</a>'); // Make the message number into a link. if (isset($this_action['extra']['message']) && $this_action['extra']['message'] == $row['id_msg']) { $this_action['extra']['message'] = '<a href="' . $scripturl . '?msg=' . $row['id_msg'] . '">' . $row['subject'] . '</a>'; } } } $db->free_result($request); } if (!empty($members)) { require_once SUBSDIR . '/Members.subs.php'; // Get the latest activated member's display name. $result = getBasicMemberData(array_keys($members)); foreach ($result as $row) { foreach ($members[$row['id_member']] as $action) { // Not used currently. $entries[$action]['member'] = array('id' => $row['id_member'], 'name' => $row['real_name'], 'href' => $scripturl . '?action=profile;u=' . $row['id_member'], 'link' => '<a href="' . $scripturl . '?action=profile;u=' . $row['id_member'] . '">' . $row['real_name'] . '</a>'); // Make the member number into a name. $entries[$action]['extra']['member'] = '<a href="' . $scripturl . '?action=profile;u=' . $row['id_member'] . '">' . $row['real_name'] . '</a>'; } } } // Do some formatting of the action string. $callback = new ModLogEntriesReplacement(); $callback->entries = $entries; foreach ($entries as $k => $entry) { // Make any message info links so its easier to go find that message. if (isset($entry['extra']['message']) && (empty($entry['message']) || empty($entry['message']['id']))) { $entries[$k]['extra']['message'] = '<a href="' . $scripturl . '?msg=' . $entry['extra']['message'] . '">' . $entry['extra']['message'] . '</a>'; } // Mark up any deleted members, topics and boards. foreach (array('board', 'board_from', 'board_to', 'member', 'topic', 'new_topic') as $type) { if (!empty($entry['extra'][$type]) && is_numeric($entry['extra'][$type])) { $entries[$k]['extra'][$type] = sprintf($txt['modlog_id'], $entry['extra'][$type]); } } if (empty($entries[$k]['action_text'])) { $entries[$k]['action_text'] = isset($txt['modlog_ac_' . $entry['action']]) ? $txt['modlog_ac_' . $entry['action']] : $entry['action']; } $callback->key = $k; $entries[$k]['action_text'] = preg_replace_callback('~\\{([A-Za-z\\d_]+)\\}~i', array($callback, 'callback'), $entries[$k]['action_text']); } // Back we go! return $entries; }