دمج موقعين من Discourse في واحد

If you have two Discourse sites that you wish were one, this guide is for you.

There’s a tool called discourse_merger that can take one Discourse site and merge it into another.

Prereqs

This is not an easy task, and should be treated like any other migration to Discourse. You will not be running discourse_merger on a live production site. You will perform the merge in another environment where you can review the output before moving the result to production.

Copy vs Merge

Almost everything will be copied from one site to the other, but Categories and Users can be merged, which will avoid duplication.

  • Users will be merged if a user on both sites has the same email address.
  • Categories will be merged if they have the same name.

If you want to do any reorganization of your data, do it before merging.

Choose the destination site

Choose which site will be the destination for the data. This is the one that will retain all its styling and settings. The other site will have its users, categories, topics, posts, uploads, etc. copied/merged into the destination site.

How to do it

Take backups of both sites including files and copy them to the environment where you’ll perform the merge. It’s possible that they’re from different versions of Discourse, so we need them to be at the same version. I would choose to use the most recent version of Discourse while performing the merge.

Restore the destination site to the merger environment. If doing this from the command line:

bundle exec ruby script/discourse restore destination-2018-08-02-134227-v2018xxx.tar.gz

Next we’ll extract the other site.

cd /path/to/data
tar xvzf other-2018-08-02-134227-v2018xxx.tar.gz

The output will include the database dump and the upload files.

Create a database with the data:

psql
CREATE DATABASE "copyme" ENCODING = 'utf8';
\q
gunzip < /path/to/data/other-2018-08-02-134227-v2018xxx.tar.gz | psql -d copyme

If you’re running the import in an official Docker container (recommended), you will need to reset the postgres password to provide it to the script, otherwise you may encounter an error that the postgres user cannot access the database.

To change the password:

sudo -u postgres psql
\password postgres
(enter the new password)
\q

Now it’s time to run the script. Some env variables you’ll set:

DB_NAME: name of database being merged into the destination site.
DB_HOST: (optional) hostname of database being merged. leave blank if it’s local.
DB_PASS: password for the postgres user to access the database
UPLOADS_PATH: absolute path (site being merged) of the directory containing “original” and “optimized” dirs. e.g. /path/to/data/uploads/default
SOURCE_BASE_URL: base url of the site being merged. e.g. https://meta.discourse.org
SOURCE_CDN: (optional) base url of the CDN of the site being merged.

You may need to run a bundle install prior to running the import script to avoid errors. To do so:

su discourse -c 'bundle config set --local with generic_import && bundle install'

On the first run, you might need to install some extra dependencies for the gems required in import.

Once the bundle is complete, run the import.

su discourse -c 'DB_NAME=copyme DB_PASS=password SOURCE_BASE_URL=http://copy.othersite.com UPLOADS_PATH=/shared/import/data/uploads/default bundle exec ruby script/bulk_import/discourse_merger.rb'

When it’s done, review the output in a web browser.

You can use the remap tool to update links from the old forum.

bundle exec ruby script/discourse remap 'copy.othersite.com' 'hot.newsite.com'

Also rebake all posts with uploads:

rake posts:rebake_match["upload:"]

If everything looks good, take a backup of the result and restore it to your production server.

bundle exec ruby script/discourse backup

Last edited by @italo 2024-11-27T00:52:10Z

Last checked by @JammyDodger 2024-05-26T21:20:00Z

Check documentPerform check on document:
45 إعجابًا

يبدو أنه يعمل، ولكن عندما أقوم بعمل نسخة احتياطية أحصل على

pg_dump: error: query failed: ERROR:  permission denied for table migration_mappings

هذا غريب جداً.

تعديل: تم الحل باستخدام

ALTER USER discourse WITH SUPERUSER;
إعجاب واحد (1)

هل استخدم أحد هذا مؤخرًا؟ كيف سار الأمر؟

وهل يعرف أحد ما إذا كان من الممكن وضع المستخدمين تلقائيًا في مجموعة لكل منتدى أصلي أيضًا؟ (لتسهيل منحهم الأذونات اللازمة لعرض المواضيع من المنتدى/المنتديات التي أتوا منها.)

لقد كان الأمر صعبًا بعض الشيء. أعتقد أنني اضطررت إلى التعليق على بعض الأشياء. كانت هناك أيضًا مشكلة في صور الدمج.

أعتقد أنني سأضيف جميع مستخدمي الموقع الجديد إلى مجموعة ما حتى يكونوا في تلك المجموعة عند دمجهم. سيكون هذا أسهل من القيام بذلك بعد الدمج أو كجزء منه.

إعجابَين (2)

في المرة الأخيرة التي قمت فيها بذلك، كانت جميع التحميلات من الموقع المدمج مفقودة. حصلت على قائمة بالتحميلات من tar tf backupfile.tar.gz ووضعتها في allfiles.txtx ونسختها إلى دليل التحميلات. هذا البرنامج النصي (الذي من المحتمل ألا يعمل معك دون تعديل) أنشأ تحميلًا لكل ملف من هذه الملفات، ثم أدى إعادة الخبز للمنشورات إلى إصلاح كل (أو معظم؟) الصور المفقودة.

def process_uploads
  begin
    # اقرأ قائمة أسماء الملفات
    filenames = File.readlines('/shared/uploads/allfiles.txt').map(&:strip)
    count = 0

    filenames.each do |filename|
      # أضف /shared إلى بداية اسم الملف
      filename.gsub!(/\.\//,"")
      full_path = File.join('/shared/uploads/default/original/', filename)

      begin
        # تحقق مما إذا كان المسار موجودًا وهو ملف عادي (وليس دليلًا)
        count += 1
        
        if File.exist?(full_path) && File.file?(full_path)
          # افتح الملف
          File.open(full_path, 'r') do |tempfile|
            # أنشئ تحميلًا باستخدام المعلمات المحددة
            u = UploadCreator.new(tempfile, 'imported', {}).create_for(-1)
            puts "#{count} -- #{u.id}: #{u.url}"
          end
        else
          puts "تحذير: المسار غير موجود أو ليس ملفًا عاديًا: #{full_path}"
        end
      rescue => e
        puts "خطأ في معالجة الملف #{full_path}: #{e.message}"
        # استمر مع الملف التالي حتى لو فشل الحالي
        next
      end
    end
  rescue Errno::ENOENT
    puts "خطأ: لم يتم العثور على الملفات.txt"
  rescue => e
    puts "خطأ في قراءة الملفات.txt: #{e.message}"
  end
end

# تنفيذ المعالجة
process_uploads;

حصلت على المنشورات السيئة بهذه الطريقة:

 bad=Post.where("cooked like '%/images/transparent.png%'")

ثم هذا لتمييزها على أنها تحتاج إلى إعادة خبز:

bad.update_all(baked_version: nil)

كنت غير صبور، لذلك استخدمت

rake posts:rebake_uncooked_posts

لإعادة خبزها.

إعجابَين (2)

أتساءل عما إذا كان من الأسهل تحويل منتدى ديسكورس الذي أرغب في دمجه إلى xenforo (عادةً ما تكون أدوات الاستيراد الخاصة بهم ممتازة) ثم دمجه مع المنتديات الأخرى التي أرغب في أن تكون جزءًا من الدمج (والتي سيتم تحويلها بدورها إلى xenforo من vbulletin) ثم أخيرًا استيراد منتدى xenforo المدمج الجديد إلى ديسكورس..