status.go
changeset 105 e2a16e19eb8b
parent 103 9860bb68a0a6
child 106 356507eb8db6
equal deleted inserted replaced
104:fc338e606d37 105:e2a16e19eb8b
     6 	"strconv"
     6 	"strconv"
     7 
     7 
     8 	"github.com/sendgrid/rest"
     8 	"github.com/sendgrid/rest"
     9 )
     9 )
    10 
    10 
       
    11 // updateStatusOptions contains option field for POST and DELETE API calls
       
    12 type updateStatusOptions struct {
       
    13 	// The ID is used for most commands
       
    14 	ID int
       
    15 
       
    16 	// The following fields are used for posting a new status
       
    17 	Status      string
       
    18 	InReplyToID int
       
    19 	MediaIDs    []int
       
    20 	Sensitive   bool
       
    21 	SpoilerText string
       
    22 	Visibility  string // "direct", "private", "unlisted" or "public"
       
    23 }
       
    24 
    11 // queryStatusData queries the statuses API
    25 // queryStatusData queries the statuses API
    12 // The subquery can be empty (the status itself), "context", "card",
    26 // The subquery can be empty or "status" (the status itself), "context",
    13 // "reblogged_by", "favourited_by".
    27 // "card", "reblogged_by", "favourited_by".
       
    28 // The data argument will receive the object(s) returned by the API server.
    14 func (g *Client) queryStatusData(statusID int, subquery string, data interface{}) error {
    29 func (g *Client) queryStatusData(statusID int, subquery string, data interface{}) error {
    15 	endPoint := "statuses/" + strconv.Itoa(statusID)
    30 	endPoint := "statuses/" + strconv.Itoa(statusID)
    16 
    31 
    17 	if statusID < 1 {
    32 	if statusID < 1 {
    18 		return ErrInvalidID
    33 		return ErrInvalidID
    19 	}
    34 	}
    20 
    35 
    21 	if subquery != "" {
    36 	if subquery != "" && subquery != "status" {
    22 		// TODO: check subquery values?
    37 		switch subquery {
       
    38 		case "context", "card", "reblogged_by", "favourited_by":
       
    39 		default:
       
    40 			return ErrInvalidParameter
       
    41 		}
       
    42 
    23 		endPoint += "/" + subquery
    43 		endPoint += "/" + subquery
    24 	}
    44 	}
    25 	req := g.prepareRequest(endPoint)
    45 	req := g.prepareRequest(endPoint)
    26 	r, err := rest.API(req)
    46 	r, err := rest.API(req)
    27 	if err != nil {
    47 	if err != nil {
    39 	}
    59 	}
    40 
    60 
    41 	return nil
    61 	return nil
    42 }
    62 }
    43 
    63 
       
    64 // updateStatusData updates the statuses
       
    65 // The subquery can be empty or "status" (to post a status), "delete" (for
       
    66 // deleting a status), "reblog", "unreblog", "favourite", "unfavourite".
       
    67 // The data argument will receive the object(s) returned by the API server.
       
    68 func (g *Client) updateStatusData(subquery string, opts updateStatusOptions, data interface{}) error {
       
    69 	method := rest.Post
       
    70 	endPoint := "statuses"
       
    71 
       
    72 	switch subquery {
       
    73 	case "", "status":
       
    74 		subquery = "status"
       
    75 		if opts.Status == "" {
       
    76 			return ErrInvalidParameter
       
    77 		}
       
    78 		switch opts.Visibility {
       
    79 		case "", "direct", "private", "unlisted", "public":
       
    80 			// Okay
       
    81 		default:
       
    82 			return ErrInvalidParameter
       
    83 		}
       
    84 		if len(opts.MediaIDs) > 4 {
       
    85 			return fmt.Errorf("too many (>4) media IDs")
       
    86 		}
       
    87 	case "delete":
       
    88 		method = rest.Delete
       
    89 		if opts.ID < 1 {
       
    90 			return ErrInvalidID
       
    91 		}
       
    92 		endPoint += "/" + strconv.Itoa(opts.ID)
       
    93 	case "reblog", "unreblog", "favourite", "unfavourite":
       
    94 		if opts.ID < 1 {
       
    95 			return ErrInvalidID
       
    96 		}
       
    97 		endPoint += "/" + strconv.Itoa(opts.ID) + "/" + subquery
       
    98 	default:
       
    99 		return ErrInvalidParameter
       
   100 	}
       
   101 
       
   102 	req := g.prepareRequest(endPoint)
       
   103 	req.Method = method
       
   104 
       
   105 	// Form items for a new toot
       
   106 	if subquery == "status" {
       
   107 		req.QueryParams["status"] = opts.Status
       
   108 		if opts.InReplyToID > 0 {
       
   109 			req.QueryParams["in_reply_to_id"] = strconv.Itoa(opts.InReplyToID)
       
   110 		}
       
   111 		for i, id := range opts.MediaIDs {
       
   112 			qID := fmt.Sprintf("media_ids[%d]", i+1)
       
   113 			req.QueryParams[qID] = strconv.Itoa(id)
       
   114 		}
       
   115 		if opts.Sensitive {
       
   116 			req.QueryParams["sensitive"] = "true"
       
   117 		}
       
   118 		if opts.SpoilerText != "" {
       
   119 			req.QueryParams["spoiler_text"] = opts.SpoilerText
       
   120 		}
       
   121 		if opts.Visibility != "" {
       
   122 			req.QueryParams["visibility"] = opts.Visibility
       
   123 		}
       
   124 	}
       
   125 
       
   126 	r, err := rest.API(req)
       
   127 	if err != nil {
       
   128 		return fmt.Errorf("status/%s API query: %s", subquery, err.Error())
       
   129 	}
       
   130 
       
   131 	// Check for error reply
       
   132 	var errorResult Error
       
   133 	if err := json.Unmarshal([]byte(r.Body), &errorResult); err == nil {
       
   134 		return fmt.Errorf("%s", errorResult.Text)
       
   135 	}
       
   136 
       
   137 	// Not an error reply; let's unmarshall the data
       
   138 	err = json.Unmarshal([]byte(r.Body), &data)
       
   139 	if err != nil {
       
   140 		return fmt.Errorf("status/%s API: %s", subquery, err.Error())
       
   141 	}
       
   142 	return nil
       
   143 }
       
   144 
    44 // GetStatus returns a status
   145 // GetStatus returns a status
    45 // The returned status can be nil if there is an error or if the
   146 // The returned status can be nil if there is an error or if the
    46 // requested ID does not exist.
   147 // requested ID does not exist.
    47 func (g *Client) GetStatus(id int) (*Status, error) {
   148 func (g *Client) GetStatus(id int) (*Status, error) {
    48 	var status Status
   149 	var status Status
    49 
   150 
    50 	if err := g.queryStatusData(id, "", &status); err != nil {
   151 	if err := g.queryStatusData(id, "status", &status); err != nil {
    51 		return nil, err
   152 		return nil, err
    52 	}
   153 	}
    53 
   154 
    54 	if status.ID == 0 {
   155 	if status.ID == 0 {
    55 		return nil, ErrEntityNotFound
   156 		return nil, ErrEntityNotFound
    91 func (g *Client) GetStatusFavouritedBy(id int) ([]Account, error) {
   192 func (g *Client) GetStatusFavouritedBy(id int) ([]Account, error) {
    92 	var accounts []Account
   193 	var accounts []Account
    93 	err := g.queryStatusData(id, "favourited_by", &accounts)
   194 	err := g.queryStatusData(id, "favourited_by", &accounts)
    94 	return accounts, err
   195 	return accounts, err
    95 }
   196 }
       
   197 
       
   198 // PostStatus posts a new "toot"
       
   199 // All parameters but "text" can be empty.
       
   200 // Visibility must be empty, or one of "direct", "private", "unlisted" and "public".
       
   201 func (g *Client) PostStatus(text string, inReplyTo int, mediaIDs []int, sensitive bool, spoilerText string, visibility string) (*Status, error) {
       
   202 	var status Status
       
   203 	o := updateStatusOptions{
       
   204 		Status:      text,
       
   205 		InReplyToID: inReplyTo,
       
   206 		MediaIDs:    mediaIDs,
       
   207 		Sensitive:   sensitive,
       
   208 		SpoilerText: spoilerText,
       
   209 		Visibility:  visibility,
       
   210 	}
       
   211 
       
   212 	err := g.updateStatusData("status", o, &status)
       
   213 	if err != nil {
       
   214 		return nil, err
       
   215 	}
       
   216 	if status.ID == 0 {
       
   217 		return nil, ErrEntityNotFound // TODO Change error message
       
   218 	}
       
   219 	return &status, err
       
   220 }
       
   221 
       
   222 // DeleteStatus deletes a status
       
   223 func (g *Client) DeleteStatus(id int) error {
       
   224 	var status Status
       
   225 	o := updateStatusOptions{ID: id}
       
   226 	err := g.updateStatusData("delete", o, &status)
       
   227 	return err
       
   228 }
       
   229 
       
   230 // ReblogStatus reblogs a status
       
   231 func (g *Client) ReblogStatus(id int) error {
       
   232 	var status Status
       
   233 	o := updateStatusOptions{ID: id}
       
   234 	err := g.updateStatusData("reblog", o, &status)
       
   235 	return err
       
   236 }
       
   237 
       
   238 // UnreblogStatus unreblogs a status
       
   239 func (g *Client) UnreblogStatus(id int) error {
       
   240 	var status Status
       
   241 	o := updateStatusOptions{ID: id}
       
   242 	err := g.updateStatusData("unreblog", o, &status)
       
   243 	return err
       
   244 }
       
   245 
       
   246 // FavouriteStatus favourites a status
       
   247 func (g *Client) FavouriteStatus(id int) error {
       
   248 	var status Status
       
   249 	o := updateStatusOptions{ID: id}
       
   250 	err := g.updateStatusData("favourite", o, &status)
       
   251 	return err
       
   252 }
       
   253 
       
   254 // UnfavouriteStatus unfavourites a status
       
   255 func (g *Client) UnfavouriteStatus(id int) error {
       
   256 	var status Status
       
   257 	o := updateStatusOptions{ID: id}
       
   258 	err := g.updateStatusData("unfavourite", o, &status)
       
   259 	return err
       
   260 }