Ich habe danach gegriffen, aber es scheint, dass ein API-Endpunkt zum Löschen eines Uploads nicht existiert.
Ich poste dies hier, da ich keine Erwähnungen oder Vorschläge dazu finden konnte. Das Nächstliegende, was ich gefunden habe, war: API: a scope with access to /uploads
In den granularen Umfangseinstellungen des API-Schlüssels für Uploads sehe ich, dass „erstellen“ verfügbar ist, „löschen“ jedoch nicht.
Es scheint, dass eine mögliche Umgehung darin bestehen könnte, eine benutzerdefinierte Automatisierung zu erstellen und diese über die API auszulösen.
Abhängig von Ihrer Konfiguration ist das Löschen von Uploads, die eine gemeinsam genutzte Ressource sind (referenziert durch Beiträge, Benutzerprofil, Abzeichen usw.), ohne angemessene Sorgfalt etwas riskant.
Außerdem werden sie nach einer Weile automatisch bereinigt, wenn sie nirgendwo referenziert werden.
Der Anwendungsfall ist die zeitkritische Entfernung von Uploads als Teil von “Human in the Loop”-Automatisierungs-Workflows unter Verwendung von activepieces, Data Explorer und der API.
Das Ziel ist es, regulären Moderatoren eine einfache Möglichkeit zu geben, Uploads sofort und mit Sicherheit vollständig zu entfernen, ohne SSH-Zugriff zu benötigen, und alle bekannten Fälle für das Brechen von Upload-Referenzen umfassend abzudecken sowie automatisch die spezifischen URLs (und im Falle von proxied Avataren das URL-Präfix basierend auf dem Benutzernamen) aus dem CDN zu löschen (purgen).
Ich war erleichtert, als ich beim Testen sah, dass Avatar-, Profilhintergrund- und Kartenhintergrund-Referenzen automatisch behandelt werden, wenn ein Upload zerstört wird.
Die beiden Hauptszenarien wären “verbrannte Erde” (scorched earth) und “chirurgische Entfernung” (surgical removal). Dies ist die laufende Arbeit für “verbrannte Erde”:
Konvertierung in eine Upload-Hash-Liste:
Avatar-URLs (Benutzernamen mittels Regex extrahieren) → Avatar-Hash über Data Explorer-Abfrage abrufen (der Hash ist nicht in der URL enthalten)
Topic-/Post-URLs → Alle in diesem Beitrag verwendeten Upload-Hashes mittels Data Explorer sammeln
Direkte Original-/optimierte Upload-URLs (einschließlich Profilhintergrund und Kartenhintergrund) → Hashes mittels Regex extrahieren
Anschließend jede Hash abfragen, um alle Vorkommen zu finden (eine Data Explorer-Abfrage zur Abdeckung aller Fälle, jeweils ein Hash):
Benutzername/ID-Liste für Benutzer, die ihn für einen Avatar verwendet haben
Benutzername/ID-Liste für Benutzer, die ihn für einen Profilhintergrund verwendet haben
Benutzername/ID-Liste für Benutzer, die ihn für einen Kartenhintergrund verwendet haben
Liste aller Beiträge (Rohdaten), die diesen Upload verwenden
Aktionen:
Alle Benutzer sperren (suspend), die den Upload für einen Avatar, Profilhintergrund oder Kartenhintergrund verwendet haben
Alle Benutzer sperren, deren Beiträge auf den Ziel-Upload verweisen, aber diejenigen ausschließen, deren Verweis innerhalb eines Zitats verschachtelt ist
Alle Themen löschen
Alle Beiträge löschen
Upload zerstören (kein API-Endpunkt)
Alle CDN-URLs (optimiert/unoptimiert) löschen (purgen)
Das Standardpräfix für proxied Avatar-URLs für jeden zugehörigen Benutzernamen löschen (um alle Größen abzudecken)
Das Szenario der chirurgischen Entfernung wäre im Wesentlichen dasselbe, würde aber die zugehörigen Benutzer nicht sperren und erfordert einige Änderungen hinsichtlich des Sammelns aller Upload-Hashes aus Post-/Topic-URLs.
Wahrscheinlich würden die Beiträge/Themen selbst immer noch gelöscht, um fehlerhafte Referenzen zu vermeiden, aber das Entfernen der Upload-Markdown-Syntax für diesen spezifischen Upload (ohne andere Uploads zu berühren) wäre besser, falls möglich. Ähnlich wie bei dieser Automatisierung, wenn sie nicht alle Markdown-Upload-Referenzen entfernt hätte.
Idealerweise möchte ich auch Hashes blockieren können, sodass nach dem Durchlaufen des Obigen jemand nicht einfach ein neues Konto erstellen und erneut hochladen kann.
Ich glaube nicht, dass dies derzeit für einen regulären Moderator möglich ist, z. B. durch die Verwendung von beobachteten Wörtern (watched words). Daher könnte das Durchführen eines periodischen Scans wie oben für eine Liste von Hashes eine Möglichkeit sein, dies zu handhaben.
Ich verlinke dies nur für Benutzer, die Ihren Beitrag lesen und ihm zustimmen, sie könnten daran interessiert sein, dafür abzustimmen (ich weiß, dass Sie ihn bereits gelesen haben):
Ja! Ich habe fast Freudentränen vergossen, als ich Ihr Plugin Anfang des Monats gesehen habe, haha. Vielen, vielen Dank für die Erstellung und Weitergabe.
Einige Szenarien, die ich damit nicht abdecken konnte:
Verwendung des Uploads: Suchpräfix, es schien nicht möglich zu sein, Profilhintergründe oder Kartenhintergründe zu finden (es sei denn, jemand hat diese Bilder direkt in einem Beitrag verlinkt).
Hartes Löschen von Bildern in diesem Szenario (Bild ohne Zuordnung zu Beiträgen).
Ähnlich für Avatare, z. B. den Hash des Avatars abrufen (er befindet sich normalerweise nicht in der URL) und dann alle anderen Konten finden, die ihn möglicherweise ebenfalls verwendet haben, falls eine Sperrung erforderlich ist + den Upload ohne Beitragszuordnung löschen.
Nice to haves:
Auslösen eines Webhooks bei der Löschung, um CDN-Bereinigungen nach der Löschung für alle Varianten der Uploads auszulösen.
Massen-/automatisches Löschen aller Beiträge/Themen, die den Upload-Verweis enthalten, wenn der Upload gelöscht wird.
In Discourse (Web-UI) scheint es weder für einen Administrator/Moderator noch für den Benutzer selbst nicht möglich zu sein, einen Benutzeravatar zu löschen (zu entfernen) (außer durch Hochladen eines Ersatzes). Dies ist für den Profilhintergrund und das Banner möglich. Aber beide zerstören den Upload nicht sofort, und wenn ein anderer unbekannter Benutzer existiert, der denselben Upload für einen Teil seines Profils (Avatar, Profilhintergrund, Profilkarte) verwendet, wird er später auch nicht bereinigt.
Ich kam zu dem Schluss, dass es sich lohnen könnte, einige automatisierte Workflows zu erstellen, die den größten Teil oder den gesamten Prozess abdecken können (mit menschlicher Überprüfung/Genehmigung und/oder vereinfachter menschlicher Eingabe). Um die konsistente Anwendung zu erleichtern, Randfälle abzudecken und idealerweise die Möglichkeit zu minimieren, dass nicht gelöschte Beiträge tote Upload-Verweise aufweisen. Außerdem automatische Sperrung bei Bedarf (es sei denn, der Ziel-Upload befindet sich in einem Zitat) und CDN-Bereinigung.
Dies ist, was ich bisher für die Data Explorer-Abfragen hatte (noch nicht beim „Zusammenfügen“-Teil), mit dem Ziel, Folgendes abzudecken:
Themen-URLs
Beitrags-URLs
Direkte Bild-URLs (Beiträge, Profilhintergrund, Kartenhintergrund)
Avatar-URLs (proxied)
Liste der Upload-Hashes vorbereiten
Benutzername (aus proxied Avatar-URL) zu Upload-Hash
-- [params]
-- user_id :username
SELECT
up.sha1 AS upload_hash
FROM
users u
JOIN uploads up ON up.id = u.uploaded_avatar_id
WHERE
u.id = :username
Beitrags-/Themen-URL zu Liste der Upload-Hashes
-- [params]
-- post_id :post_url
SELECT
COALESCE(json_agg(up.sha1), '[]'::json) AS upload_hashes
FROM
upload_references ur
JOIN uploads up ON up.id = ur.upload_id
WHERE
ur.target_id = :post_url
AND ur.target_type = 'Post'
Die anderen mir bekannten Upload-URL-Typen haben den Hash in der URL selbst (es ist nicht erforderlich, den Data Explorer zu verwenden, um diese Hashes abzurufen).
Alle umsetzbaren Informationen zu einem Upload-Hash sammeln und vorbereiten
-- [params]
-- string :upload_hash
-- string :upload_schemeless_prefix
-- string :cdn_url_prefix
-- string :app_hostname
WITH target_uploads AS (
SELECT
id,
url,
user_id
FROM
uploads
WHERE
sha1 = :upload_hash
),
all_urls AS (
SELECT
url
FROM
target_uploads
UNION
SELECT
url
FROM
optimized_images
WHERE
upload_id IN (
SELECT
id
FROM
target_uploads)
),
post_data AS (
SELECT
p.id AS post_id,
p.topic_id,
u.id AS user_id,
u.username AS author,
p.created_at,
CASE WHEN p.post_number = 1 THEN
TRUE
ELSE
FALSE
END AS is_topic_starter,
CASE WHEN t.archetype = 'private_message' THEN
TRUE
ELSE
FALSE
END AS is_dm,
p.raw
FROM
upload_references ur
JOIN posts p ON p.id = ur.target_id
AND ur.target_type = 'Post'
JOIN topics t ON t.id = p.topic_id
JOIN users u ON u.id = p.user_id
WHERE
ur.upload_id IN (
SELECT
id
FROM
target_uploads)
AND p.deleted_at IS NULL
)
SELECT
(
SELECT
COALESCE(json_agg(id), '[]'::json)
FROM
target_uploads) AS upload_ids,
(
SELECT
COALESCE(json_agg(url), '[]'::json)
FROM
all_urls) AS upload_s3_schemeless_urls,
(
SELECT
COALESCE(json_agg(
CASE WHEN url LIKE '//%' THEN
REPLACE(url, :upload_schemeless_prefix, :cdn_url_prefix)
ELSE
:cdn_url_prefix || url
END), '[]'::json)
FROM
all_urls) AS upload_cdn_urls,
(
SELECT
COALESCE(json_agg(json_build_object('user_id', id, 'username', username)), '[]'::json)
FROM
users
WHERE
uploaded_avatar_id IN (
SELECT
id
FROM
target_uploads)) AS avatar_users,
(
SELECT
COALESCE(json_agg('https://' || :app_hostname || '/user_avatar/' || :app_hostname || '/' || username || '/'), '[]'::json)
FROM
users
WHERE
uploaded_avatar_id IN (
SELECT
id
FROM
target_uploads)) AS avatar_proxied_url_prefixes,
(
SELECT
COALESCE(json_agg(json_build_object('user_id', u.id, 'username', u.username)), '[]'::json)
FROM
user_profiles up
JOIN users u ON u.id = up.user_id
WHERE
up.profile_background_upload_id IN (
SELECT
id
FROM
target_uploads)) AS profile_background_users,
(
SELECT
COALESCE(json_agg(json_build_object('user_id', u.id, 'username', u.username)), '[]'::json)
FROM
user_profiles up
JOIN users u ON u.id = up.user_id
WHERE
up.card_background_upload_id IN (
SELECT
id
FROM
target_uploads)) AS card_background_users,
(
SELECT
COALESCE(json_agg(pd.topic_id), '[]'::json)
FROM
post_data pd
WHERE
pd.is_topic_starter = TRUE) AS topic_ids,
(
SELECT
COALESCE(json_agg(pd.post_id), '[]'::json)
FROM
post_data pd
WHERE
pd.is_topic_starter = FALSE) AS post_ids,
(
SELECT
COALESCE(json_agg(json_build_object('post_id', pd.post_id, 'topic_id', pd.topic_id, 'user_id', pd.user_id, 'author', pd.author, 'created_at', pd.created_at, 'is_topic_starter', pd.is_topic_starter, 'is_dm', pd.is_dm, 'raw', pd.raw)), '[]'::json)
FROM
post_data pd) AS post_details
Deckt nicht ab: Themen/Beiträge in der Warteschlange und Entwürfe
Ausgaben:
upload_ids (sollte nur eins sein)
upload_s3_schemeless_urls
upload_cdn_urls
avatar_users
avatar_proxied_url_prefixes
profile_background_users
card_background_users
topic_ids
post_ids
post_details
Dies liefert die erforderlichen Informationen, um diese APIs selektiv zu verwenden:
Einen Benutzer sperren (für Beiträge kann der Rohinhalt in post_details verwendet werden, um Benutzer bedingt auszuschließen, wenn sich der Upload-Markdown in einem Zitat befindet)
Upload-Löschung (API existiert derzeit nicht)
Und für weitere Aktionen:
Alle CDN-URLs bereinigen (alle Varianten, optimiert und Original usw.)
Präfix-URLs von proxied Avataren bereinigen (um alle Größen abzudecken)
Automatisch von Discourse behandelt:
Entfernt den Upload-Verweis sofort aus allen Benutzerprofilen (Avatar, Profilhintergrund und Kartenhintergrund), wenn ein Upload zerstört/gelöscht wird.