Migrate a vBulletin 4 forum to Discourse

Привет. Просто хочу поделиться своим решением.

Что касается проблем с кавычками. Как я уже говорил, я сталкивался с проблемами — регулярное выражение не захватывало кавычки, когда:

  • имя пользователя и ID поста могли быть заключены в двойные кавычки
  • были вложенные кавычки

Я решил выполнить поиск и замену с использованием другой логики. Вместо поиска тегов и их содержимого я использовал регулярное выражение, которое ищет только теги:

было:
raw.gsub!(%r{\[quote="?([^;]+);(\d+)"?\](.+?)\[\/quote\]}im) do

стало:
raw.gsub!(%r{(\[QUOTE(="?([^;]+);(\d+)"?)?\])|(\[\/QUOTE\])}im) do

а затем немного изменил определение источника цитаты:

      if $3 && $4
        if topic_lookup = topic_lookup_from_imported_post_id(post_id)
          post_number = topic_lookup[:post_number]
          topic_id = topic_lookup[:topic_id]
          "\n[quote=\"#{new_username},post:#{post_number},topic:#{topic_id}\"]\n"
        else
          "\n[quote=\"#{new_username}\"]\n"
        end
      elsif $5
        "\n[/quote]\n"        
      end

Также я изменил код для спойлеров. Вместо:

    # [spoiler=Some hidden stuff]SPOILER HERE!![/spoiler]
    raw.gsub!(%r{\[spoiler="?(.+?)"?\](.+?)\[/spoiler\]}im) do
      "\n#{$1}\n[spoiler]#{$2}[/spoiler]\n"
    end

который размывал текст, я конвертировал его в тег details:

    raw.gsub!(%r{(\[spoiler(="?(.*?)"?)?\])|(\[\/spoiler\])}im) do
      if $3
        "\n[details=#{$3}]\n"
      elsif $1
        "\n[details]\n"
      elsif $4
        "\n[/details]\n"
      end
    end

Дело в том, что в мире vBulletin спойлер — это не размытый контент, а скорее свернутый. Поэтому я считаю, что для скрипта импорта из vBulletin гораздо уместнее конвертировать спойлеры в details, а не в размытый спойлер.

Я также заметил тег упоминаний. В моем случае в vBulletin упоминания выглядели так:
[mention=XXX]username[/mention]

Регулярное выражение, используемое в скрипте, не учитывает, что тег может содержать ID пользователя.

    # [MENTION]<username>[/MENTION]
    raw.gsub!(%r{\[mention\](.+?)\[/mention\]}i) do
      new_username = get_username_for_old_username($1)
      "@#{new_username}"
    end

Я исправил это по-своему:

    # [MENTION]<username>[/MENTION]
    raw.gsub!(%r{\[mention(=\d+)?\](.+?)\[/mention\]}i) do
      new_username = get_username_for_old_username($2)
      "@#{new_username}"
    end
1 лайк

Это не соответствует действительности, когда я начал миграцию своего 24-летнего форума vBulletin, работающего на vB 3. Скрипт имел множество несовместимостей и других проблем. Однако я приложил много усилий для создания импортера для vBulletin 3 на основе скрипта для vB4.

Улучшенный скрипт включен в Discourse, он называется vbulletin3.rb. Использование скрипта импорта vB3 такое же, как описано в этом руководстве. Просто выполните bundle exec ruby script/import_scripts/vbulletin3.rb вместо этого.

В vBulletin3 есть несколько значительных изменений/улучшений:

  1. Копируются права доступа к форумам
  2. Создаются группы модераторов форумов
  3. Создаются группы пользователей, в которые можно вступить, с правильной конфигурацией
  4. Вложенность форумов импортируется до 3 уровней в глубину (максимум для Discourse)
  5. Для всех тем и сообщений регистрируются постоянные ссылки, предотвращая потерю ссылок
  6. Копируются некоторые базовые настройки форумов (например, заголовок, email для уведомлений, название компании)
  7. Импортируются опросы
  8. Значительные улучшения в конвертации bbcode в markdown
  9. Глубокие ссылки на темы, сообщения и вложения преобразуются в ссылки Discourse; для этого необходимо установить переменную окружения FORUM_URL в значение forum.hostname/path (без протокола).

