L’ho cercato, ma sembra che un endpoint API per eliminare un caricamento non esista.
Lo pubblico qui, poiché non sono riuscito a trovare menzioni o suggerimenti a riguardo; il più vicino che ho trovato è: API: a scope with access to /uploads
Nelle impostazioni di ambito granulare della chiave API per i caricamenti, vedo che ‘create’ (crea) è disponibile, ma ‘delete’ (elimina) no.
Sembra che una potenziale soluzione alternativa potrebbe essere quella di creare un automatismo personalizzato e attivarlo tramite API.
A seconda della configurazione, il caricamento di file come risorsa condivisa (a cui si fa riferimento tramite post, profilo utente, badge, ecc.) comporta un certo rischio se vengono eliminati senza la dovuta diligenza.
Inoltre, vengono automaticamente eliminati dopo un po’ di tempo se non sono più referenziati da nessuna parte.
Il caso d’uso è per la rimozione di upload sensibile al tempo come parte dei flussi di lavoro di automazione human-in-the-loop utilizzando activepieces, data explorer e l’API.
L’obiettivo è consentire ai moderatori regolari di avere accesso a un modo semplice per rimuovere in modo sicuro e completo gli upload immediatamente senza accesso SSH e coprire in modo esaustivo tutti i casi noti per la rottura dei riferimenti agli upload, oltre a eseguire il purge automatico tramite CDN degli URL specifici (e nel caso di avatar con proxy, il prefisso URL basato sul nome utente).
Sono stato sollevato quando, testando, ho visto che i riferimenti ad avatar, sfondo del profilo e sfondo della card vengono gestiti automaticamente quando un upload viene distrutto.
I due scenari principali sarebbero “terra bruciata” e “rimozione chirurgica”. Questo è il lavoro in corso per la terra bruciata:
Conversione in una lista di hash degli upload:
URL degli avatar (estrai il nome utente usando regex) → ottieni l’hash dell’avatar tramite query data explorer (l’hash non è nell’URL)
URL di topic/post → raccogli tutti gli hash degli upload utilizzati in quel post usando data explorer
URL di upload originali/ottimizzati diretti (inclusi sfondo del profilo e sfondo della card) → estrai gli hash usando regex
Quindi esegui una query su ciascun hash per trovare tutte le occorrenze (una query data explorer per coprire tutti i casi, un hash alla volta):
lista nome utente/ID, per gli utenti che lo hanno utilizzato per un avatar
lista nome utente/ID, per gli utenti che lo hanno utilizzato per uno sfondo del profilo
lista nome utente/ID, per gli utenti che lo hanno utilizzato per uno sfondo della card
lista di tutti i post (raw) che utilizzano questo upload
Azioni:
sospendi tutti gli utenti che hanno utilizzato l’upload per un avatar, sfondo del profilo o sfondo della card
sospendi tutti gli utenti che hanno post che fanno riferimento all’upload di destinazione, ma escludi se il loro riferimento è annidato all’interno di una citazione
elimina tutti i topic
elimina tutti i post
distruggi l’upload (nessun endpoint API)
esegui il purge di tutti gli URL CDN (ottimizzati/non ottimizzati)
esegui il purge del prefisso standard per gli URL degli avatar con proxy per ciascun nome utente associato (per coprire tutte le dimensioni)
Lo scenario di rimozione chirurgica sarebbe essenzialmente lo stesso, ma senza sospendere gli utenti associati e richiederebbe alcune modifiche per quanto riguarda la raccolta di tutti gli hash degli upload dagli URL dei post/topic.
Probabilmente eliminare comunque i post/topic stessi per evitare riferimenti interrotti, ma rimuovere il markdown dell’upload per quell’upload specifico (senza toccare altri upload) sarebbe superiore se possibile. Come questa automazione se non rimuovesse tutti i riferimenti agli upload nel markdown.
Idealmente vorrei essere in grado di bloccare anche gli hash, in modo che dopo aver eseguito quanto sopra, qualcuno non possa semplicemente creare un nuovo account e ricaricare.
Non penso sia attualmente possibile per un mod regolare, come usando le parole osservate (watched words). Quindi forse eseguire una scansione periodica come quella sopra per una lista di hash sarebbe un modo per gestirlo.
Sto solo linkando questo per gli utenti che leggeranno e saranno d’accordo con il tuo post, potrebbero essere interessati a votare per questo (so che l’hai già letto):
Sì! Ho pianto lacrime di gioia quando ho visto il tuo plugin all’inizio di questo mese haha. Un enorme grazie per averlo creato e condiviso.
Alcuni scenari che non sono riuscito a coprire con esso:
Utilizzo del prefisso di ricerca del caricamento: non sembrava possibile trovare gli sfondi del profilo o gli sfondi delle schede (a meno che qualcuno non avesse inserito direttamente il collegamento a quelle immagini in un post).
Eliminazione forzata delle immagini in quello scenario (immagine senza associazione a post).
Simile per l’Avatar, ad esempio ottenere l’hash dell’avatar (di solito non è nell’URL), quindi trovare eventuali altri account che potrebbero averlo utilizzato, se è necessaria una sospensione + eliminare il caricamento senza associazione a post.
Funzionalità utili:
Attivare un webhook alla cancellazione, per attivare la pulizia della CDN dopo la cancellazione per tutte le varianti dei caricamenti.
Eliminazione in blocco/automatica di tutti i post/argomenti che fanno riferimento al caricamento quando il caricamento viene eliminato.
In Discourse (interfaccia web), non sembra possibile eliminare (scollegare) l’avatar di un utente, né da parte di un amministratore/moderatore né da parte dell’utente stesso (oltre a caricare una sostituzione). È possibile per lo sfondo del profilo e il banner. Ma entrambi questi non distruggono immediatamente il caricamento e se esiste un altro utente sconosciuto che utilizza lo stesso caricamento per una parte del proprio profilo (avatar, sfondo del profilo, scheda del profilo) non verrà eliminato in seguito.
Ho finito per pensare che potrebbe valere la pena provare a creare alcuni flussi di lavoro automatizzati in grado di gestire la maggior parte o la totalità del processo (con revisione/approvazione umana e/o input umano semplificato). Per facilitare l’applicazione coerente, coprire i casi limite e idealmente ridurre al minimo la possibilità di avere post non eliminati con riferimenti a caricamenti non validi. Inoltre, sospendere automaticamente se necessario (a meno che il caricamento di destinazione non sia all’interno di una citazione) e pulire la CDN.
Questo è ciò che ho finora per le query di esplorazione dati (non ancora alla parte di ‘collegarle’), con l’obiettivo di coprire:
URL degli argomenti
URL dei post
URL delle immagini dirette (post, sfondo del profilo, sfondo della scheda)
URL degli avatar (con proxy)
Prepara l’elenco degli hash di caricamento
nomeutente (da URL avatar con proxy) all’hash di caricamento
-- [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
URL post/argomento all’elenco degli hash di caricamento
-- [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'
Gli altri tipi di URL di caricamento di cui sono a conoscenza, hanno l’hash nell’URL stesso (non è necessario utilizzare l’esploratore dati per ottenere tali hash).
Raccogli e prepara tutte le informazioni attuabili su un hash di caricamento
-- [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
Non copre: argomenti in coda in attesa di revisione o post in bozza
Output:
upload_ids (dovrebbe essere solo uno)
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
Ciò fornirà le informazioni necessarie per utilizzare selettivamente queste API:
Sospendere un utente (per i post, è possibile utilizzare raw in post_details per escludere condizionalmente gli utenti se il markdown del caricamento è all’interno di una citazione)
Eliminazione caricamento (API non esiste attualmente)
E per ulteriori azioni:
Pulire tutti gli URL CDN (tutte le varianti, ottimizzate e originali, ecc.)
Pulire gli URL prefisso degli avatar con proxy (per coprire tutte le dimensioni)
Gestito automaticamente da Discourse:
Rimuove immediatamente il riferimento al caricamento da tutti i profili utente (avatar, sfondo del profilo e sfondo della scheda) quando un caricamento viene distrutto/eliminato.