Example #1
0
    /**
     * Re-syncs if a user can access a mention,
     *
     * - for example if they loose or gain access to a board, this will correct
     * the viewing of the mention table.  Since this can be a large job it is run
     * as a scheduled immediate task
     */
    public function user_access_mentions()
    {
        global $modSettings;
        $db = database();
        $user_access_mentions = @unserialize($modSettings['user_access_mentions']);
        // This should be set only because of an immediate scheduled task, so higher priority
        if (!empty($user_access_mentions)) {
            foreach ($user_access_mentions as $member => $begin) {
                // Just to stay on the safe side...
                if (empty($member)) {
                    continue;
                }
                require_once SUBSDIR . '/Boards.subs.php';
                require_once SUBSDIR . '/Mentions.subs.php';
                require_once SUBSDIR . '/Members.subs.php';
                $user_see_board = memberQuerySeeBoard($member);
                $limit = 100;
                // We need to repeat this twice: once to find the boards the user can access,
                // once for those he cannot access
                foreach (array('can', 'cannot') as $can) {
                    // Let's always start from the begin
                    $start = $begin;
                    while (true) {
                        // Find all the mentions that this user can or cannot see
                        $request = $db->query('', '
							SELECT mnt.id_mention, m.id_board
							FROM {db_prefix}log_mentions as mnt
								LEFT JOIN {db_prefix}messages AS m ON (m.id_msg = mnt.id_msg)
								LEFT JOIN {db_prefix}boards AS b ON (b.id_board = m.id_board)
							WHERE mnt.id_member = {int:current_member}
								AND mnt.mention_type IN ({array_string:mention_types})
								AND {raw:user_see_board}
							LIMIT {int:start}, {int:limit}', array('current_member' => $member, 'mention_types' => array('men', 'like', 'rlike'), 'user_see_board' => ($can == 'can' ? '' : 'NOT ') . $user_see_board, 'start' => $start, 'limit' => $limit));
                        $mentions = array();
                        $remove = array();
                        while ($row = $db->fetch_assoc($request)) {
                            if (empty($row['id_board'])) {
                                $remove[] = $row['id_mention'];
                            } else {
                                $mentions[] = $row['id_mention'];
                            }
                        }
                        $db->free_result($request);
                        if (!empty($remove)) {
                            removeMentions($remove);
                        }
                        // If we found something toggle them and increment the start for the next round
                        if (!empty($mentions)) {
                            toggleMentionsAccessibility($mentions, $can == 'can');
                        } else {
                            break;
                        }
                        // Next batch
                        $start += $limit;
                    }
                }
                // Drop the member
                unset($user_access_mentions[$member]);
                // And save everything for the next run
                updateSettings(array('user_access_mentions' => serialize($user_access_mentions)));
                // Count helps keep things correct
                countUserMentions(false, '', $member);
                // Run this only once for each user, it may be quite heavy, let's split up the load
                break;
            }
            // If there are no more users, scheduleTaskImmediate can be stopped
            if (empty($user_access_mentions)) {
                removeScheduleTaskImmediate('user_access_mentions', false);
            }
            return true;
        } else {
            // Checks 10 users at a time, the scheduled task is set to run once per hour, so 240 users a day
            // @todo <= I know you like it Spuds! :P It may be necessary to set it to something higher.
            $limit = 10;
            $current_check = !empty($modSettings['mentions_member_check']) ? $modSettings['mentions_member_check'] : 0;
            require_once SUBSDIR . '/Members.subs.php';
            require_once SUBSDIR . '/Mentions.subs.php';
            // Grab users with mentions
            $request = $db->query('', '
				SELECT COUNT(DISTINCT(id_member))
				FROM {db_prefix}log_mentions
				WHERE id_member > {int:last_id_member}
					AND mention_type IN ({array_string:mention_types})', array('last_id_member' => $current_check, 'mention_types' => array('men', 'like', 'rlike')));
            list($remaining) = $db->fetch_row($request);
            $db->free_result($request);
            if ($remaining == 0) {
                $current_check = 0;
            }
            // Grab users with mentions
            $request = $db->query('', '
				SELECT DISTINCT(id_member) as id_member
				FROM {db_prefix}log_mentions
				WHERE id_member > {int:last_id_member}
					AND mention_type IN ({array_string:mention_types})
				LIMIT {int:limit}', array('last_id_member' => $current_check, 'mention_types' => array('men', 'like', 'rlike'), 'limit' => $limit));
            // Remember where we are
            updateSettings(array('mentions_member_check' => $current_check + $limit));
            while ($row = $db->fetch_assoc($request)) {
                // Rebuild 'query_see_board', a lot of code duplication... :(
                $user_see_board = memberQuerySeeBoard($row['id_member']);
                // Find out if this user cannot see something that was supposed to be able to see
                $request2 = $db->query('', '
					SELECT mnt.id_mention
					FROM {db_prefix}log_mentions as mnt
						LEFT JOIN {db_prefix}messages AS m ON (m.id_msg = mnt.id_msg)
						LEFT JOIN {db_prefix}boards AS b ON (b.id_board = m.id_board)
					WHERE mnt.id_member = {int:current_member}
						AND mnt.mention_type IN ({array_string:mention_types})
						AND {raw:user_see_board}
						AND status < 0
					LIMIT 1', array('current_member' => $row['id_member'], 'mention_types' => array('men', 'like', 'rlike'), 'user_see_board' => 'NOT ' . $user_see_board));
                // One row of results is enough: scheduleTaskImmediate!
                if ($db->num_rows($request2) == 1) {
                    if (!empty($modSettings['user_access_mentions'])) {
                        $modSettings['user_access_mentions'] = @unserialize($modSettings['user_access_mentions']);
                    } else {
                        $modSettings['user_access_mentions'] = array();
                    }
                    // But if the member is already on the list, let's skip it
                    if (!isset($modSettings['user_access_mentions'][$row['id_member']])) {
                        $modSettings['user_access_mentions'][$row['id_member']] = 0;
                        updateSettings(array('user_access_mentions' => serialize(array_unique($modSettings['user_access_mentions']))));
                        scheduleTaskImmediate('user_access_mentions');
                    }
                }
                $db->free_result($request2);
            }
            $db->free_result($request);
            return true;
        }
    }
Example #2
0
/**
 * Calls the supplied task_name so that it is executed.
 *
 * - Logs that the task was executed with success or if it failed
 *
 * @package ScheduledTasks
 * @param int $id_task specific id of the task to run, used for logging
 * @param string $task_name name of the task, class name, function name, method in ScheduledTask.class
 */
function run_this_task($id_task, $task_name)
{
    global $time_start, $modSettings;
    // Let's start logging the task and saying we failed it
    $log_task_id = logTask(0, $id_task);
    // The method must exist in ScheduledTask class, or we are wasting our time.
    // Actually for extendability sake, we need to have other ways, so:
    // A simple procedural function?
    if (strpos($task_name, '::') === false && function_exists($task_name)) {
        $method = $task_name;
        // Do the task...
        $completed = $method();
    } else {
        // It may be a custom one
        if (strpos($task_name, '::') !== false) {
            $call = explode('::', $task_name);
            $task_object = new $call[0]();
            $method = $call[1];
        } else {
            $task_object = new Scheduled_Task();
            $method = $task_name;
        }
        if (method_exists($task_object, $method)) {
            // Try to stop a timeout, this would be bad...
            @set_time_limit(300);
            if (function_exists('apache_reset_timeout')) {
                @apache_reset_timeout();
            }
            // Do the task...
            $completed = $task_object->{$method}();
        }
    }
    // Log that we did it ;)
    if ($completed) {
        // Taking care of scheduleTaskImmediate having a maximum of 10 "fast" executions
        $scheduleTaskImmediate = @unserialize($modSettings['scheduleTaskImmediate']);
        if (!empty($scheduleTaskImmediate) && isset($scheduleTaskImmediate[$task_name])) {
            $scheduleTaskImmediate[$task_name]++;
            if ($scheduleTaskImmediate[$task_name] > 9) {
                removeScheduleTaskImmediate($task_name, false);
            } else {
                updateSettings(array('scheduleTaskImmediate' => serialize($scheduleTaskImmediate)));
            }
        }
        $total_time = round(microtime(true) - $time_start, 3);
        // If the task ended successfully, then log the proper time taken to complete
        logTask($log_task_id, $id_task, $total_time);
    }
}