Commit d5ada433 authored by Patrick Schmalstig's avatar Patrick Schmalstig
Browse files

Implemented MANTIS-6178 (cms_importer must de-dup members by e-mail)

parent bfe487a4
Loading
Loading
Loading
Loading
+2 −88
Original line number Diff line number Diff line
@@ -1035,95 +1035,9 @@ class Module_admin_cns_members
            warn_exit(do_lang_tempcode('_MEMBER_NO_EXIST', escape_html($from_username)), false, false, 404);
        }

        if ($to_id == $from_id) {
            warn_exit(do_lang_tempcode('MERGE_SAME'));
        }

        // Reassign submitter field values
        $meta = $GLOBALS['SITE_DB']->query('SELECT m_table,m_name FROM ' . get_table_prefix() . 'db_meta WHERE ' . db_string_equal_to('m_type', 'MEMBER') . ' OR ' . db_string_equal_to('m_type', '?MEMBER') . ' OR ' . db_string_equal_to('m_type', '*MEMBER'));
        foreach ($meta as $m) {
            $db = get_db_for($m['m_table']);
            $db->query_update($m['m_table'], [$m['m_name'] => $to_id], [$m['m_name'] => $from_id], '', null, 0, false, true); // Errors suppressed in case rows conflict with existing
        }

        // Reassign poster usernames
        $GLOBALS['FORUM_DB']->query_update('f_posts', ['p_poster_name_if_guest' => $to_username], ['p_posting_member' => $from_id]);

        // Merge in post count caching
        $new_post_count = $GLOBALS['FORUM_DRIVER']->get_member_row_field($from_id, 'm_cache_num_posts') + $GLOBALS['FORUM_DRIVER']->get_member_row_field($to_id, 'm_cache_num_posts');
        $GLOBALS['FORUM_DB']->query_update('f_members', ['m_cache_num_posts' => $new_post_count], ['id' => $to_id], '', 1);

        // Reassign personal galleries
        if (addon_installed('galleries')) {
            $personal_galleries = $GLOBALS['SITE_DB']->query('SELECT name FROM ' . get_table_prefix() . 'galleries WHERE name LIKE \'member_' . strval($from_id) . '\_%\'');
            foreach ($personal_galleries as $gallery) {
                $old_gallery_name = $gallery['name'];
                $new_gallery_name = preg_replace('#^member_\d+_#', 'member_' . strval($to_id) . '_', $old_gallery_name);

                $GLOBALS['SITE_DB']->query_update('galleries', ['parent_id' => $new_gallery_name], ['parent_id' => $old_gallery_name]);
                $GLOBALS['SITE_DB']->query_update('images', ['cat' => $new_gallery_name], ['cat' => $old_gallery_name]);
                $GLOBALS['SITE_DB']->query_update('videos', ['cat' => $new_gallery_name], ['cat' => $old_gallery_name]);

                $test = $GLOBALS['SITE_DB']->query_select_value_if_there('galleries', 'name', ['name' => $new_gallery_name]);
                if ($test === null) { // Rename
                    $GLOBALS['SITE_DB']->query_update('galleries', ['name' => $new_gallery_name], ['name' => $old_gallery_name], '', 1);
                } else { // Delete
                    require_code('galleries2');
                    delete_gallery($old_gallery_name);
                }
            }
        }

        require_code('cns_members_action');
        require_code('cns_members_action2');

        // Merge in CPFs
        $custom_fields = cns_get_all_custom_fields_match_member($from_id);
        foreach ($custom_fields as $details) {
            if ($details['RAW'] != '') {
                cns_set_custom_field($to_id, intval($details['FIELD_ID']), $details['RAW']);
            }
        }

        // Delete old member
        if (post_param_integer('keep', 0) != 1) {
            cns_delete_member($from_id);
        }

        // Cache emptying ...
        cns_require_all_forum_stuff();

        require_code('cns_posts_action');
        require_code('cns_posts_action2');
        require_code('cns_topics_action2');
        require_code('cns_forums_action2');

        // Members
        cns_force_update_member_post_count($to_id);
        $num_warnings = $GLOBALS['FORUM_DB']->query_select_value('f_warnings', 'COUNT(*)', ['w_member_id' => $to_id]);
        $GLOBALS['FORUM_DB']->query_update('f_members', ['m_cache_warnings' => $num_warnings], ['id' => $to_id], '', 1);

        // Topics and posts
        require_code('cns_topics_action');
        $topics = $GLOBALS['FORUM_DB']->query_select('f_topics', ['id', 't_forum_id'], ['t_cache_first_member_id' => $from_id]);
        foreach ($topics as $topic) {
            cns_force_update_topic_caching($topic['id'], null, true, true);
        }
        $topics = $GLOBALS['FORUM_DB']->query_select('f_topics', ['id', 't_forum_id'], ['t_cache_last_member_id' => $from_id]);
        foreach ($topics as $topic) {
            cns_force_update_topic_caching($topic['id'], null, true, true);
        }

        // Forums
        require_code('cns_posts_action2');
        $forums = $GLOBALS['FORUM_DB']->query_select('f_forums', ['id'], ['f_cache_last_member_id' => $from_id]);
        foreach ($forums as $forum) {
            cns_force_update_forum_caching($forum['id']);
        }

        // ---
        require_code('cns_members2');

        log_it('MERGE_MEMBERS', $from_username, $to_username);
        cns_merge_members($from_id, $to_id, (post_param_integer('keep', 0) != 1));

        $user_link = $GLOBALS['FORUM_DRIVER']->member_profile_hyperlink($to_id, '', false);
        return inform_screen($this->title, do_lang_tempcode('MERGED_MEMBERS', $user_link));
