Come trovare tutte le immagini mancanti?

Certo. Ecco il testo raw:

"Sembra che \"Fung-Wong\", \"Mario\" o semplicemente \"Typhoon #16\" [atterreranno in Giappone giovedì](http://www.jma.go.jp/jp/typh/1416l.html):\n\n![Typhoon 16](/uploads/default/35/4608d96d1b27846f.png)"

Ecco il testo cooked:

"<p>Sembra che “Fung-Wong”, “Mario” o semplicemente “Typhoon <span class=\"hashtag\">#16</span>” <a href=\"http://www.jma.go.jp/jp/typh/1416l.html\" rel=\"nofollow noopener\">atterreranno in Giappone giovedì</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>"

Questi sono piuttosto difficili da leggere quando sono compressi su una singola riga, quindi ecco il testo raw formattato:

"Sembra che \"Fung-Wong\", \"Mario\" o semplicemente
\"Typhoon #16\" <a href=\"http://www.jma.go.jp/jp/typh/1416l.html\">atterreranno in Giappone giovedì</a>:\n\n
![Typhoon 16](/uploads/default/35/4608d96d1b27846f.png)"

Ecco il testo cooked formattato:

"<p>
  Sembra che “Fung-Wong”, “Mario” o semplicemente
  “Typhoon <span class=\"hashtag\">#16</span>” <a href=\"http://www.jma.go.jp/jp/typh/1416l.html\" rel=\"nofollow noopener\">
    atterreranno in Giappone giovedì
  </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>"

Per quanto riguarda il valore aggiunto, ci sono parecchi post (ben oltre cento) come questo sul mio sito:

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

Non dovresti avere formati URL diversi nei contenuti raw e cotti. Puoi provare a ribollire il post sopra? Puoi farlo tramite il menu del post Ricostruisci HTML o con il comando post.rebake!. Esistono campi personalizzati del post relativi agli “uploads” in questo post? Puoi leggere tutti i campi personalizzati con il comando post.custom_fields.

