Jarek Radosz f7ea2fdea5
FIX: Import posts of missing users from phpbb3 (#9085)
Posts without a user probably shouldn't happen unless there was some direct database tampering, but data like that has been seen in the wild.

The importer will assign those posts to the "system" user.
2020-03-06 22:54:40 +01:00

235 lines
9.0 KiB
Ruby

# frozen_string_literal: true
require_relative 'database_base'
require_relative '../support/constants'
module ImportScripts::PhpBB3
class Database_3_0 < DatabaseBase
def count_users
count(<<-SQL)
SELECT COUNT(*) AS count
FROM #{@table_prefix}users u
WHERE u.user_type != #{Constants::USER_TYPE_IGNORE}
SQL
end
def fetch_users(last_user_id)
query(<<-SQL, :user_id)
SELECT u.user_id, u.user_email, u.username, u.user_password, u.user_regdate, u.user_lastvisit, u.user_ip,
u.user_type, u.user_inactive_reason, g.group_name, b.ban_start, b.ban_end, b.ban_reason,
u.user_posts, u.user_website, u.user_from, u.user_birthday, u.user_avatar_type, u.user_avatar
FROM #{@table_prefix}users u
LEFT OUTER JOIN #{@table_prefix}groups g ON (g.group_id = u.group_id)
LEFT OUTER JOIN #{@table_prefix}banlist b ON (
u.user_id = b.ban_userid AND b.ban_exclude = 0 AND
(b.ban_end = 0 OR b.ban_end >= UNIX_TIMESTAMP())
)
WHERE u.user_id > #{last_user_id} AND u.user_type != #{Constants::USER_TYPE_IGNORE}
ORDER BY u.user_id
LIMIT #{@batch_size}
SQL
end
def count_anonymous_users
count(<<-SQL)
SELECT COUNT(DISTINCT p.post_username) AS count
FROM #{@table_prefix}posts p
JOIN #{@table_prefix}users u ON (p.poster_id = u.user_id)
WHERE p.post_username <> '' AND u.user_type = #{Constants::USER_TYPE_IGNORE}
SQL
end
def fetch_anonymous_users(last_username)
last_username = escape(last_username)
query(<<-SQL, :post_username)
SELECT p.post_username, MIN(p.post_time) AS first_post_time
FROM #{@table_prefix}posts p
JOIN #{@table_prefix}users u ON (p.poster_id = u.user_id)
WHERE p.post_username > '#{last_username}' AND u.user_type = #{Constants::USER_TYPE_IGNORE}
GROUP BY p.post_username
ORDER BY p.post_username
LIMIT #{@batch_size}
SQL
end
def fetch_categories
query(<<-SQL)
SELECT f.forum_id, f.parent_id, f.forum_name, f.forum_desc, x.first_post_time
FROM #{@table_prefix}forums f
LEFT OUTER JOIN (
SELECT MIN(topic_time) AS first_post_time, forum_id
FROM #{@table_prefix}topics
GROUP BY forum_id
) x ON (f.forum_id = x.forum_id)
WHERE f.forum_type != #{Constants::FORUM_TYPE_LINK}
ORDER BY f.parent_id, f.left_id
SQL
end
def count_posts
count(<<-SQL)
SELECT COUNT(*) AS count
FROM #{@table_prefix}posts
SQL
end
def fetch_posts(last_post_id)
query(<<-SQL, :post_id)
SELECT p.post_id, p.topic_id, t.forum_id, t.topic_title, t.topic_first_post_id, p.poster_id,
p.post_text, p.post_time, t.topic_status, t.topic_type, t.poll_title, t.topic_views,
CASE WHEN t.poll_length > 0 THEN t.poll_start + t.poll_length ELSE NULL END AS poll_end,
t.poll_max_options, p.post_attachment, p.poster_ip,
CASE WHEN u.user_type = #{Constants::USER_TYPE_IGNORE} THEN p.post_username ELSE NULL END post_username
FROM #{@table_prefix}posts p
JOIN #{@table_prefix}topics t ON (p.topic_id = t.topic_id)
LEFT OUTER JOIN #{@table_prefix}users u ON (p.poster_id = u.user_id)
WHERE p.post_id > #{last_post_id}
ORDER BY p.post_id
LIMIT #{@batch_size}
SQL
end
def get_first_post_id(topic_id)
query(<<-SQL).try(:first).try(:[], :topic_first_post_id)
SELECT topic_first_post_id
FROM #{@table_prefix}topics
WHERE topic_id = #{topic_id}
SQL
end
def fetch_poll_options(topic_id)
query(<<-SQL)
SELECT o.poll_option_id, o.poll_option_text, o.poll_option_total AS total_votes,
o.poll_option_total - (
SELECT COUNT(DISTINCT v.vote_user_id)
FROM #{@table_prefix}poll_votes v
JOIN #{@table_prefix}users u ON (v.vote_user_id = u.user_id)
JOIN #{@table_prefix}topics t ON (v.topic_id = t.topic_id)
WHERE v.poll_option_id = o.poll_option_id AND v.topic_id = o.topic_id
) AS anonymous_votes
FROM #{@table_prefix}poll_options o
WHERE o.topic_id = #{topic_id}
ORDER BY o.poll_option_id
SQL
end
def fetch_poll_votes(topic_id)
# this query ignores invalid votes that belong to non-existent users or topics
query(<<-SQL)
SELECT u.user_id, v.poll_option_id
FROM #{@table_prefix}poll_votes v
JOIN #{@table_prefix}poll_options o ON (v.poll_option_id = o.poll_option_id AND v.topic_id = o.topic_id)
JOIN #{@table_prefix}users u ON (v.vote_user_id = u.user_id)
JOIN #{@table_prefix}topics t ON (v.topic_id = t.topic_id)
WHERE v.topic_id = #{topic_id}
SQL
end
def get_voters(topic_id)
# anonymous voters can't be counted, but lets try to make the count look "correct" anyway
query(<<-SQL).first
SELECT MAX(x.total_voters) AS total_voters,
MAX(x.total_voters) - (
SELECT COUNT(DISTINCT v.vote_user_id)
FROM #{@table_prefix}poll_votes v
JOIN #{@table_prefix}poll_options o ON (v.poll_option_id = o.poll_option_id AND v.topic_id = o.topic_id)
JOIN #{@table_prefix}users u ON (v.vote_user_id = u.user_id)
JOIN #{@table_prefix}topics t ON (v.topic_id = t.topic_id)
WHERE v.topic_id = #{topic_id}
) AS anonymous_voters
FROM (
SELECT COUNT(DISTINCT vote_user_id) AS total_voters
FROM #{@table_prefix}poll_votes
WHERE topic_id = #{topic_id}
UNION
SELECT MAX(poll_option_total) AS total_voters
FROM #{@table_prefix}poll_options
WHERE topic_id = #{topic_id}
) x
SQL
end
def get_max_attachment_size
query(<<-SQL).first[:filesize]
SELECT IFNULL(MAX(filesize), 0) AS filesize
FROM #{@table_prefix}attachments
SQL
end
def fetch_attachments(topic_id, post_id)
query(<<-SQL)
SELECT physical_filename, real_filename
FROM #{@table_prefix}attachments
WHERE topic_id = #{topic_id} AND post_msg_id = #{post_id}
ORDER BY filetime DESC, post_msg_id
SQL
end
def count_messages
count(<<-SQL)
SELECT COUNT(*) AS count
FROM #{@table_prefix}privmsgs m
WHERE NOT EXISTS ( -- ignore duplicate messages
SELECT 1
FROM #{@table_prefix}privmsgs x
WHERE x.msg_id < m.msg_id AND x.root_level = m.root_level AND x.author_id = m.author_id
AND x.to_address = m.to_address AND x.message_time = m.message_time
)
SQL
end
def fetch_messages(last_msg_id)
query(<<-SQL, :msg_id)
SELECT m.msg_id, m.root_level AS root_msg_id, m.author_id, m.message_time, m.message_subject,
m.message_text, m.to_address, r.author_id AS root_author_id, r.to_address AS root_to_address, (
SELECT COUNT(*)
FROM #{@table_prefix}attachments a
WHERE a.topic_id = 0 AND m.msg_id = a.post_msg_id
) AS attachment_count
FROM #{@table_prefix}privmsgs m
LEFT OUTER JOIN #{@table_prefix}privmsgs r ON (m.root_level = r.msg_id)
WHERE m.msg_id > #{last_msg_id}
AND NOT EXISTS ( -- ignore duplicate messages
SELECT 1
FROM #{@table_prefix}privmsgs x
WHERE x.msg_id < m.msg_id AND x.root_level = m.root_level AND x.author_id = m.author_id
AND x.to_address = m.to_address AND x.message_time = m.message_time
)
ORDER BY m.msg_id
LIMIT #{@batch_size}
SQL
end
def count_bookmarks
count(<<-SQL)
SELECT COUNT(*) AS count
FROM #{@table_prefix}bookmarks
SQL
end
def fetch_bookmarks(last_user_id, last_topic_id)
query(<<-SQL, :user_id, :topic_first_post_id)
SELECT b.user_id, t.topic_first_post_id
FROM #{@table_prefix}bookmarks b
JOIN #{@table_prefix}topics t ON (b.topic_id = t.topic_id)
WHERE b.user_id > #{last_user_id} AND b.topic_id > #{last_topic_id}
ORDER BY b.user_id, b.topic_id
LIMIT #{@batch_size}
SQL
end
def get_config_values
query(<<-SQL).first
SELECT
(SELECT config_value FROM #{@table_prefix}config WHERE config_name = 'version') AS phpbb_version,
(SELECT config_value FROM #{@table_prefix}config WHERE config_name = 'avatar_gallery_path') AS avatar_gallery_path,
(SELECT config_value FROM #{@table_prefix}config WHERE config_name = 'avatar_path') AS avatar_path,
(SELECT config_value FROM #{@table_prefix}config WHERE config_name = 'avatar_salt') AS avatar_salt,
(SELECT config_value FROM #{@table_prefix}config WHERE config_name = 'smilies_path') AS smilies_path,
(SELECT config_value FROM #{@table_prefix}config WHERE config_name = 'upload_path') AS attachment_path
SQL
end
end
end