+1 −0
Original line number Diff line number Diff line
@@ -385,6 +385,7 @@ JOINED_AGO=Days ago joined
LAST_ACTIVITY=Last activity
CANNOT_DELETE_ROOT_FORUM=You cannot delete the home forum
NUM_UNREAD={1} unread
DEDUP_MEMBERS=Merge (de-duplicate) members who have the same e-mail address according to last visit time
CACHE_FORUMS=Update the forum stats
CACHE_MEMBERS=Update the member stats
CACHE_TOPICS=Update all the topic stats
+108 −0
Original line number Diff line number Diff line
@@ -308,3 +308,111 @@ function cns_may_whisper(int $target, ?int $member_id = null) : bool
    $may_whisper_cache[$key] = $answer;
    return $answer;
}

/**
 * Merge one member into another member.
 *
 * @param  MEMBER $from_id The member ID to merge from
 * @param  MEMBER $to_id The member ID to merge into
 * @param  boolean $keep Whether to keep the $from_id member (false: the member will be deleted)
 */
function cns_merge_members(int $from_id, int $to_id, bool $keep = false)
{
    if ($to_id == $from_id) {
        warn_exit(do_lang_tempcode('MERGE_SAME'));
    }

    // Do not merge guests
    if (is_guest($from_id) || is_guest($to_id)) {
        warn_exit(do_lang_tempcode('INTERNAL_ERROR', escape_html('TODO')));
    }

    $from_username = $GLOBALS['FORUM_DRIVER']->get_username($from_id);
    $to_username = $GLOBALS['FORUM_DRIVER']->get_username($to_id);

    // Reassign submitter field values
    $meta = $GLOBALS['SITE_DB']->query('SELECT m_table,m_name FROM ' . get_table_prefix() . 'db_meta WHERE ' . db_string_equal_to('m_type', 'MEMBER') . ' OR ' . db_string_equal_to('m_type', '?MEMBER') . ' OR ' . db_string_equal_to('m_type', '*MEMBER'));
    foreach ($meta as $m) {
        $db = get_db_for($m['m_table']);
        $db->query_update($m['m_table'], [$m['m_name'] => $to_id], [$m['m_name'] => $from_id], '', null, 0, false, true); // Errors suppressed in case rows conflict with existing
    }

    // Reassign poster usernames
    $GLOBALS['FORUM_DB']->query_update('f_posts', ['p_poster_name_if_guest' => $to_username], ['p_posting_member' => $from_id]);

    // Merge in post count caching
    $new_post_count = $GLOBALS['FORUM_DRIVER']->get_member_row_field($from_id, 'm_cache_num_posts') + $GLOBALS['FORUM_DRIVER']->get_member_row_field($to_id, 'm_cache_num_posts');
    $GLOBALS['FORUM_DB']->query_update('f_members', ['m_cache_num_posts' => $new_post_count], ['id' => $to_id], '', 1);

    // Reassign personal galleries
    if (addon_installed('galleries')) {
        $personal_galleries = $GLOBALS['SITE_DB']->query('SELECT name FROM ' . get_table_prefix() . 'galleries WHERE name LIKE \'member_' . strval($from_id) . '\_%\'');
        foreach ($personal_galleries as $gallery) {
            $old_gallery_name = $gallery['name'];
            $new_gallery_name = preg_replace('#^member_\d+_#', 'member_' . strval($to_id) . '_', $old_gallery_name);

            $GLOBALS['SITE_DB']->query_update('galleries', ['parent_id' => $new_gallery_name], ['parent_id' => $old_gallery_name]);
            $GLOBALS['SITE_DB']->query_update('images', ['cat' => $new_gallery_name], ['cat' => $old_gallery_name]);
            $GLOBALS['SITE_DB']->query_update('videos', ['cat' => $new_gallery_name], ['cat' => $old_gallery_name]);

            $test = $GLOBALS['SITE_DB']->query_select_value_if_there('galleries', 'name', ['name' => $new_gallery_name]);
            if ($test === null) { // Rename
                $GLOBALS['SITE_DB']->query_update('galleries', ['name' => $new_gallery_name], ['name' => $old_gallery_name], '', 1);
            } else { // Delete
                require_code('galleries2');
                delete_gallery($old_gallery_name);
            }
        }
    }

    require_code('cns_members_action');
    require_code('cns_members_action2');

    // Merge in CPFs
    $custom_fields = cns_get_all_custom_fields_match_member($from_id);
    foreach ($custom_fields as $details) {
        if ($details['RAW'] != '') {
            cns_set_custom_field($to_id, intval($details['FIELD_ID']), $details['RAW']);
        }
    }

    // Delete old member
    if (!$keep) {
        cns_delete_member($from_id);
    }

    // Cache emptying ...
    cns_require_all_forum_stuff();

    require_code('cns_posts_action');
    require_code('cns_posts_action2');
    require_code('cns_topics_action2');
    require_code('cns_forums_action2');

    // Members
    cns_force_update_member_post_count($to_id);
    $num_warnings = $GLOBALS['FORUM_DB']->query_select_value('f_warnings', 'COUNT(*)', ['w_member_id' => $to_id]);
    $GLOBALS['FORUM_DB']->query_update('f_members', ['m_cache_warnings' => $num_warnings], ['id' => $to_id], '', 1);

    // Topics and posts
    require_code('cns_topics_action');
    $topics = $GLOBALS['FORUM_DB']->query_select('f_topics', ['id', 't_forum_id'], ['t_cache_first_member_id' => $from_id]);
    foreach ($topics as $topic) {
        cns_force_update_topic_caching($topic['id'], null, true, true);
    }
    $topics = $GLOBALS['FORUM_DB']->query_select('f_topics', ['id', 't_forum_id'], ['t_cache_last_member_id' => $from_id]);
    foreach ($topics as $topic) {
        cns_force_update_topic_caching($topic['id'], null, true, true);
    }

    // Forums
    require_code('cns_posts_action2');
    $forums = $GLOBALS['FORUM_DB']->query_select('f_forums', ['id'], ['f_cache_last_member_id' => $from_id]);
    foreach ($forums as $forum) {
        cns_force_update_forum_caching($forum['id']);
    }

    // ---

    log_it('MERGE_MEMBERS', $from_username, $to_username);
}
+3 −3
Original line number Diff line number Diff line
@@ -529,19 +529,19 @@ function make_dummy_db_row(string $table, bool $allow_null = true, array $forced
                $primary_map[$field] = $value8;
            }
        } elseif (strpos($type, 'UINTEGER') !== false) {
            $value9 = mt_rand(0, 4294967295);
            $value9 = mt_rand(0, 1000000);
            $map[$field] = $value9;
            if ($primary_field === true) {
                $primary_map[$field] = $value9;
            }
        } elseif (strpos($type, 'INTEGER') !== false) {
            $value10 = random_int(-2147483648, 2147483647);
            $value10 = random_int(-1000000, 1000000);
            $map[$field] = $value10;
            if ($primary_field === true) {
                $primary_map[$field] = $value10;
            }
        } elseif (strpos($type, 'REAL') !== false) {
            $value11 = (mt_rand(0, 4294967295) / 1000000);
            $value11 = (mt_rand(0, 1000000) / 1000000);
            $map[$field] = $value11;
            if ($primary_field === true) {
                $primary_map[$field] = $value11;
+1 −0
Original line number Diff line number Diff line
@@ -157,6 +157,7 @@ class Hook_import_cms_merge
        $info['final_message'] = do_lang_tempcode('FORUM_CACHE_CLEAR', escape_html($cleanup_url));

        $info['final_tasks'] = [
            ['cns_members_dedup', do_lang('DEDUP_MEMBERS'), 'f_members', 1000000], // Realistically, there would be very few e-mail address duplicates, and the hook uses intelligent SQL filtering so we aren't processing the full member list
            ['cns_topics_recache', do_lang('CACHE_TOPICS'), 'f_topics', 100],
            ['cns_recache', do_lang('CACHE_FORUMS'), 'f_topics', 100],
            ['cns_members_recache', do_lang('CACHE_MEMBERS'), 'f_members', 100],
Loading