サブフォルダのインストールでアップロードが壊れています

Uploaded avatars and Gravatar not working with subfolder installation… と同様です。

サブフォルダインストールのアップロードがすべて壊れています。アップロードは実際のアップロードディレクトリに格納されますが、投稿のレンダリング時にすべての画像が src="" になります。

投稿を作成中…
https://i.imgur.com/ofOUY4e.png

投稿後…
https://i.imgur.com/EBmnD6e.png

驚くべきことに、別のブラウザ(現在は Chrome)に切り替えてトピック(画像がまだ壊れている場所)を表示し、編集 をクリックすると、編集プレビューで画像が再びレンダリングされます!

https://i.imgur.com/3rQirhc.png

これにより、サーバーへのアップロードが成功していることが確認できます。これはすでに確認済みです。

root@cs6991:/var/discourse# ./launcher enter app
x86_64 arch detected.
root@cs6991-app:/var/www/discourse# ls 'public/~cs6991/forum'
backups  uploads
root@cs6991-app:/var/www/discourse# ls 'public/~cs6991/forum/uploads'
default
root@cs6991-app:/var/www/discourse# ls 'public/~cs6991/forum/uploads/default/original/1X/'
08335563eac3a393e60a902d4d38cffdfa6d967d.png  3eee67e6460792667bab4f2248ad4643be4feae3.png
29e403dabcfee32379629fb6d844354193e278ba.png  42ecfcb27b534acc9f3436fa7d291c2fca106e57.png

しかし、実際のページにはレンダリングされていません。
アバターなどの他のアップロードでも同じ問題が発生します。

情報:

サブフォルダ: /~cs6991/forum

app.yml

## これはスタンドアロンの Discourse Docker コンテナテンプレートです
##
## このファイルを変更した後は、必ず再構築してください
## /var/discourse/launcher rebuild app
##
## 編集は非常に注意してください!
## YAML ファイルは、空白や配置の誤りに非常に敏感です!
## 必要に応じて、http://www.yamllint.com/ でこのファイルを検証してください

templates:
  - "templates/postgres.template.yml"
  - "templates/redis.template.yml"
  - "templates/web.template.yml"
  - "templates/web.ratelimited.template.yml"
## Let's Encrypt (https) を追加したい場合は、これらの 2 行をコメント解除してください
  #- "templates/web.ssl.template.yml"
  #- "templates/web.letsencrypt.ssl.template.yml"

## このコンテナはどの TCP/IP ポートを公開しますか?
## Apache や nginx のような他のウェブサーバーとポートを共有したい場合は、
## 詳細については https://meta.discourse.org/t/17247 を参照してください
expose:
  - "80:80"   # http
  - "443:443" # https

params:
  db_default_text_search_config: "pg_catalog.english"

  ## db_shared_buffers を総メモリの最大 25% に設定します。
  ## ブートストラップ時に検出された RAM に基づいて自動的に設定されますが、上書きすることもできます
  db_shared_buffers: "128MB"

  ## ソートパフォーマンスを向上させる可能性がありますが、接続ごとのメモリ使用量が増加します
  #db_work_mem: "40MB"

  ## このコンテナはどの Git リビジョンを使用しますか? (デフォルト: tests-passed)
  #version: tests-passed

env:
  LC_ALL: en_US.UTF-8
  LANG: en_US.UTF-8
  LANGUAGE: en_US.UTF-8
  # DISCOURSE_DEFAULT_LOCALE: en

  ## 同時に処理できるウェブリクエスト数は? メモリと CPU コアに依存します。
  ## ブートストラップ時に検出された CPU に基づいて自動的に設定されますが、上書きすることもできます
  UNICORN_WORKERS: 2

  ## TODO: この Discourse インスタンスが応答するホスト名
  ## 必須。Discourse は IP アドレスのみでは機能しません。
  DISCOURSE_HOSTNAME: 'cgi.cse.unsw.edu.au'

  ## コンテナを上記と同じホスト名 (-h オプション) で起動したい場合はコメント解除してください (デフォルトは "$hostname-$config")
  #DOCKER_USE_HOSTNAME: true

  ## TODO: 初期サインアップ時に管理者および開発者になるメールアドレスのカンマ区切りリスト
  ## 例: 'user1@example.com,user2@example.com'
  DISCOURSE_DEVELOPER_EMAILS: '<<REDACTED>>'

  ## TODO: 新規アカウントの検証と通知の送信に使用される SMTP メールサーバー
  # SMTP アドレス、ユーザー名、パスワードが必要です
  # 注意: SMTP パスワードの '#' 文字は問題を引き起こす可能性があります!
  DISCOURSE_SMTP_ADDRESS: email-smtp.ap-southeast-2.amazonaws.com
  DISCOURSE_SMTP_PORT: 587
  DISCOURSE_SMTP_USER_NAME: <<REDACTED>>
  DISCOURSE_SMTP_PASSWORD: <<REDACTED>>
  #DISCOURSE_SMTP_ENABLE_START_TLS: true           # (オプション、デフォルトは true)
  #DISCOURSE_SMTP_DOMAIN: discourse.example.com    # (一部のプロバイダーで必要)
  DISCOURSE_NOTIFICATION_EMAIL: discourse@cs6991.email    # (通知の送信元アドレス)

  ## Lets Encrypt テンプレートを追加した場合、下のコメントを解除して無料 SSL 証明書を取得してください
  #LETSENCRYPT_ACCOUNT_EMAIL: me@example.com

  ## この Discourse インスタンスの HTTP または HTTPS CDN アドレス (プル用に設定)
  ## 詳細については https://meta.discourse.org/t/14857 を参照してください
  #DISCOURSE_CDN_URL: https://discourse-cdn.example.com

  ## IP アドレスルックアップ用の MaxMind geolocation IP アドレスキー
  ## 詳細については https://meta.discourse.org/t/-/137387/23 を参照してください
  #DISCOURSE_MAXMIND_LICENSE_KEY: 1234567890123456

  DISCOURSE_RELATIVE_URL_ROOT: '/~cs6991/forum'

