]> git.aero2k.de Git - dfde/quickmods.git/commitdiff
Add a quickmod link for archiving a whole thread
authorJTH <JTH@debianforum.de>
Sat, 24 Sep 2022 20:07:52 +0000 (22:07 +0200)
committerThorsten <mail@aero2k.de>
Mon, 3 Oct 2022 21:24:24 +0000 (23:24 +0200)
quickmod.user.js

index 2c06ddea486cb88af02ac40d0626c508d2759939..5f8c8856c502c13dfe9c7f0c668d047fa0ba742e 100644 (file)
 
 const ARCHIVFORUMID = 35;
 
+async function archiveThread(firstPage, reason) {
+    const moveProm = (async () => {
+        const moveLink = firstPage.querySelector("#quickmod .dropdown-contents a[href*='action=move']");
+
+        let form, formData;
+        try {
+            [form, formData] = await openForm(toAbsoluteURL(moveLink.href), "form#confirm");
+        } catch (err) {
+            throw `Konnte Formular zum Verschieben des Themas nicht öffnen: ${err}`;
+        }
+
+        formData.set("to_forum_id", ARCHIVFORUMID);
+        try {
+            /* Unlike splitting a thread, moving does not have a second
+             * confirmation step.
+             */
+            await postForm(form, formData, "confirm");
+        } catch (err) {
+            throw `Konnte Thema nicht verschieben: ${err}`;
+        }
+    })();
+
+    const editProm = (async () => {
+        const editLink = firstPage.querySelector(".post .post-buttons a[href*='mode=edit']");
+
+        let form, formData;
+        try {
+            [form, formData] = await openForm(toAbsoluteURL(editLink.href), "form#postform");
+        } catch (err) {
+            throw `Konnte Formular zum Bearbeiten des ersten Beitrags nicht öffnen: ${err}`;
+        }
+
+        formData.set("subject", prefixSubject(form.elements["subject"], reason));
+
+        /* All "altering actions not secured by confirm_box" require a non-zero
+         * time difference between opening and submitting a form. See
+         * check_form_key() in phpBB/includes/functions.php.
+         *
+         * So we artificially delay the postForm() for a second.
+         */
+        await new Promise((resolve) => {
+            setTimeout(async () => {
+                try {
+                    await postForm(form, formData, "post");
+                } catch (err) {
+                    throw `Konnte Thema nicht umbenennen: ${err}`;
+                }
+
+                resolve();
+            }, 1001);
+        });
+    })();
+
+    /* An mcp action and a post edit can actually be done concurrently! :-) */
+    await Promise.all([moveProm, editProm]);
+}
+
+async function archiveThreadQuickmod() {
+    const canonicalURL = new URL(document.querySelector("link[rel='canonical']").href);
+    const firstPage = await openDoc(canonicalURL);
+    const firstPost = firstPage.querySelector(".post");
+    const usernameElem = firstPost.querySelector(".author .username,.author .username-coloured");
+    const username = usernameElem.textContent;
+    const thread_title = firstPage.querySelector('.topic-title a').text;
+
+    const archiveReason = await asyncPrompt(`Thema „${ellipsify(thread_title, 100)}“ eröffnet von „${username}“ wirklich als Spam archivieren?\n\nGrund:`, "Spam");
+    if (archiveReason === null) {
+        /* Don't do any of the other actions if moving was cancelled. */
+        return;
+    }
+
+    const archivingThread = archiveThread(firstPage, archiveReason);
+
+    /* Prompting for a separate ban reason in case there is something more
+     * specific to note here.
+     */
+    const userStillExists = usernameElem.nodeName === "A";
+    const banReasonPrompt = userStillExists &&
+        asyncPrompt(`Benutzer „${username}“, der das Thema eröffnet hat, sperren?\n\nGrund:`, "Spam");
+
+    /* Mod actions via mcp.php involve a confirm_key which is stored in the
+     * database when an action is requested until it is confirmed. There can only
+     * be one confirm_key stored at a time---meaning there cannot be multiple mcp
+     * actions executed concurrently. See confirm_box() in
+     * phpBB/includes/functions.php.
+     *
+     * This means we cannot really execute the actions concurrently here,
+     * unfortunately. User interaction is still done in parallel to one action at
+     * a time, though.
+     */
+    const errors = [];
+    try {
+        await archivingThread;
+    } catch (err) {
+        errors.push(err);
+    }
+
+    let banningUser;
+    const banReason = await banReasonPrompt;
+    if (banReason) {
+        banningUser = banUser(username, banReason);
+    } else if (!userStillExists) {
+        await asyncAlert(`Benutzer „${username}“ wurde schon gelöscht und kann nicht mehr gesperrt werden.`);
+    }
+
+    const shouldCloseReport = isPostReported(firstPost) &&
+        asyncConfirm("Meldung zum ersten Beitrag schließen?");
+
+    try {
+        await banningUser;
+    } catch (err) {
+        errors.push(err);
+    }
+
+    if (await shouldCloseReport) {
+        try {
+            await closeReport(firstPost);
+        } catch (err) {
+            errors.push(err);
+        }
+    }
+
+    for (const error of errors) {
+        console.log(error);
+        window.alert(`ACHTUNG!\n\n${error}`);
+    }
+
+    if (errors.length === 0) {
+        redirectToArchive();
+    }
+}
+
 async function asyncAlert(message) {
     window.alert(message);
 }
@@ -77,6 +209,12 @@ function isPostReported(post) {
 }
 
 async function openForm(urlOrResponse, selector) {
+    const doc = await openDoc(urlOrResponse);
+    const form = doc.querySelector(selector);
+    return [form, new FormData(form)];
+}
+
+async function openDoc(urlOrResponse) {
     const resp = urlOrResponse instanceof Response ? urlOrResponse :
         await fetch(urlOrResponse);
     if (!resp.ok) {
@@ -85,9 +223,7 @@ async function openForm(urlOrResponse, selector) {
 
     const parser = new DOMParser();
     const txt = await resp.text();
-    const doc = parser.parseFromString(txt, "text/html");
-    const form = doc.querySelector(selector);
-    return [form, new FormData(form)];
+    return parser.parseFromString(txt, "text/html");
 }
 
 async function postForm(form, formData, submitName, requiresConfirmation = false) {
@@ -255,6 +391,14 @@ function add_buttons() {
         del_post_btn_outer_clone.addEventListener("click", remove_post_handler);
         postButtons.appendChild(del_post_btn_outer_clone);
     }
+
+    const quickmodLinks = document.querySelector("#quickmod .dropdown-contents");
+    const archiveThreadLink = quickmodLinks
+        .insertBefore(document.createElement("li"), quickmodLinks.firstChild)
+        .appendChild(document.createElement("a"));
+    archiveThreadLink.addEventListener("click", archiveThreadQuickmod);
+    archiveThreadLink.innerText = "Thema als Spam archivieren";
+    archiveThreadLink.style.cursor = "pointer";
 }
 
 add_buttons();