mirror of
https://github.com/hrfee/jfa-go.git
synced 2026-01-18 16:47:42 +01:00
ivnites: use actual inviteDTO for DOMInvite
no intermediary parsing step. Also, moved the date -> duration (3mo6d3h sorta thing) to the web, there's now a ValidTill field with a unix timestamp. Used the new Temporal api with a polyfill. Bumped api version (although it still isn't semver).
This commit is contained in:
@@ -359,21 +359,22 @@ func (app *appContext) GetInviteUsedCount(gc *gin.Context) {
|
||||
// @Security Bearer
|
||||
// @tags Invites,Statistics
|
||||
func (app *appContext) GetInvites(gc *gin.Context) {
|
||||
currentTime := time.Now()
|
||||
// currentTime := time.Now()
|
||||
app.checkInvites()
|
||||
var invites []inviteDTO
|
||||
for _, inv := range app.storage.GetInvites() {
|
||||
if inv.IsReferral {
|
||||
continue
|
||||
}
|
||||
years, months, days, hours, minutes, _ := timeDiff(inv.ValidTill, currentTime)
|
||||
months += years * 12
|
||||
// years, months, days, hours, minutes, _ := timeDiff(inv.ValidTill, currentTime)
|
||||
// months += years * 12
|
||||
invite := inviteDTO{
|
||||
Code: inv.Code,
|
||||
Months: months,
|
||||
Days: days,
|
||||
Hours: hours,
|
||||
Minutes: minutes,
|
||||
Code: inv.Code,
|
||||
ValidTill: inv.ValidTill.Unix(),
|
||||
// Months: months,
|
||||
// Days: days,
|
||||
// Hours: hours,
|
||||
// Minutes: minutes,
|
||||
UserExpiry: inv.UserExpiry,
|
||||
UserMonths: inv.UserMonths,
|
||||
UserDays: inv.UserDays,
|
||||
|
||||
@@ -180,7 +180,7 @@ func TestInvite(t *testing.T) {
|
||||
Created: time.Now(),
|
||||
ValidTill: time.Now().Add(30 * time.Minute),
|
||||
}
|
||||
msg, err := e.constructInvite(inv, false)
|
||||
msg, err := e.constructInvite(&inv, false)
|
||||
if err != nil {
|
||||
t.Fatalf("failed construct: %+v", err)
|
||||
}
|
||||
|
||||
2
main.go
2
main.go
@@ -715,7 +715,7 @@ func flagPassed(name string) (found bool) {
|
||||
}
|
||||
|
||||
// @title jfa-go internal API
|
||||
// @version 0.6.0
|
||||
// @version 0.6.1
|
||||
// @description API for the jfa-go frontend
|
||||
// @contact.name Harvey Tindall
|
||||
// @contact.email hrfee@hrfee.dev
|
||||
|
||||
25
models.go
25
models.go
@@ -116,25 +116,22 @@ type newProfileDTO struct {
|
||||
|
||||
type inviteDTO struct {
|
||||
Code string `json:"code" example:"sajdlj23423j23"` // Invite code
|
||||
Months int `json:"months" example:"1"` // Number of months till expiry
|
||||
Days int `json:"days" example:"1"` // Number of days till expiry
|
||||
Hours int `json:"hours" example:"2"` // Number of hours 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
|
||||
UserMonths int `json:"user-months,omitempty" example:"1"` // Number of months 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
|
||||
UserMinutes int `json:"user-minutes,omitempty" example:"3"` // Number of minutes till user expiry
|
||||
ValidTill int64 `json:"valid_till" example:"1617737207510"` // Unix timestamp of expiry
|
||||
UserExpiry bool `json:"user_expiry"` // Whether or not user expiry is enabled
|
||||
UserMonths int `json:"user_months,omitempty" example:"1"` // Number of months 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
|
||||
UserMinutes int `json:"user_minutes,omitempty" example:"3"` // Number of minutes till user expiry
|
||||
Created int64 `json:"created" example:"1617737207510"` // 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
|
||||
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)
|
||||
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"` // If true, invite can be used any number of times
|
||||
RemainingUses int `json:"remaining_uses,omitempty"` // Remaining number of uses (if applicable)
|
||||
SendTo string `json:"send_to,omitempty"` // DEPRECATED Email/Discord username the invite was sent to (if applicable)
|
||||
SentTo SentToList `json:"sent_to,omitempty"` // Email/Discord usernames attempts were made to send this invite to, and a failure reason if failed.
|
||||
|
||||
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
|
||||
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
|
||||
Label string `json:"label,omitempty" example:"For Friends"` // Optional label for the invite
|
||||
UserLabel string `json:"user_label,omitempty" example:"Friend"` // Label to apply to users created w/ this invite.
|
||||
}
|
||||
|
||||
16
package-lock.json
generated
16
package-lock.json
generated
@@ -30,6 +30,7 @@
|
||||
"remixicon": "^4.3.0",
|
||||
"remove-markdown": "^0.5.0",
|
||||
"tailwindcss": "^3.3.2",
|
||||
"temporal-polyfill": "^0.3.0",
|
||||
"typescript": "^5.1.3",
|
||||
"uncss": "^0.17.3"
|
||||
},
|
||||
@@ -6755,6 +6756,21 @@
|
||||
"node": ">=8.0"
|
||||
}
|
||||
},
|
||||
"node_modules/temporal-polyfill": {
|
||||
"version": "0.3.0",
|
||||
"resolved": "https://registry.npmjs.org/temporal-polyfill/-/temporal-polyfill-0.3.0.tgz",
|
||||
"integrity": "sha512-qNsTkX9K8hi+FHDfHmf22e/OGuXmfBm9RqNismxBrnSmZVJKegQ+HYYXT+R7Ha8F/YSm2Y34vmzD4cxMu2u95g==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"temporal-spec": "0.3.0"
|
||||
}
|
||||
},
|
||||
"node_modules/temporal-spec": {
|
||||
"version": "0.3.0",
|
||||
"resolved": "https://registry.npmjs.org/temporal-spec/-/temporal-spec-0.3.0.tgz",
|
||||
"integrity": "sha512-n+noVpIqz4hYgFSMOSiINNOUOMFtV5cZQNCmmszA6GiVFVRt3G7AqVyhXjhCSmowvQn+NsGn+jMDMKJYHd3bSQ==",
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/terser": {
|
||||
"version": "5.43.1",
|
||||
"resolved": "https://registry.npmjs.org/terser/-/terser-5.43.1.tgz",
|
||||
|
||||
@@ -38,6 +38,7 @@
|
||||
"remixicon": "^4.3.0",
|
||||
"remove-markdown": "^0.5.0",
|
||||
"tailwindcss": "^3.3.2",
|
||||
"temporal-polyfill": "^0.3.0",
|
||||
"typescript": "^5.1.3",
|
||||
"uncss": "^0.17.3"
|
||||
},
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
declare var window: GlobalWindow;
|
||||
import dateParser from "any-date-parser";
|
||||
import { Temporal } from 'temporal-polyfill';
|
||||
|
||||
export function toDateString(date: Date): string {
|
||||
const locale = window.language || (window as any).navigator.userLanguage || window.navigator.language;
|
||||
@@ -41,6 +42,36 @@ export const parseDateString = (value: string): ParsedDate => {
|
||||
return out;
|
||||
}
|
||||
|
||||
// DateCountdown sets the given el's textContent to the time till the given date (unixSeconds), updating
|
||||
// every minute. It returns the timeout, so it can be later removed with clearTimeout if desired.
|
||||
export function DateCountdown(el: HTMLElement, unixSeconds: number): ReturnType<typeof setTimeout> {
|
||||
let then = Temporal.Instant.fromEpochMilliseconds(unixSeconds * 1000);
|
||||
const toString = (): string => {
|
||||
let out = "";
|
||||
let now = Temporal.Now.instant();
|
||||
let nowPlain = Temporal.Now.plainDateTimeISO();
|
||||
let diff = now.until(then).round({
|
||||
largestUnit: "years",
|
||||
smallestUnit: "minutes",
|
||||
relativeTo: nowPlain
|
||||
});
|
||||
// FIXME: I'd really like this to be localized, but don't know of any nice solutions.
|
||||
const fields = [diff.years, diff.months, diff.days, diff.hours, diff.minutes];
|
||||
const abbrevs = ["y", "mo", "d", "h", "m"];
|
||||
for (let i = 0; i < fields.length; i++) {
|
||||
if (fields[i]) {
|
||||
out += ""+fields[i] + abbrevs[i] + " ";
|
||||
}
|
||||
}
|
||||
return out.slice(0, -1);
|
||||
};
|
||||
const update = () => {
|
||||
el.textContent = toString();
|
||||
};
|
||||
update();
|
||||
return setTimeout(update, 60000);
|
||||
}
|
||||
|
||||
export const _get = (url: string, data: Object, onreadystatechange: (req: XMLHttpRequest) => void, noConnectionError: boolean = false): void => {
|
||||
let req = new XMLHttpRequest();
|
||||
if (window.pages) { url = window.pages.Base + url; }
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
import { _get, _post, _delete, toClipboard, toggleLoader, toDateString, SetupCopyButton, addLoader, removeLoader } from "../modules/common.js";
|
||||
import { _get, _post, _delete, toClipboard, toggleLoader, toDateString, SetupCopyButton, addLoader, removeLoader, DateCountdown } from "../modules/common.js";
|
||||
import { DiscordSearch, DiscordUser, newDiscordSearch } from "../modules/discord.js";
|
||||
import { reloadProfileNames } from "../modules/profiles.js";
|
||||
|
||||
declare var window: GlobalWindow;
|
||||
|
||||
const INF = "∞";
|
||||
|
||||
export const generateCodeLink = (code: string): string => {
|
||||
// let codeLink = window.pages.Base + window.pages.Form + "/" + code;
|
||||
let codeLink = window.pages.ExternalURI + window.pages.Form + "/" + code;
|
||||
@@ -15,11 +17,11 @@ class DOMInvite implements Invite {
|
||||
let state: { [code: string]: { [type: string]: boolean } } = {};
|
||||
let revertChanges: () => void;
|
||||
if (checkbox.classList.contains("inv-notify-expiry")) {
|
||||
revertChanges = () => { this.notifyExpiry = !this.notifyExpiry };
|
||||
state[this.code] = { "notify-expiry": this.notifyExpiry };
|
||||
revertChanges = () => { this.notify_expiry = !this.notify_expiry };
|
||||
state[this.code] = { "notify-expiry": this.notify_expiry };
|
||||
} else {
|
||||
revertChanges = () => { this.notifyCreation = !this.notifyCreation };
|
||||
state[this.code] = { "notify-creation": this.notifyCreation };
|
||||
revertChanges = () => { this.notify_creation = !this.notify_creation };
|
||||
state[this.code] = { "notify-creation": this.notify_creation };
|
||||
}
|
||||
_post("/invites/notify", state, (req: XMLHttpRequest) => {
|
||||
if (req.readyState == 4 && !(req.status == 200 || req.status == 204)) {
|
||||
@@ -78,44 +80,92 @@ class DOMInvite implements Invite {
|
||||
}
|
||||
private _codeLink: string;
|
||||
|
||||
private _expiresIn: string;
|
||||
get expiresIn(): string { return this._expiresIn }
|
||||
set expiresIn(expiry: string) {
|
||||
this._expiresIn = expiry;
|
||||
this._codeArea.querySelector("span.inv-duration").textContent = expiry;
|
||||
private _validTill: number;
|
||||
private _validTillUpdater: ReturnType<typeof setTimeout> = null;
|
||||
get valid_till(): number { return this._validTill; }
|
||||
set valid_till(v: number) {
|
||||
this._validTill = v;
|
||||
if (this._validTillUpdater) clearTimeout(this._validTillUpdater);
|
||||
this._validTillUpdater = DateCountdown(this._codeArea.querySelector("span.inv-duration"), v);
|
||||
}
|
||||
|
||||
private _userExpiry: string;
|
||||
get userExpiryTime(): string { return this._userExpiry; }
|
||||
set userExpiryTime(d: string) {
|
||||
private _userExpiryEnabled: boolean;
|
||||
get user_expiry(): boolean { return this._userExpiryEnabled; }
|
||||
set user_expiry(v: boolean) { this._userExpiryEnabled = v; }
|
||||
private _userExpiry = { months: 0, days: 0, hours: 0, minutes: 0 };
|
||||
private _userExpiryString: string;
|
||||
get user_months(): number { return this._userExpiry.months; }
|
||||
get user_days(): number { return this._userExpiry.days; }
|
||||
get user_hours(): number { return this._userExpiry.hours; }
|
||||
get user_minutes(): number { return this._userExpiry.minutes; }
|
||||
set user_months(v: number) {
|
||||
this._userExpiry.months = v;
|
||||
this._updateUserExpiry();
|
||||
}
|
||||
set user_days(v: number) {
|
||||
this._userExpiry.days = v;
|
||||
this._updateUserExpiry();
|
||||
}
|
||||
set user_hours(v: number) {
|
||||
this._userExpiry.hours = v;
|
||||
this._updateUserExpiry();
|
||||
}
|
||||
set user_minutes(v: number) {
|
||||
this._userExpiry.minutes = v;
|
||||
this._updateUserExpiry();
|
||||
}
|
||||
set user_expiry_time(v: { months: number, days: number, hours: number, minutes: number }) {
|
||||
this._userExpiry = v;
|
||||
this._updateUserExpiry()
|
||||
}
|
||||
private _updateUserExpiry() {
|
||||
const expiry = this._middle.querySelector("span.user-expiry") as HTMLSpanElement;
|
||||
if (!d) {
|
||||
this._userExpiryString = "";
|
||||
if (!(this._userExpiry.months || this._userExpiry.days || this._userExpiry.hours || this._userExpiry.minutes)) {
|
||||
expiry.textContent = "";
|
||||
expiry.parentElement.classList.add("unfocused");
|
||||
} else {
|
||||
expiry.textContent = window.lang.strings("userExpiry");
|
||||
expiry.parentElement.classList.remove("unfocused");
|
||||
const fields = ["months", "days", "hours", "minutes"].map((v) => this._userExpiry[v]);
|
||||
const abbrevs = ["mo", "d", "h", "m"];
|
||||
for (let i = 0; i < fields.length; i++) {
|
||||
if (fields[i]) {
|
||||
this._userExpiryString += ""+fields[i] + abbrevs[i] + " ";
|
||||
}
|
||||
}
|
||||
this._userExpiryString = this._userExpiryString.slice(0, -1);
|
||||
}
|
||||
this._userExpiry = d;
|
||||
this._middle.querySelector("strong.user-expiry-time").textContent = d;
|
||||
this._middle.querySelector("strong.user-expiry-time").textContent = this._userExpiryString;
|
||||
}
|
||||
|
||||
private _remainingUses: string = "1";
|
||||
get remainingUses(): string { return this._remainingUses; }
|
||||
set remainingUses(remaining: string) {
|
||||
this._remainingUses = remaining;
|
||||
this._middle.querySelector("strong.inv-remaining").textContent = remaining;
|
||||
private _noLimit: boolean = false;
|
||||
get no_limit(): boolean { return this._noLimit; }
|
||||
set no_limit(v: boolean) {
|
||||
this._noLimit = v;
|
||||
const remaining = this._middle.querySelector("strong.inv-remaining") as HTMLElement;
|
||||
if (!this.no_limit) remaining.textContent = ""+this._remainingUses;
|
||||
else remaining.textContent = INF;
|
||||
}
|
||||
|
||||
private _remainingUses: number = 1;
|
||||
get remaining_uses(): number { return this._remainingUses; }
|
||||
set remaining_uses(v: number) {
|
||||
this._remainingUses = v;
|
||||
const remaining = this._middle.querySelector("strong.inv-remaining") as HTMLElement;
|
||||
if (!this.no_limit) remaining.textContent = ""+this._remainingUses;
|
||||
else remaining.textContent = INF;
|
||||
}
|
||||
|
||||
private _send_to: string = "";
|
||||
get send_to(): string { return this._send_to };
|
||||
set send_to(address: string) {
|
||||
set send_to(address: string | null) {
|
||||
this._send_to = address;
|
||||
const container = this._infoArea.querySelector(".tooltip") as HTMLDivElement;
|
||||
const icon = container.querySelector("i");
|
||||
const chip = container.querySelector("span.inv-email-chip");
|
||||
const tooltip = container.querySelector("span.content") as HTMLSpanElement;
|
||||
if (address == "") {
|
||||
if (!address) {
|
||||
icon.classList.remove("ri-mail-line");
|
||||
icon.classList.remove("ri-mail-close-line");
|
||||
chip.classList.remove("~neutral");
|
||||
@@ -177,10 +227,10 @@ class DOMInvite implements Invite {
|
||||
}
|
||||
|
||||
private _usedBy: { [name: string]: number };
|
||||
get usedBy(): { [name: string]: number } { return this._usedBy; }
|
||||
set usedBy(uB: { [name: string]: number }) {
|
||||
get used_by(): { [name: string]: number } { return this._usedBy; }
|
||||
set used_by(uB: { [name: string]: number } | null) {
|
||||
this._usedBy = uB;
|
||||
if (Object.keys(uB).length == 0) {
|
||||
if (!uB || Object.keys(uB).length == 0) {
|
||||
this._right.classList.add("empty");
|
||||
this._userTable.innerHTML = `<p class="content">${window.lang.strings("inviteNoUsersCreated")}</p>`;
|
||||
return;
|
||||
@@ -226,15 +276,15 @@ class DOMInvite implements Invite {
|
||||
}
|
||||
|
||||
private _notifyExpiry: boolean = false;
|
||||
get notifyExpiry(): boolean { return this._notifyExpiry }
|
||||
set notifyExpiry(state: boolean) {
|
||||
get notify_expiry(): boolean { return this._notifyExpiry }
|
||||
set notify_expiry(state: boolean) {
|
||||
this._notifyExpiry = state;
|
||||
(this._left.querySelector("input.inv-notify-expiry") as HTMLInputElement).checked = state;
|
||||
}
|
||||
|
||||
private _notifyCreation: boolean = false;
|
||||
get notifyCreation(): boolean { return this._notifyCreation }
|
||||
set notifyCreation(state: boolean) {
|
||||
get notify_creation(): boolean { return this._notifyCreation }
|
||||
set notify_creation(state: boolean) {
|
||||
this._notifyCreation = state;
|
||||
(this._left.querySelector("input.inv-notify-creation") as HTMLInputElement).checked = state;
|
||||
}
|
||||
@@ -366,7 +416,7 @@ class DOMInvite implements Invite {
|
||||
<a class="invite-link text-black dark:text-white font-mono bg-inherit truncate" href=""></a>
|
||||
<button class="invite-copy-button"></button>
|
||||
</div>
|
||||
<span class="inv-duration"></span>
|
||||
<span>${window.lang.var("strings", "inviteExpiresInTime", "<span class=\"inv-duration\"></span>")}</span>
|
||||
`;
|
||||
const copyButton = this._codeArea.getElementsByClassName("invite-copy-button")[0] as HTMLButtonElement;
|
||||
SetupCopyButton(copyButton, this._codeLink);
|
||||
@@ -476,30 +526,39 @@ class DOMInvite implements Invite {
|
||||
document.addEventListener("profileLoadEvent", () => { this.loadProfiles(); }, false);
|
||||
document.addEventListener("timefmt-change", () => {
|
||||
this.created = this.created;
|
||||
this.usedBy = this.usedBy;
|
||||
this.used_by = this.used_by;
|
||||
});
|
||||
}
|
||||
|
||||
update = (invite: Invite) => {
|
||||
this.code = invite.code;
|
||||
this.valid_till = invite.valid_till;
|
||||
if (invite.user_expiry) {
|
||||
this.user_expiry = invite.user_expiry;
|
||||
this.user_expiry_time = {
|
||||
months: invite.user_months,
|
||||
days: invite.user_days,
|
||||
hours: invite.user_hours,
|
||||
minutes: invite.user_minutes
|
||||
};
|
||||
}
|
||||
this.created = invite.created;
|
||||
this.profile = invite.profile;
|
||||
this.used_by = invite.used_by;
|
||||
this.no_limit = invite.no_limit ? invite.no_limit : false;
|
||||
this.remaining_uses = invite.remaining_uses;
|
||||
this.send_to = invite.send_to;
|
||||
this.sent_to = invite.sent_to;
|
||||
this.expiresIn = invite.expiresIn;
|
||||
if (window.notificationsEnabled) {
|
||||
this.notifyCreation = invite.notifyCreation;
|
||||
this.notifyExpiry = invite.notifyExpiry;
|
||||
this.notify_creation = invite.notify_creation;
|
||||
this.notify_expiry = invite.notify_expiry;
|
||||
}
|
||||
this.profile = invite.profile;
|
||||
this.remainingUses = invite.remainingUses;
|
||||
this.usedBy = invite.usedBy;
|
||||
if (invite.label) {
|
||||
this.label = invite.label;
|
||||
}
|
||||
if (invite.user_label) {
|
||||
this.user_label = invite.user_label;
|
||||
}
|
||||
this.userExpiryTime = invite.userExpiryTime || "";
|
||||
this._sendToDialog = new SendToDialog(this._middle.getElementsByClassName("invite-send-to-dialog")[0] as HTMLElement, invite, () => {
|
||||
const needsUpdatingEvent = new CustomEvent("inviteNeedsUpdating", { detail: this.code });
|
||||
document.dispatchEvent(needsUpdatingEvent);
|
||||
@@ -605,8 +664,7 @@ export class DOMInviteList implements InviteList {
|
||||
// at end delete all remaining in list from dom
|
||||
let invitesOnDOM: { [code: string]: boolean } = {};
|
||||
for (let code in this.invites) { invitesOnDOM[code] = true; }
|
||||
for (let inv of (data["invites"] as Array<any>)) {
|
||||
const invite = parseInvite(inv);
|
||||
for (let invite of (data["invites"] as Array<Invite>)) {
|
||||
if (invite.code in this.invites) {
|
||||
this.invites[invite.code].update(invite);
|
||||
delete invitesOnDOM[invite.code];
|
||||
@@ -626,47 +684,6 @@ export class DOMInviteList implements InviteList {
|
||||
|
||||
export const inviteURLEvent = (id: string) => { return new CustomEvent(DOMInviteList._inviteURLEvent, {"detail": id}) };
|
||||
|
||||
// FIXME: Please, i beg you, get rid of this horror!
|
||||
function parseInvite(invite: { [f: string]: string | number | { [name: string]: number } | boolean | SentToList }): Invite {
|
||||
let parsed: Invite = {};
|
||||
parsed.code = invite["code"] as string;
|
||||
parsed.send_to = invite["send_to"] as string || "";
|
||||
parsed.sent_to = invite["sent_to"] as SentToList || null;
|
||||
parsed.label = invite["label"] as string || "";
|
||||
parsed.user_label = invite["user_label"] as string || "";
|
||||
let time = "";
|
||||
let userExpiryTime = "";
|
||||
const fields = ["months", "days", "hours", "minutes"];
|
||||
let prefixes = [""];
|
||||
if (invite["user-expiry"] as boolean) { prefixes.push("user-"); }
|
||||
for (let i = 0; i < fields.length; i++) {
|
||||
for (let j = 0; j < prefixes.length; j++) {
|
||||
if (invite[prefixes[j]+fields[i]]) {
|
||||
let abbreviation = fields[i][0];
|
||||
if (fields[i] == "months") {
|
||||
abbreviation += fields[i][1];
|
||||
}
|
||||
let text = `${invite[prefixes[j]+fields[i]]}${abbreviation} `;
|
||||
if (prefixes[j] == "user-") {
|
||||
userExpiryTime += text;
|
||||
} else {
|
||||
time += text;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
parsed.expiresIn = window.lang.var("strings", "inviteExpiresInTime", time.slice(0, -1));
|
||||
parsed.userExpiry = invite["user-expiry"] as boolean;
|
||||
parsed.userExpiryTime = userExpiryTime.slice(0, -1);
|
||||
parsed.remainingUses = invite["no-limit"] ? "∞" : String(invite["remaining-uses"])
|
||||
parsed.usedBy = invite["used-by"] as { [name: string]: number } || {} ;
|
||||
parsed.created = invite["created"] as number || 0;
|
||||
parsed.profile = invite["profile"] as string || "";
|
||||
parsed.notifyExpiry = invite["notify-expiry"] as boolean || false;
|
||||
parsed.notifyCreation = invite["notify-creation"] as boolean || false;
|
||||
return parsed;
|
||||
}
|
||||
|
||||
export class createInvite {
|
||||
private _sendTo: SendToDialog;
|
||||
private _userExpiryToggle = document.getElementById("create-user-expiry-enabled") as HTMLInputElement;
|
||||
|
||||
@@ -71,20 +71,25 @@ declare interface InviteList {
|
||||
}
|
||||
|
||||
declare interface Invite {
|
||||
code?: string;
|
||||
expiresIn?: string;
|
||||
remainingUses?: string;
|
||||
send_to?: string; // DEPRECATED: use sent_to instead.
|
||||
sent_to?: SentToList;
|
||||
usedBy?: { [name: string]: number };
|
||||
created?: number;
|
||||
notifyExpiry?: boolean;
|
||||
notifyCreation?: boolean;
|
||||
profile?: string;
|
||||
label?: string;
|
||||
user_label?: string;
|
||||
userExpiry?: boolean;
|
||||
userExpiryTime?: string;
|
||||
code: string; // Invite code
|
||||
valid_till: number; // Unix timestamp of expiry
|
||||
user_expiry: boolean; // Whether or not user expiry is enabled
|
||||
user_months?: number; // Number of months till user expiry
|
||||
user_days?: number; // Number of days till user expiry
|
||||
user_hours?: number; // Number of hours till user expiry
|
||||
user_minutes?: number; // Number of minutes till user expiry
|
||||
created: number; // Date of creation (unix timestamp)
|
||||
profile: string; // Profile used on this invite
|
||||
used_by?: { [user: string]: number }; // Users who have used this invite mapped to their creation time in Epoch/Unix time
|
||||
no_limit: boolean; // If true, invite can be used any number of times
|
||||
remaining_uses?: number; // Remaining number of uses (if applicable)
|
||||
send_to?: string; // DEPRECATED Email/Discord username the invite was sent to (if applicable)
|
||||
sent_to?: SentToList; // Email/Discord usernames attempts were made to send this invite to, and a failure reason if failed.
|
||||
|
||||
notify_expiry?: boolean; // Whether to notify the requesting user of expiry or not
|
||||
notify_creation?: boolean; // Whether to notify the requesting user of account creation or not
|
||||
label?: string; // Optional label for the invite
|
||||
user_label?: string; // Label to apply to users created w/ this invite.
|
||||
}
|
||||
|
||||
declare interface SendFailure {
|
||||
|
||||
Reference in New Issue
Block a user