## Docker コンテナはステートレスです。すべてのデータは /shared に保存されます
volumes:
  - volume:
      host: /var/discourse/shared/standalone
      guest: /shared
  - volume:
      host: /var/discourse/shared/standalone/log/var-log
      guest: /var/log

## プラグインはここに配置します
## 詳細については https://meta.discourse.org/t/19157 を参照してください
hooks:
  after_code:
    - exec:
        cd: $home/plugins
        cmd:
          - git clone https://github.com/discourse/docker_manager.git

## ビルド後に実行するカスタムコマンド
run:
  - exec: echo "カスタムコマンドを開始します"
  ## 初回サインアップメールの「From」アドレスを設定したい場合は、コメントを解除して変更してください。
  ## 初回サインアップメールを受信したら、行を再度コメントアウトしてください。一度だけ実行する必要があります。
  #- exec: rails r "SiteSetting.notification_email='info@unconfigured.discourse.org'"
  - exec:
      cd: $home
      cmd:
        - mkdir -p public/~cs6991/forum
        - cd public/~cs6991/forum && ln -s ../../uploads && ln -s ../../backups
  - replace:
     global: true
     filename: /etc/nginx/conf.d/discourse.conf
     from: proxy_pass http://discourse;
     to: |
        rewrite ^/(.*)$ /~cs6991/forum/$1 break;
        proxy_pass http://discourse;
  - replace:
     filename: /etc/nginx/conf.d/discourse.conf
     from: etag off;
     to: |
        etag off;
        location /~cs6991/forum {
           rewrite ^/~cs6991/forum/?(.*)$ /$1;
        }
  - replace:
       filename: /etc/nginx/conf.d/discourse.conf
       from: $proxy_add_x_forwarded_for
       to: $http_your_original_ip_header
       global: true
  - exec: echo "カスタムコマンドを終了します"

それ以外は、すべて正常に機能しているように見えますが、アップロードのレンダリングだけが非常に奇妙な動作をしています。

完全に新規ビルドでこの動作を確認しました。つまり、/var/discourse を削除し、docker を完全に削除して、クラウドインストール + サブフォルダの手順に従いました。

さらに調査できることがあれば、喜んで対応させていただきます。(imgur リンクですみません。まだ画像 2 枚以上の埋め込みは許可されていません!)

よろしくお願いします!

「いいね!」 1

レンダリング前にソースがすでに削除されているようです。本番データベースにないためです。

# sudo -u postgres psql discourse
discourse=# select * from posts where id=13;
 id | user_id | topic_id | post_number |                             raw                             |                                                  cooked                                                  |        created_at         |        updated_at         | reply_to_post_number | reply_count | quote_count |         deleted_at         | off_topic_count | like_count | incoming_link_count | bookmark_count | score | reads | post_type | sort_order | last_editor_id | hidden | hidden_reason_id | notify_moderators_count | spam_count | illegal_count | inappropriate_count |      last_version_at       | user_deleted | reply_to_user_id | percent_rank | notify_user_count | like_score | deleted_by_id | edit_reason | word_count | version | cook_method | wiki |          baked_at          | baked_version | hidden_at | self_edits | reply_quoted | via_email | raw_email | public_version | action_code | locked_by_id | image_upload_id
