كيفية العثور على أي صور مفقودة؟

بالتأكيد. إليك النص raw:

"يبدو أن \"Fung-Wong\" أو \"Mario\" أو ببساطة \"Typhoon #16\" سـ[تضرب اليابـة يوم الخميس](http://www.jma.go.jp/jp/typh/1416l.html):\n\n![Typhoon 16](/uploads/default/35/4608d96d1b27846f.png)"

وهنا النص cooked:

"<p>يبدو أن “Fung-Wong” أو “Mario” أو ببساطة “Typhoon <span class=\"hashtag\">#16</span>” سـ<a href=\"http://www.jma.go.jp/jp/typh/1416l.html\" rel=\"nofollow noopener\">تضرب اليابـة يوم الخميس</a>:</p>\n<p><div class=\"lightbox-wrapper\"><a class=\"lightbox\" href=\"/uploads/default/original/2X/0/01bb9fb7e29c2b65fd663cdc58705d1720f8fea7.png\" title=\"4608d96d1b27846f.png\"><img src=\"/uploads/default/original/2X/0/01bb9fb7e29c2b65fd663cdc58705d1720f8fea7.png\" alt=\"Typhoon 16\" width=\"602\" height=\"500\"><div class=\"meta\">\n<svg class=\"fa d-icon d-icon-far-image svg-icon\" aria-hidden=\"true\"><use xlink:href=\"#far-image\"></use></svg><span class=\"filename\">4608d96d1b27846f.png</span><span class=\"informations\">800×664</span><svg class=\"fa d-icon d-icon-discourse-expand svg-icon\" aria-hidden=\"true\"><use xlink:href=\"#discourse-expand\"></use></svg>\n</div></a></div></p>"

هذه النصوص يصعب قراءتها عندما تكون مضغوطة في سطر واحد، لذا إليك النص raw بعد تنسيقه:

"يبدو أن \"Fung-Wong\" أو \"Mario\" أو ببساطة
\"Typhoon #16\" سـ[تضرب اليابـة يوم الخميس]
(http://www.jma.go.jp/jp/typh/1416l.html):\n\n
![Typhoon 16](/uploads/default/35/4608d96d1b27846f.png)"

وهنا النص cooked بعد تنسيقه:

"<p>
  يبدو أن “Fung-Wong” أو “Mario” أو ببساطة
  “Typhoon <span class=\"hashtag\">#16</span>” سـ
  <a href=\"http://www.jma.go.jp/jp/typh/1416l.html\" rel=\"nofollow noopener\">
    تضرب اليابـة يوم الخميس
  </a>:
 </p>\n
 <p>
   <div class=\"lightbox-wrapper\">
     <a class=\"lightbox\" href=\"/uploads/default/original/2X/0/01bb9fb7e29c2b65fd663cdc58705d1720f8fea7.png\" title=\"4608d96d1b27846f.png\">
       <img src=\"/uploads/default/original/2X/0/01bb9fb7e29c2b65fd663cdc58705d1720f8fea7.png\" alt=\"Typhoon 16\" width=\"602\" height=\"500\">
       <div class=\"meta\">\n
         <svg class=\"fa d-icon d-icon-far-image svg-icon\" aria-hidden=\"true\">
           <use xlink:href=\"#far-image\"></use>
         </svg>
         <span class=\"filename\">4608d96d1b27846f.png</span>
         <span class=\"informations\">800×664</span>
         <svg class=\"fa d-icon d-icon-discourse-expand svg-icon\" aria-hidden=\"true\">
           <use xlink:href=\"#discourse-expand\"></use>
         </svg>\n
       </div>
     </a>
   </div>
 </p>"

وللعلم، هناك عدد كبير (أكثر من مئة) من المنشورات المشابهة على موقعي:

[1] pry(main)> Post.where("raw ~* :regex AND cooked !~* :regex", regex: '/uploads/default/[0-9]+/').count
=> 135

يجب ألا تكون هناك تنسيقات مختلفة لعناوين URL في المحتوى الخام والمطبوخ. هل يمكنك إعادة خبز المنشور أعلاه؟ يمكنك القيام بذلك عبر قائمة المنشور إعادة بناء HTML أو عبر أمر post.rebake!. هل توجد أي حقول مخصصة للمنشور مرتبطة بـ “uploads” في هذا المنشور؟ يمكنك قراءة جميع الحقول المخصصة عبر أمر post.custom_fields.

إليك جميع الحقول المخصصة الأخرى في ذلك المنشور بالتحديد (قبل تشغيل أمر إعادة بناء HTML):

  id: 43,
  user_id: 1,
  topic_id: 36,
  post_number: 3,
  created_at: Mon, 22 Sep 2014 05:05:16 UTC +00:00,
  updated_at: Mon, 22 Sep 2014 05:11:22 UTC +00:00,
  reply_to_post_number: nil,
  reply_count: 0,
  quote_count: 0,
  deleted_at: nil,
  off_topic_count: 0,
  like_count: 0,
  incoming_link_count: 0,
  bookmark_count: 0,
  avg_time: 58,
  score: 1.2,
  reads: 6,
  post_type: 1,
  sort_order: 3,
  last_editor_id: -1,
  hidden: false,
  hidden_reason_id: nil,
  notify_moderators_count: 0,
  spam_count: 0,
  illegal_count: 0,
  inappropriate_count: 0,
  last_version_at: Mon, 22 Sep 2014 05:11:22 UTC +00:00,
  user_deleted: false,
  reply_to_user_id: nil,
  percent_rank: 0.585365853658537,
  notify_user_count: 0,
  like_score: 0,
  deleted_by_id: nil,
  edit_reason: "downloaded local copies of images",
  word_count: 34,
  version: 2,
  cook_method: 1,
  wiki: false,
  baked_at: Sun, 14 Apr 2019 09:28:00 UTC +00:00,
  baked_version: 2,
  hidden_at: nil,
  self_edits: 2,
  reply_quoted: false,
  via_email: false,
  raw_email: nil,
  public_version: 2,
  action_code: nil,
  image_url: "/uploads/default/original/2X/0/01bb9fb7e29c2b65fd663cdc58705d1720f8fea7.png",
  locked_by_id: nil

لا أرى حقلًا باسم uploads، لكن ربما يكون image_url هو ما تبحث عنه؟ كانت قيمته—قبل تشغيل أمر إعادة بناء HTML—كالتالي:

/uploads/default/original/2X/0/01bb9fb7e29c2b65fd663cdc58705d1720f8fea7.png

يبدو أن تشغيل أمر إعادة بناء HTML قد غيّر قيمة حقل image_url إلى:

https://{{SITE FQDN}}/uploads/default/35/4608d96d1b27846f.png

وقد تم تحديث جميع الروابط في النص المطبوخ أيضًا:

"<p>
  It looks like “Fung-Wong”, “Mario”, or simply
  “Typhoon <span class=\"hashtag\">#16</span>” will be
  <a href=\"http://www.jma.go.jp/jp/typh/1416l.html\" rel=\"nofollow noopener\">
    making landfall in Japan on Thursday
  </a>:
 </p>\n
 <p>
   <div class=\"lightbox-wrapper\">
     <a class=\"lightbox\" href=\"https://{{SITE FQDN}}/uploads/default/35/4608d96d1b27846f.png\">
       <img src=\"https://{{SITE FQDN}}/uploads/default/35/4608d96d1b27846f.png\" alt=\"Typhoon 16\" width=\"602\" height=\"500\">
       <div class=\"meta\">\n
         <svg class=\"fa d-icon d-icon-far-image svg-icon\" aria-hidden=\"true\">
           <use xlink:href=\"#far-image\"></use>
         </svg>
         <span class=\"filename\">4608d96d1b27846f.png</span>
         <span class=\"informations\">800×664</span>
         <svg class=\"fa d-icon d-icon-discourse-expand svg-icon\" aria-hidden=\"true\">
           <use xlink:href=\"#discourse-expand\"></use>
         </svg>\n
       </div>
     </a>
   </div>
 </p>"

ما هي العلاقة بين 4608d96d1b27846f.png و 01bb9fb7e29c2b65fd663cdc58705d1720f8fea7.png؟ لهما نفس الأبعاد ويبدوان متطابقين للوهلة الأولى، لكنهما ملفان مختلفان بوضوح:

$ diff /var/discourse/shared/standalone/uploads/default/35/4608d96d1b27846f.png /var/discourse/shared/standalone/uploads/default/original/2X/0/01bb9fb7e29c2b65fd663cdc58705d1720f8fea7.png
Binary files /var/discourse/shared/standalone/uploads/default/35/4608d96d1b27846f.png and /var/discourse/shared/standalone/uploads/default/original/2X/0/01bb9fb7e29c2b65fd663cdc58705d1720f8fea7.png differ

$ ls -l /var/discourse/shared/standalone/uploads/default/35/4608d96d1b27846f.png
-rw-r--r-- 1 chris www-data 150319 Jan 19 01:14 /var/discourse/shared/standalone/uploads/default/35/4608d96d1b27846f.png

$ ls -l /var/discourse/shared/standalone/uploads/default/original/2X/0/01bb9fb7e29c2b65fd663cdc58705d1720f8fea7.png
-rw-r--r-- 1 chris chris 95005 Jul  3 15:25 /var/discourse/shared/standalone/uploads/default/original/2X/0/01bb9fb7e29c2b65fd663cdc58705d1720f8fea7.png

وبالطبع، يبقى السؤال الذي تبلغ قيمته مليون دولار: كيف ينبغي لي أن أقوم بنقل /uploads/default/35/4608d96d1b27846f.png إلى مخطط الرفع الجديد؟

يبدو أن ملفات الرفع الخاصة بك لم تُنقل بشكل صحيح إلى المخطط الجديد. يجب أن يتولى التغيير SiteSetting.migrate_to_new_scheme = true هذه المهمة بنفسه. لست متأكدًا من سبب عدم حدوث ذلك في حالتك. يرجى التحقق من عدد ملفات الرفع التي لم تُنقل إلى المخطط الجديد. قم بتشغيل الأوامر أدناه للحصول على النتائج.

Upload.by_users.where("url NOT LIKE '%/original/_X/%' AND url LIKE '%/uploads/default%'").count
SiteSetting.migrate_to_new_scheme = true
Jobs::MigrateUploadScheme.new.execute(nil)
Upload.by_users.where("url NOT LIKE '%/original/_X/%' AND url LIKE '%/uploads/default%'").count

لا، هذه ليست حقولًا مخصصة. يجب عليك الحصول على قيم الحقول المخصصة عبر الأمر post.custom_fields.

آه، عذرًا! لقد أسأت فهم ما قصدته حقًا بحقول مخصصة.

قد أكون مخطئًا، لكن يبدو أن هذا المنشور بالتحديد لا يحتوي على أي منها:

[1] pry(main) > Post.find_by(:id => 43).custom_fields
=> {}

حسنًا، هذا مثير للاهتمام…

[2] pry(main) > Upload.by_users.where("url NOT LIKE '%/original/_X/%' AND url LIKE '%/uploads/default%'").count
=> 0
[3] pry(main) > Post.find_by(:id => 43).image_url
=> "https://{{SITE FQDN}}/uploads/default/35/4608d96d1b27846f.png"

يبدو أنه لا توجد نتائج تطابق الاستعلام الذي قدمته. هل هذا السلوك متوقع؟

أيضًا:

هل لديك أي فكرة عن الإجابة المحتملة على هذا السؤال؟

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

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

أواجه مشكلة في الصور المفقودة منذ نهاية أبريل تقريبًا، لكنني بدأت فقط في البحث فيها الليلة.

rake posts:missing_uploads
يوجد 26766 من مرفقات المنشورات مفقودة.

يوجد 22693 مرفقًا مفقودًا.
22683 من أصل 22693 هي مرفقات من النظام القديم.
يتأثر 9352 منشورًا من أصل 535188 منشورًا.

نحن نعمل على النسخة المستقرة… ونظرًا لأحدث المنشورات في هذا الموضوع، لست متأكدًا مما يجب فعله بعد الآن.

تعديل: اخترت ملف GIF معين ووجدت أنه غير موجود في مجلد المرفقات على الخادم المباشر، لكنه موجود في مجلد Tombstone على خادم النسخ الاحتياطي. قمت بنسخ هذا الملف باستخدام scp من خادم النسخ الاحتياطي (discourse/shared/standalone/uploads/tombstone/default/39/ee8670816301d4c4.gif) إلى مجلد Tombstone المطابق على الخادم المباشر، ثم أعدت تشغيل مهمة rake المذكورة أعلاه كاختبار.

الآن تظهر الصورة في المنشور المعني، وانخفضت الأرقام الإجمالية إلى:

يوجد 26750 من مرفقات المنشورات مفقودة.

يوجد 22692 مرفقًا مفقودًا.
22682 من أصل 22692 هي مرفقات من النظام القديم.
يتأثر 9336 منشورًا من أصل 535190 منشورًا.

يبدو أن مجلد Tombstone على الخادم المباشر بحجم 138 ميجابايت، بينما على خادم النسخ الاحتياطي يبلغ حجمه 9.5 جيجابايت، لذا سأقوم بمزامنة هذا المجلد باستخدام rsync وأعيد تشغيل مهمة rake مرة أخرى على أمل أن يؤدي ذلك إلى تقليل الأرقام المبلغ عنها بشكل أكبر.

@kansaichris يبدو أن لديك فقط 3 مشاركات تحتوي على روابط تحميل مفقودة. في هذه الحالة، يجب عليك تحرير نص المشاركة يدويًا واستبدال رابط التحميل برابط التحميل الصحيح.

@skl لديك العديد من التحميلات وفق المخطط القديم. بعد نسخ تحميلات “tombstone” من خادم النسخ الاحتياطي، يجب عليك تشغيل الأوامر أدناه لنقلها إلى المخطط الجديد.

rake posts:missing_uploads    # تأكد من أن أمر `rsync` قد قام بنسخ الملفات
rake uploads:recover          # في حال وجود أي تحميلات مفقودة بعد rsync
SiteSetting.migrate_to_new_scheme = true
Jobs::MigrateUploadScheme.new.execute(nil)
Upload.by_users.where("url NOT LIKE '%/original/_X/%' AND url LIKE '%/uploads/default%'").count
# تأكد من أن العدد هو 0
rake posts:missing_uploads    # تحقق من الإحصائية مرة أخرى

شكرًا لك على المساعدة، @vinothkannans. لقد اتبعت تعليماتك (استغرقت حوالي 12 ساعة للتنفيذ)، وقد انخفضت الأرقام إلى حد ما:

22614 من عمليات تحميل المنشورات مفقودة.
19830 من عمليات التحميل مفقودة.
19821 من أصل 19830 هي من عمليات التحميل وفق المخطط القديم.
7339 من أصل 535224 منشورًا متأثرة.

وبما أن هناك عمليات تحميل مفقودة لا تزال قائمة، فقد نظرت خارج مجلد tombstone ووجدت أن uploads/default على الخادم المباشر يعرض 22,885 مجلدًا فارغًا (بينما على خادم النسخ الاحتياطي يوجد 10 مجلدات فارغة فقط). كما أن هناك فرقًا في الحجم يزيد عن 10 جيجابايت على النسخ الاحتياطي، لذا سأقوم الآن بمزامنة uploads/default من النسخ الاحتياطي إلى الخادم المباشر باستخدام rsync، ثم سأتبع تعليماتك مرة أخرى.

تعديل: يبدو أن أمر rake posts:missing_uploads هو مهمة تستهلك وحدة المعالجة المركزية (CPU-bound) وتعمل بخيط واحد فقط، وقد استمرت لأكثر من 30 ساعة، لذا قمت مؤقتًا بتغيير حجم الخادم إلى مثيل مخصص لوحدة المعالجة المركزية. يبدو أن الصور قد عادت للظهور حتى الآن، وإن كانت وفق المخطط القديم، لذا يُفترض أن تحديثًا ما في Discourse هو ما تسبب في الحذف الأصلي في المقام الأول.

هه… إذا كان هناك بالفعل 3 منشورات فقط بها روابط تحميل مفقودة، فلماذا يبدو أن هناك 135 منشورًا يستخدم نصها الخام نظام التحميل القديم بينما يستخدم النص المطبوخ نظام التحميل الجديد؟

[1] pry(main)> Post.where("raw ~* :regex AND cooked !~* :regex", regex: '/uploads/default/[0-9]+/').count
=> 135

بسبب عدم تطابق مخططات عناوين URL للرفع في الأعمدة raw و cooked. مهمة posts:missing_uploads rake ستفحص الملفات المرفوعة بناءً على عمود cooked فقط. يجب عليك إصلاح عناوين URL غير المطابقة للرفع بأي طريقة. لا يمكنني مساعدتك دون النظر إلى قاعدة البيانات.

:crossed_fingers:

آه، حسنًا، لم أكن أدرك أن مهمة posts:missing_uploads تفحص عمود cooked فقط؛ وهذا سيشرح بالتأكيد التناقض. :+1:

هل من العادل القول إن عملية الهجرة التي تبدأ بتعيين SiteSetting.migrate_to_new_scheme إلى true تفحص أيضًا قيمة عمود cooked فقط؟

هجرة المخطط الجديد ستقوم باستبدال الروابط في كل من raw و cooked. لكن هذا لم يحدث في حالتك.

أظن ذلك. يمكنك أيضًا التحقق من عمود last_updated_at للمشاركات المتأثرة.

توقف المهمة عن العمل بسبب خطأ ويظهر نفس الخطأ في كل محاولة:

[2019-07-26T09:18:56.829375 #572]  WARN -- : تنسيق IFD غير صحيح: طريقة `map` غير معرّفة لـ nil:NilClass
....rake متوقفة!
ArgumentError: تم تقديم طول سالب -2
/var/www/discourse/vendor/bundle/ruby/2.6.0/gems/exifr-1.3.6/lib/exifr/jpeg.rb:89:in `readframe'
/var/www/discourse/vendor/bundle/ruby/2.6.0/gems/exifr-1.3.6/lib/exifr/jpeg.rb:116:in `examine'
/var/www/discourse/vendor/bundle/ruby/2.6.0/gems/exifr-1.3.6/lib/exifr/jpeg.rb:34:in `block in initialize'
/var/www/discourse/vendor/bundle/ruby/2.6.0/gems/exifr-1.3.6/lib/exifr/jpeg.rb:34:in `open'
/var/www/discourse/vendor/bundle/ruby/2.6.0/gems/exifr-1.3.6/lib/exifr/jpeg.rb:34:in `initialize'
/var/www/discourse/vendor/bundle/ruby/2.6.0/gems/discourse_image_optim-0.26.2/lib/image_optim/worker/jhead.rb:40:in `new'
/var/www/discourse/vendor/bundle/ruby/2.6.0/gems/discourse_image_optim-0.26.2/lib/image_optim/worker/jhead.rb:40:in `oriented?'
/var/www/discourse/vendor/bundle/ruby/2.6.0/gems/discourse_image_optim-0.26.2/lib/image_optim/worker/jhead.rb:27:in `optimize'
/var/www/discourse/vendor/bundle/ruby/2.6.0/gems/discourse_image_optim-0.26.2/lib/image_optim.rb:122:in `block (5 levels) in optimize_image'
/var/www/discourse/vendor/bundle/ruby/2.6.0/gems/discourse_image_optim-0.26.2/lib/image_optim/handler.rb:41:in `process'
/var/www/discourse/vendor/bundle/ruby/2.6.0/gems/discourse_image_optim-0.26.2/lib/image_optim.rb:122:in `block (4 levels) in optimize_image'
/var/www/discourse/vendor/bundle/ruby/2.6.0/gems/discourse_image_optim-0.26.2/lib/image_optim.rb:120:in `each'
/var/www/discourse/vendor/bundle/ruby/2.6.0/gems/discourse_image_optim-0.26.2/lib/image_optim.rb:120:in `block (3 levels) in optimize_image'
/var/www/discourse/vendor/bundle/ruby/2.6.0/gems/discourse_image_optim-0.26.2/lib/image_optim.rb:247:in `block in with_timeout'
المهام: TOP => posts:missing_uploads

هل تستخدم أحدث إصدار أم إصدارًا أقدم؟

أحدث إصدار مستقر “2.3.2 +4”

غالبًا ما ستحتاج إلى أن تكون على أحدث إصدار تجريبي.

إذا كنت تستضيف بنفسك، فلا يوجد سبب كبير للبقاء على الإصدار المستقر. في الواقع، من الصعب دعمه أكثر من ذلك.

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