حذف التحميل عبر API

لقد حاولت الوصول إليه، ولكن يبدو أن نقطة نهاية واجهة برمجة التطبيقات (API) لحذف عملية تحميل غير موجودة.

Muppet Show: Kermit's Trapeze Fall

أقوم بنشر هذا هنا، لأنني لم أتمكن من العثور على أي إشارات أو اقتراحات لهذا، وأقرب ما وجدته هو: API: a scope with access to /uploads

في إعدادات النطاق الحبيبي لمفتاح واجهة برمجة التطبيقات (API) لعمليات التحميل، أرى أن ‘إنشاء’ (create) متاح، ولكن ‘حذف’ (delete) غير متاح.

يبدو أن الحل البديل المحتمل قد يكون إنشاء أتمتة مخصصة وتشغيلها عبر واجهة برمجة التطبيقات (API).

4 إعجابات

ما هي حالة الاستخدام الخاصة بك؟

اعتمادًا على التكوين الخاص بك، فإن التحميلات التي هي مورد مشترك (يُشار إليها بواسطة المنشورات، وملف تعريف المستخدم، والشارات، وما إلى ذلك…) تشكل خطورة إلى حد ما عند حذفها دون بذل العناية الواجبة المناسبة.

بالإضافة إلى ذلك، يتم تنظيفها تلقائيًا بعد فترة قصيرة إذا لم تتم الإشارة إليها في أي مكان.

3 إعجابات

يتمثل الاستخدام في الإزالة الحرجة زمنيًا لعمليات التحميل كجزء من سير عمل الأتمتة البشرية في الحلقة باستخدام activepieces ومستكشف البيانات وواجهة برمجة التطبيقات (API).

الهدف هو تمكين المشرفين العاديين من الوصول إلى طريقة بسيطة لإزالة عمليات التحميل بالكامل وبثقة على الفور دون الحاجة إلى الوصول عبر SSH، وتغطية شاملة لجميع الحالات المعروفة لكسر مراجع التحميل، بالإضافة إلى مسح ذاكرة التخزين المؤقت لشبكة توصيل المحتوى (CDN) تلقائيًا لعنوان URL المحدد (وفي حالة الصورة الرمزية التي يتم تمريرها عبر وكيل، بادئة عنوان URL بناءً على اسم المستخدم).


لقد شعرت بالارتياح عند الاختبار، لرؤية أنه تتم معالجة مراجع الصور الرمزية وخلفية الملف الشخصي وخلفية البطاقة تلقائيًا عند تدمير عملية تحميل.

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

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


السيناريوهان الرئيسيان سيكونان “الأرض المحروقة” و"الإزالة الجراحية". هذا هو العمل الجاري للأرض المحروقة:


التحويل إلى قائمة تجزئة (هاش) لعمليات التحميل:

  • عناوين URL للصور الرمزية (استخراج اسم المستخدم باستخدام التعبير العادي) ← الحصول على تجزئة الصورة الرمزية عبر استعلام مستكشف البيانات (التجزئة ليست في عنوان URL)

  • عناوين URL للمواضيع/المنشورات ← جمع جميع تجزئات التحميل المستخدمة في هذا المنشور باستخدام مستكشف البيانات

  • عناوين URL مباشرة للتحميل الأصلي/المُحسَّن (بما في ذلك خلفية الملف الشخصي وخلفية البطاقة) ← استخراج التجزئات باستخدام التعبير العادي


ثم الاستعلام عن كل تجزئة للعثور على جميع التكرارات (استعلام واحد لمستكشف البيانات لتغطية جميع الحالات، تجزئة واحدة في كل مرة):

  • قائمة بأسماء المستخدمين/المعرفات، للمستخدمين الذين استخدموها كصورة رمزية

  • قائمة بأسماء المستخدمين/المعرفات، للمستخدمين الذين استخدموها كخلفية للملف الشخصي

  • قائمة بأسماء المستخدمين/المعرفات، للمستخدمين الذين استخدموها كخلفية للبطاقة

  • قائمة بجميع المنشورات (الخام) التي تستخدم هذا التحميل


الإجراءات:

  • تعليق جميع المستخدمين الذين استخدموا التحميل كصورة رمزية أو خلفية للملف الشخصي أو خلفية للبطاقة

  • تعليق جميع المستخدمين الذين لديهم منشورات تشير إلى التحميل المستهدف، ولكن استبعادهم إذا كان مرجعهم متداخلاً داخل اقتباس

  • حذف جميع المواضيع

  • حذف جميع المنشورات

  • تدمير التحميل (لا يوجد نقطة نهاية لواجهة برمجة التطبيقات)

  • مسح جميع عناوين URL لشبكة CDN (المُحسَّنة/غير المُحسَّنة)

  • مسح البادئة القياسية لعناوين URL للصور الرمزية التي يتم تمريرها عبر وكيل لكل اسم مستخدم مرتبط (لتغطية جميع الأحجام)


سيناريو الإزالة الجراحية سيكون هو نفسه تقريبًا، ولكن دون تعليق المستخدمين المرتبطين ويتطلب بعض التغييرات فيما يتعلق بجمع جميع تجزئات التحميل من عناوين URL للمنشورات/المواضيع.

من المحتمل أن يظل حذف المنشورات/المواضيع نفسها لتجنب المراجع المكسورة، ولكن إزالة تنسيق علامات التحميل الخاصة بعملية التحميل المحددة تلك (دون المساس بعمليات التحميل الأخرى) سيكون أفضل إذا كان ذلك ممكنًا. مثل هذه الأتمتة لو أنها لم تقم بإزالة جميع مراجع تحميل علامات التنسيق.


من الناحية المثالية، أود أن أكون قادرًا على حظر التجزئات أيضًا، بحيث بعد المرور بما سبق، لا يتمكن شخص ما من إنشاء حساب جديد وإعادة التحميل ببساطة. :melting_face: :coffin:

لا أعتقد أن هذا ممكن حاليًا لمشرف عادي، مثل استخدام الكلمات المراقبة. لذا ربما يكون إجراء فحص دوري مثل المذكور أعلاه لقائمة التجزئات طريقة للتعامل مع ذلك.

إعجاب واحد (1)

هل اطلعت على Legal Compliance Plugin الخاص بنا؟

لديه نقاط نهاية (endpoints) للحصول على التحميلات (uploads) لمنشور معين ولإزالة تحميل معين بالنظر إلى معرفي التحميل والمنشور.

كما أنه يوسع وظيفة البحث للحصول على جميع المنشورات التي تحتوي على تحميل معين، بالنظر إلى التجزئة (hash).

إعجابَين (2)

أنا فقط أرفق هذا للمستخدمين الذين سيقرؤون ويوافقون على منشورك، قد يكونون مهتمين بالتصويت لهذا (أعلم أنك قرأته بالفعل):

إعجابَين (2)

نعم! لقد ذرفت تقريبًا دموع الفرح عندما رأيت الإضافة الخاصة بك في وقت سابق من هذا الشهر ههه. شكرًا جزيلاً لك على صنعها ومشاركتها. :heart:

بعض السيناريوهات التي لم أجد طريقة لتغطيتها بها:

  • استخدام البادئة البحثية للتحميل: لم يبدُ أنه من الممكن العثور على خلفيات الملف الشخصي أو خلفيات البطاقات (إلا إذا قام شخص ما بربط تلك الصور مباشرة في منشور أيضًا).
  • الحذف الصارم للصور في هذا السيناريو (صورة بدون ارتباط بالمنشورات).
  • شيء مماثل للصورة الرمزية (Avatar) على سبيل المثال، الحصول على تجزئة الصورة الرمزية (عادةً لا تكون في عنوان URL)، ثم العثور على أي حسابات أخرى ربما استخدمتها أيضًا، إذا كانت هناك حاجة إلى تعليق (suspension) + حذف التحميل بدون ارتباط بمنشور.

أمور لطيفة:

  • تشغيل خطاف ويب (webhook) عند الحذف، لتشغيل مسح ذاكرة التخزين المؤقت لشبكة توصيل المحتوى (CDN) بعد الحذف لجميع متغيرات التحميلات.
  • الحذف المجمع/التلقائي لجميع المنشورات/المواضيع التي تحتوي على مرجع تحميل عند حذف التحميل.

في ديسكورس (واجهة الويب)، لا يبدو أنه من الممكن حذف (إلغاء ربط) الصورة الرمزية للمستخدم، سواء من قبل مسؤول/مشرف أو المستخدم نفسه (بخلاف تحميل بديل). هذا ممكن لخلفية الملف الشخصي والخلفية. لكن كلاهما لا يدمر التحميل فورًا، وإذا كان هناك مستخدم آخر غير معروف يستخدم نفس التحميل لجزء من ملفه الشخصي (صورة رمزية، خلفية ملف شخصي، بطاقة ملف شخصي) فلن يتم مسحها لاحقًا أيضًا.


انتهى بي الأمر إلى الاعتقاد بأنه قد يكون من المفيد محاولة إنشاء بعض سير العمل الآلي التي يمكنها التعامل مع معظم العملية أو كلها (مع مراجعة/موافقة بشرية و/أو مدخلات بشرية مبسطة). لجعل تطبيقها أسهل باستمرار، وتغطية الحالات الطرفية، وتقليل احتمالية وجود منشورات غير محذوفة تحتوي على مراجع تحميل ميتة. وأيضًا التعليق التلقائي إذا لزم الأمر (ما لم يكن التحميل المستهدف داخل اقتباس) ومسح ذاكرة التخزين المؤقت لشبكة توصيل المحتوى.


هذا ما توصلت إليه حتى الآن لاستعلامات مستكشف البيانات (لم أصل بعد إلى مرحلة “ربطها معًا”)، بهدف التغطية:

  • عناوين URL للمواضيع
  • عناوين URL للمنشورات
  • عناوين URL للصور المباشرة (المنشورات، خلفية الملف الشخصي، خلفية البطاقة)
  • عناوين URL للصور الرمزية (المُعاد توجيهها عبر وكيل)

إعداد قائمة تجزئات التحميل (Upload Hashes List)

اسم المستخدم (من عنوان 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

بحث وتلخيص التجزئة (hash search & summary)

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

سيوفر هذا المعلومات المطلوبة لاستخدام واجهات برمجة التطبيقات هذه بشكل انتقائي:

ولإجراءات إضافية:

  • مسح جميع عناوين URL لشبكة توصيل المحتوى (CDN) (جميع المتغيرات، والمُحسَّنة والأصلية وما إلى ذلك)
  • مسح بادئات عناوين URL للصور الرمزية المُعاد توجيهها (لتغطية جميع الأحجام)

يتم التعامل معه تلقائيًا بواسطة ديسكورس:

  • إزالة مرجع التحميل من جميع ملفات تعريف المستخدمين (الصورة الرمزية، خلفية الملف الشخصي، وخلفية البطاقة) فورًا عند تدمير/حذف التحميل.
إعجاب واحد (1)