diff --git a/api/main.tsp b/api/main.tsp index d59ce6f..b1af088 100644 --- a/api/main.tsp +++ b/api/main.tsp @@ -73,7 +73,7 @@ namespace Read { @get @operationId("GetSet") @route("/sets/{setID}") - op set(@path setID: id, @query mediaType?: mediaType = mediaType.avif): SetResp | SetNotFound; + op set(@path setID: id, @query mediaType?: mediaType = mediaType.webp): SetResp | SetNotFound; /** * Operations for connected platforms. @@ -100,7 +100,7 @@ namespace Read { @get @operationId("GetPlatformSet") @route("/set") - op set(...platformParams, @query mediaType?: mediaType = mediaType.avif): SetResp | SetNotFound; + op set(...platformParams, @query mediaType?: mediaType = mediaType.webp): SetResp | SetNotFound; /** * Report used emotes. @@ -132,12 +132,15 @@ namespace Read { @useAuth(BearerAuth) namespace EmoteManagement { /** - * Image types accepted in uploads. + * Image content for an emote upload. */ - model Image is File<"image/png" | "image/jpeg" | "image/gif" | "image/webp" | "image/avif">; + model Image { + format: mediaType; + data: bytes; + } /** Created emote. */ - model CreatedEmote is Success; + model CreatedEmote is Success; /** Updated emote. */ model UpdatedEmote is Success; @@ -147,20 +150,12 @@ namespace EmoteManagement { model ErrExcessiveUpload is Error<413>; /** - * Upload an emote. + * Create a new emote. */ @post @operationId("CreateEmote") @route("/emotes") - op new( - @header contentType: "multipart/form-data", - @multipartBody fields: { - meta: HttpPart & { - @header contentType: "application/json"; - }>; - image: HttpPart; - }, - ): CreatedEmote | ErrBadParameters | ErrAuth | ErrExcessiveUpload; + op new(emote: Emote): CreatedEmote | ErrBadParameters | ErrAuth | ErrExcessiveUpload; /** * Modify an existing emote. @@ -178,3 +173,210 @@ namespace EmoteManagement { @route("/emotes/{emoteID}") op delete(@path emoteID: id): NoContentResponse | ErrAuth; } + +/** + * The Ligmotes User Management API. + */ +@useAuth(BearerAuth) +namespace UserManagement { + // NOTE(zephyr): creating users goes through the auth api, not this + + /** + * Update a user's name or picture. + * Omitting the picture field in the request body causes the user's picture + * to be removed. + */ + @patch(#{ implicitOptionality: false }) + @operationId("UpdateUser") + @route("/users/{userID}") + op update(@path userID: id, @body user: User): Success | ErrAuth | ErrBadParameters | ErrNotFound; + + /** + * Soft-delete a user. + * + * Typically called by a user for themselves; moderators would use the + * /moderate/user API to ban them instead. + * This preserves the user's uploaded emotes as well as any moderation + * reviews they may have performed. + */ + @delete + @operationId("DeleteUser") + @route("/users/{userID}") + op delete(@path userID: id): Success | ErrAuth | ErrNotFound; +} + +/** + * The Ligmotes Chat Management API. + * Relates to managing emote sets and connections. + */ +@useAuth(BearerAuth) +namespace ChatManagement { + /** + * ID and name of an emote within a set. + * The same ID can appear multiple times in one set, but names are unique. + */ + model SetEmote { + id: id; + name: string; + + /** RenameEmote may specify a new name for an existing emote in the set. */ + rename?: string; + } + + /** + * Create a new emote set. + * Note that creating a user should automatically create their first emote + * set as well, without needing a call to this operation. + */ + @post + @operationId("CreateEmoteSet") + @route("/sets") + op create(@body emoteSet: EmoteSet): Success | ErrAuth | ErrBadParameters; + + /** Update the name of an existing emote set. */ + @patch(#{ implicitOptionality: false }) + @operationId("UpdateEmoteSet") + @route("/sets/{setID}") + op update(@path setID: id, @body emoteSet: EmoteSet): Success | ErrAuth | ErrBadParameters | ErrNotFound; + + // NOTE(zephyr): We do not allow deleting emote sets. + // That would enable many techniques to circumvent limits. + + /** Add an emote to an emote set. */ + // TODO(zephyr): is returning the entire updated emote set too expensive? + @post + @operationId("AddEmote") + @route("/sets/{setID}/emotes") + op addEmote(@path setID: id, @body emote: SetEmote): + | Success + | ErrAuth + | ErrBadParameters + | ErrNotFound + | ErrDuplicate; + + /** Rename an emote that is already in an emote set. */ + @patch(#{ implicitOptionality: false }) + @operationId("RenameEmote") + @route("/sets/{setID}/emotes") + op renameEmote(@path setID: id, @body emote: SetEmote): + | Success + | ErrAuth + | ErrBadParameters + | ErrNotFound + | ErrDuplicate; + + /** + * Remove an emote from an emote set. + * This performs a soft-delete of the association between the two. + */ + @delete + @operationId("RemoveEmote") + @route("/sets/{setID}/emotes") + op removeEmote(@path setID: id, @body emote: SetEmote): Success | ErrAuth | ErrNotFound; + + /** Give a user editor permission for an emote set. */ + @post + @operationId("AddEditor") + @route("/sets/{setID}/editors") + op addEditor( + @path setID: id, + @body editor: { + userID: id; + }, + ): Success | ErrAuth | ErrNotFound | ErrDuplicate; + + /** Remove a user's permission to edit an emote set. */ + @delete + @operationId("RemoveEditor") + @route("/sets/{setID}/editors") + op removeEditor( + @path setID: id, + @body editor: { + userID: id; + }, + ): Success | ErrAuth | ErrNotFound; + + /** Get emote sets that the user is allowed to edit. */ + // TODO(zephyr): we should report this as a field on emote set objects as well + @get + @operationId("ListEditableSets") + @route("/users/{userID}/sets") + op listEditableSets(@path userID: id): Success | ErrAuth | ErrBadParameters; + + /** Set an emote set as active for a connection. */ + @patch(#{ implicitOptionality: false }) + @operationId("UpdateActiveSet") + @route("/platforms/{platform}/connections/{connectedID}/set") + op updateActiveSet( + @path platform: platform, + @path connectedID: string, + @body update: { + setID: id; + }, + ): Success | ErrAuth | ErrBadParameters; +} + +/** + * Moderation API. + */ +@useAuth(BearerAuth) +@route("/moderate") +namespace Moderation { + /** Request body for updating emote approval status. */ + model EmoteStatus { + approved: boolean; + } + + /** Options for deleting an emote. */ + model EmoteDeleteOptions { + deleteMedia?: boolean; + } + + /** + * List a selection of emotes awaiting moderator review. + * NOTE(zephyr): Unlike other APIs, this returns the emotes directly. + * We want all the information for reviewing, and a bit extra latency for + * the join is less of an issue than it is in chat. + */ + @get + @operationId("ListUnreviewedEmotes") + @route("/emotes") + op listUnreviewed(@query limit?: integer = 100): Success | ErrAuth; + + /** + * Update an emote's approval status. + */ + @post + @operationId("UpdateEmoteStatus") + @route("/emotes/{emoteID}") + op updateEmoteStatus(@path emoteID: id, @body status: EmoteStatus): + | Success + | ErrAuth + | ErrBadParameters + | ErrNotFound; + + /** + * Fully remove an emote, e.g. for abusive or illegal content. + * + * This is a hard delete. + * Typically, a call to it should have an accompanying call to ban the user. + */ + @delete + @operationId("HardDeleteEmote") + @route("/emotes/{emoteID}") + op hardDeleteEmote(@path emoteID: id, @body options?: EmoteDeleteOptions): + | NoContentResponse + | ErrAuth + | ErrBadParameters + | ErrNotFound; + + /** + * Ban a user for a given reason. + * This revokes all the user's current sessions, removes their active emote + * sets, and enforces the restrictions described on UserBan. + */ + @post + @operationId("Ban") + @route("/users/{userID}") + op ban(@path userID: id, @body details: UserBan): Success | ErrAuth | ErrBadParameters | ErrNotFound; +} diff --git a/api/models.tsp b/api/models.tsp index 415a3c5..f3e0caf 100644 --- a/api/models.tsp +++ b/api/models.tsp @@ -23,7 +23,7 @@ model Success { * Error response. */ @error -model Error { +model Error { @statusCode code: Code; @@ -51,6 +51,14 @@ model ErrBadParameters is Error<400>; @error model ErrAuth is Error<401 | 403>; +/** Request specified an ID for a resource which does not exist. */ +@error +model ErrNotFound is Error<404>; + +/** Request tried to add an association which already exists. */ +@error +model ErrDuplicate is Error<409>; + /** * ID of a user, emote, emote list, &c. * UUIDv7. @@ -76,7 +84,7 @@ model Emote { name: string; /** Links to and metadata about the available emote images. */ - @visibility(Lifecycle.Read) + @visibility(Lifecycle.Read, Lifecycle.Create) media: Media[]; /** Emote color for sorting. */ @@ -99,7 +107,7 @@ model Emote { @visibility(Lifecycle.Read, Lifecycle.Create, Lifecycle.Update) attributions: Attribution[]; - /** List of channels allowed to use the emote, if so restricted. */ + /** List of users allowed to use the emote, if so restricted. */ @visibility(Lifecycle.Read, Lifecycle.Create, Lifecycle.Update) restrictions?: id[]; @@ -145,12 +153,28 @@ model MinEmote { * Link and metadata for an emote image. */ model Media { + @visibility(Lifecycle.Read, Lifecycle.Create) format: mediaType; + + @visibility(Lifecycle.Read, Lifecycle.Create) scale: 1 | 2 | 4; + + @visibility(Lifecycle.Create) + data: bytes; + + @visibility(Lifecycle.Read) hash: string; + + @visibility(Lifecycle.Read) url: url; + + @visibility(Lifecycle.Read) height: int16; + + @visibility(Lifecycle.Read) width: int16; + + @visibility(Lifecycle.Read) filesize: int32; } @@ -158,7 +182,7 @@ model Media { * Media formats that the CDN delivers. */ enum mediaType { - avif: "AVIF", + webp: "WebP", } /** @@ -198,10 +222,22 @@ model User { /** User ban information. Only shown to the user themselves. */ @visibility(Lifecycle.Read) - ban?: { - reason: string; - until: utcDateTime; - }; + ban?: UserBan; +} + +/** + * User ban details. + * A banned user cannot use any authenticated APIs, meaning they cannot upload + * or edit emotes, manage emote sets, or moderate. + * They can still use the Read APIs and can still be issued sessions, allowing + * them to sign in and see their ban reason. + */ +model UserBan { + /** Reason for the ban. This is shown to the banned user. */ + reason: string; + + /** Time the ban expires and the user regains full access to Ligmotes. */ + until: utcDateTime; } /** diff --git a/api/schema/openapi.v1.yaml b/api/schema/openapi.v1.yaml index 7a50f20..100ec7d 100644 --- a/api/schema/openapi.v1.yaml +++ b/api/schema/openapi.v1.yaml @@ -46,10 +46,10 @@ paths: - {} post: operationId: CreateEmote - description: Upload an emote. + description: Create a new emote. parameters: [] responses: - '202': + '200': description: Created emote. content: application/json: @@ -137,21 +137,14 @@ paths: requestBody: required: true content: - multipart/form-data: + application/json: schema: type: object properties: - meta: - $ref: '#/components/schemas/CreateEmote' - image: {} + emote: + $ref: '#/components/schemas/Models.EmoteCreate' required: - - meta - - image - encoding: - meta: - contentType: application/json - image: - contentType: image/png, image/jpeg, image/gif, image/webp, image/avif + - emote security: - BearerAuth: [] /emotes/{emoteID}: @@ -298,6 +291,389 @@ paths: - message security: - BearerAuth: [] + /moderate/emotes: + get: + operationId: ListUnreviewedEmotes + description: |- + List a selection of emotes awaiting moderator review. + NOTE(zephyr): Unlike other APIs, this returns the emotes directly. + We want all the information for reviewing, and a bit extra latency for + the join is less of an issue than it is in chat. + parameters: + - name: limit + in: query + required: false + schema: + type: integer + default: 100 + explode: false + responses: + '200': + description: Success response with data of a given type. + content: + application/json: + schema: + type: object + properties: + data: + type: array + items: + $ref: '#/components/schemas/Models.Emote' + required: + - data + '401': + description: |- + Endpoint requires authorization but: + - no token was supplied (401) + - supplied token was invalid (403) + - supplied token was expired (403) + - supplied token did not authorize the operation (403) + content: + application/json: + schema: + type: object + properties: + error: + type: string + description: Programmer-oriented error description. + message: + type: string + description: User-oriented error message. + required: + - error + - message + '403': + description: |- + Endpoint requires authorization but: + - no token was supplied (401) + - supplied token was invalid (403) + - supplied token was expired (403) + - supplied token did not authorize the operation (403) + content: + application/json: + schema: + type: object + properties: + error: + type: string + description: Programmer-oriented error description. + message: + type: string + description: User-oriented error message. + required: + - error + - message + security: + - BearerAuth: [] + /moderate/emotes/{emoteID}: + post: + operationId: UpdateEmoteStatus + description: Update an emote's approval status. + parameters: + - name: emoteID + in: path + required: true + schema: + $ref: '#/components/schemas/Models.id' + responses: + '200': + description: Success response with data of a given type. + content: + application/json: + schema: + type: object + properties: + data: + $ref: '#/components/schemas/Models.Emote' + required: + - data + '400': + description: Supplied parameters did not meet the endpoint requirements. + content: + application/json: + schema: + type: object + properties: + error: + type: string + description: Programmer-oriented error description. + message: + type: string + description: User-oriented error message. + required: + - error + - message + '401': + description: |- + Endpoint requires authorization but: + - no token was supplied (401) + - supplied token was invalid (403) + - supplied token was expired (403) + - supplied token did not authorize the operation (403) + content: + application/json: + schema: + type: object + properties: + error: + type: string + description: Programmer-oriented error description. + message: + type: string + description: User-oriented error message. + required: + - error + - message + '403': + description: |- + Endpoint requires authorization but: + - no token was supplied (401) + - supplied token was invalid (403) + - supplied token was expired (403) + - supplied token did not authorize the operation (403) + content: + application/json: + schema: + type: object + properties: + error: + type: string + description: Programmer-oriented error description. + message: + type: string + description: User-oriented error message. + required: + - error + - message + '404': + description: Request specified an ID for a resource which does not exist. + content: + application/json: + schema: + type: object + properties: + error: + type: string + description: Programmer-oriented error description. + message: + type: string + description: User-oriented error message. + required: + - error + - message + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/Moderation.EmoteStatus' + security: + - BearerAuth: [] + delete: + operationId: HardDeleteEmote + description: |- + Fully remove an emote, e.g. for abusive or illegal content. + + This is a hard delete. + Typically, a call to it should have an accompanying call to ban the user. + parameters: + - name: emoteID + in: path + required: true + schema: + $ref: '#/components/schemas/Models.id' + responses: + '204': + description: There is no content to send for this request, but the headers may be useful. + '400': + description: Supplied parameters did not meet the endpoint requirements. + content: + application/json: + schema: + type: object + properties: + error: + type: string + description: Programmer-oriented error description. + message: + type: string + description: User-oriented error message. + required: + - error + - message + '401': + description: |- + Endpoint requires authorization but: + - no token was supplied (401) + - supplied token was invalid (403) + - supplied token was expired (403) + - supplied token did not authorize the operation (403) + content: + application/json: + schema: + type: object + properties: + error: + type: string + description: Programmer-oriented error description. + message: + type: string + description: User-oriented error message. + required: + - error + - message + '403': + description: |- + Endpoint requires authorization but: + - no token was supplied (401) + - supplied token was invalid (403) + - supplied token was expired (403) + - supplied token did not authorize the operation (403) + content: + application/json: + schema: + type: object + properties: + error: + type: string + description: Programmer-oriented error description. + message: + type: string + description: User-oriented error message. + required: + - error + - message + '404': + description: Request specified an ID for a resource which does not exist. + content: + application/json: + schema: + type: object + properties: + error: + type: string + description: Programmer-oriented error description. + message: + type: string + description: User-oriented error message. + required: + - error + - message + requestBody: + required: false + content: + application/json: + schema: + $ref: '#/components/schemas/Moderation.EmoteDeleteOptions' + security: + - BearerAuth: [] + /moderate/users/{userID}: + post: + operationId: Ban + description: |- + Ban a user for a given reason. + This revokes all the user's current sessions, removes their active emote + sets, and enforces the restrictions described on UserBan. + parameters: + - name: userID + in: path + required: true + schema: + $ref: '#/components/schemas/Models.id' + responses: + '200': + description: Success response with data of a given type. + content: + application/json: + schema: + type: object + properties: + data: + $ref: '#/components/schemas/Models.User' + required: + - data + '400': + description: Supplied parameters did not meet the endpoint requirements. + content: + application/json: + schema: + type: object + properties: + error: + type: string + description: Programmer-oriented error description. + message: + type: string + description: User-oriented error message. + required: + - error + - message + '401': + description: |- + Endpoint requires authorization but: + - no token was supplied (401) + - supplied token was invalid (403) + - supplied token was expired (403) + - supplied token did not authorize the operation (403) + content: + application/json: + schema: + type: object + properties: + error: + type: string + description: Programmer-oriented error description. + message: + type: string + description: User-oriented error message. + required: + - error + - message + '403': + description: |- + Endpoint requires authorization but: + - no token was supplied (401) + - supplied token was invalid (403) + - supplied token was expired (403) + - supplied token did not authorize the operation (403) + content: + application/json: + schema: + type: object + properties: + error: + type: string + description: Programmer-oriented error description. + message: + type: string + description: User-oriented error message. + required: + - error + - message + '404': + description: Request specified an ID for a resource which does not exist. + content: + application/json: + schema: + type: object + properties: + error: + type: string + description: Programmer-oriented error description. + message: + type: string + description: User-oriented error message. + required: + - error + - message + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/Models.UserBan' + security: + - BearerAuth: [] /platforms/{platform}/connections/{connectedID}/emotes: post: operationId: ReportPlatformUse @@ -342,7 +718,7 @@ paths: required: false schema: $ref: '#/components/schemas/Models.mediaType' - default: AVIF + default: WebP explode: false responses: '200': @@ -374,6 +750,103 @@ paths: - message security: - {} + patch: + operationId: UpdateActiveSet + description: Set an emote set as active for a connection. + parameters: + - name: platform + in: path + required: true + schema: + $ref: '#/components/schemas/Models.platform' + - name: connectedID + in: path + required: true + schema: + type: string + responses: + '200': + description: Success response with data of a given type. + content: + application/json: + schema: + type: object + properties: + data: + $ref: '#/components/schemas/Models.EmoteSet' + required: + - data + '400': + description: Supplied parameters did not meet the endpoint requirements. + content: + application/json: + schema: + type: object + properties: + error: + type: string + description: Programmer-oriented error description. + message: + type: string + description: User-oriented error message. + required: + - error + - message + '401': + description: |- + Endpoint requires authorization but: + - no token was supplied (401) + - supplied token was invalid (403) + - supplied token was expired (403) + - supplied token did not authorize the operation (403) + content: + application/json: + schema: + type: object + properties: + error: + type: string + description: Programmer-oriented error description. + message: + type: string + description: User-oriented error message. + required: + - error + - message + '403': + description: |- + Endpoint requires authorization but: + - no token was supplied (401) + - supplied token was invalid (403) + - supplied token was expired (403) + - supplied token did not authorize the operation (403) + content: + application/json: + schema: + type: object + properties: + error: + type: string + description: Programmer-oriented error description. + message: + type: string + description: User-oriented error message. + required: + - error + - message + requestBody: + required: true + content: + application/json: + schema: + type: object + properties: + setID: + $ref: '#/components/schemas/Models.id' + required: + - setID + security: + - BearerAuth: [] /platforms/{platform}/connections/{connectedID}/user: get: operationId: GetPlatformUser @@ -411,6 +884,92 @@ paths: - message security: - {} + /sets: + post: + operationId: CreateEmoteSet + description: |- + Create a new emote set. + Note that creating a user should automatically create their first emote + set as well, without needing a call to this operation. + parameters: [] + responses: + '200': + description: Success response with data of a given type. + content: + application/json: + schema: + type: object + properties: + data: + $ref: '#/components/schemas/Models.EmoteSet' + required: + - data + '400': + description: Supplied parameters did not meet the endpoint requirements. + content: + application/json: + schema: + type: object + properties: + error: + type: string + description: Programmer-oriented error description. + message: + type: string + description: User-oriented error message. + required: + - error + - message + '401': + description: |- + Endpoint requires authorization but: + - no token was supplied (401) + - supplied token was invalid (403) + - supplied token was expired (403) + - supplied token did not authorize the operation (403) + content: + application/json: + schema: + type: object + properties: + error: + type: string + description: Programmer-oriented error description. + message: + type: string + description: User-oriented error message. + required: + - error + - message + '403': + description: |- + Endpoint requires authorization but: + - no token was supplied (401) + - supplied token was invalid (403) + - supplied token was expired (403) + - supplied token did not authorize the operation (403) + content: + application/json: + schema: + type: object + properties: + error: + type: string + description: Programmer-oriented error description. + message: + type: string + description: User-oriented error message. + required: + - error + - message + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/Models.EmoteSet' + security: + - BearerAuth: [] /sets/{setID}: get: operationId: GetSet @@ -426,7 +985,7 @@ paths: required: false schema: $ref: '#/components/schemas/Models.mediaType' - default: AVIF + default: WebP explode: false responses: '200': @@ -458,6 +1017,638 @@ paths: - message security: - {} + patch: + operationId: UpdateEmoteSet + description: Update the name of an existing emote set. + parameters: + - name: setID + in: path + required: true + schema: + $ref: '#/components/schemas/Models.id' + responses: + '200': + description: Success response with data of a given type. + content: + application/json: + schema: + type: object + properties: + data: + $ref: '#/components/schemas/Models.EmoteSet' + required: + - data + '400': + description: Supplied parameters did not meet the endpoint requirements. + content: + application/json: + schema: + type: object + properties: + error: + type: string + description: Programmer-oriented error description. + message: + type: string + description: User-oriented error message. + required: + - error + - message + '401': + description: |- + Endpoint requires authorization but: + - no token was supplied (401) + - supplied token was invalid (403) + - supplied token was expired (403) + - supplied token did not authorize the operation (403) + content: + application/json: + schema: + type: object + properties: + error: + type: string + description: Programmer-oriented error description. + message: + type: string + description: User-oriented error message. + required: + - error + - message + '403': + description: |- + Endpoint requires authorization but: + - no token was supplied (401) + - supplied token was invalid (403) + - supplied token was expired (403) + - supplied token did not authorize the operation (403) + content: + application/json: + schema: + type: object + properties: + error: + type: string + description: Programmer-oriented error description. + message: + type: string + description: User-oriented error message. + required: + - error + - message + '404': + description: Request specified an ID for a resource which does not exist. + content: + application/json: + schema: + type: object + properties: + error: + type: string + description: Programmer-oriented error description. + message: + type: string + description: User-oriented error message. + required: + - error + - message + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/Models.EmoteSet' + security: + - BearerAuth: [] + /sets/{setID}/editors: + post: + operationId: AddEditor + description: Give a user editor permission for an emote set. + parameters: + - name: setID + in: path + required: true + schema: + $ref: '#/components/schemas/Models.id' + responses: + '200': + description: Success response with data of a given type. + content: + application/json: + schema: + type: object + properties: + data: + $ref: '#/components/schemas/Models.EmoteSet' + required: + - data + '401': + description: |- + Endpoint requires authorization but: + - no token was supplied (401) + - supplied token was invalid (403) + - supplied token was expired (403) + - supplied token did not authorize the operation (403) + content: + application/json: + schema: + type: object + properties: + error: + type: string + description: Programmer-oriented error description. + message: + type: string + description: User-oriented error message. + required: + - error + - message + '403': + description: |- + Endpoint requires authorization but: + - no token was supplied (401) + - supplied token was invalid (403) + - supplied token was expired (403) + - supplied token did not authorize the operation (403) + content: + application/json: + schema: + type: object + properties: + error: + type: string + description: Programmer-oriented error description. + message: + type: string + description: User-oriented error message. + required: + - error + - message + '404': + description: Request specified an ID for a resource which does not exist. + content: + application/json: + schema: + type: object + properties: + error: + type: string + description: Programmer-oriented error description. + message: + type: string + description: User-oriented error message. + required: + - error + - message + '409': + description: Request tried to add an association which already exists. + content: + application/json: + schema: + type: object + properties: + error: + type: string + description: Programmer-oriented error description. + message: + type: string + description: User-oriented error message. + required: + - error + - message + requestBody: + required: true + content: + application/json: + schema: + type: object + properties: + userID: + $ref: '#/components/schemas/Models.id' + required: + - userID + security: + - BearerAuth: [] + delete: + operationId: RemoveEditor + description: Remove a user's permission to edit an emote set. + parameters: + - name: setID + in: path + required: true + schema: + $ref: '#/components/schemas/Models.id' + responses: + '200': + description: Success response with data of a given type. + content: + application/json: + schema: + type: object + properties: + data: + $ref: '#/components/schemas/Models.EmoteSet' + required: + - data + '401': + description: |- + Endpoint requires authorization but: + - no token was supplied (401) + - supplied token was invalid (403) + - supplied token was expired (403) + - supplied token did not authorize the operation (403) + content: + application/json: + schema: + type: object + properties: + error: + type: string + description: Programmer-oriented error description. + message: + type: string + description: User-oriented error message. + required: + - error + - message + '403': + description: |- + Endpoint requires authorization but: + - no token was supplied (401) + - supplied token was invalid (403) + - supplied token was expired (403) + - supplied token did not authorize the operation (403) + content: + application/json: + schema: + type: object + properties: + error: + type: string + description: Programmer-oriented error description. + message: + type: string + description: User-oriented error message. + required: + - error + - message + '404': + description: Request specified an ID for a resource which does not exist. + content: + application/json: + schema: + type: object + properties: + error: + type: string + description: Programmer-oriented error description. + message: + type: string + description: User-oriented error message. + required: + - error + - message + requestBody: + required: true + content: + application/json: + schema: + type: object + properties: + userID: + $ref: '#/components/schemas/Models.id' + required: + - userID + security: + - BearerAuth: [] + /sets/{setID}/emotes: + post: + operationId: AddEmote + description: Add an emote to an emote set. + parameters: + - name: setID + in: path + required: true + schema: + $ref: '#/components/schemas/Models.id' + responses: + '200': + description: Success response with data of a given type. + content: + application/json: + schema: + type: object + properties: + data: + $ref: '#/components/schemas/Models.EmoteSet' + required: + - data + '400': + description: Supplied parameters did not meet the endpoint requirements. + content: + application/json: + schema: + type: object + properties: + error: + type: string + description: Programmer-oriented error description. + message: + type: string + description: User-oriented error message. + required: + - error + - message + '401': + description: |- + Endpoint requires authorization but: + - no token was supplied (401) + - supplied token was invalid (403) + - supplied token was expired (403) + - supplied token did not authorize the operation (403) + content: + application/json: + schema: + type: object + properties: + error: + type: string + description: Programmer-oriented error description. + message: + type: string + description: User-oriented error message. + required: + - error + - message + '403': + description: |- + Endpoint requires authorization but: + - no token was supplied (401) + - supplied token was invalid (403) + - supplied token was expired (403) + - supplied token did not authorize the operation (403) + content: + application/json: + schema: + type: object + properties: + error: + type: string + description: Programmer-oriented error description. + message: + type: string + description: User-oriented error message. + required: + - error + - message + '404': + description: Request specified an ID for a resource which does not exist. + content: + application/json: + schema: + type: object + properties: + error: + type: string + description: Programmer-oriented error description. + message: + type: string + description: User-oriented error message. + required: + - error + - message + '409': + description: Request tried to add an association which already exists. + content: + application/json: + schema: + type: object + properties: + error: + type: string + description: Programmer-oriented error description. + message: + type: string + description: User-oriented error message. + required: + - error + - message + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/ChatManagement.SetEmote' + security: + - BearerAuth: [] + patch: + operationId: RenameEmote + description: Rename an emote that is already in an emote set. + parameters: + - name: setID + in: path + required: true + schema: + $ref: '#/components/schemas/Models.id' + responses: + '200': + description: Success response with data of a given type. + content: + application/json: + schema: + type: object + properties: + data: + $ref: '#/components/schemas/Models.EmoteSet' + required: + - data + '400': + description: Supplied parameters did not meet the endpoint requirements. + content: + application/json: + schema: + type: object + properties: + error: + type: string + description: Programmer-oriented error description. + message: + type: string + description: User-oriented error message. + required: + - error + - message + '401': + description: |- + Endpoint requires authorization but: + - no token was supplied (401) + - supplied token was invalid (403) + - supplied token was expired (403) + - supplied token did not authorize the operation (403) + content: + application/json: + schema: + type: object + properties: + error: + type: string + description: Programmer-oriented error description. + message: + type: string + description: User-oriented error message. + required: + - error + - message + '403': + description: |- + Endpoint requires authorization but: + - no token was supplied (401) + - supplied token was invalid (403) + - supplied token was expired (403) + - supplied token did not authorize the operation (403) + content: + application/json: + schema: + type: object + properties: + error: + type: string + description: Programmer-oriented error description. + message: + type: string + description: User-oriented error message. + required: + - error + - message + '404': + description: Request specified an ID for a resource which does not exist. + content: + application/json: + schema: + type: object + properties: + error: + type: string + description: Programmer-oriented error description. + message: + type: string + description: User-oriented error message. + required: + - error + - message + '409': + description: Request tried to add an association which already exists. + content: + application/json: + schema: + type: object + properties: + error: + type: string + description: Programmer-oriented error description. + message: + type: string + description: User-oriented error message. + required: + - error + - message + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/ChatManagement.SetEmote' + security: + - BearerAuth: [] + delete: + operationId: RemoveEmote + description: |- + Remove an emote from an emote set. + This performs a soft-delete of the association between the two. + parameters: + - name: setID + in: path + required: true + schema: + $ref: '#/components/schemas/Models.id' + responses: + '200': + description: Success response with data of a given type. + content: + application/json: + schema: + type: object + properties: + data: + $ref: '#/components/schemas/Models.EmoteSet' + required: + - data + '401': + description: |- + Endpoint requires authorization but: + - no token was supplied (401) + - supplied token was invalid (403) + - supplied token was expired (403) + - supplied token did not authorize the operation (403) + content: + application/json: + schema: + type: object + properties: + error: + type: string + description: Programmer-oriented error description. + message: + type: string + description: User-oriented error message. + required: + - error + - message + '403': + description: |- + Endpoint requires authorization but: + - no token was supplied (401) + - supplied token was invalid (403) + - supplied token was expired (403) + - supplied token did not authorize the operation (403) + content: + application/json: + schema: + type: object + properties: + error: + type: string + description: Programmer-oriented error description. + message: + type: string + description: User-oriented error message. + required: + - error + - message + '404': + description: Request specified an ID for a resource which does not exist. + content: + application/json: + schema: + type: object + properties: + error: + type: string + description: Programmer-oriented error description. + message: + type: string + description: User-oriented error message. + required: + - error + - message + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/ChatManagement.SetEmote' + security: + - BearerAuth: [] /users/{userID}: get: operationId: GetUser @@ -500,6 +1691,283 @@ paths: - message security: - {} + patch: + operationId: UpdateUser + description: |- + Update a user's name or picture. + Omitting the picture field in the request body causes the user's picture + to be removed. + parameters: + - name: userID + in: path + required: true + schema: + $ref: '#/components/schemas/Models.id' + responses: + '200': + description: Success response with data of a given type. + content: + application/json: + schema: + type: object + properties: + data: + $ref: '#/components/schemas/Models.User' + required: + - data + '400': + description: Supplied parameters did not meet the endpoint requirements. + content: + application/json: + schema: + type: object + properties: + error: + type: string + description: Programmer-oriented error description. + message: + type: string + description: User-oriented error message. + required: + - error + - message + '401': + description: |- + Endpoint requires authorization but: + - no token was supplied (401) + - supplied token was invalid (403) + - supplied token was expired (403) + - supplied token did not authorize the operation (403) + content: + application/json: + schema: + type: object + properties: + error: + type: string + description: Programmer-oriented error description. + message: + type: string + description: User-oriented error message. + required: + - error + - message + '403': + description: |- + Endpoint requires authorization but: + - no token was supplied (401) + - supplied token was invalid (403) + - supplied token was expired (403) + - supplied token did not authorize the operation (403) + content: + application/json: + schema: + type: object + properties: + error: + type: string + description: Programmer-oriented error description. + message: + type: string + description: User-oriented error message. + required: + - error + - message + '404': + description: Request specified an ID for a resource which does not exist. + content: + application/json: + schema: + type: object + properties: + error: + type: string + description: Programmer-oriented error description. + message: + type: string + description: User-oriented error message. + required: + - error + - message + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/Models.UserUpdate' + security: + - BearerAuth: [] + delete: + operationId: DeleteUser + description: |- + Soft-delete a user. + + Typically called by a user for themselves; moderators would use the + /moderate/user API to ban them instead. + This preserves the user's uploaded emotes as well as any moderation + reviews they may have performed. + parameters: + - name: userID + in: path + required: true + schema: + $ref: '#/components/schemas/Models.id' + responses: + '200': + description: Success response with data of a given type. + content: + application/json: + schema: + type: object + properties: + data: + $ref: '#/components/schemas/Models.User' + required: + - data + '401': + description: |- + Endpoint requires authorization but: + - no token was supplied (401) + - supplied token was invalid (403) + - supplied token was expired (403) + - supplied token did not authorize the operation (403) + content: + application/json: + schema: + type: object + properties: + error: + type: string + description: Programmer-oriented error description. + message: + type: string + description: User-oriented error message. + required: + - error + - message + '403': + description: |- + Endpoint requires authorization but: + - no token was supplied (401) + - supplied token was invalid (403) + - supplied token was expired (403) + - supplied token did not authorize the operation (403) + content: + application/json: + schema: + type: object + properties: + error: + type: string + description: Programmer-oriented error description. + message: + type: string + description: User-oriented error message. + required: + - error + - message + '404': + description: Request specified an ID for a resource which does not exist. + content: + application/json: + schema: + type: object + properties: + error: + type: string + description: Programmer-oriented error description. + message: + type: string + description: User-oriented error message. + required: + - error + - message + security: + - BearerAuth: [] + /users/{userID}/sets: + get: + operationId: ListEditableSets + description: Get emote sets that the user is allowed to edit. + parameters: + - name: userID + in: path + required: true + schema: + $ref: '#/components/schemas/Models.id' + responses: + '200': + description: Success response with data of a given type. + content: + application/json: + schema: + type: object + properties: + data: + type: array + items: + $ref: '#/components/schemas/Models.EmoteSet' + required: + - data + '400': + description: Supplied parameters did not meet the endpoint requirements. + content: + application/json: + schema: + type: object + properties: + error: + type: string + description: Programmer-oriented error description. + message: + type: string + description: User-oriented error message. + required: + - error + - message + '401': + description: |- + Endpoint requires authorization but: + - no token was supplied (401) + - supplied token was invalid (403) + - supplied token was expired (403) + - supplied token did not authorize the operation (403) + content: + application/json: + schema: + type: object + properties: + error: + type: string + description: Programmer-oriented error description. + message: + type: string + description: User-oriented error message. + required: + - error + - message + '403': + description: |- + Endpoint requires authorization but: + - no token was supplied (401) + - supplied token was invalid (403) + - supplied token was expired (403) + - supplied token did not authorize the operation (403) + content: + application/json: + schema: + type: object + properties: + error: + type: string + description: Programmer-oriented error description. + message: + type: string + description: User-oriented error message. + required: + - error + - message + security: + - BearerAuth: [] components: parameters: Read.Platforms.platformParams.connectedID: @@ -515,36 +1983,34 @@ components: schema: $ref: '#/components/schemas/Models.platform' schemas: - CreateEmote: + ChatManagement.SetEmote: type: object required: + - id - name - - tags - - attributions properties: + id: + $ref: '#/components/schemas/Models.id' name: type: string - description: Text that should be replaced with the emote image. - tags: - type: array - items: - type: string - description: Search tags for the emote. - attributions: - type: object - unevaluatedProperties: - $ref: '#/components/schemas/Models.CreateCreateAttribution' - description: People who contributed to the work. - restrictions: - type: array - items: - $ref: '#/components/schemas/Models.id' - description: List of channels allowed to use the emote, if so restricted. - replaces: - allOf: - - $ref: '#/components/schemas/Models.id' - description: Older emote version, if any. - description: '' + rename: + type: string + description: RenameEmote may specify a new name for an existing emote in the set. + description: |- + ID and name of an emote within a set. + The same ID can appear multiple times in one set, but names are unique. + EmoteManagement.Image: + type: object + required: + - format + - data + properties: + format: + $ref: '#/components/schemas/Models.mediaType' + data: + type: string + contentEncoding: base64 + description: Image content for an emote upload. Ligmotes.Versions: type: string enum: @@ -585,24 +2051,6 @@ components: type: string description: Name of the user on the connected platform. description: Active connection between an emote set and an external platform. - Models.CreateCreateAttribution: - type: object - required: - - text - - links - properties: - text: - type: string - description: Text displayed for the attribution, typically their name. - links: - type: array - items: - type: string - format: uri - description: Links associated with the attributed person. - description: |- - Emote work attributions. - These may be links to Ligmotes users or to general social media. Models.Emote: type: object required: @@ -625,7 +2073,6 @@ components: items: $ref: '#/components/schemas/Models.Media' description: Links to and metadata about the available emote images. - readOnly: true color: type: string description: Emote color for sorting. @@ -654,7 +2101,7 @@ components: type: array items: $ref: '#/components/schemas/Models.id' - description: List of channels allowed to use the emote, if so restricted. + description: List of users allowed to use the emote, if so restricted. reviewer: allOf: - $ref: '#/components/schemas/Models.id' @@ -690,6 +2137,42 @@ components: - $ref: '#/components/schemas/Models.id' description: Older emote version, if any. description: Full-detail emote model. + Models.EmoteCreate: + type: object + required: + - name + - media + - tags + - attributions + properties: + name: + type: string + description: Text that should be replaced with the emote image. + media: + type: array + items: + $ref: '#/components/schemas/Models.MediaCreateItem' + description: Links to and metadata about the available emote images. + tags: + type: array + items: + type: string + description: Search tags for the emote. + attributions: + type: array + items: + $ref: '#/components/schemas/Models.Attribution' + description: People who contributed to the work. + restrictions: + type: array + items: + $ref: '#/components/schemas/Models.id' + description: List of users allowed to use the emote, if so restricted. + replaces: + allOf: + - $ref: '#/components/schemas/Models.id' + description: Older emote version, if any. + description: Full-detail emote model. Models.EmoteSet: type: object required: @@ -760,7 +2243,7 @@ components: type: array items: $ref: '#/components/schemas/Models.id' - description: List of channels allowed to use the emote, if so restricted. + description: List of users allowed to use the emote, if so restricted. description: Full-detail emote model. Models.Media: type: object @@ -783,18 +2266,42 @@ components: - 4 hash: type: string + readOnly: true url: type: string format: uri + readOnly: true height: type: integer format: int16 + readOnly: true width: type: integer format: int16 + readOnly: true filesize: type: integer format: int32 + readOnly: true + description: Link and metadata for an emote image. + Models.MediaCreateItem: + type: object + required: + - format + - scale + - data + properties: + format: + $ref: '#/components/schemas/Models.mediaType' + scale: + type: number + enum: + - 1 + - 2 + - 4 + data: + type: string + contentEncoding: base64 description: Link and metadata for an emote image. Models.MinEmote: type: object @@ -836,19 +2343,43 @@ components: description: User's standing if other than ok. readOnly: true ban: - type: object - properties: - reason: - type: string - until: - type: string - format: date-time - required: - - reason - - until + allOf: + - $ref: '#/components/schemas/Models.UserBan' description: User ban information. Only shown to the user themselves. readOnly: true description: User details. + Models.UserBan: + type: object + required: + - reason + - until + properties: + reason: + type: string + description: Reason for the ban. This is shown to the banned user. + until: + type: string + format: date-time + description: Time the ban expires and the user regains full access to Ligmotes. + description: |- + User ban details. + A banned user cannot use any authenticated APIs, meaning they cannot upload + or edit emotes, manage emote sets, or moderate. + They can still use the Read APIs and can still be issued sessions, allowing + them to sign in and see their ban reason. + Models.UserUpdate: + type: object + required: + - name + properties: + name: + type: string + description: User's display name. Not canonicalized. + picture: + type: string + format: uri + description: User's profile picture, if any. + description: User details. Models.id: type: string description: |- @@ -857,7 +2388,7 @@ components: Models.mediaType: type: string enum: - - AVIF + - WebP description: Media formats that the CDN delivers. Models.platform: type: string @@ -871,6 +2402,20 @@ components: - deleted - banned description: General status of a user. + Moderation.EmoteDeleteOptions: + type: object + properties: + deleteMedia: + type: boolean + description: Options for deleting an emote. + Moderation.EmoteStatus: + type: object + required: + - approved + properties: + approved: + type: boolean + description: Request body for updating emote approval status. Versions: type: string enum: diff --git a/api/tspconfig.yaml b/api/tspconfig.yaml index 6c2efe2..105bca1 100644 --- a/api/tspconfig.yaml +++ b/api/tspconfig.yaml @@ -5,4 +5,4 @@ options: emitter-output-dir: "{output-dir}/schema" openapi-versions: - 3.1.0 -output-dir: "{cwd}" +output-dir: "{project-root}" diff --git a/backend/rest/rest.gen.go b/backend/rest/rest.gen.go index eca60c7..e7baf1b 100644 --- a/backend/rest/rest.gen.go +++ b/backend/rest/rest.gen.go @@ -6,6 +6,7 @@ package rest import ( + "context" "fmt" "net/http" "time" @@ -13,41 +14,63 @@ import ( "github.com/oapi-codegen/runtime" ) +const ( + BearerAuthScopes = "BearerAuth.Scopes" +) + +// Defines values for ModelsEmoteStatus. +const ( + Private ModelsEmoteStatus = "private" + Public ModelsEmoteStatus = "public" + Restricted ModelsEmoteStatus = "restricted" + Unreviewed ModelsEmoteStatus = "unreviewed" +) + +// Defines values for ModelsMediaScale. +const ( + ModelsMediaScaleN1 ModelsMediaScale = 1 + ModelsMediaScaleN2 ModelsMediaScale = 2 + ModelsMediaScaleN4 ModelsMediaScale = 4 +) + +// Defines values for ModelsMediaCreateItemScale. +const ( + ModelsMediaCreateItemScaleN1 ModelsMediaCreateItemScale = 1 + ModelsMediaCreateItemScaleN2 ModelsMediaCreateItemScale = 2 + ModelsMediaCreateItemScaleN4 ModelsMediaCreateItemScale = 4 +) + +// Defines values for ModelsMediaType. +const ( + WebP ModelsMediaType = "WebP" +) + // Defines values for ModelsPlatform. const ( Twitch ModelsPlatform = "twitch" ) -// Defines values for ReadEmoteStatus. +// Defines values for ModelsUserStanding. const ( - Private ReadEmoteStatus = "private" - Public ReadEmoteStatus = "public" - Restricted ReadEmoteStatus = "restricted" - Unreviewed ReadEmoteStatus = "unreviewed" + Banned ModelsUserStanding = "banned" + Deleted ModelsUserStanding = "deleted" + Empty ModelsUserStanding = "" ) -// Defines values for ReadMediaScale. -const ( - N1 ReadMediaScale = 1 - N2 ReadMediaScale = 2 - N4 ReadMediaScale = 4 -) +// ChatManagementSetEmote ID and name of an emote within a set. +// The same ID can appear multiple times in one set, but names are unique. +type ChatManagementSetEmote struct { + // ID ID of a user, emote, emote list, &c. + // UUIDv7. + ID ModelsID `json:"id"` + Name string `json:"name"` -// Defines values for ReadMediaType. -const ( - AVIF ReadMediaType = "AVIF" -) - -// Defines values for ReadUserStanding. -const ( - Banned ReadUserStanding = "banned" - Deleted ReadUserStanding = "deleted" - Empty ReadUserStanding = "" -) + // Rename RenameEmote may specify a new name for an existing emote in the set. + Rename *string `json:"rename,omitempty"` +} // ModelsAttribution Emote work attributions. // These may be links to Ligmotes users or to general social media. -// Attributions are subject to moderator approval. type ModelsAttribution struct { // Links Links associated with the attributed person. Links []string `json:"links"` @@ -56,15 +79,8 @@ type ModelsAttribution struct { Text string `json:"text"` } -// ModelsID ID of a user, emote, emote list, &c. -// UUIDv7. -type ModelsID = string - -// ModelsPlatform Platforms supported by Ligmotes. -type ModelsPlatform string - -// ReadConnectedSet Active connection between an emote set and an external platform. -type ReadConnectedSet struct { +// ModelsConnectedSet Active connection between an emote set and an external platform. +type ModelsConnectedSet struct { // ConnectedID ID of the user on the connected platform. ConnectedID string `json:"connectedID"` @@ -75,9 +91,9 @@ type ReadConnectedSet struct { Platform ModelsPlatform `json:"platform"` } -// ReadEmote Full-detail emote model. -type ReadEmote struct { - // ApprovedAt Time at which the emote was approved, if ever. +// ModelsEmote Full-detail emote model. +type ModelsEmote struct { + // ApprovedAt Time at which the emote was approved for public search, if ever. ApprovedAt *time.Time `json:"approvedAt,omitempty"` // Attributions People who contributed to the work. @@ -87,14 +103,14 @@ type ReadEmote struct { Color *string `json:"color,omitempty"` // CreatedAt Time at which the emote was created on Ligmotes. - CreatedAt time.Time `json:"createdAt"` + CreatedAt *time.Time `json:"createdAt,omitempty"` // ID ID of a user, emote, emote list, &c. // UUIDv7. ID ModelsID `json:"id"` // Media Links to and metadata about the available emote images. - Media []ReadMedia `json:"media"` + Media []ModelsMedia `json:"media"` // Name Text that should be replaced with the emote image. Name string `json:"name"` @@ -105,88 +121,136 @@ type ReadEmote struct { // Replaces Older emote version, if any. Replaces *ModelsID `json:"replaces,omitempty"` - // Restrictions List of channels allowed to use the emote, if so restricted. + // Restrictions List of users allowed to use the emote, if so restricted. Restrictions *[]ModelsID `json:"restrictions,omitempty"` // Reviewer Ligmotes moderator who reviewed the emote. Reviewer *ModelsID `json:"reviewer,omitempty"` // Status Emote status. - // An emote is unreviewed upon upload, when attributions change, or when - // all restrictions are removed. // If an emote has no reviewer, it is always in status "unreviewed". // If it has both a reviewer and restrictions, then it is in status "restricted". // If it has a reviewer, no restrictions, and an approved time, // then it is "public" and can appear in global search. // Otherwise, it is "private". - Status ReadEmoteStatus `json:"status"` + Status *ModelsEmoteStatus `json:"status,omitempty"` // Tags Search tags for the emote. Tags []string `json:"tags"` // Uploader ID of the user who uploaded the emote to Ligmotes. - Uploader ModelsID `json:"uploader"` + Uploader *ModelsID `json:"uploader,omitempty"` } -// ReadEmoteStatus Emote status. -// An emote is unreviewed upon upload, when attributions change, or when -// all restrictions are removed. +// ModelsEmoteStatus Emote status. // If an emote has no reviewer, it is always in status "unreviewed". // If it has both a reviewer and restrictions, then it is in status "restricted". // If it has a reviewer, no restrictions, and an approved time, // then it is "public" and can appear in global search. // Otherwise, it is "private". -type ReadEmoteStatus string +type ModelsEmoteStatus string -// ReadEmoteSet Emote set details. -type ReadEmoteSet struct { +// ModelsEmoteCreate Full-detail emote model. +type ModelsEmoteCreate struct { + // Attributions People who contributed to the work. + Attributions []ModelsAttribution `json:"attributions"` + + // Media Links to and metadata about the available emote images. + Media []ModelsMediaCreateItem `json:"media"` + + // Name Text that should be replaced with the emote image. + Name string `json:"name"` + + // Replaces Older emote version, if any. + Replaces *ModelsID `json:"replaces,omitempty"` + + // Restrictions List of users allowed to use the emote, if so restricted. + Restrictions *[]ModelsID `json:"restrictions,omitempty"` + + // Tags Search tags for the emote. + Tags []string `json:"tags"` +} + +// ModelsEmoteSet Emote set details. +type ModelsEmoteSet struct { // Connections Active connections using the set, if any. - Connections *[]ReadConnectedSet `json:"connections,omitempty"` + Connections *[]ModelsConnectedSet `json:"connections,omitempty"` // CreatedAt Time at which the emote set was created. - CreatedAt time.Time `json:"createdAt"` + CreatedAt *time.Time `json:"createdAt,omitempty"` // Emotes IDs of emotes in the set. - Emotes []ModelsID `json:"emotes"` - - // ID ID of a user, emote, emote list, &c. - // UUIDv7. - ID ModelsID `json:"id"` + Emotes *[]ModelsMinEmote `json:"emotes,omitempty"` + ID *ModelsID `json:"id,omitempty"` // Name Name of the emote set itself. Name string `json:"name"` // OwnerID ID of the user who owns the emote set. // We don't embed the full owner object because the owner embeds the set. - OwnerID ModelsID `json:"ownerID"` + OwnerID *ModelsID `json:"ownerID,omitempty"` // OwnerName Username of the owner. - OwnerName string `json:"ownerName"` + OwnerName *string `json:"ownerName,omitempty"` } -// ReadMedia Link and metadata for an emote image. -type ReadMedia struct { - Filesize int32 `json:"filesize"` +// ModelsEmoteUpdate Full-detail emote model. +type ModelsEmoteUpdate struct { + // Attributions People who contributed to the work. + Attributions []ModelsAttribution `json:"attributions"` + + // Name Text that should be replaced with the emote image. + Name string `json:"name"` + + // Restrictions List of users allowed to use the emote, if so restricted. + Restrictions *[]ModelsID `json:"restrictions,omitempty"` + + // Tags Search tags for the emote. + Tags []string `json:"tags"` +} + +// ModelsMedia Link and metadata for an emote image. +type ModelsMedia struct { + Filesize *int32 `json:"filesize,omitempty"` // Format Media formats that the CDN delivers. - Format ReadMediaType `json:"format"` - Hash string `json:"hash"` - Height int16 `json:"height"` - Scale ReadMediaScale `json:"scale"` - URL string `json:"url"` - Width int16 `json:"width"` + Format ModelsMediaType `json:"format"` + Hash *string `json:"hash,omitempty"` + Height *int16 `json:"height,omitempty"` + Scale ModelsMediaScale `json:"scale"` + URL *string `json:"url,omitempty"` + Width *int16 `json:"width,omitempty"` } -// ReadMediaScale defines model for ReadMedia.Scale. -type ReadMediaScale float32 +// ModelsMediaScale defines model for ModelsMedia.Scale. +type ModelsMediaScale float32 -// ReadUser User details. -type ReadUser struct { +// ModelsMediaCreateItem Link and metadata for an emote image. +type ModelsMediaCreateItem struct { + Data string `json:"data"` + + // Format Media formats that the CDN delivers. + Format ModelsMediaType `json:"format"` + Scale ModelsMediaCreateItemScale `json:"scale"` +} + +// ModelsMediaCreateItemScale defines model for ModelsMediaCreateItem.Scale. +type ModelsMediaCreateItemScale float32 + +// ModelsMinEmote Minimum-detail emote model for inclusion in other bodies. +type ModelsMinEmote struct { + // Hash Content hash of the 1x scale emote of a selected mediaType. + Hash string `json:"hash"` + + // ID ID of a user, emote, emote list, &c. + // UUIDv7. + ID ModelsID `json:"id"` +} + +// ModelsUser User details. +type ModelsUser struct { // Ban User ban information. Only shown to the user themselves. - Ban *struct { - Reason string `json:"reason"` - Until time.Time `json:"until"` - } `json:"ban,omitempty"` + Ban *ModelsUserBan `json:"ban,omitempty"` // ID ID of a user, emote, emote list, &c. // UUIDv7. @@ -199,40 +263,236 @@ type ReadUser struct { Picture *string `json:"picture,omitempty"` // Sets Emote sets the user owns. - Sets []ReadEmoteSet `json:"sets"` + Sets *[]ModelsEmoteSet `json:"sets,omitempty"` // Standing User's standing if other than ok. - Standing *ReadUserStanding `json:"standing,omitempty"` + Standing *ModelsUserStanding `json:"standing,omitempty"` } -// ReadMediaType Media formats that the CDN delivers. -type ReadMediaType string +// ModelsUserBan User ban details. +// A banned user cannot use any authenticated APIs, meaning they cannot upload +// or edit emotes, manage emote sets, or moderate. +// They can still use the Read APIs and can still be issued sessions, allowing +// them to sign in and see their ban reason. +type ModelsUserBan struct { + // Reason Reason for the ban. This is shown to the banned user. + Reason string `json:"reason"` -// ReadUserStanding General status of a user. -type ReadUserStanding string + // Until Time the ban expires and the user regains full access to Ligmotes. + Until time.Time `json:"until"` +} + +// ModelsUserUpdate User details. +type ModelsUserUpdate struct { + // Name User's display name. Not canonicalized. + Name string `json:"name"` + + // Picture User's profile picture, if any. + Picture *string `json:"picture,omitempty"` +} + +// ModelsID ID of a user, emote, emote list, &c. +// UUIDv7. +type ModelsID = string + +// ModelsMediaType Media formats that the CDN delivers. +type ModelsMediaType string + +// ModelsPlatform Platforms supported by Ligmotes. +type ModelsPlatform string + +// ModelsUserStanding General status of a user. +type ModelsUserStanding string + +// ModerationEmoteDeleteOptions Options for deleting an emote. +type ModerationEmoteDeleteOptions struct { + DeleteMedia *bool `json:"deleteMedia,omitempty"` +} + +// ModerationEmoteStatus Request body for updating emote approval status. +type ModerationEmoteStatus struct { + Approved bool `json:"approved"` +} + +// ReadPlatformsPlatformParamsConnectedID defines model for Read.Platforms.platformParams.connectedID. +type ReadPlatformsPlatformParamsConnectedID = string + +// ReadPlatformsPlatformParamsPlatform Platforms supported by Ligmotes. +type ReadPlatformsPlatformParamsPlatform = ModelsPlatform // GetEmotesParams defines parameters for GetEmotes. type GetEmotesParams struct { ID []ModelsID `form:"id" json:"id"` } +// CreateEmoteJSONBody defines parameters for CreateEmote. +type CreateEmoteJSONBody struct { + // Emote Full-detail emote model. + Emote ModelsEmoteCreate `json:"emote"` +} + +// ListUnreviewedEmotesParams defines parameters for ListUnreviewedEmotes. +type ListUnreviewedEmotesParams struct { + Limit *int `form:"limit,omitempty" json:"limit,omitempty"` +} + +// ReportPlatformUseJSONBody defines parameters for ReportPlatformUse. +type ReportPlatformUseJSONBody struct { + // Emotes Emote IDs used. + // IDs should be deduplicated. + Emotes []ModelsID `json:"emotes"` +} + +// GetPlatformSetParams defines parameters for GetPlatformSet. +type GetPlatformSetParams struct { + MediaType *ModelsMediaType `form:"mediaType,omitempty" json:"mediaType,omitempty"` +} + +// UpdateActiveSetJSONBody defines parameters for UpdateActiveSet. +type UpdateActiveSetJSONBody struct { + // SetID ID of a user, emote, emote list, &c. + // UUIDv7. + SetID ModelsID `json:"setID"` +} + +// GetSetParams defines parameters for GetSet. +type GetSetParams struct { + MediaType *ModelsMediaType `form:"mediaType,omitempty" json:"mediaType,omitempty"` +} + +// RemoveEditorJSONBody defines parameters for RemoveEditor. +type RemoveEditorJSONBody struct { + // UserID ID of a user, emote, emote list, &c. + // UUIDv7. + UserID ModelsID `json:"userID"` +} + +// AddEditorJSONBody defines parameters for AddEditor. +type AddEditorJSONBody struct { + // UserID ID of a user, emote, emote list, &c. + // UUIDv7. + UserID ModelsID `json:"userID"` +} + +// CreateEmoteJSONRequestBody defines body for CreateEmote for application/json ContentType. +type CreateEmoteJSONRequestBody CreateEmoteJSONBody + +// UpdateEmoteJSONRequestBody defines body for UpdateEmote for application/json ContentType. +type UpdateEmoteJSONRequestBody = ModelsEmoteUpdate + +// HardDeleteEmoteJSONRequestBody defines body for HardDeleteEmote for application/json ContentType. +type HardDeleteEmoteJSONRequestBody = ModerationEmoteDeleteOptions + +// UpdateEmoteStatusJSONRequestBody defines body for UpdateEmoteStatus for application/json ContentType. +type UpdateEmoteStatusJSONRequestBody = ModerationEmoteStatus + +// BanJSONRequestBody defines body for Ban for application/json ContentType. +type BanJSONRequestBody = ModelsUserBan + +// ReportPlatformUseJSONRequestBody defines body for ReportPlatformUse for application/json ContentType. +type ReportPlatformUseJSONRequestBody ReportPlatformUseJSONBody + +// UpdateActiveSetJSONRequestBody defines body for UpdateActiveSet for application/json ContentType. +type UpdateActiveSetJSONRequestBody UpdateActiveSetJSONBody + +// CreateEmoteSetJSONRequestBody defines body for CreateEmoteSet for application/json ContentType. +type CreateEmoteSetJSONRequestBody = ModelsEmoteSet + +// UpdateEmoteSetJSONRequestBody defines body for UpdateEmoteSet for application/json ContentType. +type UpdateEmoteSetJSONRequestBody = ModelsEmoteSet + +// RemoveEditorJSONRequestBody defines body for RemoveEditor for application/json ContentType. +type RemoveEditorJSONRequestBody RemoveEditorJSONBody + +// AddEditorJSONRequestBody defines body for AddEditor for application/json ContentType. +type AddEditorJSONRequestBody AddEditorJSONBody + +// RemoveEmoteJSONRequestBody defines body for RemoveEmote for application/json ContentType. +type RemoveEmoteJSONRequestBody = ChatManagementSetEmote + +// RenameEmoteJSONRequestBody defines body for RenameEmote for application/json ContentType. +type RenameEmoteJSONRequestBody = ChatManagementSetEmote + +// AddEmoteJSONRequestBody defines body for AddEmote for application/json ContentType. +type AddEmoteJSONRequestBody = ChatManagementSetEmote + +// UpdateUserJSONRequestBody defines body for UpdateUser for application/json ContentType. +type UpdateUserJSONRequestBody = ModelsUserUpdate + // ServerInterface represents all server handlers. type ServerInterface interface { // (GET /emotes) GetEmotes(w http.ResponseWriter, r *http.Request, params GetEmotesParams) + // (POST /emotes) + CreateEmote(w http.ResponseWriter, r *http.Request) + + // (DELETE /emotes/{emoteID}) + DeleteEmote(w http.ResponseWriter, r *http.Request, emoteID ModelsID) + + // (PATCH /emotes/{emoteID}) + UpdateEmote(w http.ResponseWriter, r *http.Request, emoteID ModelsID) + + // (GET /moderate/emotes) + ListUnreviewedEmotes(w http.ResponseWriter, r *http.Request, params ListUnreviewedEmotesParams) + + // (DELETE /moderate/emotes/{emoteID}) + HardDeleteEmote(w http.ResponseWriter, r *http.Request, emoteID ModelsID) + + // (POST /moderate/emotes/{emoteID}) + UpdateEmoteStatus(w http.ResponseWriter, r *http.Request, emoteID ModelsID) + + // (POST /moderate/users/{userID}) + Ban(w http.ResponseWriter, r *http.Request, userID ModelsID) + + // (POST /platforms/{platform}/connections/{connectedID}/emotes) + ReportPlatformUse(w http.ResponseWriter, r *http.Request, platform ReadPlatformsPlatformParamsPlatform, connectedID ReadPlatformsPlatformParamsConnectedID) + // (GET /platforms/{platform}/connections/{connectedID}/set) - GetPlatformSet(w http.ResponseWriter, r *http.Request, platform ModelsPlatform, connectedID string) + GetPlatformSet(w http.ResponseWriter, r *http.Request, platform ReadPlatformsPlatformParamsPlatform, connectedID ReadPlatformsPlatformParamsConnectedID, params GetPlatformSetParams) + + // (PATCH /platforms/{platform}/connections/{connectedID}/set) + UpdateActiveSet(w http.ResponseWriter, r *http.Request, platform ModelsPlatform, connectedID string) // (GET /platforms/{platform}/connections/{connectedID}/user) - GetPlatformUser(w http.ResponseWriter, r *http.Request, platform ModelsPlatform, connectedID string) + GetPlatformUser(w http.ResponseWriter, r *http.Request, platform ReadPlatformsPlatformParamsPlatform, connectedID ReadPlatformsPlatformParamsConnectedID) + + // (POST /sets) + CreateEmoteSet(w http.ResponseWriter, r *http.Request) // (GET /sets/{setID}) - GetSet(w http.ResponseWriter, r *http.Request, setID ModelsID) + GetSet(w http.ResponseWriter, r *http.Request, setID ModelsID, params GetSetParams) + + // (PATCH /sets/{setID}) + UpdateEmoteSet(w http.ResponseWriter, r *http.Request, setID ModelsID) + + // (DELETE /sets/{setID}/editors) + RemoveEditor(w http.ResponseWriter, r *http.Request, setID ModelsID) + + // (POST /sets/{setID}/editors) + AddEditor(w http.ResponseWriter, r *http.Request, setID ModelsID) + + // (DELETE /sets/{setID}/emotes) + RemoveEmote(w http.ResponseWriter, r *http.Request, setID ModelsID) + + // (PATCH /sets/{setID}/emotes) + RenameEmote(w http.ResponseWriter, r *http.Request, setID ModelsID) + + // (POST /sets/{setID}/emotes) + AddEmote(w http.ResponseWriter, r *http.Request, setID ModelsID) + + // (DELETE /users/{userID}) + DeleteUser(w http.ResponseWriter, r *http.Request, userID ModelsID) // (GET /users/{userID}) GetUser(w http.ResponseWriter, r *http.Request, userID ModelsID) + + // (PATCH /users/{userID}) + UpdateUser(w http.ResponseWriter, r *http.Request, userID ModelsID) + + // (GET /users/{userID}/sets) + ListEditableSets(w http.ResponseWriter, r *http.Request, userID ModelsID) } // ServerInterfaceWrapper converts contexts to parameters. @@ -278,11 +538,298 @@ func (siw *ServerInterfaceWrapper) GetEmotes(w http.ResponseWriter, r *http.Requ handler.ServeHTTP(w, r) } +// CreateEmote operation middleware +func (siw *ServerInterfaceWrapper) CreateEmote(w http.ResponseWriter, r *http.Request) { + + ctx := r.Context() + + ctx = context.WithValue(ctx, BearerAuthScopes, []string{}) + + r = r.WithContext(ctx) + + handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + siw.Handler.CreateEmote(w, r) + })) + + for _, middleware := range siw.HandlerMiddlewares { + handler = middleware(handler) + } + + handler.ServeHTTP(w, r) +} + +// DeleteEmote operation middleware +func (siw *ServerInterfaceWrapper) DeleteEmote(w http.ResponseWriter, r *http.Request) { + + var err error + + // ------------- Path parameter "emoteID" ------------- + var emoteID ModelsID + + err = runtime.BindStyledParameterWithOptions("simple", "emoteID", r.PathValue("emoteID"), &emoteID, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true}) + if err != nil { + siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "emoteID", Err: err}) + return + } + + ctx := r.Context() + + ctx = context.WithValue(ctx, BearerAuthScopes, []string{}) + + r = r.WithContext(ctx) + + handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + siw.Handler.DeleteEmote(w, r, emoteID) + })) + + for _, middleware := range siw.HandlerMiddlewares { + handler = middleware(handler) + } + + handler.ServeHTTP(w, r) +} + +// UpdateEmote operation middleware +func (siw *ServerInterfaceWrapper) UpdateEmote(w http.ResponseWriter, r *http.Request) { + + var err error + + // ------------- Path parameter "emoteID" ------------- + var emoteID ModelsID + + err = runtime.BindStyledParameterWithOptions("simple", "emoteID", r.PathValue("emoteID"), &emoteID, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true}) + if err != nil { + siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "emoteID", Err: err}) + return + } + + ctx := r.Context() + + ctx = context.WithValue(ctx, BearerAuthScopes, []string{}) + + r = r.WithContext(ctx) + + handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + siw.Handler.UpdateEmote(w, r, emoteID) + })) + + for _, middleware := range siw.HandlerMiddlewares { + handler = middleware(handler) + } + + handler.ServeHTTP(w, r) +} + +// ListUnreviewedEmotes operation middleware +func (siw *ServerInterfaceWrapper) ListUnreviewedEmotes(w http.ResponseWriter, r *http.Request) { + + var err error + + ctx := r.Context() + + ctx = context.WithValue(ctx, BearerAuthScopes, []string{}) + + r = r.WithContext(ctx) + + // Parameter object where we will unmarshal all parameters from the context + var params ListUnreviewedEmotesParams + + // ------------- Optional query parameter "limit" ------------- + + err = runtime.BindQueryParameter("form", false, false, "limit", r.URL.Query(), ¶ms.Limit) + if err != nil { + siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "limit", Err: err}) + return + } + + handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + siw.Handler.ListUnreviewedEmotes(w, r, params) + })) + + for _, middleware := range siw.HandlerMiddlewares { + handler = middleware(handler) + } + + handler.ServeHTTP(w, r) +} + +// HardDeleteEmote operation middleware +func (siw *ServerInterfaceWrapper) HardDeleteEmote(w http.ResponseWriter, r *http.Request) { + + var err error + + // ------------- Path parameter "emoteID" ------------- + var emoteID ModelsID + + err = runtime.BindStyledParameterWithOptions("simple", "emoteID", r.PathValue("emoteID"), &emoteID, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true}) + if err != nil { + siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "emoteID", Err: err}) + return + } + + ctx := r.Context() + + ctx = context.WithValue(ctx, BearerAuthScopes, []string{}) + + r = r.WithContext(ctx) + + handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + siw.Handler.HardDeleteEmote(w, r, emoteID) + })) + + for _, middleware := range siw.HandlerMiddlewares { + handler = middleware(handler) + } + + handler.ServeHTTP(w, r) +} + +// UpdateEmoteStatus operation middleware +func (siw *ServerInterfaceWrapper) UpdateEmoteStatus(w http.ResponseWriter, r *http.Request) { + + var err error + + // ------------- Path parameter "emoteID" ------------- + var emoteID ModelsID + + err = runtime.BindStyledParameterWithOptions("simple", "emoteID", r.PathValue("emoteID"), &emoteID, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true}) + if err != nil { + siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "emoteID", Err: err}) + return + } + + ctx := r.Context() + + ctx = context.WithValue(ctx, BearerAuthScopes, []string{}) + + r = r.WithContext(ctx) + + handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + siw.Handler.UpdateEmoteStatus(w, r, emoteID) + })) + + for _, middleware := range siw.HandlerMiddlewares { + handler = middleware(handler) + } + + handler.ServeHTTP(w, r) +} + +// Ban operation middleware +func (siw *ServerInterfaceWrapper) Ban(w http.ResponseWriter, r *http.Request) { + + var err error + + // ------------- Path parameter "userID" ------------- + var userID ModelsID + + err = runtime.BindStyledParameterWithOptions("simple", "userID", r.PathValue("userID"), &userID, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true}) + if err != nil { + siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "userID", Err: err}) + return + } + + ctx := r.Context() + + ctx = context.WithValue(ctx, BearerAuthScopes, []string{}) + + r = r.WithContext(ctx) + + handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + siw.Handler.Ban(w, r, userID) + })) + + for _, middleware := range siw.HandlerMiddlewares { + handler = middleware(handler) + } + + handler.ServeHTTP(w, r) +} + +// ReportPlatformUse operation middleware +func (siw *ServerInterfaceWrapper) ReportPlatformUse(w http.ResponseWriter, r *http.Request) { + + var err error + + // ------------- Path parameter "platform" ------------- + var platform ReadPlatformsPlatformParamsPlatform + + err = runtime.BindStyledParameterWithOptions("simple", "platform", r.PathValue("platform"), &platform, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true}) + if err != nil { + siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "platform", Err: err}) + return + } + + // ------------- Path parameter "connectedID" ------------- + var connectedID ReadPlatformsPlatformParamsConnectedID + + err = runtime.BindStyledParameterWithOptions("simple", "connectedID", r.PathValue("connectedID"), &connectedID, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true}) + if err != nil { + siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "connectedID", Err: err}) + return + } + + handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + siw.Handler.ReportPlatformUse(w, r, platform, connectedID) + })) + + for _, middleware := range siw.HandlerMiddlewares { + handler = middleware(handler) + } + + handler.ServeHTTP(w, r) +} + // GetPlatformSet operation middleware func (siw *ServerInterfaceWrapper) GetPlatformSet(w http.ResponseWriter, r *http.Request) { var err error + // ------------- Path parameter "platform" ------------- + var platform ReadPlatformsPlatformParamsPlatform + + err = runtime.BindStyledParameterWithOptions("simple", "platform", r.PathValue("platform"), &platform, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true}) + if err != nil { + siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "platform", Err: err}) + return + } + + // ------------- Path parameter "connectedID" ------------- + var connectedID ReadPlatformsPlatformParamsConnectedID + + err = runtime.BindStyledParameterWithOptions("simple", "connectedID", r.PathValue("connectedID"), &connectedID, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true}) + if err != nil { + siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "connectedID", Err: err}) + return + } + + // Parameter object where we will unmarshal all parameters from the context + var params GetPlatformSetParams + + // ------------- Optional query parameter "mediaType" ------------- + + err = runtime.BindQueryParameter("form", false, false, "mediaType", r.URL.Query(), ¶ms.MediaType) + if err != nil { + siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "mediaType", Err: err}) + return + } + + handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + siw.Handler.GetPlatformSet(w, r, platform, connectedID, params) + })) + + for _, middleware := range siw.HandlerMiddlewares { + handler = middleware(handler) + } + + handler.ServeHTTP(w, r) +} + +// UpdateActiveSet operation middleware +func (siw *ServerInterfaceWrapper) UpdateActiveSet(w http.ResponseWriter, r *http.Request) { + + var err error + // ------------- Path parameter "platform" ------------- var platform ModelsPlatform @@ -301,8 +848,14 @@ func (siw *ServerInterfaceWrapper) GetPlatformSet(w http.ResponseWriter, r *http return } + ctx := r.Context() + + ctx = context.WithValue(ctx, BearerAuthScopes, []string{}) + + r = r.WithContext(ctx) + handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - siw.Handler.GetPlatformSet(w, r, platform, connectedID) + siw.Handler.UpdateActiveSet(w, r, platform, connectedID) })) for _, middleware := range siw.HandlerMiddlewares { @@ -318,7 +871,7 @@ func (siw *ServerInterfaceWrapper) GetPlatformUser(w http.ResponseWriter, r *htt var err error // ------------- Path parameter "platform" ------------- - var platform ModelsPlatform + var platform ReadPlatformsPlatformParamsPlatform err = runtime.BindStyledParameterWithOptions("simple", "platform", r.PathValue("platform"), &platform, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true}) if err != nil { @@ -327,7 +880,7 @@ func (siw *ServerInterfaceWrapper) GetPlatformUser(w http.ResponseWriter, r *htt } // ------------- Path parameter "connectedID" ------------- - var connectedID string + var connectedID ReadPlatformsPlatformParamsConnectedID err = runtime.BindStyledParameterWithOptions("simple", "connectedID", r.PathValue("connectedID"), &connectedID, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true}) if err != nil { @@ -346,6 +899,26 @@ func (siw *ServerInterfaceWrapper) GetPlatformUser(w http.ResponseWriter, r *htt handler.ServeHTTP(w, r) } +// CreateEmoteSet operation middleware +func (siw *ServerInterfaceWrapper) CreateEmoteSet(w http.ResponseWriter, r *http.Request) { + + ctx := r.Context() + + ctx = context.WithValue(ctx, BearerAuthScopes, []string{}) + + r = r.WithContext(ctx) + + handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + siw.Handler.CreateEmoteSet(w, r) + })) + + for _, middleware := range siw.HandlerMiddlewares { + handler = middleware(handler) + } + + handler.ServeHTTP(w, r) +} + // GetSet operation middleware func (siw *ServerInterfaceWrapper) GetSet(w http.ResponseWriter, r *http.Request) { @@ -360,8 +933,236 @@ func (siw *ServerInterfaceWrapper) GetSet(w http.ResponseWriter, r *http.Request return } + // Parameter object where we will unmarshal all parameters from the context + var params GetSetParams + + // ------------- Optional query parameter "mediaType" ------------- + + err = runtime.BindQueryParameter("form", false, false, "mediaType", r.URL.Query(), ¶ms.MediaType) + if err != nil { + siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "mediaType", Err: err}) + return + } + handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - siw.Handler.GetSet(w, r, setID) + siw.Handler.GetSet(w, r, setID, params) + })) + + for _, middleware := range siw.HandlerMiddlewares { + handler = middleware(handler) + } + + handler.ServeHTTP(w, r) +} + +// UpdateEmoteSet operation middleware +func (siw *ServerInterfaceWrapper) UpdateEmoteSet(w http.ResponseWriter, r *http.Request) { + + var err error + + // ------------- Path parameter "setID" ------------- + var setID ModelsID + + err = runtime.BindStyledParameterWithOptions("simple", "setID", r.PathValue("setID"), &setID, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true}) + if err != nil { + siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "setID", Err: err}) + return + } + + ctx := r.Context() + + ctx = context.WithValue(ctx, BearerAuthScopes, []string{}) + + r = r.WithContext(ctx) + + handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + siw.Handler.UpdateEmoteSet(w, r, setID) + })) + + for _, middleware := range siw.HandlerMiddlewares { + handler = middleware(handler) + } + + handler.ServeHTTP(w, r) +} + +// RemoveEditor operation middleware +func (siw *ServerInterfaceWrapper) RemoveEditor(w http.ResponseWriter, r *http.Request) { + + var err error + + // ------------- Path parameter "setID" ------------- + var setID ModelsID + + err = runtime.BindStyledParameterWithOptions("simple", "setID", r.PathValue("setID"), &setID, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true}) + if err != nil { + siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "setID", Err: err}) + return + } + + ctx := r.Context() + + ctx = context.WithValue(ctx, BearerAuthScopes, []string{}) + + r = r.WithContext(ctx) + + handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + siw.Handler.RemoveEditor(w, r, setID) + })) + + for _, middleware := range siw.HandlerMiddlewares { + handler = middleware(handler) + } + + handler.ServeHTTP(w, r) +} + +// AddEditor operation middleware +func (siw *ServerInterfaceWrapper) AddEditor(w http.ResponseWriter, r *http.Request) { + + var err error + + // ------------- Path parameter "setID" ------------- + var setID ModelsID + + err = runtime.BindStyledParameterWithOptions("simple", "setID", r.PathValue("setID"), &setID, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true}) + if err != nil { + siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "setID", Err: err}) + return + } + + ctx := r.Context() + + ctx = context.WithValue(ctx, BearerAuthScopes, []string{}) + + r = r.WithContext(ctx) + + handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + siw.Handler.AddEditor(w, r, setID) + })) + + for _, middleware := range siw.HandlerMiddlewares { + handler = middleware(handler) + } + + handler.ServeHTTP(w, r) +} + +// RemoveEmote operation middleware +func (siw *ServerInterfaceWrapper) RemoveEmote(w http.ResponseWriter, r *http.Request) { + + var err error + + // ------------- Path parameter "setID" ------------- + var setID ModelsID + + err = runtime.BindStyledParameterWithOptions("simple", "setID", r.PathValue("setID"), &setID, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true}) + if err != nil { + siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "setID", Err: err}) + return + } + + ctx := r.Context() + + ctx = context.WithValue(ctx, BearerAuthScopes, []string{}) + + r = r.WithContext(ctx) + + handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + siw.Handler.RemoveEmote(w, r, setID) + })) + + for _, middleware := range siw.HandlerMiddlewares { + handler = middleware(handler) + } + + handler.ServeHTTP(w, r) +} + +// RenameEmote operation middleware +func (siw *ServerInterfaceWrapper) RenameEmote(w http.ResponseWriter, r *http.Request) { + + var err error + + // ------------- Path parameter "setID" ------------- + var setID ModelsID + + err = runtime.BindStyledParameterWithOptions("simple", "setID", r.PathValue("setID"), &setID, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true}) + if err != nil { + siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "setID", Err: err}) + return + } + + ctx := r.Context() + + ctx = context.WithValue(ctx, BearerAuthScopes, []string{}) + + r = r.WithContext(ctx) + + handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + siw.Handler.RenameEmote(w, r, setID) + })) + + for _, middleware := range siw.HandlerMiddlewares { + handler = middleware(handler) + } + + handler.ServeHTTP(w, r) +} + +// AddEmote operation middleware +func (siw *ServerInterfaceWrapper) AddEmote(w http.ResponseWriter, r *http.Request) { + + var err error + + // ------------- Path parameter "setID" ------------- + var setID ModelsID + + err = runtime.BindStyledParameterWithOptions("simple", "setID", r.PathValue("setID"), &setID, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true}) + if err != nil { + siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "setID", Err: err}) + return + } + + ctx := r.Context() + + ctx = context.WithValue(ctx, BearerAuthScopes, []string{}) + + r = r.WithContext(ctx) + + handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + siw.Handler.AddEmote(w, r, setID) + })) + + for _, middleware := range siw.HandlerMiddlewares { + handler = middleware(handler) + } + + handler.ServeHTTP(w, r) +} + +// DeleteUser operation middleware +func (siw *ServerInterfaceWrapper) DeleteUser(w http.ResponseWriter, r *http.Request) { + + var err error + + // ------------- Path parameter "userID" ------------- + var userID ModelsID + + err = runtime.BindStyledParameterWithOptions("simple", "userID", r.PathValue("userID"), &userID, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true}) + if err != nil { + siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "userID", Err: err}) + return + } + + ctx := r.Context() + + ctx = context.WithValue(ctx, BearerAuthScopes, []string{}) + + r = r.WithContext(ctx) + + handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + siw.Handler.DeleteUser(w, r, userID) })) for _, middleware := range siw.HandlerMiddlewares { @@ -396,6 +1197,68 @@ func (siw *ServerInterfaceWrapper) GetUser(w http.ResponseWriter, r *http.Reques handler.ServeHTTP(w, r) } +// UpdateUser operation middleware +func (siw *ServerInterfaceWrapper) UpdateUser(w http.ResponseWriter, r *http.Request) { + + var err error + + // ------------- Path parameter "userID" ------------- + var userID ModelsID + + err = runtime.BindStyledParameterWithOptions("simple", "userID", r.PathValue("userID"), &userID, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true}) + if err != nil { + siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "userID", Err: err}) + return + } + + ctx := r.Context() + + ctx = context.WithValue(ctx, BearerAuthScopes, []string{}) + + r = r.WithContext(ctx) + + handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + siw.Handler.UpdateUser(w, r, userID) + })) + + for _, middleware := range siw.HandlerMiddlewares { + handler = middleware(handler) + } + + handler.ServeHTTP(w, r) +} + +// ListEditableSets operation middleware +func (siw *ServerInterfaceWrapper) ListEditableSets(w http.ResponseWriter, r *http.Request) { + + var err error + + // ------------- Path parameter "userID" ------------- + var userID ModelsID + + err = runtime.BindStyledParameterWithOptions("simple", "userID", r.PathValue("userID"), &userID, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true}) + if err != nil { + siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "userID", Err: err}) + return + } + + ctx := r.Context() + + ctx = context.WithValue(ctx, BearerAuthScopes, []string{}) + + r = r.WithContext(ctx) + + handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + siw.Handler.ListEditableSets(w, r, userID) + })) + + for _, middleware := range siw.HandlerMiddlewares { + handler = middleware(handler) + } + + handler.ServeHTTP(w, r) +} + type UnescapedCookieParamError struct { ParamName string Err error @@ -517,10 +1380,29 @@ func HandlerWithOptions(si ServerInterface, options StdHTTPServerOptions) http.H } m.HandleFunc("GET "+options.BaseURL+"/emotes", wrapper.GetEmotes) + m.HandleFunc("POST "+options.BaseURL+"/emotes", wrapper.CreateEmote) + m.HandleFunc("DELETE "+options.BaseURL+"/emotes/{emoteID}", wrapper.DeleteEmote) + m.HandleFunc("PATCH "+options.BaseURL+"/emotes/{emoteID}", wrapper.UpdateEmote) + m.HandleFunc("GET "+options.BaseURL+"/moderate/emotes", wrapper.ListUnreviewedEmotes) + m.HandleFunc("DELETE "+options.BaseURL+"/moderate/emotes/{emoteID}", wrapper.HardDeleteEmote) + m.HandleFunc("POST "+options.BaseURL+"/moderate/emotes/{emoteID}", wrapper.UpdateEmoteStatus) + m.HandleFunc("POST "+options.BaseURL+"/moderate/users/{userID}", wrapper.Ban) + m.HandleFunc("POST "+options.BaseURL+"/platforms/{platform}/connections/{connectedID}/emotes", wrapper.ReportPlatformUse) m.HandleFunc("GET "+options.BaseURL+"/platforms/{platform}/connections/{connectedID}/set", wrapper.GetPlatformSet) + m.HandleFunc("PATCH "+options.BaseURL+"/platforms/{platform}/connections/{connectedID}/set", wrapper.UpdateActiveSet) m.HandleFunc("GET "+options.BaseURL+"/platforms/{platform}/connections/{connectedID}/user", wrapper.GetPlatformUser) + m.HandleFunc("POST "+options.BaseURL+"/sets", wrapper.CreateEmoteSet) m.HandleFunc("GET "+options.BaseURL+"/sets/{setID}", wrapper.GetSet) + m.HandleFunc("PATCH "+options.BaseURL+"/sets/{setID}", wrapper.UpdateEmoteSet) + m.HandleFunc("DELETE "+options.BaseURL+"/sets/{setID}/editors", wrapper.RemoveEditor) + m.HandleFunc("POST "+options.BaseURL+"/sets/{setID}/editors", wrapper.AddEditor) + m.HandleFunc("DELETE "+options.BaseURL+"/sets/{setID}/emotes", wrapper.RemoveEmote) + m.HandleFunc("PATCH "+options.BaseURL+"/sets/{setID}/emotes", wrapper.RenameEmote) + m.HandleFunc("POST "+options.BaseURL+"/sets/{setID}/emotes", wrapper.AddEmote) + m.HandleFunc("DELETE "+options.BaseURL+"/users/{userID}", wrapper.DeleteUser) m.HandleFunc("GET "+options.BaseURL+"/users/{userID}", wrapper.GetUser) + m.HandleFunc("PATCH "+options.BaseURL+"/users/{userID}", wrapper.UpdateUser) + m.HandleFunc("GET "+options.BaseURL+"/users/{userID}/sets", wrapper.ListEditableSets) return m } diff --git a/mise.toml b/mise.toml index 04162f9..9794236 100644 --- a/mise.toml +++ b/mise.toml @@ -80,7 +80,8 @@ run = [ [tasks."gen:api"] description = "Generate API scaffold" run = [ - 'go tool oapi-codegen -config ./backend/rest/config.yaml ./api/schema/openapi.yaml', + 'tsp compile ./api', + 'go tool oapi-codegen -config ./backend/rest/config.yaml ./api/schema/openapi.v1.yaml', ] [env]