Esempio n. 1
0
function qa_recalc_perform_step(&$state)
{
    $continue = false;
    @(list($operation, $length, $next, $done) = explode("\t", $state));
    switch ($operation) {
        case 'doreindexcontent':
            qa_recalc_transition($state, 'doreindexcontent_pagereindex');
            break;
        case 'doreindexcontent_pagereindex':
            $pages = qa_db_pages_get_for_reindexing($next, 10);
            if (count($pages)) {
                require_once QA_INCLUDE_DIR . 'app/format.php';
                $lastpageid = max(array_keys($pages));
                foreach ($pages as $pageid => $page) {
                    if (!($page['flags'] & QA_PAGE_FLAGS_EXTERNAL)) {
                        $searchmodules = qa_load_modules_with('search', 'unindex_page');
                        foreach ($searchmodules as $searchmodule) {
                            $searchmodule->unindex_page($pageid);
                        }
                        $searchmodules = qa_load_modules_with('search', 'index_page');
                        if (count($searchmodules)) {
                            $indextext = qa_viewer_text($page['content'], 'html');
                            foreach ($searchmodules as $searchmodule) {
                                $searchmodule->index_page($pageid, $page['tags'], $page['heading'], $page['content'], 'html', $indextext);
                            }
                        }
                    }
                }
                $next = 1 + $lastpageid;
                $done += count($pages);
                $continue = true;
            } else {
                qa_recalc_transition($state, 'doreindexcontent_postcount');
            }
            break;
        case 'doreindexcontent_postcount':
            qa_db_qcount_update();
            qa_db_acount_update();
            qa_db_ccount_update();
            qa_recalc_transition($state, 'doreindexcontent_postreindex');
            break;
        case 'doreindexcontent_postreindex':
            $posts = qa_db_posts_get_for_reindexing($next, 10);
            if (count($posts)) {
                require_once QA_INCLUDE_DIR . 'app/format.php';
                $lastpostid = max(array_keys($posts));
                qa_db_prepare_for_reindexing($next, $lastpostid);
                qa_suspend_update_counts();
                foreach ($posts as $postid => $post) {
                    qa_post_unindex($postid);
                    qa_post_index($postid, $post['type'], $post['questionid'], $post['parentid'], $post['title'], $post['content'], $post['format'], qa_viewer_text($post['content'], $post['format']), $post['tags'], $post['categoryid']);
                }
                $next = 1 + $lastpostid;
                $done += count($posts);
                $continue = true;
            } else {
                qa_db_truncate_indexes($next);
                qa_recalc_transition($state, 'doreindexposts_wordcount');
            }
            break;
        case 'doreindexposts_wordcount':
            $wordids = qa_db_words_prepare_for_recounting($next, 1000);
            if (count($wordids)) {
                $lastwordid = max($wordids);
                qa_db_words_recount($next, $lastwordid);
                $next = 1 + $lastwordid;
                $done += count($wordids);
                $continue = true;
            } else {
                qa_db_tagcount_update();
                // this is quick so just do it here
                qa_recalc_transition($state, 'doreindexposts_complete');
            }
            break;
        case 'dorecountposts':
            qa_recalc_transition($state, 'dorecountposts_postcount');
            break;
        case 'dorecountposts_postcount':
            qa_db_qcount_update();
            qa_db_acount_update();
            qa_db_ccount_update();
            qa_db_unaqcount_update();
            qa_db_unselqcount_update();
            qa_recalc_transition($state, 'dorecountposts_votecount');
            break;
        case 'dorecountposts_votecount':
            $postids = qa_db_posts_get_for_recounting($next, 1000);
            if (count($postids)) {
                $lastpostid = max($postids);
                qa_db_posts_votes_recount($next, $lastpostid);
                $next = 1 + $lastpostid;
                $done += count($postids);
                $continue = true;
            } else {
                qa_recalc_transition($state, 'dorecountposts_acount');
            }
            break;
        case 'dorecountposts_acount':
            $postids = qa_db_posts_get_for_recounting($next, 1000);
            if (count($postids)) {
                $lastpostid = max($postids);
                qa_db_posts_answers_recount($next, $lastpostid);
                $next = 1 + $lastpostid;
                $done += count($postids);
                $continue = true;
            } else {
                qa_db_unupaqcount_update();
                qa_recalc_transition($state, 'dorecountposts_complete');
            }
            break;
        case 'dorecalcpoints':
            qa_recalc_transition($state, 'dorecalcpoints_usercount');
            break;
        case 'dorecalcpoints_usercount':
            qa_db_userpointscount_update();
            // for progress update - not necessarily accurate
            qa_db_uapprovecount_update();
            // needs to be somewhere and this is the most appropriate place
            qa_recalc_transition($state, 'dorecalcpoints_recalc');
            break;
        case 'dorecalcpoints_recalc':
            $recalccount = 10;
            $userids = qa_db_users_get_for_recalc_points($next, $recalccount + 1);
            // get one extra so we know where to start from next
            $gotcount = count($userids);
            $recalccount = min($recalccount, $gotcount);
            // can't recalc more than we got
            if ($recalccount > 0) {
                $lastuserid = $userids[$recalccount - 1];
                qa_db_users_recalc_points($next, $lastuserid);
                $done += $recalccount;
            } else {
                $lastuserid = $next;
            }
            // for truncation
            if ($gotcount > $recalccount) {
                // more left to do
                $next = $userids[$recalccount];
                // start next round at first one not recalculated
                $continue = true;
            } else {
                qa_db_truncate_userpoints($lastuserid);
                qa_db_userpointscount_update();
                // quick so just do it here
                qa_recalc_transition($state, 'dorecalcpoints_complete');
            }
            break;
        case 'dorefillevents':
            qa_recalc_transition($state, 'dorefillevents_qcount');
            break;
        case 'dorefillevents_qcount':
            qa_db_qcount_update();
            qa_recalc_transition($state, 'dorefillevents_refill');
            break;
        case 'dorefillevents_refill':
            $questionids = qa_db_qs_get_for_event_refilling($next, 1);
            if (count($questionids)) {
                require_once QA_INCLUDE_DIR . 'app/events.php';
                require_once QA_INCLUDE_DIR . 'app/updates.php';
                require_once QA_INCLUDE_DIR . 'util/sort.php';
                $lastquestionid = max($questionids);
                foreach ($questionids as $questionid) {
                    //	Retrieve all posts relating to this question
                    list($question, $childposts, $achildposts) = qa_db_select_with_pending(qa_db_full_post_selectspec(null, $questionid), qa_db_full_child_posts_selectspec(null, $questionid), qa_db_full_a_child_posts_selectspec(null, $questionid));
                    //	Merge all posts while preserving keys as postids
                    $posts = array($questionid => $question);
                    foreach ($childposts as $postid => $post) {
                        $posts[$postid] = $post;
                    }
                    foreach ($achildposts as $postid => $post) {
                        $posts[$postid] = $post;
                    }
                    //	Creation and editing of each post
                    foreach ($posts as $postid => $post) {
                        $followonq = $post['basetype'] == 'Q' && $postid != $questionid;
                        if ($followonq) {
                            $updatetype = QA_UPDATE_FOLLOWS;
                        } elseif ($post['basetype'] == 'C' && @$posts[$post['parentid']]['basetype'] == 'Q') {
                            $updatetype = QA_UPDATE_C_FOR_Q;
                        } elseif ($post['basetype'] == 'C' && @$posts[$post['parentid']]['basetype'] == 'A') {
                            $updatetype = QA_UPDATE_C_FOR_A;
                        } else {
                            $updatetype = null;
                        }
                        qa_create_event_for_q_user($questionid, $postid, $updatetype, $post['userid'], @$posts[$post['parentid']]['userid'], $post['created']);
                        if (isset($post['updated']) && !$followonq) {
                            qa_create_event_for_q_user($questionid, $postid, $post['updatetype'], $post['lastuserid'], $post['userid'], $post['updated']);
                        }
                    }
                    //	Tags and categories of question
                    qa_create_event_for_tags($question['tags'], $questionid, null, $question['userid'], $question['created']);
                    qa_create_event_for_category($question['categoryid'], $questionid, null, $question['userid'], $question['created']);
                    //	Collect comment threads
                    $parentidcomments = array();
                    foreach ($posts as $postid => $post) {
                        if ($post['basetype'] == 'C') {
                            $parentidcomments[$post['parentid']][$postid] = $post;
                        }
                    }
                    //	For each comment thread, notify all previous comment authors of each comment in the thread (could get slow)
                    foreach ($parentidcomments as $parentid => $comments) {
                        $keyuserids = array();
                        qa_sort_by($comments, 'created');
                        foreach ($comments as $comment) {
                            foreach ($keyuserids as $keyuserid => $dummy) {
                                if ($keyuserid != $comment['userid'] && $keyuserid != @$posts[$parentid]['userid']) {
                                    qa_db_event_create_not_entity($keyuserid, $questionid, $comment['postid'], QA_UPDATE_FOLLOWS, $comment['userid'], $comment['created']);
                                }
                            }
                            if (isset($comment['userid'])) {
                                $keyuserids[$comment['userid']] = true;
                            }
                        }
                    }
                }
                $next = 1 + $lastquestionid;
                $done += count($questionids);
                $continue = true;
            } else {
                qa_recalc_transition($state, 'dorefillevents_complete');
            }
            break;
        case 'dorecalccategories':
            qa_recalc_transition($state, 'dorecalccategories_postcount');
            break;
        case 'dorecalccategories_postcount':
            qa_db_acount_update();
            qa_db_ccount_update();
            qa_recalc_transition($state, 'dorecalccategories_postupdate');
            break;
        case 'dorecalccategories_postupdate':
            $postids = qa_db_posts_get_for_recategorizing($next, 100);
            if (count($postids)) {
                $lastpostid = max($postids);
                qa_db_posts_recalc_categoryid($next, $lastpostid);
                qa_db_posts_calc_category_path($next, $lastpostid);
                $next = 1 + $lastpostid;
                $done += count($postids);
                $continue = true;
            } else {
                qa_recalc_transition($state, 'dorecalccategories_recount');
            }
            break;
        case 'dorecalccategories_recount':
            $categoryids = qa_db_categories_get_for_recalcs($next, 10);
            if (count($categoryids)) {
                $lastcategoryid = max($categoryids);
                foreach ($categoryids as $categoryid) {
                    qa_db_ifcategory_qcount_update($categoryid);
                }
                $next = 1 + $lastcategoryid;
                $done += count($categoryids);
                $continue = true;
            } else {
                qa_recalc_transition($state, 'dorecalccategories_backpaths');
            }
            break;
        case 'dorecalccategories_backpaths':
            $categoryids = qa_db_categories_get_for_recalcs($next, 10);
            if (count($categoryids)) {
                $lastcategoryid = max($categoryids);
                qa_db_categories_recalc_backpaths($next, $lastcategoryid);
                $next = 1 + $lastcategoryid;
                $done += count($categoryids);
                $continue = true;
            } else {
                qa_recalc_transition($state, 'dorecalccategories_complete');
            }
            break;
        case 'dodeletehidden':
            qa_recalc_transition($state, 'dodeletehidden_comments');
            break;
        case 'dodeletehidden_comments':
            $posts = qa_db_posts_get_for_deleting('C', $next, 1);
            if (count($posts)) {
                require_once QA_INCLUDE_DIR . 'app/posts.php';
                $postid = $posts[0];
                qa_post_delete($postid);
                $next = 1 + $postid;
                $done++;
                $continue = true;
            } else {
                qa_recalc_transition($state, 'dodeletehidden_answers');
            }
            break;
        case 'dodeletehidden_answers':
            $posts = qa_db_posts_get_for_deleting('A', $next, 1);
            if (count($posts)) {
                require_once QA_INCLUDE_DIR . 'app/posts.php';
                $postid = $posts[0];
                qa_post_delete($postid);
                $next = 1 + $postid;
                $done++;
                $continue = true;
            } else {
                qa_recalc_transition($state, 'dodeletehidden_questions');
            }
            break;
        case 'dodeletehidden_questions':
            $posts = qa_db_posts_get_for_deleting('Q', $next, 1);
            if (count($posts)) {
                require_once QA_INCLUDE_DIR . 'app/posts.php';
                $postid = $posts[0];
                qa_post_delete($postid);
                $next = 1 + $postid;
                $done++;
                $continue = true;
            } else {
                qa_recalc_transition($state, 'dodeletehidden_complete');
            }
            break;
        case 'doblobstodisk':
            qa_recalc_transition($state, 'doblobstodisk_move');
            break;
        case 'doblobstodisk_move':
            $blob = qa_db_get_next_blob_in_db($next);
            if (isset($blob)) {
                require_once QA_INCLUDE_DIR . 'app/blobs.php';
                require_once QA_INCLUDE_DIR . 'db/blobs.php';
                if (qa_write_blob_file($blob['blobid'], $blob['content'], $blob['format'])) {
                    qa_db_blob_set_content($blob['blobid'], null);
                }
                $next = 1 + $blob['blobid'];
                $done++;
                $continue = true;
            } else {
                qa_recalc_transition($state, 'doblobstodisk_complete');
            }
            break;
        case 'doblobstodb':
            qa_recalc_transition($state, 'doblobstodb_move');
            break;
        case 'doblobstodb_move':
            $blob = qa_db_get_next_blob_on_disk($next);
            if (isset($blob)) {
                require_once QA_INCLUDE_DIR . 'app/blobs.php';
                require_once QA_INCLUDE_DIR . 'db/blobs.php';
                $content = qa_read_blob_file($blob['blobid'], $blob['format']);
                qa_db_blob_set_content($blob['blobid'], $content);
                qa_delete_blob_file($blob['blobid'], $blob['format']);
                $next = 1 + $blob['blobid'];
                $done++;
                $continue = true;
            } else {
                qa_recalc_transition($state, 'doblobstodb_complete');
            }
            break;
        default:
            $state = '';
            break;
    }
    if ($continue) {
        $state = $operation . "\t" . $length . "\t" . $next . "\t" . $done;
    }
    return $continue && $done < $length;
}
Esempio n. 2
0
function qa_post_get_question_commentsfollows($questionid)
{
    $commentsfollows = array();
    list($childposts, $achildposts) = qa_db_multi_select(array(qa_db_full_child_posts_selectspec(null, $questionid), qa_db_full_a_child_posts_selectspec(null, $questionid)));
    foreach ($childposts as $postid => $post) {
        if ($post['basetype'] == 'C') {
            $commentsfollows[$postid] = $post;
        }
    }
    foreach ($achildposts as $postid => $post) {
        if ($post['basetype'] == 'Q' || $post['basetype'] == 'C') {
            $commentsfollows[$postid] = $post;
        }
    }
    return $commentsfollows;
}
Esempio n. 3
0
    header('Location: ../');
    exit;
}
require_once QA_INCLUDE_DIR . 'app/cookies.php';
require_once QA_INCLUDE_DIR . 'app/format.php';
require_once QA_INCLUDE_DIR . 'db/selects.php';
require_once QA_INCLUDE_DIR . 'util/sort.php';
require_once QA_INCLUDE_DIR . 'util/string.php';
require_once QA_INCLUDE_DIR . 'app/captcha.php';
require_once QA_INCLUDE_DIR . 'pages/question-view.php';
require_once QA_INCLUDE_DIR . 'app/updates.php';
$questionid = qa_request_part(0);
$userid = qa_get_logged_in_userid();
$cookieid = qa_cookie_get();
//	Get information about this question
list($question, $childposts, $achildposts, $parentquestion, $closepost, $extravalue, $categories, $favorite) = qa_db_select_with_pending(qa_db_full_post_selectspec($userid, $questionid), qa_db_full_child_posts_selectspec($userid, $questionid), qa_db_full_a_child_posts_selectspec($userid, $questionid), qa_db_post_parent_q_selectspec($questionid), qa_db_post_close_post_selectspec($questionid), qa_db_post_meta_selectspec($questionid, 'qa_q_extra'), qa_db_category_nav_selectspec($questionid, true, true, true), isset($userid) ? qa_db_is_favorite_selectspec($userid, QA_ENTITY_QUESTION, $questionid) : null);
if ($question['basetype'] != 'Q') {
    // don't allow direct viewing of other types of post
    $question = null;
}
if (isset($question)) {
    $question['extra'] = $extravalue;
    $answers = qa_page_q_load_as($question, $childposts);
    $commentsfollows = qa_page_q_load_c_follows($question, $childposts, $achildposts);
    $question = $question + qa_page_q_post_rules($question, null, null, $childposts);
    // array union
    if ($question['selchildid'] && @$answers[$question['selchildid']]['type'] != 'A') {
        $question['selchildid'] = null;
    }
    // if selected answer is hidden or somehow not there, consider it not selected
    foreach ($answers as $key => $answer) {
Esempio n. 4
0
 function get_single_question($data, $questionin)
 {
     $userid = qa_get_logged_in_userid();
     $questionid = $questionin['postid'];
     $options = qa_post_html_defaults('Q', @$data['full']);
     if (@$data['full']) {
         require_once QA_INCLUDE_DIR . 'qa-page-question-view.php';
         $cookieid = isset($userid) ? qa_cookie_get() : qa_cookie_get_create();
         // create a new cookie if necessary
         $coptions = qa_post_html_defaults('C', true);
         @(list($childposts, $achildposts, $parentquestion, $closepost, $extravalue, $categories, $favorite) = qa_db_select_with_pending(qa_db_full_child_posts_selectspec($userid, $questionid), qa_db_full_a_child_posts_selectspec($userid, $questionid), qa_db_post_parent_q_selectspec($questionid), qa_db_post_close_post_selectspec($questionid), qa_db_post_meta_selectspec($questionid, 'qa_q_extra'), qa_db_category_nav_selectspec($questionid, true, true, true), isset($userid) ? qa_db_is_favorite_selectspec($userid, QA_ENTITY_QUESTION, $questionid) : null));
         if ($questionin['basetype'] != 'Q') {
             // don't allow direct viewing of other types of post
             return null;
         }
         $questionin['extra'] = $extravalue;
         $answers = qa_page_q_load_as($questionin, $childposts);
         $allcomments = qa_page_q_load_c_follows($questionin, $childposts, $achildposts);
         $questionin = $questionin + qa_page_q_post_rules($questionin, null, null, $childposts);
         // array union
         if ($questionin['selchildid'] && @$answers[$questionin['selchildid']]['type'] != 'A') {
             $questionin['selchildid'] = null;
         }
         // if selected answer is hidden or somehow not there, consider it not selected
         foreach ($answers as $key => $answer) {
             $answers[$key] = $answer + qa_page_q_post_rules($answer, $questionin, $answers, $achildposts);
             $answers[$key]['isselected'] = $answer['postid'] == $questionin['selchildid'];
         }
         foreach ($allcomments as $key => $commentfollow) {
             $parent = $commentfollow['parentid'] == $questionid ? $questionin : @$answers[$commentfollow['parentid']];
             $allcomments[$key] = $commentfollow + qa_page_q_post_rules($commentfollow, $parent, $allcomments, null);
         }
         $usershtml = qa_userids_handles_html(array_merge(array($questionin), $answers, $allcomments), true);
         $question = $this->get_full_post($questionin, $options, $usershtml);
         $qcomments = array();
         foreach ($allcomments as $idx => $comment) {
             if ($comment['basetype'] == 'C') {
                 $comment = $this->get_full_post($comment, $coptions, $usershtml);
             } else {
                 $comment = $this->get_full_post($comment, $options, $usershtml);
             }
             $comment['username'] = $this->get_username($comment['raw']['userid']);
             if ($comment['raw']['parentid'] == $questionid) {
                 $qcomments[] = $comment;
             }
             $allcomments[$idx] = $comment;
         }
         $aoptions = qa_post_html_defaults('A', true);
         $outanswers = array();
         foreach ($answers as $answer) {
             $aoptions['isselected'] = @$answer['isselected'];
             $answer = $this->get_full_post($answer, $aoptions, $usershtml);
             if (!$answer) {
                 continue;
             }
             $answer['username'] = $this->get_username($answer['raw']['userid']);
             $acomments = array();
             foreach ($allcomments as $comment) {
                 if ($comment['raw']['parentid'] == $answer['raw']['postid']) {
                     $acomments[] = $comment;
                 }
             }
             $answer['comments'] = $acomments;
             $outanswers[] = $answer;
         }
         $question['answers'] = $outanswers;
         $question['comments'] = $qcomments;
         $question['parentquestion'] = $parentquestion;
         $question['closepost'] = $closepost;
         $question['extravalue'] = $extravalue;
         $question['categories'] = $categories;
         $question['favorite'] = $favorite;
     } else {
         $questionin = qa_db_select_with_pending(qa_db_full_post_selectspec($userid, $questionid));
         $usershtml = qa_userids_handles_html(array($questionin), true);
         $question = qa_any_to_q_html_fields($questionin, $userid, qa_cookie_get(), $usershtml, null, $options);
     }
     $question['username'] = $this->get_username($userid);
     return $question;
 }
function qa_page_q_load_q()
{
    global $qa_login_userid, $questionid, $question, $parentquestion, $answers, $commentsfollows, $relatedcount, $relatedquestions, $question, $categories;
    list($question, $childposts, $achildposts, $parentquestion, $relatedquestions, $categories) = qa_db_select_with_pending(qa_db_full_post_selectspec($qa_login_userid, $questionid), qa_db_full_child_posts_selectspec($qa_login_userid, $questionid), qa_db_full_a_child_posts_selectspec($qa_login_userid, $questionid), qa_db_post_parent_q_selectspec($questionid), qa_db_related_qs_selectspec($qa_login_userid, $questionid), qa_db_category_nav_selectspec($questionid, true, true));
    if ($question['basetype'] != 'Q') {
        // don't allow direct viewing of other types of post
        $question = null;
    }
    $answers = array();
    $commentsfollows = array();
    foreach ($childposts as $postid => $post) {
        switch ($post['type']) {
            case 'Q':
                // never show follow-on Qs which have been hidden, even to admins
            // never show follow-on Qs which have been hidden, even to admins
            case 'C':
            case 'C_HIDDEN':
                $commentsfollows[$postid] = $post;
                break;
            case 'A':
            case 'A_HIDDEN':
                $answers[$postid] = $post;
                break;
        }
    }
    foreach ($achildposts as $postid => $post) {
        switch ($post['type']) {
            case 'Q':
            case 'Q_HIDDEN':
            case 'C':
            case 'C_HIDDEN':
                $commentsfollows[$postid] = $post;
                break;
        }
    }
    if (isset($question)) {
        $relatedcount = qa_opt('do_related_qs') ? 1 + qa_opt('page_size_related_qs') : 0;
        $relatedquestions = array_slice($relatedquestions, 0, $relatedcount);
        // includes question itself at this point
        qa_page_q_post_rules($question);
        if ($question['selchildid'] && @$answers[$question['selchildid']]['type'] != 'A') {
            $question['selchildid'] = null;
        }
        // if selected answer is hidden or somehow not there, consider it not selected
        foreach ($answers as $key => $answer) {
            $question['deleteable'] = false;
            qa_page_q_post_rules($answers[$key]);
            if ($answers[$key]['isbyuser'] && !qa_opt('allow_multi_answers')) {
                $question['answerbutton'] = false;
            }
            $answers[$key]['isselected'] = $answer['postid'] == $question['selchildid'];
        }
        foreach ($commentsfollows as $key => $commentfollow) {
            if ($commentfollow['parentid'] == $questionid) {
                $question['deleteable'] = false;
            }
            if (isset($answers[$commentfollow['parentid']])) {
                $answers[$commentfollow['parentid']]['deleteable'] = false;
            }
            qa_page_q_post_rules($commentsfollows[$key]);
        }
    }
}
Esempio n. 6
0
function qa_recalc_perform_step(&$state)
{
    $continue = false;
    @(list($operation, $length, $next, $done) = explode(',', $state));
    switch ($operation) {
        case 'doreindexcontent':
            qa_recalc_transition($state, 'doreindexcontent_pagereindex');
            break;
        case 'doreindexcontent_pagereindex':
            $pages = qa_db_pages_get_for_reindexing($next, 10);
            if (count($pages)) {
                require_once QA_INCLUDE_DIR . 'qa-app-format.php';
                $lastpageid = max(array_keys($pages));
                foreach ($pages as $pageid => $page) {
                    if (!($page['flags'] & QA_PAGE_FLAGS_EXTERNAL)) {
                        $searchmodules = qa_load_modules_with('search', 'unindex_page');
                        foreach ($searchmodules as $searchmodule) {
                            $searchmodule->unindex_page($pageid);
                        }
                        $searchmodules = qa_load_modules_with('search', 'index_page');
                        if (count($searchmodules)) {
                            $indextext = qa_viewer_text($page['content'], 'html');
                            foreach ($searchmodules as $searchmodule) {
                                $searchmodule->index_page($pageid, $page['tags'], $page['heading'], $page['content'], 'html', $indextext);
                            }
                        }
                    }
                }
                $next = 1 + $lastpageid;
                $done += count($pages);
                $continue = true;
            } else {
                qa_recalc_transition($state, 'doreindexcontent_postcount');
            }
            break;
        case 'doreindexcontent_postcount':
            qa_db_qcount_update();
            qa_db_acount_update();
            qa_db_ccount_update();
            qa_recalc_transition($state, 'doreindexcontent_postreindex');
            break;
        case 'doreindexcontent_postreindex':
            $posts = qa_db_posts_get_for_reindexing($next, 10);
            if (count($posts)) {
                require_once QA_INCLUDE_DIR . 'qa-app-format.php';
                $lastpostid = max(array_keys($posts));
                qa_db_prepare_for_reindexing($next, $lastpostid);
                qa_suspend_update_counts();
                foreach ($posts as $postid => $post) {
                    qa_post_unindex($postid);
                    qa_post_index($postid, $post['type'], $post['questionid'], $post['parentid'], $post['title'], $post['content'], $post['format'], qa_viewer_text($post['content'], $post['format']), $post['tags'], $post['categoryid']);
                }
                $next = 1 + $lastpostid;
                $done += count($posts);
                $continue = true;
            } else {
                qa_db_truncate_indexes($next);
                qa_recalc_transition($state, 'doreindexposts_wordcount');
            }
            break;
        case 'doreindexposts_wordcount':
            $wordids = qa_db_words_prepare_for_recounting($next, 1000);
            if (count($wordids)) {
                $lastwordid = max($wordids);
                qa_db_words_recount($next, $lastwordid);
                $next = 1 + $lastwordid;
                $done += count($wordids);
                $continue = true;
            } else {
                qa_db_tagcount_update();
                // this is quick so just do it here
                qa_recalc_transition($state, 'doreindexposts_complete');
            }
            break;
        case 'dorecountposts':
            qa_recalc_transition($state, 'dorecountposts_postcount');
            break;
        case 'dorecountposts_postcount':
            qa_db_qcount_update();
            qa_db_acount_update();
            qa_db_ccount_update();
            qa_db_unaqcount_update();
            qa_db_unselqcount_update();
            qa_recalc_transition($state, 'dorecountposts_votecount');
            break;
        case 'dorecountposts_votecount':
            $postids = qa_db_posts_get_for_recounting($next, 1000);
            if (count($postids)) {
                $lastpostid = max($postids);
                qa_db_posts_votes_recount($next, $lastpostid);
                $next = 1 + $lastpostid;
                $done += count($postids);
                $continue = true;
            } else {
                qa_recalc_transition($state, 'dorecountposts_acount');
            }
            break;
        case 'dorecountposts_acount':
            $postids = qa_db_posts_get_for_recounting($next, 1000);
            if (count($postids)) {
                $lastpostid = max($postids);
                qa_db_posts_answers_recount($next, $lastpostid);
                $next = 1 + $lastpostid;
                $done += count($postids);
                $continue = true;
            } else {
                qa_db_unupaqcount_update();
                qa_recalc_transition($state, 'dorecountposts_complete');
            }
            break;
        case 'dorecalcpoints':
            qa_recalc_transition($state, 'dorecalcpoints_usercount');
            break;
        case 'dorecalcpoints_usercount':
            qa_db_userpointscount_update();
            // for progress update - not necessarily accurate
            qa_recalc_transition($state, 'dorecalcpoints_recalc');
            break;
        case 'dorecalcpoints_recalc':
            $userids = qa_db_users_get_for_recalc_points($next, 10);
            if (count($userids)) {
                $lastuserid = max($userids);
                qa_db_users_recalc_points($next, $lastuserid);
                $next = 1 + $lastuserid;
                $done += count($userids);
                $continue = true;
            } else {
                qa_db_truncate_userpoints($next);
                qa_db_userpointscount_update();
                // quick so just do it here
                qa_recalc_transition($state, 'dorecalcpoints_complete');
            }
            break;
        case 'dorefillevents':
            qa_recalc_transition($state, 'dorefillevents_qcount');
            break;
        case 'dorefillevents_qcount':
            qa_db_qcount_update();
            qa_recalc_transition($state, 'dorefillevents_refill');
            break;
        case 'dorefillevents_refill':
            $questionids = qa_db_qs_get_for_event_refilling($next, 1);
            if (count($questionids)) {
                require_once QA_INCLUDE_DIR . 'qa-app-events.php';
                require_once QA_INCLUDE_DIR . 'qa-app-updates.php';
                require_once QA_INCLUDE_DIR . 'qa-util-sort.php';
                $lastquestionid = max($questionids);
                foreach ($questionids as $questionid) {
                    //	Retrieve all posts relating to this question
                    list($question, $childposts, $achildposts) = qa_db_select_with_pending(qa_db_full_post_selectspec(null, $questionid), qa_db_full_child_posts_selectspec(null, $questionid), qa_db_full_a_child_posts_selectspec(null, $questionid));
                    //	Merge all posts while preserving keys as postids
                    $posts = array($questionid => $question);
                    foreach ($childposts as $postid => $post) {
                        $posts[$postid] = $post;
                    }
                    foreach ($achildposts as $postid => $post) {
                        $posts[$postid] = $post;
                    }
                    //	Creation and editing of each post
                    foreach ($posts as $postid => $post) {
                        $followonq = $post['basetype'] == 'Q' && $postid != $questionid;
                        qa_create_event_for_q_user($questionid, $postid, $followonq ? QA_UPDATE_FOLLOWS : null, $post['userid'], @$posts[$post['parentid']]['userid'], $post['created']);
                        if (isset($post['updated']) && !$followonq) {
                            qa_create_event_for_q_user($questionid, $postid, $post['updatetype'], $post['lastuserid'], $post['userid'], $post['updated']);
                        }
                    }
                    //	Tags and categories of question
                    qa_create_event_for_tags($question['tags'], $questionid, null, $question['userid'], $question['created']);
                    qa_create_event_for_category($question['categoryid'], $questionid, null, $question['userid'], $question['created']);
                    //	Collect comment threads
                    $parentidcomments = array();
                    foreach ($posts as $postid => $post) {
                        if ($post['basetype'] == 'C') {
                            $parentidcomments[$post['parentid']][$postid] = $post;
                        }
                    }
                    //	For each comment thread, notify all previous comment authors of each comment in the thread (could get slow)
                    foreach ($parentidcomments as $parentid => $comments) {
                        $keyuserids = array();
                        qa_sort_by($comments, 'created');
                        foreach ($comments as $comment) {
                            foreach ($keyuserids as $keyuserid => $dummy) {
                                if ($keyuserid != $comment['userid'] && $keyuserid != @$posts[$parentid]['userid']) {
                                    qa_db_event_create_not_entity($keyuserid, $questionid, $comment['postid'], null, $comment['userid'], $comment['created']);
                                }
                            }
                            if (isset($comment['userid'])) {
                                $keyuserids[$comment['userid']] = true;
                            }
                        }
                    }
                }
                $next = 1 + $lastquestionid;
                $done += count($questionids);
                $continue = true;
            } else {
                qa_recalc_transition($state, 'dorefillevents_complete');
            }
            break;
        case 'dorecalccategories':
            qa_recalc_transition($state, 'dorecalccategories_postcount');
            break;
        case 'dorecalccategories_postcount':
            qa_db_acount_update();
            qa_db_ccount_update();
            qa_recalc_transition($state, 'dorecalccategories_postupdate');
            break;
        case 'dorecalccategories_postupdate':
            $postids = qa_db_posts_get_for_recategorizing($next, 100);
            if (count($postids)) {
                $lastpostid = max($postids);
                qa_db_posts_recalc_categoryid($next, $lastpostid);
                qa_db_posts_calc_category_path($next, $lastpostid);
                $next = 1 + $lastpostid;
                $done += count($postids);
                $continue = true;
            } else {
                qa_recalc_transition($state, 'dorecalccategories_recount');
            }
            break;
        case 'dorecalccategories_recount':
            $categoryids = qa_db_categories_get_for_recalcs($next, 10);
            if (count($categoryids)) {
                $lastcategoryid = max($categoryids);
                foreach ($categoryids as $categoryid) {
                    qa_db_ifcategory_qcount_update($categoryid);
                }
                $next = 1 + $lastcategoryid;
                $done += count($categoryids);
                $continue = true;
            } else {
                qa_recalc_transition($state, 'dorecalccategories_backpaths');
            }
            break;
        case 'dorecalccategories_backpaths':
            $categoryids = qa_db_categories_get_for_recalcs($next, 10);
            if (count($categoryids)) {
                $lastcategoryid = max($categoryids);
                qa_db_categories_recalc_backpaths($next, $lastcategoryid);
                $next = 1 + $lastcategoryid;
                $done += count($categoryids);
                $continue = true;
            } else {
                qa_recalc_transition($state, 'dorecalccategories_complete');
            }
            break;
        case 'dodeletehidden':
            qa_recalc_transition($state, 'dodeletehidden_comments');
            break;
        case 'dodeletehidden_comments':
            $posts = qa_db_posts_get_for_deleting('C', $next, 1);
            if (count($posts)) {
                require_once QA_INCLUDE_DIR . 'qa-app-posts.php';
                $postid = $posts[0];
                qa_post_delete($postid);
                $next = 1 + $postid;
                $done++;
                $continue = true;
            } else {
                qa_recalc_transition($state, 'dodeletehidden_answers');
            }
            break;
        case 'dodeletehidden_answers':
            $posts = qa_db_posts_get_for_deleting('A', $next, 1);
            if (count($posts)) {
                require_once QA_INCLUDE_DIR . 'qa-app-posts.php';
                $postid = $posts[0];
                qa_post_delete($postid);
                $next = 1 + $postid;
                $done++;
                $continue = true;
            } else {
                qa_recalc_transition($state, 'dodeletehidden_questions');
            }
            break;
        case 'dodeletehidden_questions':
            $posts = qa_db_posts_get_for_deleting('Q', $next, 1);
            if (count($posts)) {
                require_once QA_INCLUDE_DIR . 'qa-app-posts.php';
                $postid = $posts[0];
                qa_post_delete($postid);
                $next = 1 + $postid;
                $done++;
                $continue = true;
            } else {
                qa_recalc_transition($state, 'dodeletehidden_complete');
            }
            break;
        default:
            $state = '';
            break;
    }
    if ($continue) {
        $state = $operation . ',' . $length . ',' . $next . ',' . $done;
    }
    return $continue && $done < $length;
}