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

XF 1.2 Undelete someone

The Sandman

Well-known member
#8
Never a good idea to disagree with Jake, but I *believe* that while not a complete undelete Wandigo's add-on does more than just reassociate posts with a username.
 

Jake Bunce

XenForo moderator
Staff member
#10
It's a question of what can be done without a backup.

Upon deleting a user account XenForo executes the following (from the user datawriter):

Code:
	/**
	 * Post-delete handling.
	 */
	protected function _postDelete()
	{
		$db = $this->_db;
		$userId = $this->get('user_id');
		$userIdQuoted = $db->quote($userId);

		$db->delete('xf_user_alert', "alerted_user_id = $userIdQuoted");
		$db->delete('xf_user_alert_optout', "user_id = $userIdQuoted");
		$db->delete('xf_user_change_log', "user_id = $userIdQuoted");
		$db->delete('xf_user_change_temp', "user_id = $userIdQuoted");
		$db->delete('xf_user_confirmation', "user_id = $userIdQuoted");
		$db->delete('xf_user_external_auth', "user_id = $userIdQuoted");
		$db->delete('xf_user_field_value', "user_id = $userIdQuoted");
		$db->delete('xf_user_follow', "follow_user_id = $userIdQuoted");
        $db->delete('xf_user_follow', "user_id = $userIdQuoted");
		$db->delete('xf_user_group_change', "user_id = $userIdQuoted");
		$db->delete('xf_user_group_promotion_log', "user_id = $userIdQuoted");
		$db->delete('xf_user_group_relation', "user_id = $userIdQuoted");
		$db->delete('xf_user_ignored', "ignored_user_id = $userIdQuoted");
        $db->delete('xf_user_ignored', "user_id = $userIdQuoted");
		$db->delete('xf_user_news_feed_cache', "user_id = $userIdQuoted");
		$db->delete('xf_user_trophy', "user_id = $userIdQuoted");
		$db->delete('xf_user_upgrade_active', "user_id = $userIdQuoted");
		$db->delete('xf_user_upgrade_expired', "user_id = $userIdQuoted");
		$db->delete('xf_warning', "user_id = $userIdQuoted");

		$db->delete('xf_permission_combination', "user_id = $userIdQuoted");
		$db->delete('xf_permission_entry', "user_id = $userIdQuoted");
		$db->delete('xf_permission_entry_content', "user_id = $userIdQuoted");

		if ($this->get('is_moderator'))
		{
			$db->delete('xf_moderator',  "user_id = $userIdQuoted");
			$db->delete('xf_moderator_content',  "user_id = $userIdQuoted");
		}
		if ($this->get('is_admin'))
		{
			$db->delete('xf_admin',  "user_id = $userIdQuoted");
			$db->delete('xf_admin_permission_entry',  "user_id = $userIdQuoted");
		}
		if ($this->get('is_banned'))
		{
			$db->delete('xf_user_ban',  "user_id = $userIdQuoted");
		}

		$db->delete('xf_profile_post', "profile_user_id = $userIdQuoted");

		$db->delete('xf_news_feed', "user_id = $userIdQuoted");

		$db->delete('xf_conversation_user', "owner_user_id = $userIdQuoted");
		// note: leaving records in conversation recipient to keep data somewhat intact for others

		$db->delete('xf_ip', "content_type = 'user' AND user_id = $userIdQuoted");
		// note: leaving content-associated IPs

		$db->delete('xf_forum_read', "user_id = $userIdQuoted");
		$db->delete('xf_thread_read', "user_id = $userIdQuoted");
		$db->delete('xf_forum_watch', "user_id = $userIdQuoted");
		$db->delete('xf_thread_watch', "user_id = $userIdQuoted");

		$this->getModelFromCache('XenForo_Model_Avatar')->deleteAvatar($userId, false);

		if ($this->get('user_state') == 'moderated')
		{
			$this->getModelFromCache('XenForo_Model_User')->rebuildUserModerationQueueCache();
		}

		$this->getModelFromCache('XenForo_Model_BbCode')->deleteBbCodeParseCacheForContent(
			'signature', $this->get('user_id')
		);

		$this->_getUserModel()->changeContentUser($userId, $this->get('username'), null, 0);
	}
A lot of items are permanently deleted such that they cannot be restored by any addon. Only a few items are spared from what I can see... posts, likes, and apparently conversation messages. I just examined that addon and it appears to only handle posts and likes. Nothing else is handled including profile information, custom fields, avatar, password, warnings, alerts, profile posts, follows, ignores, and conversations.

So basically the non-restore method (addon or manual queries) involves creating a new user and assigning it the posts and likes from the deleted user which is all that remains without restoring a backup. From looking at the code it appears that conversations should also remain, but you would have to update the user_ids similar to my previous query as well as recreate their inbox by inserting records into xf_conversation_user.
 

winter4w

Active member
#11
It's a question of what can be done without a backup.

Upon deleting a user account XenForo executes the following (from the user datawriter):

