1
0
mirror of https://github.com/hrfee/jfa-go.git synced 2024-09-19 19:00:11 +00:00

jellyseerr: add user modification methods

addded permissions get/set before realizing it already comes as part of
the User object. Split User attributes that will be templated into
UserTemplate struct, which User inherits. ApplyTemplateToUser takes a
UserTemplate, while ModifyUser takes a plain map with some typed fields
(display name and email, for now).
This commit is contained in:
Harvey Tindall 2024-07-29 17:26:14 +01:00
parent 9c34192b4f
commit 73e985c45c
Signed by: hrfee
GPG Key ID: BBC65952848FB1A2
3 changed files with 137 additions and 11 deletions

View File

@ -91,7 +91,7 @@ func (js *Jellyseerr) getJSON(url string, params map[string]string, queryParams
} }
// 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. // 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 (js *Jellyseerr) send(mode string, url string, data interface{}, response bool, headers map[string]string) (string, int, error) { func (js *Jellyseerr) send(mode string, url string, data any, response bool, headers map[string]string) (string, int, error) {
responseText := "" responseText := ""
params, _ := json.Marshal(data) params, _ := json.Marshal(data)
req, _ := http.NewRequest(mode, url, bytes.NewBuffer(params)) req, _ := http.NewRequest(mode, url, bytes.NewBuffer(params))
@ -129,11 +129,11 @@ func (js *Jellyseerr) send(mode string, url string, data interface{}, response b
return responseText, resp.StatusCode, nil return responseText, resp.StatusCode, nil
} }
func (js *Jellyseerr) post(url string, data map[string]interface{}, response bool) (string, int, error) { func (js *Jellyseerr) post(url string, data any, response bool) (string, int, error) {
return js.send("POST", url, data, response, nil) return js.send("POST", url, data, response, nil)
} }
func (js *Jellyseerr) put(url string, data map[string]interface{}, response bool) (string, int, error) { func (js *Jellyseerr) put(url string, data any, response bool) (string, int, error) {
return js.send("PUT", url, data, response, nil) return js.send("PUT", url, data, response, nil)
} }
@ -236,3 +236,92 @@ func (js *Jellyseerr) Me() (User, error) {
err = json.Unmarshal([]byte(resp), &data) err = json.Unmarshal([]byte(resp), &data)
return data, err return data, err
} }
func (js *Jellyseerr) GetPermissions(jfID string) (Permissions, error) {
data := permissionsDTO{Permissions: -1}
u, err := js.MustGetUser(jfID)
if err != nil {
return data.Permissions, err
}
resp, status, err := js.getJSON(fmt.Sprintf(js.server+"/user/%d/settings/permissions", u.ID), nil, url.Values{})
if err != nil {
return data.Permissions, err
}
if status != 200 {
return data.Permissions, fmt.Errorf("failed (error %d)", status)
}
err = json.Unmarshal([]byte(resp), &data)
return data.Permissions, err
}
func (js *Jellyseerr) SetPermissions(jfID string, perm Permissions) error {
u, err := js.MustGetUser(jfID)
if err != nil {
return err
}
_, status, err := js.post(fmt.Sprintf(js.server+"/user/%d/settings/permissions", u.ID), permissionsDTO{Permissions: perm}, false)
if err != nil {
return err
}
if status != 200 && status != 201 {
return fmt.Errorf("failed (error %d)", status)
}
u.Permissions = perm
js.userCache[jfID] = u
return nil
}
func (js *Jellyseerr) ApplyTemplateToUser(jfID string, tmpl UserTemplate) error {
u, err := js.MustGetUser(jfID)
if err != nil {
return err
}
_, status, err := js.put(fmt.Sprintf(js.server+"/user/%d", u.ID), tmpl, false)
if err != nil {
return err
}
if status != 200 && status != 201 {
return fmt.Errorf("failed (error %d)", status)
}
u.UserTemplate = tmpl
js.userCache[jfID] = u
return nil
}
func (js *Jellyseerr) ModifyUser(jfID string, conf map[UserField]string) error {
u, err := js.MustGetUser(jfID)
if err != nil {
return err
}
_, status, err := js.put(fmt.Sprintf(js.server+"/user/%d", u.ID), conf, false)
if err != nil {
return err
}
if status != 200 && status != 201 {
return fmt.Errorf("failed (error %d)", status)
}
// Lazily just invalidate the cache.
js.cacheExpiry = time.Now()
return nil
}
func (js *Jellyseerr) DeleteUser(jfID string) error {
u, err := js.MustGetUser(jfID)
if err != nil {
return err
}
_, status, err := js.send("DELETE", fmt.Sprintf(js.server+"/user/%d", u.ID), nil, false, nil)
if status != 200 && status != 201 {
return fmt.Errorf("failed (error %d)", status)
}
if err != nil {
return err
}
delete(js.userCache, jfID)
return err
}

View File

