• This site uses cookies. By continuing to use this site, you are agreeing to our use of cookies. Learn more.

XF 1.2 Post Edit History and Logging

digitalpoint

Well-known member
Now that I've started looking at the 1.2 underlying changes, I'm surprised that the edit history doesn't log the IP of the user making the edit. Hopefully just an oversight and maybe added before final version?

I also wish that it did have an optional "reason" for users (I know that @Mike said it was intentionally left out, but not super excited about that).
 

oman

Well-known member
Quick question: Is this a moderator only feature, or can it be enabled across all usergroups. (The ability to view post edit history).

Thanks,
oman
 

Jeremy

Well-known member
I don't have the link handy, but Mike had explained it as a moderator feature due to the fact that it shows exact dates, times, and who did the edits. It also allows a user to see content that was deemed unsuitable by a moderator.
 

digitalpoint

Well-known member
Hmmm... I guess lots of things I need to change with it... IP logging, optional reason and permission-based.

Not sure the argument about mods editing inappropriate content really happens that often. On my site, we delete inappropriate posts, not edit them... User's ability to see edit history is more about being able to see posts that said one thing and then were changed (bait and switch).
 

AlexT

Well-known member
I don't know if it was already asked, but I would be interested if the vB3->XF Importer will import edit history from vB3 too...
Not sure if @Mike or @Kier have been working on it already, but this is the code snippet I've come up with to successfully import the edit history from my test vBulletin install. Maybe it's of some help.

(I was too lazy to write an addon extending the importer since my vB importer files are already heavily modified to suit my specific purposes).

In /library/XenForo/Importer/vBulletin.php:

