diff options
Diffstat (limited to 'mastodon/accounts.go')
-rw-r--r-- | mastodon/accounts.go | 175 |
1 files changed, 141 insertions, 34 deletions
diff --git a/mastodon/accounts.go b/mastodon/accounts.go index dbd0a48..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 } @@ -244,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 { |