Code:
    /**
     * Post-delete handling.
     */
    protected function _postDelete()
    {
        $db = $this->_db;
        $userId = $this->get('user_id');
        $userIdQuoted = $db->quote($userId);

        $db->delete('xf_user_alert', "alerted_user_id = $userIdQuoted");
        $db->delete('xf_user_alert_optout', "user_id = $userIdQuoted");
        $db->delete('xf_user_change_log', "user_id = $userIdQuoted");
        $db->delete('xf_user_change_temp', "user_id = $userIdQuoted");
        $db->delete('xf_user_confirmation', "user_id = $userIdQuoted");
        $db->delete('xf_user_external_auth', "user_id = $userIdQuoted");
        $db->delete('xf_user_field_value', "user_id = $userIdQuoted");
        $db->delete('xf_user_follow', "follow_user_id = $userIdQuoted");
        $db->delete('xf_user_follow', "user_id = $userIdQuoted");
        $db->delete('xf_user_group_change', "user_id = $userIdQuoted");
        $db->delete('xf_user_group_promotion_log', "user_id = $userIdQuoted");
        $db->delete('xf_user_group_relation', "user_id = $userIdQuoted");
        $db->delete('xf_user_ignored', "ignored_user_id = $userIdQuoted");
        $db->delete('xf_user_ignored', "user_id = $userIdQuoted");
        $db->delete('xf_user_news_feed_cache', "user_id = $userIdQuoted");
        $db->delete('xf_user_trophy', "user_id = $userIdQuoted");
        $db->delete('xf_user_upgrade_active', "user_id = $userIdQuoted");
        $db->delete('xf_user_upgrade_expired', "user_id = $userIdQuoted");
        $db->delete('xf_warning', "user_id = $userIdQuoted");

        $db->delete('xf_permission_combination', "user_id = $userIdQuoted");
        $db->delete('xf_permission_entry', "user_id = $userIdQuoted");
        $db->delete('xf_permission_entry_content', "user_id = $userIdQuoted");

        if ($this->get('is_moderator'))
        {
            $db->delete('xf_moderator',  "user_id = $userIdQuoted");
            $db->delete('xf_moderator_content',  "user_id = $userIdQuoted");
        }
        if ($this->get('is_admin'))
        {
            $db->delete('xf_admin',  "user_id = $userIdQuoted");
            $db->delete('xf_admin_permission_entry',  "user_id = $userIdQuoted");
        }
        if ($this->get('is_banned'))
        {
            $db->delete('xf_user_ban',  "user_id = $userIdQuoted");
        }

        $db->delete('xf_profile_post', "profile_user_id = $userIdQuoted");

        $db->delete('xf_news_feed', "user_id = $userIdQuoted");

        $db->delete('xf_conversation_user', "owner_user_id = $userIdQuoted");
        // note: leaving records in conversation recipient to keep data somewhat intact for others

        $db->delete('xf_ip', "content_type = 'user' AND user_id = $userIdQuoted");
        // note: leaving content-associated IPs

        $db->delete('xf_forum_read', "user_id = $userIdQuoted");
        $db->delete('xf_thread_read', "user_id = $userIdQuoted");
        $db->delete('xf_forum_watch', "user_id = $userIdQuoted");
        $db->delete('xf_thread_watch', "user_id = $userIdQuoted");

        $this->getModelFromCache('XenForo_Model_Avatar')->deleteAvatar($userId, false);

        if ($this->get('user_state') == 'moderated')
        {
            $this->getModelFromCache('XenForo_Model_User')->rebuildUserModerationQueueCache();
        }

        $this->getModelFromCache('XenForo_Model_BbCode')->deleteBbCodeParseCacheForContent(
            'signature', $this->get('user_id')
        );

        $this->_getUserModel()->changeContentUser($userId, $this->get('username'), null, 0);
    }
A lot of items are permanently deleted such that they cannot be restored by any addon. Only a few items are spared from what I can see... posts, likes, and apparently conversation messages. I just examined that addon and it appears to only handle posts and likes. Nothing else is handled including profile information, custom fields, avatar, password, warnings, alerts, profile posts, follows, ignores, and conversations.

So basically the non-restore method (addon or manual queries) involves creating a new user and assigning it the posts and likes from the deleted user which is all that remains without restoring a backup. From looking at the code it appears that conversations should also remain, but you would have to update the user_ids similar to my previous query as well as recreate their inbox by inserting records into xf_conversation_user.
I did this and all it did was restore ownership of the post but not the post count. http://xenforo.com/community/threads/restore-a-deleted-user-account.16628/

UPDATE xf_post SET user_id = x WHERE username ='oldusername';
UPDATE xf_thread SET user_id = x WHERE username ='oldusername';

Can you tell me what else I need to do to restore as much as possible?
 

Jake Bunce

XenForo moderator
Staff member
#12
I did this and all it did was restore ownership of the post but not the post count. http://xenforo.com/community/threads/restore-a-deleted-user-account.16628/

UPDATE xf_post SET user_id = x WHERE username ='oldusername';
UPDATE xf_thread SET user_id = x WHERE username ='oldusername';

Can you tell me what else I need to do to restore as much as possible?
To rebuild post counts:

http://xenforo.com/community/resources/rebuild-user-post-counts-query.363/

And this script might be useful also if you need to rebuild likes:

http://xenforo.com/community/thread...t-profile-post-like-caches.42384/#post-457352
 

The Sandman

Well-known member
#13
I knew Jake would be right. Then again, in the scheme of things reassociating the posts with (what appears to be) the once deleted member is 98% of what's really important to everyone (aside from the member who was deleted).
 

audiokid

Active member
#16
Is it possible to merge all guest posts "user id 0" to a single user so I at least can search and//or have similar threads find posts made by deleted users? It appears once a user is deleted, it does a lot more harm than I ever expected.

If there is anything I can do to merge all deleted accounts and threads/posts into one username so the guest is at least back into an active state, that would be so helpful.
 

The Sandman

Well-known member
#17
You can use the Undelete Users Add-on by Jon (Waindigo) to restore the users you've deleted. Then you can manipulate them (e.g. merge them all and change the final username to anonymous, Guest Poster, or whatever).
 

audiokid

Active member
#18
Thanks, I have been looking at this, but from some user experiences I don't think its updated for 1.4.6 . I've left two posts on Jon's add-on with no response. I'm reluctant to start the process only to find it creates errors that require me to repair back. But, if it worked, I would be so happy.

Have you tried it?