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 {
-
${window.lang.strings("contactThrough")}
+
${window.lang.strings("contactThrough")}
-
+
Email
-
+
Telegram
-
+
Discord
-
+
Matrix
+
+
+ Telegram
+
+
+ Discord
+
+
+ Matrix
+
@@ -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; }