@ -9,6 +9,7 @@ import (
const ( const (
API_KEY = "MTcyMjI2MDM2MTYyMzMxNDZkZmYyLTE4MzMtNDUyNy1hODJlLTI0MTZkZGUyMDg2Ng==" API_KEY = "MTcyMjI2MDM2MTYyMzMxNDZkZmYyLTE4MzMtNDUyNy1hODJlLTI0MTZkZGUyMDg2Ng=="
URI = "http://localhost:5055" URI = "http://localhost:5055"
PERM = 2097184
) )
func client() *Jellyseerr { func client() *Jellyseerr {
@ -26,7 +27,7 @@ func TestMe(t *testing.T) {
} }
} }
func TestImportFromJellyfin(t *testing.T) { /* func TestImportFromJellyfin(t *testing.T) {
js := client() js := client()
list, err := js.ImportFromJellyfin("6b75e189efb744f583aa2e8e9cee41d3") list, err := js.ImportFromJellyfin("6b75e189efb744f583aa2e8e9cee41d3")
if err != nil { if err != nil {
@ -35,7 +36,7 @@ func TestImportFromJellyfin(t *testing.T) {
if len(list) == 0 { if len(list) == 0 {
t.Fatalf("returned no users") t.Fatalf("returned no users")
} }
} } */
func TestMustGetUser(t *testing.T) { func TestMustGetUser(t *testing.T) {
js := client() js := client()
@ -47,3 +48,22 @@ func TestMustGetUser(t *testing.T) {
t.Fatalf("returned no users") t.Fatalf("returned no users")
} }
} }
func TestSetPermissions(t *testing.T) {
js := client()
err := js.SetPermissions("6b75e189efb744f583aa2e8e9cee41d3", PERM)
if err != nil {
t.Fatalf("returned error %+v", err)
}
}
func TestGetPermissions(t *testing.T) {
js := client()
perm, err := js.GetPermissions("6b75e189efb744f583aa2e8e9cee41d3")
if err != nil {
t.Fatalf("returned error %+v", err)
}
if perm != PERM {
t.Fatalf("got unexpected perm code %d", perm)
}
}

View File

@ -2,8 +2,15 @@ package jellyseerr
import "time" import "time"
type UserField string
const (
FieldDisplayName UserField = "displayName"
FieldEmail UserField = "email"
)
type User struct { type User struct {
Permissions int `json:"permissions"` UserTemplate // Note: You can set this with User.UserTemplate = value.
Warnings []any `json:"warnings"` Warnings []any `json:"warnings"`
ID int `json:"id"` ID int `json:"id"`
Email string `json:"email"` Email string `json:"email"`
@ -11,23 +18,27 @@ type User struct {
JellyfinUsername string `json:"jellyfinUsername"` JellyfinUsername string `json:"jellyfinUsername"`
Username string `json:"username"` Username string `json:"username"`
RecoveryLinkExpirationDate any `json:"recoveryLinkExpirationDate"` RecoveryLinkExpirationDate any `json:"recoveryLinkExpirationDate"`
UserType int `json:"userType"`
PlexID string `json:"plexId"` PlexID string `json:"plexId"`
JellyfinUserID string `json:"jellyfinUserId"` JellyfinUserID string `json:"jellyfinUserId"`
JellyfinDeviceID string `json:"jellyfinDeviceId"` JellyfinDeviceID string `json:"jellyfinDeviceId"`
JellyfinAuthToken string `json:"jellyfinAuthToken"` JellyfinAuthToken string `json:"jellyfinAuthToken"`
PlexToken string `json:"plexToken"` PlexToken string `json:"plexToken"`
Avatar string `json:"avatar"` Avatar string `json:"avatar"`
MovieQuotaLimit any `json:"movieQuotaLimit"`
MovieQuotaDays any `json:"movieQuotaDays"`
TvQuotaLimit any `json:"tvQuotaLimit"`
TvQuotaDays any `json:"tvQuotaDays"`
CreatedAt time.Time `json:"createdAt"` CreatedAt time.Time `json:"createdAt"`
UpdatedAt time.Time `json:"updatedAt"` UpdatedAt time.Time `json:"updatedAt"`
RequestCount int `json:"requestCount"` RequestCount int `json:"requestCount"`
DisplayName string `json:"displayName"` DisplayName string `json:"displayName"`
} }
type UserTemplate struct {
Permissions Permissions `json:"permissions"`
UserType int `json:"userType"`
MovieQuotaLimit any `json:"movieQuotaLimit"`
MovieQuotaDays any `json:"movieQuotaDays"`
TvQuotaLimit any `json:"tvQuotaLimit"`
TvQuotaDays any `json:"tvQuotaDays"`
}
type PageInfo struct { type PageInfo struct {
Pages int `json:"pages"` Pages int `json:"pages"`
PageSize int `json:"pageSize"` PageSize int `json:"pageSize"`
@ -39,3 +50,9 @@ type GetUsersDTO struct {
Page PageInfo `json:"pageInfo"` Page PageInfo `json:"pageInfo"`
Results []User `json:"results"` Results []User `json:"results"`
} }
type permissionsDTO struct {
Permissions Permissions `json:"permissions"`
}
type Permissions int