diff options
author | 2021-04-19 19:42:19 +0200 | |
---|---|---|
committer | 2021-04-19 19:42:19 +0200 | |
commit | 32c5fd987a06e11b14a4247d13187657c14adedd (patch) | |
tree | f5b787ca0f020bea5fd020925e52d3592a77a6ad /internal/mastotypes | |
parent | Api/v1/accounts (#8) (diff) | |
download | gotosocial-32c5fd987a06e11b14a4247d13187657c14adedd.tar.xz |
Api/v1/statuses (#11)
This PR adds:
Statuses
New status creation.
View existing status
Delete a status
Fave a status
Unfave a status
See who's faved a status
Media
Upload media attachment and store/retrieve it
Upload custom emoji and store/retrieve it
Fileserver
Serve files from storage
Testing
Test models, testrig -- run a GTS test instance and play around with it.
Diffstat (limited to 'internal/mastotypes')
36 files changed, 2278 insertions, 0 deletions
diff --git a/internal/mastotypes/converter.go b/internal/mastotypes/converter.go new file mode 100644 index 000000000..e689b62da --- /dev/null +++ b/internal/mastotypes/converter.go @@ -0,0 +1,544 @@ +/* + GoToSocial + Copyright (C) 2021 GoToSocial Authors admin@gotosocial.org + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +package mastotypes + +import ( + "fmt" + "time" + + "github.com/superseriousbusiness/gotosocial/internal/config" + "github.com/superseriousbusiness/gotosocial/internal/db" + "github.com/superseriousbusiness/gotosocial/internal/db/gtsmodel" + mastotypes "github.com/superseriousbusiness/gotosocial/internal/mastotypes/mastomodel" + "github.com/superseriousbusiness/gotosocial/internal/util" +) + +// Converter is an interface for the common action of converting between mastotypes (frontend, serializable) models and internal gts models used in the database. +// It requires access to the database because many of the conversions require pulling out database entries and counting them etc. +type Converter interface { + // AccountToMastoSensitive takes a db model account as a param, and returns a populated mastotype account, or an error + // if something goes wrong. The returned account should be ready to serialize on an API level, and may have sensitive fields, + // so serve it only to an authorized user who should have permission to see it. + AccountToMastoSensitive(account *gtsmodel.Account) (*mastotypes.Account, error) + + // AccountToMastoPublic takes a db model account as a param, and returns a populated mastotype account, or an error + // if something goes wrong. The returned account should be ready to serialize on an API level, and may NOT have sensitive fields. + // In other words, this is the public record that the server has of an account. + AccountToMastoPublic(account *gtsmodel.Account) (*mastotypes.Account, error) + + // AppToMastoSensitive takes a db model application as a param, and returns a populated mastotype application, or an error + // if something goes wrong. The returned application should be ready to serialize on an API level, and may have sensitive fields + // (such as client id and client secret), so serve it only to an authorized user who should have permission to see it. + AppToMastoSensitive(application *gtsmodel.Application) (*mastotypes.Application, error) + + // AppToMastoPublic takes a db model application as a param, and returns a populated mastotype application, or an error + // if something goes wrong. The returned application should be ready to serialize on an API level, and has sensitive + // fields sanitized so that it can be served to non-authorized accounts without revealing any private information. + AppToMastoPublic(application *gtsmodel.Application) (*mastotypes.Application, error) + + // AttachmentToMasto converts a gts model media attacahment into its mastodon representation for serialization on the API. + AttachmentToMasto(attachment *gtsmodel.MediaAttachment) (mastotypes.Attachment, error) + + // MentionToMasto converts a gts model mention into its mastodon (frontend) representation for serialization on the API. + MentionToMasto(m *gtsmodel.Mention) (mastotypes.Mention, error) + + // EmojiToMasto converts a gts model emoji into its mastodon (frontend) representation for serialization on the API. + EmojiToMasto(e *gtsmodel.Emoji) (mastotypes.Emoji, error) + + // TagToMasto converts a gts model tag into its mastodon (frontend) representation for serialization on the API. + TagToMasto(t *gtsmodel.Tag) (mastotypes.Tag, error) + + // StatusToMasto converts a gts model status into its mastodon (frontend) representation for serialization on the API. + StatusToMasto(s *gtsmodel.Status, targetAccount *gtsmodel.Account, requestingAccount *gtsmodel.Account, boostOfAccount *gtsmodel.Account, replyToAccount *gtsmodel.Account, reblogOfStatus *gtsmodel.Status) (*mastotypes.Status, error) +} + +type converter struct { + config *config.Config + db db.DB +} + +// New returns a new Converter +func New(config *config.Config, db db.DB) Converter { + return &converter{ + config: config, + db: db, + } +} + +func (c *converter) AccountToMastoSensitive(a *gtsmodel.Account) (*mastotypes.Account, error) { + // we can build this sensitive account easily by first getting the public account.... + mastoAccount, err := c.AccountToMastoPublic(a) + if err != nil { + return nil, err + } + + // then adding the Source object to it... + + // check pending follow requests aimed at this account + fr := []gtsmodel.FollowRequest{} + if err := c.db.GetFollowRequestsForAccountID(a.ID, &fr); err != nil { + if _, ok := err.(db.ErrNoEntries); !ok { + return nil, fmt.Errorf("error getting follow requests: %s", err) + } + } + var frc int + if fr != nil { + frc = len(fr) + } + + mastoAccount.Source = &mastotypes.Source{ + Privacy: util.ParseMastoVisFromGTSVis(a.Privacy), + Sensitive: a.Sensitive, + Language: a.Language, + Note: a.Note, + Fields: mastoAccount.Fields, + FollowRequestsCount: frc, + } + + return mastoAccount, nil +} + +func (c *converter) AccountToMastoPublic(a *gtsmodel.Account) (*mastotypes.Account, error) { + // count followers + followers := []gtsmodel.Follow{} + if err := c.db.GetFollowersByAccountID(a.ID, &followers); err != nil { + if _, ok := err.(db.ErrNoEntries); !ok { + return nil, fmt.Errorf("error getting followers: %s", err) + } + } + var followersCount int + if followers != nil { + followersCount = len(followers) + } + + // count following + following := []gtsmodel.Follow{} + if err := c.db.GetFollowingByAccountID(a.ID, &following); err != nil { + if _, ok := err.(db.ErrNoEntries); !ok { + return nil, fmt.Errorf("error getting following: %s", err) + } + } + var followingCount int + if following != nil { + followingCount = len(following) + } + + // count statuses + statuses := []gtsmodel.Status{} + if err := c.db.GetStatusesByAccountID(a.ID, &statuses); err != nil { + if _, ok := err.(db.ErrNoEntries); !ok { + return nil, fmt.Errorf("error getting last statuses: %s", err) + } + } + var statusesCount int + if statuses != nil { + statusesCount = len(statuses) + } + + // check when the last status was + lastStatus := >smodel.Status{} + if err := c.db.GetLastStatusForAccountID(a.ID, lastStatus); err != nil { + if _, ok := err.(db.ErrNoEntries); !ok { + return nil, fmt.Errorf("error getting last status: %s", err) + } + } + var lastStatusAt string + if lastStatus != nil { + lastStatusAt = lastStatus.CreatedAt.Format(time.RFC3339) + } + + // build the avatar and header URLs + avi := >smodel.MediaAttachment{} + if err := c.db.GetAvatarForAccountID(avi, a.ID); err != nil { + if _, ok := err.(db.ErrNoEntries); !ok { + return nil, fmt.Errorf("error getting avatar: %s", err) + } + } + aviURL := avi.URL + aviURLStatic := avi.Thumbnail.URL + + header := >smodel.MediaAttachment{} + if err := c.db.GetHeaderForAccountID(avi, a.ID); err != nil { + if _, ok := err.(db.ErrNoEntries); !ok { + return nil, fmt.Errorf("error getting header: %s", err) + } + } + headerURL := header.URL + headerURLStatic := header.Thumbnail.URL + + // get the fields set on this account + fields := []mastotypes.Field{} + for _, f := range a.Fields { + mField := mastotypes.Field{ + Name: f.Name, + Value: f.Value, + } + if !f.VerifiedAt.IsZero() { + mField.VerifiedAt = f.VerifiedAt.Format(time.RFC3339) + } + fields = append(fields, mField) + } + + var acct string + if a.Domain != "" { + // this is a remote user + acct = fmt.Sprintf("%s@%s", a.Username, a.Domain) + } else { + // this is a local user + acct = a.Username + } + + return &mastotypes.Account{ + ID: a.ID, + Username: a.Username, + Acct: acct, + DisplayName: a.DisplayName, + Locked: a.Locked, + Bot: a.Bot, + CreatedAt: a.CreatedAt.Format(time.RFC3339), + Note: a.Note, + URL: a.URL, + Avatar: aviURL, + AvatarStatic: aviURLStatic, + Header: headerURL, + HeaderStatic: headerURLStatic, + FollowersCount: followersCount, + FollowingCount: followingCount, + StatusesCount: statusesCount, + LastStatusAt: lastStatusAt, + Emojis: nil, // TODO: implement this + Fields: fields, + }, nil +} + +func (c *converter) AppToMastoSensitive(a *gtsmodel.Application) (*mastotypes.Application, error) { + return &mastotypes.Application{ + ID: a.ID, + Name: a.Name, + Website: a.Website, + RedirectURI: a.RedirectURI, + ClientID: a.ClientID, + ClientSecret: a.ClientSecret, + VapidKey: a.VapidKey, + }, nil +} + +func (c *converter) AppToMastoPublic(a *gtsmodel.Application) (*mastotypes.Application, error) { + return &mastotypes.Application{ + Name: a.Name, + Website: a.Website, + }, nil +} + +func (c *converter) AttachmentToMasto(a *gtsmodel.MediaAttachment) (mastotypes.Attachment, error) { + return mastotypes.Attachment{ + ID: a.ID, + Type: string(a.Type), + URL: a.URL, + PreviewURL: a.Thumbnail.URL, + RemoteURL: a.RemoteURL, + PreviewRemoteURL: a.Thumbnail.RemoteURL, + Meta: mastotypes.MediaMeta{ + Original: mastotypes.MediaDimensions{ + Width: a.FileMeta.Original.Width, + Height: a.FileMeta.Original.Height, + Size: fmt.Sprintf("%dx%d", a.FileMeta.Original.Width, a.FileMeta.Original.Height), + Aspect: float32(a.FileMeta.Original.Aspect), + }, + Small: mastotypes.MediaDimensions{ + Width: a.FileMeta.Small.Width, + Height: a.FileMeta.Small.Height, + Size: fmt.Sprintf("%dx%d", a.FileMeta.Small.Width, a.FileMeta.Small.Height), + Aspect: float32(a.FileMeta.Small.Aspect), + }, + Focus: mastotypes.MediaFocus{ + X: a.FileMeta.Focus.X, + Y: a.FileMeta.Focus.Y, + }, + }, + Description: a.Description, + Blurhash: a.Blurhash, + }, nil +} + +func (c *converter) MentionToMasto(m *gtsmodel.Mention) (mastotypes.Mention, error) { + target := >smodel.Account{} + if err := c.db.GetByID(m.TargetAccountID, target); err != nil { + return mastotypes.Mention{}, err + } + + var local bool + if target.Domain == "" { + local = true + } + + var acct string + if local { + acct = fmt.Sprintf("@%s", target.Username) + } else { + acct = fmt.Sprintf("@%s@%s", target.Username, target.Domain) + } + + return mastotypes.Mention{ + ID: target.ID, + Username: target.Username, + URL: target.URL, + Acct: acct, + }, nil +} + +func (c *converter) EmojiToMasto(e *gtsmodel.Emoji) (mastotypes.Emoji, error) { + return mastotypes.Emoji{ + Shortcode: e.Shortcode, + URL: e.ImageURL, + StaticURL: e.ImageStaticURL, + VisibleInPicker: e.VisibleInPicker, + Category: e.CategoryID, + }, nil +} + +func (c *converter) TagToMasto(t *gtsmodel.Tag) (mastotypes.Tag, error) { + tagURL := fmt.Sprintf("%s://%s/tags/%s", c.config.Protocol, c.config.Host, t.Name) + + return mastotypes.Tag{ + Name: t.Name, + URL: tagURL, // we don't serve URLs with collections of tagged statuses (FOR NOW) so this is purely for mastodon compatibility ¯\_(ツ)_/¯ + }, nil +} + +func (c *converter) StatusToMasto( + s *gtsmodel.Status, + targetAccount *gtsmodel.Account, + requestingAccount *gtsmodel.Account, + boostOfAccount *gtsmodel.Account, + replyToAccount *gtsmodel.Account, + reblogOfStatus *gtsmodel.Status) (*mastotypes.Status, error) { + + repliesCount, err := c.db.GetReplyCountForStatus(s) + if err != nil { + return nil, fmt.Errorf("error counting replies: %s", err) + } + + reblogsCount, err := c.db.GetReblogCountForStatus(s) + if err != nil { + return nil, fmt.Errorf("error counting reblogs: %s", err) + } + + favesCount, err := c.db.GetFaveCountForStatus(s) + if err != nil { + return nil, fmt.Errorf("error counting faves: %s", err) + } + + var faved bool + var reblogged bool + var bookmarked bool + var pinned bool + var muted bool + + // requestingAccount will be nil for public requests without auth + // But if it's not nil, we can also get information about the requestingAccount's interaction with this status + if requestingAccount != nil { + faved, err = c.db.StatusFavedBy(s, requestingAccount.ID) + if err != nil { + return nil, fmt.Errorf("error checking if requesting account has faved status: %s", err) + } + + reblogged, err = c.db.StatusRebloggedBy(s, requestingAccount.ID) + if err != nil { + return nil, fmt.Errorf("error checking if requesting account has reblogged status: %s", err) + } + + muted, err = c.db.StatusMutedBy(s, requestingAccount.ID) + if err != nil { + return nil, fmt.Errorf("error checking if requesting account has muted status: %s", err) + } + + bookmarked, err = c.db.StatusBookmarkedBy(s, requestingAccount.ID) + if err != nil { + return nil, fmt.Errorf("error checking if requesting account has bookmarked status: %s", err) + } + + pinned, err = c.db.StatusPinnedBy(s, requestingAccount.ID) + if err != nil { + return nil, fmt.Errorf("error checking if requesting account has pinned status: %s", err) + } + } + + var mastoRebloggedStatus *mastotypes.Status // TODO + + var mastoApplication *mastotypes.Application + if s.CreatedWithApplicationID != "" { + gtsApplication := >smodel.Application{} + if err := c.db.GetByID(s.CreatedWithApplicationID, gtsApplication); err != nil { + return nil, fmt.Errorf("error fetching application used to create status: %s", err) + } + mastoApplication, err = c.AppToMastoPublic(gtsApplication) + if err != nil { + return nil, fmt.Errorf("error parsing application used to create status: %s", err) + } + } + + mastoTargetAccount, err := c.AccountToMastoPublic(targetAccount) + if err != nil { + return nil, fmt.Errorf("error parsing account of status author: %s", err) + } + + mastoAttachments := []mastotypes.Attachment{} + // the status might already have some gts attachments on it if it's not been pulled directly from the database + // if so, we can directly convert the gts attachments into masto ones + if s.GTSMediaAttachments != nil { + for _, gtsAttachment := range s.GTSMediaAttachments { + mastoAttachment, err := c.AttachmentToMasto(gtsAttachment) + if err != nil { + return nil, fmt.Errorf("error converting attachment with id %s: %s", gtsAttachment.ID, err) + } + mastoAttachments = append(mastoAttachments, mastoAttachment) + } + // the status doesn't have gts attachments on it, but it does have attachment IDs + // in this case, we need to pull the gts attachments from the db to convert them into masto ones + } else { + for _, a := range s.Attachments { + gtsAttachment := >smodel.MediaAttachment{} + if err := c.db.GetByID(a, gtsAttachment); err != nil { + return nil, fmt.Errorf("error getting attachment with id %s: %s", a, err) + } + mastoAttachment, err := c.AttachmentToMasto(gtsAttachment) + if err != nil { + return nil, fmt.Errorf("error converting attachment with id %s: %s", a, err) + } + mastoAttachments = append(mastoAttachments, mastoAttachment) + } + } + + mastoMentions := []mastotypes.Mention{} + // the status might already have some gts mentions on it if it's not been pulled directly from the database + // if so, we can directly convert the gts mentions into masto ones + if s.GTSMentions != nil { + for _, gtsMention := range s.GTSMentions { + mastoMention, err := c.MentionToMasto(gtsMention) + if err != nil { + return nil, fmt.Errorf("error converting mention with id %s: %s", gtsMention.ID, err) + } + mastoMentions = append(mastoMentions, mastoMention) + } + // the status doesn't have gts mentions on it, but it does have mention IDs + // in this case, we need to pull the gts mentions from the db to convert them into masto ones + } else { + for _, m := range s.Mentions { + gtsMention := >smodel.Mention{} + if err := c.db.GetByID(m, gtsMention); err != nil { + return nil, fmt.Errorf("error getting mention with id %s: %s", m, err) + } + mastoMention, err := c.MentionToMasto(gtsMention) + if err != nil { + return nil, fmt.Errorf("error converting mention with id %s: %s", gtsMention.ID, err) + } + mastoMentions = append(mastoMentions, mastoMention) + } + } + + mastoTags := []mastotypes.Tag{} + // the status might already have some gts tags on it if it's not been pulled directly from the database + // if so, we can directly convert the gts tags into masto ones + if s.GTSTags != nil { + for _, gtsTag := range s.GTSTags { + mastoTag, err := c.TagToMasto(gtsTag) + if err != nil { + return nil, fmt.Errorf("error converting tag with id %s: %s", gtsTag.ID, err) + } + mastoTags = append(mastoTags, mastoTag) + } + // the status doesn't have gts tags on it, but it does have tag IDs + // in this case, we need to pull the gts tags from the db to convert them into masto ones + } else { + for _, t := range s.Tags { + gtsTag := >smodel.Tag{} + if err := c.db.GetByID(t, gtsTag); err != nil { + return nil, fmt.Errorf("error getting tag with id %s: %s", t, err) + } + mastoTag, err := c.TagToMasto(gtsTag) + if err != nil { + return nil, fmt.Errorf("error converting tag with id %s: %s", gtsTag.ID, err) + } + mastoTags = append(mastoTags, mastoTag) + } + } + + mastoEmojis := []mastotypes.Emoji{} + // the status might already have some gts emojis on it if it's not been pulled directly from the database + // if so, we can directly convert the gts emojis into masto ones + if s.GTSEmojis != nil { + for _, gtsEmoji := range s.GTSEmojis { + mastoEmoji, err := c.EmojiToMasto(gtsEmoji) + if err != nil { + return nil, fmt.Errorf("error converting emoji with id %s: %s", gtsEmoji.ID, err) + } + mastoEmojis = append(mastoEmojis, mastoEmoji) + } + // the status doesn't have gts emojis on it, but it does have emoji IDs + // in this case, we need to pull the gts emojis from the db to convert them into masto ones + } else { + for _, e := range s.Emojis { + gtsEmoji := >smodel.Emoji{} + if err := c.db.GetByID(e, gtsEmoji); err != nil { + return nil, fmt.Errorf("error getting emoji with id %s: %s", e, err) + } + mastoEmoji, err := c.EmojiToMasto(gtsEmoji) + if err != nil { + return nil, fmt.Errorf("error converting emoji with id %s: %s", gtsEmoji.ID, err) + } + mastoEmojis = append(mastoEmojis, mastoEmoji) + } + } + + var mastoCard *mastotypes.Card + var mastoPoll *mastotypes.Poll + + return &mastotypes.Status{ + ID: s.ID, + CreatedAt: s.CreatedAt.Format(time.RFC3339), + InReplyToID: s.InReplyToID, + InReplyToAccountID: s.InReplyToAccountID, + Sensitive: s.Sensitive, + SpoilerText: s.ContentWarning, + Visibility: util.ParseMastoVisFromGTSVis(s.Visibility), + Language: s.Language, + URI: s.URI, + URL: s.URL, + RepliesCount: repliesCount, + ReblogsCount: reblogsCount, + FavouritesCount: favesCount, + Favourited: faved, + Reblogged: reblogged, + Muted: muted, + Bookmarked: bookmarked, + Pinned: pinned, + Content: s.Content, + Reblog: mastoRebloggedStatus, + Application: mastoApplication, + Account: mastoTargetAccount, + MediaAttachments: mastoAttachments, + Mentions: mastoMentions, + Tags: mastoTags, + Emojis: mastoEmojis, + Card: mastoCard, // TODO: implement cards + Poll: mastoPoll, // TODO: implement polls + Text: s.Text, + }, nil +} diff --git a/internal/mastotypes/mastomodel/README.md b/internal/mastotypes/mastomodel/README.md new file mode 100644 index 000000000..38f9e89c4 --- /dev/null +++ b/internal/mastotypes/mastomodel/README.md @@ -0,0 +1,5 @@ +# Mastotypes + +This package contains Go types/structs for Mastodon's REST API. + +See [here](https://docs.joinmastodon.org/methods/apps/). diff --git a/internal/mastotypes/mastomodel/account.go b/internal/mastotypes/mastomodel/account.go new file mode 100644 index 000000000..bbcf9c90f --- /dev/null +++ b/internal/mastotypes/mastomodel/account.go @@ -0,0 +1,131 @@ +/* + GoToSocial + Copyright (C) 2021 GoToSocial Authors admin@gotosocial.org + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +package mastotypes + +import "mime/multipart" + +// Account represents a mastodon-api Account object, as described here: https://docs.joinmastodon.org/entities/account/ +type Account struct { + // The account id + ID string `json:"id"` + // The username of the account, not including domain. + Username string `json:"username"` + // The Webfinger account URI. Equal to username for local users, or username@domain for remote users. + Acct string `json:"acct"` + // The profile's display name. + DisplayName string `json:"display_name"` + // Whether the account manually approves follow requests. + Locked bool `json:"locked"` + // Whether the account has opted into discovery features such as the profile directory. + Discoverable bool `json:"discoverable,omitempty"` + // A presentational flag. Indicates that the account may perform automated actions, may not be monitored, or identifies as a robot. + Bot bool `json:"bot"` + // When the account was created. (ISO 8601 Datetime) + CreatedAt string `json:"created_at"` + // The profile's bio / description. + Note string `json:"note"` + // The location of the user's profile page. + URL string `json:"url"` + // An image icon that is shown next to statuses and in the profile. + Avatar string `json:"avatar"` + // A static version of the avatar. Equal to avatar if its value is a static image; different if avatar is an animated GIF. + AvatarStatic string `json:"avatar_static"` + // An image banner that is shown above the profile and in profile cards. + Header string `json:"header"` + // A static version of the header. Equal to header if its value is a static image; different if header is an animated GIF. + HeaderStatic string `json:"header_static"` + // The reported followers of this profile. + FollowersCount int `json:"followers_count"` + // The reported follows of this profile. + FollowingCount int `json:"following_count"` + // How many statuses are attached to this account. + StatusesCount int `json:"statuses_count"` + // When the most recent status was posted. (ISO 8601 Datetime) + LastStatusAt string `json:"last_status_at"` + // Custom emoji entities to be used when rendering the profile. If none, an empty array will be returned. + Emojis []Emoji `json:"emojis"` + // Additional metadata attached to a profile as name-value pairs. + Fields []Field `json:"fields"` + // An extra entity returned when an account is suspended. + Suspended bool `json:"suspended,omitempty"` + // When a timed mute will expire, if applicable. (ISO 8601 Datetime) + MuteExpiresAt string `json:"mute_expires_at,omitempty"` + // An extra entity to be used with API methods to verify credentials and update credentials. + Source *Source `json:"source,omitempty"` +} + +// AccountCreateRequest represents the form submitted during a POST request to /api/v1/accounts. +// See https://docs.joinmastodon.org/methods/accounts/ +type AccountCreateRequest struct { + // Text that will be reviewed by moderators if registrations require manual approval. + Reason string `form:"reason"` + // The desired username for the account + Username string `form:"username" binding:"required"` + // The email address to be used for login + Email string `form:"email" binding:"required"` + // The password to be used for login + Password string `form:"password" binding:"required"` + // Whether the user agrees to the local rules, terms, and policies. + // These should be presented to the user in order to allow them to consent before setting this parameter to TRUE. + Agreement bool `form:"agreement" binding:"required"` + // The language of the confirmation email that will be sent + Locale string `form:"locale" binding:"required"` +} + +// UpdateCredentialsRequest represents the form submitted during a PATCH request to /api/v1/accounts/update_credentials. +// See https://docs.joinmastodon.org/methods/accounts/ +type UpdateCredentialsRequest struct { + // Whether the account should be shown in the profile directory. + Discoverable *bool `form:"discoverable"` + // Whether the account has a bot flag. + Bot *bool `form:"bot"` + // The display name to use for the profile. + DisplayName *string `form:"display_name"` + // The account bio. + Note *string `form:"note"` + // Avatar image encoded using multipart/form-data + Avatar *multipart.FileHeader `form:"avatar"` + // Header image encoded using multipart/form-data + Header *multipart.FileHeader `form:"header"` + // Whether manual approval of follow requests is required. + Locked *bool `form:"locked"` + // New Source values for this account + Source *UpdateSource `form:"source"` + // Profile metadata name and value + FieldsAttributes *[]UpdateField `form:"fields_attributes"` +} + +// UpdateSource is to be used specifically in an UpdateCredentialsRequest. +type UpdateSource struct { + // Default post privacy for authored statuses. + Privacy *string `form:"privacy"` + // Whether to mark authored statuses as sensitive by default. + Sensitive *bool `form:"sensitive"` + // Default language to use for authored statuses. (ISO 6391) + Language *string `form:"language"` +} + +// UpdateField is to be used specifically in an UpdateCredentialsRequest. +// By default, max 4 fields and 255 characters per property/value. +type UpdateField struct { + // Name of the field + Name *string `form:"name"` + // Value of the field + Value *string `form:"value"` +} diff --git a/internal/mastotypes/mastomodel/activity.go b/internal/mastotypes/mastomodel/activity.go new file mode 100644 index 000000000..b8dbf2c1b --- /dev/null +++ b/internal/mastotypes/mastomodel/activity.go @@ -0,0 +1,31 @@ +/* + GoToSocial + Copyright (C) 2021 GoToSocial Authors admin@gotosocial.org + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +package mastotypes + +// Activity represents the mastodon-api Activity type. See here: https://docs.joinmastodon.org/entities/activity/ +type Activity struct { + // Midnight at the first day of the week. (UNIX Timestamp as string) + Week string `json:"week"` + // Statuses created since the week began. Integer cast to string. + Statuses string `json:"statuses"` + // User logins since the week began. Integer cast as string. + Logins string `json:"logins"` + // User registrations since the week began. Integer cast as string. + Registrations string `json:"registrations"` +} diff --git a/internal/mastotypes/mastomodel/admin.go b/internal/mastotypes/mastomodel/admin.go new file mode 100644 index 000000000..71c2bb309 --- /dev/null +++ b/internal/mastotypes/mastomodel/admin.go @@ -0,0 +1,81 @@ +/* + GoToSocial + Copyright (C) 2021 GoToSocial Authors admin@gotosocial.org + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +package mastotypes + +// AdminAccountInfo represents the *admin* view of an account's details. See here: https://docs.joinmastodon.org/entities/admin-account/ +type AdminAccountInfo struct { + // The ID of the account in the database. + ID string `json:"id"` + // The username of the account. + Username string `json:"username"` + // The domain of the account. + Domain string `json:"domain"` + // When the account was first discovered. (ISO 8601 Datetime) + CreatedAt string `json:"created_at"` + // The email address associated with the account. + Email string `json:"email"` + // The IP address last used to login to this account. + IP string `json:"ip"` + // The locale of the account. (ISO 639 Part 1 two-letter language code) + Locale string `json:"locale"` + // Invite request text + InviteRequest string `json:"invite_request"` + // The current role of the account. + Role string `json:"role"` + // Whether the account has confirmed their email address. + Confirmed bool `json:"confirmed"` + // Whether the account is currently approved. + Approved bool `json:"approved"` + // Whether the account is currently disabled. + Disabled bool `json:"disabled"` + // Whether the account is currently silenced + Silenced bool `json:"silenced"` + // Whether the account is currently suspended. + Suspended bool `json:"suspended"` + // User-level information about the account. + Account *Account `json:"account"` + // The ID of the application that created this account. + CreatedByApplicationID string `json:"created_by_application_id,omitempty"` + // The ID of the account that invited this user + InvitedByAccountID string `json:"invited_by_account_id"` +} + +// AdminReportInfo represents the *admin* view of a report. See here: https://docs.joinmastodon.org/entities/admin-report/ +type AdminReportInfo struct { + // The ID of the report in the database. + ID string `json:"id"` + // The action taken to resolve this report. + ActionTaken string `json:"action_taken"` + // An optional reason for reporting. + Comment string `json:"comment"` + // The time the report was filed. (ISO 8601 Datetime) + CreatedAt string `json:"created_at"` + // The time of last action on this report. (ISO 8601 Datetime) + UpdatedAt string `json:"updated_at"` + // The account which filed the report. + Account *Account `json:"account"` + // The account being reported. + TargetAccount *Account `json:"target_account"` + // The account of the moderator assigned to this report. + AssignedAccount *Account `json:"assigned_account"` + // The action taken by the moderator who handled the report. + ActionTakenByAccount string `json:"action_taken_by_account"` + // Statuses attached to the report, for context. + Statuses []Status `json:"statuses"` +} diff --git a/internal/mastotypes/mastomodel/announcement.go b/internal/mastotypes/mastomodel/announcement.go new file mode 100644 index 000000000..882d6bb9b --- /dev/null +++ b/internal/mastotypes/mastomodel/announcement.go @@ -0,0 +1,37 @@ +/* + GoToSocial + Copyright (C) 2021 GoToSocial Authors admin@gotosocial.org + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +package mastotypes + +// Announcement represents an admin/moderator announcement for local users. See here: https://docs.joinmastodon.org/entities/announcement/ +type Announcement struct { + ID string `json:"id"` + Content string `json:"content"` + StartsAt string `json:"starts_at"` + EndsAt string `json:"ends_at"` + AllDay bool `json:"all_day"` + PublishedAt string `json:"published_at"` + UpdatedAt string `json:"updated_at"` + Published bool `json:"published"` + Read bool `json:"read"` + Mentions []Mention `json:"mentions"` + Statuses []Status `json:"statuses"` + Tags []Tag `json:"tags"` + Emojis []Emoji `json:"emoji"` + Reactions []AnnouncementReaction `json:"reactions"` +} diff --git a/internal/mastotypes/mastomodel/announcementreaction.go b/internal/mastotypes/mastomodel/announcementreaction.go new file mode 100644 index 000000000..444c57e2c --- /dev/null +++ b/internal/mastotypes/mastomodel/announcementreaction.go @@ -0,0 +1,33 @@ +/* + GoToSocial + Copyright (C) 2021 GoToSocial Authors admin@gotosocial.org + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +package mastotypes + +// AnnouncementReaction represents a user reaction to admin/moderator announcement. See here: https://docs.joinmastodon.org/entities/announcementreaction/ +type AnnouncementReaction struct { + // The emoji used for the reaction. Either a unicode emoji, or a custom emoji's shortcode. + Name string `json:"name"` + // The total number of users who have added this reaction. + Count int `json:"count"` + // Whether the authorized user has added this reaction to the announcement. + Me bool `json:"me"` + // A link to the custom emoji. + URL string `json:"url,omitempty"` + // A link to a non-animated version of the custom emoji. + StaticURL string `json:"static_url,omitempty"` +} diff --git a/internal/mastotypes/mastomodel/application.go b/internal/mastotypes/mastomodel/application.go new file mode 100644 index 000000000..6140a0127 --- /dev/null +++ b/internal/mastotypes/mastomodel/application.go @@ -0,0 +1,55 @@ +/* + GoToSocial + Copyright (C) 2021 GoToSocial Authors admin@gotosocial.org + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +package mastotypes + +// Application represents a mastodon-api Application, as defined here: https://docs.joinmastodon.org/entities/application/. +// Primarily, application is used for allowing apps like Tusky etc to connect to Mastodon on behalf of a user. +// See https://docs.joinmastodon.org/methods/apps/ +type Application struct { + // The application ID in the db + ID string `json:"id,omitempty"` + // The name of your application. + Name string `json:"name"` + // The website associated with your application (url) + Website string `json:"website,omitempty"` + // Where the user should be redirected after authorization. + RedirectURI string `json:"redirect_uri,omitempty"` + // ClientID to use when obtaining an oauth token for this application (ie., in client_id parameter of https://docs.joinmastodon.org/methods/apps/) + ClientID string `json:"client_id,omitempty"` + // Client secret to use when obtaining an auth token for this application (ie., in client_secret parameter of https://docs.joinmastodon.org/methods/apps/) + ClientSecret string `json:"client_secret,omitempty"` + // Used for Push Streaming API. Returned with POST /api/v1/apps. Equivalent to https://docs.joinmastodon.org/entities/pushsubscription/#server_key + VapidKey string `json:"vapid_key,omitempty"` +} + +// ApplicationPOSTRequest represents a POST request to https://example.org/api/v1/apps. +// See here: https://docs.joinmastodon.org/methods/apps/ +// And here: https://docs.joinmastodon.org/client/token/ +type ApplicationPOSTRequest struct { + // A name for your application + ClientName string `form:"client_name" binding:"required"` + // Where the user should be redirected after authorization. + // To display the authorization code to the user instead of redirecting + // to a web page, use urn:ietf:wg:oauth:2.0:oob in this parameter. + RedirectURIs string `form:"redirect_uris" binding:"required"` + // Space separated list of scopes. If none is provided, defaults to read. + Scopes string `form:"scopes"` + // A URL to the homepage of your app + Website string `form:"website"` +} diff --git a/internal/mastotypes/mastomodel/attachment.go b/internal/mastotypes/mastomodel/attachment.go new file mode 100644 index 000000000..bda79a8ee --- /dev/null +++ b/internal/mastotypes/mastomodel/attachment.go @@ -0,0 +1,98 @@ +/* + GoToSocial + Copyright (C) 2021 GoToSocial Authors admin@gotosocial.org + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +package mastotypes + +import "mime/multipart" + +// AttachmentRequest represents the form data parameters submitted by a client during a media upload request. +// See: https://docs.joinmastodon.org/methods/statuses/media/ +type AttachmentRequest struct { + File *multipart.FileHeader `form:"file"` + Thumbnail *multipart.FileHeader `form:"thumbnail"` + Description string `form:"description"` + Focus string `form:"focus"` +} + +// Attachment represents the object returned to a client after a successful media upload request. +// See: https://docs.joinmastodon.org/methods/statuses/media/ +type Attachment struct { + // The ID of the attachment in the database. + ID string `json:"id"` + // The type of the attachment. + // unknown = unsupported or unrecognized file type. + // image = Static image. + // gifv = Looping, soundless animation. + // video = Video clip. + // audio = Audio track. + Type string `json:"type"` + // The location of the original full-size attachment. + URL string `json:"url"` + // The location of a scaled-down preview of the attachment. + PreviewURL string `json:"preview_url"` + // The location of the full-size original attachment on the remote server. + RemoteURL string `json:"remote_url,omitempty"` + // The location of a scaled-down preview of the attachment on the remote server. + PreviewRemoteURL string `json:"preview_remote_url,omitempty"` + // A shorter URL for the attachment. + TextURL string `json:"text_url,omitempty"` + // Metadata returned by Paperclip. + // May contain subtrees small and original, as well as various other top-level properties. + // More importantly, there may be another top-level focus Hash object as of 2.3.0, with coordinates can be used for smart thumbnail cropping. + // See https://docs.joinmastodon.org/methods/statuses/media/#focal-points points for more. + Meta MediaMeta `json:"meta,omitempty"` + // Alternate text that describes what is in the media attachment, to be used for the visually impaired or when media attachments do not load. + Description string `json:"description,omitempty"` + // A hash computed by the BlurHash algorithm, for generating colorful preview thumbnails when media has not been downloaded yet. + // See https://github.com/woltapp/blurhash + Blurhash string `json:"blurhash,omitempty"` +} + +// MediaMeta describes the returned media +type MediaMeta struct { + Length string `json:"length,omitempty"` + Duration float32 `json:"duration,omitempty"` + FPS uint16 `json:"fps,omitempty"` + Size string `json:"size,omitempty"` + Width int `json:"width,omitempty"` + Height int `json:"height,omitempty"` + Aspect float32 `json:"aspect,omitempty"` + AudioEncode string `json:"audio_encode,omitempty"` + AudioBitrate string `json:"audio_bitrate,omitempty"` + AudioChannels string `json:"audio_channels,omitempty"` + Original MediaDimensions `json:"original"` + Small MediaDimensions `json:"small,omitempty"` + Focus MediaFocus `json:"focus,omitempty"` +} + +// MediaFocus describes the focal point of a piece of media. It should be returned to the caller as part of MediaMeta. +type MediaFocus struct { + X float32 `json:"x"` // should be between -1 and 1 + Y float32 `json:"y"` // should be between -1 and 1 +} + +// MediaDimensions describes the physical properties of a piece of media. It should be returned to the caller as part of MediaMeta. +type MediaDimensions struct { + Width int `json:"width,omitempty"` + Height int `json:"height,omitempty"` + FrameRate string `json:"frame_rate,omitempty"` + Duration float32 `json:"duration,omitempty"` + Bitrate int `json:"bitrate,omitempty"` + Size string `json:"size,omitempty"` + Aspect float32 `json:"aspect,omitempty"` +} diff --git a/internal/mastotypes/mastomodel/card.go b/internal/mastotypes/mastomodel/card.go new file mode 100644 index 000000000..d1147e04b --- /dev/null +++ b/internal/mastotypes/mastomodel/card.go @@ -0,0 +1,61 @@ +/* + GoToSocial + Copyright (C) 2021 GoToSocial Authors admin@gotosocial.org + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +package mastotypes + +// Card represents a rich preview card that is generated using OpenGraph tags from a URL. See here: https://docs.joinmastodon.org/entities/card/ +type Card struct { + // REQUIRED + + // Location of linked resource. + URL string `json:"url"` + // Title of linked resource. + Title string `json:"title"` + // Description of preview. + Description string `json:"description"` + // The type of the preview card. + // String (Enumerable, oneOf) + // link = Link OEmbed + // photo = Photo OEmbed + // video = Video OEmbed + // rich = iframe OEmbed. Not currently accepted, so won't show up in practice. + Type string `json:"type"` + + // OPTIONAL + + // The author of the original resource. + AuthorName string `json:"author_name"` + // A link to the author of the original resource. + AuthorURL string `json:"author_url"` + // The provider of the original resource. + ProviderName string `json:"provider_name"` + // A link to the provider of the original resource. + ProviderURL string `json:"provider_url"` + // HTML to be used for generating the preview card. + HTML string `json:"html"` + // Width of preview, in pixels. + Width int `json:"width"` + // Height of preview, in pixels. + Height int `json:"height"` + // Preview thumbnail. + Image string `json:"image"` + // Used for photo embeds, instead of custom html. + EmbedURL string `json:"embed_url"` + // A hash computed by the BlurHash algorithm, for generating colorful preview thumbnails when media has not been downloaded yet. + Blurhash string `json:"blurhash"` +} diff --git a/internal/mastotypes/mastomodel/context.go b/internal/mastotypes/mastomodel/context.go new file mode 100644 index 000000000..397522dc7 --- /dev/null +++ b/internal/mastotypes/mastomodel/context.go @@ -0,0 +1,27 @@ +/* + GoToSocial + Copyright (C) 2021 GoToSocial Authors admin@gotosocial.org + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +package mastotypes + +// Context represents the tree around a given status. Used for reconstructing threads of statuses. See: https://docs.joinmastodon.org/entities/context/ +type Context struct { + // Parents in the thread. + Ancestors []Status `json:"ancestors"` + // Children in the thread. + Descendants []Status `json:"descendants"` +} diff --git a/internal/mastotypes/mastomodel/conversation.go b/internal/mastotypes/mastomodel/conversation.go new file mode 100644 index 000000000..ed95c124c --- /dev/null +++ b/internal/mastotypes/mastomodel/conversation.go @@ -0,0 +1,36 @@ +/* + GoToSocial + Copyright (C) 2021 GoToSocial Authors admin@gotosocial.org + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +package mastotypes + +// Conversation represents a conversation with "direct message" visibility. See https://docs.joinmastodon.org/entities/conversation/ +type Conversation struct { + // REQUIRED + + // Local database ID of the conversation. + ID string `json:"id"` + // Participants in the conversation. + Accounts []Account `json:"accounts"` + // Is the conversation currently marked as unread? + Unread bool `json:"unread"` + + // OPTIONAL + + // The last status in the conversation, to be used for optional display. + LastStatus *Status `json:"last_status"` +} diff --git a/internal/mastotypes/mastomodel/emoji.go b/internal/mastotypes/mastomodel/emoji.go new file mode 100644 index 000000000..c50ca6343 --- /dev/null +++ b/internal/mastotypes/mastomodel/emoji.go @@ -0,0 +1,48 @@ +/* + GoToSocial + Copyright (C) 2021 GoToSocial Authors admin@gotosocial.org + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +package mastotypes + +import "mime/multipart" + +// Emoji represents a custom emoji. See https://docs.joinmastodon.org/entities/emoji/ +type Emoji struct { + // REQUIRED + + // The name of the custom emoji. + Shortcode string `json:"shortcode"` + // A link to the custom emoji. + URL string `json:"url"` + // A link to a static copy of the custom emoji. + StaticURL string `json:"static_url"` + // Whether this Emoji should be visible in the picker or unlisted. + VisibleInPicker bool `json:"visible_in_picker"` + + // OPTIONAL + + // Used for sorting custom emoji in the picker. + Category string `json:"category,omitempty"` +} + +// EmojiCreateRequest represents a request to create a custom emoji made through the admin API. +type EmojiCreateRequest struct { + // Desired shortcode for the emoji, without surrounding colons. This must be unique for the domain. + Shortcode string `form:"shortcode" validation:"required"` + // Image file to use for the emoji. Must be png or gif and no larger than 50kb. + Image *multipart.FileHeader `form:"image" validation:"required"` +} diff --git a/internal/mastotypes/mastomodel/error.go b/internal/mastotypes/mastomodel/error.go new file mode 100644 index 000000000..394085724 --- /dev/null +++ b/internal/mastotypes/mastomodel/error.go @@ -0,0 +1,32 @@ +/* + GoToSocial + Copyright (C) 2021 GoToSocial Authors admin@gotosocial.org + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +package mastotypes + +// Error represents an error message returned from the API. See https://docs.joinmastodon.org/entities/error/ +type Error struct { + // REQUIRED + + // The error message. + Error string `json:"error"` + + // OPTIONAL + + // A longer description of the error, mainly provided with the OAuth API. + ErrorDescription string `json:"error_description"` +} diff --git a/internal/mastotypes/mastomodel/featuredtag.go b/internal/mastotypes/mastomodel/featuredtag.go new file mode 100644 index 000000000..0e0bbe802 --- /dev/null +++ b/internal/mastotypes/mastomodel/featuredtag.go @@ -0,0 +1,33 @@ +/* + GoToSocial + Copyright (C) 2021 GoToSocial Authors admin@gotosocial.org + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +package mastotypes + +// FeaturedTag represents a hashtag that is featured on a profile. See https://docs.joinmastodon.org/entities/featuredtag/ +type FeaturedTag struct { + // The internal ID of the featured tag in the database. + ID string `json:"id"` + // The name of the hashtag being featured. + Name string `json:"name"` + // A link to all statuses by a user that contain this hashtag. + URL string `json:"url"` + // The number of authored statuses containing this hashtag. + StatusesCount int `json:"statuses_count"` + // The timestamp of the last authored status containing this hashtag. (ISO 8601 Datetime) + LastStatusAt string `json:"last_status_at"` +} diff --git a/internal/mastotypes/mastomodel/field.go b/internal/mastotypes/mastomodel/field.go new file mode 100644 index 000000000..29b5a1803 --- /dev/null +++ b/internal/mastotypes/mastomodel/field.go @@ -0,0 +1,33 @@ +/* + GoToSocial + Copyright (C) 2021 GoToSocial Authors admin@gotosocial.org + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +package mastotypes + +// Field represents a profile field as a name-value pair with optional verification. See https://docs.joinmastodon.org/entities/field/ +type Field struct { + // REQUIRED + + // The key of a given field's key-value pair. + Name string `json:"name"` + // The value associated with the name key. + Value string `json:"value"` + + // OPTIONAL + // Timestamp of when the server verified a URL value for a rel="me” link. String (ISO 8601 Datetime) if value is a verified URL + VerifiedAt string `json:"verified_at,omitempty"` +} diff --git a/internal/mastotypes/mastomodel/filter.go b/internal/mastotypes/mastomodel/filter.go new file mode 100644 index 000000000..86d9795a3 --- /dev/null +++ b/internal/mastotypes/mastomodel/filter.go @@ -0,0 +1,46 @@ +/* + GoToSocial + Copyright (C) 2021 GoToSocial Authors admin@gotosocial.org + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +package mastotypes + +// Filter represents a user-defined filter for determining which statuses should not be shown to the user. See https://docs.joinmastodon.org/entities/filter/ +// If whole_word is true , client app should do: +// Define ‘word constituent character’ for your app. In the official implementation, it’s [A-Za-z0-9_] in JavaScript, and [[:word:]] in Ruby. +// Ruby uses the POSIX character class (Letter | Mark | Decimal_Number | Connector_Punctuation). +// If the phrase starts with a word character, and if the previous character before matched range is a word character, its matched range should be treated to not match. +// If the phrase ends with a word character, and if the next character after matched range is a word character, its matched range should be treated to not match. +// Please check app/javascript/mastodon/selectors/index.js and app/lib/feed_manager.rb in the Mastodon source code for more details. +type Filter struct { + // The ID of the filter in the database. + ID string `json:"id"` + // The text to be filtered. + Phrase string `json:"text"` + // The contexts in which the filter should be applied. + // Array of String (Enumerable anyOf) + // home = home timeline and lists + // notifications = notifications timeline + // public = public timelines + // thread = expanded thread of a detailed status + Context []string `json:"context"` + // Should the filter consider word boundaries? + WholeWord bool `json:"whole_word"` + // When the filter should no longer be applied (ISO 8601 Datetime), or null if the filter does not expire + ExpiresAt string `json:"expires_at,omitempty"` + // Should matching entities in home and notifications be dropped by the server? + Irreversible bool `json:"irreversible"` +} diff --git a/internal/mastotypes/mastomodel/history.go b/internal/mastotypes/mastomodel/history.go new file mode 100644 index 000000000..235761378 --- /dev/null +++ b/internal/mastotypes/mastomodel/history.go @@ -0,0 +1,29 @@ +/* + GoToSocial + Copyright (C) 2021 GoToSocial Authors admin@gotosocial.org + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +package mastotypes + +// History represents daily usage history of a hashtag. See https://docs.joinmastodon.org/entities/history/ +type History struct { + // UNIX timestamp on midnight of the given day (string cast from integer). + Day string `json:"day"` + // The counted usage of the tag within that day (string cast from integer). + Uses string `json:"uses"` + // The total of accounts using the tag within that day (string cast from integer). + Accounts string `json:"accounts"` +} diff --git a/internal/mastotypes/mastomodel/identityproof.go b/internal/mastotypes/mastomodel/identityproof.go new file mode 100644 index 000000000..7265d46e3 --- /dev/null +++ b/internal/mastotypes/mastomodel/identityproof.go @@ -0,0 +1,33 @@ +/* + GoToSocial + Copyright (C) 2021 GoToSocial Authors admin@gotosocial.org + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +package mastotypes + +// IdentityProof represents a proof from an external identity provider. See https://docs.joinmastodon.org/entities/identityproof/ +type IdentityProof struct { + // The name of the identity provider. + Provider string `json:"provider"` + // The account owner's username on the identity provider's service. + ProviderUsername string `json:"provider_username"` + // The account owner's profile URL on the identity provider. + ProfileURL string `json:"profile_url"` + // A link to a statement of identity proof, hosted by the identity provider. + ProofURL string `json:"proof_url"` + // When the identity proof was last updated. + UpdatedAt string `json:"updated_at"` +} diff --git a/internal/mastotypes/mastomodel/instance.go b/internal/mastotypes/mastomodel/instance.go new file mode 100644 index 000000000..10e626a8e --- /dev/null +++ b/internal/mastotypes/mastomodel/instance.go @@ -0,0 +1,72 @@ +/* + GoToSocial + Copyright (C) 2021 GoToSocial Authors admin@gotosocial.org + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +package mastotypes + +// Instance represents the software instance of Mastodon running on this domain. See https://docs.joinmastodon.org/entities/instance/ +type Instance struct { + // REQUIRED + + // The domain name of the instance. + URI string `json:"uri"` + // The title of the website. + Title string `json:"title"` + // Admin-defined description of the Mastodon site. + Description string `json:"description"` + // A shorter description defined by the admin. + ShortDescription string `json:"short_description"` + // An email that may be contacted for any inquiries. + Email string `json:"email"` + // The version of Mastodon installed on the instance. + Version string `json:"version"` + // Primary langauges of the website and its staff. + Languages []string `json:"languages"` + // Whether registrations are enabled. + Registrations bool `json:"registrations"` + // Whether registrations require moderator approval. + ApprovalRequired bool `json:"approval_required"` + // Whether invites are enabled. + InvitesEnabled bool `json:"invites_enabled"` + // URLs of interest for clients apps. + URLS *InstanceURLs `json:"urls"` + // Statistics about how much information the instance contains. + Stats *InstanceStats `json:"stats"` + + // OPTIONAL + + // Banner image for the website. + Thumbnail string `json:"thumbnail,omitempty"` + // A user that can be contacted, as an alternative to email. + ContactAccount *Account `json:"contact_account,omitempty"` +} + +// InstanceURLs represents URLs necessary for successfully connecting to the instance as a user. See https://docs.joinmastodon.org/entities/instance/ +type InstanceURLs struct { + // Websockets address for push streaming. + StreamingAPI string `json:"streaming_api"` +} + +// InstanceStats represents some public-facing stats about the instance. See https://docs.joinmastodon.org/entities/instance/ +type InstanceStats struct { + // Users registered on this instance. + UserCount int `json:"user_count"` + // Statuses authored by users on instance. + StatusCount int `json:"status_count"` + // Domains federated with this instance. + DomainCount int `json:"domain_count"` +} diff --git a/internal/mastotypes/mastomodel/list.go b/internal/mastotypes/mastomodel/list.go new file mode 100644 index 000000000..5b704367b --- /dev/null +++ b/internal/mastotypes/mastomodel/list.go @@ -0,0 +1,31 @@ +/* + GoToSocial + Copyright (C) 2021 GoToSocial Authors admin@gotosocial.org + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +package mastotypes + +// List represents a list of some users that the authenticated user follows. See https://docs.joinmastodon.org/entities/list/ +type List struct { + // The internal database ID of the list. + ID string `json:"id"` + // The user-defined title of the list. + Title string `json:"title"` + // followed = Show replies to any followed user + // list = Show replies to members of the list + // none = Show replies to no one + RepliesPolicy string `json:"replies_policy"` +} diff --git a/internal/mastotypes/mastomodel/marker.go b/internal/mastotypes/mastomodel/marker.go new file mode 100644 index 000000000..790322313 --- /dev/null +++ b/internal/mastotypes/mastomodel/marker.go @@ -0,0 +1,37 @@ +/* + GoToSocial + Copyright (C) 2021 GoToSocial Authors admin@gotosocial.org + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +package mastotypes + +// Marker represents the last read position within a user's timelines. See https://docs.joinmastodon.org/entities/marker/ +type Marker struct { + // Information about the user's position in the home timeline. + Home *TimelineMarker `json:"home"` + // Information about the user's position in their notifications. + Notifications *TimelineMarker `json:"notifications"` +} + +// TimelineMarker contains information about a user's progress through a specific timeline. See https://docs.joinmastodon.org/entities/marker/ +type TimelineMarker struct { + // The ID of the most recently viewed entity. + LastReadID string `json:"last_read_id"` + // The timestamp of when the marker was set (ISO 8601 Datetime) + UpdatedAt string `json:"updated_at"` + // Used for locking to prevent write conflicts. + Version string `json:"version"` +} diff --git a/internal/mastotypes/mastomodel/mention.go b/internal/mastotypes/mastomodel/mention.go new file mode 100644 index 000000000..81a593d99 --- /dev/null +++ b/internal/mastotypes/mastomodel/mention.go @@ -0,0 +1,31 @@ +/* + GoToSocial + Copyright (C) 2021 GoToSocial Authors admin@gotosocial.org + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +package mastotypes + +// Mention represents the mastodon-api mention type, as documented here: https://docs.joinmastodon.org/entities/mention/ +type Mention struct { + // The account id of the mentioned user. + ID string `json:"id"` + // The username of the mentioned user. + Username string `json:"username"` + // The location of the mentioned user's profile. + URL string `json:"url"` + // The webfinger acct: URI of the mentioned user. Equivalent to username for local users, or username@domain for remote users. + Acct string `json:"acct"` +} diff --git a/internal/mastotypes/mastomodel/notification.go b/internal/mastotypes/mastomodel/notification.go new file mode 100644 index 000000000..26d361b43 --- /dev/null +++ b/internal/mastotypes/mastomodel/notification.go @@ -0,0 +1,45 @@ +/* + GoToSocial + Copyright (C) 2021 GoToSocial Authors admin@gotosocial.org + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +package mastotypes + +// Notification represents a notification of an event relevant to the user. See https://docs.joinmastodon.org/entities/notification/ +type Notification struct { + // REQUIRED + + // The id of the notification in the database. + ID string `json:"id"` + // The type of event that resulted in the notification. + // follow = Someone followed you + // follow_request = Someone requested to follow you + // mention = Someone mentioned you in their status + // reblog = Someone boosted one of your statuses + // favourite = Someone favourited one of your statuses + // poll = A poll you have voted in or created has ended + // status = Someone you enabled notifications for has posted a status + Type string `json:"type"` + // The timestamp of the notification (ISO 8601 Datetime) + CreatedAt string `json:"created_at"` + // The account that performed the action that generated the notification. + Account *Account `json:"account"` + + // OPTIONAL + + // Status that was the object of the notification, e.g. in mentions, reblogs, favourites, or polls. + Status *Status `json:"status"` +} diff --git a/internal/mastotypes/mastomodel/oauth.go b/internal/mastotypes/mastomodel/oauth.go new file mode 100644 index 000000000..d93ea079f --- /dev/null +++ b/internal/mastotypes/mastomodel/oauth.go @@ -0,0 +1,37 @@ +/* + GoToSocial + Copyright (C) 2021 GoToSocial Authors admin@gotosocial.org + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +package mastotypes + +// OAuthAuthorize represents a request sent to https://example.org/oauth/authorize +// See here: https://docs.joinmastodon.org/methods/apps/oauth/ +type OAuthAuthorize struct { + // Forces the user to re-login, which is necessary for authorizing with multiple accounts from the same instance. + ForceLogin string `form:"force_login,omitempty"` + // Should be set equal to `code`. + ResponseType string `form:"response_type"` + // Client ID, obtained during app registration. + ClientID string `form:"client_id"` + // Set a URI to redirect the user to. + // If this parameter is set to urn:ietf:wg:oauth:2.0:oob then the authorization code will be shown instead. + // Must match one of the redirect URIs declared during app registration. + RedirectURI string `form:"redirect_uri"` + // List of requested OAuth scopes, separated by spaces (or by pluses, if using query parameters). + // Must be a subset of scopes declared during app registration. If not provided, defaults to read. + Scope string `form:"scope,omitempty"` +} diff --git a/internal/mastotypes/mastomodel/poll.go b/internal/mastotypes/mastomodel/poll.go new file mode 100644 index 000000000..bedaebec2 --- /dev/null +++ b/internal/mastotypes/mastomodel/poll.go @@ -0,0 +1,64 @@ +/* + GoToSocial + Copyright (C) 2021 GoToSocial Authors admin@gotosocial.org + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +package mastotypes + +// Poll represents the mastodon-api poll type, as described here: https://docs.joinmastodon.org/entities/poll/ +type Poll struct { + // The ID of the poll in the database. + ID string `json:"id"` + // When the poll ends. (ISO 8601 Datetime), or null if the poll does not end + ExpiresAt string `json:"expires_at"` + // Is the poll currently expired? + Expired bool `json:"expired"` + // Does the poll allow multiple-choice answers? + Multiple bool `json:"multiple"` + // How many votes have been received. + VotesCount int `json:"votes_count"` + // How many unique accounts have voted on a multiple-choice poll. Null if multiple is false. + VotersCount int `json:"voters_count,omitempty"` + // When called with a user token, has the authorized user voted? + Voted bool `json:"voted,omitempty"` + // When called with a user token, which options has the authorized user chosen? Contains an array of index values for options. + OwnVotes []int `json:"own_votes,omitempty"` + // Possible answers for the poll. + Options []PollOptions `json:"options"` + // Custom emoji to be used for rendering poll options. + Emojis []Emoji `json:"emojis"` +} + +// PollOptions represents the current vote counts for different poll options +type PollOptions struct { + // The text value of the poll option. String. + Title string `json:"title"` + // The number of received votes for this option. Number, or null if results are not published yet. + VotesCount int `json:"votes_count,omitempty"` +} + +// PollRequest represents a mastodon-api poll attached to a status POST request, as defined here: https://docs.joinmastodon.org/methods/statuses/ +// It should be used at the path https://example.org/api/v1/statuses +type PollRequest struct { + // Array of possible answers. If provided, media_ids cannot be used, and poll[expires_in] must be provided. + Options []string `form:"options"` + // Duration the poll should be open, in seconds. If provided, media_ids cannot be used, and poll[options] must be provided. + ExpiresIn int `form:"expires_in"` + // Allow multiple choices? + Multiple bool `form:"multiple"` + // Hide vote counts until the poll ends? + HideTotals bool `form:"hide_totals"` +} diff --git a/internal/mastotypes/mastomodel/preferences.go b/internal/mastotypes/mastomodel/preferences.go new file mode 100644 index 000000000..c28f5d5ab --- /dev/null +++ b/internal/mastotypes/mastomodel/preferences.go @@ -0,0 +1,40 @@ +/* + GoToSocial + Copyright (C) 2021 GoToSocial Authors admin@gotosocial.org + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +package mastotypes + +// Preferences represents a user's preferences. See https://docs.joinmastodon.org/entities/preferences/ +type Preferences struct { + // Default visibility for new posts. + // public = Public post + // unlisted = Unlisted post + // private = Followers-only post + // direct = Direct post + PostingDefaultVisibility string `json:"posting:default:visibility"` + // Default sensitivity flag for new posts. + PostingDefaultSensitive bool `json:"posting:default:sensitive"` + // Default language for new posts. (ISO 639-1 language two-letter code), or null + PostingDefaultLanguage string `json:"posting:default:language,omitempty"` + // Whether media attachments should be automatically displayed or blurred/hidden. + // default = Hide media marked as sensitive + // show_all = Always show all media by default, regardless of sensitivity + // hide_all = Always hide all media by default, regardless of sensitivity + ReadingExpandMedia string `json:"reading:expand:media"` + // Whether CWs should be expanded by default. + ReadingExpandSpoilers bool `json:"reading:expand:spoilers"` +} diff --git a/internal/mastotypes/mastomodel/pushsubscription.go b/internal/mastotypes/mastomodel/pushsubscription.go new file mode 100644 index 000000000..4d7535100 --- /dev/null +++ b/internal/mastotypes/mastomodel/pushsubscription.go @@ -0,0 +1,45 @@ +/* + GoToSocial + Copyright (C) 2021 GoToSocial Authors admin@gotosocial.org + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +package mastotypes + +// PushSubscription represents a subscription to the push streaming server. See https://docs.joinmastodon.org/entities/pushsubscription/ +type PushSubscription struct { + // The id of the push subscription in the database. + ID string `json:"id"` + // Where push alerts will be sent to. + Endpoint string `json:"endpoint"` + // The streaming server's VAPID key. + ServerKey string `json:"server_key"` + // Which alerts should be delivered to the endpoint. + Alerts *PushSubscriptionAlerts `json:"alerts"` +} + +// PushSubscriptionAlerts represents the specific alerts that this push subscription will give. +type PushSubscriptionAlerts struct { + // Receive a push notification when someone has followed you? + Follow bool `json:"follow"` + // Receive a push notification when a status you created has been favourited by someone else? + Favourite bool `json:"favourite"` + // Receive a push notification when someone else has mentioned you in a status? + Mention bool `json:"mention"` + // Receive a push notification when a status you created has been boosted by someone else? + Reblog bool `json:"reblog"` + // Receive a push notification when a poll you voted in or created has ended? + Poll bool `json:"poll"` +} diff --git a/internal/mastotypes/mastomodel/relationship.go b/internal/mastotypes/mastomodel/relationship.go new file mode 100644 index 000000000..1e0bbab46 --- /dev/null +++ b/internal/mastotypes/mastomodel/relationship.go @@ -0,0 +1,49 @@ +/* + GoToSocial + Copyright (C) 2021 GoToSocial Authors admin@gotosocial.org + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +package mastotypes + +// Relationship represents a relationship between accounts. See https://docs.joinmastodon.org/entities/relationship/ +type Relationship struct { + // The account id. + ID string `json:"id"` + // Are you following this user? + Following bool `json:"following"` + // Are you receiving this user's boosts in your home timeline? + ShowingReblogs bool `json:"showing_reblogs"` + // Have you enabled notifications for this user? + Notifying bool `json:"notifying"` + // Are you followed by this user? + FollowedBy bool `json:"followed_by"` + // Are you blocking this user? + Blocking bool `json:"blocking"` + // Is this user blocking you? + BlockedBy bool `json:"blocked_by"` + // Are you muting this user? + Muting bool `json:"muting"` + // Are you muting notifications from this user? + MutingNotifications bool `json:"muting_notifications"` + // Do you have a pending follow request for this user? + Requested bool `json:"requested"` + // Are you blocking this user's domain? + DomainBlocking bool `json:"domain_blocking"` + // Are you featuring this user on your profile? + Endorsed bool `json:"endorsed"` + // Your note on this account. + Note string `json:"note"` +} diff --git a/internal/mastotypes/mastomodel/results.go b/internal/mastotypes/mastomodel/results.go new file mode 100644 index 000000000..3fa7c7abb --- /dev/null +++ b/internal/mastotypes/mastomodel/results.go @@ -0,0 +1,29 @@ +/* + GoToSocial + Copyright (C) 2021 GoToSocial Authors admin@gotosocial.org + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +package mastotypes + +// Results represents the results of a search. See https://docs.joinmastodon.org/entities/results/ +type Results struct { + // Accounts which match the given query + Accounts []Account `json:"accounts"` + // Statuses which match the given query + Statuses []Status `json:"statuses"` + // Hashtags which match the given query + Hashtags []Tag `json:"hashtags"` +} diff --git a/internal/mastotypes/mastomodel/scheduledstatus.go b/internal/mastotypes/mastomodel/scheduledstatus.go new file mode 100644 index 000000000..ff45eaade --- /dev/null +++ b/internal/mastotypes/mastomodel/scheduledstatus.go @@ -0,0 +1,39 @@ +/* + GoToSocial + Copyright (C) 2021 GoToSocial Authors admin@gotosocial.org + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +package mastotypes + +// ScheduledStatus represents a status that will be published at a future scheduled date. See https://docs.joinmastodon.org/entities/scheduledstatus/ +type ScheduledStatus struct { + ID string `json:"id"` + ScheduledAt string `json:"scheduled_at"` + Params *StatusParams `json:"params"` + MediaAttachments []Attachment `json:"media_attachments"` +} + +// StatusParams represents parameters for a scheduled status. See https://docs.joinmastodon.org/entities/scheduledstatus/ +type StatusParams struct { + Text string `json:"text"` + InReplyToID string `json:"in_reply_to_id,omitempty"` + MediaIDs []string `json:"media_ids,omitempty"` + Sensitive bool `json:"sensitive,omitempty"` + SpoilerText string `json:"spoiler_text,omitempty"` + Visibility string `json:"visibility"` + ScheduledAt string `json:"scheduled_at,omitempty"` + ApplicationID string `json:"application_id"` +} diff --git a/internal/mastotypes/mastomodel/source.go b/internal/mastotypes/mastomodel/source.go new file mode 100644 index 000000000..0445a1ffb --- /dev/null +++ b/internal/mastotypes/mastomodel/source.go @@ -0,0 +1,41 @@ +/* + GoToSocial + Copyright (C) 2021 GoToSocial Authors admin@gotosocial.org + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +package mastotypes + +// Source represents display or publishing preferences of user's own account. +// Returned as an additional entity when verifying and updated credentials, as an attribute of Account. +// See https://docs.joinmastodon.org/entities/source/ +type Source struct { + // The default post privacy to be used for new statuses. + // public = Public post + // unlisted = Unlisted post + // private = Followers-only post + // direct = Direct post + Privacy Visibility `json:"privacy,omitempty"` + // Whether new statuses should be marked sensitive by default. + Sensitive bool `json:"sensitive,omitempty"` + // The default posting language for new statuses. + Language string `json:"language,omitempty"` + // Profile bio. + Note string `json:"note"` + // Metadata about the account. + Fields []Field `json:"fields"` + // The number of pending follow requests. + FollowRequestsCount int `json:"follow_requests_count,omitempty"` +} diff --git a/internal/mastotypes/mastomodel/status.go b/internal/mastotypes/mastomodel/status.go new file mode 100644 index 000000000..a27a0e6a2 --- /dev/null +++ b/internal/mastotypes/mastomodel/status.go @@ -0,0 +1,119 @@ +/* + GoToSocial + Copyright (C) 2021 GoToSocial Authors admin@gotosocial.org + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +package mastotypes + +// Status represents a mastodon-api Status type, as defined here: https://docs.joinmastodon.org/entities/status/ +type Status struct { + // ID of the status in the database. + ID string `json:"id"` + // The date when this status was created (ISO 8601 Datetime) + CreatedAt string `json:"created_at"` + // ID of the status being replied. + InReplyToID string `json:"in_reply_to_id,omitempty"` + // ID of the account being replied to. + InReplyToAccountID string `json:"in_reply_to_account_id,omitempty"` + // Is this status marked as sensitive content? + Sensitive bool `json:"sensitive"` + // Subject or summary line, below which status content is collapsed until expanded. + SpoilerText string `json:"spoiler_text,omitempty"` + // Visibility of this status. + Visibility Visibility `json:"visibility"` + // Primary language of this status. (ISO 639 Part 1 two-letter language code) + Language string `json:"language"` + // URI of the status used for federation. + URI string `json:"uri"` + // A link to the status's HTML representation. + URL string `json:"url"` + // How many replies this status has received. + RepliesCount int `json:"replies_count"` + // How many boosts this status has received. + ReblogsCount int `json:"reblogs_count"` + // How many favourites this status has received. + FavouritesCount int `json:"favourites_count"` + // Have you favourited this status? + Favourited bool `json:"favourited"` + // Have you boosted this status? + Reblogged bool `json:"reblogged"` + // Have you muted notifications for this status's conversation? + Muted bool `json:"muted"` + // Have you bookmarked this status? + Bookmarked bool `json:"bookmarked"` + // Have you pinned this status? Only appears if the status is pinnable. + Pinned bool `json:"pinned"` + // HTML-encoded status content. + Content string `json:"content"` + // The status being reblogged. + Reblog *Status `json:"reblog,omitempty"` + // The application used to post this status. + Application *Application `json:"application"` + // The account that authored this status. + Account *Account `json:"account"` + // Media that is attached to this status. + MediaAttachments []Attachment `json:"media_attachments"` + // Mentions of users within the status content. + Mentions []Mention `json:"mentions"` + // Hashtags used within the status content. + Tags []Tag `json:"tags"` + // Custom emoji to be used when rendering status content. + Emojis []Emoji `json:"emojis"` + // Preview card for links included within status content. + Card *Card `json:"card"` + // The poll attached to the status. + Poll *Poll `json:"poll"` + // Plain-text source of a status. Returned instead of content when status is deleted, + // so the user may redraft from the source text without the client having to reverse-engineer + // the original text from the HTML content. + Text string `json:"text"` +} + +// StatusCreateRequest represents a mastodon-api status POST request, as defined here: https://docs.joinmastodon.org/methods/statuses/ +// It should be used at the path https://mastodon.example/api/v1/statuses +type StatusCreateRequest struct { + // Text content of the status. If media_ids is provided, this becomes optional. Attaching a poll is optional while status is provided. + Status string `form:"status"` + // Array of Attachment ids to be attached as media. If provided, status becomes optional, and poll cannot be used. + MediaIDs []string `form:"media_ids"` + // Poll to include with this status. + Poll *PollRequest `form:"poll"` + // ID of the status being replied to, if status is a reply + InReplyToID string `form:"in_reply_to_id"` + // Mark status and attached media as sensitive? + Sensitive bool `form:"sensitive"` + // Text to be shown as a warning or subject before the actual content. Statuses are generally collapsed behind this field. + SpoilerText string `form:"spoiler_text"` + // Visibility of the posted status. Enumerable oneOf public, unlisted, private, direct. + Visibility Visibility `form:"visibility"` + // ISO 8601 Datetime at which to schedule a status. Providing this paramter will cause ScheduledStatus to be returned instead of Status. Must be at least 5 minutes in the future. + ScheduledAt string `form:"scheduled_at"` + // ISO 639 language code for this status. + Language string `form:"language"` +} + +type Visibility string + +const ( + // visible to everyone + VisibilityPublic Visibility = "public" + // visible to everyone but only on home timelines or in lists + VisibilityUnlisted Visibility = "unlisted" + // visible to followers only + VisibilityPrivate Visibility = "private" + // visible only to tagged recipients + VisibilityDirect Visibility = "direct" +) diff --git a/internal/mastotypes/mastomodel/tag.go b/internal/mastotypes/mastomodel/tag.go new file mode 100644 index 000000000..82e6e6618 --- /dev/null +++ b/internal/mastotypes/mastomodel/tag.go @@ -0,0 +1,27 @@ +/* + GoToSocial + Copyright (C) 2021 GoToSocial Authors admin@gotosocial.org + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +package mastotypes + +// Tag represents a hashtag used within the content of a status. See https://docs.joinmastodon.org/entities/tag/ +type Tag struct { + // The value of the hashtag after the # sign. + Name string `json:"name"` + // A link to the hashtag on the instance. + URL string `json:"url"` +} diff --git a/internal/mastotypes/mastomodel/token.go b/internal/mastotypes/mastomodel/token.go new file mode 100644 index 000000000..c9ac1f177 --- /dev/null +++ b/internal/mastotypes/mastomodel/token.go @@ -0,0 +1,31 @@ +/* + GoToSocial + Copyright (C) 2021 GoToSocial Authors admin@gotosocial.org + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +package mastotypes + +// Token represents an OAuth token used for authenticating with the API and performing actions.. See https://docs.joinmastodon.org/entities/token/ +type Token struct { + // An OAuth token to be used for authorization. + AccessToken string `json:"access_token"` + // The OAuth token type. Mastodon uses Bearer tokens. + TokenType string `json:"token_type"` + // The OAuth scopes granted by this token, space-separated. + Scope string `json:"scope"` + // When the token was generated. (UNIX timestamp seconds) + CreatedAt int64 `json:"created_at"` +} diff --git a/internal/mastotypes/mock_Converter.go b/internal/mastotypes/mock_Converter.go new file mode 100644 index 000000000..732d933ae --- /dev/null +++ b/internal/mastotypes/mock_Converter.go @@ -0,0 +1,148 @@ +// Code generated by mockery v2.7.4. DO NOT EDIT. + +package mastotypes + +import ( + mock "github.com/stretchr/testify/mock" + gtsmodel "github.com/superseriousbusiness/gotosocial/internal/db/gtsmodel" + mastotypes "github.com/superseriousbusiness/gotosocial/internal/mastotypes/mastomodel" +) + +// MockConverter is an autogenerated mock type for the Converter type +type MockConverter struct { + mock.Mock +} + +// AccountToMastoPublic provides a mock function with given fields: account +func (_m *MockConverter) AccountToMastoPublic(account *gtsmodel.Account) (*mastotypes.Account, error) { + ret := _m.Called(account) + + var r0 *mastotypes.Account + if rf, ok := ret.Get(0).(func(*gtsmodel.Account) *mastotypes.Account); ok { + r0 = rf(account) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*mastotypes.Account) + } + } + + var r1 error + if rf, ok := ret.Get(1).(func(*gtsmodel.Account) error); ok { + r1 = rf(account) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// AccountToMastoSensitive provides a mock function with given fields: account +func (_m *MockConverter) AccountToMastoSensitive(account *gtsmodel.Account) (*mastotypes.Account, error) { + ret := _m.Called(account) + + var r0 *mastotypes.Account + if rf, ok := ret.Get(0).(func(*gtsmodel.Account) *mastotypes.Account); ok { + r0 = rf(account) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*mastotypes.Account) + } + } + + var r1 error + if rf, ok := ret.Get(1).(func(*gtsmodel.Account) error); ok { + r1 = rf(account) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// AppToMastoPublic provides a mock function with given fields: application +func (_m *MockConverter) AppToMastoPublic(application *gtsmodel.Application) (*mastotypes.Application, error) { + ret := _m.Called(application) + + var r0 *mastotypes.Application + if rf, ok := ret.Get(0).(func(*gtsmodel.Application) *mastotypes.Application); ok { + r0 = rf(application) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*mastotypes.Application) + } + } + + var r1 error + if rf, ok := ret.Get(1).(func(*gtsmodel.Application) error); ok { + r1 = rf(application) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// AppToMastoSensitive provides a mock function with given fields: application +func (_m *MockConverter) AppToMastoSensitive(application *gtsmodel.Application) (*mastotypes.Application, error) { + ret := _m.Called(application) + + var r0 *mastotypes.Application + if rf, ok := ret.Get(0).(func(*gtsmodel.Application) *mastotypes.Application); ok { + r0 = rf(application) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*mastotypes.Application) + } + } + + var r1 error + if rf, ok := ret.Get(1).(func(*gtsmodel.Application) error); ok { + r1 = rf(application) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// AttachmentToMasto provides a mock function with given fields: attachment +func (_m *MockConverter) AttachmentToMasto(attachment *gtsmodel.MediaAttachment) (mastotypes.Attachment, error) { + ret := _m.Called(attachment) + + var r0 mastotypes.Attachment + if rf, ok := ret.Get(0).(func(*gtsmodel.MediaAttachment) mastotypes.Attachment); ok { + r0 = rf(attachment) + } else { + r0 = ret.Get(0).(mastotypes.Attachment) + } + + var r1 error + if rf, ok := ret.Get(1).(func(*gtsmodel.MediaAttachment) error); ok { + r1 = rf(attachment) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// MentionToMasto provides a mock function with given fields: m +func (_m *MockConverter) MentionToMasto(m *gtsmodel.Mention) (mastotypes.Mention, error) { + ret := _m.Called(m) + + var r0 mastotypes.Mention + if rf, ok := ret.Get(0).(func(*gtsmodel.Mention) mastotypes.Mention); ok { + r0 = rf(m) + } else { + r0 = ret.Get(0).(mastotypes.Mention) + } + + var r1 error + if rf, ok := ret.Get(1).(func(*gtsmodel.Mention) error); ok { + r1 = rf(m) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} |