diff --git a/.gitignore b/.gitignore index cfd2188..6dafb29 100644 --- a/.gitignore +++ b/.gitignore @@ -5,6 +5,8 @@ scss/*.css* scss/bs4/*.css* scss/bs5/*.css* data/static/*.css +data/static/*.js +!data/static/setup.js data/config-base.json data/config-default.ini data/*.html diff --git a/Makefile b/Makefile index a8b8b40..90ba951 100644 --- a/Makefile +++ b/Makefile @@ -1,40 +1,44 @@ configuration: - echo "Fixing config-base" + $(info Fixing config-base) python3 config/fixconfig.py -i config/config-base.json -o data/config-base.json - echo "Generating config-default.ini" + $(info Generating config-default.ini) python3 config/generate_ini.py -i config/config-base.json -o data/config-default.ini --version git sass: - echo "Getting libsass" + $(info Getting libsass) python3 -m pip install libsass - echo "Getting node dependencies" + $(info Getting node dependencies) python3 scss/get_node_deps.py - echo "Compiling sass" + $(info Compiling sass) python3 scss/compile.py sass-headless: - echo "Getting libsass" + $(info Getting libsass) python3 -m pip install libsass - echo "Getting node dependencies" + $(info Getting node dependencies) python3 scss/get_node_deps.py - echo "Compiling sass" + $(info Compiling sass) python3 scss/compile.py -y mail-headless: - echo "Generating email html" + $(info Generating email html) python3 mail/generate.py -y mail: - echo "Generating email html" + $(info Generating email html) python3 mail/generate.py +typescript: + $(info Compiling typescript) + -npx tsc -p ts/ + version: python3 version.py auto version.go compile: - echo "Downloading deps" + $(info Downloading deps) go mod download - echo "Building" + $(info Building) mkdir -p build CGO_ENABLED=0 go build -o build/jfa-go *.go @@ -42,14 +46,14 @@ compress: upx --lzma build/jfa-go copy: - echo "Copying data" + $(info Copying data) cp -r data build/ install: cp -r build $(DESTDIR)/jfa-go -all: configuration sass mail version compile copy -headless: configuration sass-headless mail-headless version compile copy +all: configuration sass mail version typescript compile copy +headless: configuration sass-headless mail-headless version typescript compile copy diff --git a/api.go b/api.go index e5c60a5..063d1f7 100644 --- a/api.go +++ b/api.go @@ -230,6 +230,7 @@ func (app *appContext) NewUserAdmin(gc *gin.Context) { } } } + app.jf.cacheExpiry = time.Now() } func (app *appContext) NewUser(gc *gin.Context) { diff --git a/data/static/accounts.js b/data/static/accounts.js deleted file mode 100644 index b651a5f..0000000 --- a/data/static/accounts.js +++ /dev/null @@ -1,356 +0,0 @@ -document.getElementById('selectAll').onclick = function() { - const checkboxes = document.getElementById('accountsList').querySelectorAll('input[type=checkbox]'); - for (check of checkboxes) { - check.checked = this.checked; - } - checkCheckboxes(); -}; - -function checkCheckboxes() { - const defaultsButton = document.getElementById('accountsTabSetDefaults'); - const deleteButton = document.getElementById('accountsTabDelete'); - const checkboxes = document.getElementById('accountsList').querySelectorAll('input[type=checkbox]'); - let checked = 0; - for (check of checkboxes) { - if (check.checked) { - checked++; - } - } - if (checked == 0) { - defaultsButton.classList.add('unfocused'); - deleteButton.classList.add('unfocused'); - } else { - if (defaultsButton.classList.contains('unfocused')) { - defaultsButton.classList.remove('unfocused'); - } - if (deleteButton.classList.contains('unfocused')) { - deleteButton.classList.remove('unfocused'); - } - if (checked == 1) { - deleteButton.textContent = 'Delete User'; - } else { - deleteButton.textContent = 'Delete Users'; - } - } -} - -document.getElementById('deleteModalNotify').onclick = function() { - const textbox = document.getElementById('deleteModalReasonBox'); - if (this.checked && textbox.classList.contains('unfocused')) { - textbox.classList.remove('unfocused'); - } else if (!this.checked) { - textbox.classList.add('unfocused'); - } -}; - -document.getElementById('accountsTabDelete').onclick = function() { - const deleteButton = this; - let selected = []; - const checkboxes = document.getElementById('accountsList').querySelectorAll('input[type=checkbox]'); - for (check of checkboxes) { - if (check.checked) { - selected.push(check.id.replace('select_', '')); - } - } - let title = " user"; - let msg = "Notify user"; - if (selected.length > 1) { - title += "s"; - msg += "s"; - } - title = "Delete " + selected.length + title; - msg += " of account deletion"; - document.getElementById('deleteModalTitle').textContent = title; - document.getElementById('deleteModalNotify').checked = false; - document.getElementById('deleteModalNotifyLabel').textContent = msg; - document.getElementById('deleteModalReason').value = ''; - document.getElementById('deleteModalReasonBox').classList.add('unfocused'); - document.getElementById('deleteModalSend').textContent = 'Delete'; - - document.getElementById('deleteModalSend').onclick = function() { - const button = this; - const send = { - 'users': selected, - 'notify': document.getElementById('deleteModalNotify').checked, - 'reason': document.getElementById('deleteModalReason').value - }; - let req = new XMLHttpRequest(); - req.open("POST", "/deleteUser", true); - req.responseType = 'json'; - req.setRequestHeader("Authorization", "Basic " + btoa(window.token + ":")); - req.setRequestHeader('Content-Type', 'application/json; charset=UTF-8'); - req.onreadystatechange = function() { - if (this.readyState == 4) { - if (this.status == 500) { - if ("error" in req.response) { - button.textContent = 'Failed'; - } else { - button.textContent = 'Partial fail (check console)'; - console.log(req.response); - } - setTimeout(function() { - deleteModal.hide(); - deleteButton.classList.add('unfocused'); - }, 4000); - } else { - deleteButton.classList.add('unfocused'); - deleteModal.hide(); - } - populateUsers(); - checkCheckboxes(); - } - }; - req.send(JSON.stringify(send)); - }; - deleteModal.show(); -} - -var jfUsers = []; - -function validEmail(email) { - const re = /\S+@\S+\.\S+/; - return re.test(email); -} - -function changeEmail(icon, id) { - const iconContent = icon.outerHTML; - icon.setAttribute("class", ""); - const entry = icon.nextElementSibling; - const ogEmail = entry.value; - entry.readOnly = false; - entry.classList.remove('form-control-plaintext'); - entry.classList.add('form-control'); - if (entry.value == "") { - entry.placeholder = 'Address'; - } - const tick = document.createElement('i'); - tick.classList.add("fa", "fa-check", "d-inline-block", "icon-button", "text-success"); - tick.setAttribute('style', 'margin-left: 0.5rem; margin-right: 0.5rem;'); - tick.onclick = function() { - const newEmail = entry.value; - if (!validEmail(newEmail) || newEmail == ogEmail) { - return - } - cross.remove(); - this.outerHTML = ` -
, , <1: Empty invite (no delete/link), 0: Actual invite>, , , [], , , , ]
-function parseInvite(invite, empty = false) {
- if (empty) {
- return ["None", "", 1];
- }
- let i = [invite["code"], "", 0, invite["email"]];
- let time = ""
- for (m of ["days", "hours", "minutes"]) {
- if (invite[m] != 0) {
- time += `${invite[m]}${m[0]} `;
- }
- }
- i[1] = `Expires in ${time.slice(0, -1)}`;
- if ('remaining-uses' in invite) {
- i[4] = invite['remaining-uses'];
- }
- if (invite['no-limit']) {
- i[4] = '∞';
- }
- if ('used-by' in invite) {
- i[5] = invite['used-by'];
- } else {
- i[5] = [];
- }
- if ('created' in invite) {
- i[6] = invite['created'];
- }
- if ('notify-expiry' in invite) {
- i[7] = invite['notify-expiry'];
- }
- if ('notify-creation' in invite) {
- i[8] = invite['notify-creation'];
- }
- if ('profile' in invite) {
- i[9] = invite['profile'];
- }
- return i;
-}
-
-function addItem(parsedInvite) {
- let links = document.getElementById('invites');
- let itemContainer = document.createElement('div');
- itemContainer.id = parsedInvite[0];
- let listItem = document.createElement('div');
- // listItem.id = parsedInvite[0];
- listItem.classList.add('list-group-item', 'd-flex', 'justify-content-between', 'd-inline-block');
-
- let code = document.createElement('div');
- code.classList.add('d-flex', 'align-items-center', 'font-monospace');
- code.setAttribute('style', 'width: 40%;');
- let codeLink = document.createElement('a');
- codeLink.textContent = parsedInvite[0].replace(/-/g, '-');
-
- code.appendChild(codeLink);
-
- listItem.appendChild(code);
-
- let listRight = document.createElement('div');
- listRight.setAttribute('style', 'text-align: right;');
- let listText = document.createElement('span');
- listText.id = parsedInvite[0] + '_expiry';
- listText.setAttribute('style', 'margin-right: 1rem;');
- listText.textContent = parsedInvite[1];
-
- listRight.appendChild(listText);
-
- if (parsedInvite[2] == 0) {
- let inviteCode = window.location.href.split('#')[0] + 'invite/' + parsedInvite[0];
- //
- codeLink.href = inviteCode;
- codeLink.classList.add('invite-link');
- let copyButton = document.createElement('i');
- copyButton.onclick = function() { toClipboard(inviteCode); };
- copyButton.classList.add('fa', 'fa-clipboard', 'icon-button');
- copyButton.setAttribute('style', 'margin-right: 0.5rem; margin-left: 0.5rem;');
-
- code.appendChild(copyButton);
-
- if (parsedInvite[3] !== undefined) {
- let sentTo = document.createElement('span');
- sentTo.classList.add('text-muted');
- sentTo.setAttribute('style', 'margin-left: 0.4rem; font-style: italic, font-size: 0.75rem;');
- if (!parsedInvite[3].includes('Failed to send to')) {
- sentTo.textContent = "Sent to ";
- }
- sentTo.textContent += parsedInvite[3];
-
- code.appendChild(sentTo);
- }
-
- let deleteButton = document.createElement('button');
- deleteButton.onclick = function() { deleteInvite(parsedInvite[0]); };
- deleteButton.classList.add('btn', 'btn-outline-danger');
- deleteButton.textContent = "Delete";
-
- let block = document.createElement('div');
- block.setAttribute('style', 'display: inline-block;');
- block.appendChild(deleteButton);
- let dropButton = document.createElement('i');
- dropButton.classList.add('fa', 'fa-angle-down', 'collapsed', 'icon-button', 'not-rotated');
- dropButton.setAttribute('style', 'padding: 1rem; margin: -1rem -1rem -1rem 0;');
- dropButton.setAttribute('data-toggle', 'collapse');
- dropButton.setAttribute('aria-expanded', 'false');
- dropButton.setAttribute('data-target', '#' + CSS.escape(parsedInvite[0]) + '_collapse');
- dropButton.onclick = function() {
- if (this.classList.contains('rotated')) {
- this.classList.remove('rotated');
- this.classList.add('not-rotated');
- } else {
- this.classList.remove('not-rotated');
- this.classList.add('rotated');
- }
- };
- dropButton.setAttribute('style', 'margin-left: 1rem;');
- block.appendChild(dropButton);
- listRight.appendChild(block);
- }
-
- listItem.appendChild(listRight);
- itemContainer.appendChild(listItem);
- if (parsedInvite[2] == 0) {
- let itemDropdown = document.createElement('div');
- itemDropdown.id = parsedInvite[0] + '_collapse';
- itemDropdown.classList.add('collapse');
-
- let dropdownContent = document.createElement('div');
- dropdownContent.classList.add('container', 'row', 'align-items-start', 'card-body');
-
- let dropdownLeft = document.createElement('div');
- dropdownLeft.classList.add('col');
-
- let leftList = document.createElement('ul');
- leftList.classList.add('list-group', 'list-group-flush');
-
- let profileBox = document.createElement('li');
- profileBox.classList.add('input-group', 'py-1');
- let prof = `
-
- `;
- profileBox.innerHTML = prof;
- leftList.appendChild(profileBox);
- // 9 is profileName! availableProfiles
-
- if (typeof(parsedInvite[6]) != 'undefined') {
- let createdDate = document.createElement('li');
- createdDate.classList.add('list-group-item', 'py-1');
- createdDate.textContent = `Created: ${parsedInvite[6]}`;
- leftList.appendChild(createdDate);
- }
-
- let remainingUses = document.createElement('li');
- remainingUses.classList.add('list-group-item', 'py-1');
- remainingUses.id = parsedInvite[0] + '_remainingUses';
- remainingUses.textContent = `Remaining uses: ${parsedInvite[4]}`;
- leftList.appendChild(remainingUses);
-
- dropdownLeft.appendChild(leftList);
- dropdownContent.appendChild(dropdownLeft);
-
- if (notifications_enabled) {
- let dropdownMiddle = document.createElement('div');
- dropdownMiddle.id = parsedInvite[0] + '_notifyButtons';
- dropdownMiddle.classList.add('col');
-
- let middleList = document.createElement('ul');
- middleList.classList.add('list-group', 'list-group-flush');
- middleList.textContent = 'Notify on:';
-
- let notifyExpiry = document.createElement('li');
- notifyExpiry.classList.add('list-group-item', 'py-1', 'form-check');
- notifyExpiry.innerHTML = `
-
-
- `;
- if (typeof(parsedInvite[7]) == 'boolean') {
- notifyExpiry.getElementsByTagName('input')[0].checked = parsedInvite[7];
- }
-
- notifyExpiry.getElementsByTagName('input')[0].onclick = function() {
- let req = new XMLHttpRequest();
- var thisEl = this;
- let send = {};
- let code = thisEl.id.replace('_notifyExpiry', '');
- send[code] = {};
- send[code]['notify-expiry'] = thisEl.checked;
- req.open("POST", "/setNotify", true);
- req.setRequestHeader("Authorization", "Basic " + btoa(window.token + ":"));
- req.setRequestHeader('Content-Type', 'application/json; charset=UTF-8');
- req.onreadystatechange = function() {
- if (this.readyState == 4 && this.status != 200) {
- thisEl.checked = !thisEl.checked;
- }
- };
- req.send(JSON.stringify(send));
- };
- middleList.appendChild(notifyExpiry);
-
- let notifyCreation = document.createElement('li');
- notifyCreation.classList.add('list-group-item', 'py-1', 'form-check');
- notifyCreation.innerHTML = `
-
-
- `;
- if (typeof(parsedInvite[8]) == 'boolean') {
- notifyCreation.getElementsByTagName('input')[0].checked = parsedInvite[8];
- }
- notifyCreation.getElementsByTagName('input')[0].onclick = function() {
- let req = new XMLHttpRequest();
- var thisEl = this;
- let send = {};
- let code = thisEl.id.replace('_notifyCreation', '');
- send[code] = {};
- send[code]['notify-creation'] = thisEl.checked;
- req.open("POST", "/setNotify", true);
- req.setRequestHeader("Authorization", "Basic " + btoa(window.token + ":"));
- req.setRequestHeader('Content-Type', 'application/json; charset=UTF-8');
- req.onreadystatechange = function() {
- if (this.readyState == 4 && this.status != 200) {
- thisEl.checked = !thisEl.checked;
- }
- };
- req.send(JSON.stringify(send));
- };
- middleList.appendChild(notifyCreation);
-
- dropdownMiddle.appendChild(middleList);
- dropdownContent.appendChild(dropdownMiddle);
- }
-
-
- let dropdownRight = document.createElement('div');
- dropdownRight.id = parsedInvite[0] + '_usersCreated';
- dropdownRight.classList.add('col');
- if (parsedInvite[5].length != 0) {
- let userList = document.createElement('ul');
- userList.classList.add('list-group', 'list-group-flush');
- userList.innerHTML = 'Users created: ';
- for (let user of parsedInvite[5]) {
- let li = document.createElement('li');
- li.classList.add('list-group-item', 'py-1', 'disabled');
- let username = document.createElement('div');
- username.classList.add('d-flex', 'float-left');
- username.textContent = user[0];
- li.appendChild(username);
- let date = document.createElement('div');
- date.classList.add('d-flex', 'float-right');
- date.textContent = user[1];
- li.appendChild(date);
- userList.appendChild(li);
- }
- dropdownRight.appendChild(userList);
- }
- dropdownContent.appendChild(dropdownRight);
-
- itemDropdown.appendChild(dropdownContent);
-
- itemContainer.appendChild(itemDropdown);
- }
- links.appendChild(itemContainer);
-}
-
-function updateInvite(parsedInvite) {
- let expiry = document.getElementById(parsedInvite[0] + '_expiry');
- expiry.textContent = parsedInvite[1];
-
- let remainingUses = document.getElementById(parsedInvite[0] + '_remainingUses');
- if (remainingUses) {
- remainingUses.textContent = `Remaining uses: ${parsedInvite[4]}`;
- }
-
- if (parsedInvite[5].length != 0) {
- let usersCreated = document.getElementById(parsedInvite[0] + '_usersCreated');
- let dropdownRight = document.createElement('div');
- dropdownRight.id = parsedInvite[0] + '_usersCreated';
- dropdownRight.classList.add('col');
- let userList = document.createElement('ul');
- userList.classList.add('list-group', 'list-group-flush');
- userList.innerHTML = 'Users created: ';
- for (let user of parsedInvite[5]) {
- let li = document.createElement('li');
- li.classList.add('list-group-item', 'py-1', 'disabled');
- let username = document.createElement('div');
- username.classList.add('d-flex', 'float-left');
- username.textContent = user[0];
- li.appendChild(username);
- let date = document.createElement('div');
- date.classList.add('d-flex', 'float-right');
- date.textContent = user[1];
- li.appendChild(date);
- userList.appendChild(li);
- }
- dropdownRight.appendChild(userList);
- usersCreated.replaceWith(dropdownRight);
- }
-
-
-}
-
-// delete from list on page
-function removeInvite(code) {
- let item = document.getElementById(code);
- item.parentNode.removeChild(item);
-}
-
-function generateInvites(empty = false) {
- if (empty === false) {
- let req = new XMLHttpRequest();
- req.open("GET", "/getInvites", true);
- req.setRequestHeader("Authorization", "Basic " + btoa(window.token + ":"));
- req.responseType = 'json';
- req.onreadystatechange = function() {
- if (this.readyState == 4) {
- var data = this.response;
- availableProfiles = data['profiles'];
- if (data['invites'] == null || data['invites'].length == 0) {
- document.getElementById('invites').textContent = '';
- addItem(parseInvite([], true));
- } else {
- for (let invite of data['invites']) {
- let match = false;
- let items = document.getElementById('invites').children;
- for (let item of items) {
- if (item.id == invite['code']) {
- match = true;
- updateInvite(parseInvite(invite));
- }
- }
- if (match == false) {
- addItem(parseInvite(invite));
- }
- }
- let items = document.getElementById('invites').children;
- for (let item of items) {
- var exists = false;
- for (let invite of data['invites']) {
- if (item.id == invite['code']) {
- exists = true;
- }
- }
- if (exists == false) {
- removeInvite(item.id);
- }
- }
- }
- }
- };
- req.send();
- } else if (empty === true) {
- document.getElementById('invites').textContent = '';
- addItem(parseInvite([], true));
- }
-}
-
-// actually delete invite
-function deleteInvite(code) {
- let send = JSON.stringify({ "code": code });
- let req = new XMLHttpRequest();
- req.open("POST", "/deleteInvite", true);
- req.setRequestHeader("Authorization", "Basic " + btoa(window.token + ":"));
- req.setRequestHeader('Content-Type', 'application/json; charset=UTF-8');
- req.onreadystatechange = function() {
- if (this.readyState == 4) {
- generateInvites();
- }
- };
- req.send(send);
-}
-
-// Add numbers to select element
-function addOptions(length, selectElement) {
- for (let v = 0; v <= length; v++) {
- let opt = document.createElement('option');
- opt.textContent = v;
- opt.value = v;
- selectElement.appendChild(opt);
- }
-}
-
-function toClipboard(str) {
- const el = document.createElement('textarea');
- el.value = str;
- el.setAttribute('readOnly', '');
- el.style.position = 'absolute';
- el.style.left = '-9999px';
- document.body.appendChild(el);
- const selected = document.getSelection().rangeCount > 0 ? document.getSelection().getRangeAt(0) : false;
- el.select();
- document.execCommand('copy');
- document.body.removeChild(el);
- if (selected) {
- document.getSelection().removeAllRanges();
- document.getSelection().addRange(selected);
- }
-}
-
-function fixCheckboxes() {
- let send_to_address = [document.getElementById('send_to_address'), document.getElementById('send_to_address_enabled')]
- if (send_to_address[0] != null) {
- send_to_address[0].disabled = !send_to_address[1].checked;
- }
- let multiUseEnabled = document.getElementById('multiUseEnabled');
- let multiUseCount = document.getElementById('multiUseCount');
- let noUseLimit = document.getElementById('noUseLimit');
- multiUseCount.disabled = !multiUseEnabled.checked;
- noUseLimit.checked = false;
- noUseLimit.disabled = !multiUseEnabled.checked;
-}
-
-fixCheckboxes();
-
-document.getElementById('inviteForm').onsubmit = function() {
- let button = document.getElementById('generateSubmit');
- button.disabled = true;
- button.innerHTML =
- '' +
- 'Loading...';
- send_object = serializeForm('inviteForm');
- if (!send_object['multiple-uses'] || send_object['no-limit']) {
- delete send_object['remaining-uses'];
- }
- if (document.getElementById('send_to_address') != null) {
- if (send_object['send_to_address_enabled']) {
- send_object['email'] = send_object['send_to_address'];
- delete send_object['send_to_address'];
- delete send_object['send_to_address_enabled'];
- }
- }
- let send = JSON.stringify(send_object);
- let req = new XMLHttpRequest();
- req.open("POST", "/generateInvite", true);
- req.setRequestHeader("Authorization", "Basic " + btoa(window.token + ":"));
- req.setRequestHeader('Content-Type', 'application/json; charset=UTF-8');
- req.onreadystatechange = function() {
- if (this.readyState == 4) {
- button.textContent = 'Generate';
- button.disabled = false;
- generateInvites();
- }
- };
- req.send(send);
- return false;
-};
-
-function tryLogin(username, password, modal, button, callback) {
- let req = new XMLHttpRequest();
- req.responseType = 'json';
- req.onreadystatechange = function() {
- if (this.readyState == 4) {
- if (this.status != 200) {
- let errormsg = req.response["error"];
- if (errormsg == "") {
- errormsg = "Unknown error"
- }
- if (modal) {
- button.disabled = false;
- button.textContent = errormsg;
- if (!button.classList.contains('btn-danger')) {
- button.classList.add('btn-danger');
- button.classList.remove('btn-primary');
- }
- setTimeout(function () {
- if (button.classList.contains('btn-danger')) {
- button.classList.add('btn-primary');
- button.classList.remove('btn-danger');
- button.textContent = 'Login';
- }
- }, 4000)
- } else {
- loginModal.show();
- }
- } else {
- const data = this.response;
- window.token = data['token'];
- generateInvites();
- const interval = setInterval(function() { generateInvites(); }, 60 * 1000);
- let day = document.getElementById('days');
- addOptions(30, day);
- day.selected = "0";
- let hour = document.getElementById('hours');
- addOptions(24, hour);
- hour.selected = "0";
- let minutes = document.getElementById('minutes');
- addOptions(59, minutes);
- minutes.selected = "30";
- checkDuration();
- if (modal) {
- loginModal.hide();
- }
- document.getElementById('logoutButton').setAttribute('style', '');
- }
- if (typeof callback === "function") {
- callback(this.status);
- }
- }
- };
- req.open("GET", "/getToken", true);
- req.setRequestHeader("Authorization", "Basic " + btoa(username + ":" + password));
- req.send();
-}
-
-document.getElementById('loginForm').onsubmit = function() {
- window.token = "";
- let details = serializeForm('loginForm');
- // let errorArea = document.getElementById('loginErrorArea');
- // errorArea.textContent = '';
- let button = document.getElementById('loginSubmit');
- if (button.classList.contains('btn-danger')) {
- button.classList.add('btn-primary');
- button.classList.remove('btn-danger');
- }
- button.disabled = true;
- button.innerHTML =
- '' +
- 'Loading...';
- tryLogin(username = details['username'], password = details['password'], modal = true, button = button)
- return false;
-};
-
-document.getElementById('openAbout').onclick = function() {
- settingsModal.hide();
- aboutModal.show();
-};
-
-function populateRadios() {
- let radioList = document.getElementById('defaultUserRadios');
- radioList.textContent = '';
- let first = true;
- for (user of jfUsers) {
- let radio = document.createElement('div');
- radio.classList.add('form-check');
- let checked = 'checked';
- if (first) {
- first = false;
- } else {
- checked = '';
- }
- // radio.innerHTML =
- // ``;
- radio.innerHTML = `
-
- `;
- radioList.appendChild(radio);
- }
-}
-
-document.getElementById('openDefaultsWizard').onclick = function() {
- this.disabled = true
- this.innerHTML =
- '' +
- 'Loading...';
- let req = new XMLHttpRequest();
- req.responseType = 'json';
- req.open("GET", "/getUsers", true);
- req.setRequestHeader("Authorization", "Basic " + btoa(window.token + ":"));
- req.onreadystatechange = function() {
- if (this.readyState == 4) {
- if (this.status == 200) {
- jfUsers = req.response['users'];
- populateRadios();
- let button = document.getElementById('openDefaultsWizard');
- button.disabled = false;
- button.innerHTML = 'New User Defaults ';
- let submitButton = document.getElementById('storeDefaults');
- submitButton.disabled = false;
- submitButton.textContent = 'Submit';
- if (submitButton.classList.contains('btn-success')) {
- submitButton.classList.remove('btn-success');
- submitButton.classList.add('btn-primary');
- } else if (submitButton.classList.contains('btn-danger')) {
- submitButton.classList.remove('btn-danger');
- submitButton.classList.add('btn-primary');
- }
- settingsModal.hide();
- document.getElementById('defaultsTitle').textContent = `New user defaults`;
- document.getElementById('userDefaultsDescription').textContent = `
- Create an account and configure it to your liking, then choose it from below to store the settings as a template for all new users.`;
- document.getElementById('storeHomescreenLabel').textContent = `Store homescreen layout`;
- document.getElementById('defaultsSource').value = 'fromUser';
- document.getElementById('defaultsSourceSection').classList.add('unfocused');
- document.getElementById('storeDefaults').onclick = function() {
- storeDefaults('all');
- };
- const list = document.getElementById('defaultUserRadios');
- if (list.classList.contains('unfocused')) {
- list.classList.remove('unfocused');
- }
- userDefaultsModal.show();
- }
- }
- };
- req.send();
-};
-
-function storeDefaults(users) {
- this.disabled = true;
- this.innerHTML =
- '' +
- 'Loading...';
- let button = document.getElementById('storeDefaults');
- let radios = document.getElementsByName('defaultRadios');
- let id = '';
- for (let radio of radios) {
- if (radio.checked) {
- id = radio.id.replace('default_', '');
- break;
- }
- }
- let route = '/setDefaults';
- let data = {
- 'from': 'user',
- 'id': id,
- 'homescreen': false
- };
- if (document.getElementById('defaultsSource').value == 'userTemplate') {
- data['from'] = 'template';
- }
- if (users != 'all') {
- data['apply_to'] = users;
- route = '/applySettings';
- }
- if (document.getElementById('storeDefaultHomescreen').checked) {
- data['homescreen'] = true;
- }
- let req = new XMLHttpRequest();
- req.open("POST", route, true);
- req.responseType = 'json';
- req.setRequestHeader("Authorization", "Basic " + btoa(window.token + ":"));
- req.setRequestHeader('Content-Type', 'application/json; charset=UTF-8');
- req.onreadystatechange = function() {
- if (this.readyState == 4) {
- if (this.status == 200 || this.status == 204) {
- button.textContent = "Success";
- if (button.classList.contains('btn-danger')) {
- button.classList.remove('btn-danger');
- } else if (button.classList.contains('btn-primary')) {
- button.classList.remove('btn-primary');
- }
- button.classList.add('btn-success');
- button.disabled = false;
- setTimeout(function() {
- let button = document.getElementById('storeDefaults');
- button.textContent = "Submit";
- button.classList.remove('btn-success');
- button.classList.add('btn-primary');
- button.disabled = false;
- userDefaultsModal.hide();
- }, 1000);
- } else {
- if ("error" in req.response) {
- button.textContent = req.response["error"];
- } else if (("policy" in req.response) || ("homescreen" in req.response)) {
- button.textContent = "Failed (Check JS Console)";
- } else {
- button.textContent = "Failed";
- }
- button.classList.remove('btn-primary');
- button.classList.add('btn-danger');
- setTimeout(function() {
- let button = document.getElementById('storeDefaults');
- button.textContent = "Submit";
- button.classList.remove('btn-danger');
- button.classList.add('btn-primary');
- button.disabled = false;
- }, 1000);
- }
- }
- };
- req.send(JSON.stringify(data));
-};
-
-var ombiDefaultsModal = '';
-if (ombiEnabled) {
- ombiDefaultsModal = createModal('ombiDefaults');
- document.getElementById('openOmbiDefaults').onclick = function() {
- this.disabled = true;
- this.innerHTML =
- '' +
- 'Loading...';
- let req = new XMLHttpRequest();
- req.responseType = 'json';
- req.open("GET", "/getOmbiUsers", true);
- req.setRequestHeader("Authorization", "Basic " + btoa(window.token + ":"));
- req.onreadystatechange = function() {
- if (this.readyState == 4) {
- if (this.status == 200) {
- let users = req.response['users'];
- let radioList = document.getElementById('ombiUserRadios');
- radioList.textContent = '';
- let first = true;
- // name and id
- for (user of users) {
- let radio = document.createElement('div');
- radio.classList.add('radio');
- let checked = 'checked';
- if (first) {
- first = false;
- } else {
- checked = '';
- }
- radio.innerHTML =
- ``;
- radioList.appendChild(radio);
- }
- let button = document.getElementById('openOmbiDefaults');
- button.disabled = false;
- button.innerHTML = 'Ombi User Defaults ';
- let submitButton = document.getElementById('storeOmbiDefaults');
- submitButton.disabled = false;
- submitButton.textContent = 'Submit';
- if (submitButton.classList.contains('btn-success')) {
- submitButton.classList.remove('btn-success');
- submitButton.classList.add('btn-primary');
- } else if (submitButton.classList.contains('btn-danger')) {
- submitButton.classList.remove('btn-danger');
- submitButton.classList.add('btn-primary');
- }
- settingsModal.hide();
- ombiDefaultsModal.show();
- }
- }
- };
- req.send();
- };
- document.getElementById('storeOmbiDefaults').onclick = function() {
- this.disabled = true;
- this.innerHTML =
- '' +
- 'Loading...';
- let button = document.getElementById('storeOmbiDefaults');
- let radios = document.getElementsByName('ombiRadios');
- for (let radio of radios) {
- if (radio.checked) {
- let data = {
- 'id': radio.id.slice(8),
- };
- let req = new XMLHttpRequest();
- req.open("POST", "/setOmbiDefaults", true);
- req.setRequestHeader("Authorization", "Basic " + btoa(window.token + ":"));
- req.setRequestHeader('Content-Type', 'application/json; charset=UTF-8');
- req.onreadystatechange = function() {
- if (this.readyState == 4) {
- if (this.status == 200 || this.status == 204) {
- button.textContent = "Success";
- if (button.classList.contains('btn-danger')) {
- button.classList.remove('btn-danger');
- } else if (button.classList.contains('btn-primary')) {
- button.classList.remove('btn-primary');
- }
- button.classList.add('btn-success');
- button.disabled = false;
- setTimeout(function() { ombiDefaultsModal.hide(); }, 1000);
- } else {
- button.textContent = "Failed";
- button.classList.remove('btn-primary');
- button.classList.add('btn-danger');
- setTimeout(function() {
- let button = document.getElementById('storeOmbiDefaults');
- button.textContent = "Submit";
- button.classList.remove('btn-danger');
- button.classList.add('btn-primary');
- button.disabled = false;
- }, 1000);
- }
- }
- };
- req.send(JSON.stringify(data));
- }
- }
- };
-}
-
-generateInvites(empty = true);
-
-tryLogin("", "", false, callback = function(code){
- console.log(code);
- if (code != 200) {
- loginModal.show();
- }
-});
-
-document.getElementById('logoutButton').onclick = function () {
- let req = new XMLHttpRequest();
- req.open("POST", "/logout", true);
- req.responseType = 'json';
- req.setRequestHeader("Authorization", "Basic " + btoa(window.token + ":"));
- req.onreadystatechange = function() {
- if (this.readyState == 4 && this.status == 200) {
- window.token = '';
- location.reload();
- return false;
- }
- };
- req.send();
-}
-
-var config = {};
-var modifiedConfig = {};
-
-document.getElementById('openSettings').onclick = function () {
- let req = new XMLHttpRequest();
- req.open("GET", "/getConfig", true);
- req.responseType = 'json';
- req.setRequestHeader("Authorization", "Basic " + btoa(window.token + ":"));
- req.onreadystatechange = function() {
- if (this.readyState == 4 && this.status == 200) {
- let settingsList = document.getElementById('settingsList');
- settingsList.textContent = '';
- config = this.response;
- for (let section of config["order"]) {
- let sectionCollapse = document.createElement('div');
- sectionCollapse.classList.add('collapse');
- sectionCollapse.id = section;
-
- let sectionTitle = config[section]['meta']['name'];
- let sectionDescription = config[section]['meta']['description'];
- let entryListID = section + '_entryList';
- let sectionFooter = section + '_footer';
-
- let innerCollapse = `
-
- ${sectionDescription}
-
-
-
- `;
-
- sectionCollapse.innerHTML = innerCollapse;
-
- for (var entry of config[section]["order"]) {
- if (entry != 'meta') {
- let entryName = config[section][entry]['name'];
- let required = false;
- if (config[section][entry]['required']) {
- entryName += ' *';
- required = true;
- }
- if (config[section][entry]['requires_restart']) {
- entryName += ' R';
- }
- if (config[section][entry].hasOwnProperty('description')) {
- let tooltip = `
-
- `;
- entryName += ' ';
- entryName += tooltip;
- };
- let entryValue = config[section][entry]['value'];
- let entryType = config[section][entry]['type'];
- let entryGroup = document.createElement('div');
- if (entryType == 'bool') {
- entryGroup.classList.add('form-check');
- if (entryValue.toString() == 'true') {
- var checked = true;
- } else {
- var checked = false;
- }
- entryGroup.innerHTML = `
-
-
- `;
- entryGroup.getElementsByClassName('form-check-input')[0].required = required;
- entryGroup.getElementsByClassName('form-check-input')[0].checked = checked;
- entryGroup.getElementsByClassName('form-check-input')[0].onclick = function() {
- var state = this.checked;
- for (var sect of Object.keys(config)) {
- for (var ent of Object.keys(config[sect])) {
- if ((sect + '_' + config[sect][ent]['depends_true']) == this.id) {
- document.getElementById(sect + '_' + ent).disabled = !state;
- } else if ((sect + '_' + config[sect][ent]['depends_false']) == this.id) {
- document.getElementById(sect + '_' + ent).disabled = state;
- }
- }
- }
- };
- } else if ((entryType == 'text') || (entryType == 'email') || (entryType == 'password') || (entryType == 'number')) {
- entryGroup.classList.add('form-group');
- entryGroup.innerHTML = `
-
-
- `;
- entryGroup.getElementsByClassName('form-control')[0].required = required;
- } else if (entryType == 'select') {
- entryGroup.classList.add('form-group');
- let entryOptions = config[section][entry]['options'];
- let innerGroup = `
-
- ';
- entryGroup.innerHTML = innerGroup;
- entryGroup.getElementsByClassName('form-control')[0].required = required;
-
- }
- sectionCollapse.getElementsByClassName(entryListID)[0].appendChild(entryGroup);
- }
- }
- let sectionButton = document.createElement('button');
- sectionButton.setAttribute('type', 'button');
- sectionButton.classList.add('list-group-item', 'list-group-item-action');
- sectionButton.appendChild(document.createTextNode(sectionTitle));
- sectionButton.id = section + '_button';
- sectionButton.setAttribute('data-toggle', 'collapse');
- sectionButton.setAttribute('data-target', '#' + section);
- settingsList.appendChild(sectionButton);
- settingsList.appendChild(sectionCollapse);
- }
- }
- };
- req.send();
- settingsModal.show();
-}
-
-triggerTooltips();
-
-function sendConfig(modalId, restart = false) {
- let modal = document.getElementById(modalId);
- modifiedConfig['restart-program'] = false;
- if (restart) {
- modifiedConfig['restart-program'] = true;
- }
- let send = JSON.stringify(modifiedConfig);
- let req = new XMLHttpRequest();
- req.open("POST", "/modifyConfig", true);
- req.setRequestHeader("Authorization", "Basic " + btoa(window.token + ":"));
- req.setRequestHeader('Content-Type', 'application/json; charset=UTF-8');
- req.onreadystatechange = function() {
- if (this.readyState == 4) {
- if (this.status == 200 || this.status == 204) {
- createModal(modalId, true).hide();
- if (modalId != 'settingsMenu') {
- settingsModal.hide();
- }
- } else if (restart) {
- refreshModal.show();
- }
- }
- };
- req.send(send);
-}
-
-document.getElementById('settingsSave').onclick = function() {
- modifiedConfig = {};
- var restart_setting_changed = false;
- var settings_changed = false;
-
- for (let section of config["order"]) {
- for (let entry of config[section]["order"]) {
- if (entry != 'meta') {
- let entryID = section + '_' + entry;
- let el = document.getElementById(entryID);
- if (el.type == 'checkbox') {
- var value = el.checked.toString();
- } else {
- var value = el.value.toString();
- }
- if (value != config[section][entry]['value'].toString()) {
- if (!modifiedConfig.hasOwnProperty(section)) {
- modifiedConfig[section] = {};
- }
- modifiedConfig[section][entry] = value;
- settings_changed = true;
- if (config[section][entry]['requires_restart']) {
- restart_setting_changed = true;
- }
- }
- }
- }
- }
- if (restart_setting_changed) {
- document.getElementById('applyRestarts').onclick = function(){ sendConfig('restartModal'); };
- let restartButton = document.getElementById('applyAndRestart')
- if (restartButton) {
- restartButton.onclick = function(){ sendConfig('restartModal', restart=true); };
- }
- settingsModal.hide();
- restartModal.show();
- } else if (settings_changed) {
- sendConfig('settingsMenu');
- } else {
- settingsModal.hide();
- }
-}
-
-function setProfile(select) {
- if (select.value == "") {
- return;
- }
- let invite = select.id.replace("profile_", "");
- let req = new XMLHttpRequest();
- let send = {
- "invite": invite,
- "profile": select.value
- };
- req.open("POST", "/setProfile", true);
- req.setRequestHeader("Authorization", "Basic " + btoa(window.token + ":"));
- req.setRequestHeader('Content-Type', 'application/json; charset=UTF-8');
- req.onreadystatechange = function() {
- if (this.readyState == 4 && this.status != 200) {
- generateInvites(false);
- }
- };
- req.send(JSON.stringify(send));
-}
-
-
-// Disable 'Generate' button if days, hours, minutes are all zero
-function checkDuration() {
- let boxVals = [document.getElementById("days").value, document.getElementById("hours").value, document.getElementById("minutes").value];
- let submit = document.getElementById("generateSubmit");
- if (boxVals[0] != 0 || boxVals[1] != 0 || boxVals[2] != 0) {
- submit.disabled = false;
- } else if (boxVals[0] == 0 && boxVals[1] == 0 && boxVals[2] == 0) {
- submit.disabled = true;
- }
-}
-
-for (i of ["days", "hours", "minutes"]) {
- document.getElementById(i).addEventListener("change", checkDuration);
-}
diff --git a/data/static/serialize.js b/data/static/serialize.js
deleted file mode 100644
index 51aa656..0000000
--- a/data/static/serialize.js
+++ /dev/null
@@ -1,32 +0,0 @@
-function serializeForm(id) {
- var form = document.getElementById(id);
- var formData = {};
- for (var i = 0; i < form.elements.length; i++) {
- var el = form.elements[i];
- if (el.type != 'submit') {
- var name = el.name;
- if (name == '') {
- name = el.id;
- };
- switch (el.type) {
- case 'checkbox':
- formData[name] = el.checked;
- break;
- case 'text':
- case 'password':
- case 'email':
- case 'number':
- formData[name] = el.value;
- break;
- case 'select-one':
- let val = el.value;
- if (!isNaN(val)) {
- val = parseInt(val)
- }
- formData[name] = val;
- break;
- };
- };
- };
- return formData;
-};
diff --git a/data/templates/admin.html b/data/templates/admin.html
index 5e3684b..7b7e876 100644
--- a/data/templates/admin.html
+++ b/data/templates/admin.html
@@ -31,9 +31,9 @@
return "";
}
{{ if .bs5 }}
- const bsVersion = 5;
+ var bsVersion = 5;
{{ else }}
- const bsVersion = 4;
+ var bsVersion = 4;
{{ end }}
var cssFile = "{{ .cssFile }}";
var css = document.createElement('link');
@@ -52,8 +52,6 @@
}
css.setAttribute('href', cssFile);
document.head.appendChild(css);
- // store whether ombi is enabled, 1 or 0.
- var ombiEnabled = {{ .ombiEnabled }}
{{ if not .bs5 }}
@@ -315,7 +313,7 @@
-