2022-09-02 11:07:30 +00:00
|
|
|
class Utils {
|
2023-01-12 14:40:28 +00:00
|
|
|
static escape(text) {
|
|
|
|
// https://codereview.stackexchange.com/a/126722
|
|
|
|
var table = {
|
|
|
|
'<': 'lt',
|
|
|
|
'>': 'gt',
|
|
|
|
'"': 'quot',
|
|
|
|
'\'': 'apos',
|
|
|
|
'&': 'amp',
|
|
|
|
'\r': '#10',
|
|
|
|
'\n': '#13'
|
|
|
|
};
|
|
|
|
|
|
|
|
return text.toString().replace(/[<>"'\r\n&]/g, (chr) => {
|
|
|
|
return '&' + table[chr] + ';';
|
|
|
|
});
|
|
|
|
};
|
|
|
|
|
2023-01-10 09:04:01 +00:00
|
|
|
static HTMLToElement(HTMLString) {
|
|
|
|
let templateElement = document.createElement('template');
|
|
|
|
templateElement.innerHTML = HTMLString.trim();
|
|
|
|
return templateElement.content.firstChild;
|
2022-09-02 11:07:30 +00:00
|
|
|
}
|
|
|
|
|
2023-01-09 09:03:52 +00:00
|
|
|
static generateElementId(prefix='', suffix='') {
|
2023-01-04 19:00:37 +00:00
|
|
|
for (let i = 0; true; i++) {
|
2023-01-09 09:03:52 +00:00
|
|
|
if (document.querySelector(`#${prefix}${i}${suffix}`) !== null) {continue;}
|
|
|
|
return `${prefix}${i}${suffix}`;
|
2023-01-04 19:00:37 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-01-09 07:45:47 +00:00
|
|
|
static isObject(object) {
|
|
|
|
return object !== null && typeof object === 'object' && !Array.isArray(object);
|
|
|
|
}
|
|
|
|
|
|
|
|
static mergeObjectsDeep(...objects) {
|
|
|
|
let mergedObject = {};
|
|
|
|
if (objects.length === 0) {
|
|
|
|
return mergedObject;
|
|
|
|
}
|
2023-01-09 09:03:52 +00:00
|
|
|
if (!Utils.isObject(objects[0])) {throw 'Cannot merge non-object';}
|
2023-01-09 07:45:47 +00:00
|
|
|
if (objects.length === 1) {
|
|
|
|
return Utils.mergeObjectsDeep(mergedObject, objects[0]);
|
|
|
|
}
|
2023-01-09 09:03:52 +00:00
|
|
|
if (!Utils.isObject(objects[1])) {throw 'Cannot merge non-object';}
|
2023-01-09 07:45:47 +00:00
|
|
|
for (let key in objects[0]) {
|
|
|
|
if (objects[0].hasOwnProperty(key)) {
|
|
|
|
if (objects[1].hasOwnProperty(key)) {
|
|
|
|
if (Utils.isObject(objects[0][key]) && Utils.isObject(objects[1][key])) {
|
|
|
|
mergedObject[key] = Utils.mergeObjectsDeep(objects[0][key], objects[1][key]);
|
|
|
|
} else {
|
|
|
|
mergedObject[key] = objects[1][key];
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
mergedObject[key] = objects[0][key];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
for (let key in objects[1]) {
|
|
|
|
if (objects[1].hasOwnProperty(key)) {
|
|
|
|
if (!objects[0].hasOwnProperty(key)) {
|
|
|
|
mergedObject[key] = objects[1][key];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (objects.length === 2) {
|
|
|
|
return mergedObject;
|
|
|
|
}
|
|
|
|
return Utils.mergeObjectsDeep(mergedObject, ...objects.slice(2));
|
|
|
|
}
|
|
|
|
|
2022-09-02 11:07:30 +00:00
|
|
|
static deleteCorpusFileRequest(userId, corpusId, corpusFileId) {
|
|
|
|
return new Promise((resolve, reject) => {
|
2023-01-09 09:03:52 +00:00
|
|
|
let corpusFile;
|
|
|
|
try {
|
|
|
|
corpusFile = app.data.users[userId].corpora[corpusId].files[corpusFileId];
|
|
|
|
} catch (error) {
|
|
|
|
corpusFile = {};
|
|
|
|
}
|
2022-09-02 11:07:30 +00:00
|
|
|
|
2023-01-10 09:04:01 +00:00
|
|
|
let modalElement = Utils.HTMLToElement(
|
2022-09-02 11:07:30 +00:00
|
|
|
`
|
|
|
|
<div class="modal">
|
|
|
|
<div class="modal-content">
|
2022-11-15 14:11:16 +00:00
|
|
|
<h4>Confirm Corpus File deletion</h4>
|
2023-01-09 09:03:52 +00:00
|
|
|
<p>Do you really want to delete the Corpus File <b>${corpusFile?.title}</b>? All files will be permanently deleted!</p>
|
2022-09-02 11:07:30 +00:00
|
|
|
</div>
|
|
|
|
<div class="modal-footer">
|
|
|
|
<a class="action-button btn modal-close waves-effect waves-light" data-action="cancel">Cancel</a>
|
|
|
|
<a class="action-button btn modal-close red waves-effect waves-light" data-action="confirm">Delete</a>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
`
|
|
|
|
);
|
|
|
|
document.querySelector('#modals').appendChild(modalElement);
|
|
|
|
let modal = M.Modal.init(
|
|
|
|
modalElement,
|
|
|
|
{
|
|
|
|
dismissible: false,
|
|
|
|
onCloseEnd: () => {
|
|
|
|
modal.destroy();
|
|
|
|
modalElement.remove();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
);
|
|
|
|
|
|
|
|
let confirmElement = modalElement.querySelector('.action-button[data-action="confirm"]');
|
|
|
|
confirmElement.addEventListener('click', (event) => {
|
2023-01-09 09:03:52 +00:00
|
|
|
let corpusFileTitle = corpusFile?.title;
|
2022-09-02 11:07:30 +00:00
|
|
|
fetch(`/corpora/${corpusId}/files/${corpusFileId}`, {method: 'DELETE', headers: {Accept: 'application/json'}})
|
|
|
|
.then(
|
|
|
|
(response) => {
|
2022-11-21 14:41:07 +00:00
|
|
|
if (response.status === 403) {app.flash('Forbidden', 'error'); reject(response);}
|
|
|
|
if (response.status === 404) {app.flash('Not Found', 'error'); reject(response);}
|
|
|
|
app.flash(`Corpus File "${corpusFileTitle}" deleted`, 'corpus');
|
|
|
|
resolve(response);
|
2022-09-02 11:07:30 +00:00
|
|
|
},
|
|
|
|
(response) => {
|
2022-11-21 13:08:49 +00:00
|
|
|
app.flash('Something went wrong', 'error');
|
2022-11-15 14:11:16 +00:00
|
|
|
reject(response);
|
|
|
|
}
|
|
|
|
);
|
|
|
|
});
|
|
|
|
modal.open();
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2022-12-19 15:25:10 +00:00
|
|
|
static deleteProfileAvatarRequest(userId) {
|
|
|
|
return new Promise((resolve, reject) => {
|
2023-01-10 09:04:01 +00:00
|
|
|
let modalElement = Utils.HTMLToElement(
|
2022-12-19 15:25:10 +00:00
|
|
|
`
|
|
|
|
<div class="modal">
|
|
|
|
<div class="modal-content">
|
|
|
|
<h4>Confirm Avatar deletion</h4>
|
|
|
|
<p>Do you really want to delete your Avatar?</p>
|
|
|
|
</div>
|
|
|
|
<div class="modal-footer">
|
|
|
|
<a class="action-button btn modal-close waves-effect waves-light" data-action="cancel">Cancel</a>
|
|
|
|
<a class="action-button btn modal-close red waves-effect waves-light" data-action="confirm">Delete</a>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
`
|
|
|
|
);
|
|
|
|
document.querySelector('#modals').appendChild(modalElement);
|
|
|
|
let modal = M.Modal.init(
|
|
|
|
modalElement,
|
|
|
|
{
|
|
|
|
dismissible: false,
|
|
|
|
onCloseEnd: () => {
|
|
|
|
modal.destroy();
|
|
|
|
modalElement.remove();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
);
|
|
|
|
|
|
|
|
let confirmElement = modalElement.querySelector('.action-button[data-action="confirm"]');
|
|
|
|
confirmElement.addEventListener('click', (event) => {
|
2022-12-23 17:08:33 +00:00
|
|
|
fetch(`/users/${userId}/avatar`, {method: 'DELETE', headers: {Accept: 'application/json'}})
|
2022-12-19 15:25:10 +00:00
|
|
|
.then(
|
|
|
|
(response) => {
|
|
|
|
if (response.status === 403) {app.flash('Forbidden', 'error'); reject(response);}
|
|
|
|
if (response.status === 404) {app.flash('Not Found', 'error'); reject(response);}
|
|
|
|
app.flash(`Avatar marked for deletion`);
|
|
|
|
resolve(response);
|
|
|
|
},
|
|
|
|
(response) => {
|
|
|
|
app.flash('Something went wrong', 'error');
|
|
|
|
reject(response);
|
|
|
|
}
|
|
|
|
);
|
|
|
|
});
|
|
|
|
modal.open();
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2022-09-02 11:07:30 +00:00
|
|
|
static deleteJobRequest(userId, jobId) {
|
|
|
|
return new Promise((resolve, reject) => {
|
2023-01-09 09:03:52 +00:00
|
|
|
let job;
|
|
|
|
try {
|
|
|
|
job = app.data.users[userId].jobs[jobId];
|
|
|
|
} catch (error) {
|
|
|
|
job = {};
|
|
|
|
}
|
2022-09-02 11:07:30 +00:00
|
|
|
|
|
|
|
let confirmElement = modalElement.querySelector('.action-button[data-action="confirm"]');
|
|
|
|
confirmElement.addEventListener('click', (event) => {
|
2023-01-09 09:03:52 +00:00
|
|
|
let jobTitle = job?.title;
|
|
|
|
fetch(`/jobs/${jobId}`, {method: 'DELETE', headers: {Accept: 'application/json'}})
|
2022-09-02 11:07:30 +00:00
|
|
|
.then(
|
|
|
|
(response) => {
|
2022-11-21 14:41:07 +00:00
|
|
|
if (response.status === 403) {app.flash('Forbidden', 'error'); reject(response);}
|
|
|
|
if (response.status === 404) {app.flash('Not Found', 'error'); reject(response);}
|
|
|
|
app.flash(`Job "${jobTitle}" marked for deletion`, 'job');
|
|
|
|
resolve(response);
|
2022-09-02 11:07:30 +00:00
|
|
|
},
|
|
|
|
(response) => {
|
2022-11-21 13:08:49 +00:00
|
|
|
app.flash('Something went wrong', 'error');
|
2022-09-02 11:07:30 +00:00
|
|
|
reject(response);
|
|
|
|
}
|
|
|
|
);
|
|
|
|
});
|
|
|
|
modal.open();
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
static getJobLogRequest(userId, jobId) {
|
|
|
|
return new Promise((resolve, reject) => {
|
2023-01-09 09:03:52 +00:00
|
|
|
fetch(`/jobs/${jobId}/log`, {method: 'GET', headers: {Accept: 'application/json, text/plain'}})
|
2022-09-02 11:07:30 +00:00
|
|
|
.then(
|
|
|
|
(response) => {
|
2022-11-21 14:41:07 +00:00
|
|
|
if (response.status === 403) {app.flash('Forbidden', 'error'); reject(response);}
|
|
|
|
if (response.status === 404) {app.flash('Not Found', 'error'); reject(response);}
|
|
|
|
return response.text();
|
2022-09-02 11:07:30 +00:00
|
|
|
},
|
|
|
|
(response) => {
|
2022-11-21 13:08:49 +00:00
|
|
|
app.flash('Something went wrong', 'error');
|
2022-09-02 11:07:30 +00:00
|
|
|
reject(response);
|
|
|
|
}
|
|
|
|
)
|
|
|
|
.then(
|
|
|
|
(text) => {
|
2023-01-10 09:04:01 +00:00
|
|
|
let modalElement = Utils.HTMLToElement(
|
2022-09-02 11:07:30 +00:00
|
|
|
`
|
|
|
|
<div class="modal">
|
|
|
|
<div class="modal-content">
|
|
|
|
<h4>Job logs</h4>
|
|
|
|
<pre><code>${text}</code></pre>
|
|
|
|
</div>
|
|
|
|
<div class="modal-footer">
|
|
|
|
<a class="btn modal-close waves-effect waves-light">Close</a>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
`
|
|
|
|
);
|
|
|
|
document.querySelector('#modals').appendChild(modalElement);
|
|
|
|
let modal = M.Modal.init(
|
|
|
|
modalElement,
|
|
|
|
{
|
|
|
|
onCloseEnd: () => {
|
|
|
|
modal.destroy();
|
|
|
|
modalElement.remove();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
);
|
|
|
|
modal.open();
|
2022-11-21 14:41:07 +00:00
|
|
|
resolve(text);
|
2022-09-02 11:07:30 +00:00
|
|
|
}
|
|
|
|
);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
static restartJobRequest(userId, jobId) {
|
|
|
|
return new Promise((resolve, reject) => {
|
2023-01-09 09:03:52 +00:00
|
|
|
let job;
|
|
|
|
try {
|
|
|
|
job = app.data.users[userId].jobs[jobId];
|
|
|
|
} catch (error) {
|
|
|
|
job = {};
|
|
|
|
}
|
2022-09-02 11:07:30 +00:00
|
|
|
|
2023-01-10 09:04:01 +00:00
|
|
|
let modalElement = Utils.HTMLToElement(
|
2022-09-02 11:07:30 +00:00
|
|
|
`
|
|
|
|
<div class="modal">
|
|
|
|
<div class="modal-content">
|
2022-11-16 13:15:52 +00:00
|
|
|
<h4>Confirm Job restart</h4>
|
2023-01-09 09:03:52 +00:00
|
|
|
<p>Do you really want to restart the Job <b>${job?.title}</b>? All Job Results will be permanently deleted.</p>
|
2022-09-02 11:07:30 +00:00
|
|
|
</div>
|
|
|
|
<div class="modal-footer">
|
|
|
|
<a class="action-button btn modal-close waves-effect waves-light" data-action="cancel">Cancel</a>
|
|
|
|
<a class="action-button btn modal-close red waves-effect waves-light" data-action="confirm">Restart</a>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
`
|
|
|
|
);
|
|
|
|
document.querySelector('#modals').appendChild(modalElement);
|
|
|
|
let modal = M.Modal.init(
|
|
|
|
modalElement,
|
|
|
|
{
|
|
|
|
dismissible: false,
|
|
|
|
onCloseEnd: () => {
|
|
|
|
modal.destroy();
|
|
|
|
modalElement.remove();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
);
|
|
|
|
|
|
|
|
let confirmElement = modalElement.querySelector('.action-button[data-action="confirm"]');
|
|
|
|
confirmElement.addEventListener('click', (event) => {
|
2023-01-09 09:03:52 +00:00
|
|
|
let jobTitle = job?.title;
|
|
|
|
fetch(`/jobs/${jobId}/restart`, {method: 'POST', headers: {Accept: 'application/json'}})
|
2022-09-02 11:07:30 +00:00
|
|
|
.then(
|
|
|
|
(response) => {
|
2022-11-21 14:41:07 +00:00
|
|
|
if (response.status === 403) {app.flash('Forbidden', 'error'); reject(response);}
|
|
|
|
if (response.status === 404) {app.flash('Not Found', 'error'); reject(response);}
|
|
|
|
if (response.status === 409) {app.flash('Conflict', 'error'); reject(response);}
|
|
|
|
app.flash(`Job "${jobTitle}" restarted.`, 'job');
|
|
|
|
resolve(response);
|
2022-09-02 11:07:30 +00:00
|
|
|
},
|
|
|
|
(response) => {
|
2022-11-21 13:08:49 +00:00
|
|
|
app.flash('Something went wrong', 'error');
|
2022-09-02 11:07:30 +00:00
|
|
|
reject(response);
|
|
|
|
}
|
|
|
|
);
|
|
|
|
});
|
|
|
|
modal.open();
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
static deleteUserRequest(userId) {
|
|
|
|
return new Promise((resolve, reject) => {
|
2023-01-09 09:03:52 +00:00
|
|
|
let user;
|
|
|
|
try {
|
|
|
|
user = app.data.users[userId];
|
|
|
|
} catch (error) {
|
|
|
|
user = {};
|
|
|
|
}
|
2022-09-02 11:07:30 +00:00
|
|
|
|
2023-01-10 09:04:01 +00:00
|
|
|
let modalElement = Utils.HTMLToElement(
|
2022-09-02 11:07:30 +00:00
|
|
|
`
|
|
|
|
<div class="modal">
|
|
|
|
<div class="modal-content">
|
2022-11-16 13:15:52 +00:00
|
|
|
<h4>Confirm User deletion</h4>
|
2023-01-09 09:03:52 +00:00
|
|
|
<p>Do you really want to delete the User <b>${user?.username}</b>? All files will be permanently deleted!</p>
|
2022-09-02 11:07:30 +00:00
|
|
|
</div>
|
|
|
|
<div class="modal-footer">
|
|
|
|
<a class="action-button btn modal-close waves-effect waves-light" data-action="cancel">Cancel</a>
|
|
|
|
<a class="action-button btn modal-close red waves-effect waves-light" data-action="confirm">Delete</a>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
`
|
|
|
|
);
|
|
|
|
document.querySelector('#modals').appendChild(modalElement);
|
|
|
|
let modal = M.Modal.init(
|
|
|
|
modalElement,
|
|
|
|
{
|
|
|
|
dismissible: false,
|
|
|
|
onCloseEnd: () => {
|
|
|
|
modal.destroy();
|
|
|
|
modalElement.remove();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
);
|
|
|
|
|
|
|
|
let confirmElement = modalElement.querySelector('.action-button[data-action="confirm"]');
|
|
|
|
confirmElement.addEventListener('click', (event) => {
|
2023-01-09 09:03:52 +00:00
|
|
|
let userName = user?.username;
|
|
|
|
fetch(`/users/${userId}`, {method: 'DELETE', headers: {Accept: 'application/json'}})
|
2022-09-02 11:07:30 +00:00
|
|
|
.then(
|
|
|
|
(response) => {
|
2022-11-21 14:41:07 +00:00
|
|
|
if (response.status === 403) {app.flash('Forbidden', 'error'); reject(response);}
|
|
|
|
if (response.status === 404) {app.flash('Not Found', 'error'); reject(response);}
|
|
|
|
app.flash(`User "${userName}" marked for deletion`);
|
|
|
|
resolve(response);
|
2022-09-02 11:07:30 +00:00
|
|
|
},
|
|
|
|
(response) => {
|
2022-11-21 13:08:49 +00:00
|
|
|
app.flash('Something went wrong', 'error');
|
2022-09-02 11:07:30 +00:00
|
|
|
reject(response);
|
|
|
|
}
|
|
|
|
);
|
|
|
|
});
|
|
|
|
modal.open();
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|