mirror of
https://github.com/hrfee/jfa-go.git
synced 2024-12-22 09:00:10 +00:00
use unix timestamp for inv created & usedBy
usedBy is still stored as a string in invites.json to cope with existing invites with times stored formatted. knz/strtime requires cgo for strptime, so it has been replaced with the native itchyny/timefmt-go.
This commit is contained in:
parent
6ec2186bdf
commit
3f8414c70a
24
api.go
24
api.go
@ -11,7 +11,7 @@ import (
|
|||||||
"github.com/dgrijalva/jwt-go"
|
"github.com/dgrijalva/jwt-go"
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"github.com/hrfee/mediabrowser"
|
"github.com/hrfee/mediabrowser"
|
||||||
"github.com/knz/strtime"
|
"github.com/itchyny/timefmt-go"
|
||||||
"github.com/lithammer/shortuuid/v3"
|
"github.com/lithammer/shortuuid/v3"
|
||||||
"gopkg.in/ini.v1"
|
"gopkg.in/ini.v1"
|
||||||
)
|
)
|
||||||
@ -48,8 +48,8 @@ func (app *appContext) loadStrftime() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (app *appContext) prettyTime(dt time.Time) (date, time string) {
|
func (app *appContext) prettyTime(dt time.Time) (date, time string) {
|
||||||
date, _ = strtime.Strftime(dt, app.datePattern)
|
date = timefmt.Format(dt, app.datePattern)
|
||||||
time, _ = strtime.Strftime(dt, app.timePattern)
|
time = timefmt.Format(dt, app.timePattern)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -189,7 +189,7 @@ func (app *appContext) checkInvite(code string, used bool, username string) bool
|
|||||||
// 0 means infinite i guess?
|
// 0 means infinite i guess?
|
||||||
newInv.RemainingUses--
|
newInv.RemainingUses--
|
||||||
}
|
}
|
||||||
newInv.UsedBy = append(newInv.UsedBy, []string{username, app.formatDatetime(currentTime)})
|
newInv.UsedBy = append(newInv.UsedBy, []string{username, strconv.FormatInt(currentTime.Unix(), 10)})
|
||||||
if !del {
|
if !del {
|
||||||
app.storage.invites[code] = newInv
|
app.storage.invites[code] = newInv
|
||||||
}
|
}
|
||||||
@ -870,13 +870,25 @@ func (app *appContext) GetInvites(gc *gin.Context) {
|
|||||||
UserDays: inv.UserDays,
|
UserDays: inv.UserDays,
|
||||||
UserHours: inv.UserHours,
|
UserHours: inv.UserHours,
|
||||||
UserMinutes: inv.UserMinutes,
|
UserMinutes: inv.UserMinutes,
|
||||||
Created: app.formatDatetime(inv.Created),
|
Created: inv.Created.Unix(),
|
||||||
Profile: inv.Profile,
|
Profile: inv.Profile,
|
||||||
NoLimit: inv.NoLimit,
|
NoLimit: inv.NoLimit,
|
||||||
Label: inv.Label,
|
Label: inv.Label,
|
||||||
}
|
}
|
||||||
if len(inv.UsedBy) != 0 {
|
if len(inv.UsedBy) != 0 {
|
||||||
invite.UsedBy = inv.UsedBy
|
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.RemainingUses = 1
|
invite.RemainingUses = 1
|
||||||
if inv.RemainingUses != 0 {
|
if inv.RemainingUses != 0 {
|
||||||
|
6
email.go
6
email.go
@ -19,8 +19,8 @@ import (
|
|||||||
|
|
||||||
"github.com/gomarkdown/markdown"
|
"github.com/gomarkdown/markdown"
|
||||||
"github.com/gomarkdown/markdown/html"
|
"github.com/gomarkdown/markdown/html"
|
||||||
|
"github.com/itchyny/timefmt-go"
|
||||||
jEmail "github.com/jordan-wright/email"
|
jEmail "github.com/jordan-wright/email"
|
||||||
"github.com/knz/strtime"
|
|
||||||
"github.com/mailgun/mailgun-go/v4"
|
"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) {
|
func (emailer *Emailer) formatExpiry(expiry time.Time, tzaware bool, datePattern, timePattern string) (d, t, expiresIn string) {
|
||||||
d, _ = strtime.Strftime(expiry, datePattern)
|
d = timefmt.Format(expiry, datePattern)
|
||||||
t, _ = strtime.Strftime(expiry, timePattern)
|
t = timefmt.Format(expiry, timePattern)
|
||||||
currentTime := time.Now()
|
currentTime := time.Now()
|
||||||
if tzaware {
|
if tzaware {
|
||||||
currentTime = currentTime.UTC()
|
currentTime = currentTime.UTC()
|
||||||
|
2
go.mod
2
go.mod
@ -26,8 +26,8 @@ require (
|
|||||||
github.com/hrfee/jfa-go/docs v0.0.0-20201112212552-b6f3cd7c1f71
|
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/jfa-go/ombi v0.0.0-20201112212552-b6f3cd7c1f71
|
||||||
github.com/hrfee/mediabrowser v0.3.3
|
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/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/lithammer/shortuuid/v3 v3.0.4
|
||||||
github.com/mailgun/mailgun-go/v4 v4.3.0
|
github.com/mailgun/mailgun-go/v4 v4.3.0
|
||||||
github.com/mailru/easyjson v0.7.7 // indirect
|
github.com/mailru/easyjson v0.7.7 // indirect
|
||||||
|
4
go.sum
4
go.sum
@ -129,6 +129,8 @@ 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/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 h1:7E05uiol8hh2ytKn3WVLrUIvHAyifYEIy3Y5qtuNh8I=
|
||||||
github.com/hrfee/mediabrowser v0.3.3/go.mod h1:PnHZbdxmbv1wCVdAQyM7nwPwpVj9fdKx2EcET7sAk+U=
|
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 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/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=
|
github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
|
||||||
@ -141,8 +143,6 @@ 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/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 h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo=
|
||||||
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
|
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 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
|
||||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||||
|
34
models.go
34
models.go
@ -72,23 +72,23 @@ type newProfileDTO struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type inviteDTO struct {
|
type inviteDTO struct {
|
||||||
Code string `json:"code" example:"sajdlj23423j23"` // Invite code
|
Code string `json:"code" example:"sajdlj23423j23"` // Invite code
|
||||||
Days int `json:"days" example:"1"` // Number of days till expiry
|
Days int `json:"days" example:"1"` // Number of days till expiry
|
||||||
Hours int `json:"hours" example:"2"` // Number of hours till expiry
|
Hours int `json:"hours" example:"2"` // Number of hours till expiry
|
||||||
Minutes int `json:"minutes" example:"3"` // Number of minutes till expiry
|
Minutes int `json:"minutes" example:"3"` // Number of minutes till expiry
|
||||||
UserExpiry bool `json:"user-expiry"` // Whether or not user expiry is enabled
|
UserExpiry bool `json:"user-expiry"` // Whether or not user expiry is enabled
|
||||||
UserDays int `json:"user-days,omitempty" example:"1"` // Number of days till user expiry
|
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
|
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
|
UserMinutes int `json:"user-minutes,omitempty" example:"3"` // Number of minutes till user expiry
|
||||||
Created string `json:"created" example:"01/01/20 12:00"` // Date of creation
|
Created int64 `json:"created" example:"1617737207510"` // Date of creation
|
||||||
Profile string `json:"profile" example:"DefaultProfile"` // Profile used on this invite
|
Profile string `json:"profile" example:"DefaultProfile"` // Profile used on this invite
|
||||||
UsedBy [][]string `json:"used-by,omitempty"` // Users who have used 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
|
||||||
NoLimit bool `json:"no-limit,omitempty"` // If true, invite can be used any number of times
|
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)
|
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)
|
Email string `json:"email,omitempty"` // Email the invite was sent to (if applicable)
|
||||||
NotifyExpiry bool `json:"notify-expiry,omitempty"` // Whether to notify the requesting user of expiry or not
|
NotifyExpiry bool `json:"notify-expiry,omitempty"` // Whether to notify the requesting user of expiry or not
|
||||||
NotifyCreation bool `json:"notify-creation,omitempty"` // Whether to notify the requesting user of account creation or not
|
NotifyCreation bool `json:"notify-creation,omitempty"` // Whether to notify the requesting user of account creation or not
|
||||||
Label string `json:"label,omitempty" example:"For Friends"` // Optional label for the invite
|
Label string `json:"label,omitempty" example:"For Friends"` // Optional label for the invite
|
||||||
}
|
}
|
||||||
|
|
||||||
type getInvitesDTO struct {
|
type getInvitesDTO struct {
|
||||||
|
29
storage.go
29
storage.go
@ -59,20 +59,21 @@ type Profile struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type Invite struct {
|
type Invite struct {
|
||||||
Created time.Time `json:"created"`
|
Created time.Time `json:"created"`
|
||||||
NoLimit bool `json:"no-limit"`
|
NoLimit bool `json:"no-limit"`
|
||||||
RemainingUses int `json:"remaining-uses"`
|
RemainingUses int `json:"remaining-uses"`
|
||||||
ValidTill time.Time `json:"valid_till"`
|
ValidTill time.Time `json:"valid_till"`
|
||||||
UserExpiry bool `json:"user-duration"`
|
UserExpiry bool `json:"user-duration"`
|
||||||
UserDays int `json:"user-days,omitempty"`
|
UserDays int `json:"user-days,omitempty"`
|
||||||
UserHours int `json:"user-hours,omitempty"`
|
UserHours int `json:"user-hours,omitempty"`
|
||||||
UserMinutes int `json:"user-minutes,omitempty"`
|
UserMinutes int `json:"user-minutes,omitempty"`
|
||||||
Email string `json:"email"`
|
Email string `json:"email"`
|
||||||
UsedBy [][]string `json:"used-by"`
|
// Used to be stored as formatted time, now as Unix.
|
||||||
Notify map[string]map[string]bool `json:"notify"`
|
UsedBy [][]string `json:"used-by"`
|
||||||
Profile string `json:"profile"`
|
Notify map[string]map[string]bool `json:"notify"`
|
||||||
Label string `json:"label,omitempty"`
|
Profile string `json:"profile"`
|
||||||
Keys []string `json:"keys,omitempty"`
|
Label string `json:"label,omitempty"`
|
||||||
|
Keys []string `json:"keys,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type Lang struct {
|
type Lang struct {
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { _get, _post, _delete, toClipboard, toggleLoader } from "../modules/common.js";
|
import { _get, _post, _delete, toClipboard, toggleLoader, toDateString } from "../modules/common.js";
|
||||||
|
|
||||||
export class DOMInvite implements Invite {
|
export class DOMInvite implements Invite {
|
||||||
updateNotify = (checkbox: HTMLInputElement) => {
|
updateNotify = (checkbox: HTMLInputElement) => {
|
||||||
@ -116,10 +116,9 @@ export class DOMInvite implements Invite {
|
|||||||
tooltip.textContent = address;
|
tooltip.textContent = address;
|
||||||
}
|
}
|
||||||
|
|
||||||
private _usedBy: string[][];
|
private _usedBy: { [name: string]: number };
|
||||||
get usedBy(): string[][] { return this._usedBy; }
|
get usedBy(): { [name: string]: number } { return this._usedBy; }
|
||||||
set usedBy(uB: string[][]) {
|
set usedBy(uB: { [name: string]: number }) {
|
||||||
// ub[i][0]: username, ub[i][1]: date
|
|
||||||
this._usedBy = uB;
|
this._usedBy = uB;
|
||||||
if (uB.length == 0) {
|
if (uB.length == 0) {
|
||||||
this._right.classList.add("empty");
|
this._right.classList.add("empty");
|
||||||
@ -137,11 +136,11 @@ export class DOMInvite implements Invite {
|
|||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
`;
|
`;
|
||||||
for (let user of uB) {
|
for (let username in uB) {
|
||||||
innerHTML += `
|
innerHTML += `
|
||||||
<tr>
|
<tr>
|
||||||
<td>${user[0]}</td>
|
<td>${username}</td>
|
||||||
<td>${user[1]}</td>
|
<td>${toDateString(new Date(uB[username] * 1000))}</td>
|
||||||
</tr>
|
</tr>
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
@ -152,11 +151,16 @@ export class DOMInvite implements Invite {
|
|||||||
this._userTable.innerHTML = innerHTML;
|
this._userTable.innerHTML = innerHTML;
|
||||||
}
|
}
|
||||||
|
|
||||||
private _created: string;
|
private _createdUnix: number;
|
||||||
get created(): string { return this._created; }
|
get created(): number { return this._createdUnix; }
|
||||||
set created(created: string) {
|
set created(unix: number) {
|
||||||
this._created = created;
|
this._createdUnix = unix;
|
||||||
this._middle.querySelector("strong.inv-created").textContent = created;
|
const el = this._middle.querySelector("strong.inv-created");
|
||||||
|
if (unix == 0) {
|
||||||
|
el.textContent = "n/a";
|
||||||
|
} else {
|
||||||
|
el.textContent = toDateString(new Date(unix*1000));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private _notifyExpiry: boolean = false;
|
private _notifyExpiry: boolean = false;
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { _get, _post, toggleLoader } from "../modules/common.js";
|
import { _get, _post, toggleLoader, toDateString } from "../modules/common.js";
|
||||||
import { Marked, Renderer } from "@ts-stack/markdown";
|
import { Marked, Renderer } from "@ts-stack/markdown";
|
||||||
|
|
||||||
interface updateDTO {
|
interface updateDTO {
|
||||||
@ -29,7 +29,7 @@ export class Updater implements updater {
|
|||||||
get date(): number { return Math.floor(this._date.getTime() / 1000); }
|
get date(): number { return Math.floor(this._date.getTime() / 1000); }
|
||||||
set date(unix: number) {
|
set date(unix: number) {
|
||||||
this._date = new Date(unix * 1000);
|
this._date = new Date(unix * 1000);
|
||||||
document.getElementById("update-date").textContent = this._date.toDateString() + " " + this._date.toLocaleTimeString();
|
document.getElementById("update-date").textContent = toDateString(this._date);
|
||||||
}
|
}
|
||||||
|
|
||||||
get description(): string { return this._update.description; }
|
get description(): string { return this._update.description; }
|
||||||
|
@ -104,8 +104,8 @@ interface Invite {
|
|||||||
expiresIn?: string;
|
expiresIn?: string;
|
||||||
remainingUses?: string;
|
remainingUses?: string;
|
||||||
email?: string;
|
email?: string;
|
||||||
usedBy?: string[][];
|
usedBy?: { [name: string]: number };
|
||||||
created?: string;
|
created?: number;
|
||||||
notifyExpiry?: boolean;
|
notifyExpiry?: boolean;
|
||||||
notifyCreation?: boolean;
|
notifyCreation?: boolean;
|
||||||
profile?: string;
|
profile?: string;
|
||||||
|
Loading…
Reference in New Issue
Block a user