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

<div data-theme-toc="true"> </div>

إذا كان لديك موقعان من Discourse تود دمجهما في موقع واحد، فهذا الدليل لك.

هناك أداة تسمى [discourse_merger](https://github.com/discourse/discourse/blob/main/script/bulk_import/discourse_merger.rb) يمكنها أخذ موقع Discourse واحد ودمجه في موقع آخر.

# المتطلبات الأساسية

هذه ليست مهمة سهلة، ويجب التعامل معها مثل أي عملية ترحيل أخرى إلى Discourse. لن تقوم بتشغيل `discourse_merger` على موقع إنتاج مباشر. ستقوم بإجراء الدمج في بيئة أخرى حيث يمكنك مراجعة المخرجات قبل نقل النتيجة إلى الإنتاج.

### النسخ مقابل الدمج

سيتم **نسخ** كل شيء تقريبًا من موقع إلى آخر، ولكن يمكن **دمج** الفئات والمستخدمين، مما يتجنب التكرار.

* سيتم دمج المستخدمين إذا كان لدى مستخدم في كلا الموقعين نفس عنوان البريد الإلكتروني.
* سيتم دمج الفئات إذا كان لها نفس الاسم.

إذا كنت ترغب في إجراء أي إعادة تنظيم لبياناتك، فقم بذلك قبل الدمج.

### اختر موقع الوجهة

اختر الموقع الذي سيكون وجهة البيانات. هذا هو الموقع الذي سيحتفظ بجميع التنسيقات والإعدادات الخاصة به. سيتم نسخ/دمج موقع الآخر بما في ذلك المستخدمين والفئات والمواضيع والمنشورات والتحميلات وما إلى ذلك إلى موقع الوجهة.

# كيفية القيام بذلك

خذ نسخًا احتياطية لكلا الموقعين *بما في ذلك الملفات* وانسخها إلى البيئة التي ستقوم فيها بإجراء الدمج. من المحتمل أنهما من إصدارات مختلفة من Discourse، لذلك نحتاج إلى أن يكونا على نفس الإصدار. أود اختيار استخدام أحدث إصدار من Discourse أثناء إجراء الدمج.

استرجع موقع الوجهة إلى بيئة الدمج. إذا كنت تقوم بذلك من سطر الأوامر:

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

بعد ذلك سنقوم بفك ضغط الموقع الآخر.

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

سيشمل الإخراج تفريغ قاعدة البيانات وملفات التحميل.

أنشئ قاعدة بيانات بالبيانات:

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

إذا كنت تقوم بتشغيل الاستيراد في حاوية Docker رسمية (موصى به)، فستحتاج إلى إعادة تعيين كلمة مرور postgres لتوفيرها للبرنامج النصي، وإلا فقد تواجه خطأ يفيد بأن المستخدم postgres لا يمكنه الوصول إلى قاعدة البيانات.

لتغيير كلمة المرور:

sudo -u postgres psql
\password postgres
(أدخل كلمة المرور الجديدة)
\q

الآن حان وقت تشغيل البرنامج النصي. بعض متغيرات البيئة التي ستقوم بتعيينها:

DB_NAME: اسم قاعدة البيانات التي يتم دمجها في موقع الوجهة.
DB_HOST: (اختياري) اسم المضيف لقاعدة البيانات التي يتم دمجها. اتركه فارغًا إذا كان محليًا.
DB_PASS: كلمة المرور للمستخدم postgres للوصول إلى قاعدة البيانات
UPLOADS_PATH: المسار المطلق (الموقع الذي يتم دمجه) للدليل الذي يحتوي على الدلائل “original” و “optimized”. على سبيل المثال، /path/to/data/uploads/default
SOURCE_BASE_URL: عنوان URL الأساسي للموقع الذي يتم دمجه. على سبيل المثال، https://meta.discourse.org
SOURCE_CDN: (اختياري) عنوان URL الأساسي لشبكة توصيل المحتوى (CDN) للموقع الذي يتم دمجه.

قد تحتاج إلى تشغيل bundle install قبل تشغيل برنامج الاستيراد النصي لتجنب الأخطاء. للقيام بذلك:

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

في التشغيل الأول، قد تحتاج إلى تثبيت بعض التبعيات الإضافية (dependencies) للجواهر (gems) المطلوبة في الاستيراد.

بمجرد اكتمال الحزمة، قم بتشغيل الاستيراد.

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'

عندما ينتهي، راجع المخرجات في متصفح الويب.

يمكنك استخدام أداة remap لتحديث الروابط من المنتدى القديم.

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

وكذلك إعادة خبز (rebake) جميع المنشورات التي تحتوي على تحميلات:

rake posts:rebake_match["upload:"]

إذا بدا كل شيء جيدًا، فقم بأخذ نسخة احتياطية من النتيجة وقم باستعادتها على خادم الإنتاج الخاص بك.

bundle exec ruby script/discourse backup
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 المدمج الجديد إلى ديسكورس..