]> git.ipfire.org Git - thirdparty/rspamd.git/commitdiff
[WebUI] Add file upload to Test Selectors (#5381)
authorShravan A Y <shravanay205@gmail.com>
Mon, 10 Mar 2025 16:21:59 +0000 (21:51 +0530)
committerAlexander Moisseev <moiseev@mezonplus.ru>
Mon, 19 May 2025 14:15:37 +0000 (17:15 +0300)
Squashed and rebased original commits from ShravanAYG’s selector-file-upload branch

Co-authored-by: ShravanAYG <shravanay205@gmail.com>
See: https://github.com/rspamd/rspamd/pull/5381

interface/css/rspamd.css
interface/index.html
interface/js/app/common.js
interface/js/app/selectors.js
interface/js/app/upload.js

index 896f9200884ec56fbcf41d18d94eba84e438c858..a79fed28b0fa3315522086fbd3381398b48da109 100644 (file)
@@ -418,13 +418,18 @@ table#symbolsTable input[type="number"] {
 
 .outline-dashed-primary { outline: 2px dashed var(--bs-primary); }
 
-#scanMsgSource:placeholder-shown {
+#scanMsgSource:placeholder-shown,
+#selectorsMsgArea:placeholder-shown {
   background-image: url("../img/drop-area.svg");
   background-repeat: no-repeat;
   background-position: center;
   opacity: 0.8;
 }
-#scanMsgSource:not(:placeholder-shown) { background-image: none;}
+
+#scanMsgSource:not(:placeholder-shown),
+#selectorsMsgArea:not(:placeholder-shown) {
+  background-image: none;
+}
 
 .scorebar-spam {
     background-color: rgba(240 0 0 / 0.1) !important;
index cf21876012927f25de8a63d3c17ebb940a6fa197..b176d6527303fa37ae7dae7ace52eee7710e1e49 100644 (file)
                                        <div class="card-header text-secondary py-2 d-flex align-items-center">
                                                <span class="icon me-3"><i class="fas fa-envelope"></i></span>
                                                <span class="h6 fw-bolder my-auto">Test Rspamd selectors</span>
+                                               <div class="d-flex input-group-sm align-items-center ms-auto">
+                                                       <label for="formFile" class="col-auto col-form-label-sm me-1">Choose a file:</label>
+                                                       <input class="form-control form-control-sm btn btn-secondary" id="selectorsFile" type="file">
+                                               </div>
                                        </div>
                                        <div class="card-body p-0">
                                                <div class="row h-100 m-0" id="row-main">
                                                                                                        <div class="col">
                                                                                                                <div class="form-group">
                                                                                                                        <label class="form-label" for="selectorsMsgArea">Message source:</label>
-                                                                                                                       <textarea class="form-control" id="selectorsMsgArea" rows="9" placeholder="Paste raw message source"></textarea>
+                                                                                                                       <textarea class="form-control" id="selectorsMsgArea" rows="9" placeholder='Paste raw message source, drag and drop files here or use "Browse..." button.'></textarea>
                                                                                                                </div>
                                                                                                                <button class="btn btn-secondary d-flex align-items-center float-end" id="selectorsMsgClean"><i class="fas fa-trash-alt me-2"></i>Clean form</button>
                                                                                                        </div>
index ace4bbba17a5ec935bbd3034f9a5d369a64887ca..20c13f9f915f7fac027e69cb054397ad90f8b581 100644 (file)
@@ -261,5 +261,71 @@ define(["jquery", "nprogress"],
             ).appendTo(ftFilter.$dropdown);
         };
 
+        ui.fileUtils = {
+            files: null,
+            filesIdx: 0,
+
+            enableButton(button, textArea, validator) {
+                const hasText = $.trim($(textArea).val()).length > 0;
+                const needsValidation = validator !== "none";
+
+                $(button).prop("disabled", !hasText || (needsValidation && !$(validator).hasClass("is-valid")));
+            },
+
+            readFile(callback, textArea, button, validator) {
+                if (!this.files || this.files.length === 0) {
+                    alertMessage("alert-error", "No files selected.");
+                    return;
+                }
+
+                const reader = new FileReader();
+
+                reader.onload = () => {
+                    $(textArea).val(reader.result).trigger("input");
+                    this.enableButton(button, textArea, validator);
+
+                    if (callback) callback(reader.result);
+                };
+                reader.onerror = () => alertMessage("alert-error", "Error reading file.");
+                reader.readAsText(this.files[this.filesIdx]);
+            },
+
+            handleFileInput(fileSrc, textArea, button, fileInput, validator) {
+                ({
+                    files: this.files
+                } = fileSrc);
+                this.filesIdx = 0;
+
+                if (!this.files.length) {
+                    alertMessage("alert-warning", "No file was provided.");
+                    return;
+                }
+                $(fileInput)[0].files = this.files;
+                // eslint-disable-next-line no-alert
+                if (this.files.length === 1 || confirm(`Are you sure you want to process ${this.files.length} files?`)) {
+                    this.readFile(null, textArea, button, validator);
+                }
+            },
+
+            setupFileHandling(textArea, fileInput, button, validator) {
+                const highlightClass = "outline-dashed-primary bg-primary-subtle";
+
+                $(textArea)
+                    .on("dragenter dragover", (e) => {
+                        e.preventDefault();
+                        $(textArea).addClass(highlightClass);
+                    })
+                    .on("dragleave drop", () => $(textArea).removeClass(highlightClass))
+                    .on("drop", (e) => {
+                        e.preventDefault();
+                        this.handleFileInput(e.originalEvent.dataTransfer, textArea, button, fileInput, validator);
+                    });
+                $(fileInput).on("change", (e) => {
+                    this.handleFileInput(e.target, textArea, button, fileInput, validator);
+                });
+                $(textArea).on("input", () => this.enableButton(button, textArea, validator));
+            }
+        };
+
         return ui;
     });
