package api import ( "context" "encoding/json" "errors" "fmt" "html/template" "io/ioutil" "net/http" ) var ( ErrNoContent = errors.New("no content found for query") ) type API struct { user, pass string space int baseURL string client *http.Client } type Content struct { ContentID string ContentParentTypeID string ContentValues []ContentValue valueMap map[string]ContentValue } func (c *Content) Val(key string) (string, bool) { val, ok := c.valueMap[key] if !ok { return "", false } return val.FieldValue, true } func (c *Content) HTML(key string) (template.HTML, bool) { val, ok := c.valueMap[key] if !ok { return template.HTML(""), false } return template.HTML(val.FieldValue), true } func (c *Content) Ref(key string) (*Content, bool) { val, ok := c.valueMap[key] if !ok || val.FieldReference == nil { return nil, false } ref := transform(*val.FieldReference) return &ref, true } func (c *Content) List(key string) ([]Content, bool) { val, ok := c.valueMap[key] if !ok || val.FieldReferenceList == nil { return nil, false } var list []Content for _, item := range val.FieldReferenceList { list = append(list, transform(item)) } return list, true } type ContentMust struct { c Content } func (c *Content) Must() ContentMust { return ContentMust{Content{c.ContentID, c.ContentParentTypeID, c.ContentValues, c.valueMap}} } func (cm ContentMust) Val(key string) string { val, _ := cm.c.Val(key) return val } func (cm ContentMust) Ref(key string) *Content { val, _ := cm.c.Ref(key) return val } func (cm ContentMust) List(key string) []Content { val, _ := cm.c.List(key) return val } type ContentList struct { ContentList []Content ContentMore bool } type ContentValue struct { FieldID string FieldType string FieldName string FieldValue string FieldReference *Content FieldReferenceList []Content } func New(user, pass, baseURL string, space int) API { return NewWithClient(user, pass, baseURL, space, http.DefaultClient) } func NewWithClient(user, pass, baseURL string, space int, client *http.Client) API { return API{ user: user, pass: pass, space: space, baseURL: baseURL, client: client, } } func (cms API) List(ctx context.Context, typeID int, order, field string) ([]Content, error) { var ( url = fmt.Sprintf("%s/contenttype/%d/%d?order=%s&field=%s", cms.baseURL, cms.space, typeID, order, field) body struct{ ContentList ContentList } ) req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil) if err != nil { return nil, err } req.SetBasicAuth(cms.user, cms.pass) resp, err := cms.client.Do(req) if err != nil { return nil, err } defer resp.Body.Close() bytes, err := ioutil.ReadAll(resp.Body) if err != nil { return nil, err } if err := json.Unmarshal(bytes, &body); err != nil { return nil, err } return transformList(body.ContentList.ContentList), nil } func (cms API) Find(ctx context.Context, typeID int, field, query string) (*Content, error) { var ( url = fmt.Sprintf("%s/content/search?space=%d&contenttype=%d&field=%s&query=%s", cms.baseURL, cms.space, typeID, field, query) body ContentList ) req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil) if err != nil { return nil, err } req.SetBasicAuth(cms.user, cms.pass) resp, err := cms.client.Do(req) if err != nil { return nil, err } defer resp.Body.Close() bytes, err := ioutil.ReadAll(resp.Body) if err != nil { return nil, err } if err := json.Unmarshal(bytes, &body); err != nil { return nil, err } if len(body.ContentList) < 1 { return nil, ErrNoContent } c := transform(body.ContentList[0]) return &c, nil } func transformList(in []Content) []Content { for i, c := range in { in[i] = transform(c) } return in } func transform(in Content) Content { in.valueMap = make(map[string]ContentValue) for _, val := range in.ContentValues { in.valueMap[val.FieldName] = val } return in }