add option to set new expiry for when re-enabling users

for this reddit comment: https://www.reddit.com/r/jellyfin/comments/nc6tsi/tip_jfago_is_awesome/hgh0yet/?context=3
This commit is contained in:
Harvey Tindall 2021-10-18 20:39:23 +01:00
parent 4d27f7fc7a
commit 0bf8cd65cd
Signed by: hrfee
GPG Key ID: BBC65952848FB1A2
5 changed files with 88 additions and 17 deletions

5
api.go
View File

@ -758,7 +758,7 @@ func (app *appContext) DeleteUsers(gc *gin.Context) {
respondBool(200, true, gc)
}
// @Summary Extend time before the user(s) expiry.
// @Summary Extend time before the user(s) expiry, or create and expiry if it doesn't exist.
// @Produce json
// @Param extendExpiryDTO body extendExpiryDTO true "Extend expiry object"
// @Success 200 {object} boolResponse
@ -780,6 +780,9 @@ func (app *appContext) ExtendExpiry(gc *gin.Context) {
if expiry, ok := app.storage.users[id]; ok {
app.storage.users[id] = expiry.AddDate(0, req.Months, req.Days).Add(time.Duration(((60 * req.Hours) + req.Minutes)) * time.Minute)
app.debug.Printf("Expiry extended for \"%s\"", id)
} else {
app.storage.users[id] = time.Now().AddDate(0, req.Months, req.Days).Add(time.Duration(((60 * req.Hours) + req.Minutes)) * time.Minute)
app.debug.Printf("Created expiry for \"%s\"", id)
}
}
if err := app.storage.storeUsers(); err != nil {

5
go.sum
View File

@ -20,6 +20,7 @@ github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792/go.mod h1:ghJtE
github.com/btcsuite/winsvc v1.0.0/go.mod h1:jsenWakMcC0zFBFurPLEAyrnc/teJEM1O46fmI40EZs=
github.com/bwmarrin/discordgo v0.23.2 h1:BzrtTktixGHIu9Tt7dEE6diysEF9HWnXeHuoJEt2fH4=
github.com/bwmarrin/discordgo v0.23.2/go.mod h1:c1WtWUGN6nREDmzIpyTp/iD3VYt4Fpx+bVyfBG7JE+M=
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d h1:U+s90UTSYgptZMwQh2aRr3LuazLJIa+Pg3Kc1ylSYVY=
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/davecgh/go-spew v0.0.0-20171005155431-ecdeabc65495/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
@ -58,6 +59,7 @@ github.com/getlantern/ops v0.0.0-20200403153110-8476b16edcd6 h1:QthAQCekS1YOeYWS
github.com/getlantern/ops v0.0.0-20200403153110-8476b16edcd6/go.mod h1:D5ao98qkA6pxftxoqzibIBBrLSUli+kYnJqrgBf9cIA=
github.com/getlantern/systray v1.1.0 h1:U0wCEqseLi2ok1fE6b88gJklzriavPJixZysZPkZd/Y=
github.com/getlantern/systray v1.1.0/go.mod h1:AecygODWIsBquJCJFop8MEQcJbWFfw/1yWbVabNgpCM=
github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk=
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
github.com/gin-contrib/gzip v0.0.1 h1:ezvKOL6jH+jlzdHNE4h9h8q8uMpDQjyl0NN0Jd7jozc=
github.com/gin-contrib/gzip v0.0.1/go.mod h1:fGBJBCdt6qCZuCAOwWuFhBB4OOq9EFqlo5dEaFhhu5w=
@ -216,6 +218,7 @@ github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTE
github.com/rogpeppe/go-internal v1.8.0 h1:FCbCCtXNOY3UtUuHUYaghJg4y7Fd14rXifAYUAtL9R8=
github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE=
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
@ -263,8 +266,10 @@ github.com/ugorji/go/codec v1.1.5-pre/go.mod h1:tULtS6Gy1AE1yCENaw4Vb//HLH5njI2t
github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY=
github.com/ugorji/go/codec v1.2.6 h1:7kbGefxLoDBuYXOms4yD7223OpNMMPNPZxXk5TvFcyQ=
github.com/ugorji/go/codec v1.2.6/go.mod h1:V6TCNZ4PHqoHGFZuSG1W8nrCzzdgA2DozYxWFFpvxTw=
github.com/urfave/cli v1.20.0 h1:fDqGv3UG/4jbVl/QkFwEdddtEDjh/5Ov6X+0B/3bPaw=
github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
github.com/urfave/cli/v2 v2.1.1/go.mod h1:SE9GqnLQmjVa0iPEY0f1w3ygNIYcIJ0OKPMoW2caLfQ=
github.com/urfave/cli/v2 v2.3.0 h1:qph92Y649prgesehzOrQjdWyxFOp/QVM+6imKHad91M=
github.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI=
github.com/writeas/go-strip-markdown v2.0.1+incompatible h1:IIqxTM5Jr7RzhigcL6FkrCNfXkvbR+Nbu1ls48pXYcw=
github.com/writeas/go-strip-markdown v2.0.1+incompatible/go.mod h1:Rsyu10ZhbEK9pXdk8V6MVnZmTzRG0alMNLMwa0J01fE=

View File

@ -152,6 +152,11 @@
</div>
</div>
</div>
<label class="switch mb-1">
<input type="checkbox" id="expiry-extend-enable" checked>
<span>{{ .strings.sendDeleteNotificationEmail }}</span>
</label>
<textarea id="textarea-extend-enable" class="textarea full-width ~neutral !normal mb-1" placeholder="{{ .strings.sendDeleteNotificationExample }}"></textarea>
<label>
<input type="submit" class="unfocused">
<span class="button ~critical !normal full-width center supra submit">{{ .strings.submit }}</span>
@ -574,7 +579,14 @@
</div>
<span class="col sm button ~urge !normal center mb-half" id="accounts-modify-user">{{ .strings.modifySettings }}</span>
<span class="col sm button ~warning !normal center mb-half" id="accounts-extend-expiry">{{ .strings.extendExpiry }}</span>
<span class="col sm button ~positive !normal center mb-half" id="accounts-disable-enable">{{ .strings.disable }}</span>
<div id="accounts-disable-enable-dropdown" class="col sm dropdown manual" tabindex="0">
<span class="h-100 sm button ~positive !normal center mb-half" id="accounts-disable-enable">{{ .strings.disable }}</span>
<div class="dropdown-display">
<div class="card ~neutral !low">
<span class="button ~neutral sm full-width accounts-announce-template-button" id="accounts-enable-expiry">{{ .strings.setExpiry }}</span>
</div>
</div>
</div>
<span class="col sm button ~info !normal center mb-half" id="accounts-send-pwr">{{ .strings.sendPWR }}</span>
<span class="col sm button ~critical !normal center mb-half" id="accounts-delete-user">{{ .quantityStrings.deleteUser.Singular }}</span>
</div>

View File

@ -27,6 +27,7 @@
"enabled": "Enabled",
"disabled": "Disabled",
"reEnable": "Re-enable",
"setExpiry": "Set expiry",
"disable": "Disable",
"admin": "Admin",
"updates": "Updates",

View File

@ -560,9 +560,12 @@ export class accountsList {
private _announceTextarea = document.getElementById("textarea-announce") as HTMLTextAreaElement;
private _deleteUser = document.getElementById("accounts-delete-user") as HTMLSpanElement;
private _disableEnable = document.getElementById("accounts-disable-enable") as HTMLSpanElement;
private _enableExpiry = document.getElementById("accounts-enable-expiry") as HTMLSpanElement;
private _deleteNotify = document.getElementById("delete-user-notify") as HTMLInputElement;
private _deleteReason = document.getElementById("textarea-delete-user") as HTMLTextAreaElement;
private _extendExpiry = document.getElementById("accounts-extend-expiry") as HTMLSpanElement;
private _enableExpiryNotify = document.getElementById("expiry-extend-enable") as HTMLInputElement;
private _enableExpiryReason = document.getElementById("textarea-extend-enable") as HTMLTextAreaElement;
private _modifySettings = document.getElementById("accounts-modify-user") as HTMLSpanElement;
private _modifySettingsProfile = document.getElementById("radio-use-profile") as HTMLInputElement;
private _modifySettingsUser = document.getElementById("radio-use-user") as HTMLInputElement;
@ -751,10 +754,12 @@ export class accountsList {
if (showDisableEnable) {
let message: string;
if (this._shouldEnable) {
this._disableEnable.parentElement.classList.remove("manual");
message = window.lang.strings("reEnable");
this._disableEnable.classList.add("~positive");
this._disableEnable.classList.remove("~warning");
} else {
this._disableEnable.parentElement.classList.add("manual");
message = window.lang.strings("disable");
this._disableEnable.classList.add("~warning");
this._disableEnable.classList.remove("~positive");
@ -964,6 +969,17 @@ export class accountsList {
}
}
});
private _enableDisableUsers = (users: string[], enable: boolean, notify: boolean, reason: string|null, post: (req: XMLHttpRequest) => void) => {
let send = {
"users": users,
"enabled": enable,
"notify": notify
};
if (reason) send["reason"] = reason;
_post("/users/enable", send, post, true);
};
enableDisableUsers = () => {
// We can share the delete modal for this
const modalHeader = document.getElementById("header-delete-user");
@ -987,13 +1003,7 @@ export class accountsList {
form.onsubmit = (event: Event) => {
event.preventDefault();
toggleLoader(button);
let send = {
"users": list,
"enabled": this._shouldEnable,
"notify": this._deleteNotify.checked,
"reason": this._deleteNotify ? this._deleteReason.value : ""
};
_post("/users/enable", send, (req: XMLHttpRequest) => {
this._enableDisableUsers(list, this._shouldEnable, this._deleteNotify.checked, this._deleteNotify ? this._deleteReason.value : null, (req: XMLHttpRequest) => {
if (req.readyState == 4) {
toggleLoader(button);
window.modals.deleteUser.close();
@ -1010,7 +1020,7 @@ export class accountsList {
}
this.reload();
}
}, true);
});
}
window.modals.deleteUser.show();
}
@ -1176,18 +1186,27 @@ export class accountsList {
window.modals.modifyUser.show();
}
extendExpiry = () => {
extendExpiry = (enableUser?: boolean) => {
const list = this._collectUsers();
let applyList: string[] = [];
for (let id of list) {
if (this._users[id].expiry) {
if (this._users[id].expiry || enableUser) {
applyList.push(id);
}
}
document.getElementById("header-extend-expiry").textContent = window.lang.quantity("extendExpiry", applyList.length);
const form = document.getElementById("form-extend-expiry") as HTMLFormElement;
form.onsubmit = (event: Event) => {
event.preventDefault();
this._enableExpiryReason.classList.add("unfocused");
let header: string;
if (enableUser) {
header = window.lang.quantity("reEnableUsers", list.length);
this._enableExpiryNotify.parentElement.classList.remove("unfocused");
this._enableExpiryNotify.checked = false;
this._enableExpiryReason.value = "";
} else {
header = window.lang.quantity("extendExpiry", applyList.length);
this._enableExpiryNotify.parentElement.classList.add("unfocused");
}
document.getElementById("header-extend-expiry").textContent = header;
const extend = () => {
let send = { "users": applyList }
for (let field of ["months", "days", "hours", "minutes"]) {
send[field] = +(document.getElementById("extend-expiry-"+field) as HTMLSelectElement).value;
@ -1203,6 +1222,28 @@ export class accountsList {
this.reload();
}
});
};
const form = document.getElementById("form-extend-expiry") as HTMLFormElement;
form.onsubmit = (event: Event) => {
event.preventDefault();
if (enableUser) {
this._enableDisableUsers(applyList, true, this._enableExpiryNotify.checked, this._enableExpiryNotify ? this._enableExpiryReason.value : null, (req: XMLHttpRequest) => {
if (req.readyState == 4) {
if (req.status != 200 && req.status != 204) {
window.modals.extendExpiry.close();
let errorMsg = window.lang.notif("errorFailureCheckLogs");
if (!("error" in req.response)) {
errorMsg = window.lang.notif("errorPartialFailureCheckLogs");
}
window.notifications.customError("deleteUserError", errorMsg);
return;
}
extend();
}
});
} else {
extend();
}
}
window.modals.extendExpiry.show();
}
@ -1257,12 +1298,21 @@ export class accountsList {
this._announceButton.onclick = this.announce;
this._announceButton.classList.add("unfocused");
this._extendExpiry.onclick = this.extendExpiry;
this._extendExpiry.onclick = () => { this.extendExpiry(); };
this._extendExpiry.classList.add("unfocused");
this._disableEnable.onclick = this.enableDisableUsers;
this._disableEnable.classList.add("unfocused");
this._enableExpiry.onclick = () => { this.extendExpiry(true); };
this._enableExpiryNotify.onchange = () => {
if (this._enableExpiryNotify.checked) {
this._enableExpiryReason.classList.remove("unfocused");
} else {
this._enableExpiryReason.classList.add("unfocused");
}
};
if (!window.usernameEnabled) {
this._addUserName.classList.add("unfocused");
this._addUserName = this._addUserEmail;