아… 프로덕션 데이터에서 임포터를 두 번 이상 실행하는 것에 대해 전혀 생각해 본 적이 없네요. 좋은 아이디어를 알려 주셔서 감사합니다.
즉, 기본적으로 프로덕션 Drupal 데이터베이스 덤프를 가져온 후 Drupal 포럼을 대중에게 계속 개방한 채로 임포터의 전체 가져오기를 수행하고, 그 과정이 끝나면 Drupal 포럼을 오프라인 모드로 전환하여 두 번째 데이터베이스 덤프를 생성하고, 해당 덤프를 임포터의 MySQL 인스턴스에 로드한 뒤 임포터 스크립트를 다시 실행하는 방식이 맞나요?
제가 볼 때 이 방식의 유일한 단점은 첫 번째 가져오기부터 두 번째 가져오기까지의 기간(예를 들어 3일) 동안 발생한 Drupal 게시글 수정이나 게시글 삭제, 또는 기존 사용자 프로필 변경 사항은 가져오지지 않고, 그 기간 동안 생성된 완전히 새로운 사용자 및 게시글만 가져오진다는 점입니다. 맞습니까?
최종 프로덕션 임포트 실행을 확정하고 바로 그 시점에, 임포트된 포럼 스레드 중 몇 가지를 무작위로 확인하다가 큰 문제를 발견했습니다. 여기서 반복적으로 언급되어 온 것처럼, 이는 실제로는 Discourse나 임포트 스크립트의 과실이 아닙니다. 하지만 드루팔(Drupal) 용어인 '댓글’에 해당하는 토픽 답변이 수정될 때, 가끔created 타임스탬프가 변경되는 것으로 밝혀졌습니다. 제 판단으로는 대신 changed 타임스탬프가 변경되어야 합니다. 하지만 드루팔의 이 버그에도 불구하고 여전히 댓글 스레딩 순서는 유지됩니다. 다만 Discourse용 드루팔 임포트 스크립트는 답변을 created 타임스탬프 기준으로 정렬하는 것 같습니다(그런데 drupal.rb 스크립트에서 ORDER 절을 찾아볼 수 없기는 합니다). 드루팔 데이터베이스에서 phpMyAdmin으로 테스트해 본 결과, 원래의 드루팔 댓글 ID인 cid를 통해 올바른 스레딩 순서를 유지하려면 단순히 ORDER BY c.cid ASC만 있으면 되는 것으로 보입니다. cid는 순차적이며 절대 변경되지 않으므로요. 하지만 Discourse 임포트어가 순차적인 답변들의 날짜가 순서대로 정렬되지 않은 경우를 허용하는지, 그리고/또는 자체적으로 게시 날짜 기준으로 정렬을 수행하는지 확신이 서지 않습니다. drupal.rb 임포트어의 원래 작성자(그리고 물론 다른 분들도)의 의견을 듣고 싶습니다. 이 방법이 작동할까요? 그리고 의도치 않은 결과가 있을까요?
그리고 당연히 Drupal은 created와 changed를 동일한 값으로 설정해 버렸죠… 그리고 이것은 가끔만 발생합니다. 제가 오래된 게시글을 편집해 보아도 재현할 수 없습니다. 하지만 이 주제에 대한 원글 작성자가 게시글을 올린 직후 "reserved"라는 본문을 가진 추가 댓글을 하나나 두 개 올렸고, 수년 후에 추가 정보를 넣기 위해 수정한 것과 동일한 문제가 여러 개의 장기 진행 중인 스레드에서 발생하고 있습니다.
그렇게 되면 말이 되겠지만, 여기 사용 중인 두 테이블에 걸쳐 동일한 문제의 편집된 댓글이 나뉘어 있는 상태입니다:
좋습니다. 이렇게 하면 제가 발견한 두 개의 뒤섞인 스레드가 수정되었고, 다른 부분에 해를 끼치지 않는 것 같습니다.
def import_replies
…
batches(BATCH_SIZE) do |offset|
results = mysql_query(<<-SQL
SELECT c.cid, c.pid, c.nid, c.uid, c.created,
f.comment_body_value body,
f.comment_body_format format
FROM comment c,
field_data_comment_body f,
node n
WHERE c.cid = f.entity_id
AND n.nid = c.nid
AND c.status = 1
AND n.type IN ('poll', 'forum')
AND n.status = 1
AND c.created > UNIX_TIMESTAMP(STR_TO_DATE('#{IMPORT_AFTER}', '%Y-%m-%d'))
ORDER BY c.cid ASC #<--- 수정됨
LIMIT #{BATCH_SIZE}
OFFSET #{offset}
SQL
).to_a
음, 이 문제가 결국 제 발목을 잡는 것 같습니다. postprocess_posts 함수가 구 내부 링크를 새로운 Discourse URL로 대체하기 때문에, Wayback Machine의 구 Drupal 투표용 https://web.archive.org/web/20230101093741/https://MyOldForum.com/node/98765 링크에 대해 코드에서 예외를 설정해 두었습니다. 그런데 분명 무언가 잘못되었는지, 방금 프로덕션 마이그레이션 사이트에서 링크가 https://web.archive.org/web/20230101093741/https://MyOldForum.com/t/-/12345 로 끝나는 것을 확인했습니다.
이제 더 이상 마이그레이션 컨텍스트가 아닌 상황에서, 원래의 Drupal 노드 nid가 포함된 사용자 정의 필드가 여전히 Discourse topics DB 테이블에서 사용 가능한가요? 그렇다면 View this poll on the Wayback Machine을 포함하는 첫 번째 게시물이 있는 모든 토픽에 대해 Rails 콘솔에서 문자열 치환을 수행할 수 있을 것 같습니다. 그리고 https://web.archive.org/web/20230101093741/https://MyOldForum.com/t/-/[01234567890]*
를 https://web.archive.org/web/20230101093741/http://MyOldForum.com/node/$original_nid
로 대체하면 됩니다.
제 원래의 투표 가져오기 함수는 다음과 같습니다:
def import_poll_topics
puts '', "importing poll topics"
polls = mysql_query(<<-SQL
SELECT n.nid nid, n.title title, n.uid uid, n.created created, n.sticky sticky, taxonomy_index.tid tid, node_counter.totalcount views
FROM node n
LEFT JOIN taxonomy_index ON n.nid = taxonomy_index.nid
LEFT JOIN node_counter ON n.nid = node_counter.nid
WHERE n.type = 'poll'
AND n.status = 1
SQL
).to_a
create_posts(polls) do |topic|
{
id: "nid:#{topic['nid']}",
user_id: user_id_from_imported_user_id(topic['uid']) || -1,
category: category_id_from_imported_category_id(topic['tid']),
# Use TEMPmyoldforum.com or else postprocess_posts() will try to convert the Wayback Machine /node/YYY link
raw: "### View this poll on the Wayback Machine:\n**https://web.archive.org/web/20230101093741/http://TEMPmyoldforum.com/node/#{topic['nid']}**",
created_at: Time.zone.at(topic['created']),
pinned_at: topic['sticky'].to_i == 1 ? Time.zone.at(topic['created']) : nil,
title: topic['title'].try(:strip),
views: topic['views'],
custom_fields: { import_id: "nid:#{topic['nid']}" }
}
end
end