mirror of
https://github.com/hrfee/jfa-go.git
synced 2024-12-22 09:00:10 +00:00
jellyseerr: cleanup requests method, read proper errors
single req() function is wrapped by methods for each http method, and error messages are parsed and returned if given by the server. also added note about Jellyseerr's enforcement of unique email addresses in settings.
This commit is contained in:
parent
1fa340f096
commit
db1c62cc46
@ -1629,6 +1629,14 @@
|
|||||||
"value": false,
|
"value": false,
|
||||||
"depends_true": "enabled",
|
"depends_true": "enabled",
|
||||||
"description": "Existing users (and those created outside jfa-go) will have their contact info imported to Jellyseerr."
|
"description": "Existing users (and those created outside jfa-go) will have their contact info imported to Jellyseerr."
|
||||||
|
},
|
||||||
|
"constraints_note": {
|
||||||
|
"name": "Unique Emails:",
|
||||||
|
"type": "note",
|
||||||
|
"value": "",
|
||||||
|
"depends_true": "import_existing",
|
||||||
|
"required": "false",
|
||||||
|
"description": "Jellyseerr requires email addresses to be unique. If this is not the case, you may see errors in jfa-go's logs. You can require unique addresses in Settings > Email."
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -55,73 +55,60 @@ func NewJellyseerr(server, key string, timeoutHandler common.TimeoutHandler) *Je
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// does a GET and returns the response as a string.
|
func (js *Jellyseerr) req(mode string, uri string, data any, queryParams url.Values, headers map[string]string, response bool) (string, int, error) {
|
||||||
func (js *Jellyseerr) getJSON(url string, params map[string]string, queryParams url.Values) (string, int, error) {
|
var params []byte
|
||||||
if js.key == "" {
|
if data != nil {
|
||||||
return "", 401, fmt.Errorf("No API key provided")
|
params, _ = json.Marshal(data)
|
||||||
|
}
|
||||||
|
if js.LogRequestBodies {
|
||||||
|
fmt.Printf("Jellyseerr API Client: Sending Data \"%s\" to \"%s\"\n", string(params), uri)
|
||||||
|
}
|
||||||
|
if qp := queryParams.Encode(); qp != "" {
|
||||||
|
uri += "?" + qp
|
||||||
}
|
}
|
||||||
var req *http.Request
|
var req *http.Request
|
||||||
if params != nil {
|
if data != nil {
|
||||||
jsonParams, _ := json.Marshal(params)
|
req, _ = http.NewRequest(mode, uri, bytes.NewBuffer(params))
|
||||||
if js.LogRequestBodies {
|
|
||||||
fmt.Printf("Jellyseerr API Client: Sending Data \"%s\" to \"%s\"\n", string(jsonParams), url)
|
|
||||||
}
|
|
||||||
req, _ = http.NewRequest("GET", url+"?"+queryParams.Encode(), bytes.NewBuffer(jsonParams))
|
|
||||||
} else {
|
} else {
|
||||||
req, _ = http.NewRequest("GET", url+"?"+queryParams.Encode(), nil)
|
req, _ = http.NewRequest(mode, uri, nil)
|
||||||
}
|
}
|
||||||
for name, value := range js.header {
|
|
||||||
req.Header.Add(name, value)
|
|
||||||
}
|
|
||||||
resp, err := js.httpClient.Do(req)
|
|
||||||
defer js.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 (js *Jellyseerr) send(mode string, url string, data any, response bool, headers map[string]string) (string, int, error) {
|
|
||||||
responseText := ""
|
|
||||||
params, _ := json.Marshal(data)
|
|
||||||
if js.LogRequestBodies {
|
|
||||||
fmt.Printf("Jellyseerr API Client: Sending Data \"%s\" to \"%s\"\n", string(params), url)
|
|
||||||
}
|
|
||||||
req, _ := http.NewRequest(mode, url, bytes.NewBuffer(params))
|
|
||||||
req.Header.Add("Content-Type", "application/json")
|
req.Header.Add("Content-Type", "application/json")
|
||||||
for name, value := range js.header {
|
for name, value := range js.header {
|
||||||
req.Header.Add(name, value)
|
req.Header.Add(name, value)
|
||||||
}
|
}
|
||||||
|
if headers != nil {
|
||||||
for name, value := range headers {
|
for name, value := range headers {
|
||||||
req.Header.Add(name, value)
|
req.Header.Add(name, value)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
resp, err := js.httpClient.Do(req)
|
resp, err := js.httpClient.Do(req)
|
||||||
|
reqFailed := err != nil || !(resp.StatusCode == 200 || resp.StatusCode == 201)
|
||||||
defer js.timeoutHandler()
|
defer js.timeoutHandler()
|
||||||
if err != nil || !(resp.StatusCode == 200 || resp.StatusCode == 201) {
|
var responseText string
|
||||||
if resp.StatusCode == 401 {
|
defer resp.Body.Close()
|
||||||
return "", 401, fmt.Errorf("Invalid API Key")
|
if response || reqFailed {
|
||||||
|
responseText, err = js.decodeResp(resp)
|
||||||
|
if err != nil {
|
||||||
|
return responseText, resp.StatusCode, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if reqFailed {
|
||||||
|
var msg ErrorDTO
|
||||||
|
err = json.Unmarshal([]byte(responseText), &msg)
|
||||||
|
if err != nil {
|
||||||
|
return responseText, resp.StatusCode, err
|
||||||
|
}
|
||||||
|
if msg.Message == "" {
|
||||||
|
err = fmt.Errorf("failed (error %d)", resp.StatusCode)
|
||||||
|
} else {
|
||||||
|
err = fmt.Errorf("got %d: %s", resp.StatusCode, msg.Message)
|
||||||
}
|
}
|
||||||
return responseText, resp.StatusCode, err
|
return responseText, resp.StatusCode, err
|
||||||
}
|
}
|
||||||
if response {
|
return responseText, resp.StatusCode, err
|
||||||
defer resp.Body.Close()
|
}
|
||||||
|
|
||||||
|
func (js *Jellyseerr) decodeResp(resp *http.Response) (string, error) {
|
||||||
var out io.Reader
|
var out io.Reader
|
||||||
switch resp.Header.Get("Content-Encoding") {
|
switch resp.Header.Get("Content-Encoding") {
|
||||||
case "gzip":
|
case "gzip":
|
||||||
@ -130,21 +117,28 @@ func (js *Jellyseerr) send(mode string, url string, data any, response bool, hea
|
|||||||
out = resp.Body
|
out = resp.Body
|
||||||
}
|
}
|
||||||
buf := new(strings.Builder)
|
buf := new(strings.Builder)
|
||||||
_, err = io.Copy(buf, out)
|
_, err := io.Copy(buf, out)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", 500, err
|
return "", err
|
||||||
}
|
}
|
||||||
responseText = buf.String()
|
return buf.String(), nil
|
||||||
}
|
|
||||||
return responseText, resp.StatusCode, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (js *Jellyseerr) post(url string, data any, response bool) (string, int, error) {
|
func (js *Jellyseerr) get(uri string, data any, params url.Values) (string, int, error) {
|
||||||
return js.send("POST", url, data, response, nil)
|
return js.req(http.MethodGet, uri, data, params, nil, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (js *Jellyseerr) put(url string, data any, response bool) (string, int, error) {
|
func (js *Jellyseerr) post(uri string, data any, response bool) (string, int, error) {
|
||||||
return js.send("PUT", url, data, response, nil)
|
return js.req(http.MethodPost, uri, data, url.Values{}, nil, response)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (js *Jellyseerr) put(uri string, data any, response bool) (string, int, error) {
|
||||||
|
return js.req(http.MethodPut, uri, data, url.Values{}, nil, response)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (js *Jellyseerr) delete(uri string, data any) (int, error) {
|
||||||
|
_, status, err := js.req(http.MethodDelete, uri, data, url.Values{}, nil, false)
|
||||||
|
return status, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (js *Jellyseerr) ImportFromJellyfin(jfIDs ...string) ([]User, error) {
|
func (js *Jellyseerr) ImportFromJellyfin(jfIDs ...string) ([]User, error) {
|
||||||
@ -203,7 +197,7 @@ func (js *Jellyseerr) getUserPage(page int) (GetUsersDTO, error) {
|
|||||||
if js.LogRequestBodies {
|
if js.LogRequestBodies {
|
||||||
fmt.Printf("Jellyseerr API Client: Sending with URL params \"%+v\"\n", params)
|
fmt.Printf("Jellyseerr API Client: Sending with URL params \"%+v\"\n", params)
|
||||||
}
|
}
|
||||||
resp, status, err := js.getJSON(js.server+"/user", nil, params)
|
resp, status, err := js.get(js.server+"/user", nil, params)
|
||||||
var data GetUsersDTO
|
var data GetUsersDTO
|
||||||
if status != 200 {
|
if status != 200 {
|
||||||
return data, fmt.Errorf("failed (error %d)", status)
|
return data, fmt.Errorf("failed (error %d)", status)
|
||||||
@ -267,7 +261,7 @@ func (js *Jellyseerr) getUser(jfID string) (User, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (js *Jellyseerr) Me() (User, error) {
|
func (js *Jellyseerr) Me() (User, error) {
|
||||||
resp, status, err := js.getJSON(js.server+"/auth/me", nil, url.Values{})
|
resp, status, err := js.get(js.server+"/auth/me", nil, url.Values{})
|
||||||
var data User
|
var data User
|
||||||
data.ID = -1
|
data.ID = -1
|
||||||
if status != 200 {
|
if status != 200 {
|
||||||
@ -287,7 +281,7 @@ func (js *Jellyseerr) GetPermissions(jfID string) (Permissions, error) {
|
|||||||
return data.Permissions, err
|
return data.Permissions, err
|
||||||
}
|
}
|
||||||
|
|
||||||
resp, status, err := js.getJSON(fmt.Sprintf(js.server+"/user/%d/settings/permissions", u.ID), nil, url.Values{})
|
resp, status, err := js.get(fmt.Sprintf(js.server+"/user/%d/settings/permissions", u.ID), nil, url.Values{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return data.Permissions, err
|
return data.Permissions, err
|
||||||
}
|
}
|
||||||
@ -361,7 +355,7 @@ func (js *Jellyseerr) DeleteUser(jfID string) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
_, status, err := js.send("DELETE", fmt.Sprintf(js.server+"/user/%d", u.ID), nil, false, nil)
|
status, err := js.delete(fmt.Sprintf(js.server+"/user/%d", u.ID), nil)
|
||||||
if status != 200 && status != 201 {
|
if status != 200 && status != 201 {
|
||||||
return fmt.Errorf("failed (error %d)", status)
|
return fmt.Errorf("failed (error %d)", status)
|
||||||
}
|
}
|
||||||
@ -382,7 +376,7 @@ func (js *Jellyseerr) GetNotificationPreferences(jfID string) (Notifications, er
|
|||||||
|
|
||||||
func (js *Jellyseerr) GetNotificationPreferencesByID(jellyseerrID int64) (Notifications, error) {
|
func (js *Jellyseerr) GetNotificationPreferencesByID(jellyseerrID int64) (Notifications, error) {
|
||||||
var data Notifications
|
var data Notifications
|
||||||
resp, status, err := js.getJSON(fmt.Sprintf(js.server+"/user/%d/settings/notifications", jellyseerrID), nil, url.Values{})
|
resp, status, err := js.get(fmt.Sprintf(js.server+"/user/%d/settings/notifications", jellyseerrID), nil, url.Values{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return data, err
|
return data, err
|
||||||
}
|
}
|
||||||
@ -435,7 +429,7 @@ func (js *Jellyseerr) GetUsers() (map[string]User, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (js *Jellyseerr) UserByID(jellyseerrID int64) (User, error) {
|
func (js *Jellyseerr) UserByID(jellyseerrID int64) (User, error) {
|
||||||
resp, status, err := js.getJSON(js.server+fmt.Sprintf("/user/%d", jellyseerrID), nil, url.Values{})
|
resp, status, err := js.get(js.server+fmt.Sprintf("/user/%d", jellyseerrID), nil, url.Values{})
|
||||||
var data User
|
var data User
|
||||||
if status != 200 {
|
if status != 200 {
|
||||||
return data, fmt.Errorf("failed (error %d)", status)
|
return data, fmt.Errorf("failed (error %d)", status)
|
||||||
|
@ -130,3 +130,7 @@ type MainUserSettings struct {
|
|||||||
WatchlistSyncMovies any `json:"watchlistSyncMovies,omitempty"`
|
WatchlistSyncMovies any `json:"watchlistSyncMovies,omitempty"`
|
||||||
WatchlistSyncTv any `json:"watchlistSyncTv,omitempty"`
|
WatchlistSyncTv any `json:"watchlistSyncTv,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type ErrorDTO struct {
|
||||||
|
Message string `json:"message,omitempty"`
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user