Migrate a phpBB3 forum to Discourse

Возможно ли импортировать форумы phpBB в существующий форум Discourse, то есть объединить их? Я предполагаю, что это зависит от настроек сопоставления категорий.

Есть ли какие-либо проблемы, о которых стоит знать?

Объединяются ли пользователи, если у них одинаковый адрес электронной почты?

1 лайк

Да. Если вы не настроите собственное сопоставление категорий в файле настроек, новые категории будут создаваться по мере необходимости во время импорта. Если в Discourse уже существует категория, название которой совпадает с названием категории из phpBB, они будут объединены.

Да, конечно. Вот тема, где подробно описаны проблемы, с которыми я столкнулся. Там есть мои советы, а также репозиторий с моими объединёнными обновлениями для импортера.

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

2 лайка

Меня интересует, можно ли объединить форум phpBB3 с Discourse, сохранив все импортированные темы только для чтения. Я поискал в теме, но не нашел упоминания об этом. Спасибо.

Вы можете изменить скрипт импорта для архивирования всех созданных тем, или, возможно, будет проще сделать это массово после выполнения скрипта. Примеры см. по ссылке: Administrative Bulk Operations.

2 лайка

Здравствуйте,

У меня возникла проблема при запуске импортера. Похоже, ошибка происходит во время импорта пользователей или сразу после него. Я приложил стек вызовов и короткое 20-секундное видео вывода.

Пожалуйста, дайте рекомендации.

0x00007fe87a88bb10 /var/www/discourse/script/import_scripts/phpbb3/importers/user_importer.rb:87>}
/var/www/discourse/vendor/bundle/ruby/3.2.0/gems/activerecord-7.0.7/lib/active_record/validations.rb:80:in `raise_validation_error': Validation failed: Name can't be blank (ActiveRecord::RecordInvalid)
        from /var/www/discourse/vendor/bundle/ruby/3.2.0/gems/activerecord-7.0.7/lib/active_record/validations.rb:53:in `save!'
        from /var/www/discourse/vendor/bundle/ruby/3.2.0/gems/activerecord-7.0.7/lib/active_record/transactions.rb:302:in `block in save!'
        from /var/www/discourse/vendor/bundle/ruby/3.2.0/gems/activerecord-7.0.7/lib/active_record/transactions.rb:354:in `block in with_transaction_returning_status'
        from /var/www/discourse/vendor/bundle/ruby/3.2.0/gems/activerecord-7.0.7/lib/active_record/connection_adapters/abstract/database_statements.rb:314:in `transaction'
        from /var/www/discourse/vendor/bundle/ruby/3.2.0/gems/activerecord-7.0.7/lib/active_record/transactions.rb:350:in `with_transaction_returning_status'
        from /var/www/discourse/vendor/bundle/ruby/3.2.0/gems/activerecord-7.0.7/lib/active_record/transactions.rb:302:in `save!'
        from /var/www/discourse/vendor/bundle/ruby/3.2.0/gems/activerecord-7.0.7/lib/active_record/suppressor.rb:54:in `save!'
        from /var/www/discourse/script/import_scripts/base.rb:361:in `block in create_user'
        from /var/www/discourse/vendor/bundle/ruby/3.2.0/gems/activerecord-7.0.7/lib/active_record/connection_adapters/abstract/transaction.rb:319:in `block in within_new_transaction'
        from /var/www/discourse/vendor/bundle/ruby/3.2.0/gems/activesupport-7.0.7/lib/active_support/concurrency/load_interlock_aware_monitor.rb:25:in `handle_interrupt'
        from /var/www/discourse/vendor/bundle/ruby/3.2.0/gems/activesupport-7.0.7/lib/active_support/concurrency/load_interlock_aware_monitor.rb:25:in `block in synchronize'
        from /var/www/discourse/vendor/bundle/ruby/3.2.0/gems/activesupport-7.0.7/lib/active_support/concurrency/load_interlock_aware_monitor.rb:21:in `handle_interrupt'
        from /var/www/discourse/vendor/bundle/ruby/3.2.0/gems/activesupport-7.0.7/lib/active_support/concurrency/load_interlock_aware_monitor.rb:21:in `synchronize'
        from /var/www/discourse/vendor/bundle/ruby/3.2.0/gems/activerecord-7.0.7/lib/active_record/connection_adapters/abstract/transaction.rb:317:in `within_new_transaction'
        from /var/www/discourse/vendor/bundle/ruby/3.2.0/gems/activerecord-7.0.7/lib/active_record/connection_adapters/abstract/database_statements.rb:316:in `transaction'
        from /var/www/discourse/vendor/bundle/ruby/3.2.0/gems/activerecord-7.0.7/lib/active_record/transactions.rb:209:in `transaction'
        from /var/www/discourse/script/import_scripts/base.rb:360:in `create_user'
        from /var/www/discourse/script/import_scripts/base.rb:278:in `block in create_users'
        from /var/www/discourse/vendor/bundle/ruby/3.2.0/gems/rack-mini-profiler-3.1.1/lib/patches/db/mysql2/alias_method.rb:8:in `each'
        from /var/www/discourse/vendor/bundle/ruby/3.2.0/gems/rack-mini-profiler-3.1.1/lib/patches/db/mysql2/alias_method.rb:8:in `each'
        from /var/www/discourse/script/import_scripts/base.rb:266:in `create_users'
        from /var/www/discourse/script/import_scripts/phpbb3/importer.rb:106:in `block in import_anonymous_users'
        from /var/www/discourse/script/import_scripts/base.rb:948:in `block in batches'
        from /var/www/discourse/script/import_scripts/base.rb:947:in `loop'
        from /var/www/discourse/script/import_scripts/base.rb:947:in `batches'
        from /var/www/discourse/script/import_scripts/phpbb3/importer.rb:293:in `batches'
        from /var/www/discourse/script/import_scripts/phpbb3/importer.rb:102:in `import_anonymous_users'
        from /var/www/discourse/script/import_scripts/phpbb3/importer.rb:33:in `execute'
        from /var/www/discourse/script/import_scripts/base.rb:47:in `perform'
        from /var/www/discourse/script/import_scripts/phpbb3/importer.rb:22:in `perform'
        from script/import_scripts/phpbb3.rb:35:in `<module:PhpBB3>'
        from script/import_scripts/phpbb3.rb:16:in `<module:ImportScripts>'
        from script/import_scripts/phpbb3.rb:15:in `<main>'

