Skip to content

Commit

Permalink
chore: enrich S3Object with more metadata + dynamic params (#258)
Browse files Browse the repository at this point in the history
* chore: enrich S3Object

* fix: router params

* fix: router params

* fix: error checking

* feat: enrich snapshot.mosaic field

* chore: improve S3Object data structure
  • Loading branch information
bouassaba authored Aug 10, 2024
1 parent bb97963 commit 568d059
Show file tree
Hide file tree
Showing 13 changed files with 218 additions and 116 deletions.
48 changes: 26 additions & 22 deletions api/docs/index.html

Large diffs are not rendered by default.

62 changes: 47 additions & 15 deletions api/docs/swagger.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -80,30 +80,41 @@ definitions:
userMessage:
type: string
type: object
model.DocumentProps:
properties:
pages:
type: integer
type: object
model.ImageProps:
properties:
height:
type: integer
width:
type: integer
type: object
model.PDFProps:
model.PathProps:
properties:
pages:
type: integer
extension:
type: string
type: object
model.S3Object:
properties:
bucket:
type: string
document:
$ref: '#/definitions/model.DocumentProps'
image:
$ref: '#/definitions/model.ImageProps'
key:
type: string
pdf:
$ref: '#/definitions/model.PDFProps'
page:
$ref: '#/definitions/model.PathProps'
size:
type: integer
thumbnail:
$ref: '#/definitions/model.PathProps'
tile:
$ref: '#/definitions/model.PathProps'
type: object
router.FileGrantGroupPermissionOptions:
properties:
Expand Down Expand Up @@ -221,16 +232,27 @@ definitions:
required:
- storageCapacity
type: object
service.DocumentProps:
properties:
pages:
type: integer
type: object
service.Download:
properties:
document:
$ref: '#/definitions/service.DocumentProps'
extension:
type: string
image:
$ref: '#/definitions/service.ImageProps'
pdf:
$ref: '#/definitions/service.PDFProps'
page:
$ref: '#/definitions/service.PathProps'
size:
type: integer
thumbnail:
$ref: '#/definitions/service.PathProps'
tile:
$ref: '#/definitions/service.PathProps'
type: object
service.File:
properties:
Expand Down Expand Up @@ -547,10 +569,10 @@ definitions:
totalPages:
type: integer
type: object
service.PDFProps:
service.PathProps:
properties:
pages:
type: integer
extension:
type: string
type: object
service.Snapshot:
properties:
Expand Down Expand Up @@ -1236,7 +1258,7 @@ paths:
summary: Patch Name
tags:
- Files
/files/{id}/original{ext}:
/files/{id}/original.{ext}:
get:
description: Download Original
operationId: files_download_original
Expand Down Expand Up @@ -1359,7 +1381,7 @@ paths:
summary: Get Path
tags:
- Files
/files/{id}/preview{ext}:
/files/{id}/preview.{ext}:
get:
description: Download Preview
operationId: files_download_preview
Expand Down Expand Up @@ -1423,7 +1445,7 @@ paths:
summary: Revoke Group Permission
tags:
- Files
/files/{id}/segmentation/pages/{page}.png:
/files/{id}/segmentation/pages/{page}.{ext}:
get:
description: Download Segmentation Page
operationId: files_download_segmentation_page
Expand All @@ -1438,6 +1460,11 @@ paths:
name: page
required: true
type: string
- description: Extension
in: path
name: ext
required: true
type: string
- description: Access Token
in: query
name: access_token
Expand All @@ -1457,7 +1484,7 @@ paths:
summary: Download Segmentation Page
tags:
- Files
/files/{id}/segmentation/thumbnails/{page}.jpg:
/files/{id}/segmentation/thumbnails/{page}.{ext}:
get:
description: Download Segmentation Thumbnail
operationId: files_download_segmentation_thumbnail
Expand All @@ -1472,6 +1499,11 @@ paths:
name: page
required: true
type: string
- description: Extension
in: path
name: ext
required: true
type: string
- description: Access Token
in: query
name: access_token
Expand Down Expand Up @@ -1519,7 +1551,7 @@ paths:
summary: Get Size
tags:
- Files
/files/{id}/thumbnail{ext}:
/files/{id}/thumbnail.{ext}:
get:
description: Download Thumbnail
operationId: files_download_thumbnail
Expand Down
10 changes: 10 additions & 0 deletions api/errorpkg/error_creators.go
Original file line number Diff line number Diff line change
Expand Up @@ -322,6 +322,16 @@ func NewMissingQueryParamError(param string) *ErrorResponse {
)
}

