Add missing status commands
authorMikael Berthe <mikael@lilotux.net>
Thu, 13 Apr 2017 12:54:05 +0200
changeset 105 e2a16e19eb8b
parent 104 fc338e606d37
child 106 356507eb8db6
Add missing status commands
status.go
--- a/status.go	Thu Apr 13 12:38:59 2017 +0200
+++ b/status.go	Thu Apr 13 12:54:05 2017 +0200
@@ -8,9 +8,24 @@
 	"github.com/sendgrid/rest"
 )
 
+// updateStatusOptions contains option field for POST and DELETE API calls
+type updateStatusOptions struct {
+	// The ID is used for most commands
+	ID int
+
+	// The following fields are used for posting a new status
+	Status      string
+	InReplyToID int
+	MediaIDs    []int
+	Sensitive   bool
+	SpoilerText string
+	Visibility  string // "direct", "private", "unlisted" or "public"
+}
+
 // queryStatusData queries the statuses API
-// The subquery can be empty (the status itself), "context", "card",
-// "reblogged_by", "favourited_by".
+// The subquery can be empty or "status" (the status itself), "context",
+// "card", "reblogged_by", "favourited_by".
+// The data argument will receive the object(s) returned by the API server.
 func (g *Client) queryStatusData(statusID int, subquery string, data interface{}) error {
 	endPoint := "statuses/" + strconv.Itoa(statusID)
 
@@ -18,8 +33,13 @@
 		return ErrInvalidID
 	}
 
-	if subquery != "" {
-		// TODO: check subquery values?
+	if subquery != "" && subquery != "status" {
+		switch subquery {
+		case "context", "card", "reblogged_by", "favourited_by":
+		default:
+			return ErrInvalidParameter
+		}
+
 		endPoint += "/" + subquery
 	}
 	req := g.prepareRequest(endPoint)
@@ -41,13 +61,94 @@
 	return nil
 }
 
+// updateStatusData updates the statuses
+// The subquery can be empty or "status" (to post a status), "delete" (for
+// deleting a status), "reblog", "unreblog", "favourite", "unfavourite".
+// The data argument will receive the object(s) returned by the API server.
+func (g *Client) updateStatusData(subquery string, opts updateStatusOptions, data interface{}) error {
+	method := rest.Post
+	endPoint := "statuses"
+
+	switch subquery {
+	case "", "status":
+		subquery = "status"
+		if opts.Status == "" {
+			return ErrInvalidParameter
+		}
+		switch opts.Visibility {
+		case "", "direct", "private", "unlisted", "public":
+			// Okay
+		default:
+			return ErrInvalidParameter
+		}
+		if len(opts.MediaIDs) > 4 {
+			return fmt.Errorf("too many (>4) media IDs")
+		}
+	case "delete":
+		method = rest.Delete
+		if opts.ID < 1 {
+			return ErrInvalidID
+		}
+		endPoint += "/" + strconv.Itoa(opts.ID)
+	case "reblog", "unreblog", "favourite", "unfavourite":
+		if opts.ID < 1 {
+			return ErrInvalidID
+		}
+		endPoint += "/" + strconv.Itoa(opts.ID) + "/" + subquery
+	default:
+		return ErrInvalidParameter
+	}
+
+	req := g.prepareRequest(endPoint)
+	req.Method = method
+
+	// Form items for a new toot
+	if subquery == "status" {
+		req.QueryParams["status"] = opts.Status
+		if opts.InReplyToID > 0 {
+			req.QueryParams["in_reply_to_id"] = strconv.Itoa(opts.InReplyToID)
+		}
+		for i, id := range opts.MediaIDs {
+			qID := fmt.Sprintf("media_ids[%d]", i+1)
+			req.QueryParams[qID] = strconv.Itoa(id)
+		}
+		if opts.Sensitive {
+			req.QueryParams["sensitive"] = "true"
+		}
+		if opts.SpoilerText != "" {
+			req.QueryParams["spoiler_text"] = opts.SpoilerText
+		}
+		if opts.Visibility != "" {
+			req.QueryParams["visibility"] = opts.Visibility
+		}
+	}
+
+	r, err := rest.API(req)
+	if err != nil {
+		return fmt.Errorf("status/%s API query: %s", subquery, err.Error())
+	}
+
+	// Check for error reply
+	var errorResult Error
+	if err := json.Unmarshal([]byte(r.Body), &errorResult); err == nil {
+		return fmt.Errorf("%s", errorResult.Text)
+	}
+
+	// Not an error reply; let's unmarshall the data
+	err = json.Unmarshal([]byte(r.Body), &data)
+	if err != nil {
+		return fmt.Errorf("status/%s API: %s", subquery, err.Error())
+	}
+	return nil
+}
+
 // GetStatus returns a status
 // The returned status can be nil if there is an error or if the
 // requested ID does not exist.
 func (g *Client) GetStatus(id int) (*Status, error) {
 	var status Status
 
-	if err := g.queryStatusData(id, "", &status); err != nil {
+	if err := g.queryStatusData(id, "status", &status); err != nil {
 		return nil, err
 	}
 
@@ -93,3 +194,67 @@
 	err := g.queryStatusData(id, "favourited_by", &accounts)
 	return accounts, err
 }
+
+// PostStatus posts a new "toot"
+// All parameters but "text" can be empty.
+// Visibility must be empty, or one of "direct", "private", "unlisted" and "public".
+func (g *Client) PostStatus(text string, inReplyTo int, mediaIDs []int, sensitive bool, spoilerText string, visibility string) (*Status, error) {
+	var status Status
+	o := updateStatusOptions{
+		Status:      text,
+		InReplyToID: inReplyTo,
+		MediaIDs:    mediaIDs,
+		Sensitive:   sensitive,
+		SpoilerText: spoilerText,
+		Visibility:  visibility,
+	}
+
+	err := g.updateStatusData("status", o, &status)
+	if err != nil {
+		return nil, err
+	}
+	if status.ID == 0 {
+		return nil, ErrEntityNotFound // TODO Change error message
+	}
+	return &status, err
+}
+
+// DeleteStatus deletes a status
+func (g *Client) DeleteStatus(id int) error {
+	var status Status
+	o := updateStatusOptions{ID: id}
+	err := g.updateStatusData("delete", o, &status)
+	return err
+}
+
+// ReblogStatus reblogs a status
+func (g *Client) ReblogStatus(id int) error {
+	var status Status
+	o := updateStatusOptions{ID: id}
+	err := g.updateStatusData("reblog", o, &status)
+	return err
+}
+
+// UnreblogStatus unreblogs a status
+func (g *Client) UnreblogStatus(id int) error {
+	var status Status
+	o := updateStatusOptions{ID: id}
+	err := g.updateStatusData("unreblog", o, &status)
+	return err
+}
+
+// FavouriteStatus favourites a status
+func (g *Client) FavouriteStatus(id int) error {
+	var status Status
+	o := updateStatusOptions{ID: id}
+	err := g.updateStatusData("favourite", o, &status)
+	return err
+}
+
+// UnfavouriteStatus unfavourites a status
+func (g *Client) UnfavouriteStatus(id int) error {
+	var status Status
+	o := updateStatusOptions{ID: id}
+	err := g.updateStatusData("unfavourite", o, &status)
+	return err
+}