diff --git a/api-messages.go b/api-messages.go index e571803..a5031bd 100644 --- a/api-messages.go +++ b/api-messages.go @@ -724,3 +724,60 @@ func (app *appContext) DiscordConnect(gc *gin.Context) { linkExistingOmbiDiscordTelegram(app) respondBool(200, true, gc) } + +// @Summary unlink a Discord account from a Jellyfin user. Always succeeds. +// @Produce json +// @Success 200 {object} boolResponse +// @Param forUserDTO body forUserDTO true "User's Jellyfin ID." +// @Router /users/discord [delete] +// @Tags Users +func (app *appContext) UnlinkDiscord(gc *gin.Context) { + var req forUserDTO + gc.BindJSON(&req) + /* user, status, err := app.jf.UserByID(req.ID, false) + if req.ID == "" || status != 200 || err != nil { + respond(400, "User not found", gc) + return + } */ + delete(app.storage.discord, req.ID) + app.storage.storeDiscordUsers() + respondBool(200, true, gc) +} + +// @Summary unlink a Telegram account from a Jellyfin user. Always succeeds. +// @Produce json +// @Success 200 {object} boolResponse +// @Param forUserDTO body forUserDTO true "User's Jellyfin ID." +// @Router /users/telegram [delete] +// @Tags Users +func (app *appContext) UnlinkTelegram(gc *gin.Context) { + var req forUserDTO + gc.BindJSON(&req) + /* user, status, err := app.jf.UserByID(req.ID, false) + if req.ID == "" || status != 200 || err != nil { + respond(400, "User not found", gc) + return + } */ + delete(app.storage.telegram, req.ID) + app.storage.storeTelegramUsers() + respondBool(200, true, gc) +} + +// @Summary unlink a Matrix account from a Jellyfin user. Always succeeds. +// @Produce json +// @Success 200 {object} boolResponse +// @Param forUserDTO body forUserDTO true "User's Jellyfin ID." +// @Router /users/matrix [delete] +// @Tags Users +func (app *appContext) UnlinkMatrix(gc *gin.Context) { + var req forUserDTO + gc.BindJSON(&req) + /* user, status, err := app.jf.UserByID(req.ID, false) + if req.ID == "" || status != 200 || err != nil { + respond(400, "User not found", gc) + return + } */ + delete(app.storage.matrix, req.ID) + app.storage.storeMatrixUsers() + respondBool(200, true, gc) +} diff --git a/lang/admin/en-us.json b/lang/admin/en-us.json index a85c532..b2056b3 100644 --- a/lang/admin/en-us.json +++ b/lang/admin/en-us.json @@ -59,6 +59,7 @@ "reset": "Reset", "edit": "Edit", "donate": "Donate", + "unlink": "Unlink Account", "sendPWR": "Send Password Reset", "contactThrough": "Contact through:", "extendExpiry": "Extend expiry", diff --git a/models.go b/models.go index a27e8d7..db67cde 100644 --- a/models.go +++ b/models.go @@ -355,3 +355,7 @@ type setAccountsAdminDTO map[string]bool type genCaptchaDTO struct { ID string `json:"id"` } + +type forUserDTO struct { + ID string `json:"id"` // Jellyfin ID +} diff --git a/router.go b/router.go index e84cc2e..eae0637 100644 --- a/router.go +++ b/router.go @@ -192,6 +192,9 @@ func (app *appContext) loadRoutes(router *gin.Engine) { api.GET(p+"/telegram/pin", app.TelegramGetPin) api.GET(p+"/telegram/verified/:pin", app.TelegramVerified) api.POST(p+"/users/telegram", app.TelegramAddUser) + api.DELETE(p+"/users/telegram", app.UnlinkTelegram) + api.DELETE(p+"/users/discord", app.UnlinkDiscord) + api.DELETE(p+"/users/matrix", app.UnlinkMatrix) } if emailEnabled { api.POST(p+"/users/contact", app.SetContactMethods) diff --git a/ts/modules/accounts.ts b/ts/modules/accounts.ts index e13c11d..a076e46 100644 --- a/ts/modules/accounts.ts +++ b/ts/modules/accounts.ts @@ -81,6 +81,15 @@ class user implements User { if (email) return "email"; } + private _checkUnlinkArea = () => { + const unlinkHeader = this._notifyDropdown.querySelector(".accounts-unlink-header") as HTMLSpanElement; + if (this.lastNotifyMethod() == "email" || !this.lastNotifyMethod()) { + unlinkHeader.classList.add("unfocused"); + } else { + unlinkHeader.classList.remove("unfocused"); + } + } + get selected(): boolean { return this._selected; } set selected(state: boolean) { this._selected = state; @@ -164,31 +173,41 @@ class user implements User { @@ -200,6 +219,10 @@ class user implements User { for (let i = 0; i < checks.length; i++) { checks[i].onclick = () => this._setNotifyMethod(); } + + for (let service of ["telegram", "discord", "matrix"]) { + el.querySelector(".accounts-unlink-"+service).addEventListener("click", () => _delete(`/users/${service}`, {"id": this.id}, () => document.dispatchEvent(new CustomEvent("accounts-reload")))); + } button.onclick = () => { dropdown.classList.add("selected"); @@ -218,12 +241,14 @@ class user implements User { set matrix(u: string) { if (!window.matrixEnabled) { this._notifyDropdown.querySelector(".accounts-area-matrix").classList.add("unfocused"); + this._notifyDropdown.querySelector(".accounts-unlink-matrix").classList.add("unfocused"); return; } const lastNotifyMethod = this.lastNotifyMethod() == "matrix"; this._matrixID = u; if (!u) { this._notifyDropdown.querySelector(".accounts-area-matrix").classList.add("unfocused"); + this._notifyDropdown.querySelector(".accounts-unlink-matrix").classList.add("unfocused"); this._matrix.innerHTML = `
@@ -233,6 +258,7 @@ class user implements User { (this._matrix.querySelector("span") as HTMLSpanElement).onclick = this._addMatrix; } else { this._notifyDropdown.querySelector(".accounts-area-matrix").classList.remove("unfocused"); + this._notifyDropdown.querySelector(".accounts-unlink-matrix").classList.remove("unfocused"); this._matrix.innerHTML = `
${u} @@ -242,6 +268,7 @@ class user implements User { (this._matrix.querySelector(".table-inline") as HTMLDivElement).appendChild(this._notifyDropdown); } } + this._checkUnlinkArea(); } private _addMatrix = () => { @@ -290,16 +317,19 @@ class user implements User { set telegram(u: string) { if (!window.telegramEnabled) { this._notifyDropdown.querySelector(".accounts-area-telegram").classList.add("unfocused"); + this._notifyDropdown.querySelector(".accounts-unlink-telegram").classList.add("unfocused"); return; } const lastNotifyMethod = this.lastNotifyMethod() == "telegram"; this._telegramUsername = u; if (!u) { this._notifyDropdown.querySelector(".accounts-area-telegram").classList.add("unfocused"); + this._notifyDropdown.querySelector(".accounts-unlink-telegram").classList.add("unfocused"); this._telegram.innerHTML = `
`; (this._telegram.querySelector("span") as HTMLSpanElement).onclick = this._addTelegram; } else { this._notifyDropdown.querySelector(".accounts-area-telegram").classList.remove("unfocused"); + this._notifyDropdown.querySelector(".accounts-unlink-telegram").classList.remove("unfocused"); this._telegram.innerHTML = `
@${u} @@ -309,6 +339,7 @@ class user implements User { (this._telegram.querySelector(".table-inline") as HTMLDivElement).appendChild(this._notifyDropdown); } } + this._checkUnlinkArea(); } get notify_telegram(): boolean { return this._notifyTelegram; } @@ -356,6 +387,7 @@ class user implements User { set discord(u: string) { if (!window.discordEnabled) { this._notifyDropdown.querySelector(".accounts-area-discord").classList.add("unfocused"); + this._notifyDropdown.querySelector(".accounts-unlink-discord").classList.add("unfocused"); return; } const lastNotifyMethod = this.lastNotifyMethod() == "discord"; @@ -364,8 +396,10 @@ class user implements User { this._discord.innerHTML = `
`; (this._discord.querySelector("span") as HTMLSpanElement).onclick = () => addDiscord(this.id); this._notifyDropdown.querySelector(".accounts-area-discord").classList.add("unfocused"); + this._notifyDropdown.querySelector(".accounts-unlink-discord").classList.add("unfocused"); } else { this._notifyDropdown.querySelector(".accounts-area-discord").classList.remove("unfocused"); + this._notifyDropdown.querySelector(".accounts-unlink-discord").classList.remove("unfocused"); this._discord.innerHTML = `
${u} @@ -375,6 +409,7 @@ class user implements User { (this._discord.querySelector(".table-inline") as HTMLDivElement).appendChild(this._notifyDropdown); } } + this._checkUnlinkArea(); } get discord_id(): string { return this._discordID; }