mirror of
https://github.com/hrfee/jfa-go.git
synced 2024-12-22 17:10:10 +00:00
fix/improve parsing of last active dates
parseDT only uses the magic json.Unmarshal method if theres an error with the better version. Error came from some times being sent without a "Z" at the end denoting UTC.
This commit is contained in:
parent
3c952d21f7
commit
a1e30ff5db
17
api.go
17
api.go
@ -839,10 +839,20 @@ type dateToParse struct {
|
|||||||
Parsed time.Time `json:"parseme"`
|
Parsed time.Time `json:"parseme"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// json magically parses datetimes so why not
|
func parseDT(date string) time.Time {
|
||||||
func parseDt(date string) time.Time {
|
// decent method
|
||||||
|
dt, err := time.Parse("2006-01-02T15:04:05.000000", date)
|
||||||
|
if err == nil {
|
||||||
|
return dt
|
||||||
|
}
|
||||||
|
// magic method
|
||||||
|
// some stored dates from jellyfin have no timezone at the end, if not we assume UTC
|
||||||
|
if date[len(date)-1] != 'Z' {
|
||||||
|
date += "Z"
|
||||||
|
}
|
||||||
timeJSON := []byte("{ \"parseme\": \"" + date + "\" }")
|
timeJSON := []byte("{ \"parseme\": \"" + date + "\" }")
|
||||||
var parsed dateToParse
|
var parsed dateToParse
|
||||||
|
// Magically turn it into a time.Time
|
||||||
json.Unmarshal(timeJSON, &parsed)
|
json.Unmarshal(timeJSON, &parsed)
|
||||||
return parsed.Parsed
|
return parsed.Parsed
|
||||||
}
|
}
|
||||||
@ -869,8 +879,9 @@ func (app *appContext) GetUsers(gc *gin.Context) {
|
|||||||
var user respUser
|
var user respUser
|
||||||
user.LastActive = "n/a"
|
user.LastActive = "n/a"
|
||||||
if jfUser["LastActivityDate"] != nil {
|
if jfUser["LastActivityDate"] != nil {
|
||||||
date := parseDt(jfUser["LastActivityDate"].(string))
|
date := parseDT(jfUser["LastActivityDate"].(string))
|
||||||
user.LastActive = app.formatDatetime(date)
|
user.LastActive = app.formatDatetime(date)
|
||||||
|
// fmt.Printf("%s: %s, %s, %+v\n", jfUser["Name"].(string), jfUser["LastActivityDate"].(string), user.LastActive, date)
|
||||||
}
|
}
|
||||||
user.ID = jfUser["Id"].(string)
|
user.ID = jfUser["Id"].(string)
|
||||||
user.Name = jfUser["Name"].(string)
|
user.Name = jfUser["Name"].(string)
|
||||||
|
8
nohup.out
Normal file
8
nohup.out
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
Nov 29 23:37 : exception: Failed to bind to '[::]:6600'; Failed to bind socket: Address already in use
|
||||||
|
/usr/bin/mpDris2:1367: DeprecationWarning: The SafeConfigParser class has been renamed to ConfigParser in Python 3.2. This alias will be removed in future versions. Use ConfigParser directly instead.
|
||||||
|
config = configparser.SafeConfigParser()
|
||||||
|
2020-11-29 23:37:53,454 mpDris2 INFO: Using file:///home/hrfee/Music as music library path.
|
||||||
|
2020-11-29 23:37:53,454 mpDris2 INFO: Using Mutagen to read covers from music files.
|
||||||
|
2020-11-29 23:37:53,456 base INFO: Calling MPD connect('localhost', '6600', timeout=None)
|
||||||
|
2020-11-29 23:37:57,776 mpDris2 INFO: Replaced by :1.24 (PID 1128)
|
||||||
|
2020-11-29 23:37:57,777 base INFO: Calling MPD disconnect()
|
@ -1,7 +1,7 @@
|
|||||||
import { checkCheckboxes, populateUsers, populateRadios } from "./modules/accounts.js";
|
import { checkCheckboxes, populateUsers, populateRadios, changeEmail, validateEmail } from "./modules/accounts.js";
|
||||||
import { _post, _get, _delete, rmAttr, addAttr } from "./modules/common.js";
|
import { _post, _get, _delete, rmAttr, addAttr, createEl } from "./modules/common.js";
|
||||||
import { populateProfiles } from "./modules/settings.js";
|
import { populateProfiles } from "./modules/settings.js";
|
||||||
import { Focus, Unfocus, createEl, storeDefaults } from "./modules/admin.js";
|
import { Focus, Unfocus, storeDefaults } from "./modules/admin.js";
|
||||||
|
|
||||||
interface aWindow extends Window {
|
interface aWindow extends Window {
|
||||||
changeEmail(icon: HTMLElement, id: string): void;
|
changeEmail(icon: HTMLElement, id: string): void;
|
||||||
@ -9,67 +9,7 @@ interface aWindow extends Window {
|
|||||||
|
|
||||||
declare var window: aWindow;
|
declare var window: aWindow;
|
||||||
|
|
||||||
const validateEmail = (email: string): boolean => /\S+@\S+\.\S+/.test(email);
|
window.changeEmail = changeEmail;
|
||||||
|
|
||||||
window.changeEmail = (icon: HTMLElement, id: string): void => {
|
|
||||||
const iconContent = icon.outerHTML;
|
|
||||||
icon.setAttribute('class', '');
|
|
||||||
const entry = icon.nextElementSibling as HTMLInputElement;
|
|
||||||
const ogEmail = entry.value;
|
|
||||||
entry.readOnly = false;
|
|
||||||
entry.classList.remove('form-control-plaintext');
|
|
||||||
entry.classList.add('form-control');
|
|
||||||
if (ogEmail == "") {
|
|
||||||
entry.placeholder = 'Address';
|
|
||||||
}
|
|
||||||
const tick = createEl(`
|
|
||||||
<i class="fa fa-check d-inline-block icon-button text-success" style="margin-left: 0.5rem; margin-right: 0.5rem;"></i>
|
|
||||||
`);
|
|
||||||
tick.onclick = (): void => {
|
|
||||||
const newEmail = entry.value;
|
|
||||||
if (!validateEmail(newEmail) || newEmail == ogEmail) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
cross.remove();
|
|
||||||
const spinner = createEl(`
|
|
||||||
<div class="spinner-border spinner-border-sm" role="status" style="width: 1rem; height: 1rem; margin-left: 0.5rem;">
|
|
||||||
<span class="sr-only">Saving...</span>
|
|
||||||
</div>
|
|
||||||
`);
|
|
||||||
tick.replaceWith(spinner);
|
|
||||||
let send = {};
|
|
||||||
send[id] = newEmail;
|
|
||||||
_post("/users/emails", send, function (): void {
|
|
||||||
if (this.readyState == 4) {
|
|
||||||
if (this.status == 200 || this.status == 204) {
|
|
||||||
entry.nextElementSibling.remove();
|
|
||||||
} else {
|
|
||||||
entry.value = ogEmail;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
icon.outerHTML = iconContent;
|
|
||||||
entry.readOnly = true;
|
|
||||||
entry.classList.remove('form-control');
|
|
||||||
entry.classList.add('form-control-plaintext');
|
|
||||||
entry.placeholder = '';
|
|
||||||
};
|
|
||||||
const cross = createEl(`
|
|
||||||
<i class="fa fa-close d-inline-block icon-button text-danger"></i>
|
|
||||||
`);
|
|
||||||
cross.onclick = (): void => {
|
|
||||||
tick.remove();
|
|
||||||
cross.remove();
|
|
||||||
icon.outerHTML = iconContent;
|
|
||||||
entry.readOnly = true;
|
|
||||||
entry.classList.remove('form-control');
|
|
||||||
entry.classList.add('form-control-plaintext');
|
|
||||||
entry.placeholder = '';
|
|
||||||
entry.value = ogEmail;
|
|
||||||
};
|
|
||||||
icon.parentNode.appendChild(tick);
|
|
||||||
icon.parentNode.appendChild(cross);
|
|
||||||
};
|
|
||||||
|
|
||||||
(<HTMLInputElement>document.getElementById('selectAll')).onclick = function (): void {
|
(<HTMLInputElement>document.getElementById('selectAll')).onclick = function (): void {
|
||||||
const checkboxes: NodeListOf<HTMLInputElement> = document.getElementById('accountsList').querySelectorAll('input[type=checkbox]');
|
const checkboxes: NodeListOf<HTMLInputElement> = document.getElementById('accountsList').querySelectorAll('input[type=checkbox]');
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { _get, _post, _delete } from "../modules/common.js";
|
import { _get, _post, _delete, createEl } from "../modules/common.js";
|
||||||
import { Focus, Unfocus } from "../modules/admin.js";
|
import { Focus, Unfocus } from "../modules/admin.js";
|
||||||
|
|
||||||
interface aWindow extends Window {
|
interface aWindow extends Window {
|
||||||
@ -7,6 +7,8 @@ interface aWindow extends Window {
|
|||||||
|
|
||||||
declare var window: aWindow;
|
declare var window: aWindow;
|
||||||
|
|
||||||
|
export const validateEmail = (email: string): boolean => /\S+@\S+\.\S+/.test(email);
|
||||||
|
|
||||||
export const checkCheckboxes = (): void => {
|
export const checkCheckboxes = (): void => {
|
||||||
const defaultsButton = document.getElementById('accountsTabSetDefaults');
|
const defaultsButton = document.getElementById('accountsTabSetDefaults');
|
||||||
const deleteButton = document.getElementById('accountsTabDelete');
|
const deleteButton = document.getElementById('accountsTabDelete');
|
||||||
@ -28,6 +30,66 @@ export const checkCheckboxes = (): void => {
|
|||||||
|
|
||||||
window.checkCheckboxes = checkCheckboxes;
|
window.checkCheckboxes = checkCheckboxes;
|
||||||
|
|
||||||
|
export function changeEmail(icon: HTMLElement, id: string): void {
|
||||||
|
const iconContent = icon.outerHTML;
|
||||||
|
icon.setAttribute('class', '');
|
||||||
|
const entry = icon.nextElementSibling as HTMLInputElement;
|
||||||
|
const ogEmail = entry.value;
|
||||||
|
entry.readOnly = false;
|
||||||
|
entry.classList.remove('form-control-plaintext');
|
||||||
|
entry.classList.add('form-control');
|
||||||
|
if (ogEmail == "") {
|
||||||
|
entry.placeholder = 'Address';
|
||||||
|
}
|
||||||
|
const tick = createEl(`
|
||||||
|
<i class="fa fa-check d-inline-block icon-button text-success" style="margin-left: 0.5rem; margin-right: 0.5rem;"></i>
|
||||||
|
`);
|
||||||
|
tick.onclick = (): void => {
|
||||||
|
const newEmail = entry.value;
|
||||||
|
if (!validateEmail(newEmail) || newEmail == ogEmail) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
cross.remove();
|
||||||
|
const spinner = createEl(`
|
||||||
|
<div class="spinner-border spinner-border-sm" role="status" style="width: 1rem; height: 1rem; margin-left: 0.5rem;">
|
||||||
|
<span class="sr-only">Saving...</span>
|
||||||
|
</div>
|
||||||
|
`);
|
||||||
|
tick.replaceWith(spinner);
|
||||||
|
let send = {};
|
||||||
|
send[id] = newEmail;
|
||||||
|
_post("/users/emails", send, function (): void {
|
||||||
|
if (this.readyState == 4) {
|
||||||
|
if (this.status == 200 || this.status == 204) {
|
||||||
|
entry.nextElementSibling.remove();
|
||||||
|
} else {
|
||||||
|
entry.value = ogEmail;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
icon.outerHTML = iconContent;
|
||||||
|
entry.readOnly = true;
|
||||||
|
entry.classList.remove('form-control');
|
||||||
|
entry.classList.add('form-control-plaintext');
|
||||||
|
entry.placeholder = '';
|
||||||
|
};
|
||||||
|
const cross = createEl(`
|
||||||
|
<i class="fa fa-close d-inline-block icon-button text-danger"></i>
|
||||||
|
`);
|
||||||
|
cross.onclick = (): void => {
|
||||||
|
tick.remove();
|
||||||
|
cross.remove();
|
||||||
|
icon.outerHTML = iconContent;
|
||||||
|
entry.readOnly = true;
|
||||||
|
entry.classList.remove('form-control');
|
||||||
|
entry.classList.add('form-control-plaintext');
|
||||||
|
entry.placeholder = '';
|
||||||
|
entry.value = ogEmail;
|
||||||
|
};
|
||||||
|
icon.parentNode.appendChild(tick);
|
||||||
|
icon.parentNode.appendChild(cross);
|
||||||
|
};
|
||||||
|
|
||||||
export function populateUsers(): void {
|
export function populateUsers(): void {
|
||||||
const acList = document.getElementById('accountsList');
|
const acList = document.getElementById('accountsList');
|
||||||
acList.innerHTML = `
|
acList.innerHTML = `
|
||||||
@ -53,10 +115,6 @@ export function populateUsers(): void {
|
|||||||
return entry.outerHTML;
|
return entry.outerHTML;
|
||||||
};
|
};
|
||||||
const template = (id: string, username: string, email: string, lastActive: string, admin: boolean): string => {
|
const template = (id: string, username: string, email: string, lastActive: string, admin: boolean): string => {
|
||||||
let isAdmin = "No";
|
|
||||||
if (admin) {
|
|
||||||
isAdmin = "Yes";
|
|
||||||
}
|
|
||||||
let fci = "form-check-input";
|
let fci = "form-check-input";
|
||||||
if (window.bsVersion != 5) {
|
if (window.bsVersion != 5) {
|
||||||
fci = "";
|
fci = "";
|
||||||
|
@ -1,14 +1,8 @@
|
|||||||
import { rmAttr, addAttr, _post, _get, _delete } from "../modules/common.js";
|
import { rmAttr, addAttr, _post, _get, _delete, createEl } from "../modules/common.js";
|
||||||
|
|
||||||
export const Focus = (el: HTMLElement): void => rmAttr(el, 'unfocused');
|
export const Focus = (el: HTMLElement): void => rmAttr(el, 'unfocused');
|
||||||
export const Unfocus = (el: HTMLElement): void => addAttr(el, 'unfocused');
|
export const Unfocus = (el: HTMLElement): void => addAttr(el, 'unfocused');
|
||||||
|
|
||||||
export function createEl(html: string): HTMLElement {
|
|
||||||
let div = document.createElement('div') as HTMLDivElement;
|
|
||||||
div.innerHTML = html;
|
|
||||||
return div.firstElementChild as HTMLElement;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function storeDefaults(users: string | Array<string>): void {
|
export function storeDefaults(users: string | Array<string>): void {
|
||||||
const button = document.getElementById('storeDefaults') as HTMLButtonElement;
|
const button = document.getElementById('storeDefaults') as HTMLButtonElement;
|
||||||
button.disabled = true;
|
button.disabled = true;
|
||||||
|
@ -1,5 +1,11 @@
|
|||||||
declare var window: Window;
|
declare var window: Window;
|
||||||
|
|
||||||
|
export function createEl(html: string): HTMLElement {
|
||||||
|
let div = document.createElement('div') as HTMLDivElement;
|
||||||
|
div.innerHTML = html;
|
||||||
|
return div.firstElementChild as HTMLElement;
|
||||||
|
}
|
||||||
|
|
||||||
export function serializeForm(id: string): Object {
|
export function serializeForm(id: string): Object {
|
||||||
const form = document.getElementById(id) as HTMLFormElement;
|
const form = document.getElementById(id) as HTMLFormElement;
|
||||||
let formData = {};
|
let formData = {};
|
||||||
|
Loading…
Reference in New Issue
Block a user