Крупная миграция форума Drupal: ошибки импортера и ограничения

Ох… я даже не думал запускать импортёр более одного раза для данных на продакшене. Большое спасибо за эту идею.

Итак, по сути, я сделаю дамп базы данных Drupal на продакшене и запущу полный импорт, сколько бы это ни заняло времени, оставив форум Drupal открытым для публики. Затем я переведу форум Drupal в офлайн-режим, сделаю ещё один дамп базы данных, загрузлю его в экземпляр MySQL импортёра и снова запущу скрипт импортёра?

Единственный недостаток, который я вижу, заключается в том, что любые правки постов в Drupal, удаления постов или изменения существующих профилей пользователей в течение этого интервала (назовём его 3 днями) — от момента первоначального импорта до второго импорта — не будут импортированы. Будут импортированы только совершенно новые пользователи и посты, появившиеся в этот период, верно?

Верно. Данные, которые будут отредактированы, будут утеряны. Альтернативой является временное отключение форума от сети. Можно предупредить пользователей. На практике никто не жаловался.

Круто, это звучит как вполне разумный компромисс для минимизации простоев. Ещё раз спасибо за идею.

Только что после того, как я завершил финальный импорт в продакшн, я случайно проверил несколько импортированных тем форума и обнаружил серьёзную проблему. Как и ранее, это не вина Discourse или скрипта импорта. Оказывается, что при редактировании ответа на тему («комментария» в терминологии Drupal) иногда меняется метка времени created. Насколько я могу судить, должна изменяться метка времени changed. Несмотря на эту ошибку в Drupal, нитевидная структура комментариев сохраняется в правильном порядке. Однако скрипт импорта Drupal для Discourse, судя по всему, сортирует ответы по метке времени created (хотя в скрипте drupal.rb я не вижу никаких предложений ORDER). По результатам моих тестов в phpMyAdmin с базой данных Drupal, достаточно добавить ORDER BY c.cid ASC, чтобы сохранить правильный порядок нитей через исходный последовательный и неизменный идентификатор комментария Drupal — cid. Но я не уверен, позволит ли импортер Discourse, чтобы у последовательных ответов даты были не по порядку, и/или выполнит ли он собственную сортировку по дате публикации? Хотелось бы узнать мнение создателя скрипта импорта drupal.rb (и любого другого, конечно): сработает ли это и не повлечёт ли это каких-либо непредвиденных последствий?

Я думаю (но точно не знаю, база данных Drupal для меня не имеет смысла), что можно изменить запрос так, чтобы получать дату создания из оригинального поста, а не из отредактированного.

Кажется, есть таблица, содержащая оригинальный пост и время его создания, и другая — с правками.

Думаю, сортировка по cid ни к чему плохому не приведёт.

Это действительно не имеет никакого смысла. Проблема заключается в следующем: две выделенные строки должны быть вторым и третьим ответами в теме, но в Discourse они находятся где-то после 500-й позиции, потому что именно там стоит их временная метка.

И, разумеется, Drupal решил установить поля created и changed в одно и то же значение… И это происходит только иногда; я не могу воспроизвести это самостоятельно, редактируя старые посты. Однако у меня есть эта же проблема в нескольких длинных темах, где автор темы (OP) сначала опубликовал пост, а затем сразу же написал один или два дополнительных комментария со словом «reserved» в теле, чтобы позже добавить дополнительную информацию, что он и сделал несколько лет спустя.

Это имело бы смысл, но вот тот же проблемный отредактированный комментарий, распределённый по двум используемым им таблицам:


OK, похоже, это работает: исправляет две перемешанные ветки, которые я обнаружил, и, кажется, не вредит ничему другому.

  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 заменяет старые внутренние ссылки на новый URL Discourse, я сделал исключение в коде для ссылок https://web.archive.org/web/20230101093741/https://MyOldForum.com/node/98765, которые мой импортер создал для старых опросов Drupal в Wayback Machine. Но, похоже, что-то пошло не так, потому что я только что заметил на перенесенном продакшн-сайте, что ссылки оказались в виде https://web.archive.org/web/20230101093741/https://MyOldForum.com/t/-/12345.

Теперь, когда я больше не нахожусь в контексте контейнера миграции, доступно ли пользовательское поле с оригинальным nid ноды Drupal в таблице DB тем Discourse? Если да, то кажется возможным выполнить замену строки в консоли Rails для всех тем с первым сообщением, содержащим View this poll on the Wayback Machine, а затем заменить
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 или иначе postprocess_posts() попытается преобразовать ссылку /node/YYY из Wayback Machine
        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

Да.

t = Topic.find(1234)
t.custom_fields
t.custom_fields['import_id']