----+---------+----------+-------------+-------------------------------------------------------------+----------------------------------------------------------------------------------------------------------+---------------------------+---------------------------+----------------------+-------------+-------------+----------------------------+-----------------+------------+---------------------+----------------+-------+-------+-----------+------------+----------------+--------+------------------+-------------------------+------------+---------------+---------------------+----------------------------+--------------+------------------+--------------+-------------------+------------+---------------+-------------+------------+---------+-------------+------+----------------------------+---------------+-----------+------------+--------------+-----------+-----------+----------------+-------------+--------------+-----------------
 13 |       1 |        7 |           2 | ![ferris|690x459](upload://5YA5Y9vjz0iQmn2DErtUBrHCKng.png) | <p><img src="" alt="ferris" data-base62-sha1="5YA5Y9vjz0iQmn2DErtUBrHCKng" width="690" height="459"></p> | 2022-09-01 19:30:38.97281 | 2022-09-01 19:30:38.97281 |                      |           0 |           0 | 2022-09-01 19:47:34.612042 |               0 |          0 |                   0 |              0 |   0.2 |     1 |         1 |          2 |              1 | f      |                  |                       0 |          0 |             0 |                   0 | 2022-09-01 19:30:38.993775 | f            |                  |          0.5 |                 0 |          0 |             1 |             |          5 |       1 |           1 | f    | 2022-09-01 19:30:38.972751 |             2 |           |          0 | f            | f         |           |              1 |             |              |

ネットワークタブから、画像付きの返信を作成します。

raw	"My+image+is+inserted+next:\n\n![ferris|690x459](upload://5YA5Y9vjz0iQmn2DErtUBrHCKng.png)\n\n\nThe+image+is+above."
unlist_topic	"false"
category	"4"
topic_id	"7"
is_warning	"false"
archetype	"regular"
typing_duration_msecs	"7500"
composer_open_duration_msecs	"14116"
featured_link	""
shared_draft	"false"
draft_key	"topic_7"
image_sizes[https://cgi.cse.unsw.edu.au/~cs6991/forum/uploads/default/original/1X/29e403dabcfee32379629fb6d844354193e278ba.png][width]	"1200"
image_sizes[https://cgi.cse.unsw.edu.au/~cs6991/forum/uploads/default/original/1X/29e403dabcfee32379629fb6d844354193e278ba.png][height]	"800"
nested_post	"true"

または、必要であれば生のクエリ文字列を使用します。

raw=My+image+is+inserted+next%3A%0A%0A!%5Bferris%7C690x459%5D(upload%3A%2F%2F5YA5Y9vjz0iQmn2DErtUBrHCKng.png)%0A%0A%0AThe+image+is+above.%26unlist_topic=false%26category=4%26topic_id=7%26is_warning=false%26archetype=regular%26typing_duration_msecs=7500%26composer_open_duration_msecs=14116%26featured_link=%26shared_draft=false%26draft_key=topic_7%26image_sizes%5Bhttps%3A%2F%2Fcgi.cse.unsw.edu.au%2F~cs6991%2Fforum%2Fuploads%2Fdefault%2Foriginal%2F1X%2F29e403dabcfee32379629fb6d844354193e278ba.png%5D%5Bwidth%5D=1200%26image_sizes%5Bhttps%3A%2F%2Fcgi.cse.unsw.edu.au%2F~cs6991%2Fforum%2Fuploads%2Fdefault%2Foriginal%2F1X%2F29e403dabcfee32379629fb6d844354193e278ba.png%5D%5Bheight%5D=800%26nested_post=true

レスポンスは投稿をエコーバックしているようで、その時点でsrcがすでに削除されていることがわかります。

{
  "action": "create_post",
  "post": {
    "id": 16,
    "name": null,
    "username": "z.kologlu",
    "avatar_template": "/~cs6991/forum/letter_avatar_proxy/v4/letter/z/b9bd4f/{size}.png",
    "created_at": "2022-09-02T05:37:25.680Z",
    "cooked": "<p>My image is inserted next:</p>\n<p><img src=\"\" alt=\"ferris\" data-base62-sha1=\"5YA5Y9vjz0iQmn2DErtUBrHCKng\" width=\"690\" height=\"459\"></p>\n<p>The image is above.</p>",
    "post_number": 5,
    "post_type": 1,
    "updated_at": "2022-09-02T05:37:25.680Z",
    "reply_count": 0,
    "reply_to_post_number": null,
    "quote_count": 0,
    "incoming_link_count": 0,
    "reads": 0,
    "readers_count": 0,
    "score": 0,
    "yours": true,
    "topic_id": 7,
    "topic_slug": "welcome-to-discourse",
    "display_username": null,
    "primary_group_name": null,
    "flair_name": null,
    "flair_url": null,
    "flair_bg_color": null,
    "flair_color": null,
    "version": 1,
    "can_edit": true,
    "can_delete": true,
    "can_recover": false,
    "can_wiki": true,
    "user_title": null,
    "bookmarked": false,
    "raw": "My image is inserted next:\n\n![ferris|690x459](upload://5YA5Y9vjz0iQmn2DErtUBrHCKng.png)\n\n\nThe image is above.",
    "actions_summary": [
      {
        "id": 3,
        "can_act": true
      },
      {
        "id": 4,
        "can_act": true
      },
      {
        "id": 8,
        "can_act": true
      },
      {
        "id": 7,
        "can_act": true
      }
    ],
    "moderator": false,
    "admin": true,
    "staff": true,
    "user_id": 1,
    "draft_sequence": 12,
    "hidden": false,
    "trust_level": 1,
    "deleted_at": null,
    "user_deleted": false,
    "edit_reason": null,
    "can_view_edit_history": true,
    "wiki": false,
    "reviewable_id": null,
    "reviewable_score_count": 0,
    "reviewable_score_pending_count": 0
  },
  "success": true
}

この問題をさらに調査したところ、この関数に行き着きました: discourse/app/models/post.rb at main · discourse/discourse · GitHub

ローカル関数を変更しました:

  def cook(raw, opts = {})
    Rails.logger.info("Cooking post with raw: #{raw}")
    # 例えばRSS経由でインポートされた一部の投稿では、生のHTMLをサポートしています。その場合、
    # レンダリングパイプラインをスキップできます。
    return raw if cook_method == Post.cook_methods[:raw_html]

    options = opts.dup
    options[:cook_method] = cook_method

    post_user = self.user
    options[:user_id] = post_user.id if post_user
    options[:omit_nofollow] = true if omit_nofollow?

    if self.with_secure_media?
      each_upload_url do |url|
        uri = URI.parse(url)
        if FileHelper.is_supported_media?(File.basename(uri.path))
          raw = raw.sub(
            url, Rails.application.routes.url_for(
              controller: "uploads", action: "show_secure", path: uri.path[1..-1], host: Discourse.current_hostname
            )
          )
        end
      end
    end

    cooked = post_analyzer.cook(raw, options)

    Rails.logger.info("Cooked into: #{cooked}")

    new_cooked = Plugin::Filter.apply(:after_post_cook, self, cooked)

    if post_type == Post.types[:regular]
      if new_cooked != cooked && new_cooked.blank?
        Rails.logger.debug("Plugin is blanking out post: #{self.url}\nraw: #{raw}")
      elsif new_cooked.blank?
        Rails.logger.debug("Blank post detected post: #{self.url}\nraw: #{raw}")
      end
    end

    Rails.logger.info("New cooked into: #{new_cooked}")

    new_cooked
  end

出力:

Completed 200 OK in 335ms (Views: 0.4ms | ActiveRecord: 0.0ms | Allocations: 78316)
done
done
Cooking post with raw: ![ferris|690x459](upload://5YA5Y9vjz0iQmn2DErtUBrHCKng.png)
Started POST "/~cs6991/forum/presence/update" for 127.0.0.1 at 2022-09-02 05:55:33 +0000
Processing by PresenceController#update as */*
  Parameters: {"client_id"=>"16308337827949548cb8b156301a493b", "leave_channels"=>["/discourse-presence/reply/7"]}
Completed 200 OK in 19ms (Views: 0.2ms | ActiveRecord: 0.0ms | Allocations: 6182)
done
Cooked into: <p><img src="" alt="ferris" data-base62-sha1="5YA5Y9vjz0iQmn2DErtUBrHCKng" width="690" height="459"></p>
New cooked into: <p><img src="" alt="ferris" data-base62-sha1="5YA5Y9vjz0iQmn2DErtUBrHCKng" width="690" height="459"></p>
done

投稿のアップロードをこの正確な行まで追跡できました。

https://github.com/discourse/discourse/blob/main/app/assets/javascripts/pretty-text/addon/sanitizer.js#L23

特に、

  // relative urls
  if (/^\\/[\\w\\.\\-]+/i.test(href)) {
    return href;
  }

は、私のフォーラムのURLがApacheのユーザーWebディレクトリ(私が制御できないもの)から提供されているため、~で始まるため、その正規表現が壊れます。
~を含めるように文字クラスを([\\w\\.\\-~]のように)変更すると、投稿のアップロードが修正されることを確認しましたが、痛ましいことにアバターのアップロードはまだ壊れています!

「いいね!」 1

…そして、もう一つの壊れた正規表現です。

同じ状況です。文字クラスに ~ が必要です。
これでアバターが修正されます。

「いいね!」 1

もしCoreがPRにあまり乗り気でない場合は、特定のサイト用のカスタムプラグインで恒久的に解決できるでしょう。

「いいね!」 1