Ecco tutti gli altri campi personalizzati di quel particolare post (prima di eseguire il comando Rebuild 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

Non vedo un campo uploads, ma forse image_url è quello che stai cercando? Il suo valore—prima di eseguire il comando Rebuild HTML—era:

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

Eseguire il comando Rebuild HTML sembra aver modificato il valore del campo image_url in:

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

Tutti gli URL nel testo elaborato sembrano essere stati aggiornati anch’essi:

"<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>"

Qual è la relazione tra 4608d96d1b27846f.png e 01bb9fb7e29c2b65fd663cdc58705d1720f8fea7.png? Hanno le stesse dimensioni e sembrano identici a prima vista, ma sono chiaramente file diversi:

$ 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

E, naturalmente, rimane la domanda da un milione di dollari: come dovrei procedere per migrare /uploads/default/35/4608d96d1b27846f.png al nuovo schema di caricamento?

Sembra che i tuoi caricamenti non siano stati migrati correttamente al nuovo schema. La modifica SiteSetting.migrate_to_new_scheme = true dovrebbe risolvere da sola questa situazione. Non sono sicuro del motivo per cui ciò non avvenga nel tuo caso. Controlla il numero di caricamenti non migrati al nuovo schema. Esegui i comandi qui sotto per ottenere i risultati.

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

No, questi non sono campi personalizzati. Dovresti ottenere i valori dei campi personalizzati con il comando post.custom_fields.

Oh, scusa! Ho frainteso completamente cosa intendevi per campi personalizzati.

Potrei sbagliarmi, ma non sembra che quel post specifico ne abbia alcuno:

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

Beh, questa è interessante…

[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"

Sembra che non ci siano risultati corrispondenti alla query che hai fornito. È questo il comportamento atteso?

Inoltre:

Hai idea di quale potrebbe essere la risposta a questa domanda?

Sembra che i tuoi upload siano già stati migrati al nuovo schema. Tuttavia, i post non sono stati mappati correttamente sugli URL del nuovo schema. Questi post si trovano ora in uno stato compromesso. Posso avere le credenziali del tuo sito in un messaggio privato? Così potrò indagare più a fondo quando sarò libero.

Ah, ecco cosa temevo. Purtroppo si tratta di un’installazione privata e non sono sicuro di avere l’autorizzazione a concedere l’accesso (root) al server a un soggetto esterno. Non c’è forse altro che possa fare per risolvere il problema?

Dal fine aprile ho notato immagini mancanti, ma solo stasera ho iniziato a indagare.

rake posts:missing_uploads
Mancano 26766 upload di post.

Mancano 22693 upload.
22683 su 22693 sono upload con il vecchio schema.
9352 su 535188 post sono interessati.

Siamo su una versione stabile… considerando gli ultimi post in questa discussione, non sono sicuro di quale sia il passo successivo.

Modifica: Ho scelto un file GIF specifico e ho scoperto che mancava dalla directory uploads sul server live; invece era presente nella directory tombstone sul mio server di backup. Ho copiato questo file dal server di backup (discourse/shared/standalone/uploads/tombstone/default/39/ee8670816301d4c4.gif) alla corrispondente directory tombstone sul server live, quindi ho rieseguito il comando rake sopra come test.

L’immagine ora è visibile nel post in questione e i numeri complessivi sono scesi a:

Mancano 26750 upload di post.

Mancano 22692 upload.
22682 su 22692 sono upload con il vecchio schema.
9336 su 535190 post sono interessati.

Sembra che la directory tombstone sul server live occupi 138 MB, mentre sul server di backup ne occupi 9,5 GB. Procederò quindi con un rsync di questa directory e rieseguirò il comando rake, nella speranza di ridurre ulteriormente i conteggi riportati.

@kansaichris sembra che tu abbia solo 3 post con caricamenti mancanti. In tal caso, dovresti modificare manualmente il testo grezzo del post inserendo l’URL corretto del caricamento.

@skl hai molti caricamenti con il vecchio schema. Dopo aver copiato i caricamenti “tombstone” dal server di backup, dovresti eseguire i seguenti comandi per migrarli al nuovo schema.

rake posts:missing_uploads    # assicurati che `rsync` abbia copiato i file
rake uploads:recover          # se ci sono caricamenti mancanti dopo 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
# assicurati che il conteggio sia 0
rake posts:missing_uploads    # controlla di nuovo lo stato

Grazie per l’aiuto, @vinothkannans. Ho seguito le tue istruzioni (ci sono volute circa 12 ore per l’esecuzione) e i numeri sono diminuiti in parte:

Mancano 22.614 caricamenti di post.
Mancano 19.830 caricamenti.
Di questi, 19.821 sono caricamenti con il vecchio schema.
Sono interessati 7.339 post su 535.224.

Poiché ci sono ancora caricamenti mancanti, ho esaminato anche al di fuori della cartella tombstone e ho scoperto che su upload/default del server live sono presenti 22.885 directory vuote (sul server di backup ce ne sono solo 10). C’è inoltre una differenza di dimensione superiore a 10 GB sul backup, quindi ora eseguirò un rsync di upload/default dal backup al server live e poi ripeterò le tue istruzioni.

Modifica: rake posts:missing_uploads sembra essere un’attività single-threaded limitata dalla CPU in esecuzione da oltre 30 ore, quindi ho temporaneamente ridimensionato il server su un’istanza dedicata alla CPU. Le immagini sembrano essere tornate, per il momento, sebbene con il vecchio schema; presumibilmente, un aggiornamento di Discourse aveva causato l’eliminazione originale in primo luogo.

Hmm… se ci sono davvero solo 3 post con caricamenti mancanti, perché sembrano essercene 135 il cui testo grezzo utilizza il vecchio schema di caricamento, anche se il testo elaborato usa quello nuovo?

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

A causa delle discrepanze nello schema degli URL di caricamento nelle colonne raw e cooked. Il task rake posts:missing_uploads controlla i caricamenti solo rispetto alla colonna cooked. In qualche modo devi correggere quegli URL di caricamento non corrispondenti. Non posso aiutarti senza esaminare il database.

:crossed_fingers:

Ah, capisco, non sapevo che il task posts:missing_uploads controllasse solo la colonna cooked—ciò spiegherebbe sicuramente la discrepanza. :+1:

È corretto affermare che anche il processo di migrazione avviato impostando SiteSetting.migrate_to_new_scheme su true controlli solo il valore della colonna cooked?

La nuova migrazione dello schema sostituirà gli URL sia in raw che in cooked (discourse/app/models/upload.rb at 73a45048a015890a4bce6ec7c203430900adfa02 · discourse/discourse · GitHub). Ma nel tuo caso non è accaduto.

Penso di sì. Puoi controllare anche la colonna last_updated_at dei post interessati.

L’attività è stata interrotta a causa di un errore, che si ripresenta identico ad ogni tentativo:

[2019-07-26T09:18:56.829375 #572]  WARN -- : IFD malformata: metodo `map' non definito per nil:NilClass
....rake interrotta!
ArgumentError: lunghezza negativa -2 fornita
/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'
Tasks: TOP => posts:missing_uploads

Sei sull’ultima versione o su una più vecchia?

Ultima versione stabile “2.3.2 +4”

Probabilmente dovrai essere sull’ultima beta.

Se stai effettuando un hosting autonomo, non c’è molta ragione per rimanere sulla versione stabile. In realtà, è più difficile da supportare.

Il cliente ha specificamente richiesto di rimanere sulla versione stabile. È stato categorico al riguardo quando ho assunto la gestione del progetto.