Вместо попытки конвертировать личные сообщения vBulletin в личные сообщения Discourse пользователи получат системное личное сообщение, содержащее архив их личных сообщений. Структура личных сообщений в vBulletin не совсем совместима с Discourse. Попытка их конвертации также могла бы нарушить конфиденциальность в зависимости от того, как люди использовали личные сообщения в vBulletin.

Как и в случае с другими импортерами, конвертация может занять довольно много времени. Скрипт конвертации работал 5,5 часов на моей рабочей станции для 7 тысяч пользователей, 16 тысяч тем и 415 тысяч сообщений. Я не знаю, сколько времени заняла постобработка — я оставил её работать на ночь. С момента начала до конца форум был недоступен в течение 30 часов. В итоге я доволен результатом.

2 лайка

Вот это ностальгия :slight_smile:

Ваш форум выглядит очень приятно. Мне нравится чередование цветов в строках тем.

Похоже, что и эта тема, и инструмент импорта уже давно устарели. С помощью этой темы я решил несколько проблем, но теперь застрял на этапе импорта пользователей с следующей ошибкой. Кто-нибудь знает, как это исправить?

<internal:timev>:286:in at’: can’t convert NilClass into an exact number (TypeError)`

Либо запрос составлен неверно, либо в таблице отсутствует значение.

Довольно странно отвечать на это спустя столько лет, но сейчас я выполняю импорт из VB с помощью массового импортера, и оказалось, что многие изображения отсутствуют. Причина в том, что имя файла вложения было перемещено в другое поле.

 SELECT a.filedataid attachment_id, a.userid user_id, a.filename filename
             FROM attachment a
            WHERE a.attachmentid = 383075;

Теперь поле NUMBER.attach соответствует полю filedataid, а не полю attachment_id. Поэтому этот запрос нужно обновить в скрипте.

Мне поручили мигрировать форум vBulletin 4.25 на Discourse… Чтение этой ветки вызывает смешанные чувства… Похоже, это возможно, но потенциально это огромная головная боль и трата времени (чего я бы сейчас хотел избежать)…

Неужели нигде нет обновлённого скрипта для vBulletin 4.25? На официальной странице я вижу только версии 3 и 5?

Что ж, в директории массового импорта находятся скрипты vbulletin и vbulletin5, которым всего несколько месяцев. Запуск таких массовых импортов довольно сложен и плохо документирован.

Я выполнил более 100 импортов и уверен, что ни один из них не обошёлся без доработки скрипта по той или иной причине.

Я писал несколько скриптов импорта ещё до того, как по-настоящему выучил Ruby (но один профессор в середине 1980-х заверил меня, что после его курса «Языки программирования» я смогу сказать, что знаю любой язык, если у меня есть выходные и книга; он был в основном прав).

Но да, скорее всего, это будет не менее болезненным и затратным по времени, чем вы предполагаете.

Я подозреваю, что скрипт для vbulletin справится вполне достойно; я бы не рекомендовал использовать скрипт массового импорта, если у вас нет более миллиона постов и пользователей.

1 лайк

Спасибо за это :slight_smile:

Кажется, мне нужно решить, чем я буду заниматься в эти выходные :smiley:

1 лайк

Я был бы очень признателен за помощь с этим :face_with_spiral_eyes:

Я прочитал всю ветку и выполнил несколько шагов, которые здесь видел, но застрял.

  1. Подключаюсь по SSH к моему VPS
  2. Захожу в образ Docker
  3. Устанавливаю mariadb-server
  4. Пытаюсь выполнить команду mysql для создания базы данных, но получаю ошибку: ‘can’t connect to local server through socket’

Инструкции здесь датированы несколькими годами назад — я видел, что несколько человек столкнулись с той же ошибкой, но не нашёл решений.

Кто-нибудь выполнял этот процесс недавно и может указать правильное направление? Не думаю, что где-то упускаю пошаговое руководство, верно?

Редактирование: добавлю, что я перепробовал всевозможные ухищрения и в итоге установил образ Docker с MariaDB на локальный хост (не в Docker), после чего открыл порт. Теперь я могу подключиться к базе данных из образа Docker… но при запуске скрипта возникает ошибка: Gemfile: Undefined local variable or method mysql2. Я пытался установить gem, но это не удаётся… И прежде чем углубляться в устранение неполадок, у меня возникает ощущение, что я использую устаревшую информацию и, возможно, старые пакеты… Я просто очень запутался и мне нужна помощь!

Любая помощь будет оценена!

…Я продолжил и в итоге добрался до запуска скрипта! Однако после начала выполнения он завершается с ошибкой:

"root@vps-xxxxxxxx-app:/var/www/discourse/script/import_scripts# bundle exec ruby vbulletin.rb
/var/www/discourse/config/initializers/013-excon_defaults.rb:4:in `<main>': can't modify frozen Hash: {:chunk_size=>1048576,                                                             :ciphers=>"ECDHE-ECDSA- [................]"

…и, кажется, я исчерпал свои возможности по устранению неполадок.

Не знаю, имеет ли значение запуск из /var/www/discourse, но я всегда делаю именно так. Вот что рекомендуется в первом сообщении.

Мне не знакома эта ошибка.

1 лайк

К тому моменту, когда я вчера вечером сдался после часов «исследований», я так много экспериментировал с вещами вне моей зоны комфорта, что начал беспокоиться: не причиняю ли я больше вреда, чем пользы. Мне также очень хотелось узнать, делал ли кто-то это недавно и есть ли какой-то волшебный шаг, который я упустил, вместо того чтобы снова погружаться в повторяющиеся кроличьи норы :winking_face_with_tongue:

Возможно, возникла какая-то новая проблема. На днях я импортировал файл mbox и, думаю, это задействовало тот же код, который вызвал у вас ошибку.

Ах, я сделал это в контейнере, а эти инструкции предназначены для среды разработки. Вы настраивали среду разработки? Удалось ли вам запустить всё? Это непросто сделать через VPN.

Сегодня у меня мигрень, поэтому я удалю всё и попробую снова завтра.

Дам знать, как всё пройдёт :slightly_smiling_face:

1 лайк

Вы настроили среду разработки? Это был ваш первый шаг?

Я пробовал сделать это через хост-сервер VPS, а позже пытался исправить всё через контейнер. К тому моменту, как я закончил, я уже не был уверен, что и где именно делал. Скорее всего, это проблема моих навыков… Завтра я начну всё заново с чистого листа.

Если вы делаете это на виртуальной машине, то использование контейнера, скорее всего, будет проще. Я бы посмотрел другие примеры инструкций по импорту (в них будет шаблон MySQL).

Вы зайдёте в контейнер, возможно, отредактируете файл Gem и выполните bundle install.

Использование контейнера для MySQL или MariaDB, вероятно, имеет смысл (но тогда нужно убедиться, что контейнеры видят друг друга).

1 лайк

У меня есть отличная новость…

Скрипт работает (я составлю руководство, когда всё будет готово), он импортировал группы пользователей, но застрял на импорте самих пользователей. Думаю, дело в переменной часового пояса?

importing users
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/tzinfo-2.0.6/lib/tzinfo/timestamp.rb:138:in `for': Integer values are not supported (ArgumentError)

            raise ArgumentError, "#{value.class} values are not supported" unless is_time_like?(value)
                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
        from /var/www/discourse/vendor/bundle/ruby/3.3.0/gems/tzinfo-2.0.6/lib/tzinfo/timezone.rb:575:in `utc_to_local'
        from script/import_scripts/vbulletin.rb:1019:in `parse_timestamp'
        from script/import_scripts/vbulletin.rb:166:in `block (2 levels) in import_users'
        from /var/www/discourse/script/import_scripts/base.rb:267:in `block in create_users'
        from /var/www/discourse/script/import_scripts/base.rb:266:in `each'
        from /var/www/discourse/script/import_scripts/base.rb:266:in `create_users'
        from script/import_scripts/vbulletin.rb:148:in `block in import_users'
        from /var/www/discourse/script/import_scripts/base.rb:951:in `block in batches'
        from <internal:kernel>:187:in `loop'
        from /var/www/discourse/script/import_scripts/base.rb:950:in `batches'
        from script/import_scripts/vbulletin.rb:126:in `import_users'
        from script/import_scripts/vbulletin.rb:82:in `execute'
        from /var/www/discourse/script/import_scripts/base.rb:47:in `perform'
        from script/import_scripts/vbulletin.rb:1027:in `<main>'

В скрипте по умолчанию указано «America/Los Angeles». Форум vBulletin настроен на (GMT) Западноевропейское время (Лондон, Лиссабон, Касабланка), а в экземпляр Discourse, в который я импортирую данные, добавлены два часовых пояса: America/Los Angeles и Europe/Paris.

Подскажите, какой из них выбрать?

Не так важно, что именно вы выберете.

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

1 лайк