1
0
mirror of https://github.com/hrfee/jfa-go.git synced 2024-12-23 01:20:11 +00:00

add user button

added create user button for the admin to use.
This commit is contained in:
Harvey Tindall 2020-09-18 00:59:59 +01:00
parent 9213f2a078
commit d4b94bc9d9
Signed by: hrfee
GPG Key ID: BBC65952848FB1A2
6 changed files with 160 additions and 7 deletions

52
api.go
View File

@ -180,6 +180,58 @@ type newUserReq struct {
Code string `json:"code"` 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) { func (app *appContext) NewUser(gc *gin.Context) {
var req newUserReq var req newUserReq
gc.BindJSON(&req) gc.BindJSON(&req)

View File

@ -171,8 +171,6 @@ function changeEmail(icon, id) {
icon.parentNode.appendChild(cross); icon.parentNode.appendChild(cross);
} }
function populateUsers() { function populateUsers() {
const acList = document.getElementById('accountsList'); const acList = document.getElementById('accountsList');
acList.innerHTML = ` acList.innerHTML = `
@ -292,6 +290,74 @@ document.getElementById('defaultsSource').addEventListener('change', function()
} }
}) })
document.getElementById('newUserCreate').onclick = function() {
const ogText = this.textContent;
this.innerHTML = `
<span class="spinner-border spinner-border-sm" role="status" aria-hidden="true"></span> 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();
};

View File

@ -135,6 +135,7 @@ var restartModal = createModal('restartModal');
var refreshModal = createModal('refreshModal'); var refreshModal = createModal('refreshModal');
var aboutModal = createModal('aboutModal'); var aboutModal = createModal('aboutModal');
var deleteModal = createModal('deleteModal'); var deleteModal = createModal('deleteModal');
var newUserModal = createModal('newUserModal');
// Parsed invite: [<code>, <expires in _>, <1: Empty invite (no delete/link), 0: Actual invite>, <email address>, <remaining uses>, [<used-by>], <date created>, <notify on expiry>, <notify on creation>] // Parsed invite: [<code>, <expires in _>, <1: Empty invite (no delete/link), 0: Actual invite>, <email address>, <remaining uses>, [<used-by>], <date created>, <notify on expiry>, <notify on creation>]
function parseInvite(invite, empty = false) { function parseInvite(invite, empty = false) {

View File

@ -207,8 +207,8 @@
</div> </div>
<div class="modal-footer"> <div class="modal-footer">
<button type="button" class="btn btn-light" data-dismiss="modal">Cancel</button> <button type="button" class="btn btn-light" data-dismiss="modal">Cancel</button>
<button type="button" class="btn btn-secondary" id="applyRestarts" data-dismiss="modal">Apply, Restart later</button> <button type="button" class="btn btn-secondary" id="applyrestarts" data-dismiss="modal">apply, restart later</button>
<button type="button" class="btn btn-primary" id="applyAndRestart" data-dismiss="modal">Apply &amp; Restart</button> <button type="button" class="btn btn-primary" id="applyandrestart" data-dismiss="modal">apply &amp; restart</button>
</div> </div>
</div> </div>
</div> </div>
@ -270,6 +270,38 @@
</div> </div>
</div> </div>
</div> </div>
<div class="modal fade" id="newUserModal" role="dialog" aria-labelledby="Create new user" aria-hidden="true">
<div class="modal-dialog modal-dialog-centered" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">Create a user</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
<div class="mb-3">
<label for="newUserEmail" class="form-label">Email address</label>
<input type="email" class="form-control" id="newUserEmail" aria-describedby="Email address">
</div>
{{ if .username }}
<div class="mb-3">
<label for="newUserName" class="form-label">Username</label>
<input type="text" class="form-control" id="newUserName" aria-describedby="Username">
</div>
{{ end }}
<div class="mb-3">
<label for="newUserPassword" class="form-label">Password</label>
<input type="password" class="form-control" id="newUserPassword" aria-describedby="Password">
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-light" data-dismiss="modal">Cancel</button>
<button type="button" class="btn btn-primary" id="newUserCreate">Create</button>
</div>
</div>
</div>
</div>
<div class="pageContainer"> <div class="pageContainer">
<h1><a id="invitesTabButton" class="text-button">invites </a><a id="accountsTabButton" class="text-button text-muted">accounts</a></h1> <h1><a id="invitesTabButton" class="text-button">invites </a><a id="accountsTabButton" class="text-button text-muted">accounts</a></h1>
<div class="btn-group" role="group" id="headerButtons"> <div class="btn-group" role="group" id="headerButtons">
@ -360,7 +392,7 @@
<div class="card-header d-flex" style="align-items: center;"> <div class="card-header d-flex" style="align-items: center;">
<div>Accounts</div> <div>Accounts</div>
<div class="ml-auto"> <div class="ml-auto">
<!--<button type="button" class="btn btn-secondary">Add User</button>--> <button type="button" class="btn btn-secondary" id="accountsTabAddUser">Add User</button>
<button type="button" class="btn btn-primary unfocused" id="accountsTabSetDefaults">Set Defaults</button> <button type="button" class="btn btn-primary unfocused" id="accountsTabSetDefaults">Set Defaults</button>
<button type="button" class="btn btn-danger unfocused" id="accountsTabDelete"></button> <button type="button" class="btn btn-danger unfocused" id="accountsTabDelete"></button>
</div> </div>

View File

@ -435,6 +435,7 @@ func start(asDaemon, firstCall bool) {
router.GET("/invite/:invCode", app.InviteProxy) router.GET("/invite/:invCode", app.InviteProxy)
api := router.Group("/", app.webAuth()) api := router.Group("/", app.webAuth())
router.POST("/logout", app.Logout) router.POST("/logout", app.Logout)
api.POST("/newUserAdmin", app.NewUserAdmin)
api.POST("/generateInvite", app.GenerateInvite) api.POST("/generateInvite", app.GenerateInvite)
api.GET("/getInvites", app.GetInvites) api.GET("/getInvites", app.GetInvites)
api.POST("/setNotify", app.SetNotify) api.POST("/setNotify", app.SetNotify)

View File

@ -20,6 +20,7 @@ func (app *appContext) AdminPage(gc *gin.Context) {
"version": VERSION, "version": VERSION,
"commit": COMMIT, "commit": COMMIT,
"ombiEnabled": ombiEnabled, "ombiEnabled": ombiEnabled,
"username": !app.config.Section("email").Key("no_username").MustBool(false),
}) })
} }