diff --git a/api-userpage.go b/api-userpage.go
index dbfd0d5..c771b73 100644
--- a/api-userpage.go
+++ b/api-userpage.go
@@ -207,7 +207,7 @@ func (app *appContext) confirmMyAction(gc *gin.Context, key string) {
// @Failure 500 {object} stringResponse
// @Router /my/email [post]
// @Security Bearer
-// @tags Users
+// @tags User Page
func (app *appContext) ModifyMyEmail(gc *gin.Context) {
var req ModifyMyEmailDTO
gc.BindJSON(&req)
@@ -258,3 +258,79 @@ func (app *appContext) ModifyMyEmail(gc *gin.Context) {
app.confirmMyAction(gc, key)
return
}
+
+// @Summary Returns a 10-minute, one-use Discord server invite
+// @Produce json
+// @Success 200 {object} DiscordInviteDTO
+// @Failure 400 {object} boolResponse
+// @Failure 401 {object} boolResponse
+// @Failure 500 {object} boolResponse
+// @Param invCode path string true "invite Code"
+// @Router /my/discord/invite [get]
+// @tags User Page
+func (app *appContext) MyDiscordServerInvite(gc *gin.Context) {
+ if app.discord.inviteChannelName == "" {
+ respondBool(400, false, gc)
+ return
+ }
+ invURL, iconURL := app.discord.NewTempInvite(10*60, 1)
+ if invURL == "" {
+ respondBool(500, false, gc)
+ return
+ }
+ gc.JSON(200, DiscordInviteDTO{invURL, iconURL})
+}
+
+// @Summary Returns a linking PIN for discord/telegram
+// @Produce json
+// @Success 200 {object} GetMyPINDTO
+// @Failure 400 {object} stringResponse
+// Param service path string true "discord/telegram"
+// @Router /my/pin/{service} [get]
+// @tags User Page
+func (app *appContext) GetMyPIN(gc *gin.Context) {
+ service := gc.Param("service")
+ resp := GetMyPINDTO{}
+ switch service {
+ case "discord":
+ resp.PIN = app.discord.NewAuthToken()
+ break
+ case "telegram":
+ resp.PIN = app.telegram.NewAuthToken()
+ break
+ default:
+ respond(400, "invalid service", gc)
+ return
+ }
+ gc.JSON(200, resp)
+}
+
+// @Summary Returns true/false on whether or not your discord PIN was verified, and assigns the discord user to you.
+// @Produce json
+// @Success 200 {object} boolResponse
+// @Failure 401 {object} boolResponse
+// @Param pin path string true "PIN code to check"
+// @Router /my/discord/verified/{pin} [get]
+// @tags User Page
+func (app *appContext) MyDiscordVerifiedInvite(gc *gin.Context) {
+ pin := gc.Param("pin")
+ dcUser, ok := app.discord.verifiedTokens[pin]
+ if !ok {
+ respondBool(200, false, gc)
+ return
+ }
+ if app.config.Section("discord").Key("require_unique").MustBool(false) {
+ for _, u := range app.storage.discord {
+ if app.discord.verifiedTokens[pin].ID == u.ID {
+ delete(app.discord.verifiedTokens, pin)
+ respondBool(400, false, gc)
+ return
+ }
+ }
+ }
+ dc := app.storage.discord
+ dc[gc.GetString("jfId")] = dcUser
+ app.storage.discord = dc
+ app.storage.storeDiscordUsers()
+ respondBool(200, true, gc)
+}
diff --git a/html/user.html b/html/user.html
index 39789cd..3e61003 100644
--- a/html/user.html
+++ b/html/user.html
@@ -4,14 +4,22 @@
{{ template "header.html" . }}
{{ .lang.Strings.pageTitle }}
@@ -33,6 +41,47 @@
+
+
+
{{ .strings.linkDiscord }}
+
{{ .discordSendPINMessage }}
+
+
+
{{ .strings.success }}
+
+
+
+
+
+
{{ .strings.linkMatrix }}
+
{{ .strings.matrixEnterUser }}
+
+
+
+
+
+
+
+ {{ .matrixUser }}
+
+
{{ .strings.submit }}
+
+
diff --git a/lang/form/en-us.json b/lang/form/en-us.json
index 43b2928..715d0d3 100644
--- a/lang/form/en-us.json
+++ b/lang/form/en-us.json
@@ -60,4 +60,4 @@
"plural": "Must have at least {n} special characters"
}
}
-}
\ No newline at end of file
+}
diff --git a/models.go b/models.go
index 084d010..9f3aef9 100644
--- a/models.go
+++ b/models.go
@@ -402,3 +402,7 @@ const (
UserEmailChange ConfirmationTarget = iota
NoOp
)
+
+type GetMyPINDTO struct {
+ PIN string `json:"pin"`
+}
diff --git a/router.go b/router.go
index 27e2281..80bec1a 100644
--- a/router.go
+++ b/router.go
@@ -231,6 +231,9 @@ func (app *appContext) loadRoutes(router *gin.Engine) {
user.POST(p+"/contact", app.SetMyContactMethods)
user.POST(p+"/logout", app.LogoutUser)
user.POST(p+"/email", app.ModifyMyEmail)
+ user.GET(p+"/discord/invite", app.MyDiscordServerInvite)
+ user.GET(p+"/pin/:service", app.GetMyPIN)
+ user.GET(p+"/discord/verified/:pin", app.MyDiscordVerifiedInvite)
}
}
}
diff --git a/ts/form.ts b/ts/form.ts
index 31cdf0d..b3dbc25 100644
--- a/ts/form.ts
+++ b/ts/form.ts
@@ -1,6 +1,6 @@
import { Modal } from "./modules/modal.js";
import { notificationBox, whichAnimationEvent } from "./modules/common.js";
-import { _get, _post, toggleLoader, addLoader, removeLoader, toDateString } from "./modules/common.js";
+import { _get, _post, toggleLoader, addLoader, removeLoader, toDateString, DiscordInvite } from "./modules/common.js";
import { loadLangSelector } from "./modules/lang.js";
import { initValidator } from "./modules/validator.js";
@@ -91,11 +91,6 @@ if (window.telegramEnabled) {
};
}
-interface DiscordInvite {
- invite: string;
- icon: string;
-}
-
var discordVerified = false;
if (window.discordEnabled) {
window.discordModal = new Modal(document.getElementById("modal-discord"), window.discordRequired);
diff --git a/ts/modules/common.ts b/ts/modules/common.ts
index 4687cc8..6ae320d 100644
--- a/ts/modules/common.ts
+++ b/ts/modules/common.ts
@@ -221,3 +221,8 @@ export function insertText(textarea: HTMLTextAreaElement, text: string) {
textarea.focus();
}
}
+
+export interface DiscordInvite {
+ invite: string;
+ icon: string;
+}
diff --git a/ts/user.ts b/ts/user.ts
index a611c15..ac34517 100644
--- a/ts/user.ts
+++ b/ts/user.ts
@@ -1,12 +1,20 @@
import { ThemeManager } from "./modules/theme.js";
import { lang, LangFile, loadLangSelector } from "./modules/lang.js";
import { Modal } from "./modules/modal.js";
-import { _get, _post, notificationBox, whichAnimationEvent, toDateString, toggleLoader } from "./modules/common.js";
+import { _get, _post, notificationBox, whichAnimationEvent, toDateString, toggleLoader, DiscordInvite } from "./modules/common.js";
import { Login } from "./modules/login.js";
interface userWindow extends Window {
jellyfinID: string;
username: string;
+ emailRequired: boolean;
+ discordRequired: boolean;
+ telegramRequired: boolean;
+ matrixRequired: boolean;
+ discordServerName: string;
+ discordInviteLink: boolean;
+ matrixUserID: string;
+ discordSendPINMessage: string;
}
declare var window: userWindow;
@@ -26,6 +34,9 @@ window.modals = {} as Modals;
(() => {
window.modals.login = new Modal(document.getElementById("modal-login"), true);
window.modals.email = new Modal(document.getElementById("modal-email"), false);
+ window.modals.discord = new Modal(document.getElementById("modal-discord"), false);
+ window.modals.telegram = new Modal(document.getElementById("modal-telegram"), false);
+ window.modals.matrix = new Modal(document.getElementById("modal-matrix"), false);
})();
window.notifications = new notificationBox(document.getElementById('notification-box') as HTMLDivElement, 5);
@@ -87,8 +98,8 @@ class ContactMethods {
${(details.value == "") ? window.lang.strings("notSet") : details.value}
-