Files
Konrad NeitzelandCursor 7921694782 Extract AppAPI auth and OCS preferences from CheckDNS.
Publish gonexapp v1 with Credentials, OCSClient, and parameterized
AppAPIPreferences so ExApps share Nextcloud ExApp plumbing per ADR 0013.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-26 19:14:22 +02:00

68 lines
1.6 KiB
Go

package gonexapp
import (
"bytes"
"encoding/json"
"fmt"
"io"
"net/http"
"strings"
)
// OCSClient performs AppAPI-authenticated OCS requests with format=json.
type OCSClient struct {
Cred Credentials
Client *http.Client
}
func (c OCSClient) httpClient() *http.Client {
if c.Client != nil {
return c.Client
}
return http.DefaultClient
}
// URL builds an OCS URL under /ocs/v2.php with format=json.
func (c OCSClient) URL(path string) string {
base := strings.TrimRight(c.Cred.BaseURL, "/")
path = strings.TrimPrefix(path, "/")
return base + "/ocs/v2.php/" + path + "?format=json"
}
// Call performs method against path with an optional JSON body and returns the response body
// after verifying it is valid JSON. Non-2xx responses return an error including the status.
func (c OCSClient) Call(method, path string, body []byte) ([]byte, error) {
var reader io.Reader
if len(body) > 0 {
reader = bytes.NewReader(body)
}
req, err := http.NewRequest(method, c.URL(path), reader)
if err != nil {
return nil, err
}
if len(body) > 0 {
req.Header.Set("Content-Type", "application/json")
}
for k, vs := range c.Cred.AuthHeaders() {
for _, v := range vs {
req.Header.Set(k, v)
}
}
res, err := c.httpClient().Do(req)
if err != nil {
return nil, err
}
defer res.Body.Close()
raw, err := io.ReadAll(res.Body)
if err != nil {
return nil, err
}
if res.StatusCode >= 300 {
return nil, fmt.Errorf("ocs %s %s: %s", method, path, res.Status)
}
if !json.Valid(raw) {
return nil, fmt.Errorf("ocs %s %s: response is not JSON", method, path)
}
return raw, nil
}