PHP:
    public function getSteps()
    {
        return array(
...
            'edithistory' => array(
                'title' => 'MobileRead Import Edit History',
                'depends' => array('threads', 'users', 'forums')
          ),
...
        );
PHP:
    public function stepedithistory($start, array $options)
    {
        $options = array_merge(array(
            'limit' => 10,
            'max' => false
        ), $options);

        $sDb = $this->_sourceDb;
        $prefix = $this->_prefix;

        /* @var $model XenForo_Model_Import */
        $model = $this->_importModel;

        if ($options['max'] === false)
        {
            $options['max'] = $sDb->fetchOne('
                SELECT MAX(postid)
                FROM ' . $prefix . 'postedithistory
            ');
        }

        $postIds = $sDb->fetchCol($sDb->limit(
            '
                SELECT DISTINCT postid
                FROM ' . $prefix . 'postedithistory
                WHERE postid > ' . $sDb->quote($start) . '
                ORDER BY postid
            ', $options['limit']
        ));

        if (!$postIds)
        {
            return true;
        }

        $next = 0;
        $total = 0;

        XenForo_Db::beginTransaction();

        foreach ($postIds as $postId)
        {
            $next = $postId;

            // order by dateline!
            $oldEdits = $sDb->fetchAll(
                '
                    SELECT postedithistoryid AS edit_history_id, original, \'post\' AS content_type, postid AS content_id, userid AS edit_user_id, dateline AS edit_date, pagetext AS old_text
                    FROM ' . $prefix . 'postedithistory
                    WHERE postid =  ' . $sDb->quote($postId) . '
                    ORDER BY dateline
                '
            );

            $userIdMap = $model->getUserIdsMapFromArray($oldEdits, 'edit_user_id');
            $postIdMap = $model->getPostIdsMapFromArray($oldEdits, 'content_id');

            $newEdits = array();
            foreach ($oldEdits as $i => $oldEdit)
            {
                $newUserId = $this->_mapLookUp($userIdMap, $oldEdit['edit_user_id']);
                $newContentId = $this->_mapLookUp($postIdMap, $oldEdit['content_id']);

                if (!$newUserId)
                {
                    continue;
                }

                $oldEdit['old_text'] = $this->_convertToUtf8($oldEdit['old_text']);

                // rewrite quotes into xF 1.2 syntax
                if (stripos($oldEdit['old_text'], '[quote=') !== false)
                {
                    if (preg_match_all('/\[quote=("|\'|)(?P<username>[^;]*);\s*(?P<postid>\d+)\s*\1\]/siU', $oldEdit['old_text'], $quotes, PREG_SET_ORDER))
                    {
                        $post['quotes'] = array();

                        foreach ($quotes AS $quote)
                        {
                            $quotedPostId = intval($quote['postid']);

                            $quotedPostIds[] = $quotedPostId;

                            $post['quotes'][$quote[0]] = array($quote['username'], $quotedPostId);
                        }
                    }
                }

                $quotedPostIdMap = (empty($quotedPostIds) ? array() : $model->getImportContentMap('post', $quotedPostIds));

                if (!empty($post['quotes']))
                {
                    $oldEdit['old_text'] = $this->_rewriteQuotes($oldEdit['old_text'], $post['quotes'], $quotedPostIdMap);
                }
                // quote rewrite end

                $newEdits[$i]['old_text'] = $oldEdit['old_text'];

                if (!$oldEdit['original'] == 1)
                {
                    $newEdits[$i-1]['content_type'] = $oldEdit['content_type'];
                    $newEdits[$i-1]['content_id'] = $newContentId;
                    $newEdits[$i-1]['edit_user_id'] = $newUserId;
                    $newEdits[$i-1]['edit_date'] = $oldEdit['edit_date'];
                }

                $lastUser = $newUserId;
                $lastDate = $oldEdit['edit_date'];
            }
           
            // remove last
            array_pop($newEdits);

            $model->importEditHistory($newEdits, $postId, sizeof($newEdits), $lastUser, $lastDate);

            $total++;
   
        }

        XenForo_Db::commit();

        $this->_session->incrementStepImportTotal($total);

        return array($next, $options, $this->_getProgressOutput($next, $options['max']));
    }
In /library/XenForo/Model/Import.php:

PHP:
    public function importEditHistory($newEdits, $contentId, $count, $lastUser, $lastDate)
    {
        foreach ($newEdits as $newEdit)
        {
            $historyDw = XenForo_DataWriter::create('XenForo_DataWriter_EditHistory', XenForo_DataWriter::ERROR_SILENT);
            $historyDw->bulkSet($newEdit);
            $historyDw->save();
        }

        $dw = XenForo_DataWriter::create('XenForo_DataWriter_DiscussionMessage_Post', XenForo_DataWriter::ERROR_SILENT);
        $dw->setExistingData($contentId);
        $dw->setOption(XenForo_DataWriter_DiscussionMessage::OPTION_LOG_EDIT, false);
        $dw->setOption(XenForo_DataWriter_DiscussionMessage::OPTION_EDIT_DATE_DELAY, -1);
        $dw->setOption(XenForo_DataWriter_DiscussionMessage::OPTION_IS_AUTOMATED, true);
        $dw->set('edit_count', $count);
        $dw->set('last_edit_date', $lastDate);
        $dw->set('last_edit_user_id', $lastUser);
        return $dw->save();
    }
 

Max

Well-known member
Can we import post edit history from vb 3.8 to xf 1.2 ?
hope you guys will upgrade the vb3.8 importers for xf 1.2 new features.
 
Not sure if @Mike or @Kier have been working on it already, but this is the code snippet I've come up with to successfully import the edit history from my test vBulletin install. Maybe it's of some help.

(I was too lazy to write an addon extending the importer since my vB importer files are already heavily modified to suit my specific purposes).

In /library/XenForo/Importer/vBulletin.php:

PHP:
    public function getSteps()
    {
        return array(
...
            'edithistory' => array(
                'title' => 'MobileRead Import Edit History',
                'depends' => array('threads', 'users', 'forums')
          ),
...
        );
PHP:
    public function stepedithistory($start, array $options)
    {
        $options = array_merge(array(
            'limit' => 10,
            'max' => false
        ), $options);

        $sDb = $this->_sourceDb;
        $prefix = $this->_prefix;

        /* @var $model XenForo_Model_Import */
        $model = $this->_importModel;

        if ($options['max'] === false)
        {
            $options['max'] = $sDb->fetchOne('
                SELECT MAX(postid)
                FROM ' . $prefix . 'postedithistory
            ');
        }

        $postIds = $sDb->fetchCol($sDb->limit(
            '
                SELECT DISTINCT postid
                FROM ' . $prefix . 'postedithistory
                WHERE postid > ' . $sDb->quote($start) . '
                ORDER BY postid
            ', $options['limit']
        ));

        if (!$postIds)
        {
            return true;
        }

        $next = 0;
        $total = 0;

        XenForo_Db::beginTransaction();

        foreach ($postIds as $postId)
        {
            $next = $postId;

            // order by dateline!
            $oldEdits = $sDb->fetchAll(
                '
                    SELECT postedithistoryid AS edit_history_id, original, \'post\' AS content_type, postid AS content_id, userid AS edit_user_id, dateline AS edit_date, pagetext AS old_text
                    FROM ' . $prefix . 'postedithistory
                    WHERE postid =  ' . $sDb->quote($postId) . '
                    ORDER BY dateline
                '
            );

            $userIdMap = $model->getUserIdsMapFromArray($oldEdits, 'edit_user_id');
            $postIdMap = $model->getPostIdsMapFromArray($oldEdits, 'content_id');

            $newEdits = array();
            foreach ($oldEdits as $i => $oldEdit)
            {
                $newUserId = $this->_mapLookUp($userIdMap, $oldEdit['edit_user_id']);
                $newContentId = $this->_mapLookUp($postIdMap, $oldEdit['content_id']);

                if (!$newUserId)
                {
                    continue;
                }

                $oldEdit['old_text'] = $this->_convertToUtf8($oldEdit['old_text']);

                // rewrite quotes into xF 1.2 syntax
                if (stripos($oldEdit['old_text'], '[quote=') !== false)
                {
                    if (preg_match_all('/\[quote=("|\'|)(?P<username>[^;]*);\s*(?P<postid>\d+)\s*\1\]/siU', $oldEdit['old_text'], $quotes, PREG_SET_ORDER))
                    {
                        $post['quotes'] = array();

                        foreach ($quotes AS $quote)
                        {
                            $quotedPostId = intval($quote['postid']);

                            $quotedPostIds[] = $quotedPostId;

                            $post['quotes'][$quote[0]] = array($quote['username'], $quotedPostId);
                        }
                    }
                }

                $quotedPostIdMap = (empty($quotedPostIds) ? array() : $model->getImportContentMap('post', $quotedPostIds));

                if (!empty($post['quotes']))
                {
                    $oldEdit['old_text'] = $this->_rewriteQuotes($oldEdit['old_text'], $post['quotes'], $quotedPostIdMap);
                }
                // quote rewrite end

                $newEdits[$i]['old_text'] = $oldEdit['old_text'];

                if (!$oldEdit['original'] == 1)
                {
                    $newEdits[$i-1]['content_type'] = $oldEdit['content_type'];
                    $newEdits[$i-1]['content_id'] = $newContentId;
                    $newEdits[$i-1]['edit_user_id'] = $newUserId;
                    $newEdits[$i-1]['edit_date'] = $oldEdit['edit_date'];
                }

                $lastUser = $newUserId;
                $lastDate = $oldEdit['edit_date'];
            }
          
            // remove last
            array_pop($newEdits);

            $model->importEditHistory($newEdits, $postId, sizeof($newEdits), $lastUser, $lastDate);

            $total++;
  
        }

        XenForo_Db::commit();

        $this->_session->incrementStepImportTotal($total);

        return array($next, $options, $this->_getProgressOutput($next, $options['max']));
    }
In /library/XenForo/Model/Import.php:

PHP:
    public function importEditHistory($newEdits, $contentId, $count, $lastUser, $lastDate)
    {
        foreach ($newEdits as $newEdit)
        {
            $historyDw = XenForo_DataWriter::create('XenForo_DataWriter_EditHistory', XenForo_DataWriter::ERROR_SILENT);
            $historyDw->bulkSet($newEdit);
            $historyDw->save();
        }

        $dw = XenForo_DataWriter::create('XenForo_DataWriter_DiscussionMessage_Post', XenForo_DataWriter::ERROR_SILENT);
        $dw->setExistingData($contentId);
        $dw->setOption(XenForo_DataWriter_DiscussionMessage::OPTION_LOG_EDIT, false);
        $dw->setOption(XenForo_DataWriter_DiscussionMessage::OPTION_EDIT_DATE_DELAY, -1);
        $dw->setOption(XenForo_DataWriter_DiscussionMessage::OPTION_IS_AUTOMATED, true);
        $dw->set('edit_count', $count);
        $dw->set('last_edit_date', $lastDate);
        $dw->set('last_edit_user_id', $lastUser);
        return $dw->save();
    }
I try this night to import the vb edit history from my old forum, with your code, thanks a lot for share.
 
This can be used for many things, including handling the "rage-delete" situation, where a user edits all of their content, potentially destroying the flow of many threads.
Being a forum mod, I signed up here to say thank you, THANK YOU, THANK YOU for this feature. You can't imagine how THANKFUL I am for this.