remove ajax and md5

This commit is contained in:
Evgenii Alekseev 2024-09-04 18:38:24 +03:00
parent bd926de740
commit 8e8be8a622
7 changed files with 201 additions and 143 deletions

View File

@ -2,7 +2,7 @@
const alertPlaceholder = document.getElementById("alert-placeholder"); const alertPlaceholder = document.getElementById("alert-placeholder");
function createAlert(title, message, clz, action, id) { function createAlert(title, message, clz, action, id) {
if (!id) id = $.md5(title + message); // MD5 id from the content id ??= md5(title + message); // MD5 id from the content
if (alertPlaceholder.querySelector(`#alert-${id}`)) return; // check if there are duplicates if (alertPlaceholder.querySelector(`#alert-${id}`)) return; // check if there are duplicates
const wrapper = document.createElement("div"); const wrapper = document.createElement("div");
@ -32,12 +32,12 @@
toast.show(); toast.show();
} }
function showFailure(title, description, jqXHR, errorThrown) { function showFailure(title, description, error) {
let details; let details;
try { try {
details = JSON.parse(jqXHR.responseText).error; // execution handler json error response details = JSON.parse(error.text).error; // execution handler json error response
} catch (_) { } catch (_) {
details = errorThrown; details = error.text ?? error;
} }
createAlert(title, description(details), "text-bg-danger"); createAlert(title, description(details), "text-bg-danger");
} }

View File

@ -55,13 +55,17 @@
const server = keyImportServerInput.value; const server = keyImportServerInput.value;
if (key && server) { if (key && server) {
$.ajax({ makeRequest(
url: "/api/v1/service/pgp", "/api/v1/service/pgp",
data: {"key": key, "server": server}, {
type: "GET", query: {
dataType: "json", key: key,
success: response => { keyImportBodyInput.textContent = response.key; }, server: server,
}); },
convert: response => response.json(),
},
data => { keyImportBodyInput.textContent = data.key; },
);
} }
} }
@ -70,20 +74,24 @@
const server = keyImportServerInput.value; const server = keyImportServerInput.value;
if (key && server) { if (key && server) {
$.ajax({ makeRequest(
url: "/api/v1/service/pgp", "/api/v1/service/pgp",
data: JSON.stringify({key: key, server: server}), {
type: "POST", method: "POST",
contentType: "application/json", json: {
success: _ => { key: key,
server: server,
},
},
_ => {
bootstrap.Modal.getOrCreateInstance(keyImportModal).hide(); bootstrap.Modal.getOrCreateInstance(keyImportModal).hide();
showSuccess("Success", `Key ${key} has been imported`); showSuccess("Success", `Key ${key} has been imported`);
}, },
error: (jqXHR, _, errorThrown) => { error => {
const message = _ => `Could not import key ${key} from ${server}`; const message = _ => `Could not import key ${key} from ${server}`;
showFailure("Action failed", message, jqXHR, errorThrown); showFailure("Action failed", message, error);
}, },
}); );
} }
} }

View File

@ -46,23 +46,27 @@
const username = loginUsernameInput.value; const username = loginUsernameInput.value;
if (username && password) { if (username && password) {
$.ajax({ makeRequest(
url: "/api/v1/login", "/api/v1/login",
data: JSON.stringify({username: username, password: password}), {
type: "POST", method: "POST",
contentType: "application/json", json: {
success: _ => { username: username,
password: password,
},
},
_ => {
bootstrap.Modal.getOrCreateInstance(loginModal).hide(); bootstrap.Modal.getOrCreateInstance(loginModal).hide();
showSuccess("Logged in", `Successfully logged in as ${username}`, _ => location.href = "/"); showSuccess("Logged in", `Successfully logged in as ${username}`, _ => location.href = "/");
}, },
error: (jqXHR, _, errorThrown) => { error => {
const message = _ => const message = _ =>
username === "admin" && password === "admin" username === "admin" && password === "admin"
? "You've entered a password for user \"root\", did you make a typo in username?" ? "You've entered a password for user \"root\", did you make a typo in username?"
: `Could not login as ${username}`; : `Could not login as ${username}`;
showFailure("Login error", message, jqXHR, errorThrown); showFailure("Login error", message, error);
}, },
}); );
} }
} }

View File

@ -141,10 +141,15 @@
const value = packageAddInput.value; const value = packageAddInput.value;
if (value.length >= 3) { if (value.length >= 3) {
const query = new URLSearchParams({for: value}); makeRequest(
fetch(`/api/v1/service/search?${query.toString()}`) "/api/v1/service/search",
.then(response => response.json()) {
.then(data => { query: {
for: value,
},
convert: response => response.json(),
},
data => {
const options = data.map(pkg => { const options = data.map(pkg => {
const option = document.createElement("option"); const option = document.createElement("option");
option.value = pkg.package; option.value = pkg.package;
@ -152,8 +157,8 @@
return option; return option;
}); });
packageAddKnownPackagesList.replaceChildren(...options); packageAddKnownPackagesList.replaceChildren(...options);
}) },
.catch(_ => {}); );
} }
}, 500); }, 500);
}); });