func NewInvalidPathParamError(param string) *ErrorResponse {
return NewErrorResponse(
"invalid_path_param",
http.StatusBadRequest,
fmt.Sprintf("Path param '%s' is invalid.", param),
MsgInvalidRequest,
nil,
)
}

func NewInvalidQueryParamError(param string) *ErrorResponse {
return NewErrorResponse(
"invalid_query_param",
Expand Down
19 changes: 13 additions & 6 deletions api/model/snapshot_model.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,22 +57,29 @@ type Snapshot interface {
}

type S3Object struct {
Bucket string `json:"bucket"`
Key string `json:"key"`
Size *int64 `json:"size,omitempty"`
Image *ImageProps `json:"image,omitempty"`
PDF *PDFProps `json:"pdf,omitempty"`
Bucket string `json:"bucket"`
Key string `json:"key"`
Size *int64 `json:"size,omitempty"`
Image *ImageProps `json:"image,omitempty"`
Document *DocumentProps `json:"document,omitempty"`
Page *PathProps `json:"page,omitempty"`
Thumbnail *PathProps `json:"thumbnail,omitempty"`
Tile *PathProps `json:"tile,omitempty"`
}

type ImageProps struct {
Width int `json:"width"`
Height int `json:"height"`
}

type PDFProps struct {
type DocumentProps struct {
Pages int `json:"pages"`
}

type PathProps struct {
Extension string `json:"extension"`
}

type S3Reference struct {
Bucket string `json:"bucket"`
Key string `json:"key"`
Expand Down
42 changes: 25 additions & 17 deletions api/router/file_router.go
Original file line number Diff line number Diff line change
Expand Up @@ -85,11 +85,11 @@ func (r *FileRouter) AppendRoutes(g fiber.Router) {
}

func (r *FileRouter) AppendNonJWTRoutes(g fiber.Router) {
g.Get("/:id/original:ext", r.DownloadOriginal)
g.Get("/:id/preview:ext", r.DownloadPreview)
g.Get("/:id/thumbnail:ext", r.DownloadThumbnail)
g.Get("/:id/segmentation/pages/:page.pdf", r.DownloadSegmentationPage)
g.Get("/:id/segmentation/thumbnails/:page.jpg", r.DownloadSegmentationThumbnail)
g.Get("/:id/original.:ext", r.DownloadOriginal)
g.Get("/:id/preview.:ext", r.DownloadPreview)
g.Get("/:id/thumbnail.:ext", r.DownloadThumbnail)
g.Get("/:id/segmentation/pages/:page.:ext", r.DownloadSegmentationPage)
g.Get("/:id/segmentation/thumbnails/:page.:ext", r.DownloadSegmentationThumbnail)
g.Post("/create_from_s3", r.CreateFromS3)
g.Patch("/:id/patch_from_s3", r.PatchFromS3)
}
Expand Down Expand Up @@ -844,7 +844,7 @@ func (r *FileRouter) GetGroupPermissions(c *fiber.Ctx) error {
// @Param ext query string true "Extension"
// @Failure 404 {object} errorpkg.ErrorResponse
// @Failure 500 {object} errorpkg.ErrorResponse
// @Router /files/{id}/original{ext} [get]
// @Router /files/{id}/original.{ext} [get]
func (r *FileRouter) DownloadOriginal(c *fiber.Ctx) error {
accessToken := c.Cookies(r.accessTokenCookieName)
if accessToken == "" {
Expand Down Expand Up @@ -872,7 +872,7 @@ func (r *FileRouter) DownloadOriginal(c *fiber.Ctx) error {
if err != nil {
return err
}
if filepath.Ext(res.Snapshot.GetOriginal().Key) != ext {
if strings.TrimPrefix(filepath.Ext(res.Snapshot.GetOriginal().Key), ".") != ext {
return errorpkg.NewS3ObjectNotFoundError(nil)
}
b := res.Buffer.Bytes()
Expand All @@ -897,7 +897,7 @@ func (r *FileRouter) DownloadOriginal(c *fiber.Ctx) error {
// @Param access_token query string true "Access Token"
// @Failure 404 {object} errorpkg.ErrorResponse
// @Failure 500 {object} errorpkg.ErrorResponse
// @Router /files/{id}/preview{ext} [get]
// @Router /files/{id}/preview.{ext} [get]
func (r *FileRouter) DownloadPreview(c *fiber.Ctx) error {
accessToken := c.Cookies(r.accessTokenCookieName)
if accessToken == "" {
Expand Down Expand Up @@ -925,7 +925,7 @@ func (r *FileRouter) DownloadPreview(c *fiber.Ctx) error {
if err != nil {
return err
}
if filepath.Ext(res.Snapshot.GetPreview().Key) != ext {
if strings.TrimPrefix(filepath.Ext(res.Snapshot.GetPreview().Key), ".") != ext {
return errorpkg.NewS3ObjectNotFoundError(nil)
}
b := buf.Bytes()
Expand All @@ -950,7 +950,7 @@ func (r *FileRouter) DownloadPreview(c *fiber.Ctx) error {
// @Param access_token query string true "Access Token"
// @Failure 404 {object} errorpkg.ErrorResponse
// @Failure 500 {object} errorpkg.ErrorResponse
// @Router /files/{id}/thumbnail{ext} [get]
// @Router /files/{id}/thumbnail.{ext} [get]
func (r *FileRouter) DownloadThumbnail(c *fiber.Ctx) error {
accessToken := c.Cookies(r.accessTokenCookieName)
if accessToken == "" {
Expand All @@ -975,7 +975,7 @@ func (r *FileRouter) DownloadThumbnail(c *fiber.Ctx) error {
if err != nil {
return err
}
if filepath.Ext(snapshot.GetThumbnail().Key) != ext {
if strings.TrimPrefix(filepath.Ext(snapshot.GetThumbnail().Key), ".") != ext {
return errorpkg.NewS3ObjectNotFoundError(nil)
}
b := buf.Bytes()
Expand All @@ -993,10 +993,11 @@ func (r *FileRouter) DownloadThumbnail(c *fiber.Ctx) error {
// @Produce json
// @Param id path string true "ID"
// @Param page path string true "Page"
// @Param ext path string true "Extension"
// @Param access_token query string true "Access Token"
// @Failure 404 {object} errorpkg.ErrorResponse
// @Failure 500 {object} errorpkg.ErrorResponse
// @Router /files/{id}/segmentation/pages/{page}.png [get]
// @Router /files/{id}/segmentation/pages/{page}.{ext} [get]
func (r *FileRouter) DownloadSegmentationPage(c *fiber.Ctx) error {
accessToken := c.Cookies(r.accessTokenCookieName)
if accessToken == "" {
Expand All @@ -1015,12 +1016,15 @@ func (r *FileRouter) DownloadSegmentationPage(c *fiber.Ctx) error {
}
page, err := strconv.Atoi(c.Params("page"))
if err != nil {
return errorpkg.NewInvalidQueryParamError("page")
return errorpkg.NewInvalidPathParamError("page")
}
buf, file, err := r.fileSvc.DownloadSegmentationPageBuffer(id, page, userID)
buf, snapshot, file, err := r.fileSvc.DownloadSegmentationPageBuffer(id, page, userID)
if err != nil {
return err
}
if strings.TrimPrefix(snapshot.GetSegmentation().Page.Extension, ".") != c.Params("ext") {
return errorpkg.NewS3ObjectNotFoundError(nil)
}
b := buf.Bytes()
c.Set("Content-Type", infra.DetectMimeFromBytes(b))
c.Set("Content-Disposition", fmt.Sprintf("filename=\"%s\"", filepath.Base(file.GetName())))
Expand All @@ -1036,10 +1040,11 @@ func (r *FileRouter) DownloadSegmentationPage(c *fiber.Ctx) error {
// @Produce json
// @Param id path string true "ID"
// @Param page path string true "Page"
// @Param ext path string true "Extension"
// @Param access_token query string true "Access Token"
// @Failure 404 {object} errorpkg.ErrorResponse
// @Failure 500 {object} errorpkg.ErrorResponse
// @Router /files/{id}/segmentation/thumbnails/{page}.jpg [get]
// @Router /files/{id}/segmentation/thumbnails/{page}.{ext} [get]
func (r *FileRouter) DownloadSegmentationThumbnail(c *fiber.Ctx) error {
accessToken := c.Cookies(r.accessTokenCookieName)
if accessToken == "" {
Expand All @@ -1058,12 +1063,15 @@ func (r *FileRouter) DownloadSegmentationThumbnail(c *fiber.Ctx) error {
}
page, err := strconv.Atoi(c.Params("page"))
if err != nil {
return errorpkg.NewInvalidQueryParamError("page")
return errorpkg.NewInvalidPathParamError("page")
}
buf, file, err := r.fileSvc.DownloadSegmentationThumbnailBuffer(id, page, userID)
buf, snapshot, file, err := r.fileSvc.DownloadSegmentationThumbnailBuffer(id, page, userID)
if err != nil {
return err
}
if strings.TrimPrefix(snapshot.GetSegmentation().Thumbnail.Extension, ".") != c.Params("ext") {
return errorpkg.NewS3ObjectNotFoundError(nil)
}
b := buf.Bytes()
c.Set("Content-Type", infra.DetectMimeFromBytes(b))
c.Set("Content-Disposition", fmt.Sprintf("filename=\"%s\"", filepath.Base(file.GetName())))
Expand Down
9 changes: 5 additions & 4 deletions api/router/mosaic_router.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import (
"fmt"
"net/http"
"strconv"
"strings"

"github.com/gofiber/fiber/v2"
"github.com/golang-jwt/jwt/v5"
Expand Down Expand Up @@ -166,10 +167,7 @@ func (r *MosaicRouter) DownloadTile(c *fiber.Ctx) error {
}
}
ext := c.Params("ext")
if ext == "" {
return errorpkg.NewMissingQueryParamError("ext")
}
buf, err := r.mosaicSvc.DownloadTileBuffer(id, service.MosaicDownloadTileOptions{
buf, snapshot, err := r.mosaicSvc.DownloadTileBuffer(id, service.MosaicDownloadTileOptions{
ZoomLevel: int(zoomLevel),
Row: int(row),
Col: int(col),
Expand All @@ -178,6 +176,9 @@ func (r *MosaicRouter) DownloadTile(c *fiber.Ctx) error {
if err != nil {
return err
}
if strings.TrimPrefix(snapshot.GetMosaic().Tile.Extension, ".") != c.Params("ext") {
return errorpkg.NewS3ObjectNotFoundError(nil)
}
b := buf.Bytes()
c.Set("Content-Type", infra.DetectMimeFromBytes(b))
c.Set("Content-Disposition", fmt.Sprintf("filename=\"tile%s\"", ext))
Expand Down
Loading

0 comments on commit 568d059

Please sign in to comment.