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
.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;
<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>
).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;
});
$("#selectorsSelArea").on("input", () => {
checkSelectors();
});
+ $("#selectorsMsgClean").on("click", () => {
+ $("#selectorsMsgArea").val("");
+ $("#selectorsFile").val("");
+ });
+
+ common.fileUtils.setupFileHandling("#selectorsMsgArea", "#selectorsFile", "#selectorsChkMsgBtn", "#selectorsSelArea");
return ui;
});
($, common, libft) => {
"use strict";
const ui = {};
- let files = null;
let filesIdx = null;
+ let files = null;
let scanTextHeaders = {};
function uploadText(data, url, headers, method = "POST") {
.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", {
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")
});
}
+
function getFuzzyHashes(data) {
function fillHashTable(rules) {
$("#hashTable tbody").empty();
$("#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");
enable_disable_scan_btn();
if (files) {
files = null;
- setFileInputFiles();
+ updateFileInput();
}
});
});
- 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;
});