View File

@ -163,12 +163,13 @@
variableButtonRemove.classList.add("btn-outline-danger"); variableButtonRemove.classList.add("btn-outline-danger");
variableButtonRemove.innerHTML = "<i class=\"bi bi-trash\"></i>"; variableButtonRemove.innerHTML = "<i class=\"bi bi-trash\"></i>";
variableButtonRemove.onclick = _ => { variableButtonRemove.onclick = _ => {
$.ajax({ makeRequest(
url: `/api/v1/packages/${packageBase}/patches/${variable.key}`, `/api/v1/packages/${packageBase}/patches/${variable.key}`,
type: "DELETE", {
dataType: "json", method: "DELETE",
success: _ => variableInput.remove(), },
}); _ => variableInput.remove(),
);
}; };
// bring them together // bring them together
@ -181,39 +182,41 @@
} }
function loadChanges(packageBase, onFailure) { function loadChanges(packageBase, onFailure) {
$.ajax({ makeRequest(
url: `/api/v1/packages/${packageBase}/changes`, `/api/v1/packages/${packageBase}/changes`,
data: { {
architecture: repository.architecture, query: {
repository: repository.repository, architecture: repository.architecture,
repository: repository.repository,
},
convert: response => response.json(),
}, },
type: "GET", data => {
dataType: "json", const changes = data.changes;
success: response => {
const changes = response.changes;
packageInfoChangesInput.textContent = changes ?? ""; packageInfoChangesInput.textContent = changes ?? "";
highlight(packageInfoChangesInput); highlight(packageInfoChangesInput);
}, },
error: onFailure, onFailure,
}); );
} }
function loadEvents(packageBase, onFailure) { function loadEvents(packageBase, onFailure) {
packageInfoEventsTable.bootstrapTable("showLoading"); packageInfoEventsTable.bootstrapTable("showLoading");
clearChart(); clearChart();
$.ajax({ makeRequest(
url: `/api/v1/events`, "/api/v1/events",
data: { {
architecture: repository.architecture, query: {
repository: repository.repository, architecture: repository.architecture,
object_id: packageBase, repository: repository.repository,
limit: 30, object_id: packageBase,
limit: 30,
},
convert: response => response.json(),
}, },
type: "GET", data => {
dataType: "json", const events = data.map(event => {
success: response => {
const events = response.map(event => {
return { return {
timestamp: new Date(1000 * event.created).toISOStringShort(), timestamp: new Date(1000 * event.created).toISOStringShort(),
event: event.event, event: event.event,
@ -225,7 +228,7 @@
packageInfoEventsTable.bootstrapTable("hideLoading"); packageInfoEventsTable.bootstrapTable("hideLoading");
if (packageInfoEventsUpdateChart) { if (packageInfoEventsUpdateChart) {
const chart = response.filter(event => event.event === "package-updated"); const chart = data.filter(event => event.event === "package-updated");
packageInfoEventsUpdateChart.config.data = { packageInfoEventsUpdateChart.config.data = {
labels: chart.map(event => new Date(1000 * event.created).toISOStringShort()), labels: chart.map(event => new Date(1000 * event.created).toISOStringShort()),
datasets: [{ datasets: [{
@ -237,30 +240,31 @@
}; };
packageInfoEventsUpdateChart.update(); packageInfoEventsUpdateChart.update();
} }
packageInfoEventsUpdateChart.hidden = !events.length; packageInfoEventsUpdateChartCanvas.hidden = !events.length;
}, },
error: onFailure, onFailure,
}); );
} }
function loadLogs(packageBase, onFailure) { function loadLogs(packageBase, onFailure) {
$.ajax({ makeRequest(
url: `/api/v2/packages/${packageBase}/logs`, `/api/v2/packages/${packageBase}/logs`,
data: { {
architecture: repository.architecture, query: {
repository: repository.repository, architecture: repository.architecture,
repository: repository.repository,
},
convert: response => response.json(),
}, },
type: "GET", data => {
dataType: "json", const logs = data.map(log_record => {
success: response => {
const logs = response.map(log_record => {
return `[${new Date(1000 * log_record.created).toISOString()}] ${log_record.message}`; return `[${new Date(1000 * log_record.created).toISOString()}] ${log_record.message}`;
}); });
packageInfoLogsInput.textContent = logs.join("\n"); packageInfoLogsInput.textContent = logs.join("\n");
highlight(packageInfoLogsInput); highlight(packageInfoLogsInput);
}, },
error: onFailure, onFailure,
}); );
} }
function loadPackage(packageBase, onFailure) { function loadPackage(packageBase, onFailure) {
@ -272,16 +276,17 @@
return ["bg-secondary", "text-white"]; return ["bg-secondary", "text-white"];
}; };
$.ajax({ makeRequest(
url: `/api/v1/packages/${packageBase}`, `/api/v1/packages/${packageBase}`,
data: { {
architecture: repository.architecture, query: {
repository: repository.repository, architecture: repository.architecture,
repository: repository.repository,
},
convert: response => response.json(),
}, },
type: "GET", data => {
dataType: "json", const description = data.find(Boolean);
success: response => {
const description = response.find(Boolean);
const packages = Object.keys(description.package.packages); const packages = Object.keys(description.package.packages);
const aurUrl = description.package.remote.web_url; const aurUrl = description.package.remote.web_url;
const upstreamUrls = Array.from( const upstreamUrls = Array.from(
@ -313,22 +318,23 @@
packageInfoUpstreamUrl.innerHTML = upstreamUrls.map(url => safeLink(url, url, "upstream link").outerHTML).join("<br>"); packageInfoUpstreamUrl.innerHTML = upstreamUrls.map(url => safeLink(url, url, "upstream link").outerHTML).join("<br>");
packageInfoVersion.textContent = description.package.version; packageInfoVersion.textContent = description.package.version;
}, },
error: onFailure, onFailure,
}); );
} }
function loadPatches(packageBase, onFailure) { function loadPatches(packageBase, onFailure) {
$.ajax({ makeRequest(
url: `/api/v1/packages/${packageBase}/patches`, `/api/v1/packages/${packageBase}/patches`,
type: "GET", {
dataType: "json", convert: response => response.json(),
success: response => {
packageInfoVariablesDiv.replaceChildren();
response.map(patch => insertVariable(packageBase, patch));
packageInfoVariablesBlock.hidden = !response.length;
}, },
error: onFailure, data => {
}); packageInfoVariablesDiv.replaceChildren();
data.map(patch => insertVariable(packageBase, patch));
packageInfoVariablesBlock.hidden = !data.length;
},
onFailure,
);
} }
function packageInfoRemove() { function packageInfoRemove() {
@ -348,10 +354,10 @@
else else
packageBase = packageInfoModal.package; // read package base from the current window attribute packageBase = packageInfoModal.package; // read package base from the current window attribute
const onFailure = (jqXHR, _, errorThrown) => { const onFailure = error => {
if (isPackageBaseSet) { if (isPackageBaseSet) {
const message = error => `Could not load package ${packageBase} info: ${error}`; const message = details => `Could not load package ${packageBase} info: ${details}`;
showFailure("Load failure", message, jqXHR, errorThrown); showFailure("Load failure", message, error);
} }
}; };

View File

@ -11,24 +11,24 @@
const versionBadge = document.getElementById("badge-version"); const versionBadge = document.getElementById("badge-version");
function doPackageAction(uri, packages, repository, successText, failureText, data) { function doPackageAction(uri, packages, repository, successText, failureText, data) {
const queryParams = $.param({ makeRequest(
architecture: repository.architecture, uri,
repository: repository.repository, {
}); // it will never be empty btw method: "POST",
query: {
$.ajax({ architecture: repository.architecture,
url: `${uri}?${queryParams}`, repository: repository.repository,
data: JSON.stringify(Object.assign({}, {packages: packages}, data || {})), },
type: "POST", json: Object.assign({}, {packages: packages}, data || {}),
contentType: "application/json", },
success: _ => { _ => {
const message = successText(packages.join(", ")); const message = successText(packages.join(", "));
showSuccess("Success", message); showSuccess("Success", message);
}, },
error: (jqXHR, _, errorThrown) => { error => {
showFailure("Action failed", failureText, jqXHR, errorThrown); showFailure("Action failed", failureText, error);
}, },
}); );
} }
function filterListGroups() { function filterListGroups() {
@ -84,16 +84,17 @@
return "btn-outline-secondary"; return "btn-outline-secondary";
}; };
$.ajax({ makeRequest(
url: "/api/v1/packages", "/api/v1/packages",
data: { {
architecture: repository.architecture, query: {
repository: repository.repository, architecture: repository.architecture,
repository: repository.repository,
},
convert: response => response.json(),
}, },
type: "GET", data => {
dataType: "json", const payload = data.map(description => {
success: response => {
const payload = response.map(description => {
const package_base = description.package.base; const package_base = description.package.base;
const web_url = description.package.remote.web_url; const web_url = description.package.remote.web_url;
return { return {
@ -113,8 +114,8 @@
table.bootstrapTable("uncheckAll"); table.bootstrapTable("uncheckAll");
table.bootstrapTable("hideLoading"); table.bootstrapTable("hideLoading");
}, },
error: (jqXHR, _, errorThrown) => { error => {
if ((jqXHR.status === 401) || (jqXHR.status === 403)) { if ((error.status === 401) || (error.status === 403)) {
// authorization error // authorization error
const text = "In order to see statuses you must login first."; const text = "In order to see statuses you must login first.";
table.find("tr.unauthorized").remove(); table.find("tr.unauthorized").remove();
@ -122,33 +123,34 @@
table.bootstrapTable("hideLoading"); table.bootstrapTable("hideLoading");
} else { } else {
// other errors // other errors
const message = error => `Could not load list of packages: ${error}`; const message = details => `Could not load list of packages: ${details}`;
showFailure("Load failure", message, jqXHR, errorThrown); showFailure("Load failure", message, error);
} }
}, },
}); );
$.ajax({ makeRequest(
url: "/api/v1/status", "/api/v1/status",
data: { {
architecture: repository.architecture, query: {
repository: repository.repository, architecture: repository.architecture,
repository: repository.repository,
},
convert: response => response.json(),
}, },
type: "GET", data => {
dataType: "json", versionBadge.innerHTML = `<i class="bi bi-github"></i> ahriman ${safe(data.version)}`;
success: response => {
versionBadge.innerHTML = `<i class="bi bi-github"></i> ahriman ${safe(response.version)}`;
statusBadge.classList.remove(...statusBadge.classList); statusBadge.classList.remove(...statusBadge.classList);
statusBadge.classList.add("btn"); statusBadge.classList.add("btn");
statusBadge.classList.add(badgeClass(response.status.status)); statusBadge.classList.add(badgeClass(data.status.status));
const popover = bootstrap.Popover.getOrCreateInstance(statusBadge); const popover = bootstrap.Popover.getOrCreateInstance(statusBadge);
popover.dispose(); popover.dispose();
statusBadge.dataset.bsContent = `${response.status.status} at ${new Date(1000 * response.status.timestamp).toISOStringShort()}`; statusBadge.dataset.bsContent = `${data.status.status} at ${new Date(1000 * data.status.timestamp).toISOStringShort()}`;
bootstrap.Popover.getOrCreateInstance(statusBadge); bootstrap.Popover.getOrCreateInstance(statusBadge);
}, },
}); );
} }
function selectRepository() { function selectRepository() {

View File

@ -1,5 +1,5 @@
<script src="https://cdn.jsdelivr.net/npm/jquery@3.7.1/dist/jquery.min.js" crossorigin="anonymous" type="application/javascript"></script> <script src="https://cdn.jsdelivr.net/npm/jquery@3.7.1/dist/jquery.min.js" crossorigin="anonymous" type="application/javascript"></script>
<script src="https://cdn.jsdelivr.net/npm/jquery.md5@1.0.2/index.min.js" crossorigin="anonymous" type="application/javascript"></script> <script src="https://cdn.jsdelivr.net/npm/js-md5@0.8.3/src/md5.min.js" crossorigin="anonymous" type="application/javascript"></script>
<script src="https://cdn.jsdelivr.net/npm/moment@2.29.4/moment.min.js" crossorigin="anonymous" type="application/javascript"></script> <script src="https://cdn.jsdelivr.net/npm/moment@2.29.4/moment.min.js" crossorigin="anonymous" type="application/javascript"></script>
<script src="https://cdn.jsdelivr.net/npm/daterangepicker@3.1.0/daterangepicker.min.js" crossorigin="anonymous" type="application/javascript"></script> <script src="https://cdn.jsdelivr.net/npm/daterangepicker@3.1.0/daterangepicker.min.js" crossorigin="anonymous" type="application/javascript"></script>
@ -66,6 +66,39 @@
.join("<br>"); .join("<br>");
} }
function makeRequest(url, params, onSuccess, onFailure) {
const requestParams = {
method: params.method,
body: params.json ? JSON.stringify(params.json) : params.json,
headers: {
"Accept": "application/json",
"Content-Type": "application/json",
},
};
if (params.query) {
const query = new URLSearchParams(params.query);
url += `?${query.toString()}`;
}
convert = params.convert ?? (response => response.text());
return fetch(url, requestParams)
.then(response => {
if (response.ok) {
return convert(response);
} else {
const error = new Error("Network request error");
error.status = response.status;
error.statusText = response.statusText;
return response.text().then(text => {
error.text = text;
throw error;
});
}
})
.then(data => onSuccess && onSuccess(data))
.catch(error => onFailure && onFailure(error));
}
function safe(string) { function safe(string) {
return String(string) return String(string)
.replace(/&/g, "&amp;") .replace(/&/g, "&amp;")