More API refactoring and working on cleaning up
Signed-off-by: Kris Nóva <kris@nivenly.com>
This commit is contained in:
parent
e4323b6047
commit
3b41c9dd5f
9 changed files with 232 additions and 148 deletions
106
client.go
106
client.go
|
@ -6,72 +6,75 @@ import (
|
|||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strings"
|
||||
|
||||
"github.com/kris-nova/client-go/api/v1"
|
||||
v1 "github.com/kris-nova/client-go/api/v1"
|
||||
)
|
||||
|
||||
const (
|
||||
// DefaultContentType is the content type header the API expects
|
||||
DefaultContentType string = "application/json; charset=utf-8"
|
||||
APIContentType string = "application/json; charset=utf-8"
|
||||
|
||||
// Default Host Configuration
|
||||
DefaultHost string = "localhost"
|
||||
DefaultLoopback string = "127.0.0.1"
|
||||
DefaultPort string = "8080"
|
||||
DefaultConnectionString string = "http://localhost:8080"
|
||||
DefaultTokenKey string = "X-Session-Id"
|
||||
APIAuthHeaderKey string = "X-Session-Id"
|
||||
)
|
||||
|
||||
// New is used to create a new Client to authenticate with
|
||||
// Photoprism.
|
||||
func New(connectionString string) *Client {
|
||||
c := &Client{
|
||||
contentType: DefaultContentType,
|
||||
connectionString: DefaultConnectionString,
|
||||
contentType: APIContentType,
|
||||
connectionString: connectionString,
|
||||
}
|
||||
return c
|
||||
}
|
||||
|
||||
// Client represents a client to a Photoprism application
|
||||
type Client struct {
|
||||
v1client *api.V1Client
|
||||
v1client *v1.V1Client
|
||||
authenticator ClientAuthenticator
|
||||
contentType string
|
||||
connectionString string
|
||||
connectionURL *url.URL
|
||||
}
|
||||
|
||||
// ClientAuthenticator is used to store the secret
|
||||
// data for authenticating with the Photoprism API
|
||||
//
|
||||
// TODO @kris-nova obfuscate the data, and make immutable and unexported fields
|
||||
type ClientAuthenticator interface {
|
||||
getKey() string
|
||||
getSecret() string
|
||||
JSON() ([]byte, error)
|
||||
}
|
||||
|
||||
// -- [ ClientAuthLogin ] --
|
||||
|
||||
// ClientAuthLogin holds secret login information
|
||||
type ClientAuthLogin struct {
|
||||
// Request
|
||||
authPayload
|
||||
}
|
||||
|
||||
type authPayload struct {
|
||||
Username string `json:"username"`
|
||||
Password string `json:"password"`
|
||||
|
||||
// Response
|
||||
}
|
||||
|
||||
// NewClientAuthLogin is used to build a new login struct
|
||||
func NewClientAuthLogin(user, pass string) ClientAuthenticator {
|
||||
return &ClientAuthLogin{
|
||||
Username: user,
|
||||
Password: pass,
|
||||
authPayload: authPayload{
|
||||
Username: user,
|
||||
Password: pass,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// getKey is used internally to get the key with any modifiers
|
||||
func (c *ClientAuthLogin) getKey() string {
|
||||
return c.Username
|
||||
return c.authPayload.Username
|
||||
}
|
||||
|
||||
// getKey is used internally to get the secret with any modifiers
|
||||
func (c *ClientAuthLogin) getSecret() string {
|
||||
return c.Password
|
||||
return c.authPayload.Password
|
||||
}
|
||||
|
||||
// JSON is used to marshal the fields to JSON
|
||||
|
@ -80,13 +83,14 @@ func (c *ClientAuthLogin) JSON() ([]byte, error) {
|
|||
}
|
||||
|
||||
// V1 is used to access the V1 version of the Photoprism API
|
||||
func (c *Client) V1() *api.V1Client {
|
||||
func (c *Client) V1() *v1.V1Client {
|
||||
return c.v1client
|
||||
}
|
||||
|
||||
// Login is used to attempt to authenticate with the Photoprism API
|
||||
func (c *Client) Auth(auth ClientAuthenticator) error {
|
||||
c.authenticator = auth
|
||||
|
||||
// @kris-nova We are returning V1 by default
|
||||
return c.LoginV1()
|
||||
}
|
||||
|
@ -95,6 +99,15 @@ func (c *Client) Auth(auth ClientAuthenticator) error {
|
|||
//
|
||||
// Data: {username: "admin", password: "missy"}
|
||||
func (c *Client) LoginV1() error {
|
||||
// Auth wil also validate the connection string
|
||||
// We do this here so that New() will never return
|
||||
// an error.
|
||||
url, err := url.Parse(c.connectionString)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to parse connection string url [%s]: %v", c.connectionString, err)
|
||||
}
|
||||
c.connectionURL = url
|
||||
|
||||
body, err := c.authenticator.JSON()
|
||||
if err != nil {
|
||||
return fmt.Errorf("JSON marshal error: %v", err)
|
||||
|
@ -111,11 +124,11 @@ func (c *Client) LoginV1() error {
|
|||
}
|
||||
return fmt.Errorf("login error [%d] %s", resp.StatusCode, body)
|
||||
}
|
||||
token := resp.Header.Get(DefaultTokenKey)
|
||||
token := resp.Header.Get(APIAuthHeaderKey)
|
||||
if token == "" {
|
||||
return fmt.Errorf("missing auth token from successful login")
|
||||
}
|
||||
c.v1client = api.New(c.connectionString, token)
|
||||
c.v1client = v1.New(c.connectionURL, token)
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -123,45 +136,10 @@ func (c *Client) LoginV1() error {
|
|||
// based on the API version and Host/Port
|
||||
func (c *Client) Endpoint(str string) string {
|
||||
if strings.HasPrefix("/", str) {
|
||||
return fmt.Sprintf("%s%s", c.connectionString, str)
|
||||
str = fmt.Sprintf("%s%s", c.connectionString, str)
|
||||
} else {
|
||||
str = fmt.Sprintf("%s/%s", c.connectionString, str)
|
||||
}
|
||||
return fmt.Sprintf("%s/%s", c.connectionString, str)
|
||||
//logger.Debug(str)
|
||||
return str
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------------------
|
||||
// Dump from Chrome/Network
|
||||
|
||||
// [REQUEST]
|
||||
//Request URL: http://localhost:8080/api/v1/session
|
||||
//Request Method: POST
|
||||
//Status Code: 200 OK
|
||||
//Remote Address: 127.0.0.1:8080
|
||||
//Referrer Policy: strict-origin-when-cross-origin
|
||||
|
||||
// [RESPONSE HEADERS]
|
||||
//Content-Type: application/json; charset=utf-8
|
||||
//Date: Thu, 04 Feb 2021 03:27:03 GMT
|
||||
//Transfer-Encoding: chunked
|
||||
//X-Session-Id: d92837cb1c41e37b9993d25e282efb3b337b6ae609a687d9
|
||||
|
||||
// [REQUEST HEADERS]
|
||||
//Accept: application/json, text/plain, */*
|
||||
//Accept-Encoding: gzip, deflate, br
|
||||
//Accept-Language: en-US,en;q=0.9
|
||||
//Connection: keep-alive
|
||||
//Content-Length: 39
|
||||
//Content-Type: application/json;charset=UTF-8
|
||||
//Host: localhost:8080
|
||||
//Origin: http://localhost:8080
|
||||
//Referer: http://localhost:8080/login
|
||||
//Sec-Fetch-Dest: empty
|
||||
//Sec-Fetch-Mode: cors
|
||||
//Sec-Fetch-Site: same-origin
|
||||
//User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.96 Safari/537.36
|
||||
//X-Client-Hash: 2607a5a5
|
||||
//X-Client-Version: 210121-07e559df-Linux-x86_64
|
||||
|
||||
// [POST DATA]
|
||||
//{username: "admin", password: "missy"}
|
||||
//password: "missy"
|
||||
//username: "admin"
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue