diff --git a/internal/api/errors.go b/internal/api/errors.go index b5dce6ca4..119edd528 100644 --- a/internal/api/errors.go +++ b/internal/api/errors.go @@ -53,7 +53,7 @@ func GetErrors(router *gin.RouterGroup) { // DeleteErrors removes all entries from the error logs. // // @Summary removes all entries from the error logs -// @Id Delete Errors +// @Id DeleteErrors // @Tags Errors // @Produce json // @Failure 401,403,429,500 {object} i18n.Response diff --git a/internal/api/file_delete.go b/internal/api/file_delete.go index 4d9c31fc2..65217a783 100644 --- a/internal/api/file_delete.go +++ b/internal/api/file_delete.go @@ -17,12 +17,15 @@ import ( // DeleteFile removes a file from storage. // -// The request parameters are: -// -// - uid: string Photo UID as returned by the API -// - file_uid: string File UID as returned by the API -// -// DELETE /api/v1/photos/:uid/files/:file_uid +// @Summary removes a file from storage +// @Id DeleteFile +// @Tags Files +// @Produce json +// @Success 200 {object} entity.Photo +// @Failure 401,403,404,429,500 {object} i18n.Response +// @Param uid path string true "photo uid" +// @Param fileuid path string true "file uid" +// @Router /api/v1/photos/{uid}/files/{fileuid} [delete] func DeleteFile(router *gin.RouterGroup) { router.DELETE("/photos/:uid/files/:file_uid", func(c *gin.Context) { s := Auth(c, acl.ResourceFiles, acl.ActionDelete) diff --git a/internal/api/file_orientation.go b/internal/api/file_orientation.go index d033ddfda..3ef2d8ea4 100644 --- a/internal/api/file_orientation.go +++ b/internal/api/file_orientation.go @@ -16,12 +16,16 @@ import ( // ChangeFileOrientation changes the orientation of a file. // -// The request parameters are: -// -// - uid: string Photo UID as returned by the API -// - file_uid: string File UID as returned by the API -// -// PUT /api/v1/photos/:uid/files/:file_uid/orientation +// @Summary changes the orientation of a file +// @Id ChangeFileOrientation +// @Tags Files +// @Produce json +// @Success 200 {object} entity.Photo +// @Failure 400,401,403,404,429,500 {object} i18n.Response +// @Param uid path string true "photo uid" +// @Param fileuid path string true "file uid" +// @Param file body form.File true "file orientation" +// @Router /api/v1/photos/{uid}/files/{fileuid}/orientation [put] func ChangeFileOrientation(router *gin.RouterGroup) { router.PUT("/photos/:uid/files/:file_uid/orientation", func(c *gin.Context) { s := Auth(c, acl.ResourceFiles, acl.ActionUpdate) diff --git a/internal/api/files.go b/internal/api/files.go index ef8fd2383..02c5183f0 100644 --- a/internal/api/files.go +++ b/internal/api/files.go @@ -12,11 +12,14 @@ import ( // GetFile returns file details as JSON. // -// The request parameters are: -// -// - hash (string) SHA-1 hash of the file -// -// GET /api/v1/files/:hash +// @Summary returns file details as JSON +// @Id GetFile +// @Tags Files +// @Produce json +// @Success 200 {object} entity.File +// @Failure 401,403,404,429 {object} i18n.Response +// @Param hash path string true "hash (string) SHA-1 hash of the file" +// @Router /api/v1/files/{hash} [get] func GetFile(router *gin.RouterGroup) { router.GET("/files/:hash", func(c *gin.Context) { s := Auth(c, acl.ResourceFiles, acl.ActionView) diff --git a/internal/api/folders_cover.go b/internal/api/folders_cover.go index c26eb7331..de532e6a4 100644 --- a/internal/api/folders_cover.go +++ b/internal/api/folders_cover.go @@ -21,13 +21,18 @@ const ( // FolderCover returns a folder cover image. // -// The request parameters are: -// -// - uid: string folder uid -// - token: string url security token, see config -// - size: string thumb type, see thumb.Sizes -// -// GET /api/v1/folders/t/:hash/:token/:size +// @Summary returns a folder cover image +// @Id FolderCover +// @Produce image/jpeg +// @Produce image/svg+xml +// @Tags Images, Folders +// @Failure 403 {file} image/svg+xml +// @Failure 200 {file} image/svg+xml +// @Success 200 {file} image/jpg +// @Param uid path string true "folder uid" +// @Param token path string true "user-specific security token provided with session or 'public' when running PhotoPrism in public mode" +// @Param size path string true "thumbnail size" Enums(tile_50, tile_100, left_224, right_224, tile_224, tile_500, fit_720, tile_1080, fit_1280, fit_1600, fit_1920, fit_2048, fit_2560, fit_3840, fit_4096, fit_7680) +// @Router /api/v1/folders/t/{uid}/{token}/{size} [get] func FolderCover(router *gin.RouterGroup) { router.GET("/folders/t/:uid/:token/:size", func(c *gin.Context) { if InvalidPreviewToken(c) { diff --git a/internal/api/labels_search.go b/internal/api/labels_search.go index ffd25f407..6add4ad86 100644 --- a/internal/api/labels_search.go +++ b/internal/api/labels_search.go @@ -14,7 +14,17 @@ import ( // SearchLabels finds and returns labels as JSON. // -// GET /api/v1/labels +// @Summary finds and returns labels as JSON +// @Id SearchLabels +// @Tags Labels +// @Produce json +// @Success 200 {object} search.Label +// @Failure 401,429,403,400 {object} i18n.Response +// @Param count query int true "maximum number of results" minimum(1) maximum(100000) +// @Param offset query int false "search result offset" minimum(0) maximum(100000) +// @Param all query bool false "show all" +// @Param q query string false "search query" +// @Router /api/v1/labels [get] func SearchLabels(router *gin.RouterGroup) { router.GET("/labels", func(c *gin.Context) { s := Auth(c, acl.ResourceLabels, acl.ActionSearch) diff --git a/internal/api/swagger.json b/internal/api/swagger.json index 33637458a..bba1b0786 100644 --- a/internal/api/swagger.json +++ b/internal/api/swagger.json @@ -1411,7 +1411,7 @@ "Errors" ], "summary": "removes all entries from the error logs", - "operationId": "Delete Errors", + "operationId": "DeleteErrors", "responses": { "401": { "description": "Unauthorized", @@ -1668,6 +1668,128 @@ } } }, + "/api/v1/files/{hash}": { + "get": { + "produces": [ + "application/json" + ], + "tags": [ + "Files" + ], + "summary": "returns file details as JSON", + "operationId": "GetFile", + "parameters": [ + { + "type": "string", + "description": "hash (string) SHA-1 hash of the file", + "name": "hash", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/entity.File" + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/i18n.Response" + } + }, + "403": { + "description": "Forbidden", + "schema": { + "$ref": "#/definitions/i18n.Response" + } + }, + "404": { + "description": "Not Found", + "schema": { + "$ref": "#/definitions/i18n.Response" + } + }, + "429": { + "description": "Too Many Requests", + "schema": { + "$ref": "#/definitions/i18n.Response" + } + } + } + } + }, + "/api/v1/folders/t/{uid}/{token}/{size}": { + "get": { + "produces": [ + "image/jpeg", + "image/svg+xml" + ], + "tags": [ + "Images", + "Folders" + ], + "summary": "returns a folder cover image", + "operationId": "FolderCover", + "parameters": [ + { + "type": "string", + "description": "folder uid", + "name": "uid", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "user-specific security token provided with session or 'public' when running PhotoPrism in public mode", + "name": "token", + "in": "path", + "required": true + }, + { + "enum": [ + "tile_50", + "tile_100", + "left_224", + "right_224", + "tile_224", + "tile_500", + "fit_720", + "tile_1080", + "fit_1280", + "fit_1600", + "fit_1920", + "fit_2048", + "fit_2560", + "fit_3840", + "fit_4096", + "fit_7680" + ], + "type": "string", + "description": "thumbnail size", + "name": "size", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "file" + } + }, + "403": { + "description": "Forbidden", + "schema": { + "type": "file" + } + } + } + } + }, "/api/v1/import/{path}": { "post": { "tags": [ @@ -1684,6 +1806,81 @@ "responses": {} } }, + "/api/v1/labels": { + "get": { + "produces": [ + "application/json" + ], + "tags": [ + "Labels" + ], + "summary": "finds and returns labels as JSON", + "operationId": "SearchLabels", + "parameters": [ + { + "maximum": 100000, + "minimum": 1, + "type": "integer", + "description": "maximum number of results", + "name": "count", + "in": "query", + "required": true + }, + { + "maximum": 100000, + "minimum": 0, + "type": "integer", + "description": "search result offset", + "name": "offset", + "in": "query" + }, + { + "type": "boolean", + "description": "show all", + "name": "all", + "in": "query" + }, + { + "type": "string", + "description": "search query", + "name": "q", + "in": "query" + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/search.Label" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/i18n.Response" + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/i18n.Response" + } + }, + "403": { + "description": "Forbidden", + "schema": { + "$ref": "#/definitions/i18n.Response" + } + }, + "429": { + "description": "Too Many Requests", + "schema": { + "$ref": "#/definitions/i18n.Response" + } + } + } + } + }, "/api/v1/labels/{uid}": { "put": { "produces": [ @@ -2181,6 +2378,153 @@ "responses": {} } }, + "/api/v1/photos/{uid}/files/{fileuid}": { + "delete": { + "produces": [ + "application/json" + ], + "tags": [ + "Files" + ], + "summary": "removes a file from storage", + "operationId": "DeleteFile", + "parameters": [ + { + "type": "string", + "description": "photo uid", + "name": "uid", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "file uid", + "name": "fileuid", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/entity.Photo" + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/i18n.Response" + } + }, + "403": { + "description": "Forbidden", + "schema": { + "$ref": "#/definitions/i18n.Response" + } + }, + "404": { + "description": "Not Found", + "schema": { + "$ref": "#/definitions/i18n.Response" + } + }, + "429": { + "description": "Too Many Requests", + "schema": { + "$ref": "#/definitions/i18n.Response" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/i18n.Response" + } + } + } + } + }, + "/api/v1/photos/{uid}/files/{fileuid}/orientation": { + "put": { + "produces": [ + "application/json" + ], + "tags": [ + "Files" + ], + "summary": "changes the orientation of a file", + "operationId": "ChangeFileOrientation", + "parameters": [ + { + "type": "string", + "description": "photo uid", + "name": "uid", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "file uid", + "name": "fileuid", + "in": "path", + "required": true + }, + { + "description": "file orientation", + "name": "file", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/form.File" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/entity.Photo" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/i18n.Response" + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/i18n.Response" + } + }, + "403": { + "description": "Forbidden", + "schema": { + "$ref": "#/definitions/i18n.Response" + } + }, + "404": { + "description": "Not Found", + "schema": { + "$ref": "#/definitions/i18n.Response" + } + }, + "429": { + "description": "Too Many Requests", + "schema": { + "$ref": "#/definitions/i18n.Response" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/i18n.Response" + } + } + } + } + }, "/api/v1/photos/{uid}/label": { "post": { "tags": [ @@ -4436,6 +4780,14 @@ } } }, + "form.File": { + "type": "object", + "properties": { + "Orientation": { + "type": "integer" + } + } + }, "form.Label": { "type": "object", "properties": { @@ -4782,6 +5134,56 @@ } } }, + "search.Label": { + "type": "object", + "properties": { + "CreatedAt": { + "type": "string" + }, + "CustomSlug": { + "type": "string" + }, + "DeletedAt": { + "type": "string" + }, + "Description": { + "type": "string" + }, + "Favorite": { + "type": "boolean" + }, + "ID": { + "type": "integer" + }, + "Name": { + "type": "string" + }, + "Notes": { + "type": "string" + }, + "PhotoCount": { + "type": "integer" + }, + "Priority": { + "type": "integer" + }, + "Slug": { + "type": "string" + }, + "Thumb": { + "type": "string" + }, + "ThumbSrc": { + "type": "string" + }, + "UID": { + "type": "string" + }, + "UpdatedAt": { + "type": "string" + } + } + }, "search.Photo": { "type": "object", "properties": { @@ -4994,6 +5396,22 @@ "time.Duration": { "type": "integer", "enum": [ + -9223372036854775808, + 9223372036854775807, + 1, + 1000, + 1000000, + 1000000000, + 60000000000, + 3600000000000, + -9223372036854775808, + 9223372036854775807, + 1, + 1000, + 1000000, + 1000000000, + 60000000000, + 3600000000000, -9223372036854775808, 9223372036854775807, 1, @@ -5012,6 +5430,22 @@ 3600000000000 ], "x-enum-varnames": [ + "minDuration", + "maxDuration", + "Nanosecond", + "Microsecond", + "Millisecond", + "Second", + "Minute", + "Hour", + "minDuration", + "maxDuration", + "Nanosecond", + "Microsecond", + "Millisecond", + "Second", + "Minute", + "Hour", "minDuration", "maxDuration", "Nanosecond",