gtsocial-umbx

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

commit 0386a28b5a3c4212320e8a96ddd14c54b65a2090
parent cb85f65ccac434b869e6a87eff1dc77ac19c7f25
Author: Tobi Smethurst <31960611+tsmethurst@users.noreply.github.com>
Date:   Mon,  2 Aug 2021 19:06:44 +0200

Frodo swaggins (#126)

* more swagger fun

* document a whole bunch more stuff

* more swagger yayyyyyyy

* progress + go fmt
Diffstat:
MDockerfile | 4++++
MPROGRESS.md | 2+-
Mdocs/api/swagger.yaml | 1937+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------
Mdocs/swagger.go | 7+++++++
Minternal/api/client/account/accountcreate.go | 15++++-----------
Minternal/api/client/account/accountget.go | 4+---
Minternal/api/client/account/accountupdate.go | 13++++++-------
Minternal/api/client/account/accountverify.go | 6+-----
Minternal/api/client/account/block.go | 4+---
Minternal/api/client/account/follow.go | 34++++++++++++++++++++++++++--------
Minternal/api/client/account/followers.go | 4+---
Minternal/api/client/account/following.go | 4+---
Minternal/api/client/account/relationships.go | 4+---
Minternal/api/client/account/statuses.go | 6++----
Minternal/api/client/account/unblock.go | 4+---
Minternal/api/client/account/unfollow.go | 4+---
Minternal/api/client/admin/domainblockcreate.go | 24+++++++++---------------
Minternal/api/client/admin/domainblockdelete.go | 4+---
Minternal/api/client/admin/domainblockget.go | 4+---
Minternal/api/client/admin/domainblocksget.go | 4+---
Minternal/api/client/admin/emojicreate.go | 9++++-----
Minternal/api/client/app/appcreate.go | 37+++++++++++++++++++++++++++++++++++--
Minternal/api/client/blocks/blocksget.go | 58+++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
Minternal/api/client/instance/instanceget.go | 23++++++++++++++++++++++-
Minternal/api/client/instance/instancepatch.go | 76+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
Minternal/api/client/media/mediacreate.go | 53++++++++++++++++++++++++++++++++++++++++++++++++++++-
Minternal/api/client/media/mediaget.go | 54++++++++++++++++++++++++++++++++++++++++++++----------
Minternal/api/client/media/mediaupdate.go | 88++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------------
Minternal/api/client/search/searchget.go | 28++++++++++++++++++++++++++--
Minternal/api/client/status/statusboost.go | 40+++++++++++++++++++++++++++++++++++++++-
Dinternal/api/client/status/statusboosted_by.go | 60------------------------------------------------------------
Ainternal/api/client/status/statusboostedby.go | 95+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Minternal/api/client/status/statuscontext.go | 39++++++++++++++++++++++++++++++++++++++-
Minternal/api/client/status/statuscreate.go | 37++++++++++++++++++++++++++++++++++++-
Minternal/api/client/status/statusdelete.go | 39++++++++++++++++++++++++++++++++++++++-
Minternal/api/client/status/statusfave.go | 36+++++++++++++++++++++++++++++++++++-
Minternal/api/client/status/statusfavedby.go | 37++++++++++++++++++++++++++++++++++++-
Minternal/api/client/status/statusget.go | 36+++++++++++++++++++++++++++++++++++-
Minternal/api/client/status/statusunboost.go | 37++++++++++++++++++++++++++++++++++++-
Minternal/api/client/status/statusunfave.go | 36+++++++++++++++++++++++++++++++++++-
Minternal/api/client/streaming/stream.go | 98++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
Minternal/api/client/timeline/home.go | 80++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------
Minternal/api/client/timeline/public.go | 78+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---
Minternal/api/model/account.go | 29++++++++++++++++-------------
Minternal/api/model/admin.go | 4++--
Minternal/api/model/announcement.go | 56+++++++++++++++++++++++++++++++++++++++++---------------
Minternal/api/model/announcementreaction.go | 16++++++++++++----
Minternal/api/model/application.go | 31+++++++++++++++++++++----------
Minternal/api/model/attachment.go | 142+++++++++++++++++++++++++++++++++++++++++++++++++++++++++----------------------
Minternal/api/model/card.go | 10+++++-----
Minternal/api/model/context.go | 4+++-
Minternal/api/model/instance.go | 81++++++++++++++++++++++++++++++++++++++++++++++++-------------------------------
Minternal/api/model/poll.go | 27++++++++++++++++-----------
Minternal/api/model/search.go | 87+++++++++++++++++++++++++++++++++++++++++++++++++++++++++----------------------
Minternal/api/model/status.go | 90+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--------------------
Minternal/gtsmodel/status.go | 26++++++++++++++------------
Minternal/processing/account/createfollow.go | 18+++++++++---------
Minternal/processing/status/util.go | 20++++++++------------
Minternal/typeutils/internaltofrontend.go | 11++++++++---
59 files changed, 3367 insertions(+), 547 deletions(-)

diff --git a/Dockerfile b/Dockerfile @@ -11,6 +11,7 @@ WORKDIR /go/src/github.com/superseriousbusiness/gotosocial ADD cmd /go/src/github.com/superseriousbusiness/gotosocial/cmd ADD internal /go/src/github.com/superseriousbusiness/gotosocial/internal ADD testrig /go/src/github.com/superseriousbusiness/gotosocial/testrig +ADD docs/swagger.go /go/src/github.com/superseriousbusiness/gotosocial/docs/swagger.go ADD go.mod /go/src/github.com/superseriousbusiness/gotosocial/go.mod ADD go.sum /go/src/github.com/superseriousbusiness/gotosocial/go.sum @@ -56,6 +57,9 @@ COPY --from=binary_builder /go/src/github.com/superseriousbusiness/gotosocial/go # copy over the web directory with templates etc COPY --from=web_builder web /gotosocial/web +# put the swagger yaml in the web assets directory so it can be accessed +COPY docs/api/swagger.yaml /gotosocial/web/assets/swagger.yaml + # copy over the admin directory COPY --from=admin_builder /gotosocial-admin/public /gotosocial/web/assets/admin diff --git a/PROGRESS.md b/PROGRESS.md @@ -225,7 +225,7 @@ Things are moving on the project! As of July 2021 you can now: * [ ] Scope middleware * [ ] Permissions/acl middleware for admins+moderators * [ ] Documentation - * [ ] Swagger API documentation + * [x] Swagger API documentation * [ ] ReadTheDocs.io documentation * [ ] Deployment documentation * [ ] App creation guide diff --git a/docs/api/swagger.yaml b/docs/api/swagger.yaml @@ -82,7 +82,68 @@ definitions: title: Source represents display or publishing preferences of user's own account. type: object x-go-package: github.com/superseriousbusiness/gotosocial/internal/api/model + StatusCreateRequest: + properties: + format: + $ref: '#/definitions/statusFormat' + in_reply_to_id: + description: |- + ID of the status being replied to, if status is a reply. + in: formData + type: string + x-go-name: InReplyToID + language: + description: |- + ISO 639 language code for this status. + in: formData + type: string + x-go-name: Language + media_ids: + description: |- + Array of Attachment ids to be attached as media. + If provided, status becomes optional, and poll cannot be used. + in: formData + items: + type: string + type: array + x-go-name: MediaIDs + scheduled_at: + description: |- + 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. + in: formData + type: string + x-go-name: ScheduledAt + sensitive: + description: |- + Status and attached media should be marked as sensitive. + in: formData + type: boolean + x-go-name: Sensitive + spoiler_text: + description: |- + Text to be shown as a warning or subject before the actual content. + Statuses are generally collapsed behind this field. + in: formData + type: string + x-go-name: SpoilerText + status: + description: |- + Text content of the status. + If media_ids is provided, this becomes optional. + Attaching a poll is optional while status is provided. + in: formData + type: string + x-go-name: Status + visibility: + $ref: '#/definitions/statusVisibility' + title: StatusCreateRequest models status creation parameters. + type: object + x-go-package: github.com/superseriousbusiness/gotosocial/internal/api/model account: + description: The modelled account can be either a remote account, or one on this + instance. properties: acct: description: |- @@ -113,8 +174,7 @@ definitions: type: string x-go-name: CreatedAt discoverable: - description: Account has opted into discovery features such as the profile - directory. + description: Account has opted into discovery features. type: boolean x-go-name: Discoverable display_name: @@ -203,64 +263,10 @@ definitions: example: some_user type: string x-go-name: Username - title: Account represents a fediverse account of some kind, either a remote one - or one on this instance. + title: Account models a fediverse account. type: object x-go-name: Account x-go-package: github.com/superseriousbusiness/gotosocial/internal/api/model - accountCreateRequest: - properties: - agreement: - description: The user agrees to the terms, conditions, and policies of the - instance. - type: boolean - x-go-name: Agreement - email: - description: The email address to be used for login. - type: string - x-go-name: Email - locale: - description: The language of the confirmation email that will be sent. - type: string - x-go-name: Locale - password: - description: The password to be used for login. This will be hashed before - storage. - type: string - x-go-name: Password - reason: - description: Text that will be reviewed by moderators if registrations require - manual approval. - type: string - x-go-name: Reason - username: - description: The desired username for the account. - type: string - x-go-name: Username - title: AccountCreateRequest represents the form submitted during a POST request - to /api/v1/accounts. - type: object - x-go-name: AccountCreateRequest - x-go-package: github.com/superseriousbusiness/gotosocial/internal/api/model - accountFollowRequest: - description: AccountFollowRequest is for parsing requests at /api/v1/accounts/:id/follow - properties: - TargetAccountID: - description: |- - ID of the account to follow request - This should be a URL parameter not a form field - type: string - notify: - description: Notify when this account posts? - type: boolean - x-go-name: Notify - reblogs: - description: Show reblogs for this account? - type: boolean - x-go-name: Reblogs - type: object - x-go-name: AccountFollowRequest - x-go-package: github.com/superseriousbusiness/gotosocial/internal/api/model accountRelationship: properties: blocked_by: @@ -322,9 +328,232 @@ definitions: type: object x-go-name: Relationship x-go-package: github.com/superseriousbusiness/gotosocial/internal/api/model + advancedStatusCreateForm: + description: |- + AdvancedStatusCreateForm wraps the mastodon status create form along with the GTS advanced + visibility settings. + properties: + boostable: + description: This status can be boosted/reblogged. + type: boolean + x-go-name: Boostable + federated: + description: This status will be federated beyond the local timeline(s). + type: boolean + x-go-name: Federated + format: + $ref: '#/definitions/statusFormat' + in_reply_to_id: + description: |- + ID of the status being replied to, if status is a reply. + in: formData + type: string + x-go-name: InReplyToID + language: + description: |- + ISO 639 language code for this status. + in: formData + type: string + x-go-name: Language + likeable: + description: This status can be liked/faved. + type: boolean + x-go-name: Likeable + media_ids: + description: |- + Array of Attachment ids to be attached as media. + If provided, status becomes optional, and poll cannot be used. + in: formData + items: + type: string + type: array + x-go-name: MediaIDs + replyable: + description: This status can be replied to. + type: boolean + x-go-name: Replyable + scheduled_at: + description: |- + 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. + in: formData + type: string + x-go-name: ScheduledAt + sensitive: + description: |- + Status and attached media should be marked as sensitive. + in: formData + type: boolean + x-go-name: Sensitive + spoiler_text: + description: |- + Text to be shown as a warning or subject before the actual content. + Statuses are generally collapsed behind this field. + in: formData + type: string + x-go-name: SpoilerText + status: + description: |- + Text content of the status. + If media_ids is provided, this becomes optional. + Attaching a poll is optional while status is provided. + in: formData + type: string + x-go-name: Status + visibility: + $ref: '#/definitions/statusVisibility' + type: object + x-go-name: AdvancedStatusCreateForm + x-go-package: github.com/superseriousbusiness/gotosocial/internal/api/model + advancedVisibilityFlagsForm: + description: |- + AdvancedVisibilityFlagsForm allows a few more advanced flags to be set on new statuses, in addition + to the standard mastodon-compatible ones. + properties: + boostable: + description: This status can be boosted/reblogged. + type: boolean + x-go-name: Boostable + federated: + description: This status will be federated beyond the local timeline(s). + type: boolean + x-go-name: Federated + likeable: + description: This status can be liked/faved. + type: boolean + x-go-name: Likeable + replyable: + description: This status can be replied to. + type: boolean + x-go-name: Replyable + type: object + x-go-name: AdvancedVisibilityFlagsForm + x-go-package: github.com/superseriousbusiness/gotosocial/internal/api/model + announcement: + properties: + all_day: + description: Announcement doesn't have begin time and end time, but begin + day and end day. + type: boolean + x-go-name: AllDay + content: + description: |- + The body of the announcement. + Should be HTML formatted. + example: <p>This is an announcement. No malarky.</p> + type: string + x-go-name: Content + emoji: + description: Emojis used in this announcement. + items: + $ref: '#/definitions/emoji' + type: array + x-go-name: Emojis + ends_at: + description: |- + When the announcement should stop being displayed (ISO 8601 Datetime). + If the announcement has no end time, this will be omitted or empty. + example: "2021-07-30T09:20:25+00:00" + type: string + x-go-name: EndsAt + id: + description: The ID of the announcement. + example: 01FC30T7X4TNCZK0TH90QYF3M4 + type: string + x-go-name: ID + mentions: + description: Mentions this announcement contains. + items: + $ref: '#/definitions/Mention' + type: array + x-go-name: Mentions + published: + description: |- + Announcement is 'published', ie., visible to users. + Announcements that are not published should be shown only to admins. + type: boolean + x-go-name: Published + published_at: + description: When the announcement was first published (ISO 8601 Datetime). + example: "2021-07-30T09:20:25+00:00" + type: string + x-go-name: PublishedAt + reactions: + description: Reactions to this announcement. + items: + $ref: '#/definitions/announcementReaction' + type: array + x-go-name: Reactions + read: + description: Requesting account has seen this announcement. + type: boolean + x-go-name: Read + starts_at: + description: |- + When the announcement should begin to be displayed (ISO 8601 Datetime). + If the announcement has no start time, this will be omitted or empty. + example: "2021-07-30T09:20:25+00:00" + type: string + x-go-name: StartsAt + statuses: + description: Statuses contained in this announcement. + items: + $ref: '#/definitions/status' + type: array + x-go-name: Statuses + tags: + description: Tags used in this announcement. + items: + $ref: '#/definitions/tag' + type: array + x-go-name: Tags + updated_at: + description: When the announcement was last updated (ISO 8601 Datetime). + example: "2021-07-30T09:20:25+00:00" + type: string + x-go-name: UpdatedAt + title: Announcement models an admin announcement for the instance. + type: object + x-go-name: Announcement + x-go-package: github.com/superseriousbusiness/gotosocial/internal/api/model + announcementReaction: + properties: + count: + description: The total number of users who have added this reaction. + example: 5 + format: int64 + type: integer + x-go-name: Count + me: + description: This reaction belongs to the account viewing it. + type: boolean + x-go-name: Me + name: + description: The emoji used for the reaction. Either a unicode emoji, or a + custom emoji's shortcode. + example: blobcat_uwu + type: string + x-go-name: Name + static_url: + description: |- + Web link to a non-animated image of the custom emoji. + Empty for unicode emojis. + example: https://example.org/custom_emojis/statuc/blobcat_uwu.png + type: string + x-go-name: StaticURL + url: + description: |- + Web link to the image of the custom emoji. + Empty for unicode emojis. + example: https://example.org/custom_emojis/original/blobcat_uwu.png + type: string + x-go-name: URL + title: AnnouncementReaction models a user reaction to an announcement. + type: object + x-go-name: AnnouncementReaction + x-go-package: github.com/superseriousbusiness/gotosocial/internal/api/model application: - description: Primarily, application is used for allowing apps like Tusky etc to - connect to Mastodon on behalf of a user. properties: client_id: description: Client ID associated with this application. @@ -358,7 +587,7 @@ definitions: example: https://tusky.app type: string x-go-name: Website - title: Application represents an api Application, as defined here. + title: Application models an api application. type: object x-go-name: Application x-go-package: github.com/superseriousbusiness/gotosocial/internal/api/model @@ -377,6 +606,7 @@ definitions: x-go-name: Description id: description: The ID of the attachment. + example: 01FC31DZT1AYWDZ8XTCRWRBYRK type: string x-go-name: ID meta: @@ -401,17 +631,13 @@ definitions: type: string x-go-name: RemoteURL text_url: - description: A shorter URL for the attachment. + description: |- + A shorter URL for the attachment. + Not currently used. type: string x-go-name: TextURL type: - description: |- - The type of the attachment. - unknown = unsupported or unrecognized file type. - image = Static image. - gifv = Looping, soundless animation. - video = Video clip. - audio = Audio track. + description: The type of the attachment. example: image type: string x-go-name: Type @@ -420,8 +646,7 @@ definitions: example: https://example.org/fileserver/some_id/attachments/some_id/original/attachment.jpeg type: string x-go-name: URL - title: Attachment represents the object returned to a client after a successful - media upload request. + title: Attachment models a media attachment. type: object x-go-name: Attachment x-go-package: github.com/superseriousbusiness/gotosocial/internal/api/model @@ -481,13 +706,7 @@ definitions: type: string x-go-name: Title type: - 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. + description: The type of the preview card. example: link type: string x-go-name: Type @@ -650,58 +869,196 @@ definitions: type: object x-go-name: Field x-go-package: github.com/superseriousbusiness/gotosocial/internal/api/model + instance: + properties: + approval_required: + description: New account registrations require admin approval. + type: boolean + x-go-name: ApprovalRequired + contact_account: + $ref: '#/definitions/account' + description: + description: |- + Description of the instance. + + Should be HTML formatted, but might be plaintext. + + This should be displayed on the 'about' page for an instance. + type: string + x-go-name: Description + email: + description: An email address that may be used for inquiries. + example: admin@example.org + type: string + x-go-name: Email + invites_enabled: + description: Invites are enabled on this instance. + type: boolean + x-go-name: InvitesEnabled + languages: + description: Primary language of the instance. + example: en + items: + type: string + type: array + x-go-name: Languages + max_toot_chars: + description: |- + Maximum allowed length of a post on this instance, in characters. + + This is provided for compatibility with Tusky and other apps. + example: 5000 + format: uint64 + type: integer + x-go-name: MaxTootChars + registrations: + description: New account registrations are enabled on this instance. + type: boolean + x-go-name: Registrations + short_description: + description: |- + A shorter description of the instance. + + Should be HTML formatted, but might be plaintext. + + This should be displayed on the instance splash/landing page. + type: string + x-go-name: ShortDescription + stats: + additionalProperties: + format: int64 + type: integer + description: 'Statistics about the instance: number of posts, accounts, etc.' + type: object + x-go-name: Stats + thumbnail: + description: URL of the instance avatar/banner image. + example: https://example.org/files/instance/thumbnail.jpeg + type: string + x-go-name: Thumbnail + title: + description: The title of the instance. + example: GoToSocial Example Instance + type: string + x-go-name: Title + uri: + description: The URI of the instance. + example: https://example.org + type: string + x-go-name: URI + urls: + $ref: '#/definitions/instanceURLs' + version: + description: |- + The version of GoToSocial installed on the instance. + + This will contain at least a semantic version number. + + It may also contain, after a space, the short git commit ID of the running software. + example: 0.1.1 cb85f65 + type: string + x-go-name: Version + title: Instance models information about this or another instance. + type: object + x-go-name: Instance + x-go-package: github.com/superseriousbusiness/gotosocial/internal/api/model + instanceURLs: + properties: + streaming_api: + description: Websockets address for status and notification streaming. + example: wss://example.org + type: string + x-go-name: StreamingAPI + title: InstanceURLs models instance-relevant URLs for client application consumption. + type: object + x-go-name: InstanceURLs + x-go-package: github.com/superseriousbusiness/gotosocial/internal/api/model mediaDimensions: properties: aspect: + description: |- + Aspect ratio of the media. + Equal to width / height. + example: 1.777777778 format: float type: number x-go-name: Aspect bitrate: + description: Bitrate of the media in bits per second. + example: 1000000 format: int64 type: integer x-go-name: Bitrate duration: + description: |- + Duration of the media in seconds. + Only set for video and audio. + example: 5.43 format: float type: number x-go-name: Duration frame_rate: + description: |- + Framerate of the media. + Only set for video and gifs. + example: "30" type: string x-go-name: FrameRate height: + description: |- + Height of the media in pixels. + Not set for audio. + example: 1080 format: int64 type: integer x-go-name: Height size: + description: |- + Size of the media, in the format `[width]x[height]`. + Not set for audio. + example: 1920x1080 type: string x-go-name: Size width: + description: |- + Width of the media in pixels. + Not set for audio. + example: 1920 format: int64 type: integer x-go-name: Width - title: MediaDimensions describes the physical properties of a piece of media. - It should be returned to the caller as part of MediaMeta. + title: MediaDimensions models detailed properties of a piece of media. type: object x-go-name: MediaDimensions x-go-package: github.com/superseriousbusiness/gotosocial/internal/api/model mediaFocus: properties: x: + description: |- + x position of the focus + should be between -1 and 1 format: float type: number x-go-name: X "y": + description: |- + y position of the focus + should be between -1 and 1 format: float type: number x-go-name: "Y" - title: MediaFocus describes the focal point of a piece of media. It should be - returned to the caller as part of MediaMeta. + title: MediaFocus models the focal point of a piece of media. type: object x-go-name: MediaFocus x-go-package: github.com/superseriousbusiness/gotosocial/internal/api/model mediaMeta: - description: MediaMeta describes the returned media + description: This can be metadata about an image, an audio file, video, etc. properties: aspect: + description: |- + Aspect ratio of the media. + Equal to width / height. + example: 1.777777778 format: float type: number x-go-name: Aspect @@ -715,16 +1072,28 @@ definitions: type: string x-go-name: AudioEncode duration: + description: |- + Duration of the media in seconds. + Only set for video and audio. + example: 5.43 format: float type: number x-go-name: Duration focus: $ref: '#/definitions/mediaFocus' fps: + description: |- + Framerate of the media. + Only set for video and gifs. + example: 30 format: uint16 type: integer x-go-name: FPS height: + description: |- + Height of the media in pixels. + Not set for audio. + example: 1080 format: int64 type: integer x-go-name: Height @@ -734,14 +1103,23 @@ definitions: original: $ref: '#/definitions/mediaDimensions' size: + description: |- + Size of the media, in the format `[width]x[height]`. + Not set for audio. + example: 1920x1080 type: string x-go-name: Size small: $ref: '#/definitions/mediaDimensions' width: + description: |- + Width of the media in pixels. + Not set for audio. + example: 1920 format: int64 type: integer x-go-name: Width + title: MediaMeta models media metadata. type: object x-go-name: MediaMeta x-go-package: github.com/superseriousbusiness/gotosocial/internal/api/model @@ -838,8 +1216,9 @@ definitions: type: string x-go-name: Title votes_count: - description: The number of received votes for this option. Number, or null - if results are not published yet. + description: |- + The number of received votes for this option. + Number, or null if results are not published yet. format: int64 type: integer x-go-name: VotesCount @@ -847,6 +1226,27 @@ definitions: type: object x-go-name: PollOptions x-go-package: github.com/superseriousbusiness/gotosocial/internal/api/model + searchResult: + properties: + accounts: + items: + $ref: '#/definitions/account' + type: array + x-go-name: Accounts + hashtags: + items: + $ref: '#/definitions/tag' + type: array + x-go-name: Hashtags + statuses: + items: + $ref: '#/definitions/status' + type: array + x-go-name: Statuses + title: SearchResult models a search result. + type: object + x-go-name: SearchResult + x-go-package: github.com/superseriousbusiness/gotosocial/internal/api/model status: properties: account: @@ -932,7 +1332,7 @@ definitions: poll: $ref: '#/definitions/poll' reblog: - $ref: '#/definitions/status' + $ref: '#/definitions/statusReblogged' reblogged: description: This status has been boosted/reblogged by the account viewing it. @@ -986,33 +1386,200 @@ definitions: x-go-name: URL visibility: $ref: '#/definitions/statusVisibility' - title: Status represents a status or post. + title: Status models a status or post. type: object x-go-name: Status x-go-package: github.com/superseriousbusiness/gotosocial/internal/api/model - statusVisibility: - title: Visibility denotes the visibility of a status to other users. - type: string - x-go-name: Visibility - x-go-package: github.com/superseriousbusiness/gotosocial/internal/api/model - tag: + statusContext: properties: - name: - description: 'The value of the hashtag after the # sign.' - example: helloworld - type: string - x-go-name: Name - url: - description: Web link to the hashtag. - example: https://example.org/tags/helloworld - type: string - x-go-name: URL - title: Tag represents a hashtag used within the content of a status. + ancestors: + description: Parents in the thread. + items: + $ref: '#/definitions/status' + type: array + x-go-name: Ancestors + descendants: + description: Children in the thread. + items: + $ref: '#/definitions/status' + type: array + x-go-name: Descendants + title: Context models the tree around a given status. type: object - x-go-name: Tag + x-go-name: Context x-go-package: github.com/superseriousbusiness/gotosocial/internal/api/model - updateField: - description: By default, max 4 fields and 255 characters per property/value. + statusFormat: + description: Can be either plain or markdown. Empty will default to plain. + title: StatusFormat is the format in which to parse the submitted status. + type: string + x-go-name: StatusFormat + x-go-package: github.com/superseriousbusiness/gotosocial/internal/api/model + statusReblogged: + properties: + account: + $ref: '#/definitions/account' + application: + $ref: '#/definitions/application' + bookmarked: + description: This status has been bookmarked by the account viewing it. + type: boolean + x-go-name: Bookmarked + card: + $ref: '#/definitions/card' + content: + description: The content of this status. Should be HTML, but might also be + plaintext in some cases. + example: <p>Hey this is a status!</p> + type: string + x-go-name: Content + created_at: + description: The date when this status was created (ISO 8601 Datetime). + example: "2021-07-30T09:20:25+00:00" + type: string + x-go-name: CreatedAt + emojis: + description: Custom emoji to be used when rendering status content. + items: + $ref: '#/definitions/emoji' + type: array + x-go-name: Emojis + favourited: + description: This status has been favourited by the account viewing it. + type: boolean + x-go-name: Favourited + favourites_count: + description: Number of favourites/likes this status has received, according + to our instance. + format: int64 + type: integer + x-go-name: FavouritesCount + id: + description: ID of the status. + example: 01FBVD42CQ3ZEEVMW180SBX03B + type: string + x-go-name: ID + in_reply_to_account_id: + description: ID of the account being replied to. + example: 01FBVD42CQ3ZEEVMW180SBX03B + type: string + x-go-name: InReplyToAccountID + in_reply_to_id: + description: ID of the status being replied to. + example: 01FBVD42CQ3ZEEVMW180SBX03B + type: string + x-go-name: InReplyToID + language: + description: Primary language of this status (ISO 639 Part 1 two-letter language + code). + example: en + type: string + x-go-name: Language + media_attachments: + description: Media that is attached to this status. + items: + $ref: '#/definitions/attachment' + type: array + x-go-name: MediaAttachments + mentions: + description: Mentions of users within the status content. + items: + $ref: '#/definitions/Mention' + type: array + x-go-name: Mentions + muted: + description: Replies to this status have been muted by the account viewing + it. + type: boolean + x-go-name: Muted + pinned: + description: This status has been pinned by the account viewing it (only relevant + for your own statuses). + type: boolean + x-go-name: Pinned + poll: + $ref: '#/definitions/poll' + reblog: + $ref: '#/definitions/statusReblogged' + reblogged: + description: This status has been boosted/reblogged by the account viewing + it. + type: boolean + x-go-name: Reblogged + reblogs_count: + description: Number of times this status has been boosted/reblogged, according + to our instance. + format: int64 + type: integer + x-go-name: ReblogsCount + replies_count: + description: Number of replies to this status, according to our instance. + format: int64 + type: integer + x-go-name: RepliesCount + sensitive: + description: Status contains sensitive content. + example: false + type: boolean + x-go-name: Sensitive + spoiler_text: + description: Subject, summary, or content warning for the status. + example: warning nsfw + type: string + x-go-name: SpoilerText + tags: + description: Hashtags used within the status content. + items: + $ref: '#/definitions/tag' + type: array + x-go-name: Tags + text: + description: |- + 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. + type: string + x-go-name: Text + uri: + description: ActivityPub URI of the status. Equivalent to the status's activitypub + ID. + example: https://example.org/users/some_user/statuses/01FBVD42CQ3ZEEVMW180SBX03B + type: string + x-go-name: URI + url: + description: The status's publicly available web URL. This link will only + work if the visibility of the status is 'public'. + example: https://example.org/@some_user/statuses/01FBVD42CQ3ZEEVMW180SBX03B + type: string + x-go-name: URL + visibility: + $ref: '#/definitions/statusVisibility' + title: StatusReblogged represents a reblogged status. + type: object + x-go-name: StatusReblogged + x-go-package: github.com/superseriousbusiness/gotosocial/internal/api/model + statusVisibility: + title: Visibility models the visibility of a status. + type: string + x-go-name: Visibility + x-go-package: github.com/superseriousbusiness/gotosocial/internal/api/model + tag: + properties: + name: + description: 'The value of the hashtag after the # sign.' + example: helloworld + type: string + x-go-name: Name + url: + description: Web link to the hashtag. + example: https://example.org/tags/helloworld + type: string + x-go-name: URL + title: Tag represents a hashtag used within the content of a status. + type: object + x-go-name: Tag + x-go-package: github.com/superseriousbusiness/gotosocial/internal/api/model + updateField: + description: By default, max 4 fields and 255 characters per property/value. properties: name: description: Name of the field @@ -1026,6 +1593,24 @@ definitions: type: object x-go-name: UpdateField x-go-package: github.com/superseriousbusiness/gotosocial/internal/api/model + updateSource: + properties: + language: + description: Default language to use for authored statuses. (ISO 6391) + type: string + x-go-name: Language + privacy: + description: Default post privacy for authored statuses. + type: string + x-go-name: Privacy + sensitive: + description: Mark authored statuses as sensitive by default. + type: boolean + x-go-name: Sensitive + title: UpdateSource is to be used specifically in an UpdateCredentialsRequest. + type: object + x-go-name: UpdateSource + x-go-package: github.com/superseriousbusiness/gotosocial/internal/api/model host: example.org info: contact: @@ -1044,13 +1629,44 @@ paths: - application/json - application/xml - application/x-www-form-urlencoded - - multipart/form-data + description: |- + The parameters can also be given in the body of the request, as JSON, if the content-type is set to 'application/json'. + The parameters can also be given in the body of the request, as XML, if the content-type is set to 'application/xml'. operationId: accountCreate parameters: - - in: body - name: Account Create Request - schema: - $ref: '#/definitions/accountCreateRequest' + - description: Text that will be reviewed by moderators if registrations require + manual approval. + in: query + name: reason + type: string + x-go-name: Reason + - description: The desired username for the account. + in: query + name: username + type: string + x-go-name: Username + - description: The email address to be used for login. + in: query + name: email + type: string + x-go-name: Email + - description: The password to be used for login. This will be hashed before + storage. + in: query + name: password + type: string + x-go-name: Password + - description: The user agrees to the terms, conditions, and policies of the + instance. + in: query + name: agreement + type: boolean + x-go-name: Agreement + - description: The language of the confirmation email that will be sent. + in: query + name: locale + type: string + x-go-name: Locale produces: - application/json responses: @@ -1130,13 +1746,32 @@ paths: - accounts /api/v1/accounts/{id}/follow: post: + consumes: + - application/json + - application/xml + - application/x-www-form-urlencoded + description: |- + The parameters can also be given in the body of the request, as JSON, if the content-type is set to 'application/json'. + The parameters can also be given in the body of the request, as XML, if the content-type is set to 'application/xml'. operationId: accountFollow parameters: - - description: The id of the account to follow. + - description: ID of the account to follow. in: path name: id required: true type: string + - default: true + description: Show reblogs from this account. + in: formData + name: reblogs + type: boolean + x-go-name: Reblogs + - default: false + description: Notify when this account posts. + in: formData + name: notify + type: boolean + x-go-name: Notify produces: - application/json responses: @@ -1258,7 +1893,7 @@ paths: - application/json responses: "200": - description: Array of statuses.. + description: Array of statuses. schema: items: $ref: '#/definitions/status' @@ -1378,11 +2013,13 @@ paths: in: formData name: bot type: boolean - - description: The display name to use for the account. + - allowEmptyValue: true + description: The display name to use for the account. in: formData name: display_name type: string - - description: Bio/description of this account. + - allowEmptyValue: true + description: Bio/description of this account. in: formData name: note type: string @@ -1400,15 +2037,15 @@ paths: type: boolean - description: Default post privacy for authored statuses. in: formData - name: source.privacy + name: source[privacy] type: string - description: Mark authored statuses as sensitive by default. in: formData - name: source.sensitive + name: source[sensitive] type: boolean - description: Default language to use for authored statuses (ISO 6391). in: formData - name: source.language + name: source[language] type: string produces: - application/json @@ -1458,14 +2095,15 @@ paths: - description: |- The code to use for the emoji, which will be used by instance denizens to select it. This must be unique on the instance. - example: blobcat_uwu in: formData name: shortcode pattern: \w{2,30} + required: true type: string - - description: A jpeg, png, or gif image of the emoji. + - description: A png or gif image of the emoji. Animated pngs work too! in: formData - name: domains + name: image + required: true type: file produces: - application/json @@ -1517,11 +2155,11 @@ paths: summary: View all domain blocks currently in place. tags: - admin - patch: + post: consumes: - multipart/form-data description: |- - Note that you have two options when using this endpoint: either you can set 'import' to true + Note that you have two options when using this endpoint: either you can set `import` to true and upload a file containing multiple domain blocks, JSON-formatted, or you can leave import as false, and just add one domain block. @@ -1537,38 +2175,34 @@ paths: type: boolean - description: |- JSON-formatted list of domain blocks to import. - This is only used if 'import' is set to true. + This is only used if `import` is set to true. in: formData name: domains type: file - description: |- Single domain to block. - Used only if 'import' is not true. - example: example.org + Used only if `import` is not true. in: formData name: domain type: string - description: |- Obfuscate the name of the domain when serving it publicly. Eg., 'example.org' becomes something like 'ex***e.org'. - Used only if 'import' is not true. + Used only if `import` is not true. in: formData name: obfuscate type: boolean - description: |- Public comment about this domain block. Will be displayed alongside the domain block if you choose to share blocks. - Used only if 'import' is not true. - example: harassment, transphobia + Used only if `import` is not true. in: formData name: public_comment type: string - description: |- Private comment about this domain block. Will only be shown to other admins, so this is a useful way of internally keeping track of why a certain domain ended up blocked. - Used only if 'import' is not true. - example: harassment, transphobia, and some stuff only other admins need to - know about + Used only if `import` is not true. in: formData name: private_comment type: string @@ -1576,9 +2210,9 @@ paths: - application/json responses: "200": - description: "The newly created domain block, if import != true.\nNote that - if a list has been imported, then an `array` of\nnewly created domain - blocks will be returned instead. " + description: |- + The newly created domain block, if `import` != `true`. + Note that if a list has been imported, then an `array` of newly created domain blocks will be returned instead. schema: $ref: '#/definitions/domainBlock' "400": @@ -1646,6 +2280,1032 @@ paths: summary: View domain block with the given ID. tags: - admin + /api/v1/apps: + post: + consumes: + - application/json + - application/xml + - application/x-www-form-urlencoded + description: |- + The registered application can be used to obtain an application token. + This can then be used to register a new account, or (through user auth) obtain an access token. + + The parameters can also be given in the body of the request, as JSON, if the content-type is set to 'application/json'. + The parameters can also be given in the body of the request, as XML, if the content-type is set to 'application/xml'. + operationId: appCreate + parameters: + - description: The name of the application. + in: formData + name: client_name + required: true + type: string + x-go-name: ClientName + - description: |- + 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. + in: formData + name: redirect_uris + required: true + type: string + x-go-name: RedirectURIs + - description: |- + Space separated list of scopes. + + If no scopes are provided, defaults to `read`. + in: formData + name: scopes + type: string + x-go-name: Scopes + - description: A URL to the web page of the app (optional). + in: formData + name: website + type: string + x-go-name: Website + produces: + - application/json + responses: + "200": + description: The newly-created application. + schema: + $ref: '#/definitions/application' + "400": + description: bad request + "401": + description: unauthorized + "422": + description: unprocessable + "500": + description: internal error + summary: Register a new application on this instance. + tags: + - apps + /api/v1/blocks: + get: + description: |- + The next and previous queries can be parsed from the returned Link header. + Example: + + ``` + <https://example.org/api/v1/blocks?limit=80&max_id=01FC0SKA48HNSVR6YKZCQGS2V8>; rel="next", <https://example.org/api/v1/blocks?limit=80&min_id=01FC0SKW5JK2Q4EVAV2B462YY0>; rel="prev" + ```` + operationId: blocksGet + parameters: + - default: 20 + description: Number of blocks to return. + in: query + name: limit + type: integer + - description: |- + Return only blocks *OLDER* than the given max block ID. + The block with the specified ID will not be included in the response. + in: query + name: max_id + type: string + - description: |- + Return only blocks *NEWER* than the given since block ID. + The block with the specified ID will not be included in the response. + in: query + name: since_id + type: string + produces: + - application/json + responses: + "200": + description: "" + headers: + Link: + description: Links to the next and previous queries. + type: string + schema: + items: + $ref: '#/definitions/account' + type: array + "400": + description: bad request + "401": + description: unauthorized + "404": + description: not found + security: + - OAuth2 Bearer: + - read:blocks + summary: Get an array of accounts that requesting account has blocked. + tags: + - blocks + /api/v1/instance: + get: + description: "This is mostly provided for Mastodon application compatibility, + since many apps that work with Mastodon use `/api/v1/instance` to inform their + connection parameters. \n\nHowever, it can also be used by other instances + for gathering instance information and representing instances in some UI or + other." + operationId: instanceGet + produces: + - application/json + responses: + "200": + description: Instance information. + schema: + $ref: '#/definitions/instance' + "500": + description: internal error + summary: View instance information. + tags: + - instance + patch: + consumes: + - multipart/form-data + description: This requires admin permissions on the instance. + operationId: instanceUpdate + parameters: + - allowEmptyValue: true + description: Title to use for the instance. + in: formData + maximum: 40 + name: title + type: string + - allowEmptyValue: true + description: |- + Username of the contact account. + This must be the username of an instance admin. + in: formData + name: contact_username + type: string + - allowEmptyValue: true + description: Email address to use as the instance contact. + in: formData + name: contact_email + type: string + - allowEmptyValue: true + description: Short description of the instance. + in: formData + maximum: 500 + name: short_description + type: string + - allowEmptyValue: true + description: Longer description of the instance. + in: formData + maximum: 5000 + name: description + type: string + - allowEmptyValue: true + description: Terms and conditions of the instance. + in: formData + maximum: 5000 + name: terms + type: string + - description: Avatar of the instance. + in: formData + name: avatar + type: file + - description: Header of the instance. + in: formData + name: header + type: file + produces: + - application/json + responses: + "200": + description: The newly updated instance. + schema: + $ref: '#/definitions/instance' + "400": + description: bad request + "401": + description: unauthorized + security: + - OAuth2 Bearer: + - admin + summary: Update your instance information and/or upload a new avatar/header + for the instance. + tags: + - instance + /api/v1/media: + post: + consumes: + - multipart/form-data + operationId: mediaCreate + parameters: + - description: |- + Image or media description to use as alt-text on the attachment. + This is very useful for users of screenreaders. + May or may not be required, depending on your instance settings. + in: formData + name: description + type: string + - description: |- + Focus of the media file. + If present, it should be in the form of two comma-separated floats between -1 and 1. + For example: `-0.5,0.25`. + in: formData + name: focus + type: string + - description: The media attachment to upload. + in: formData + name: file + required: true + type: file + produces: + - application/json + responses: + "200": + description: The newly-created media attachment. + schema: + $ref: '#/definitions/attachment' + "400": + description: bad request + "401": + description: unauthorized + "403": + description: forbidden + "422": + description: unprocessable + security: + - OAuth2 Bearer: + - write:media + summary: Upload a new media attachment. + tags: + - media + /api/v1/media/{id}: + get: + operationId: mediaGet + parameters: + - description: id of the attachment + in: path + name: id + required: true + type: string + produces: + - application/json + responses: + "200": + description: The requested media attachment. + schema: + $ref: '#/definitions/attachment' + "400": + description: bad request + "401": + description: unauthorized + "403": + description: forbidden + "422": + description: unprocessable + security: + - OAuth2 Bearer: + - read:media + summary: Get a media attachment that you own. + tags: + - media + put: + consumes: + - application/json + - application/xml + - application/x-www-form-urlencoded + description: |- + You must own the media attachment, and the attachment must not yet be attached to a status. + + The parameters can also be given in the body of the request, as JSON, if the content-type is set to 'application/json'. + The parameters can also be given in the body of the request, as XML, if the content-type is set to 'application/xml'. + operationId: mediaUpdate + parameters: + - description: id of the attachment to update + in: path + name: id + required: true + type: string + - allowEmptyValue: true + description: |- + Image or media description to use as alt-text on the attachment. + This is very useful for users of screenreaders. + May or may not be required, depending on your instance settings. + in: formData + name: description + type: string + - allowEmptyValue: true + description: |- + Focus of the media file. + If present, it should be in the form of two comma-separated floats between -1 and 1. + For example: `-0.5,0.25`. + in: formData + name: focus + type: string + produces: + - application/json + responses: + "200": + description: The newly-updated media attachment. + schema: + $ref: '#/definitions/attachment' + "400": + description: bad request + "401": + description: unauthorized + "403": + description: forbidden + "422": + description: unprocessable + security: + - OAuth2 Bearer: + - write:media + summary: Update a media attachment. + tags: + - media + /api/v1/search: + get: + description: If statuses are in the result, they will be returned in descending + chronological order (newest first), with sequential IDs (bigger = newer). + operationId: searchGet + parameters: + - description: If type is `statuses`, then statuses returned will be authored + only by this account. + in: query + name: account_id + type: string + x-go-name: AccountID + - description: |- + Return results *older* than this id. + + The entry with this ID will not be included in the search results. + in: query + name: max_id + type: string + x-go-name: MaxID + - description: |- + Return results *newer* than this id. + + The entry with this ID will not be included in the search results. + in: query + name: min_id + type: string + x-go-name: MinID + - description: |- + Type of the search query to perform. + + Must be one of: `accounts`, `hashtags`, `statuses`. + in: query + name: type + required: true + type: string + x-go-name: Type + - default: false + description: Filter out tags that haven't been reviewed and approved by an + instance admin. + in: query + name: exclude_unreviewed + type: boolean + x-go-name: ExcludeUnreviewed + - description: |- + String to use as a search query. + + For accounts, this should be in the format `@someaccount@some.instance.com`, or the format `https://some.instance.com/@someaccount` + + For a status, this can be in the format: `https://some.instance.com/@someaccount/SOME_ID_OF_A_STATUS` + in: query + name: q + required: true + type: string + x-go-name: Query + - default: false + description: Attempt to resolve the query by performing a remote webfinger + lookup, if the query includes a remote host. + in: query + name: resolve + type: boolean + x-go-name: Resolve + - default: 20 + description: Maximum number of results to load, per type. + format: int64 + in: query + maximum: 40 + minimum: 1 + name: limit + type: integer + x-go-name: Limit + - default: 0 + description: Offset for paginating search results. + format: int64 + in: query + name: offset + type: integer + x-go-name: Offset + - default: false + description: Only include accounts that the searching account is following. + in: query + name: following + type: boolean + x-go-name: Following + responses: + "200": + description: Results of the search. + schema: + items: + $ref: '#/definitions/searchResult' + type: array + "400": + description: bad request + "401": + description: unauthorized + security: + - OAuth2 Bearer: + - read:search + summary: Search for statuses, accounts, or hashtags, on this instance or elsewhere. + tags: + - search + /api/v1/statuses: + post: + consumes: + - application/json + - application/xml + - application/x-www-form-urlencoded + description: |- + The parameters can also be given in the body of the request, as JSON, if the content-type is set to 'application/json'. + The parameters can also be given in the body of the request, as XML, if the content-type is set to 'application/xml'. + operationId: statusCreate + parameters: + - description: |- + Text content of the status. + If media_ids is provided, this becomes optional. + Attaching a poll is optional while status is provided. + in: formData + name: status + type: string + x-go-name: Status + - description: |- + Array of Attachment ids to be attached as media. + If provided, status becomes optional, and poll cannot be used. + in: formData + items: + type: string + name: media_ids + type: array + x-go-name: MediaIDs + - description: ID of the status being replied to, if status is a reply. + in: formData + name: in_reply_to_id + type: string + x-go-name: InReplyToID + - description: Status and attached media should be marked as sensitive. + in: formData + name: sensitive + type: boolean + x-go-name: Sensitive + - description: |- + Text to be shown as a warning or subject before the actual content. + Statuses are generally collapsed behind this field. + in: formData + name: spoiler_text + type: string + x-go-name: SpoilerText + - description: Visibility of the posted status. + in: formData + name: visibility + type: string + x-go-name: Visibility + - description: |- + 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. + in: formData + name: scheduled_at + type: string + x-go-name: ScheduledAt + - description: ISO 639 language code for this status. + in: formData + name: language + type: string + x-go-name: Language + - description: Format to use when parsing this status. + in: formData + name: format + type: string + x-go-name: Format + produces: + - application/json + responses: + "200": + description: The newly created status. + schema: + $ref: '#/definitions/status' + "400": + description: bad request + "401": + description: unauthorized + "404": + description: not found + "500": + description: internal error + security: + - OAuth2 Bearer: + - write:statuses + summary: Create a new status. + tags: + - statuses + /api/v1/statuses/{id}: + delete: + description: |- + The deleted status will be returned in the response. The `text` field will contain the original text of the status as it was submitted. + This is useful when doing a 'delete and redraft' type operation. + operationId: statusDelete + parameters: + - description: Target status ID. + in: path + name: id + required: true + type: string + produces: + - application/json + responses: + "200": + description: The newly deleted status. + schema: + $ref: '#/definitions/status' + "400": + description: bad request + "401": + description: unauthorized + "403": + description: forbidden + "404": + description: not found + security: + - OAuth2 Bearer: + - write:statuses + summary: Delete status with the given ID. The status must belong to you. + tags: + - statuses + get: + operationId: statusGet + parameters: + - description: Target status ID. + in: path + name: id + required: true + type: string + produces: + - application/json + responses: + "200": + description: The requested created status. + schema: + $ref: '#/definitions/status' + "400": + description: bad request + "401": + description: unauthorized + "404": + description: not found + "500": + description: internal error + security: + - OAuth2 Bearer: + - read:statuses + summary: View status with the given ID. + tags: + - statuses + /api/v1/statuses/{id}/context: + get: + description: The returned statuses will be ordered in a thread structure, so + they are suitable to be displayed in the order in which they were returned. + operationId: statusContext + parameters: + - description: Target status ID. + in: path + name: id + required: true + type: string + produces: + - application/json + responses: + "200": + description: Status context object. + schema: + $ref: '#/definitions/statusContext' + "400": + description: bad request + "401": + description: unauthorized + "403": + description: forbidden + "404": + description: not found + security: + - OAuth2 Bearer: + - read:statuses + summary: Return ancestors and descendants of the given status. + tags: + - statuses + /api/v1/statuses/{id}/favourite: + post: + operationId: statusFave + parameters: + - description: Target status ID. + in: path + name: id + required: true + type: string + produces: + - application/json + responses: + "200": + description: The newly faved status. + schema: + $ref: '#/definitions/status' + "400": + description: bad request + "401": + description: unauthorized + "403": + description: forbidden + "404": + description: not found + security: + - OAuth2 Bearer: + - write:statuses + summary: Star/like/favourite the given status, if permitted. + tags: + - statuses + /api/v1/statuses/{id}/favourited_by: + get: + operationId: statusFavedBy + parameters: + - description: Target status ID. + in: path + name: id + required: true + type: string + produces: + - application/json + responses: + "200": + description: "" + schema: + items: + $ref: '#/definitions/account' + type: array + "400": + description: bad request + "401": + description: unauthorized + "403": + description: forbidden + "404": + description: not found + security: + - OAuth2 Bearer: + - read:accounts + summary: View accounts that have faved/starred/liked the target status. + tags: + - statuses + /api/v1/statuses/{id}/reblog: + post: + description: |- + If the target status is rebloggable/boostable, it will be shared with your followers. + This is equivalent to an activitypub 'announce' activity. + operationId: statusReblog + parameters: + - description: Target status ID. + in: path + name: id + required: true + type: string + produces: + - application/json + responses: + "200": + description: The boost of the status. + schema: + $ref: '#/definitions/status' + "400": + description: bad request + "401": + description: unauthorized + "403": + description: forbidden + "404": + description: not found + security: + - OAuth2 Bearer: + - write:statuses + summary: Reblog/boost status with the given ID. + tags: + - statuses + /api/v1/statuses/{id}/reblogged_by: + get: + operationId: statusBoostedBy + parameters: + - description: Target status ID. + in: path + name: id + required: true + type: string + produces: + - application/json + responses: + "200": + description: "" + schema: + items: + $ref: '#/definitions/account' + type: array + "400": + description: bad request + "401": + description: unauthorized + "403": + description: forbidden + "404": + description: not found + security: + - OAuth2 Bearer: + - read:accounts + summary: View accounts that have reblogged/boosted the target status. + tags: + - statuses + /api/v1/statuses/{id}/unfavourite: + post: + operationId: statusUnfave + parameters: + - description: Target status ID. + in: path + name: id + required: true + type: string + produces: + - application/json + responses: + "200": + description: The unfaved status. + schema: + $ref: '#/definitions/status' + "400": + description: bad request + "401": + description: unauthorized + "403": + description: forbidden + "404": + description: not found + security: + - OAuth2 Bearer: + - write:statuses + summary: Unstar/unlike/unfavourite the given status. + tags: + - statuses + /api/v1/statuses/{id}/unreblog: + post: + operationId: statusUnreblog + parameters: + - description: Target status ID. + in: path + name: id + required: true + type: string + produces: + - application/json + responses: + "200": + description: The unboosted status. + schema: + $ref: '#/definitions/status' + "400": + description: bad request + "401": + description: unauthorized + "403": + description: forbidden + "404": + description: not found + security: + - OAuth2 Bearer: + - write:statuses + summary: Unreblog/unboost status with the given ID. + tags: + - statuses + /api/v1/streaming: + get: + description: |- + The scheme used should *always* be `wss`. The streaming basepath can be viewed at `/api/v1/instance`. + + On a successful connection, a code `101` will be returned, which indicates that the connection is being upgraded to a secure websocket connection. + + As long as the connection is open, various message types will be streamed into it. + + GoToSocial will ping the connection every 30 seconds to check whether the client is still receiving. + + If the ping fails, or something else goes wrong during transmission, then the connection will be dropped, and the client will be expected to start it again. + operationId: streamGet + parameters: + - description: Access token for the requesting account. + in: query + name: access_token + required: true + type: string + - description: |- + Type of stream to request. + + Options are: + + `user`: receive updates for the account's home timeline. + `public`: receive updates for the public timeline. + `public:local`: receive updates for the local timeline. + `hashtag`: receive updates for a given hashtag. + `hashtag:local`: receive local updates for a given hashtag. + `list`: receive updates for a certain list of accounts. + `direct`: receive updates for direct messages. + in: query + name: stream + required: true + type: string + produces: + - application/json + responses: + "101": + description: "" + schema: + properties: + event: + description: |- + The type of event being received. + + `update`: a new status has been received. + `notification`: a new notification has been received. + `delete`: a status has been deleted. + `filters_changed`: not implemented. + enum: + - update + - notification + - delete + - filters_changed + type: string + payload: + description: |- + The payload of the streamed message. + Different depending on the `event` type. + + If present, it should be parsed as a string. + + If `event` = `update`, then the payload will be a JSON string of a status. + If `event` = `notification`, then the payload will be a JSON string of a notification. + If `event` = `delete`, then the payload will be a status ID. + example: '{"id":"01FC3TZ5CFG6H65GCKCJRKA669","created_at":"2021-08-02T16:25:52Z","sensitive":false,"spoiler_text":"","visibility":"public","language":"en","uri":"https://gts.superseriousbusiness.org/users/dumpsterqueer/statuses/01FC3TZ5CFG6H65GCKCJRKA669","url":"https://gts.superseriousbusiness.org/@dumpsterqueer/statuses/01FC3TZ5CFG6H65GCKCJRKA669","replies_count":0,"reblogs_count":0,"favourites_count":0,"favourited":false,"reblogged":false,"muted":false,"bookmarked":fals…//gts.superseriousbusiness.org/fileserver/01JNN207W98SGG3CBJ76R5MVDN/header/original/019036W043D8FXPJKSKCX7G965.png","header_static":"https://gts.superseriousbusiness.org/fileserver/01JNN207W98SGG3CBJ76R5MVDN/header/small/019036W043D8FXPJKSKCX7G965.png","followers_count":33,"following_count":28,"statuses_count":126,"last_status_at":"2021-08-02T16:25:52Z","emojis":[],"fields":[]},"media_attachments":[],"mentions":[],"tags":[],"emojis":[],"card":null,"poll":null,"text":"a"}' + type: string + stream: + items: + enum: + - user + - public + - public:local + - hashtag + - hashtag:local + - list + - direct + type: string + type: array + type: object + "400": + description: bad request + "401": + description: unauthorized + schemes: + - wss + security: + - OAuth2 Bearer: + - read:streaming + summary: Initiate a websocket connection for live streaming of statuses and + notifications. + tags: + - streaming + /api/v1/timelines/home: + get: + description: |- + The statuses will be returned in descending chronological order (newest first), with sequential IDs (bigger = newer). + + The returned Link header can be used to generate the previous and next queries when scrolling up or down a timeline. + + Example: + + ``` + <https://example.org/api/v1/timelines/home?limit=20&max_id=01FC3GSQ8A3MMJ43BPZSGEG29M>; rel="next", <https://example.org/api/v1/timelines/home?limit=20&min_id=01FC3KJW2GYXSDDRA6RWNDM46M>; rel="prev" + ```` + operationId: homeTimeline + parameters: + - description: |- + Return only statuses *OLDER* than the given max status ID. + The status with the specified ID will not be included in the response. + in: query + name: max_id + type: string + - description: |- + Return only statuses *NEWER* than the given since status ID. + The status with the specified ID will not be included in the response. + in: query + name: since_id + type: string + - description: |- + Return only statuses *NEWER* than the given since status ID. + The status with the specified ID will not be included in the response. + in: query + name: min_id + type: string + - default: 20 + description: Number of statuses to return. + in: query + name: limit + type: integer + - default: false + description: Show only statuses posted by local accounts. + in: query + name: local + type: boolean + produces: + - application/json + responses: + "200": + description: Array of statuses. + headers: + Link: + description: Links to the next and previous queries. + type: string + schema: + items: + $ref: '#/definitions/status' + type: array + "400": + description: bad request + "401": + description: unauthorized + security: + - OAuth2 Bearer: + - read:statuses + summary: See statuses/posts by accounts you follow. + tags: + - timelines + /api/v1/timelines/public: + get: + description: |- + The statuses will be returned in descending chronological order (newest first), with sequential IDs (bigger = newer). + + The returned Link header can be used to generate the previous and next queries when scrolling up or down a timeline. + + Example: + + ``` + <https://example.org/api/v1/timelines/public?limit=20&max_id=01FC3GSQ8A3MMJ43BPZSGEG29M>; rel="next", <https://example.org/api/v1/timelines/public?limit=20&min_id=01FC3KJW2GYXSDDRA6RWNDM46M>; rel="prev" + ```` + operationId: publicTimeline + parameters: + - description: |- + Return only statuses *OLDER* than the given max status ID. + The status with the specified ID will not be included in the response. + in: query + name: max_id + type: string + - description: |- + Return only statuses *NEWER* than the given since status ID. + The status with the specified ID will not be included in the response. + in: query + name: since_id + type: string + - description: |- + Return only statuses *NEWER* than the given since status ID. + The status with the specified ID will not be included in the response. + in: query + name: min_id + type: string + - default: 20 + description: Number of statuses to return. + in: query + name: limit + type: integer + - default: false + description: Show only statuses posted by local accounts. + in: query + name: local + type: boolean + produces: + - application/json + responses: + "200": + description: Array of statuses. + headers: + Link: + description: Links to the next and previous queries. + type: string + schema: + items: + $ref: '#/definitions/status' + type: array + "400": + description: bad request + "401": + description: unauthorized + security: + - OAuth2 Bearer: + - read:statuses + summary: See public statuses/posts that your instance is aware of. + tags: + - timelines schemes: - https - http @@ -1664,10 +3324,17 @@ securityDefinitions: admin:accounts: grants admin access to accounts read: grants read access to everything read:accounts: grants read access to accounts + read:blocks: grant read access to blocks + read:media: grant read access to media + read:search: grant read access to searches + read:statuses: grants read access to statuses + read:streaming: grants read access to streaming api write: grants write access to everything write:accounts: grants write access to accounts write:blocks: grants write access to blocks write:follows: grants write access to follows + write:media: grants write access to media + write:statuses: grants write access to statuses tokenUrl: https://example.org/oauth/token type: oauth2 swagger: "2.0" diff --git a/docs/swagger.go b/docs/swagger.go @@ -35,10 +35,17 @@ // scopes: // read: grants read access to everything // read:accounts: grants read access to accounts +// read:blocks: grant read access to blocks +// read:media: grant read access to media +// read:search: grant read access to searches +// read:statuses: grants read access to statuses +// read:streaming: grants read access to streaming api // write: grants write access to everything // write:accounts: grants write access to accounts // write:blocks: grants write access to blocks // write:follows: grants write access to follows +// write:media: grants write access to media +// write:statuses: grants write access to statuses // admin: grants admin access to everything // admin:accounts: grants admin access to accounts // OAuth2 Application: diff --git a/internal/api/client/account/accountcreate.go b/internal/api/client/account/accountcreate.go @@ -30,13 +30,13 @@ import ( "github.com/superseriousbusiness/gotosocial/internal/util" ) -// AccountCreatePOSTHandler handles create account requests, validates them, -// and puts them in the database if they're valid. -// -// swagger:operation POST /api/v1/accounts accountCreate +// AccountCreatePOSTHandler swagger:operation POST /api/v1/accounts accountCreate // // Create a new account using an application token. // +// The parameters can also be given in the body of the request, as JSON, if the content-type is set to 'application/json'. +// The parameters can also be given in the body of the request, as XML, if the content-type is set to 'application/xml'. +// // --- // tags: // - accounts @@ -45,17 +45,10 @@ import ( // - application/json // - application/xml // - application/x-www-form-urlencoded -// - multipart/form-data // // produces: // - application/json // -// parameters: -// - name: Account Create Request -// in: body -// schema: -// "$ref": "#/definitions/accountCreateRequest" -// // security: // - OAuth2 Application: // - write:accounts diff --git a/internal/api/client/account/accountget.go b/internal/api/client/account/accountget.go @@ -25,9 +25,7 @@ import ( "github.com/superseriousbusiness/gotosocial/internal/oauth" ) -// AccountGETHandler returns info about the given account. -// -// swagger:operation GET /api/v1/accounts/{id} accountGet +// AccountGETHandler swagger:operation GET /api/v1/accounts/{id} accountGet // // Get information about an account with the given ID. // diff --git a/internal/api/client/account/accountupdate.go b/internal/api/client/account/accountupdate.go @@ -26,10 +26,7 @@ import ( "github.com/superseriousbusiness/gotosocial/internal/oauth" ) -// AccountUpdateCredentialsPATCHHandler allows a user to modify their account/profile settings. -// It should be served as a PATCH at /api/v1/accounts/update_credentials -// -// swagger:operation PATCH /api/v1/accounts/update_credentials accountUpdate +// AccountUpdateCredentialsPATCHHandler swagger:operation PATCH /api/v1/accounts/update_credentials accountUpdate // // Update your account. // @@ -56,10 +53,12 @@ import ( // in: formData // description: The display name to use for the account. // type: string +// allowEmptyValue: true // - name: note // in: formData // description: Bio/description of this account. // type: string +// allowEmptyValue: true // - name: avatar // in: formData // description: Avatar of the user. @@ -72,15 +71,15 @@ import ( // in: formData // description: Require manual approval of follow requests. // type: boolean -// - name: source.privacy +// - name: source[privacy] // in: formData // description: Default post privacy for authored statuses. // type: string -// - name: source.sensitive +// - name: source[sensitive] // in: formData // description: Mark authored statuses as sensitive by default. // type: boolean -// - name: source.language +// - name: source[language] // in: formData // description: Default language to use for authored statuses (ISO 6391). // type: string diff --git a/internal/api/client/account/accountverify.go b/internal/api/client/account/accountverify.go @@ -25,11 +25,7 @@ import ( "github.com/superseriousbusiness/gotosocial/internal/oauth" ) -// AccountVerifyGETHandler serves a user's account details to them IF they reached this -// handler while in possession of a valid token, according to the oauth middleware. -// It should be served as a GET at /api/v1/accounts/verify_credentials. -// -// swagger:operation GET /api/v1/accounts/verify_credentials accountVerify +// AccountVerifyGETHandler swagger:operation GET /api/v1/accounts/verify_credentials accountVerify // // Verify a token by returning account details pertaining to it. // diff --git a/internal/api/client/account/block.go b/internal/api/client/account/block.go @@ -25,9 +25,7 @@ import ( "github.com/superseriousbusiness/gotosocial/internal/oauth" ) -// AccountBlockPOSTHandler handles the creation of a block from the authed account targeting the given account ID. -// -// swagger:operation POST /api/v1/accounts/{id}/block accountBlock +// AccountBlockPOSTHandler swagger:operation POST /api/v1/accounts/{id}/block accountBlock // // Block account with id. // diff --git a/internal/api/client/account/follow.go b/internal/api/client/account/follow.go @@ -26,25 +26,43 @@ import ( "github.com/superseriousbusiness/gotosocial/internal/oauth" ) -// AccountFollowPOSTHandler is the endpoint for creating a new follow request to the target account -// -// swagger:operation POST /api/v1/accounts/{id}/follow accountFollow +// AccountFollowPOSTHandler swagger:operation POST /api/v1/accounts/{id}/follow accountFollow // // Follow account with id. // +// The parameters can also be given in the body of the request, as JSON, if the content-type is set to 'application/json'. +// The parameters can also be given in the body of the request, as XML, if the content-type is set to 'application/xml'. +// // --- // tags: // - accounts // -// produces: +// consumes: // - application/json +// - application/xml +// - application/x-www-form-urlencoded // // parameters: // - name: id -// type: string -// description: The id of the account to follow. -// in: path // required: true +// in: path +// description: ID of the account to follow. +// type: string +// - default: true +// description: Show reblogs from this account. +// in: formData +// name: reblogs +// type: boolean +// x-go-name: Reblogs +// - default: false +// description: Notify when this account posts. +// in: formData +// name: notify +// type: boolean +// x-go-name: Notify +// +// produces: +// - application/json // // security: // - OAuth2 Bearer: @@ -79,7 +97,7 @@ func (m *Module) AccountFollowPOSTHandler(c *gin.Context) { c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) return } - form.TargetAccountID = targetAcctID + form.ID = targetAcctID relationship, errWithCode := m.processor.AccountFollowCreate(authed, form) if errWithCode != nil { diff --git a/internal/api/client/account/followers.go b/internal/api/client/account/followers.go @@ -25,9 +25,7 @@ import ( "github.com/superseriousbusiness/gotosocial/internal/oauth" ) -// AccountFollowersGETHandler serves the followers of the requested account, if they're visible to the requester. -// -// swagger:operation GET /api/v1/accounts/{id}/followers accountFollowers +// AccountFollowersGETHandler swagger:operation GET /api/v1/accounts/{id}/followers accountFollowers // // See followers of account with given id. // diff --git a/internal/api/client/account/following.go b/internal/api/client/account/following.go @@ -25,9 +25,7 @@ import ( "github.com/superseriousbusiness/gotosocial/internal/oauth" ) -// AccountFollowingGETHandler serves the following of the requested account, if they're visible to the requester. -// -// swagger:operation GET /api/v1/accounts/{id}/following accountFollowing +// AccountFollowingGETHandler swagger:operation GET /api/v1/accounts/{id}/following accountFollowing // // See accounts followed by given account id. // diff --git a/internal/api/client/account/relationships.go b/internal/api/client/account/relationships.go @@ -8,9 +8,7 @@ import ( "github.com/superseriousbusiness/gotosocial/internal/oauth" ) -// AccountRelationshipsGETHandler serves the relationship of the requesting account with one or more requested account IDs. -// -// swagger:operation GET /api/v1/accounts/relationships accountRelationships +// AccountRelationshipsGETHandler swagger:operation GET /api/v1/accounts/relationships accountRelationships // // See your account's relationships with the given account IDs. // diff --git a/internal/api/client/account/statuses.go b/internal/api/client/account/statuses.go @@ -26,9 +26,7 @@ import ( "github.com/superseriousbusiness/gotosocial/internal/oauth" ) -// AccountStatusesGETHandler serves the statuses of the requested account, if they're visible to the requester. -// -// swagger:operation GET /api/v1/accounts/{id}/statuses accountStatuses +// AccountStatusesGETHandler swagger:operation GET /api/v1/accounts/{id}/statuses accountStatuses // // See statuses posted by the requested account. // @@ -86,7 +84,7 @@ import ( // responses: // '200': // name: statuses -// description: Array of statuses.. +// description: Array of statuses. // schema: // type: array // items: diff --git a/internal/api/client/account/unblock.go b/internal/api/client/account/unblock.go @@ -25,9 +25,7 @@ import ( "github.com/superseriousbusiness/gotosocial/internal/oauth" ) -// AccountUnblockPOSTHandler handles the removal of a block from the authed account targeting the given account ID. -// -// swagger:operation POST /api/v1/accounts/{id}/unblock accountUnblock +// AccountUnblockPOSTHandler swagger:operation POST /api/v1/accounts/{id}/unblock accountUnblock // // Unblock account with ID. // diff --git a/internal/api/client/account/unfollow.go b/internal/api/client/account/unfollow.go @@ -25,9 +25,7 @@ import ( "github.com/superseriousbusiness/gotosocial/internal/oauth" ) -// AccountUnfollowPOSTHandler is the endpoint for removing a follow and/or follow request to the target account -// -// swagger:operation POST /api/v1/accounts/{id}/unfollow accountUnfollow +// AccountUnfollowPOSTHandler swagger:operation POST /api/v1/accounts/{id}/unfollow accountUnfollow // // Unfollow account with id. // diff --git a/internal/api/client/admin/domainblockcreate.go b/internal/api/client/admin/domainblockcreate.go @@ -12,13 +12,11 @@ import ( "github.com/superseriousbusiness/gotosocial/internal/oauth" ) -// DomainBlocksPOSTHandler deals with the creation of one or more domain blocks. -// -// swagger:operation PATCH /api/v1/admin/domain_blocks domainBlockCreate +// DomainBlocksPOSTHandler swagger:operation POST /api/v1/admin/domain_blocks domainBlockCreate // // Create one or more domain blocks, from a string or a file. // -// Note that you have two options when using this endpoint: either you can set 'import' to true +// Note that you have two options when using this endpoint: either you can set `import` to true // and upload a file containing multiple domain blocks, JSON-formatted, or you can leave import as // false, and just add one domain block. // @@ -46,38 +44,35 @@ import ( // in: formData // description: |- // JSON-formatted list of domain blocks to import. -// This is only used if 'import' is set to true. +// This is only used if `import` is set to true. // type: file // - name: domain // in: formData // description: |- // Single domain to block. -// Used only if 'import' is not true. +// Used only if `import` is not true. // type: string -// example: example.org // - name: obfuscate // in: formData // description: |- // Obfuscate the name of the domain when serving it publicly. // Eg., 'example.org' becomes something like 'ex***e.org'. -// Used only if 'import' is not true. +// Used only if `import` is not true. // type: boolean // - name: public_comment // in: formData // description: |- // Public comment about this domain block. // Will be displayed alongside the domain block if you choose to share blocks. -// Used only if 'import' is not true. +// Used only if `import` is not true. // type: string -// example: "harassment, transphobia" // - name: private_comment // in: formData // description: |- // Private comment about this domain block. Will only be shown to other admins, so this // is a useful way of internally keeping track of why a certain domain ended up blocked. -// Used only if 'import' is not true. +// Used only if `import` is not true. // type: string -// example: "harassment, transphobia, and some stuff only other admins need to know about" // // security: // - OAuth2 Bearer: @@ -86,9 +81,8 @@ import ( // responses: // '200': // description: |- -// The newly created domain block, if import != true. -// Note that if a list has been imported, then an `array` of -// newly created domain blocks will be returned instead. +// The newly created domain block, if `import` != `true`. +// Note that if a list has been imported, then an `array` of newly created domain blocks will be returned instead. // schema: // "$ref": "#/definitions/domainBlock" // '403': diff --git a/internal/api/client/admin/domainblockdelete.go b/internal/api/client/admin/domainblockdelete.go @@ -8,9 +8,7 @@ import ( "github.com/superseriousbusiness/gotosocial/internal/oauth" ) -// DomainBlockDELETEHandler deals with the delete of an existing domain block. -// -// swagger:operation DELETE /api/v1/admin/domain_blocks/{id} domainBlockDelete +// DomainBlockDELETEHandler swagger:operation DELETE /api/v1/admin/domain_blocks/{id} domainBlockDelete // // Delete domain block with the given ID. // diff --git a/internal/api/client/admin/domainblockget.go b/internal/api/client/admin/domainblockget.go @@ -9,9 +9,7 @@ import ( "github.com/superseriousbusiness/gotosocial/internal/oauth" ) -// DomainBlockGETHandler returns one existing domain block, identified by its id. -// -// swagger:operation GET /api/v1/admin/domain_blocks/{id} domainBlockGet +// DomainBlockGETHandler swagger:operation GET /api/v1/admin/domain_blocks/{id} domainBlockGet // // View domain block with the given ID. // diff --git a/internal/api/client/admin/domainblocksget.go b/internal/api/client/admin/domainblocksget.go @@ -9,9 +9,7 @@ import ( "github.com/superseriousbusiness/gotosocial/internal/oauth" ) -// DomainBlocksGETHandler returns a list of all existing domain blocks. -// -// swagger:operation GET /api/v1/admin/domain_blocks domainBlocksGet +// DomainBlocksGETHandler swagger:operation GET /api/v1/admin/domain_blocks domainBlocksGet // // View all domain blocks currently in place. // diff --git a/internal/api/client/admin/emojicreate.go b/internal/api/client/admin/emojicreate.go @@ -31,9 +31,7 @@ import ( "github.com/superseriousbusiness/gotosocial/internal/util" ) -// emojiCreateRequest handles the creation of a new instance emoji. -// -// swagger:operation POST /api/v1/admin/custom_emojis emojiCreate +// emojiCreateRequest swagger:operation POST /api/v1/admin/custom_emojis emojiCreate // // Upload and create a new instance emoji. // @@ -55,11 +53,12 @@ import ( // This must be unique on the instance. // type: string // pattern: \w{2,30} -// example: blobcat_uwu -// - name: domains +// required: true +// - name: image // in: formData // description: A png or gif image of the emoji. Animated pngs work too! // type: file +// required: true // // security: // - OAuth2 Bearer: diff --git a/internal/api/client/app/appcreate.go b/internal/api/client/app/appcreate.go @@ -27,8 +27,41 @@ import ( "github.com/superseriousbusiness/gotosocial/internal/oauth" ) -// AppsPOSTHandler should be served at https://example.org/api/v1/apps -// It is equivalent to: https://docs.joinmastodon.org/methods/apps/ +// AppsPOSTHandler swagger:operation POST /api/v1/apps appCreate +// +// Register a new application on this instance. +// +// The registered application can be used to obtain an application token. +// This can then be used to register a new account, or (through user auth) obtain an access token. +// +// The parameters can also be given in the body of the request, as JSON, if the content-type is set to 'application/json'. +// The parameters can also be given in the body of the request, as XML, if the content-type is set to 'application/xml'. +// +// --- +// tags: +// - apps +// +// consumes: +// - application/json +// - application/xml +// - application/x-www-form-urlencoded +// +// produces: +// - application/json +// +// responses: +// '200': +// description: "The newly-created application." +// schema: +// "$ref": "#/definitions/application" +// '401': +// description: unauthorized +// '400': +// description: bad request +// '422': +// description: unprocessable +// '500': +// description: internal error func (m *Module) AppsPOSTHandler(c *gin.Context) { l := m.log.WithField("func", "AppsPOSTHandler") l.Trace("entering AppsPOSTHandler") diff --git a/internal/api/client/blocks/blocksget.go b/internal/api/client/blocks/blocksget.go @@ -26,7 +26,63 @@ import ( "github.com/superseriousbusiness/gotosocial/internal/oauth" ) -// BlocksGETHandler handles GETting blocks. +// BlocksGETHandler swagger:operation GET /api/v1/blocks blocksGet +// +// Get an array of accounts that requesting account has blocked. +// +// The next and previous queries can be parsed from the returned Link header. +// Example: +// +// ``` +// <https://example.org/api/v1/blocks?limit=80&max_id=01FC0SKA48HNSVR6YKZCQGS2V8>; rel="next", <https://example.org/api/v1/blocks?limit=80&min_id=01FC0SKW5JK2Q4EVAV2B462YY0>; rel="prev" +// ```` +// +// --- +// tags: +// - blocks +// +// produces: +// - application/json +// +// parameters: +// - name: limit +// type: integer +// description: Number of blocks to return. +// default: 20 +// in: query +// - name: max_id +// type: string +// description: |- +// Return only blocks *OLDER* than the given max block ID. +// The block with the specified ID will not be included in the response. +// in: query +// - name: since_id +// type: string +// description: |- +// Return only blocks *NEWER* than the given since block ID. +// The block with the specified ID will not be included in the response. +// in: query +// +// security: +// - OAuth2 Bearer: +// - read:blocks +// +// responses: +// '200': +// headers: +// Link: +// type: string +// description: Links to the next and previous queries. +// schema: +// type: array +// items: +// "$ref": "#/definitions/account" +// '401': +// description: unauthorized +// '400': +// description: bad request +// '404': +// description: not found func (m *Module) BlocksGETHandler(c *gin.Context) { l := m.log.WithField("func", "PublicTimelineGETHandler") diff --git a/internal/api/client/instance/instanceget.go b/internal/api/client/instance/instanceget.go @@ -6,7 +6,28 @@ import ( "github.com/gin-gonic/gin" ) -// InstanceInformationGETHandler is for serving instance information at /api/v1/instance +// InstanceInformationGETHandler swagger:operation GET /api/v1/instance instanceGet +// +// View instance information. +// +// This is mostly provided for Mastodon application compatibility, since many apps that work with Mastodon use `/api/v1/instance` to inform their connection parameters. +// +// However, it can also be used by other instances for gathering instance information and representing instances in some UI or other. +// +// --- +// tags: +// - instance +// +// produces: +// - application/json +// +// responses: +// '200': +// description: "Instance information." +// schema: +// "$ref": "#/definitions/instance" +// '500': +// description: internal error func (m *Module) InstanceInformationGETHandler(c *gin.Context) { l := m.log.WithField("func", "InstanceInformationGETHandler") diff --git a/internal/api/client/instance/instancepatch.go b/internal/api/client/instance/instancepatch.go @@ -8,7 +8,81 @@ import ( "github.com/superseriousbusiness/gotosocial/internal/oauth" ) -// InstanceUpdatePATCHHandler allows an admin to update the instance information served at /api/v1/instance +// InstanceUpdatePATCHHandler swagger:operation PATCH /api/v1/instance instanceUpdate +// +// Update your instance information and/or upload a new avatar/header for the instance. +// +// This requires admin permissions on the instance. +// +// --- +// tags: +// - instance +// +// consumes: +// - multipart/form-data +// +// produces: +// - application/json +// +// parameters: +// - name: title +// in: formData +// description: Title to use for the instance. +// type: string +// maximum: 40 +// allowEmptyValue: true +// - name: contact_username +// in: formData +// description: |- +// Username of the contact account. +// This must be the username of an instance admin. +// type: string +// allowEmptyValue: true +// - name: contact_email +// in: formData +// description: Email address to use as the instance contact. +// type: string +// allowEmptyValue: true +// - name: short_description +// in: formData +// description: Short description of the instance. +// type: string +// maximum: 500 +// allowEmptyValue: true +// - name: description +// in: formData +// description: Longer description of the instance. +// type: string +// maximum: 5000 +// allowEmptyValue: true +// - name: terms +// in: formData +// description: Terms and conditions of the instance. +// type: string +// maximum: 5000 +// allowEmptyValue: true +// - name: avatar +// in: formData +// description: Avatar of the instance. +// type: file +// - name: header +// in: formData +// description: Header of the instance. +// type: file +// +// security: +// - OAuth2 Bearer: +// - admin +// +// responses: +// '200': +// description: "The newly updated instance." +// schema: +// "$ref": "#/definitions/instance" +// '401': +// description: unauthorized +// '400': +// description: bad request func (m *Module) InstanceUpdatePATCHHandler(c *gin.Context) { l := m.log.WithField("func", "InstanceUpdatePATCHHandler") authed, err := oauth.Authed(c, true, true, true, true) diff --git a/internal/api/client/media/mediacreate.go b/internal/api/client/media/mediacreate.go @@ -29,7 +29,58 @@ import ( "github.com/superseriousbusiness/gotosocial/internal/oauth" ) -// MediaCreatePOSTHandler handles requests to create/upload media attachments +// MediaCreatePOSTHandler swagger:operation POST /api/v1/media mediaCreate +// +// Upload a new media attachment. +// +// --- +// tags: +// - media +// +// consumes: +// - multipart/form-data +// +// produces: +// - application/json +// +// parameters: +// - name: description +// in: formData +// description: |- +// Image or media description to use as alt-text on the attachment. +// This is very useful for users of screenreaders. +// May or may not be required, depending on your instance settings. +// type: string +// - name: focus +// in: formData +// description: |- +// Focus of the media file. +// If present, it should be in the form of two comma-separated floats between -1 and 1. +// For example: `-0.5,0.25`. +// type: string +// - name: file +// in: formData +// description: The media attachment to upload. +// type: file +// required: true +// +// security: +// - OAuth2 Bearer: +// - write:media +// +// responses: +// '200': +// description: The newly-created media attachment. +// schema: +// "$ref": "#/definitions/attachment" +// '400': +// description: bad request +// '401': +// description: unauthorized +// '403': +// description: forbidden +// '422': +// description: unprocessable func (m *Module) MediaCreatePOSTHandler(c *gin.Context) { l := m.log.WithField("func", "statusCreatePOSTHandler") authed, err := oauth.Authed(c, true, true, true, true) // posting new media is serious business so we want *everything* diff --git a/internal/api/client/media/mediaget.go b/internal/api/client/media/mediaget.go @@ -1,12 +1,3 @@ -package media - -import ( - "net/http" - - "github.com/gin-gonic/gin" - "github.com/superseriousbusiness/gotosocial/internal/oauth" -) - /* GoToSocial Copyright (C) 2021 GoToSocial Authors admin@gotosocial.org @@ -25,7 +16,50 @@ import ( along with this program. If not, see <http://www.gnu.org/licenses/>. */ -// MediaGETHandler allows the owner of an attachment to get information about that attachment before it's used in a status. +package media + +import ( + "net/http" + + "github.com/gin-gonic/gin" + "github.com/superseriousbusiness/gotosocial/internal/oauth" +) + +// MediaGETHandler swagger:operation GET /api/v1/media/{id} mediaGet +// +// Get a media attachment that you own. +// +// --- +// tags: +// - media +// +// produces: +// - application/json +// +// parameters: +// - name: id +// description: id of the attachment +// type: string +// in: path +// required: true +// +// security: +// - OAuth2 Bearer: +// - read:media +// +// responses: +// '200': +// description: The requested media attachment. +// schema: +// "$ref": "#/definitions/attachment" +// '400': +// description: bad request +// '401': +// description: unauthorized +// '403': +// description: forbidden +// '422': +// description: unprocessable func (m *Module) MediaGETHandler(c *gin.Context) { l := m.log.WithField("func", "MediaGETHandler") authed, err := oauth.Authed(c, true, true, true, true) diff --git a/internal/api/client/media/mediaupdate.go b/internal/api/client/media/mediaupdate.go @@ -1,16 +1,3 @@ -package media - -import ( - "errors" - "fmt" - "net/http" - - "github.com/gin-gonic/gin" - "github.com/superseriousbusiness/gotosocial/internal/api/model" - "github.com/superseriousbusiness/gotosocial/internal/config" - "github.com/superseriousbusiness/gotosocial/internal/oauth" -) - /* GoToSocial Copyright (C) 2021 GoToSocial Authors admin@gotosocial.org @@ -29,7 +16,80 @@ import ( along with this program. If not, see <http://www.gnu.org/licenses/>. */ -// MediaPUTHandler allows the owner of an attachment to update information about that attachment before it's used in a status. +package media + +import ( + "errors" + "fmt" + "net/http" + + "github.com/gin-gonic/gin" + "github.com/superseriousbusiness/gotosocial/internal/api/model" + "github.com/superseriousbusiness/gotosocial/internal/config" + "github.com/superseriousbusiness/gotosocial/internal/oauth" +) + +// MediaPUTHandler swagger:operation PUT /api/v1/media/{id} mediaUpdate +// +// Update a media attachment. +// +// You must own the media attachment, and the attachment must not yet be attached to a status. +// +// The parameters can also be given in the body of the request, as JSON, if the content-type is set to 'application/json'. +// The parameters can also be given in the body of the request, as XML, if the content-type is set to 'application/xml'. +// +// --- +// tags: +// - media +// +// consumes: +// - application/json +// - application/xml +// - application/x-www-form-urlencoded +// +// produces: +// - application/json +// +// parameters: +// - name: id +// description: id of the attachment to update +// type: string +// in: path +// required: true +// - name: description +// in: formData +// description: |- +// Image or media description to use as alt-text on the attachment. +// This is very useful for users of screenreaders. +// May or may not be required, depending on your instance settings. +// type: string +// allowEmptyValue: true +// - name: focus +// in: formData +// description: |- +// Focus of the media file. +// If present, it should be in the form of two comma-separated floats between -1 and 1. +// For example: `-0.5,0.25`. +// type: string +// allowEmptyValue: true +// +// security: +// - OAuth2 Bearer: +// - write:media +// +// responses: +// '200': +// description: The newly-updated media attachment. +// schema: +// "$ref": "#/definitions/attachment" +// '400': +// description: bad request +// '401': +// description: unauthorized +// '403': +// description: forbidden +// '422': +// description: unprocessable func (m *Module) MediaPUTHandler(c *gin.Context) { l := m.log.WithField("func", "MediaGETHandler") authed, err := oauth.Authed(c, true, true, true, true) diff --git a/internal/api/client/search/searchget.go b/internal/api/client/search/searchget.go @@ -29,8 +29,32 @@ import ( "github.com/superseriousbusiness/gotosocial/internal/oauth" ) -// SearchGETHandler handles searches for local and remote accounts, statuses, and hashtags. -// It corresponds to the mastodon endpoint described here: https://docs.joinmastodon.org/methods/search/ +// SearchGETHandler swagger:operation GET /api/v1/search searchGet +// +// Search for statuses, accounts, or hashtags, on this instance or elsewhere. +// +// If statuses are in the result, they will be returned in descending chronological order (newest first), with sequential IDs (bigger = newer). +// +// --- +// tags: +// - search +// +// security: +// - OAuth2 Bearer: +// - read:search +// +// responses: +// '200': +// name: search results +// description: Results of the search. +// schema: +// type: array +// items: +// "$ref": "#/definitions/searchResult" +// '401': +// description: unauthorized +// '400': +// description: bad request func (m *Module) SearchGETHandler(c *gin.Context) { l := m.log.WithFields(logrus.Fields{ "func": "SearchGETHandler", diff --git a/internal/api/client/status/statusboost.go b/internal/api/client/status/statusboost.go @@ -26,7 +26,45 @@ import ( "github.com/superseriousbusiness/gotosocial/internal/oauth" ) -// StatusBoostPOSTHandler handles boost requests against a given status ID +// StatusBoostPOSTHandler swagger:operation POST /api/v1/statuses/{id}/reblog statusReblog +// +// Reblog/boost status with the given ID. +// +// If the target status is rebloggable/boostable, it will be shared with your followers. +// This is equivalent to an activitypub 'announce' activity. +// +// --- +// tags: +// - statuses +// +// produces: +// - application/json +// +// parameters: +// - name: id +// type: string +// description: Target status ID. +// in: path +// required: true +// +// security: +// - OAuth2 Bearer: +// - write:statuses +// +// responses: +// '200': +// name: status +// description: The boost of the status. +// schema: +// "$ref": "#/definitions/status" +// '400': +// description: bad request +// '401': +// description: unauthorized +// '403': +// description: forbidden +// '404': +// description: not found func (m *Module) StatusBoostPOSTHandler(c *gin.Context) { l := m.log.WithFields(logrus.Fields{ "func": "StatusBoostPOSTHandler", diff --git a/internal/api/client/status/statusboosted_by.go b/internal/api/client/status/statusboosted_by.go @@ -1,60 +0,0 @@ -/* - 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 status - -import ( - "net/http" - - "github.com/gin-gonic/gin" - "github.com/sirupsen/logrus" - "github.com/superseriousbusiness/gotosocial/internal/oauth" -) - -// StatusBoostedByGETHandler is for serving a list of accounts that have boosted/reblogged a given status -func (m *Module) StatusBoostedByGETHandler(c *gin.Context) { - l := m.log.WithFields(logrus.Fields{ - "func": "StatusBoostedByGETHandler", - "request_uri": c.Request.RequestURI, - "user_agent": c.Request.UserAgent(), - "origin_ip": c.ClientIP(), - }) - l.Debugf("entering function") - - authed, err := oauth.Authed(c, true, true, true, true) // we don't really need an app here but we want everything else - if err != nil { - l.Errorf("error authing status boosted by request: %s", err) - c.JSON(http.StatusBadRequest, gin.H{"error": "not authed"}) - return - } - - targetStatusID := c.Param(IDKey) - if targetStatusID == "" { - c.JSON(http.StatusBadRequest, gin.H{"error": "no status id provided"}) - return - } - - mastoAccounts, err := m.processor.StatusBoostedBy(authed, targetStatusID) - if err != nil { - l.Debugf("error processing status boosted by request: %s", err) - c.JSON(http.StatusBadRequest, gin.H{"error": "bad request"}) - return - } - - c.JSON(http.StatusOK, mastoAccounts) -} diff --git a/internal/api/client/status/statusboostedby.go b/internal/api/client/status/statusboostedby.go @@ -0,0 +1,95 @@ +/* + 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 status + +import ( + "net/http" + + "github.com/gin-gonic/gin" + "github.com/sirupsen/logrus" + "github.com/superseriousbusiness/gotosocial/internal/oauth" +) + +// StatusBoostedByGETHandler swagger:operation GET /api/v1/statuses/{id}/reblogged_by statusBoostedBy +// +// View accounts that have reblogged/boosted the target status. +// +// --- +// tags: +// - statuses +// +// produces: +// - application/json +// +// parameters: +// - name: id +// type: string +// description: Target status ID. +// in: path +// required: true +// +// security: +// - OAuth2 Bearer: +// - read:accounts +// +// responses: +// '200': +// schema: +// type: array +// items: +// "$ref": "#/definitions/account" +// '400': +// description: bad request +// '401': +// description: unauthorized +// '403': +// description: forbidden +// '404': +// description: not found +func (m *Module) StatusBoostedByGETHandler(c *gin.Context) { + l := m.log.WithFields(logrus.Fields{ + "func": "StatusBoostedByGETHandler", + "request_uri": c.Request.RequestURI, + "user_agent": c.Request.UserAgent(), + "origin_ip": c.ClientIP(), + }) + l.Debugf("entering function") + + authed, err := oauth.Authed(c, true, true, true, true) // we don't really need an app here but we want everything else + if err != nil { + l.Errorf("error authing status boosted by request: %s", err) + c.JSON(http.StatusBadRequest, gin.H{"error": "not authed"}) + return + } + + targetStatusID := c.Param(IDKey) + if targetStatusID == "" { + c.JSON(http.StatusBadRequest, gin.H{"error": "no status id provided"}) + return + } + + mastoAccounts, err := m.processor.StatusBoostedBy(authed, targetStatusID) + if err != nil { + l.Debugf("error processing status boosted by request: %s", err) + c.JSON(http.StatusBadRequest, gin.H{"error": "bad request"}) + return + } + + c.JSON(http.StatusOK, mastoAccounts) +} diff --git a/internal/api/client/status/statuscontext.go b/internal/api/client/status/statuscontext.go @@ -26,7 +26,44 @@ import ( "github.com/superseriousbusiness/gotosocial/internal/oauth" ) -// StatusContextGETHandler returns the context around the given status ID. +// StatusContextGETHandler swagger:operation GET /api/v1/statuses/{id}/context statusContext +// +// Return ancestors and descendants of the given status. +// +// The returned statuses will be ordered in a thread structure, so they are suitable to be displayed in the order in which they were returned. +// +// --- +// tags: +// - statuses +// +// produces: +// - application/json +// +// parameters: +// - name: id +// type: string +// description: Target status ID. +// in: path +// required: true +// +// security: +// - OAuth2 Bearer: +// - read:statuses +// +// responses: +// '200': +// name: statuses +// description: Status context object. +// schema: +// "$ref": "#/definitions/statusContext" +// '400': +// description: bad request +// '401': +// description: unauthorized +// '403': +// description: forbidden +// '404': +// description: not found func (m *Module) StatusContextGETHandler(c *gin.Context) { l := m.log.WithFields(logrus.Fields{ "func": "StatusContextGETHandler", diff --git a/internal/api/client/status/statuscreate.go b/internal/api/client/status/statuscreate.go @@ -30,7 +30,42 @@ import ( "github.com/superseriousbusiness/gotosocial/internal/util" ) -// StatusCreatePOSTHandler deals with the creation of new statuses +// StatusCreatePOSTHandler swagger:operation POST /api/v1/statuses statusCreate +// +// Create a new status. +// +// The parameters can also be given in the body of the request, as JSON, if the content-type is set to 'application/json'. +// The parameters can also be given in the body of the request, as XML, if the content-type is set to 'application/xml'. +// +// --- +// tags: +// - statuses +// +// consumes: +// - application/json +// - application/xml +// - application/x-www-form-urlencoded +// +// produces: +// - application/json +// +// security: +// - OAuth2 Bearer: +// - write:statuses +// +// responses: +// '200': +// description: "The newly created status." +// schema: +// "$ref": "#/definitions/status" +// '401': +// description: unauthorized +// '400': +// description: bad request +// '404': +// description: not found +// '500': +// description: internal error func (m *Module) StatusCreatePOSTHandler(c *gin.Context) { l := m.log.WithField("func", "statusCreatePOSTHandler") authed, err := oauth.Authed(c, true, true, true, true) // posting a status is serious business so we want *everything* diff --git a/internal/api/client/status/statusdelete.go b/internal/api/client/status/statusdelete.go @@ -26,7 +26,44 @@ import ( "github.com/superseriousbusiness/gotosocial/internal/oauth" ) -// StatusDELETEHandler verifies and handles deletion of a status +// StatusDELETEHandler swagger:operation DELETE /api/v1/statuses/{id} statusDelete +// +// Delete status with the given ID. The status must belong to you. +// +// The deleted status will be returned in the response. The `text` field will contain the original text of the status as it was submitted. +// This is useful when doing a 'delete and redraft' type operation. +// +// --- +// tags: +// - statuses +// +// produces: +// - application/json +// +// parameters: +// - name: id +// type: string +// description: Target status ID. +// in: path +// required: true +// +// security: +// - OAuth2 Bearer: +// - write:statuses +// +// responses: +// '200': +// description: "The newly deleted status." +// schema: +// "$ref": "#/definitions/status" +// '400': +// description: bad request +// '401': +// description: unauthorized +// '403': +// description: forbidden +// '404': +// description: not found func (m *Module) StatusDELETEHandler(c *gin.Context) { l := m.log.WithFields(logrus.Fields{ "func": "StatusDELETEHandler", diff --git a/internal/api/client/status/statusfave.go b/internal/api/client/status/statusfave.go @@ -26,7 +26,41 @@ import ( "github.com/superseriousbusiness/gotosocial/internal/oauth" ) -// StatusFavePOSTHandler handles fave requests against a given status ID +// StatusFavePOSTHandler swagger:operation POST /api/v1/statuses/{id}/favourite statusFave +// +// Star/like/favourite the given status, if permitted. +// +// --- +// tags: +// - statuses +// +// produces: +// - application/json +// +// parameters: +// - name: id +// type: string +// description: Target status ID. +// in: path +// required: true +// +// security: +// - OAuth2 Bearer: +// - write:statuses +// +// responses: +// '200': +// description: "The newly faved status." +// schema: +// "$ref": "#/definitions/status" +// '400': +// description: bad request +// '401': +// description: unauthorized +// '403': +// description: forbidden +// '404': +// description: not found func (m *Module) StatusFavePOSTHandler(c *gin.Context) { l := m.log.WithFields(logrus.Fields{ "func": "StatusFavePOSTHandler", diff --git a/internal/api/client/status/statusfavedby.go b/internal/api/client/status/statusfavedby.go @@ -26,7 +26,42 @@ import ( "github.com/superseriousbusiness/gotosocial/internal/oauth" ) -// StatusFavedByGETHandler is for serving a list of accounts that have faved a given status +// StatusFavedByGETHandler swagger:operation GET /api/v1/statuses/{id}/favourited_by statusFavedBy +// +// View accounts that have faved/starred/liked the target status. +// +// --- +// tags: +// - statuses +// +// produces: +// - application/json +// +// parameters: +// - name: id +// type: string +// description: Target status ID. +// in: path +// required: true +// +// security: +// - OAuth2 Bearer: +// - read:accounts +// +// responses: +// '200': +// schema: +// type: array +// items: +// "$ref": "#/definitions/account" +// '400': +// description: bad request +// '401': +// description: unauthorized +// '403': +// description: forbidden +// '404': +// description: not found func (m *Module) StatusFavedByGETHandler(c *gin.Context) { l := m.log.WithFields(logrus.Fields{ "func": "statusGETHandler", diff --git a/internal/api/client/status/statusget.go b/internal/api/client/status/statusget.go @@ -26,7 +26,41 @@ import ( "github.com/superseriousbusiness/gotosocial/internal/oauth" ) -// StatusGETHandler is for handling requests to just get one status based on its ID +// StatusGETHandler swagger:operation GET /api/v1/statuses/{id} statusGet +// +// View status with the given ID. +// +// --- +// tags: +// - statuses +// +// produces: +// - application/json +// +// parameters: +// - name: id +// type: string +// description: Target status ID. +// in: path +// required: true +// +// security: +// - OAuth2 Bearer: +// - read:statuses +// +// responses: +// '200': +// description: "The requested created status." +// schema: +// "$ref": "#/definitions/status" +// '401': +// description: unauthorized +// '400': +// description: bad request +// '404': +// description: not found +// '500': +// description: internal error func (m *Module) StatusGETHandler(c *gin.Context) { l := m.log.WithFields(logrus.Fields{ "func": "statusGETHandler", diff --git a/internal/api/client/status/statusunboost.go b/internal/api/client/status/statusunboost.go @@ -26,7 +26,42 @@ import ( "github.com/superseriousbusiness/gotosocial/internal/oauth" ) -// StatusUnboostPOSTHandler handles unboost requests against a given status ID +// StatusUnboostPOSTHandler swagger:operation POST /api/v1/statuses/{id}/unreblog statusUnreblog +// +// Unreblog/unboost status with the given ID. +// +// --- +// tags: +// - statuses +// +// produces: +// - application/json +// +// parameters: +// - name: id +// type: string +// description: Target status ID. +// in: path +// required: true +// +// security: +// - OAuth2 Bearer: +// - write:statuses +// +// responses: +// '200': +// name: status +// description: The unboosted status. +// schema: +// "$ref": "#/definitions/status" +// '400': +// description: bad request +// '401': +// description: unauthorized +// '403': +// description: forbidden +// '404': +// description: not found func (m *Module) StatusUnboostPOSTHandler(c *gin.Context) { l := m.log.WithFields(logrus.Fields{ "func": "StatusUnboostPOSTHandler", diff --git a/internal/api/client/status/statusunfave.go b/internal/api/client/status/statusunfave.go @@ -26,7 +26,41 @@ import ( "github.com/superseriousbusiness/gotosocial/internal/oauth" ) -// StatusUnfavePOSTHandler is for undoing a fave on a status with a given ID +// StatusUnfavePOSTHandler swagger:operation POST /api/v1/statuses/{id}/unfavourite statusUnfave +// +// Unstar/unlike/unfavourite the given status. +// +// --- +// tags: +// - statuses +// +// produces: +// - application/json +// +// parameters: +// - name: id +// type: string +// description: Target status ID. +// in: path +// required: true +// +// security: +// - OAuth2 Bearer: +// - write:statuses +// +// responses: +// '200': +// description: "The unfaved status." +// schema: +// "$ref": "#/definitions/status" +// '400': +// description: bad request +// '401': +// description: unauthorized +// '403': +// description: forbidden +// '404': +// description: not found func (m *Module) StatusUnfavePOSTHandler(c *gin.Context) { l := m.log.WithFields(logrus.Fields{ "func": "StatusUnfavePOSTHandler", diff --git a/internal/api/client/streaming/stream.go b/internal/api/client/streaming/stream.go @@ -9,7 +9,103 @@ import ( "github.com/gorilla/websocket" ) -// StreamGETHandler handles the creation of a new websocket streaming request. +// StreamGETHandler swagger:operation GET /api/v1/streaming streamGet +// +// Initiate a websocket connection for live streaming of statuses and notifications. +// +// The scheme used should *always* be `wss`. The streaming basepath can be viewed at `/api/v1/instance`. +// +// On a successful connection, a code `101` will be returned, which indicates that the connection is being upgraded to a secure websocket connection. +// +// As long as the connection is open, various message types will be streamed into it. +// +// GoToSocial will ping the connection every 30 seconds to check whether the client is still receiving. +// +// If the ping fails, or something else goes wrong during transmission, then the connection will be dropped, and the client will be expected to start it again. +// +// --- +// tags: +// - streaming +// +// produces: +// - application/json +// +// schemes: +// - wss +// +// parameters: +// - name: access_token +// type: string +// description: Access token for the requesting account. +// in: query +// required: true +// - name: stream +// type: string +// description: |- +// Type of stream to request. +// +// Options are: +// +// `user`: receive updates for the account's home timeline. +// `public`: receive updates for the public timeline. +// `public:local`: receive updates for the local timeline. +// `hashtag`: receive updates for a given hashtag. +// `hashtag:local`: receive local updates for a given hashtag. +// `list`: receive updates for a certain list of accounts. +// `direct`: receive updates for direct messages. +// in: query +// required: true +// security: +// - OAuth2 Bearer: +// - read:streaming +// +// responses: +// '101': +// schema: +// type: object +// properties: +// stream: +// type: array +// items: +// type: string +// enum: +// - user +// - public +// - public:local +// - hashtag +// - hashtag:local +// - list +// - direct +// event: +// description: |- +// The type of event being received. +// +// `update`: a new status has been received. +// `notification`: a new notification has been received. +// `delete`: a status has been deleted. +// `filters_changed`: not implemented. +// type: string +// enum: +// - update +// - notification +// - delete +// - filters_changed +// payload: +// description: |- +// The payload of the streamed message. +// Different depending on the `event` type. +// +// If present, it should be parsed as a string. +// +// If `event` = `update`, then the payload will be a JSON string of a status. +// If `event` = `notification`, then the payload will be a JSON string of a notification. +// If `event` = `delete`, then the payload will be a status ID. +// type: string +// example: "{\"id\":\"01FC3TZ5CFG6H65GCKCJRKA669\",\"created_at\":\"2021-08-02T16:25:52Z\",\"sensitive\":false,\"spoiler_text\":\"\",\"visibility\":\"public\",\"language\":\"en\",\"uri\":\"https://gts.superseriousbusiness.org/users/dumpsterqueer/statuses/01FC3TZ5CFG6H65GCKCJRKA669\",\"url\":\"https://gts.superseriousbusiness.org/@dumpsterqueer/statuses/01FC3TZ5CFG6H65GCKCJRKA669\",\"replies_count\":0,\"reblogs_count\":0,\"favourites_count\":0,\"favourited\":false,\"reblogged\":false,\"muted\":false,\"bookmarked\":fals…//gts.superseriousbusiness.org/fileserver/01JNN207W98SGG3CBJ76R5MVDN/header/original/019036W043D8FXPJKSKCX7G965.png\",\"header_static\":\"https://gts.superseriousbusiness.org/fileserver/01JNN207W98SGG3CBJ76R5MVDN/header/small/019036W043D8FXPJKSKCX7G965.png\",\"followers_count\":33,\"following_count\":28,\"statuses_count\":126,\"last_status_at\":\"2021-08-02T16:25:52Z\",\"emojis\":[],\"fields\":[]},\"media_attachments\":[],\"mentions\":[],\"tags\":[],\"emojis\":[],\"card\":null,\"poll\":null,\"text\":\"a\"}" +// '401': +// description: unauthorized +// '400': +// description: bad request func (m *Module) StreamGETHandler(c *gin.Context) { l := m.log.WithField("func", "StreamGETHandler") diff --git a/internal/api/client/timeline/home.go b/internal/api/client/timeline/home.go @@ -26,15 +26,81 @@ import ( "github.com/superseriousbusiness/gotosocial/internal/oauth" ) -// HomeTimelineGETHandler serves status from the HOME timeline. +// HomeTimelineGETHandler swagger:operation GET /api/v1/timelines/home homeTimeline // -// Several different filters might be passed into this function in the query: +// See statuses/posts by accounts you follow. // -// max_id -- the maximum ID of the status to show -// since_id -- Return results newer than id -// min_id -- Return results immediately newer than id -// limit -- show only limit number of statuses -// local -- Return only local statuses? +// The statuses will be returned in descending chronological order (newest first), with sequential IDs (bigger = newer). +// +// The returned Link header can be used to generate the previous and next queries when scrolling up or down a timeline. +// +// Example: +// +// ``` +// <https://example.org/api/v1/timelines/home?limit=20&max_id=01FC3GSQ8A3MMJ43BPZSGEG29M>; rel="next", <https://example.org/api/v1/timelines/home?limit=20&min_id=01FC3KJW2GYXSDDRA6RWNDM46M>; rel="prev" +// ```` +// +// --- +// tags: +// - timelines +// +// produces: +// - application/json +// +// parameters: +// - name: max_id +// type: string +// description: |- +// Return only statuses *OLDER* than the given max status ID. +// The status with the specified ID will not be included in the response. +// in: query +// required: false +// - name: since_id +// type: string +// description: |- +// Return only statuses *NEWER* than the given since status ID. +// The status with the specified ID will not be included in the response. +// in: query +// - name: min_id +// type: string +// description: |- +// Return only statuses *NEWER* than the given since status ID. +// The status with the specified ID will not be included in the response. +// in: query +// required: false +// - name: limit +// type: integer +// description: Number of statuses to return. +// default: 20 +// in: query +// required: false +// - name: local +// type: boolean +// description: Show only statuses posted by local accounts. +// default: false +// in: query +// required: false +// +// security: +// - OAuth2 Bearer: +// - read:statuses +// +// responses: +// '200': +// name: statuses +// description: Array of statuses. +// schema: +// type: array +// items: +// "$ref": "#/definitions/status" +// headers: +// Link: +// type: string +// description: Links to the next and previous queries. +// '401': +// description: unauthorized +// '400': +// description: bad request func (m *Module) HomeTimelineGETHandler(c *gin.Context) { l := m.log.WithField("func", "HomeTimelineGETHandler") diff --git a/internal/api/client/timeline/public.go b/internal/api/client/timeline/public.go @@ -26,9 +26,81 @@ import ( "github.com/superseriousbusiness/gotosocial/internal/oauth" ) -// PublicTimelineGETHandler handles PUBLIC timeline requests. -// This includes requests to local, which are actually just public -// requests with a filter. +// PublicTimelineGETHandler swagger:operation GET /api/v1/timelines/public publicTimeline +// +// See public statuses/posts that your instance is aware of. +// +// The statuses will be returned in descending chronological order (newest first), with sequential IDs (bigger = newer). +// +// The returned Link header can be used to generate the previous and next queries when scrolling up or down a timeline. +// +// Example: +// +// ``` +// <https://example.org/api/v1/timelines/public?limit=20&max_id=01FC3GSQ8A3MMJ43BPZSGEG29M>; rel="next", <https://example.org/api/v1/timelines/public?limit=20&min_id=01FC3KJW2GYXSDDRA6RWNDM46M>; rel="prev" +// ```` +// +// --- +// tags: +// - timelines +// +// produces: +// - application/json +// +// parameters: +// - name: max_id +// type: string +// description: |- +// Return only statuses *OLDER* than the given max status ID. +// The status with the specified ID will not be included in the response. +// in: query +// required: false +// - name: since_id +// type: string +// description: |- +// Return only statuses *NEWER* than the given since status ID. +// The status with the specified ID will not be included in the response. +// in: query +// - name: min_id +// type: string +// description: |- +// Return only statuses *NEWER* than the given since status ID. +// The status with the specified ID will not be included in the response. +// in: query +// required: false +// - name: limit +// type: integer +// description: Number of statuses to return. +// default: 20 +// in: query +// required: false +// - name: local +// type: boolean +// description: Show only statuses posted by local accounts. +// default: false +// in: query +// required: false +// +// security: +// - OAuth2 Bearer: +// - read:statuses +// +// responses: +// '200': +// name: statuses +// description: Array of statuses. +// schema: +// type: array +// items: +// "$ref": "#/definitions/status" +// headers: +// Link: +// type: string +// description: Links to the next and previous queries. +// '401': +// description: unauthorized +// '400': +// description: bad request func (m *Module) PublicTimelineGETHandler(c *gin.Context) { l := m.log.WithField("func", "PublicTimelineGETHandler") diff --git a/internal/api/model/account.go b/internal/api/model/account.go @@ -23,7 +23,9 @@ import ( "net" ) -// Account represents a fediverse account of some kind, either a remote one or one on this instance. +// Account models a fediverse account. +// +// The modelled account can be either a remote account, or one on this instance. // // swagger:model account type Account struct { @@ -42,7 +44,7 @@ type Account struct { DisplayName string `json:"display_name"` // Account manually approves follow requests. Locked bool `json:"locked"` - // Account has opted into discovery features such as the profile directory. + // Account has opted into discovery features. Discoverable bool `json:"discoverable,omitempty"` // Account identifies as a bot. Bot bool `json:"bot"` @@ -90,9 +92,9 @@ type Account struct { Source *Source `json:"source,omitempty"` } -// AccountCreateRequest represents the form submitted during a POST request to /api/v1/accounts. +// AccountCreateRequest models account creation parameters. // -// swagger:model accountCreateRequest +// swagger:parameters accountCreate type AccountCreateRequest struct { // Text that will be reviewed by moderators if registrations require manual approval. Reason string `form:"reason" json:"reason" xml:"reason"` @@ -127,7 +129,8 @@ type AccountCreateRequest struct { IP net.IP `form:"-"` } -// UpdateCredentialsRequest represents the form submitted during a PATCH request to /api/v1/accounts/update_credentials. +// UpdateCredentialsRequest models an update to an account, by the account owner. +// // swagger:ignore type UpdateCredentialsRequest struct { // Account should be made discoverable and shown in the profile directory (if enabled). @@ -151,7 +154,8 @@ type UpdateCredentialsRequest struct { } // UpdateSource is to be used specifically in an UpdateCredentialsRequest. -// swagger:ignore +// +// swagger:model updateSource type UpdateSource struct { // Default post privacy for authored statuses. Privacy *string `form:"privacy" json:"privacy" xml:"privacy"` @@ -172,15 +176,14 @@ type UpdateField struct { Value *string `form:"value" json:"value" xml:"value"` } -// AccountFollowRequest is for parsing requests at /api/v1/accounts/:id/follow +// AccountFollowRequest models a request to follow an account. // -// swagger:model accountFollowRequest +// swagger:ignore type AccountFollowRequest struct { - // ID of the account to follow request - // This should be a URL parameter not a form field - TargetAccountID string `form:"-"` - // Show reblogs for this account? + // The id of the account to follow. + ID string `form:"-" json:"-" xml:"-"` + // Show reblogs from this account. Reblogs *bool `form:"reblogs" json:"reblogs" xml:"reblogs"` - // Notify when this account posts? + // Notify when this account posts. Notify *bool `form:"notify" json:"notify" xml:"notify"` } diff --git a/internal/api/model/admin.go b/internal/api/model/admin.go @@ -18,7 +18,7 @@ package model -// AdminAccountInfo represents the *admin* view of an account's details. See here: https://docs.joinmastodon.org/entities/admin-account/ +// AdminAccountInfo models the admin view of an account's details. type AdminAccountInfo struct { // The ID of the account in the database. ID string `json:"id"` @@ -56,7 +56,7 @@ type AdminAccountInfo struct { InvitedByAccountID string `json:"invited_by_account_id"` } -// AdminReportInfo represents the *admin* view of a report. See here: https://docs.joinmastodon.org/entities/admin-report/ +// AdminReportInfo models the admin view of a report. type AdminReportInfo struct { // The ID of the report in the database. ID string `json:"id"` diff --git a/internal/api/model/announcement.go b/internal/api/model/announcement.go @@ -18,20 +18,46 @@ package model -// Announcement represents an admin/moderator announcement for local users. See here: https://docs.joinmastodon.org/entities/announcement/ +// Announcement models an admin announcement for the instance. +// +// swagger:model 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"` + // The ID of the announcement. + // example: 01FC30T7X4TNCZK0TH90QYF3M4 + ID string `json:"id"` + // The body of the announcement. + // Should be HTML formatted. + // example: <p>This is an announcement. No malarky.</p> + Content string `json:"content"` + // When the announcement should begin to be displayed (ISO 8601 Datetime). + // If the announcement has no start time, this will be omitted or empty. + // example: 2021-07-30T09:20:25+00:00 + StartsAt string `json:"starts_at"` + // When the announcement should stop being displayed (ISO 8601 Datetime). + // If the announcement has no end time, this will be omitted or empty. + // example: 2021-07-30T09:20:25+00:00 + EndsAt string `json:"ends_at"` + // Announcement doesn't have begin time and end time, but begin day and end day. + AllDay bool `json:"all_day"` + // When the announcement was first published (ISO 8601 Datetime). + // example: 2021-07-30T09:20:25+00:00 + PublishedAt string `json:"published_at"` + // When the announcement was last updated (ISO 8601 Datetime). + // example: 2021-07-30T09:20:25+00:00 + UpdatedAt string `json:"updated_at"` + // Announcement is 'published', ie., visible to users. + // Announcements that are not published should be shown only to admins. + Published bool `json:"published"` + // Requesting account has seen this announcement. + Read bool `json:"read"` + // Mentions this announcement contains. + Mentions []Mention `json:"mentions"` + // Statuses contained in this announcement. + Statuses []Status `json:"statuses"` + // Tags used in this announcement. + Tags []Tag `json:"tags"` + // Emojis used in this announcement. + Emojis []Emoji `json:"emoji"` + // Reactions to this announcement. + Reactions []AnnouncementReaction `json:"reactions"` } diff --git a/internal/api/model/announcementreaction.go b/internal/api/model/announcementreaction.go @@ -18,16 +18,24 @@ package model -// AnnouncementReaction represents a user reaction to admin/moderator announcement. See here: https://docs.joinmastodon.org/entities/announcementreaction/ +// AnnouncementReaction models a user reaction to an announcement. +// +// swagger:model announcementReaction type AnnouncementReaction struct { // The emoji used for the reaction. Either a unicode emoji, or a custom emoji's shortcode. + // example: blobcat_uwu Name string `json:"name"` // The total number of users who have added this reaction. + // example: 5 Count int `json:"count"` - // Whether the authorized user has added this reaction to the announcement. + // This reaction belongs to the account viewing it. Me bool `json:"me"` - // A link to the custom emoji. + // Web link to the image of the custom emoji. + // Empty for unicode emojis. + // example: https://example.org/custom_emojis/original/blobcat_uwu.png URL string `json:"url,omitempty"` - // A link to a non-animated version of the custom emoji. + // Web link to a non-animated image of the custom emoji. + // Empty for unicode emojis. + // example: https://example.org/custom_emojis/statuc/blobcat_uwu.png StaticURL string `json:"static_url,omitempty"` } diff --git a/internal/api/model/application.go b/internal/api/model/application.go @@ -18,8 +18,7 @@ package model -// Application represents an api Application, as defined here. -// Primarily, application is used for allowing apps like Tusky etc to connect to Mastodon on behalf of a user. +// Application models an api application. // // swagger:model application type Application struct { @@ -43,18 +42,30 @@ type Application struct { VapidKey string `json:"vapid_key,omitempty"` } -// ApplicationCreateRequest 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/ +// ApplicationCreateRequest models app create parameters. +// +// swagger:parameters appCreate type ApplicationCreateRequest struct { - // A name for your application + // The name of the application. + // + // in: formData + // required: true ClientName string `form:"client_name" json:"client_name" xml:"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. + // + // 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. + // + // in: formData + // required: true RedirectURIs string `form:"redirect_uris" json:"redirect_uris" xml:"redirect_uris" binding:"required"` - // Space separated list of scopes. If none is provided, defaults to read. + // Space separated list of scopes. + // + // If no scopes are provided, defaults to `read`. + // + // in: formData Scopes string `form:"scopes" json:"scopes" xml:"scopes"` - // A URL to the homepage of your app + // A URL to the web page of the app (optional). + // + // in: formData Website string `form:"website" json:"website" xml:"website"` } diff --git a/internal/api/model/attachment.go b/internal/api/model/attachment.go @@ -20,33 +20,50 @@ package model 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/ +// AttachmentRequest models media attachment creation parameters. +// +// swagger: ignore type AttachmentRequest struct { - File *multipart.FileHeader `form:"file" binding:"required"` - Description string `form:"description"` - Focus string `form:"focus"` + // Media file. + File *multipart.FileHeader `form:"file" binding:"required"` + // Description of the media file. Optional. + // This will be used as alt-text for users of screenreaders etc. + // example: This is an image of some kittens, they are very cute and fluffy. + Description string `form:"description"` + // Focus of the media file. Optional. + // If present, it should be in the form of two comma-separated floats between -1 and 1. + // example: -0.5,0.565 + Focus string `form:"focus"` } -// AttachmentUpdateRequest represents the form data parameters submitted by a client during a media update/PUT request. -// See: https://docs.joinmastodon.org/methods/statuses/media/ +// AttachmentUpdateRequest models an update request for an attachment. +// +// swagger:ignore type AttachmentUpdateRequest struct { + // Description of the media file. + // This will be used as alt-text for users of screenreaders etc. + // allowEmptyValue: true Description *string `form:"description" json:"description" xml:"description"` - Focus *string `form:"focus" json:"focus" xml:"focus"` + // Focus of the media file. + // If present, it should be in the form of two comma-separated floats between -1 and 1. + // allowEmptyValue: true + Focus *string `form:"focus" json:"focus" xml:"focus"` } -// Attachment represents the object returned to a client after a successful media upload request. +// Attachment models a media attachment. // // swagger:model attachment type Attachment struct { // The ID of the attachment. + // example: 01FC31DZT1AYWDZ8XTCRWRBYRK 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. + // enum: + // - unknown + // - image + // - gifv + // - video + // - audio // example: image Type string `json:"type"` // The location of the original full-size attachment. @@ -64,6 +81,7 @@ type Attachment struct { // example: https://some-other-server.org/attachments/small/ahhhhh.jpeg PreviewRemoteURL string `json:"preview_remote_url,omitempty"` // A shorter URL for the attachment. + // Not currently used. TextURL string `json:"text_url,omitempty"` // Metadata for this attachment. Meta MediaMeta `json:"meta,omitempty"` @@ -75,42 +93,88 @@ type Attachment struct { Blurhash string `json:"blurhash,omitempty"` } -// MediaMeta describes the returned media +// MediaMeta models media metadata. +// This can be metadata about an image, an audio file, video, etc. // // swagger:model mediaMeta 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"` + Length string `json:"length,omitempty"` + // Duration of the media in seconds. + // Only set for video and audio. + // example: 5.43 + Duration float32 `json:"duration,omitempty"` + // Framerate of the media. + // Only set for video and gifs. + // example: 30 + FPS uint16 `json:"fps,omitempty"` + // Size of the media, in the format `[width]x[height]`. + // Not set for audio. + // example: 1920x1080 + Size string `json:"size,omitempty"` + // Width of the media in pixels. + // Not set for audio. + // example: 1920 + Width int `json:"width,omitempty"` + // Height of the media in pixels. + // Not set for audio. + // example: 1080 + Height int `json:"height,omitempty"` + // Aspect ratio of the media. + // Equal to width / height. + // example: 1.777777778 + Aspect float32 `json:"aspect,omitempty"` + AudioEncode string `json:"audio_encode,omitempty"` + AudioBitrate string `json:"audio_bitrate,omitempty"` + AudioChannels string `json:"audio_channels,omitempty"` + // Dimensions of the original media. + Original MediaDimensions `json:"original"` + // Dimensions of the thumbnail/small version of the media. + Small MediaDimensions `json:"small,omitempty"` + // Focus data for the media. + 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. +// MediaFocus models the focal point of a piece of media. // // swagger:model mediaFocus type MediaFocus struct { - X float32 `json:"x"` // should be between -1 and 1 - Y float32 `json:"y"` // should be between -1 and 1 + // x position of the focus + // should be between -1 and 1 + X float32 `json:"x"` + // y position of the focus + // should be between -1 and 1 + Y float32 `json:"y"` } -// MediaDimensions describes the physical properties of a piece of media. It should be returned to the caller as part of MediaMeta. +// MediaDimensions models detailed properties of a piece of media. // // swagger:model mediaDimensions 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"` + // Width of the media in pixels. + // Not set for audio. + // example: 1920 + Width int `json:"width,omitempty"` + // Height of the media in pixels. + // Not set for audio. + // example: 1080 + Height int `json:"height,omitempty"` + // Framerate of the media. + // Only set for video and gifs. + // example: 30 + FrameRate string `json:"frame_rate,omitempty"` + // Duration of the media in seconds. + // Only set for video and audio. + // example: 5.43 + Duration float32 `json:"duration,omitempty"` + // Bitrate of the media in bits per second. + // example: 1000000 + Bitrate int `json:"bitrate,omitempty"` + // Size of the media, in the format `[width]x[height]`. + // Not set for audio. + // example: 1920x1080 + Size string `json:"size,omitempty"` + // Aspect ratio of the media. + // Equal to width / height. + // example: 1.777777778 + Aspect float32 `json:"aspect,omitempty"` } diff --git a/internal/api/model/card.go b/internal/api/model/card.go @@ -32,11 +32,11 @@ type Card struct { // example: Is water wet? We're not sure. In this article, we ask an expert... 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. + // enum: + // - link + // - photo + // - video + // - rich // example: link Type string `json:"type"` // The author of the original resource. diff --git a/internal/api/model/context.go b/internal/api/model/context.go @@ -18,7 +18,9 @@ package model -// Context represents the tree around a given status. Used for reconstructing threads of statuses. See: https://docs.joinmastodon.org/entities/context/ +// Context models the tree around a given status. +// +// swagger:model statusContext type Context struct { // Parents in the thread. Ancestors []Status `json:"ancestors"` diff --git a/internal/api/model/instance.go b/internal/api/model/instance.go @@ -20,60 +20,77 @@ package model import "mime/multipart" -// Instance represents the software instance of Mastodon running on this domain. See https://docs.joinmastodon.org/entities/instance/ +// Instance models information about this or another instance. +// +// swagger:model instance type Instance struct { - // REQUIRED - - // The domain name of the instance. + // The URI of the instance. + // example: https://example.org URI string `json:"uri,omitempty"` - // The title of the website. + // The title of the instance. + // example: GoToSocial Example Instance Title string `json:"title,omitempty"` - // Admin-defined description of the Mastodon site. + // Description of the instance. + // + // Should be HTML formatted, but might be plaintext. + // + // This should be displayed on the 'about' page for an instance. Description string `json:"description"` - // A shorter description defined by the admin. + // A shorter description of the instance. + // + // Should be HTML formatted, but might be plaintext. + // + // This should be displayed on the instance splash/landing page. ShortDescription string `json:"short_description"` - // An email that may be contacted for any inquiries. + // An email address that may be used for inquiries. + // example: admin@example.org Email string `json:"email"` - // The version of Mastodon installed on the instance. + // The version of GoToSocial installed on the instance. + // + // This will contain at least a semantic version number. + // + // It may also contain, after a space, the short git commit ID of the running software. + // + // example: 0.1.1 cb85f65 Version string `json:"version"` - // Primary langauges of the website and its staff. + // Primary language of the instance. + // example: en Languages []string `json:"languages,omitempty"` - // Whether registrations are enabled. + // New account registrations are enabled on this instance. Registrations bool `json:"registrations"` - // Whether registrations require moderator approval. + // New account registrations require admin approval. ApprovalRequired bool `json:"approval_required"` - // Whether invites are enabled. + // Invites are enabled on this instance. InvitesEnabled bool `json:"invites_enabled"` - // URLs of interest for clients apps. + // URLs of interest for client applications. URLS *InstanceURLs `json:"urls,omitempty"` - // Statistics about how much information the instance contains. + // Statistics about the instance: number of posts, accounts, etc. Stats map[string]int `json:"stats,omitempty"` - // Banner image for the website. + // URL of the instance avatar/banner image. + // example: https://example.org/files/instance/thumbnail.jpeg Thumbnail string `json:"thumbnail"` - // A user that can be contacted, as an alternative to email. + // Contact account for the instance. ContactAccount *Account `json:"contact_account,omitempty"` - // What's the maximum allowed length of a post on this instance? - // This is provided for compatibility with Tusky. + // Maximum allowed length of a post on this instance, in characters. + // + // This is provided for compatibility with Tusky and other apps. + // + // example: 5000 MaxTootChars uint `json:"max_toot_chars"` } -// InstanceURLs represents URLs necessary for successfully connecting to the instance as a user. See https://docs.joinmastodon.org/entities/instance/ +// InstanceURLs models instance-relevant URLs for client application consumption. +// +// swagger:model instanceURLs type InstanceURLs struct { - // Websockets address for push streaming. + // Websockets address for status and notification streaming. + // example: wss://example.org 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"` -} - -// InstanceSettingsUpdateRequest is the form to be parsed on a PATCH to /api/v1/instance +// InstanceSettingsUpdateRequest models an instance update request. +// +// swagger:ignore type InstanceSettingsUpdateRequest struct { // Title to use for the instance. Max 40 characters. Title *string `form:"title" json:"title" xml:"title"` diff --git a/internal/api/model/poll.go b/internal/api/model/poll.go @@ -51,19 +51,24 @@ type Poll struct { 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. + // 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 +// PollRequest models a request to create a poll. +// +// swagger:parameters createStatus 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"` + // Array of possible answers. + // If provided, media_ids cannot be used, and poll[expires_in] must be provided. + // name: poll[options] + Options []string `form:"options" json:"options" xml:"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" json:"expires_in" xml:"expires_in"` + // Allow multiple choices on this poll. + Multiple bool `form:"multiple" json:"multiple" xml:"multiple"` + // Hide vote counts until the poll ends. + HideTotals bool `form:"hide_totals" json:"hide_totals" xml:"hide_totals"` } diff --git a/internal/api/model/search.go b/internal/api/model/search.go @@ -18,33 +18,72 @@ package model -// SearchQuery corresponds to search parameters as submitted through the client API. -// See https://docs.joinmastodon.org/methods/search/ +// SearchQuery models a search request. +// +// swagger:parameters searchGet type SearchQuery struct { - // If provided, statuses returned will be authored only by this account - AccountID string - // Return results older than this id - MaxID string - // Return results immediately newer than this id - MinID string - // Enum(accounts, hashtags, statuses) - Type string - // Filter out unreviewed tags? Defaults to false. Use true when trying to find trending tags. - ExcludeUnreviewed bool - // The search query - Query string - // Attempt WebFinger lookup. Defaults to false. - Resolve bool - // Maximum number of results to load, per type. Defaults to 20. Max 40. - Limit int - // Offset in search results. Used for pagination. Defaults to 0. - Offset int - // Only include accounts that the user is following. Defaults to false. - Following bool + // If type is `statuses`, then statuses returned will be authored only by this account. + // + // in: query + AccountID string `json:"account_id"` + // Return results *older* than this id. + // + // The entry with this ID will not be included in the search results. + // in: query + MaxID string `json:"max_id"` + // Return results *newer* than this id. + // + // The entry with this ID will not be included in the search results. + // in: query + MinID string `json:"min_id"` + // Type of the search query to perform. + // + // Must be one of: `accounts`, `hashtags`, `statuses`. + // + // enum: + // - accounts + // - hashtags + // - statuses + // required: true + // in: query + Type string `json:"type"` + // Filter out tags that haven't been reviewed and approved by an instance admin. + // + // default: false + // in: query + ExcludeUnreviewed bool `json:"exclude_unreviewed"` + // String to use as a search query. + // + // For accounts, this should be in the format `@someaccount@some.instance.com`, or the format `https://some.instance.com/@someaccount` + // + // For a status, this can be in the format: `https://some.instance.com/@someaccount/SOME_ID_OF_A_STATUS` + // + // required: true + // in: query + Query string `json:"q"` + // Attempt to resolve the query by performing a remote webfinger lookup, if the query includes a remote host. + // default: false + Resolve bool `json:"resolve"` + // Maximum number of results to load, per type. + // default: 20 + // minimum: 1 + // maximum: 40 + // in: query + Limit int `json:"limit"` + // Offset for paginating search results. + // + // default: 0 + // in: query + Offset int `json:"offset"` + // Only include accounts that the searching account is following. + // default: false + // in: query + Following bool `json:"following"` } -// SearchResult corresponds to a search result, containing accounts, statuses, and hashtags. -// See https://docs.joinmastodon.org/methods/search/ +// SearchResult models a search result. +// +// swagger:model searchResult type SearchResult struct { Accounts []Account `json:"accounts"` Statuses []Status `json:"statuses"` diff --git a/internal/api/model/status.go b/internal/api/model/status.go @@ -18,7 +18,7 @@ package model -// Status represents a status or post. +// Status models a status or post. // // swagger:model status type Status struct { @@ -71,8 +71,9 @@ type Status struct { // The content of this status. Should be HTML, but might also be plaintext in some cases. // example: <p>Hey this is a status!</p> Content string `json:"content"` - // The status that this status is a reblog/boost of. - Reblog *Status `json:"reblog,omitempty"` + // The status that this status reblogs/boosts. + // nullable: true + Reblog *StatusReblogged `json:"reblog,omitempty"` // The application used to post this status, if visible. Application *Application `json:"application"` // The account that authored this status. @@ -95,35 +96,71 @@ type Status struct { 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 +// StatusReblogged represents a reblogged status. +// +// swagger:model statusReblogged +type StatusReblogged struct { + *Status +} + +// StatusCreateRequest models status creation parameters. +// +// swagger:parameters statusCreate 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. + // Text content of the status. + // If media_ids is provided, this becomes optional. + // Attaching a poll is optional while status is provided. + // in: formData Status string `form:"status" json:"status" xml:"status"` - // Array of Attachment ids to be attached as media. If provided, status becomes optional, and poll cannot be used. + // Array of Attachment ids to be attached as media. + // If provided, status becomes optional, and poll cannot be used. + // in: formData MediaIDs []string `form:"media_ids" json:"media_ids" xml:"media_ids"` // Poll to include with this status. + // swagger:ignore Poll *PollRequest `form:"poll" json:"poll" xml:"poll"` - // ID of the status being replied to, if status is a reply + // ID of the status being replied to, if status is a reply. + // in: formData InReplyToID string `form:"in_reply_to_id" json:"in_reply_to_id" xml:"in_reply_to_id"` - // Mark status and attached media as sensitive? + // Status and attached media should be marked as sensitive. + // in: formData Sensitive bool `form:"sensitive" json:"sensitive" xml:"sensitive"` - // Text to be shown as a warning or subject before the actual content. Statuses are generally collapsed behind this field. + // Text to be shown as a warning or subject before the actual content. + // Statuses are generally collapsed behind this field. + // in: formData SpoilerText string `form:"spoiler_text" json:"spoiler_text" xml:"spoiler_text"` - // Visibility of the posted status. Enumerable oneOf public, unlisted, private, direct. + // Visibility of the posted status. + // enum: + // - public + // - unlisted + // - private + // - direct + // in: formData Visibility Visibility `form:"visibility" json:"visibility" xml:"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. + // 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. + // in: formData ScheduledAt string `form:"scheduled_at" json:"scheduled_at" xml:"scheduled_at"` // ISO 639 language code for this status. + // in: formData Language string `form:"language" json:"language" xml:"language"` - // Format in which to parse the submitted status. - // Can be either plain or markdown. Empty will default to plain. + // Format to use when parsing this status. + // enum: + // - markdown + // - plain + // in: formData Format StatusFormat `form:"format" json:"format" xml:"format"` } -// Visibility denotes the visibility of a status to other users. +// Visibility models the visibility of a status. // // swagger:model statusVisibility +// enum: +// - public +// - unlisted +// - private +// - direct type Visibility string const ( @@ -141,6 +178,8 @@ const ( // AdvancedStatusCreateForm wraps the mastodon status create form along with the GTS advanced // visibility settings. +// +// swagger:model advancedStatusCreateForm type AdvancedStatusCreateForm struct { StatusCreateRequest AdvancedVisibilityFlagsForm @@ -148,20 +187,27 @@ type AdvancedStatusCreateForm struct { // AdvancedVisibilityFlagsForm allows a few more advanced flags to be set on new statuses, in addition // to the standard mastodon-compatible ones. +// +// swagger:model advancedVisibilityFlagsForm type AdvancedVisibilityFlagsForm struct { - // The gotosocial visibility model - VisibilityAdvanced *string `form:"visibility_advanced" json:"visibility_advanced" xml:"visibility_advanced"` - // This status will be federated beyond the local timeline(s) + // This status will be federated beyond the local timeline(s). Federated *bool `form:"federated" json:"federated" xml:"federated"` - // This status can be boosted/reblogged + // This status can be boosted/reblogged. Boostable *bool `form:"boostable" json:"boostable" xml:"boostable"` - // This status can be replied to + // This status can be replied to. Replyable *bool `form:"replyable" json:"replyable" xml:"replyable"` - // This status can be liked/faved + // This status can be liked/faved. Likeable *bool `form:"likeable" json:"likeable" xml:"likeable"` } -// StatusFormat determines what kind of format a submitted status should be parsed in +// StatusFormat is the format in which to parse the submitted status. +// Can be either plain or markdown. Empty will default to plain. +// +// swagger:model statusFormat +// enum: +// - plain +// - markdown +// example: plain type StatusFormat string // StatusFormatPlain expects a plaintext status which will then be formatted into html. diff --git a/internal/gtsmodel/status.go b/internal/gtsmodel/status.go @@ -117,22 +117,24 @@ const ( VisibilityFollowersOnly Visibility = "followers_only" // VisibilityMutualsOnly means this status is visible to mutual followers only. VisibilityMutualsOnly Visibility = "mutuals_only" - // VisibilityDirect means this status is visible only to mentioned recipients + // VisibilityDirect means this status is visible only to mentioned recipients. VisibilityDirect Visibility = "direct" - // VisibilityDefault is used when no other setting can be found - VisibilityDefault Visibility = "public" + // VisibilityDefault is used when no other setting can be found. + VisibilityDefault Visibility = VisibilityUnlocked ) -// VisibilityAdvanced denotes a set of flags that can be set on a status for fine-tuning visibility and interactivity of the status. +// VisibilityAdvanced models flags for fine-tuning visibility and interactivity of a status. +// +// All flags default to true. +// +// If PUBLIC is selected, flags will all be overwritten to TRUE regardless of what is selected. +// +// If UNLOCKED is selected, any flags can be turned on or off in any combination. +// +// If FOLLOWERS-ONLY or MUTUALS-ONLY are selected, boostable will always be FALSE. Other flags can be turned on or off as desired. +// +// If DIRECT is selected, boostable will be FALSE, and all other flags will be TRUE. type VisibilityAdvanced struct { - /* - ADVANCED SETTINGS -- These should all default to TRUE. - - If PUBLIC is selected, they will all be overwritten to TRUE regardless of what is selected. - If UNLOCKED is selected, any of them can be turned on or off in any combination. - If FOLLOWERS-ONLY or MUTUALS-ONLY are selected, boostable will always be FALSE. The others can be turned on or off as desired. - If DIRECT is selected, boostable will be FALSE, and all other flags will be TRUE. - */ // This status will be federated beyond the local timeline(s) Federated bool `pg:"default:true"` // This status can be boosted/reblogged diff --git a/internal/processing/account/createfollow.go b/internal/processing/account/createfollow.go @@ -31,7 +31,7 @@ import ( func (p *processor) FollowCreate(requestingAccount *gtsmodel.Account, form *apimodel.AccountFollowRequest) (*apimodel.Relationship, gtserror.WithCode) { // if there's a block between the accounts we shouldn't create the request ofc - blocked, err := p.db.Blocked(requestingAccount.ID, form.TargetAccountID) + blocked, err := p.db.Blocked(requestingAccount.ID, form.ID) if err != nil { return nil, gtserror.NewErrorInternalError(err) } @@ -41,9 +41,9 @@ func (p *processor) FollowCreate(requestingAccount *gtsmodel.Account, form *apim // make sure the target account actually exists in our db targetAcct := &gtsmodel.Account{} - if err := p.db.GetByID(form.TargetAccountID, targetAcct); err != nil { + if err := p.db.GetByID(form.ID, targetAcct); err != nil { if _, ok := err.(db.ErrNoEntries); ok { - return nil, gtserror.NewErrorNotFound(fmt.Errorf("accountfollowcreate: account %s not found in the db: %s", form.TargetAccountID, err)) + return nil, gtserror.NewErrorNotFound(fmt.Errorf("accountfollowcreate: account %s not found in the db: %s", form.ID, err)) } } @@ -54,7 +54,7 @@ func (p *processor) FollowCreate(requestingAccount *gtsmodel.Account, form *apim } if follows { // already follows so just return the relationship - return p.RelationshipGet(requestingAccount, form.TargetAccountID) + return p.RelationshipGet(requestingAccount, form.ID) } // check if a follow exists already @@ -64,7 +64,7 @@ func (p *processor) FollowCreate(requestingAccount *gtsmodel.Account, form *apim } if followRequested { // already follow requested so just return the relationship - return p.RelationshipGet(requestingAccount, form.TargetAccountID) + return p.RelationshipGet(requestingAccount, form.ID) } // make the follow request @@ -76,7 +76,7 @@ func (p *processor) FollowCreate(requestingAccount *gtsmodel.Account, form *apim fr := &gtsmodel.FollowRequest{ ID: newFollowID, AccountID: requestingAccount.ID, - TargetAccountID: form.TargetAccountID, + TargetAccountID: form.ID, ShowReblogs: true, URI: util.GenerateURIForFollow(requestingAccount.Username, p.config.Protocol, p.config.Host, newFollowID), Notify: false, @@ -95,11 +95,11 @@ func (p *processor) FollowCreate(requestingAccount *gtsmodel.Account, form *apim // if it's a local account that's not locked we can just straight up accept the follow request if !targetAcct.Locked && targetAcct.Domain == "" { - if _, err := p.db.AcceptFollowRequest(requestingAccount.ID, form.TargetAccountID); err != nil { + if _, err := p.db.AcceptFollowRequest(requestingAccount.ID, form.ID); err != nil { return nil, gtserror.NewErrorInternalError(fmt.Errorf("accountfollowcreate: error accepting folow request for local unlocked account: %s", err)) } // return the new relationship - return p.RelationshipGet(requestingAccount, form.TargetAccountID) + return p.RelationshipGet(requestingAccount, form.ID) } // otherwise we leave the follow request as it is and we handle the rest of the process asynchronously @@ -112,5 +112,5 @@ func (p *processor) FollowCreate(requestingAccount *gtsmodel.Account, form *apim } // return whatever relationship results from this - return p.RelationshipGet(requestingAccount, form.TargetAccountID) + return p.RelationshipGet(requestingAccount, form.ID) } diff --git a/internal/processing/status/util.go b/internal/processing/status/util.go @@ -21,22 +21,18 @@ func (p *processor) processVisibility(form *apimodel.AdvancedStatusCreateForm, a Likeable: true, } - var gtsBasicVis gtsmodel.Visibility - // Advanced takes priority if it's set. - // If it's not set, take whatever masto visibility is set. - // If *that's* not set either, then just take the account default. + var vis gtsmodel.Visibility + // If visibility isn't set on the form, then just take the account default. // If that's also not set, take the default for the whole instance. - if form.VisibilityAdvanced != nil { - gtsBasicVis = gtsmodel.Visibility(*form.VisibilityAdvanced) - } else if form.Visibility != "" { - gtsBasicVis = p.tc.MastoVisToVis(form.Visibility) + if form.Visibility != "" { + vis = p.tc.MastoVisToVis(form.Visibility) } else if accountDefaultVis != "" { - gtsBasicVis = accountDefaultVis + vis = accountDefaultVis } else { - gtsBasicVis = gtsmodel.VisibilityDefault + vis = gtsmodel.VisibilityDefault } - switch gtsBasicVis { + switch vis { case gtsmodel.VisibilityPublic: // for public, there's no need to change any of the advanced flags from true regardless of what the user filled out break @@ -82,7 +78,7 @@ func (p *processor) processVisibility(form *apimodel.AdvancedStatusCreateForm, a gtsAdvancedVis.Likeable = true } - status.Visibility = gtsBasicVis + status.Visibility = vis status.VisibilityAdvanced = gtsAdvancedVis return nil } diff --git a/internal/typeutils/internaltofrontend.go b/internal/typeutils/internaltofrontend.go @@ -488,7 +488,7 @@ func (c *converter) StatusToMasto(s *gtsmodel.Status, requestingAccount *gtsmode statusInteractions = si } - return &model.Status{ + apiStatus := &model.Status{ ID: s.ID, CreatedAt: s.CreatedAt.Format(time.RFC3339), InReplyToID: s.InReplyToID, @@ -508,7 +508,6 @@ func (c *converter) StatusToMasto(s *gtsmodel.Status, requestingAccount *gtsmode Reblogged: statusInteractions.Reblogged, Pinned: s.Pinned, Content: s.Content, - Reblog: mastoRebloggedStatus, Application: mastoApplication, Account: mastoAuthorAccount, MediaAttachments: mastoAttachments, @@ -518,7 +517,13 @@ func (c *converter) StatusToMasto(s *gtsmodel.Status, requestingAccount *gtsmode Card: mastoCard, // TODO: implement cards Poll: mastoPoll, // TODO: implement polls Text: s.Text, - }, nil + } + + if mastoRebloggedStatus != nil { + apiStatus.Reblog = &model.StatusReblogged{Status: mastoRebloggedStatus} + } + + return apiStatus, nil } // VisToMasto converts a gts visibility into its mastodon equivalent