smeserver-dmarc-srg/root/opt/dmarc-srg/js/files.js

395 lines
11 KiB
JavaScript

/**
* dmarc-srg - A php parser, viewer and summary report generator for incoming DMARC reports.
* Copyright (C) 2020 Aleksey Andreev (liuch)
*
* Available at:
* https://github.com/liuch/dmarc-srg
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation, either version 3 of the License.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
class Files {
constructor() {
this._container = null;
this._fieldset1 = null;
this._fieldset2 = null;
this._dir_table = null;
this._element = document.getElementById("main-block");
this._fcount_info = null;
this._fsize_info = null;
this._limits = {
upload_max_file_count: 0,
upload_max_file_size: 0
};
this._directories = [];
}
display() {
this._create_container();
this._create_local_file_uploading_element();
this._create_directory_loading_element();
this._container.appendChild(this._fieldset1);
this._container.appendChild(this._fieldset2);
this._element.appendChild(this._container);
this._fieldset1.focus();
}
update() {
if (!Status.instance().error()) {
this._fetch_data(true, true);
}
}
title() {
return "Report Files";
}
_create_container() {
this._container = document.createElement("div");
this._container.setAttribute("class", "panel-container round-border");
}
_create_local_file_uploading_element() {
this._fieldset1 = document.createElement("fieldset");
this._fieldset1.setAttribute("class", "round-border");
this._fieldset1.disabled = true;
let lg = document.createElement("legend");
lg.appendChild(document.createTextNode("Uploading local report files"));
this._fieldset1.appendChild(lg);
let fm = document.createElement("form");
fm.setAttribute("enctype", "multipart/form-data");
fm.setAttribute("method", "post");
fm.appendChild(this._create_input_element("hidden", "cmd", "upload-report"));
let fl = this._create_input_element("file", "report_file[]", null)
fl.required = true;
fl.multiple = true;
fm.appendChild(fl);
let dv = document.createElement("div");
dv.setAttribute("class", "buttons-block");
let sb = this._create_button_element("submit", "Upload reports");
sb.disabled = true;
dv.appendChild(sb);
dv.appendChild(this._create_button_element("reset", "Reset"));
fm.appendChild(dv);
let that = this;
fl.addEventListener("change", function(event) {
sb.disabled = !that._check_files(fl);
});
fm.addEventListener("reset", function(event) {
sb.disabled = true;
that._clear_warnings();
});
fm.addEventListener("submit", function(event) {
window.fetch("files.php", {
method: "POST",
credentials: "same-origin",
body: new FormData(fm)
}).then(function(resp) {
if (!resp.ok)
throw new Error("Failed to upload a report file");
return resp.json();
}).then(function(data) {
Common.checkResult(data);
Notification.add({ text: (data.message || "Uploaded successfully!"), type: "info" });
}).catch(function(err) {
Common.displayError(err);
Notification.add({ text: (err.message || "Error!"), type: "error" });
});
event.preventDefault();
fm.reset();
});
this._fieldset1.appendChild(fm);
}
_create_directory_loading_element() {
this._fieldset2 = document.createElement("fieldset");
this._fieldset2.setAttribute("class", "round-border");
this._fieldset2.disabled = true;
let lg = document.createElement("legend");
lg.appendChild(document.createTextNode("Loading report files from the server directory"));
this._fieldset2.appendChild(lg);
let fm = document.createElement("form");
fm.setAttribute("method", "post");
this._dir_table = new ITable({
class: "main-table subtable",
onclick: function(row) {
let userdata = row.userdata();
let checkbox = row.element().querySelector("input");
if (checkbox && !userdata.error) {
userdata.checked = !userdata.checked;
checkbox.checked = userdata.checked;
this._update_directory_button();
}
}.bind(this),
nodata_text: "No directories are configured."
});
[
{ content: "", class: "cell-status" },
{ content: "Name" },
{ content: "Files" },
{ content: "Location" }
].forEach(function(col) {
this._dir_table.add_column(col);
}, this);
fm.appendChild(this._dir_table.element());
let bb = document.createElement("div");
bb.setAttribute("class", "buttons-block");
fm.appendChild(bb);
let sb = this._create_button_element("submit", "Load reports");
sb.disabled = true;
bb.appendChild(sb);
fm.addEventListener("submit", function(event) {
sb.disabled = true;
let ids = this._directories.filter(function(it) {
return it.checked;
}).map(function(it) {
return it.id;
});
let that = this;
window.fetch("files.php", {
method: "POST",
headers: Object.assign(HTTP_HEADERS, HTTP_HEADERS_POST),
credentials: "same-origin",
body: JSON.stringify({ cmd: "load-directory", ids: ids })
}).then(function(resp) {
if (!resp.ok)
throw new Error("Failed to load report files");
return resp.json();
}).then(function(data) {
if (!data.error_code) {
Notification.add({ text: (data.message || "Loaded successfully!"), type: "info" });
}
if (data.other_errors) {
that._notify_other_errors(data.other_errors);
}
Common.checkResult(data);
}).catch(function(err) {
Common.displayError(err);
Notification.add({ text: (err.message || "Error!"), type: "error" });
}).finally(function() {
that._fetch_data(false, true);
});
event.preventDefault();
}.bind(this));
this._fieldset2.appendChild(fm);
}
_display_files_info() {
this._fcount_info = document.createElement("div");
this._fcount_info.setAttribute("class", "state-gray");
let dv = document.createElement("div");
dv.setAttribute("class", "state-text");
dv.appendChild(
document.createTextNode(
"You can upload not more than " + this._limits.upload_max_file_count + " files."
)
);
this._fcount_info.appendChild(dv);
this._fsize_info = document.createElement("div");
this._fsize_info.setAttribute("class", "state-gray");
dv = document.createElement("div");
dv.setAttribute("class", "state-text");
dv.appendChild(
document.createTextNode(
"You can upload a file with no more than " + bytes2size(this._limits.upload_max_file_size) + "."
)
);
this._fsize_info.appendChild(dv);
dv = document.createElement("div");
dv.setAttribute("class", "info-block");
dv.appendChild(this._fcount_info);
dv.appendChild(this._fsize_info);
this._fieldset1.appendChild(dv);
}
_update_directory_loading_element() {
this._dir_table.clear();
let d = {};
d.rows = this._directories.map(function(it) {
let files = it.files;
let chkbox = false;
it.checked = false;
let rd = { cells: [], userdata: it };
if (files < 0) {
chkbox = null;
files = "Error!";
rd.class = "state-red";
it.error = true;
}
rd.cells.push(new DirectoryCheckboxCell(chkbox));
rd.cells.push({ content: it.name });
rd.cells.push({ content: files, class: "state-text" });
rd.cells.push({ content: it.location });
return rd;
});
this._dir_table.add_frame(new ITableFrame(d, this._dir_table.last_row_index() + 1));
}
_update_directory_button() {
this._fieldset2.querySelector("button[type=submit]").disabled = !this._directories.some(function(it) {
return it.checked;
});
}
_clear_warnings() {
[ this._fcount_info, this._fsize_info ].forEach(function(el) {
if (el) {
el.classList.remove("state-red");
el.classList.add("state-gray");
}
});
}
_notify_other_errors(errors) {
let cut = null;
let length = errors.length;
if (length > 4) {
cut = errors.slice(0, 3);
cut.push("and " + (length - 3) + " more errors");
}
Notification.add({ text: cut || errors, type: "error" });
}
_set_warning(el) {
if (el) {
el.classList.remove("state-gray");
el.classList.add("state-red");
}
}
_check_files(fl_el) {
this._clear_warnings();
if (fl_el.files.length == 0) {
return false;
}
let res = true;
if (fl_el.files.length > this._limits.upload_max_file_count) {
res = false;
this._set_warning(this._fcount_info);
let message = "You can only upload " + this._limits.upload_max_file_count + " files.";
Notification.add({ type: "error", text: message, delay: 10000 });
}
let bf_cnt = 0;
for (let i = 0; i < fl_el.files.length; ++i) {
if (fl_el.files[i].size > this._limits.upload_max_file_size) {
++bf_cnt;
}
};
if (bf_cnt > 0) {
res = false;
this._set_warning(this._fsize_info);
Notification.add({
type: "error",
text: "" + bf_cnt + " file" + (bf_cnt > 1 && "s" || "") + " exceed the maximum allowed size.",
delay: 10000
});
}
return res;
}
_create_button_element(type, text) {
let el = document.createElement("button");
el.setAttribute("type", type);
el.appendChild(document.createTextNode(text));
return el;
}
_create_input_element(type, name, value) {
let el = document.createElement("input");
el.setAttribute("type", type);
if (name)
el.setAttribute("name", name);
if (value)
el.setAttribute("value", value);
return el;
}
_fetch_data(files, dirs) {
if (files) {
this._fieldset1.disabled = true;
this._fieldset1.insertBefore(set_wait_status(), this._fieldset1.children[0]);
}
if (dirs) {
this._fieldset2.disabled = true;
this._fieldset2.insertBefore(set_wait_status(), this._fieldset2.children[0]);
}
let that = this;
window.fetch("files.php", {
method: "GET",
headers: HTTP_HEADERS,
credentials: "same-origin"
}).then(function(resp) {
if (!resp.ok)
throw new Error("Failed to get loader data");
return resp.json();
}).then(function(data) {
Common.checkResult(data);
if (files) {
that._limits.upload_max_file_count = data.upload_max_file_count;
that._limits.upload_max_file_size = data.upload_max_file_size;
that._display_files_info();
that._fieldset1.disabled = false;
}
if (dirs) {
that._directories = data.directories || [];
that._update_directory_loading_element();
that._fieldset2.disabled = false;
}
}).catch(function(err) {
Common.displayError(err);
Notification.add({ type: "error", text: err.message });
if (files) {
that._fieldset1.insertBefore(set_error_status(null, err.message), that._fieldset1.children[0]);
}
if (dirs) {
that._fieldset2.insertBefore(set_error_status(null, err.message), that._fieldset2.children[0]);
}
}).finally(function() {
if (files) {
that._fieldset1.querySelector(".wait-message").remove();
}
if (dirs) {
that._fieldset2.querySelector(".wait-message").remove();
}
});
}
}
class DirectoryCheckboxCell extends ITableCell {
value(target) {
if (target === "dom") {
let cb = document.createElement("input");
cb.setAttribute("type", "checkbox");
if (this._content !== null) {
cb.checked = this._content;
}
else {
cb.disabled = true;
cb.checked = false;
}
return cb;
}
return this._content;
}
}