РЕДАКТИРОВАНИЕ:

Похоже, проблема связана с анонимными пользователями. Думаю, я проверю свою базу данных.

 def map_anonymous_user(row)
      username = row[:post_username]

      {
        id: @settings.prefix(username),
        email: "anonymous_#{SecureRandom.hex}@no-email.invalid",
        username: username,
        name: @settings.username_as_name ? username : "",
        created_at: Time.zone.at(row[:first_post_time]),
        active: true,
        trust_level: TrustLevel[0],
        approved: true,
        approved_by_id: Discourse.system_user.id,
        approved_at: Time.now,
        post_create_action:
          proc do |user|
            row[:user_inactive_reason] = Constants::INACTIVE_MANUAL
            row[:ban_reason] = "Anonymous user from phpBB3" # TODO i18n
            suspend_user(user, row, true)
          end,
      }
    end

РЕДАКТИРОВАНИЕ

Мне удалось обойти ошибку, изменив эту строку в методе map_anonymous_user. Оказалось, что по умолчанию имя устанавливалось в пустую строку, поэтому я просто вставил туда слово.

Изменил это

name: @settings.username_as_name ? username : "",

на это

name: @settings.username_as_name ? username : "Anonymous ",
3 лайка

Могу ли я удалить старые посты перед запуском инкрементального импорта? Я успешно выполнил импорт локально в тестовой установке, восстановил его на сервере с Docker-установкой и планирую запустить импорт новых постов там. Однако, даже если игнорировать уже импортированные посты, запуск импорта на сервере занимает часы. Мой форум довольно большой (1,3 млн постов), а диск на сервере медленный, поэтому даже загрузка файла .sql занимает часы.

Вызовет ли это проблемы, если я сделаю что-то вроде DELETE FROM phpbb_posts WHERE post_id < 2926807 локально, затем даммп и загрузку этого на сервер и запущу импорт как обычно?

Я добавил настройку IMPORT_AFTER в некоторые скрипты, чтобы они импортировали только данные, полученные после определённой даты. Таким образом, мне нужно будет изменить SQL-запрос, который загружает сообщения, чтобы он получал только те, что были созданы за день до последнего дампа данных.

Однако, если у вас очень медленный диск, скорее всего, вы столкнётесь с трудностями при размещении Discourse. Устраивает ли вас производительность с имеющимися данными?

1 лайк

Да, для обычного использования я буду применять более быстрый диск, но его недостаточно для размещения нескольких копий базы данных одновременно, поэтому я перенаправляю /shared/import на более крупный, но медленный диск в секции volumes файла import.yml. Этот трюк отлично сработал при восстановлении начальной резервной копии: после того как восстановление не удалось из-за нехватки места (хотя у меня было свободно 18 ГБ, а база данных занимала 6 ГБ — я думаю, я видел, где вы упоминали, что при восстановлении создаются три копии базы данных), я перенаправил /shared/tmp на медленный диск. Но на тот момент простои не были проблемой.