index c2b8b27e5eeb5c46e73e64edd71752d57e5d7b0f..788ceeacb680899e9de11ff045fd65ac93bf06ed 100644 (file)
@@ -135,6 +135,12 @@ define(["jquery", "app/common"],
         $("#selectorsSelArea").on("input", () => {
             checkSelectors();
         });
+        $("#selectorsMsgClean").on("click", () => {
+            $("#selectorsMsgArea").val("");
+            $("#selectorsFile").val("");
+        });
+
+        common.fileUtils.setupFileHandling("#selectorsMsgArea", "#selectorsFile", "#selectorsChkMsgBtn", "#selectorsSelArea");
 
         return ui;
     });
index d5283cdb16505c926bc353c71ebf6eb7fa7faa1f..2ba4b616796c83a5a9bbf7547f190b72c2d82115 100644 (file)
@@ -28,8 +28,8 @@ define(["jquery", "app/common", "app/libft"],
     ($, common, libft) => {
         "use strict";
         const ui = {};
-        let files = null;
         let filesIdx = null;
+        let files = null;
         let scanTextHeaders = {};
 
         function uploadText(data, url, headers, method = "POST") {
@@ -70,18 +70,14 @@ define(["jquery", "app/common", "app/libft"],
                 .prop("disabled", (disable || $.trim($("textarea").val()).length === 0));
         }
 
-        function setFileInputFiles(i) {
+        function updateFileInput(i) {
             const dt = new DataTransfer();
-            if (arguments.length) dt.items.add(files[i]);
+            if (arguments.length > 0 && files && files[i]) {
+                dt.items.add(files[i]);
+            }
             $("#formFile").prop("files", dt.files);
         }
 
-        function readFile(callback, i) {
-            const reader = new FileReader();
-            reader.readAsText(files[(arguments.length === 1) ? 0 : i]);
-            reader.onload = () => callback(reader.result);
-        }
-
         function scanText(data) {
             enable_disable_scan_btn(true);
             common.query("checkv2", {
@@ -109,13 +105,15 @@ define(["jquery", "app/common", "app/libft"],
                                 libft.initHistoryTable(data, items, "scan", libft.columns_v2("scan"), true,
                                     () => {
                                         if (files && filesIdx < files.length - 1) {
-                                            readFile((result) => {
+                                            common.fileUtils.files = files;
+                                            common.fileUtils.filesIdx = ++filesIdx;
+                                            common.fileUtils.readFile((result) => {
                                                 if (filesIdx === files.length - 1) {
                                                     $("#scanMsgSource").val(result);
-                                                    setFileInputFiles(filesIdx);
+                                                    updateFileInput(filesIdx);
                                                 }
                                                 scanText(result);
-                                            }, ++filesIdx);
+                                            }, "#scanMsgSource", "#scanCheckMsgBtn", "none");
                                         } else {
                                             enable_disable_scan_btn();
                                             $("#cleanScanHistory, #scan .ft-columns-dropdown .btn-dropdown-apply")
@@ -148,6 +146,7 @@ define(["jquery", "app/common", "app/libft"],
             });
         }
 
+
         function getFuzzyHashes(data) {
             function fillHashTable(rules) {
                 $("#hashTable tbody").empty();
@@ -187,7 +186,8 @@ define(["jquery", "app/common", "app/libft"],
         $("#cleanScanHistory").off("click");
         $("#cleanScanHistory").on("click", (e) => {
             e.preventDefault();
-            if (!confirm("Are you sure you want to clean scan history?")) { // eslint-disable-line no-alert
+            // eslint-disable-next-line no-alert
+            if (!confirm("Are you sure you want to clean scan history?")) {
                 return;
             }
             libft.destroyTable("scan");
@@ -200,7 +200,7 @@ define(["jquery", "app/common", "app/libft"],
             enable_disable_scan_btn();
             if (files) {
                 files = null;
-                setFileInputFiles();
+                updateFileInput();
             }
         });
 
@@ -304,39 +304,7 @@ define(["jquery", "app/common", "app/libft"],
         });
 
 
-        function fileInputHandler(obj) {
-            ({files} = obj);
-            filesIdx = 0;
-
-            if (files.length === 1) {
-                setFileInputFiles(0);
-                enable_disable_scan_btn();
-                readFile((result) => {
-                    $("#scanMsgSource").val(result);
-                    enable_disable_scan_btn();
-                });
-            // eslint-disable-next-line no-alert
-            } else if (files.length < 10 || confirm("Are you sure you want to scan " + files.length + " files?")) {
-                getScanTextHeaders();
-                readFile((result) => scanText(result));
-            }
-        }
-
-        const dragoverClassList = "outline-dashed-primary bg-primary-subtle";
-        $("#scanMsgSource")
-            .on("dragenter dragover dragleave drop", (e) => {
-                e.preventDefault();
-                e.stopPropagation();
-            })
-            .on("dragenter dragover", () => {
-                $("#scanMsgSource").addClass(dragoverClassList);
-            })
-            .on("dragleave drop", () => {
-                $("#scanMsgSource").removeClass(dragoverClassList);
-            })
-            .on("drop", (e) => fileInputHandler(e.originalEvent.dataTransfer));
-
-        $("#formFile").on("change", (e) => fileInputHandler(e.target));
+        common.fileUtils.setupFileHandling("#scanMsgSource", "#formFile", "#scanCheckMsgBtn", "none");
 
         return ui;
     });