aboutsummaryrefslogtreecommitdiff
path: root/mastodon/accounts.go
diff options
context:
space:
mode:
Diffstat (limited to 'mastodon/accounts.go')
-rw-r--r--mastodon/accounts.go176
1 files changed, 142 insertions, 34 deletions
diff --git a/mastodon/accounts.go b/mastodon/accounts.go
index df0a3b7..31021fd 100644
--- a/mastodon/accounts.go
+++ b/mastodon/accounts.go
@@ -1,16 +1,20 @@
package mastodon
import (
+ "bytes"
"context"
"fmt"
+ "io"
+ "mime/multipart"
"net/http"
"net/url"
+ "path/filepath"
"strconv"
"time"
)
type AccountPleroma struct {
- Relationship Relationship `json:"relationship"`
+ Relationship *Relationship `json:"relationship"`
}
// Account hold information for mastodon account.
@@ -34,7 +38,11 @@ type Account struct {
Moved *Account `json:"moved"`
Fields []Field `json:"fields"`
Bot bool `json:"bot"`
+ Source *AccountSource `json:"source"`
Pleroma *AccountPleroma `json:"pleroma"`
+
+ // Duplicate field for compatibilty with Pleroma
+ FollowRequestsCount int64 `json:"follow_requests_count"`
}
// Field is a Mastodon account profile field.
@@ -46,17 +54,20 @@ type Field struct {
// AccountSource is a Mastodon account profile field.
type AccountSource struct {
- Privacy *string `json:"privacy"`
- Sensitive *bool `json:"sensitive"`
- Language *string `json:"language"`
- Note *string `json:"note"`
- Fields *[]Field `json:"fields"`
+ Privacy *string `json:"privacy"`
+ Sensitive *bool `json:"sensitive"`
+ Language *string `json:"language"`
+ Note *string `json:"note"`
+ Fields *[]Field `json:"fields"`
+ FollowRequestsCount int64 `json:"follow_requests_count"`
}
// GetAccount return Account.
func (c *Client) GetAccount(ctx context.Context, id string) (*Account, error) {
var account Account
- err := c.doAPI(ctx, http.MethodGet, fmt.Sprintf("/api/v1/accounts/%s", url.PathEscape(string(id))), nil, &account, nil)
+ params := url.Values{}
+ params.Set("with_relationships", strconv.FormatBool(true))
+ err := c.doAPI(ctx, http.MethodGet, fmt.Sprintf("/api/v1/accounts/%s", url.PathEscape(string(id))), params, &account, nil)
if err != nil {
return nil, err
}
@@ -66,7 +77,7 @@ func (c *Client) GetAccount(ctx context.Context, id string) (*Account, error) {
return nil, err
}
if len(rs) > 0 {
- account.Pleroma = &AccountPleroma{*rs[0]}
+ account.Pleroma = &AccountPleroma{rs[0]}
}
}
return &account, nil
@@ -93,54 +104,115 @@ type Profile struct {
Source *AccountSource
// Set the base64 encoded character string of the image.
- Avatar string
- Header string
+ Avatar *multipart.FileHeader
+ Header *multipart.FileHeader
}
// AccountUpdate updates the information of the current user.
func (c *Client) AccountUpdate(ctx context.Context, profile *Profile) (*Account, error) {
- params := url.Values{}
+ var buf bytes.Buffer
+ mw := multipart.NewWriter(&buf)
if profile.DisplayName != nil {
- params.Set("display_name", *profile.DisplayName)
+ err := mw.WriteField("display_name", *profile.DisplayName)
+ if err != nil {
+ return nil, err
+ }
}
if profile.Note != nil {
- params.Set("note", *profile.Note)
+ err := mw.WriteField("note", *profile.Note)
+ if err != nil {
+ return nil, err
+ }
}
if profile.Locked != nil {
- params.Set("locked", strconv.FormatBool(*profile.Locked))
+ err := mw.WriteField("locked", strconv.FormatBool(*profile.Locked))
+ if err != nil {
+ return nil, err
+ }
}
if profile.Fields != nil {
for idx, field := range *profile.Fields {
- params.Set(fmt.Sprintf("fields_attributes[%d][name]", idx), field.Name)
- params.Set(fmt.Sprintf("fields_attributes[%d][value]", idx), field.Value)
+ err := mw.WriteField(fmt.Sprintf("fields_attributes[%d][name]", idx), field.Name)
+ if err != nil {
+ return nil, err
+ }
+ err = mw.WriteField(fmt.Sprintf("fields_attributes[%d][value]", idx), field.Value)
+ if err != nil {
+ return nil, err
+ }
}
}
- if profile.Source != nil {
- if profile.Source.Privacy != nil {
- params.Set("source[privacy]", *profile.Source.Privacy)
+ if profile.Avatar != nil {
+ f, err := profile.Avatar.Open()
+ if err != nil {
+ return nil, err
}
- if profile.Source.Sensitive != nil {
- params.Set("source[sensitive]", strconv.FormatBool(*profile.Source.Sensitive))
+ fname := filepath.Base(profile.Avatar.Filename)
+ part, err := mw.CreateFormFile("avatar", fname)
+ if err != nil {
+ return nil, err
}
- if profile.Source.Language != nil {
- params.Set("source[language]", *profile.Source.Language)
+ _, err = io.Copy(part, f)
+ if err != nil {
+ return nil, err
+ }
+ }
+ if profile.Header != nil {
+ f, err := profile.Header.Open()
+ if err != nil {
+ return nil, err
+ }
+ fname := filepath.Base(profile.Header.Filename)
+ part, err := mw.CreateFormFile("header", fname)
+ if err != nil {
+ return nil, err
+ }
+ _, err = io.Copy(part, f)
+ if err != nil {
+ return nil, err
}
}
- if profile.Avatar != "" {
- params.Set("avatar", profile.Avatar)
+ err := mw.Close()
+ if err != nil {
+ return nil, err
}
- if profile.Header != "" {
- params.Set("header", profile.Header)
+ params := &multipartRequest{Data: &buf, ContentType: mw.FormDataContentType()}
+ var account Account
+ err = c.doAPI(ctx, http.MethodPatch, "/api/v1/accounts/update_credentials", params, &account, nil)
+ if err != nil {
+ return nil, err
}
+ return &account, nil
+}
+func (c *Client) accountDeleteField(ctx context.Context, field string) (*Account, error) {
+ var buf bytes.Buffer
+ mw := multipart.NewWriter(&buf)
+ _, err := mw.CreateFormField(field)
+ if err != nil {
+ return nil, err
+ }
+ err = mw.Close()
+ if err != nil {
+ return nil, err
+ }
+ params := &multipartRequest{Data: &buf, ContentType: mw.FormDataContentType()}
var account Account
- err := c.doAPI(ctx, http.MethodPatch, "/api/v1/accounts/update_credentials", params, &account, nil)
+ err = c.doAPI(ctx, http.MethodPatch, "/api/v1/accounts/update_credentials", params, &account, nil)
if err != nil {
return nil, err
}
return &account, nil
}
+func (c *Client) AccountDeleteAvatar(ctx context.Context) (*Account, error) {
+ return c.accountDeleteField(ctx, "avatar")
+}
+
+func (c *Client) AccountDeleteHeader(ctx context.Context) (*Account, error) {
+ return c.accountDeleteField(ctx, "header")
+}
+
// GetAccountStatuses return statuses by specified accuont.
func (c *Client) GetAccountStatuses(ctx context.Context, id string, onlyMedia bool, pg *Pagination) ([]*Status, error) {
var statuses []*Status
@@ -153,10 +225,40 @@ func (c *Client) GetAccountStatuses(ctx context.Context, id string, onlyMedia bo
return statuses, nil
}
+func (c *Client) getMissingRelationships(ctx context.Context, accounts []*Account) ([]*Account, error) {
+ var ids []string
+ for _, a := range accounts {
+ if a.Pleroma == nil || len(a.Pleroma.Relationship.ID) < 1 {
+ ids = append(ids, a.ID)
+ }
+ }
+ if len(ids) < 1 {
+ return accounts, nil
+ }
+ rs, err := c.GetAccountRelationships(ctx, ids)
+ if err != nil {
+ return nil, err
+ }
+ rsm := make(map[string]*Relationship, len(rs))
+ for _, r := range rs {
+ rsm[r.ID] = r
+ }
+ for _, a := range accounts {
+ a.Pleroma = &AccountPleroma{rsm[a.ID]}
+ }
+ return accounts, nil
+}
+
// GetAccountFollowers return followers list.
func (c *Client) GetAccountFollowers(ctx context.Context, id string, pg *Pagination) ([]*Account, error) {
var accounts []*Account
- err := c.doAPI(ctx, http.MethodGet, fmt.Sprintf("/api/v1/accounts/%s/followers", url.PathEscape(string(id))), nil, &accounts, pg)
+ params := url.Values{}
+ params.Set("with_relationships", strconv.FormatBool(true))
+ err := c.doAPI(ctx, http.MethodGet, fmt.Sprintf("/api/v1/accounts/%s/followers", url.PathEscape(string(id))), params, &accounts, pg)
+ if err != nil {
+ return nil, err
+ }
+ accounts, err = c.getMissingRelationships(ctx, accounts)
if err != nil {
return nil, err
}
@@ -166,7 +268,13 @@ func (c *Client) GetAccountFollowers(ctx context.Context, id string, pg *Paginat
// GetAccountFollowing return following list.
func (c *Client) GetAccountFollowing(ctx context.Context, id string, pg *Pagination) ([]*Account, error) {
var accounts []*Account
- err := c.doAPI(ctx, http.MethodGet, fmt.Sprintf("/api/v1/accounts/%s/following", url.PathEscape(string(id))), nil, &accounts, pg)
+ params := url.Values{}
+ params.Set("with_relationships", strconv.FormatBool(true))
+ err := c.doAPI(ctx, http.MethodGet, fmt.Sprintf("/api/v1/accounts/%s/following", url.PathEscape(string(id))), params, &accounts, pg)
+ if err != nil {
+ return nil, err
+ }
+ accounts, err = c.getMissingRelationships(ctx, accounts)
if err != nil {
return nil, err
}
@@ -189,6 +297,7 @@ type Relationship struct {
Following bool `json:"following"`
FollowedBy bool `json:"followed_by"`
Blocking bool `json:"blocking"`
+ BlockedBy bool `json:"blocked_by"`
Muting bool `json:"muting"`
MutingNotifications bool `json:"muting_notifications"`
Subscribing bool `json:"subscribing"`
@@ -243,11 +352,10 @@ func (c *Client) AccountUnblock(ctx context.Context, id string) (*Relationship,
}
// AccountMute mute the account.
-func (c *Client) AccountMute(ctx context.Context, id string, notifications *bool) (*Relationship, error) {
+func (c *Client) AccountMute(ctx context.Context, id string, notifications bool, duration int) (*Relationship, error) {
params := url.Values{}
- if notifications != nil {
- params.Set("notifications", strconv.FormatBool(*notifications))
- }
+ params.Set("notifications", strconv.FormatBool(notifications))
+ params.Set("duration", strconv.Itoa(duration))
var relationship Relationship
err := c.doAPI(ctx, http.MethodPost, fmt.Sprintf("/api/v1/accounts/%s/mute", url.PathEscape(string(id))), params, &relationship, nil)
if err != nil {