1
0
mirror of https://github.com/hrfee/jfa-go.git synced 2024-10-18 17:10:11 +00:00

Compare commits

..

No commits in common. "3e73d16cce77bc0ae877629c2a3304673d0be7fe" and "8a6cfe0b4d0439ee49b4af9733ac362e11d084ce" have entirely different histories.

20 changed files with 115 additions and 223 deletions

34
api.go
View File

@ -11,7 +11,7 @@ import (
"github.com/dgrijalva/jwt-go"
"github.com/gin-gonic/gin"
"github.com/hrfee/mediabrowser"
"github.com/itchyny/timefmt-go"
"github.com/knz/strtime"
"github.com/lithammer/shortuuid/v3"
"gopkg.in/ini.v1"
)
@ -48,8 +48,8 @@ func (app *appContext) loadStrftime() {
}
func (app *appContext) prettyTime(dt time.Time) (date, time string) {
date = timefmt.Format(dt, app.datePattern)
time = timefmt.Format(dt, app.timePattern)
date, _ = strtime.Strftime(dt, app.datePattern)
time, _ = strtime.Strftime(dt, app.timePattern)
return
}
@ -189,7 +189,7 @@ func (app *appContext) checkInvite(code string, used bool, username string) bool
// 0 means infinite i guess?
newInv.RemainingUses--
}
newInv.UsedBy = append(newInv.UsedBy, []string{username, strconv.FormatInt(currentTime.Unix(), 10)})
newInv.UsedBy = append(newInv.UsedBy, []string{username, app.formatDatetime(currentTime)})
if !del {
app.storage.invites[code] = newInv
}
@ -870,25 +870,13 @@ func (app *appContext) GetInvites(gc *gin.Context) {
UserDays: inv.UserDays,
UserHours: inv.UserHours,
UserMinutes: inv.UserMinutes,
Created: inv.Created.Unix(),
Created: app.formatDatetime(inv.Created),
Profile: inv.Profile,
NoLimit: inv.NoLimit,
Label: inv.Label,
}
if len(inv.UsedBy) != 0 {
invite.UsedBy = map[string]int64{}
for _, pair := range inv.UsedBy {
// These used to be stored formatted instead of as a unix timestamp.
unix, err := strconv.ParseInt(pair[1], 10, 64)
if err != nil {
date, err := timefmt.Parse(pair[1], app.datePattern+" "+app.timePattern)
if err != nil {
app.err.Printf("Failed to parse usedBy time: %v", err)
}
unix = date.Unix()
}
invite.UsedBy[pair[0]] = unix
}
invite.UsedBy = inv.UsedBy
}
invite.RemainingUses = 1
if inv.RemainingUses != 0 {
@ -1044,8 +1032,6 @@ func (app *appContext) GetUsers(gc *gin.Context) {
return
}
i := 0
app.storage.usersLock.Lock()
defer app.storage.usersLock.Unlock()
for _, jfUser := range users {
user := respUser{
ID: jfUser.ID,
@ -1053,15 +1039,15 @@ func (app *appContext) GetUsers(gc *gin.Context) {
Admin: jfUser.Policy.IsAdministrator,
Disabled: jfUser.Policy.IsDisabled,
}
user.LastActive = "n/a"
if !jfUser.LastActivityDate.IsZero() {
user.LastActive = jfUser.LastActivityDate.Unix()
user.LastActive = app.formatDatetime(jfUser.LastActivityDate.Time)
}
if email, ok := app.storage.emails[jfUser.ID]; ok {
user.Email = email.(string)
}
expiry, ok := app.storage.users[jfUser.ID]
if ok {
user.Expiry = expiry.Unix()
if expiry, ok := app.storage.users[jfUser.ID]; ok {
user.Expiry = app.formatDatetime(expiry)
}
resp.UserList[i] = user

View File

@ -19,8 +19,8 @@ import (
"github.com/gomarkdown/markdown"
"github.com/gomarkdown/markdown/html"
"github.com/itchyny/timefmt-go"
jEmail "github.com/jordan-wright/email"
"github.com/knz/strtime"
"github.com/mailgun/mailgun-go/v4"
)
@ -101,8 +101,8 @@ type Email struct {
}
func (emailer *Emailer) formatExpiry(expiry time.Time, tzaware bool, datePattern, timePattern string) (d, t, expiresIn string) {
d = timefmt.Format(expiry, datePattern)
t = timefmt.Format(expiry, timePattern)
d, _ = strtime.Strftime(expiry, datePattern)
t, _ = strtime.Strftime(expiry, timePattern)
currentTime := time.Now()
if tzaware {
currentTime = currentTime.UTC()

2
go.mod
View File

@ -26,8 +26,8 @@ require (
github.com/hrfee/jfa-go/docs v0.0.0-20201112212552-b6f3cd7c1f71
github.com/hrfee/jfa-go/ombi v0.0.0-20201112212552-b6f3cd7c1f71
github.com/hrfee/mediabrowser v0.3.3
github.com/itchyny/timefmt-go v0.1.2
github.com/jordan-wright/email v4.0.1-0.20200917010138-e1c00e156980+incompatible
github.com/knz/strtime v0.0.0-20200924090105-187c67f2bf5e
github.com/lithammer/shortuuid/v3 v3.0.4
github.com/mailgun/mailgun-go/v4 v4.3.0
github.com/mailru/easyjson v0.7.7 // indirect

4
go.sum
View File

@ -129,8 +129,6 @@ github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGa
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
github.com/hrfee/mediabrowser v0.3.3 h1:7E05uiol8hh2ytKn3WVLrUIvHAyifYEIy3Y5qtuNh8I=
github.com/hrfee/mediabrowser v0.3.3/go.mod h1:PnHZbdxmbv1wCVdAQyM7nwPwpVj9fdKx2EcET7sAk+U=
github.com/itchyny/timefmt-go v0.1.2 h1:q0Xa4P5it6K6D7ISsbLAMwx1PnWlixDcJL6/sFs93Hs=
github.com/itchyny/timefmt-go v0.1.2/go.mod h1:0osSSCQSASBJMsIZnhAaF1C2fCBTJZXrnj37mG8/c+A=
github.com/jordan-wright/email v4.0.1-0.20200917010138-e1c00e156980+incompatible h1:CL0ooBNfbNyJTJATno+m0h+zM5bW6v7fKlboKUGP/dI=
github.com/jordan-wright/email v4.0.1-0.20200917010138-e1c00e156980+incompatible/go.mod h1:1c7szIrayyPPB/987hsnvNzLushdWf4o/79s3P08L8A=
github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
@ -143,6 +141,8 @@ github.com/json-iterator/go v1.1.10 h1:Kz6Cvnvv2wGdaG/V8yMvfkmNiXq9Ya2KUv4rouJJr
github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo=
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
github.com/knz/strtime v0.0.0-20200924090105-187c67f2bf5e h1:ViPE0JEOvtw5I0EGUiFSr2VNKGNU+3oBT+oHbDXHbxk=
github.com/knz/strtime v0.0.0-20200924090105-187c67f2bf5e/go.mod h1:4ZxfWkxwtc7dBeifERVVWRy9F9rTU9p0yCDgeCtlius=
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=

View File

@ -8,10 +8,9 @@
"password": "Passwort",
"emailAddress": "E-Mail-Adresse",
"submit": "Absenden",
"success": "Erfolgreich",
"success": "Erfolg",
"error": "Fehler",
"copy": "Kopieren",
"theme": "Thema",
"copied": "Kopiert"
"theme": "Thema"
}
}

View File

@ -11,7 +11,6 @@
"success": "Success",
"error": "Fout",
"copy": "Kopiëer",
"theme": "Thema",
"copied": "Gekopieerd"
"theme": "Thema"
}
}

View File

@ -11,7 +11,6 @@
"success": "Sucesso",
"error": "Erro",
"copy": "Copiar",
"theme": "Tema",
"copied": "Copiado"
"theme": "Tema"
}
}

View File

@ -23,11 +23,10 @@
"passwordReset": {
"title": "Wachtwoordreset aangevraagd - Jellyfin",
"someoneHasRequestedReset": "Iemand heeft recentelijk een wachtwoordreset aangevraagd in Jellyfin.",
"ifItWasYou": "Als jij dit was, voer dan onderstaande PIN in.",
"ifItWasYou": "Als jij dit was, voor dan onderstaande PIN in.",
"codeExpiry": "De code verloopt op {date}, op {time} UTC, dat is over {expiresInMinutes}.",
"pin": "PIN",
"name": "Wachtwoordreset",
"ifItWasYouLink": "Als jij dit was, klik dan op onderstaande link."
"name": "Wachtwoordreset"
},
"userDeleted": {
"title": "Je account is verwijderd - Jellyfin",

View File

@ -26,8 +26,7 @@
"ifItWasYou": "Se foi você, insira o PIN abaixo.",
"codeExpiry": "O código irá expirar em {date}, ás {time}, que está em {expiresInMinutes}.",
"pin": "PIN",
"name": "Redefinir senha",
"ifItWasYouLink": "Se foi você, clique no link abaixo."
"name": "Redefinir senha"
},
"userDeleted": {
"title": "Sua conta foi excluída - Jellyfin",

View File

@ -13,11 +13,11 @@
"reEnterPasswordInvalid": "Passwörter stimmen nicht überein.",
"createAccountButton": "Konto erstellen",
"passwordRequirementsHeader": "Passwortanforderungen",
"successHeader": "Erfolgreich!",
"successHeader": "Erfolg!",
"successContinueButton": "Weiter",
"confirmationRequired": "E-Mail-Bestätigung erforderlich",
"confirmationRequiredMessage": "Bitte überprüfe dein Posteingang und bestätige deine E-Mail-Adresse.",
"yourAccountIsValidUntil": "Dein Konto wird bis zum {date} gültig sein."
"yourAccountIsValidUntil": "Dein Konto wird bis am {date} gültig sein."
},
"validationStrings": {
"length": {

View File

@ -31,9 +31,9 @@
"language": {
"title": "Sprache",
"description": "Gemeinschaftsübersetzungen sind für die meisten Teile von jfa-go verfügbar. Du kannst unten die Standardsprachen auswählen, aber Benutzer können dies immer noch ändern, wenn sie wollen. Wenn du helfen willst zu übersetzen, melde dich bei {n} an, um anzufangen, etwas beizutragen!",
"defaultAdminLang": "Admin Standardsprache",
"defaultFormLang": "Kontoerstellung Standardsprache",
"defaultEmailLang": "E-Mail Standardsprache"
"defaultAdminLang": "Standardsprache Admin",
"defaultFormLang": "Standardsprache Kontoerstellung",
"defaultEmailLang": "Standardsprache E-Mail"
},
"general": {
"title": "Allgemein",

42
main.go
View File

@ -489,47 +489,31 @@ func start(asDaemon, firstCall bool) {
}
if noHyphens == app.jf.Hyphens {
var newEmails map[string]interface{}
var newUsers map[string]time.Time
var status, status2 int
var err, err2 error
var status int
var err error
if app.jf.Hyphens {
app.info.Println(info("Your build of Jellyfin appears to hypenate user IDs. Your emails.json/users.json file will be modified to match."))
app.info.Println(info("Your build of Jellyfin appears to hypenate user IDs. Your emails.json file will be modified to match."))
time.Sleep(time.Second * time.Duration(3))
newEmails, status, err = app.hyphenateEmailStorage(app.storage.emails)
newUsers, status2, err2 = app.hyphenateUserStorage(app.storage.users)
} else {
app.info.Println(info("Your emails.json/users.json file uses hyphens, but the Jellyfin server no longer does. It will be modified."))
app.info.Println(info("Your emails.json file uses hyphens, but the Jellyfin server no longer does. It will be modified."))
time.Sleep(time.Second * time.Duration(3))
newEmails, status, err = app.deHyphenateEmailStorage(app.storage.emails)
newUsers, status2, err2 = app.deHyphenateUserStorage(app.storage.users)
}
if status != 200 || err != nil {
app.err.Printf("Failed to get users from Jellyfin (%d): %v", status, err)
app.err.Printf("Failed to get users from Jellyfin: Code %d", status)
app.debug.Printf("Error: %s", err)
app.err.Fatalf("Couldn't upgrade emails.json")
}
if status2 != 200 || err2 != nil {
app.err.Printf("Failed to get users from Jellyfin (%d): %v", status, err)
app.err.Fatalf("Couldn't upgrade users.json")
}
emailBakFile := app.storage.emails_path + ".bak"
usersBakFile := app.storage.users_path + ".bak"
err = storeJSON(emailBakFile, app.storage.emails)
err2 = storeJSON(usersBakFile, app.storage.users)
bakFile := app.storage.emails_path + ".bak"
err = storeJSON(bakFile, app.storage.emails)
if err != nil {
app.err.Fatalf("couldn't store emails.json backup: %v", err)
}
if err2 != nil {
app.err.Fatalf("couldn't store users.json backup: %v", err)
app.err.Fatalf("couldn't store emails.json backup: %s", err)
}
app.storage.emails = newEmails
app.storage.users = newUsers
err = app.storage.storeEmails()
err2 = app.storage.storeUsers()
if err != nil {
app.err.Fatalf("couldn't store emails.json: %v", err)
}
if err2 != nil {
app.err.Fatalf("couldn't store users.json: %v", err)
app.err.Fatalf("couldn't store emails.json: %s", err)
}
}
}
@ -576,13 +560,11 @@ func start(asDaemon, firstCall bool) {
os.Exit(0)
}
invDaemon := newInviteDaemon(time.Duration(60*time.Second), app)
go invDaemon.run()
defer invDaemon.shutdown()
inviteDaemon := newInviteDaemon(time.Duration(60*time.Second), app)
go inviteDaemon.run()
userDaemon := newUserDaemon(time.Duration(60*time.Second), app)
go userDaemon.run()
defer userDaemon.shutdown()
if app.config.Section("password_resets").Key("enabled").MustBool(false) && serverType == mediabrowser.JellyfinServer {
go app.StartPWR()

View File

@ -80,9 +80,9 @@ type inviteDTO struct {
UserDays int `json:"user-days,omitempty" example:"1"` // Number of days till user expiry
UserHours int `json:"user-hours,omitempty" example:"2"` // Number of hours till user expiry
UserMinutes int `json:"user-minutes,omitempty" example:"3"` // Number of minutes till user expiry
Created int64 `json:"created" example:"1617737207510"` // Date of creation
Created string `json:"created" example:"01/01/20 12:00"` // Date of creation
Profile string `json:"profile" example:"DefaultProfile"` // Profile used on this invite
UsedBy map[string]int64 `json:"used-by,omitempty"` // Users who have used this invite mapped to their creation time in Epoch/Unix time
UsedBy [][]string `json:"used-by,omitempty"` // Users who have used this invite
NoLimit bool `json:"no-limit,omitempty"` // If true, invite can be used any number of times
RemainingUses int `json:"remaining-uses,omitempty"` // Remaining number of uses (if applicable)
Email string `json:"email,omitempty"` // Email the invite was sent to (if applicable)
@ -112,9 +112,9 @@ type respUser struct {
ID string `json:"id" example:"fdgsdfg45534fa"` // userID of user
Name string `json:"name" example:"jeff"` // Username of user
Email string `json:"email,omitempty" example:"jeff@jellyf.in"` // Email address of user (if available)
LastActive int64 `json:"last_active" example:"1617737207510"` // Time of last activity on Jellyfin
LastActive string `json:"last_active"` // Time of last activity on Jellyfin
Admin bool `json:"admin" example:"false"` // Whether or not the user is Administrator
Expiry int64 `json:"expiry" example:"1617737207510"` // Expiry time of user as Epoch/Unix time.
Expiry string `json:"expiry" example:"01/02/21 12:00"` // Expiry time of user, if applicable.
Disabled bool `json:"disabled"` // Whether or not the user is disabled.
}

View File

@ -68,7 +68,6 @@ type Invite struct {
UserHours int `json:"user-hours,omitempty"`
UserMinutes int `json:"user-minutes,omitempty"`
Email string `json:"email"`
// Used to be stored as formatted time, now as Unix.
UsedBy [][]string `json:"used-by"`
Notify map[string]map[string]bool `json:"notify"`
Profile string `json:"profile"`
@ -481,11 +480,11 @@ func (st *Storage) storeInvites() error {
}
func (st *Storage) loadUsers() error {
st.usersLock.Lock()
defer st.usersLock.Unlock()
if st.users == nil {
st.users = map[string]time.Time{}
}
st.usersLock.Lock()
defer st.usersLock.Unlock()
temp := map[string]time.Time{}
err := loadJSON(st.users_path, &temp)
if err != nil {
@ -639,7 +638,7 @@ func hyphenate(userID string) string {
return userID[:8] + "-" + userID[8:12] + "-" + userID[12:16] + "-" + userID[16:20] + "-" + userID[20:]
}
func (app *appContext) deHyphenateStorage(old map[string]interface{}) (map[string]interface{}, int, error) {
func (app *appContext) deHyphenateEmailStorage(old map[string]interface{}) (map[string]interface{}, int, error) {
jfUsers, status, err := app.jf.GetUsers(false)
if status != 200 || err != nil {
return nil, status, err
@ -648,15 +647,15 @@ func (app *appContext) deHyphenateStorage(old map[string]interface{}) (map[strin
for _, user := range jfUsers {
unHyphenated := user.ID
hyphenated := hyphenate(unHyphenated)
val, ok := old[hyphenated]
email, ok := old[hyphenated]
if ok {
newEmails[unHyphenated] = val
newEmails[unHyphenated] = email
}
}
return newEmails, status, err
}
func (app *appContext) hyphenateStorage(old map[string]interface{}) (map[string]interface{}, int, error) {
func (app *appContext) hyphenateEmailStorage(old map[string]interface{}) (map[string]interface{}, int, error) {
jfUsers, status, err := app.jf.GetUsers(false)
if status != 200 || err != nil {
return nil, status, err
@ -665,50 +664,10 @@ func (app *appContext) hyphenateStorage(old map[string]interface{}) (map[string]
for _, user := range jfUsers {
unstripped := user.ID
stripped := strings.ReplaceAll(unstripped, "-", "")
val, ok := old[stripped]
email, ok := old[stripped]
if ok {
newEmails[unstripped] = val
newEmails[unstripped] = email
}
}
return newEmails, status, err
}
func (app *appContext) hyphenateEmailStorage(old map[string]interface{}) (map[string]interface{}, int, error) {
return app.hyphenateStorage(old)
}
func (app *appContext) deHyphenateEmailStorage(old map[string]interface{}) (map[string]interface{}, int, error) {
return app.deHyphenateStorage(old)
}
func (app *appContext) hyphenateUserStorage(old map[string]time.Time) (map[string]time.Time, int, error) {
asInterface := map[string]interface{}{}
for k, v := range old {
asInterface[k] = v
}
fixed, status, err := app.hyphenateStorage(asInterface)
if err != nil {
return nil, status, err
}
out := map[string]time.Time{}
for k, v := range fixed {
out[k] = v.(time.Time)
}
return out, status, err
}
func (app *appContext) deHyphenateUserStorage(old map[string]time.Time) (map[string]time.Time, int, error) {
asInterface := map[string]interface{}{}
for k, v := range old {
asInterface[k] = v
}
fixed, status, err := app.deHyphenateStorage(asInterface)
if err != nil {
return nil, status, err
}
out := map[string]time.Time{}
for k, v := range fixed {
out[k] = v.(time.Time)
}
return out, status, err
}

View File

@ -1,13 +1,13 @@
import { _get, _post, _delete, toggleLoader, toDateString } from "../modules/common.js";
import { _get, _post, _delete, toggleLoader } from "../modules/common.js";
interface User {
id: string;
name: string;
email: string | undefined;
last_active: number;
last_active: string;
admin: boolean;
disabled: boolean;
expiry: number;
expiry: string;
}
class user implements User {
@ -20,9 +20,7 @@ class user implements User {
private _emailAddress: string;
private _emailEditButton: HTMLElement;
private _expiry: HTMLTableDataCellElement;
private _expiryUnix: number;
private _lastActive: HTMLTableDataCellElement;
private _lastActiveUnix: number;
id: string;
private _selected: boolean;
@ -69,25 +67,11 @@ class user implements User {
}
}
get expiry(): number { return this._expiryUnix; }
set expiry(unix: number) {
this._expiryUnix = unix;
if (unix == 0) {
this._expiry.textContent = "";
} else {
this._expiry.textContent = toDateString(new Date(unix*1000));
}
}
get expiry(): string { return this._expiry.textContent; }
set expiry(value: string) { this._expiry.textContent = value; }
get last_active(): number { return this._lastActiveUnix; }
set last_active(unix: number) {
this._lastActiveUnix = unix;
if (unix == 0) {
this._lastActive.textContent == "";
} else {
this._lastActive.textContent = toDateString(new Date(unix*1000));
}
}
get last_active(): string { return this._lastActive.textContent; }
set last_active(value: string) { this._lastActive.textContent = value; }
private _checkEvent = new CustomEvent("accountCheckEvent");
private _uncheckEvent = new CustomEvent("accountUncheckEvent");

View File

@ -6,13 +6,6 @@ export function createEl(html: string): HTMLElement {
return div.firstElementChild as HTMLElement;
}
export function toDateString(date: Date): string {
return date.toLocaleDateString() + " " + date.toLocaleString([], {
hour: "2-digit",
minute: "2-digit"
})
}
export function serializeForm(id: string): Object {
const form = document.getElementById(id) as HTMLFormElement;
let formData = {};

View File

@ -1,4 +1,4 @@
import { _get, _post, _delete, toClipboard, toggleLoader, toDateString } from "../modules/common.js";
import { _get, _post, _delete, toClipboard, toggleLoader } from "../modules/common.js";
export class DOMInvite implements Invite {
updateNotify = (checkbox: HTMLInputElement) => {
@ -116,9 +116,10 @@ export class DOMInvite implements Invite {
tooltip.textContent = address;
}
private _usedBy: { [name: string]: number };
get usedBy(): { [name: string]: number } { return this._usedBy; }
set usedBy(uB: { [name: string]: number }) {
private _usedBy: string[][];
get usedBy(): string[][] { return this._usedBy; }
set usedBy(uB: string[][]) {
// ub[i][0]: username, ub[i][1]: date
this._usedBy = uB;
if (uB.length == 0) {
this._right.classList.add("empty");
@ -136,11 +137,11 @@ export class DOMInvite implements Invite {
</thead>
<tbody>
`;
for (let username in uB) {
for (let user of uB) {
innerHTML += `
<tr>
<td>${username}</td>
<td>${toDateString(new Date(uB[username] * 1000))}</td>
<td>${user[0]}</td>
<td>${user[1]}</td>
</tr>
`;
}
@ -151,16 +152,11 @@ export class DOMInvite implements Invite {
this._userTable.innerHTML = innerHTML;
}
private _createdUnix: number;
get created(): number { return this._createdUnix; }
set created(unix: number) {
this._createdUnix = unix;
const el = this._middle.querySelector("strong.inv-created");
if (unix == 0) {
el.textContent = "n/a";
} else {
el.textContent = toDateString(new Date(unix*1000));
}
private _created: string;
get created(): string { return this._created; }
set created(created: string) {
this._created = created;
this._middle.querySelector("strong.inv-created").textContent = created;
}
private _notifyExpiry: boolean = false;

View File

@ -1,4 +1,4 @@
import { _get, _post, toggleLoader, toDateString } from "../modules/common.js";
import { _get, _post, toggleLoader } from "../modules/common.js";
import { Marked, Renderer } from "@ts-stack/markdown";
interface updateDTO {
@ -29,7 +29,7 @@ export class Updater implements updater {
get date(): number { return Math.floor(this._date.getTime() / 1000); }
set date(unix: number) {
this._date = new Date(unix * 1000);
document.getElementById("update-date").textContent = toDateString(this._date);
document.getElementById("update-date").textContent = this._date.toDateString() + " " + this._date.toLocaleTimeString();
}
get description(): string { return this._update.description; }

View File

@ -104,8 +104,8 @@ interface Invite {
expiresIn?: string;
remainingUses?: string;
email?: string;
usedBy?: { [name: string]: number };
created?: number;
usedBy?: string[][];
created?: string;
notifyExpiry?: boolean;
notifyCreation?: boolean;
profile?: string;

View File

@ -35,6 +35,7 @@ func (rt *userDaemon) run() {
break
}
started := time.Now()
rt.app.storage.loadInvites()
rt.app.checkUsers()
finished := time.Now()
duration := finished.Sub(started)
@ -42,13 +43,6 @@ func (rt *userDaemon) run() {
}
}
func (rt *userDaemon) shutdown() {
rt.Stopped = true
rt.ShutdownChannel <- "Down"
<-rt.ShutdownChannel
close(rt.ShutdownChannel)
}
func (app *appContext) checkUsers() {
if err := app.storage.loadUsers(); err != nil {
app.err.Printf("Failed to load user expiries: %v", err)
@ -82,8 +76,12 @@ func (app *appContext) checkUsers() {
}
for id, expiry := range app.storage.users {
if _, ok := userExists[id]; !ok {
app.info.Printf("Deleting expiry for non-existent user \"%s\"", id)
app.debug.Printf("Deleting expiry for non-existent user \"%s\"", id)
delete(app.storage.users, id)
err = app.storage.storeUsers()
if err != nil {
app.err.Printf("Failed to store user duration: %s", err)
}
} else if time.Now().After(expiry) {
found := false
var user mediabrowser.User
@ -113,7 +111,10 @@ func (app *appContext) checkUsers() {
continue
}
delete(app.storage.users, id)
app.jf.CacheExpiry = time.Now()
err = app.storage.storeUsers()
if err != nil {
app.err.Printf("Failed to store user duration: %s", err)
}
if email {
address, ok := app.storage.emails[id]
if !ok {
@ -130,8 +131,4 @@ func (app *appContext) checkUsers() {
}
}
}
err = app.storage.storeUsers()
if err != nil {
app.err.Printf("Failed to store user expiries: %s", err)
}
}