diff --git a/api.go b/api.go index bd471e2..380bf8d 100644 --- a/api.go +++ b/api.go @@ -180,6 +180,58 @@ type newUserReq struct { Code string `json:"code"` } +func (app *appContext) NewUserAdmin(gc *gin.Context) { + var req newUserReq + gc.BindJSON(&req) + existingUser, _, _ := app.jf.userByName(req.Username, false) + if existingUser != nil { + msg := fmt.Sprintf("User already exists named %s", req.Username) + app.info.Printf("%s New user failed: %s", req.Username, msg) + respond(401, msg, gc) + return + } + user, status, err := app.jf.newUser(req.Username, req.Password) + if !(status == 200 || status == 204) || err != nil { + app.err.Printf("%s New user failed: Jellyfin responded with %d", req.Username, status) + respond(401, "Unknown error", gc) + return + } + var id string + if user["Id"] != nil { + id = user["Id"].(string) + } + if len(app.storage.policy) != 0 { + status, err = app.jf.setPolicy(id, app.storage.policy) + if !(status == 200 || status == 204) { + app.err.Printf("%s: Failed to set user policy: Code %d", req.Username, status) + } + } + if len(app.storage.configuration) != 0 && len(app.storage.displayprefs) != 0 { + status, err = app.jf.setConfiguration(id, app.storage.configuration) + if (status == 200 || status == 204) && err == nil { + status, err = app.jf.setDisplayPreferences(id, app.storage.displayprefs) + } else { + app.err.Printf("%s: Failed to set configuration template: Code %d", req.Username, status) + } + } + if app.config.Section("password_resets").Key("enabled").MustBool(false) { + app.storage.emails[id] = req.Email + app.storage.storeEmails() + } + if app.config.Section("ombi").Key("enabled").MustBool(false) { + app.storage.loadOmbiTemplate() + if len(app.storage.ombi_template) != 0 { + errors, code, err := app.ombi.newUser(req.Username, req.Password, req.Email, app.storage.ombi_template) + if err != nil || code != 200 { + app.info.Printf("Failed to create Ombi user (%d): %s", code, err) + app.debug.Printf("Errors reported by Ombi: %s", strings.Join(errors, ", ")) + } else { + app.info.Println("Created Ombi user") + } + } + } +} + func (app *appContext) NewUser(gc *gin.Context) { var req newUserReq gc.BindJSON(&req) diff --git a/data/static/accounts.js b/data/static/accounts.js index 396a944..74d00a1 100644 --- a/data/static/accounts.js +++ b/data/static/accounts.js @@ -171,8 +171,6 @@ function changeEmail(icon, id) { icon.parentNode.appendChild(cross); } - - function populateUsers() { const acList = document.getElementById('accountsList'); acList.innerHTML = ` @@ -292,6 +290,74 @@ document.getElementById('defaultsSource').addEventListener('change', function() } }) +document.getElementById('newUserCreate').onclick = function() { + const ogText = this.textContent; + this.innerHTML = ` + Creating...`; + const email = document.getElementById('newUserEmail').value; + var username = email; + if (document.getElementById('newUserName') != null) { + username = document.getElementById('newUserName').value; + } + const password = document.getElementById('newUserPassword').value; + if (!validEmail(email) && email != "") { + return; + } + const send = { + 'username': username, + 'password': password, + 'email': email + } + let req = new XMLHttpRequest() + req.open("POST", "/newUserAdmin", true); + req.responseType = 'json'; + req.setRequestHeader("Authorization", "Basic " + btoa(window.token + ":")); + const button = this; + req.onreadystatechange = function() { + if (this.readyState == 4) { + button.textContent = ogText; + if (this.status == 200) { + if (button.classList.contains('btn-primary')) { + button.classList.remove('btn-primary'); + } + button.classList.add('btn-success'); + button.textContent = 'Success'; + setTimeout(function() { + if (button.classList.contains('btn-success')) { + button.classList.remove('btn-success'); + } + button.classList.add('btn-primary'); + button.textContent = ogText; + newUserModal.hide(); + }, 1000); + } else { + if (button.classList.contains('btn-primary')) { + button.classList.remove('btn-primary'); + } + button.classList.add('btn-danger'); + if ("error" in req.response) { + button.textContent = req.response["error"]; + } else { + button.textContent = 'Failed'; + } + setTimeout(function() { + if (button.classList.contains('btn-danger')) { + button.classList.remove('btn-danger'); + } + button.classList.add('btn-primary'); + button.textContent = ogText; + }, 2000); + } + } + }; + req.send(JSON.stringify(send)); +} - - +document.getElementById('accountsTabAddUser').onclick = function() { + document.getElementById('newUserEmail').value = ''; + document.getElementById('newUserPassword').value = ''; + if (document.getElementById('newUserName') != null) { + document.getElementById('newUserName').value = ''; + } + newUserModal.show(); +}; diff --git a/data/static/admin.js b/data/static/admin.js index 398b6d6..1152d54 100644 --- a/data/static/admin.js +++ b/data/static/admin.js @@ -135,6 +135,7 @@ var restartModal = createModal('restartModal'); var refreshModal = createModal('refreshModal'); var aboutModal = createModal('aboutModal'); var deleteModal = createModal('deleteModal'); +var newUserModal = createModal('newUserModal'); // Parsed invite: [, , <1: Empty invite (no delete/link), 0: Actual invite>, , , [], , , ] function parseInvite(invite, empty = false) { diff --git a/data/templates/admin.html b/data/templates/admin.html index 4ba954d..4716a92 100644 --- a/data/templates/admin.html +++ b/data/templates/admin.html @@ -207,8 +207,8 @@ @@ -270,6 +270,38 @@ +

invites accounts

@@ -360,7 +392,7 @@
Accounts
- +
diff --git a/main.go b/main.go index 7b6a482..70fca6c 100644 --- a/main.go +++ b/main.go @@ -435,6 +435,7 @@ func start(asDaemon, firstCall bool) { router.GET("/invite/:invCode", app.InviteProxy) api := router.Group("/", app.webAuth()) router.POST("/logout", app.Logout) + api.POST("/newUserAdmin", app.NewUserAdmin) api.POST("/generateInvite", app.GenerateInvite) api.GET("/getInvites", app.GetInvites) api.POST("/setNotify", app.SetNotify) diff --git a/views.go b/views.go index a184fda..c91d527 100644 --- a/views.go +++ b/views.go @@ -20,6 +20,7 @@ func (app *appContext) AdminPage(gc *gin.Context) { "version": VERSION, "commit": COMMIT, "ombiEnabled": ombiEnabled, + "username": !app.config.Section("email").Key("no_username").MustBool(false), }) }