1
0
mirror of https://github.com/hrfee/jfa-go.git synced 2024-09-19 19:00:11 +00:00
jfa-go/ombi/ombi.go
Harvey Tindall 95db48d8f8
start main app integration, restructure build process
the backend code has been added back in, and the build process has been
modified so that no output files are left outside of build/. Admin page
loads and logs in correctly, nothing else functionality-wise yet.
2020-12-29 18:42:26 +00:00

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
}