mirror of
https://github.com/hrfee/jfa-go.git
synced 2024-12-22 17:10:10 +00:00
Harvey Tindall
af61549bf1
When password reset links are enabled, the ombi password will be reset to the PIN along with Jellyfin.
222 lines
6.2 KiB
Go
222 lines
6.2 KiB
Go
package ombi
|
|
|
|
import (
|
|
"bytes"
|
|
"compress/gzip"
|
|
"encoding/json"
|
|
"fmt"
|
|
"io"
|
|
"net/http"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/hrfee/jfa-go/common"
|
|
)
|
|
|
|
// Ombi represents a running Ombi instance.
|
|
type Ombi struct {
|
|
server, key string
|
|
header map[string]string
|
|
httpClient *http.Client
|
|
userCache []map[string]interface{}
|
|
cacheExpiry time.Time
|
|
cacheLength int
|
|
timeoutHandler common.TimeoutHandler
|
|
}
|
|
|
|
// NewOmbi returns an Ombi object.
|
|
func NewOmbi(server, key string, timeoutHandler common.TimeoutHandler) *Ombi {
|
|
return &Ombi{
|
|
server: server,
|
|
key: key,
|
|
httpClient: &http.Client{
|
|
Timeout: 10 * time.Second,
|
|
},
|
|
header: map[string]string{
|
|
"ApiKey": key,
|
|
},
|
|
cacheLength: 30,
|
|
cacheExpiry: time.Now(),
|
|
timeoutHandler: timeoutHandler,
|
|
}
|
|
}
|
|
|
|
// does a GET and returns the response as a string.
|
|
func (ombi *Ombi) getJSON(url string, params map[string]string) (string, int, error) {
|
|
if ombi.key == "" {
|
|
return "", 401, fmt.Errorf("No API key provided")
|
|
}
|
|
var req *http.Request
|
|
if params != nil {
|
|
jsonParams, _ := json.Marshal(params)
|
|
req, _ = http.NewRequest("GET", url, bytes.NewBuffer(jsonParams))
|
|
} else {
|
|
req, _ = http.NewRequest("GET", url, nil)
|
|
}
|
|
for name, value := range ombi.header {
|
|
req.Header.Add(name, value)
|
|
}
|
|
resp, err := ombi.httpClient.Do(req)
|
|
defer ombi.timeoutHandler()
|
|
if err != nil || resp.StatusCode != 200 {
|
|
if resp.StatusCode == 401 {
|
|
return "", 401, fmt.Errorf("Invalid API Key")
|
|
}
|
|
return "", resp.StatusCode, err
|
|
}
|
|
defer resp.Body.Close()
|
|
var data io.Reader
|
|
switch resp.Header.Get("Content-Encoding") {
|
|
case "gzip":
|
|
data, _ = gzip.NewReader(resp.Body)
|
|
default:
|
|
data = resp.Body
|
|
}
|
|
buf := new(strings.Builder)
|
|
_, err = io.Copy(buf, data)
|
|
if err != nil {
|
|
return "", 500, err
|
|
}
|
|
return buf.String(), resp.StatusCode, nil
|
|
}
|
|
|
|
// does a POST and optionally returns response as string. Returns a string instead of an io.reader bcs i couldn't get it working otherwise.
|
|
func (ombi *Ombi) send(mode string, url string, data map[string]interface{}, response bool) (string, int, error) {
|
|
responseText := ""
|
|
params, _ := json.Marshal(data)
|
|
req, _ := http.NewRequest(mode, url, bytes.NewBuffer(params))
|
|
req.Header.Add("Content-Type", "application/json")
|
|
for name, value := range ombi.header {
|
|
req.Header.Add(name, value)
|
|
}
|
|
resp, err := ombi.httpClient.Do(req)
|
|
defer ombi.timeoutHandler()
|
|
if err != nil || !(resp.StatusCode == 200 || resp.StatusCode == 201) {
|
|
if resp.StatusCode == 401 {
|
|
return "", 401, fmt.Errorf("Invalid API Key")
|
|
}
|
|
return responseText, resp.StatusCode, err
|
|
}
|
|
if response {
|
|
defer resp.Body.Close()
|
|
var out io.Reader
|
|
switch resp.Header.Get("Content-Encoding") {
|
|
case "gzip":
|
|
out, _ = gzip.NewReader(resp.Body)
|
|
default:
|
|
out = resp.Body
|
|
}
|
|
buf := new(strings.Builder)
|
|
_, err = io.Copy(buf, out)
|
|
if err != nil {
|
|
return "", 500, err
|
|
}
|
|
responseText = buf.String()
|
|
}
|
|
return responseText, resp.StatusCode, nil
|
|
}
|
|
|
|
func (ombi *Ombi) post(url string, data map[string]interface{}, response bool) (string, int, error) {
|
|
return ombi.send("POST", url, data, response)
|
|
}
|
|
|
|
func (ombi *Ombi) put(url string, data map[string]interface{}, response bool) (string, int, error) {
|
|
return ombi.send("PUT", url, data, response)
|
|
}
|
|
|
|
// ModifyUser applies the given modified user object to the corresponding user.
|
|
func (ombi *Ombi) ModifyUser(user map[string]interface{}) (status int, err error) {
|
|
if _, ok := user["id"]; !ok {
|
|
err = fmt.Errorf("No ID provided")
|
|
return
|
|
}
|
|
_, status, err = ombi.put(ombi.server+"/api/v1/Identity/", user, false)
|
|
return
|
|
}
|
|
|
|
// DeleteUser deletes the user corresponding to the given ID.
|
|
func (ombi *Ombi) DeleteUser(id string) (code int, err error) {
|
|
url := fmt.Sprintf("%s/api/v1/Identity/%s", ombi.server, id)
|
|
req, _ := http.NewRequest("DELETE", url, nil)
|
|
req.Header.Add("Content-Type", "application/json")
|
|
for name, value := range ombi.header {
|
|
req.Header.Add(name, value)
|
|
}
|
|
resp, err := ombi.httpClient.Do(req)
|
|
defer ombi.timeoutHandler()
|
|
return resp.StatusCode, err
|
|
}
|
|
|
|
// UserByID returns the user corresponding to the provided ID.
|
|
func (ombi *Ombi) UserByID(id string) (result map[string]interface{}, code int, err error) {
|
|
resp, code, err := ombi.getJSON(fmt.Sprintf("%s/api/v1/Identity/User/%s", ombi.server, id), nil)
|
|
json.Unmarshal([]byte(resp), &result)
|
|
return
|
|
}
|
|
|
|
// GetUsers returns all users on the Ombi instance.
|
|
func (ombi *Ombi) GetUsers() ([]map[string]interface{}, int, error) {
|
|
if time.Now().After(ombi.cacheExpiry) {
|
|
resp, code, err := ombi.getJSON(fmt.Sprintf("%s/api/v1/Identity/Users", ombi.server), nil)
|
|
var result []map[string]interface{}
|
|
json.Unmarshal([]byte(resp), &result)
|
|
ombi.userCache = result
|
|
if (code == 200 || code == 204) && err == nil {
|
|
ombi.cacheExpiry = time.Now().Add(time.Minute * time.Duration(ombi.cacheLength))
|
|
}
|
|
return result, code, err
|
|
}
|
|
return ombi.userCache, 200, nil
|
|
}
|
|
|
|
// Strip these from a user when saving as a template.
|
|
// We also need to strip userQualityProfiles{"id", "userId"}
|
|
var stripFromOmbi = []string{
|
|
"alias",
|
|
"emailAddress",
|
|
"hasLoggedIn",
|
|
"id",
|
|
"lastLoggedIn",
|
|
"password",
|
|
"userName",
|
|
}
|
|
|
|
// TemplateByID returns a template based on the user corresponding to the provided ID's settings.
|
|
func (ombi *Ombi) TemplateByID(id string) (result map[string]interface{}, code int, err error) {
|
|
result, code, err = ombi.UserByID(id)
|
|
if err != nil || code != 200 {
|
|
return
|
|
}
|
|
for _, key := range stripFromOmbi {
|
|
if _, ok := result[key]; ok {
|
|
delete(result, key)
|
|
}
|
|
}
|
|
if qp, ok := result["userQualityProfiles"].(map[string]interface{}); ok {
|
|
delete(qp, "id")
|
|
delete(qp, "userId")
|
|
result["userQualityProfiles"] = qp
|
|
}
|
|
return
|
|
}
|
|
|
|
// NewUser creates a new user with the given username, password and email address.
|
|
func (ombi *Ombi) NewUser(username, password, email string, template map[string]interface{}) ([]string, int, error) {
|
|
url := fmt.Sprintf("%s/api/v1/Identity", ombi.server)
|
|
user := template
|
|
user["userName"] = username
|
|
user["password"] = password
|
|
user["emailAddress"] = email
|
|
resp, code, err := ombi.post(url, user, true)
|
|
var data map[string]interface{}
|
|
json.Unmarshal([]byte(resp), &data)
|
|
if err != nil || code != 200 {
|
|
var lst []string
|
|
if data["errors"] != nil {
|
|
lst = data["errors"].([]string)
|
|
}
|
|
return lst, code, err
|
|
}
|
|
return nil, code, err
|
|
}
|