Frodo swaggins (#126)

* more swagger fun

* document a whole bunch more stuff

* more swagger yayyyyyyy

* progress + go fmt
This commit is contained in:
Tobi Smethurst 2021-08-02 19:06:44 +02:00 committed by GitHub
parent cb85f65cca
commit 0386a28b5a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
58 changed files with 3289 additions and 469 deletions

View File

@ -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

View File

@ -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

File diff suppressed because it is too large Load Diff

View File

@ -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:

View File

@ -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

View File

@ -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.
//

View File

@ -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

View File

@ -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.
//

View File

@ -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.
//

View File

@ -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 {

View File

@ -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.
//

View File

@ -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.
//

View File

@ -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.
//

View File

@ -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:

View File

@ -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.
//

View File

@ -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.
//

View File

@ -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':

View File

@ -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.
//

View File

@ -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.
//

View File

@ -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.
//

View File

@ -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:

View File

@ -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")

View File

@ -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")

View File

@ -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")

View File

@ -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)

View File

@ -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*

View File

@ -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)

View File

@ -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)

View File

@ -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",

View File

@ -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",

View File

@ -26,7 +26,42 @@ import (
"github.com/superseriousbusiness/gotosocial/internal/oauth"
)
// StatusBoostedByGETHandler is for serving a list of accounts that have boosted/reblogged a given status
// 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",

View File

@ -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",

View File

@ -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*

View File

@ -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",

View File

@ -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",

View File

@ -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",

View File

@ -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",

View File

@ -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",

View File

@ -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",

View File

@ -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")

View File

@ -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")

View File

@ -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")

View File

@ -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"`
}

View File

@ -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"`

View File

@ -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"`
}

View File

@ -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"`
}

View File

@ -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"`
}

View File

@ -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"`
}

View File

@ -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.

View File

@ -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"`

View File

@ -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"`

View File

@ -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"`
}

View File

@ -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"`

View File

@ -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.

View File

@ -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

View File

@ -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)
}

View File

@ -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
}

View File

@ -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