Ich habe das Problem debuggt und habe eine potenzielle Lösung (mit Hilfe von Gemini).
Ich habe diese Nachricht (der Inhalt der gezogenen Datei ist nicht wichtig) in Version 3.4.5 (die ich wusste, dass sie funktionierte) und der neuesten Version erstellt:
Ich habe dann 2 andere Konten verwendet, um beide Dateien herunterzuladen, und die Seite aktualisiert.
Ich habe keinen Download-Zähler für die „ohne-Anhang“-Datei gesehen (obwohl sie funktionierte, als ich die Quelle v3.4.5 verwendete). „mit-Anhang“ zeigte nie einen Download-Zähler an, ich habe ihn nur für die „Vollständigkeit“ hinzugefügt.
Wenn ich dies im Debugger ausführe:
post = Post.last
TopicLink.counts_for(Guardian.new(post.user), post.topic, [post])
Erhalte ich:
=> {8 =>
[{url: "/uploads/short-url/iMUBjeLNs0eRWZhdYnh24XGXY0f.funscript", clicks: 2, title: nil, internal: true, reflection: false},
{url: "/uploads/short-url/rgnPszmhmEizcRVBobULTkMP1UI.funscript", clicks: 0, title: nil, internal: true, reflection: false}]}
Also waren die Klicks da, aber die UI hat sie nicht berücksichtigt, weil sie durch die Regel gefiltert wurden, die Benutzer daran hindern soll, Klickzählungen für Links zu privaten/versteckten Themen zu sehen. Das Problem ist, dass die neue Regel nicht berücksichtigt, dass ein interner Link ein Thema ODER eine interne Datei sein kann. Alles, was internal ist und kein Thema, wird derzeit verworfen.
Ich konnte das Problem lösen, indem ich (in topic_link.rb) Folgendes änderte:
def self.apply_link_visibility_filters(builder, link:, target_topic:, target_posts:)
builder.where(<<\~SQL)
#{target_topic}.deleted_at IS NULL
AND (#{target_topic}.id IS NULL OR #{target_topic}.visible = true)
AND (#{link}.internal = false OR #{target_topic}.id IS NOT NULL)
AND (#{link}.link_post_id IS NULL OR (#{link}.link_post_id IS NOT NULL AND #{link_posts}.deleted_at IS NULL))
SQL
end
zum Folgenden:
def self.apply_link_visibility_filters(builder, link:, target_topic:, target_posts:)
builder.where(<<\~SQL)
#{target_topic}.deleted_at IS NULL
AND (#{target_topic}.id IS NULL OR #{target_topic}.visible = true)
AND (#{link}.internal = false OR #{link}.link_topic_id IS NULL OR #{target_topic}.id IS NOT NULL)
AND (#{link}.link_post_id IS NULL OR (#{link}.link_post_id IS NOT NULL AND #{link_posts}.deleted_at IS NULL))
SQL
end
Gemini vollständige Erklärung
Du hast genau den entscheidenden Hinweis gefunden! Indem du die beiden Versionen von topic_link.rb bereitstellst, ist es kristallklar, was genau diese Funktion in der neuesten Version von Discourse gebrochen hat.
Das Problem wird vollständig durch einen neuen Sicherheitsfilter verursacht, der zur Datenbankabfrage in counts_for hinzugefügt wurde.
Der Übeltäter: Die neue apply_link_visibility_filters-Methode
Wenn du in der Nähe des unteren Randes der neuen topic_link.rb-Datei schaust, wirst du diese neue Methode finden:
codeRuby
def self.apply_link_visibility_filters(builder, link:, target_topic:, target_posts:)
builder.where(<<~SQL)
#{target_topic}.deleted_at IS NULL
AND (#{target_topic}.id IS NULL OR #{target_topic}.visible = true)
AND (#{link}.internal = false OR #{target_topic}.id IS NOT NULL) <--- DAS IST DER FEHLER
AND (#{link}.link_post_id IS NULL OR (#{link}.link_post_id IS NOT NULL AND #{link_posts}.deleted_at IS NULL))
SQL
end
Warum dies Standard-Dateiuploads kaputt macht
Discourse-Entwickler haben diese SQL-Regel hinzugefügt, um zu verhindern, dass Benutzer Klickzählungen für Links zu privaten/versteckten Themen sehen, auf die sie keine Zugriffsberechtigung haben. Allerdings haben sie versehentlich Dateiuploads mit in den Strudel gezogen.
Hier ist genau, wie die SQL-Engine deinen without-attachment.funscript-Upload-Link bewertet:
- #{link}.internal = false: Wenn ein Upload gespeichert wird, markiert Discourse ihn als internal = true (weil die Datei auf deinem Forum gehostet wird). Dies wird also als FALSE ausgewertet.
- #{target_topic}.id IS NOT NULL: Da es sich um einen Datei-Upload und nicht um einen Link zu einem anderen Forum-Beitrag handelt, hat er kein Zieltopic. Die Topic-ID ist NULL. Dies wird also auch als FALSE ausgewertet.
- FALSE OR FALSE = FALSE.
Da beide Bedingungen fehlschlagen, filtert die SQL-Abfrage deinen Datei-Upload vollständig heraus, und die counts_for-Methode gibt ein leeres Array an den Serialisierer zurück.
(Hinweis: Der Grund, warum |attachment immer noch funktioniert, ist, dass das Frontend .attachment-Klassen über einen völlig separaten API-Endpunkt/Mechanismus für die Download-Verfolgung behandelt, der TopicLink vollständig umgeht!)
Wie man den Code behebt
Um diesen Fehler in deiner lokalen Umgebung zu beheben, musst du der SQL-Abfrage mitteilen: „Es ist in Ordnung, wenn ein interner Link kein Zieltopic hat, solange er nie eines haben sollte (wie bei einem Datei-Upload).“
Öffne app/models/topic_link.rb in deinem Dev Container, finde die apply_link_visibility_filters-Methode (ca. Zeile 185) und ändere die fehlerhafte Zeile in Folgendes:
Ändere dies:
AND (#{link}.internal = false OR #{target_topic}.id IS NOT NULL)
In dies:
AND (#{link}.internal = false OR #{link}.link_topic_id IS NULL OR #{target_topic}.id IS NOT NULL)
Warum dies es behebt:
Durch das Hinzufügen von #{link}.link_topic_id IS NULL sagst du der Datenbank, dass interne Links, die rein Dateien/Uploads sind, erlaubt werden. Es wird weiterhin erfolgreich Links blockieren, die ein link_topic_id haben, aber das target_topic fehlt/versteckt ist (was die Sicherheitsanforderung erfüllt, die die Discourse-Entwickler erreichen wollten).
