diff --git a/api.go b/api.go index 6c640c9..3d272ca 100644 --- a/api.go +++ b/api.go @@ -4,6 +4,7 @@ import ( "fmt" "os" "os/signal" + "strings" "syscall" "time" @@ -253,6 +254,18 @@ func (app *appContext) NewUser(gc *gin.Context) { 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") + } + } + } gc.JSON(200, validation) } @@ -471,6 +484,30 @@ func (app *appContext) GetUsers(gc *gin.Context) { gc.JSON(200, resp) } +type ombiUser struct { + Name string `json:"name,omitempty"` + ID string `json:"id"` +} + +func (app *appContext) OmbiUsers(gc *gin.Context) { + app.debug.Println("Ombi users requested") + users, status, err := app.ombi.getUsers() + if err != nil || status != 200 { + app.err.Printf("Failed to get users from Ombi: Code %d", status) + app.debug.Printf("Error: %s", err) + respond(500, "Couldn't get users", gc) + return + } + userlist := make([]ombiUser, len(users)) + for i, data := range users { + userlist[i] = ombiUser{ + Name: data["userName"].(string), + ID: data["id"].(string), + } + } + gc.JSON(200, map[string][]ombiUser{"users": userlist}) +} + func (app *appContext) ModifyEmails(gc *gin.Context) { var req map[string]string gc.BindJSON(&req) @@ -492,6 +529,21 @@ func (app *appContext) ModifyEmails(gc *gin.Context) { gc.JSON(200, map[string]bool{"success": true}) } +func (app *appContext) SetOmbiDefaults(gc *gin.Context) { + var req ombiUser + gc.BindJSON(&req) + template, code, err := app.ombi.templateByID(req.ID) + if err != nil || code != 200 || len(template) == 0 { + app.err.Printf("Couldn't get user from Ombi: %d %s", code, err) + respond(500, "Couldn't get user", gc) + return + } + app.storage.ombi_template = template + fmt.Println(app.storage.ombi_path) + app.storage.storeOmbiTemplate() + gc.JSON(200, map[string]bool{"success": true}) +} + type defaultsReq struct { Username string `json:"username"` Homescreen bool `json:"homescreen"` diff --git a/config.go b/config.go index 6ed7285..38f34cd 100644 --- a/config.go +++ b/config.go @@ -48,7 +48,7 @@ func (app *appContext) loadConfig() error { // } key.SetValue(key.MustString(filepath.Join(app.data_path, (key.Name() + ".json")))) } - for _, key := range []string{"user_configuration", "user_displayprefs"} { + for _, key := range []string{"user_configuration", "user_displayprefs", "ombi_template"} { // if app.config.Section("files").Key(key).MustString("") == "" { // key.SetValue(filepath.Join(app.data_path, (key.Name() + ".json"))) // } diff --git a/config/config-base.json b/config/config-base.json index ec125aa..5d37047 100644 --- a/config/config-base.json +++ b/config/config-base.json @@ -40,7 +40,7 @@ "required": true, "requires_restart": true, "type": "text", - "value": "jf-accounts", + "value": "jfa-go", "description": "This and below settings will show on the Jellyfin dashboard when the program connects. You may as well leave them alone." }, "version": { @@ -55,14 +55,14 @@ "required": true, "requires_restart": true, "type": "text", - "value": "jf-accounts" + "value": "jfa-go" }, "device_id": { "name": "Device ID", "required": true, "requires_restart": true, "type": "text", - "value": "jf-accounts-{version}" + "value": "jfa-go-{version}" } }, "ui": { @@ -398,7 +398,7 @@ "depends_true": "enabled", "type": "text", "value": "http://accounts.jellyf.in:8056/invite", - "description": "Base URL for jf-accounts. This is necessary because using a reverse proxy means the program has no way of knowing the URL itself." + "description": "Base URL for jfa-go. This is necessary because using a reverse proxy means the program has no way of knowing the URL itself." } }, "notifications": { @@ -511,6 +511,38 @@ "value": "smtp password" } }, + "ombi": { + "meta": { + "name": "Ombi Integration", + "description": "Connect to Ombi to automatically create a new user's account. You'll need to create an Ombi user template." + }, + "enabled": { + "name": "Enabled", + "required": false, + "requires_restart": true, + "type": "bool", + "value": false, + "description": "Enable to create an Ombi account for new Jellyfin users" + }, + "server": { + "name": "URL", + "required": false, + "requires_restart": true, + "type": "text", + "value": "localhost:5000", + "depends_true": "enabled", + "description": "Ombi server URL, including http(s)://." + }, + "api_key": { + "name": "API Key", + "required": false, + "requires_restart": true, + "type": "text", + "value": "", + "depends_true": "enabled", + "description": "API Key. Get this from the first tab in Ombi settings." + } + }, "files": { "meta": { "name": "File Storage", @@ -532,6 +564,14 @@ "value": "", "description": "Location of stored email addresses (json)." }, + "ombi_template": { + "name": "Ombi user template", + "required": false, + "requires_restart": false, + "type": "text", + "value": "", + "description": "Location of stored Ombi user template." + }, "user_template": { "name": "User Template", "required": false, diff --git a/data/config-base.json b/data/config-base.json index 72e9b8f..cddce8c 100644 --- a/data/config-base.json +++ b/data/config-base.json @@ -9,6 +9,7 @@ "notifications", "mailgun", "smtp", + "ombi", "files" ], "jellyfin": { @@ -62,7 +63,7 @@ "required": true, "requires_restart": true, "type": "text", - "value": "jf-accounts", + "value": "jfa-go", "description": "This and below settings will show on the Jellyfin dashboard when the program connects. You may as well leave them alone." }, "version": { @@ -77,14 +78,14 @@ "required": true, "requires_restart": true, "type": "text", - "value": "jf-accounts" + "value": "jfa-go" }, "device_id": { "name": "Device ID", "required": true, "requires_restart": true, "type": "text", - "value": "jf-accounts-{version}" + "value": "jfa-go-{version}" } }, "ui": { @@ -466,7 +467,7 @@ "depends_true": "enabled", "type": "text", "value": "http://accounts.jellyf.in:8056/invite", - "description": "Base URL for jf-accounts. This is necessary because using a reverse proxy means the program has no way of knowing the URL itself." + "description": "Base URL for jfa-go. This is necessary because using a reverse proxy means the program has no way of knowing the URL itself." } }, "notifications": { @@ -596,10 +597,48 @@ "value": "smtp password" } }, + "ombi": { + "order": [ + "enabled", + "server", + "api_key" + ], + "meta": { + "name": "Ombi Integration", + "description": "Connect to Ombi to automatically create a new user's account. You'll need to create an Ombi user template." + }, + "enabled": { + "name": "Enabled", + "required": false, + "requires_restart": true, + "type": "bool", + "value": false, + "description": "Enable to create an Ombi account for new Jellyfin users" + }, + "server": { + "name": "URL", + "required": false, + "requires_restart": true, + "type": "text", + "value": "localhost:5000", + "depends_true": "enabled", + "description": "Ombi server URL." + }, + "api_key": { + "name": "API Key", + "required": false, + "requires_restart": true, + "type": "text", + "value": "", + "depends_true": "enabled", + "description": "API Key. Get this from the first tab in Ombi settings." + } + }, "files": { "order": [ "invites", "emails", + "ombi_template", "user_template", "user_configuration", "user_displayprefs", @@ -625,6 +664,14 @@ "value": "", "description": "Location of stored email addresses (json)." }, + "ombi_template": { + "name": "Ombi user template", + "required": false, + "requires_restart": false, + "type": "text", + "value": "", + "description": "Location of stored Ombi user template." + }, "user_template": { "name": "User Template", "required": false, diff --git a/data/static/admin.js b/data/static/admin.js index 1b2926c..1a92025 100644 --- a/data/static/admin.js +++ b/data/static/admin.js @@ -627,9 +627,6 @@ document.getElementById('openDefaultsWizard').onclick = function() { let users = req.response['users']; let radioList = document.getElementById('defaultUserRadios'); radioList.textContent = ''; - if (document.getElementById('setDefaultUser')) { - document.getElementById('setDefaultUser').remove(); - } let first = true; for (user of users) { let radio = document.createElement('div'); @@ -639,14 +636,14 @@ document.getElementById('openDefaultsWizard').onclick = function() { first = false; } else { checked = ''; - }; + } radio.innerHTML = ``; radioList.appendChild(radio); } let button = document.getElementById('openDefaultsWizard'); button.disabled = false; - button.innerHTML = 'Set new account defaults'; + button.innerHTML = 'New account defaults'; let submitButton = document.getElementById('storeDefaults'); submitButton.disabled = false; submitButton.textContent = 'Submit'; @@ -715,6 +712,107 @@ document.getElementById('storeDefaults').onclick = function () { } }; +var ombiDefaultsModal = ''; +if (ombiEnabled) { + ombiDefaultsModal = createModal('ombiDefaults'); + document.getElementById('openOmbiDefaults').onclick = function() { + this.disabled = true; + this.innerHTML = + '' + + 'Loading...'; + let req = new XMLHttpRequest(); + req.responseType = 'json'; + req.open("GET", "/getOmbiUsers", true); + req.setRequestHeader("Authorization", "Basic " + btoa(window.token + ":")); + req.onreadystatechange = function() { + if (this.readyState == 4) { + if (this.status == 200) { + let users = req.response['users']; + let radioList = document.getElementById('ombiUserRadios'); + radioList.textContent = ''; + let first = true; + // name and id + for (user of users) { + let radio = document.createElement('div'); + radio.classList.add('radio'); + let checked = 'checked'; + if (first) { + first = false; + } else { + checked = ''; + } + radio.innerHTML = + ``; + radioList.appendChild(radio); + } + let button = document.getElementById('openOmbiDefaults'); + button.disabled = false; + button.innerHTML = 'Ombi user defaults'; + let submitButton = document.getElementById('storeOmbiDefaults'); + submitButton.disabled = false; + submitButton.textContent = 'Submit'; + if (submitButton.classList.contains('btn-success')) { + submitButton.classList.remove('btn-success'); + submitButton.classList.add('btn-primary'); + } else if (submitButton.classList.contains('btn-danger')) { + submitButton.classList.remove('btn-danger'); + submitButton.classList.add('btn-primary'); + } + settingsModal.hide(); + ombiDefaultsModal.show(); + } + } + }; + req.send(); + }; + document.getElementById('storeOmbiDefaults').onclick = function() { + this.disabled = true; + this.innerHTML = + '' + + 'Loading...'; + let button = document.getElementById('storeOmbiDefaults'); + let radios = document.getElementsByName('ombiRadios'); + for (let radio of radios) { + if (radio.checked) { + let data = { + 'id': radio.id.slice(8), + }; + let req = new XMLHttpRequest(); + req.open("POST", "/setOmbiDefaults", true); + req.setRequestHeader("Authorization", "Basic " + btoa(window.token + ":")); + req.setRequestHeader('Content-Type', 'application/json; charset=UTF-8'); + req.onreadystatechange = function() { + if (this.readyState == 4) { + if (this.status == 200 || this.status == 204) { + button.textContent = "Success"; + if (button.classList.contains('btn-danger')) { + button.classList.remove('btn-danger'); + } else if (button.classList.contains('btn-primary')) { + button.classList.remove('btn-primary'); + } + button.classList.add('btn-success'); + button.disabled = false; + setTimeout(function() { ombiDefaultsModal.hide(); }, 1000); + } else { + button.textContent = "Failed"; + button.classList.remove('btn-primary'); + button.classList.add('btn-danger'); + setTimeout(function() { + let button = document.getElementById('storeOmbiDefaults'); + button.textContent = "Submit"; + button.classList.remove('btn-danger'); + button.classList.add('btn-primary'); + button.disabled = false; + }, 1000); + } + } + }; + req.send(JSON.stringify(data)); + } + } + }; +} + document.getElementById('openUsers').onclick = function () { this.disabled = true; this.innerHTML = diff --git a/data/templates/admin.html b/data/templates/admin.html index 7c0004f..48f05bc 100644 --- a/data/templates/admin.html +++ b/data/templates/admin.html @@ -52,6 +52,8 @@ } css.setAttribute('href', cssFile); document.head.appendChild(css); + // store whether ombi is enabled, 1 or 0. + var ombiEnabled = {{ .ombiEnabled }} {{ if not .bs5 }} @@ -177,6 +179,11 @@ + {{ if .ombiEnabled }} + + {{ end }}
@@ -230,6 +237,28 @@ + {{ if .ombiEnabled }} + + {{ end }}