通过 API 删除上传内容

我试着去寻找,但似乎没有用于删除上传的 API 端点 不存在

Muppet Show: Kermit's Trapeze Fall

我把它发在这里,因为我没有找到任何关于此的提及或建议,我找到的最接近的是:API: a scope with access to /uploads

在上传的 API 密钥粒度范围设置中,我看到“创建”可用,但“删除”不可用。

似乎一个可能的变通方法是创建一个自定义自动化并通过 API 触发它。

4 个赞

您的使用场景是什么?

根据您的配置,上传文件作为共享资源(被帖子、用户资料、徽章等引用),在没有进行适当尽职调查的情况下删除它们是有些风险的。

此外,如果上传文件没有被任何地方引用,它们会在一段时间后被自动清理掉。

3 个赞

该用例是使用 activepiecesdata explorer 和 API 在“人在回路”自动化工作流程中,对上传内容进行时间敏感性的移除。

目标是让普通版主能够有一种简单的方式,自信地立即完全移除上传内容,同时全面覆盖所有已知的破坏上传引用的情况,并自动清除特定 URL 的 CDN(对于代理头像的情况,则清除基于用户名的 URL 前缀)。


测试时,我很高兴地看到,当销毁上传内容时,头像、个人资料背景和卡片背景引用会自动处理。

https://github.com/discourse/discourse/commit/e1975e293f2625259e925b4a3c93d88d5acfcaa8

https://github.com/discourse/discourse/commit/38e7b1a0492dd4282c3cd3b1ddb2b3343661d31f


主要有两种场景:“焦土政策”和“外科手术式移除”。以下是“焦土政策”的进行中工作:


转换为上传哈希列表:

  • 头像 URL(使用正则表达式提取用户名)→ 通过数据探索器查询获取头像哈希(哈希不在 URL 中)

  • 主题/帖子 URL → 使用数据探索器收集该帖子中使用的所有上传哈希

  • 直接原始/优化上传 URL(包括个人资料背景和卡片背景)→ 使用正则表达式提取哈希


然后对每个哈希进行查询,以查找所有出现的地方(一次一个数据探索器查询,涵盖所有情况):

  • 用户名/ID 列表,用于曾将其用作头像的用户

  • 用户名/ID 列表,用于曾将其用作个人资料背景的用户

  • 用户名/ID 列表,用于曾将其用作卡片背景的用户

  • 使用此上传的所有帖子(原始)列表


操作:

  • 暂停所有曾将该上传用作头像、个人资料背景或卡片背景的用户

  • 暂停所有引用目标上传的用户帖子,但如果其引用嵌套在引用中则排除

  • 删除所有主题

  • 删除所有帖子

  • 销毁上传(没有 API 端点)

  • 清除所有 CDN URL(优化/未优化)

  • 清除代理头像 URL 的标准前缀,针对每个相关用户名(以覆盖所有尺寸)


“外科手术式移除”场景基本上是相同的,但不暂停相关用户,并且在从帖子/主题 URL 收集所有上传哈希方面需要进行一些更改。

可能仍然需要删除帖子/主题本身以避免引用断裂,但如果可能,剥离该特定上传的上传 Markdown(不触及其他上传)会更好。类似于这个自动化,但它会剥离所有上传的 Markdown 引用。


理想情况下,我希望能够阻止哈希,这样在完成上述操作后,某人就不能简单地创建一个新帐户并重新上传。:melting_face: :coffin:

我不认为普通版主目前可以做到,比如通过使用监视词。所以,对哈希列表进行上述那样的定期扫描可能是处理这种情况的一种方法。

1 个赞

您看过我们的 Legal Compliance Plugin 吗?

它有用于获取帖子上传内容和根据上传和帖子 ID 删除上传的端点。

它还扩展了搜索功能,可以根据哈希值获取包含特定上传的所有帖子。

2 个赞

我只是为会阅读并同意您的帖子的用户链接此内容,他们可能对投票支持此内容感兴趣(我知道您已经阅读过了):

2 个赞

是的!看到您的插件时,我简直喜极而泣哈哈。非常感谢您制作并分享它。:heart:

我没有找到用它来覆盖的一些场景:

  • 使用上传项:搜索前缀,似乎无法找到个人资料背景或卡片背景(除非有人在帖子中直接链接了这些图片)。
  • 在该场景下硬删除图片(与帖子没有关联的图片)。
  • 头像也是类似的情况,例如获取头像的哈希值(它通常不在 URL 中),然后查找可能也使用了该头像的其他帐户,以便在需要停用时删除没有帖子关联的上传项。

“有更好”的功能:

  • 在删除时触发 Webhook,以便在删除后触发所有上传项变体的 CDN 清除。
  • 在删除上传项时,批量/自动删除所有引用了该上传项的帖子/主题。

在 Discourse(Web UI)中,似乎管理员/版主或用户本人都无法删除(取消链接)用户头像(除了上传一个替换项)。个人资料背景和横幅是可以的。但这两种情况都不会立即销毁上传项,如果存在另一个未知用户将其上传项用于其个人资料的某个部分(头像、个人资料背景、个人资料卡),它也不会在之后被清除。


我最终认为,值得尝试创建一些可以处理大部分或全部流程的自动化工作流程(带有人工审核/批准和/或简化的用户输入)。以便更容易地保持一致性、覆盖边缘情况,并理想情况下最大限度地减少存在指向已删除上传项的未删除帖子的可能性。如果需要,还可以自动停用并清除 CDN。


这是我目前为数据资源管理器查询所做的(尚未达到“将它们粘合在一起”的阶段),目标是覆盖:

  • 主题 URL
  • 帖子 URL
  • 直接图片 URL(帖子、个人资料背景、卡片背景)
  • 头像 URL(代理的)

准备上传哈希列表

username (来自代理头像 URL) 到上传哈希

-- [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 到上传哈希列表

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

我所知道的其他上传 URL 类型,其哈希值包含在 URL 本身中(无需使用数据资源管理器来获取这些哈希值)。


收集并准备有关上传哈希的所有可操作信息

示例参数:

upload_schemeless_prefix:
//my-s3-bucket.somehost.example.com

cdn_url_prefix:
https://cdn.example.com

app_hostname:
www.example.com

upload_hash:
0000000000000000000000000000000000000000

哈希搜索和摘要

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

不包括:待审核队列中的主题/帖子或草稿帖子

输出:

upload_ids (应该只有一个)
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

这将提供所需的信息,以便有选择地使用以下 API:

以及用于进一步操作:

  • 清除所有 CDN URL(所有变体,优化和原始等)
  • 清除代理头像的前缀 URL(以覆盖所有尺寸)

Discourse 自动处理:

  • 当上传项被销毁/删除时,立即从所有用户个人资料(头像、个人资料背景和卡片背景)中删除上传项引用。
1 个赞