Так что в повседневной работе ни размер, ни скорость не являются проблемой: мой форум довольно тихий, просто старый.

Я посмотрю, как можно модифицировать SQL в скриптах. Спасибо!

2 лайка

В файле settings.yml содержимое для подключения к MySQL выглядит так:


Где можно указать имя базы данных?

Имя базы данных должно быть указано в параметре schema. Да, название этого параметра немного сбивает с толку. Вы можете увидеть это здесь в коде: он передаётся как имя базы данных.

2 лайка

https://www.loom.com/share/1f66315779af4cf7b286c8541d4f3f09

Привет! Я записал короткое видео о проблеме, с которой мы столкнулись при импорте. Мы переносим около 650 000 постов.

Спасибо большое!

https://www.loom.com/share/1f66315779af4cf7b286c8541d4f3f09?sid=11a46d3c-8510-43a1-82e9-1a3524cbb365

Привет. Есть ли способ выполнять импорт построчно? У нас возникают проблемы с завершением скрипта. Некоторые вещи работают, например пользователи и аватары, другие — нет. Я переустанавливал сервер около четырёх раз, так как где-то прочитал, что после ошибки при импорте требуется чистая установка.

Другие детали указаны в видео, которое я опубликовал. Любая помощь будет оценена по достоинству.

Привет. Я уже около 18 часов занимаюсь миграцией, но всё ещё не могу добиться её успешного завершения. Не могли бы вы посмотреть моё видео и дать совет: есть ли какие-то полезные приёмы или, возможно, что-то упущено в настройках? Нам нужны только посты, темы, личные сообщения и категории. Аватары и пользователи работают. Сервер чистый, Ubuntu 22.04.

Более простое решение — сделать резервную копию после создания сайта, чтобы можно было восстановить её. Другой способ получить чистую базу данных — выполнить rake db:drop db:create db:migrate, но для этого нужно выполнить несколько дополнительных действий. Если вы не можете догадаться, что именно нужно сделать, исходя из сообщений об ошибках, то лучше воспользоваться решением с резервным копированием и восстановлением; к тому же, оно может оказаться быстрее.

Вы можете добавить несколько отладочных операторов puts, хотя структура скрипта phpbb3 может быть немного запутанной для тех, кто плохо знает Ruby.

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

Это выходит за рамки того, что я могу сделать бесплатно. Если у вас есть бюджет, вы можете связаться со мной напрямую или написать в канал Marketplace.

Скрипт импорта, похоже, не работает. Проблема показана в видео. Будем признательны, если кто-нибудь из команды Discourse Migrations сможет разобраться.

Если поддержка платная, не могли бы вы указать стоимость миграции? Я понимал, что это место, где мы задаём вопросы о том, как заставить скрипт работать. Я не против оплаты, просто думал, что это проект с открытым исходным кодом, и именно здесь мы можем задавать вопросы.

Я хочу сказать, что я здесь волонтёр, и не готов бесплатно смотреть видео, в основном из-за моего иррационального неприятия видеоконтента. Но я не единственный такой. Многие люди любят смотреть видео.

То есть каждый раз при запуске он создаёт дубликаты пользователей, созданных в предыдущем запуске? Не могу представить, чтобы такое было возможно. Вы уверены? Так работать он не должен.

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

Это так. Иногда людям нужна или требуется помощь, которую невозможно получить бесплатно.

2 лайка

Понял. Не могли бы вы опубликовать свои расценки на миграцию? Я понимаю, что скрипт, похоже, не работает, и требуется платная поддержка. Для меня это абсолютно нормально.

1 лайк

Миграции — довольно сложный процесс. Каждая из них сопряжена с уникальными вызовами, так как данные каждого форума индивидуальны. Отладка проблем миграции может занять несколько часов и требует детального анализа логов, базы данных, кода и т. д. Сложно помочь, просто глядя на эти сообщения, извините, что не могу быть более полезен! Вот наш FAQ по миграциям: Migrating to Discourse | Discourse - Civilized Discussion

Спасибо за ссылку. Я, кажется, разобрался с проблемой, и скрипт импорта теперь работает. Сейчас обработано примерно 100 000 из 666 357 сообщений. Chat GPT помог выявить некоторые ошибки, связанные с правами доступа, и другие проблемы.

2 лайка