928 lines
25 KiB
Go
928 lines
25 KiB
Go
package router
|
|
|
|
import (
|
|
"encoding/base64"
|
|
"encoding/json"
|
|
"errors"
|
|
"fmt"
|
|
"net/http"
|
|
"os"
|
|
"path/filepath"
|
|
"strconv"
|
|
"strings"
|
|
"voltaserve/config"
|
|
"voltaserve/errorpkg"
|
|
"voltaserve/helper"
|
|
"voltaserve/infra"
|
|
"voltaserve/model"
|
|
"voltaserve/service"
|
|
|
|
"github.com/go-playground/validator/v10"
|
|
"github.com/gofiber/fiber/v2"
|
|
"github.com/gofiber/fiber/v2/log"
|
|
"github.com/golang-jwt/jwt/v5"
|
|
)
|
|
|
|
type FileRouter struct {
|
|
fileSvc *service.FileService
|
|
workspaceSvc *service.WorkspaceService
|
|
config config.Config
|
|
}
|
|
|
|
func NewFileRouter() *FileRouter {
|
|
return &FileRouter{
|
|
fileSvc: service.NewFileService(),
|
|
workspaceSvc: service.NewWorkspaceService(),
|
|
config: config.GetConfig(),
|
|
}
|
|
}
|
|
|
|
func (r *FileRouter) AppendRoutes(g fiber.Router) {
|
|
g.Post("/", r.Upload)
|
|
g.Post("/create_folder", r.CreateFolder)
|
|
g.Get("/list", r.ListByPath)
|
|
g.Get("/get", r.GetByPath)
|
|
g.Post("/batch_delete", r.BatchDelete)
|
|
g.Post("/batch_get", r.BatchGet)
|
|
g.Get("/:id", r.GetByID)
|
|
g.Patch("/:id", r.Patch)
|
|
g.Delete("/:id", r.Delete)
|
|
g.Get("/:id/list", r.List)
|
|
g.Get("/:id/get_item_count", r.GetItemCount)
|
|
g.Get("/:id/get_path", r.GetPath)
|
|
g.Get("/:id/get_ids", r.GetIDs)
|
|
g.Post("/:id/move", r.Move)
|
|
g.Post("/:id/rename", r.Rename)
|
|
g.Post("/:id/copy", r.Copy)
|
|
g.Get("/:id/get_size", r.GetSize)
|
|
g.Post("/grant_user_permission", r.GrantUserPermission)
|
|
g.Post("/revoke_user_permission", r.RevokeUserPermission)
|
|
g.Post("/grant_group_permission", r.GrantGroupPermission)
|
|
g.Post("/revoke_group_permission", r.RevokeGroupPermission)
|
|
g.Get("/:id/get_user_permissions", r.GetUserPermissions)
|
|
g.Get("/:id/get_group_permissions", r.GetGroupPermissions)
|
|
}
|
|
|
|
// Upload godoc
|
|
//
|
|
// @Summary Upload
|
|
// @Description Upload
|
|
// @Tags Files
|
|
// @Id files_upload
|
|
// @Accept x-www-form-urlencoded
|
|
// @Produce json
|
|
// @Param workspace_id query string true "Workspace ID"
|
|
// @Param parent_id query string false "Parent ID"
|
|
// @Param name query string false "Name"
|
|
// @Success 200 {object} service.File
|
|
// @Failure 404 {object} errorpkg.ErrorResponse
|
|
// @Failure 400 {object} errorpkg.ErrorResponse
|
|
// @Failure 500 {object} errorpkg.ErrorResponse
|
|
// @Router /files [post]
|
|
func (r *FileRouter) Upload(c *fiber.Ctx) error {
|
|
userID := GetUserID(c)
|
|
workspaceID := c.Query("workspace_id")
|
|
if workspaceID == "" {
|
|
return errorpkg.NewMissingQueryParamError("workspace_id")
|
|
}
|
|
parentID := c.Query("parent_id")
|
|
if parentID == "" {
|
|
workspace, err := r.workspaceSvc.Find(workspaceID, userID)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
parentID = workspace.RootID
|
|
}
|
|
fh, err := c.FormFile("file")
|
|
if err != nil {
|
|
return err
|
|
}
|
|
ok, err := r.workspaceSvc.HasEnoughSpaceForByteSize(workspaceID, fh.Size)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if !ok {
|
|
return errorpkg.NewStorageLimitExceededError()
|
|
}
|
|
name := c.Query("name")
|
|
if name == "" {
|
|
name = fh.Filename
|
|
}
|
|
file, err := r.fileSvc.Create(service.FileCreateOptions{
|
|
Name: name,
|
|
Type: model.FileTypeFile,
|
|
ParentID: &parentID,
|
|
WorkspaceID: workspaceID,
|
|
}, userID)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
path := filepath.FromSlash(os.TempDir() + "/" + helper.NewID() + filepath.Ext(fh.Filename))
|
|
if err := c.SaveFile(fh, path); err != nil {
|
|
return err
|
|
}
|
|
defer func(name string) {
|
|
if err := os.Remove(name); err != nil {
|
|
log.Error(err)
|
|
}
|
|
}(path)
|
|
file, err = r.fileSvc.Store(file.ID, path, userID)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return c.Status(http.StatusCreated).JSON(file)
|
|
}
|
|
|
|
// Patch godoc
|
|
//
|
|
// @Summary Patch
|
|
// @Description Patch
|
|
// @Tags Files
|
|
// @Id files_patch
|
|
// @Accept x-www-form-urlencoded
|
|
// @Produce json
|
|
// @Param id path string true "ID"
|
|
// @Success 200 {object} service.File
|
|
// @Failure 404 {object} errorpkg.ErrorResponse
|
|
// @Failure 400 {object} errorpkg.ErrorResponse
|
|
// @Failure 500 {object} errorpkg.ErrorResponse
|
|
// @Router /files/{id} [patch]
|
|
func (r *FileRouter) Patch(c *fiber.Ctx) error {
|
|
userID := GetUserID(c)
|
|
files, err := r.fileSvc.FindByID([]string{c.Params("id")}, userID)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
file := files[0]
|
|
fh, err := c.FormFile("file")
|
|
if err != nil {
|
|
return err
|
|
}
|
|
ok, err := r.workspaceSvc.HasEnoughSpaceForByteSize(file.WorkspaceID, fh.Size)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if !ok {
|
|
return errorpkg.NewStorageLimitExceededError()
|
|
}
|
|
path := filepath.FromSlash(os.TempDir() + "/" + helper.NewID() + filepath.Ext(fh.Filename))
|
|
if err := c.SaveFile(fh, path); err != nil {
|
|
return err
|
|
}
|
|
defer func(name string) {
|
|
if err := os.Remove(name); err != nil {
|
|
log.Error(err)
|
|
}
|
|
}(path)
|
|
file, err = r.fileSvc.Store(file.ID, path, userID)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return c.JSON(file)
|
|
}
|
|
|
|
// CreateFolder godoc
|
|
//
|
|
// @Summary Create
|
|
// @Description Create
|
|
// @Tags Files
|
|
// @Id files_create_folder
|
|
// @Accept json
|
|
// @Produce json
|
|
// @Param body body service.FileCreateFolderOptions true "Body"
|
|
// @Success 200 {object} service.File
|
|
// @Failure 400 {object} errorpkg.ErrorResponse
|
|
// @Failure 500 {object} errorpkg.ErrorResponse
|
|
// @Router /files/create_folder [post]
|
|
func (r *FileRouter) CreateFolder(c *fiber.Ctx) error {
|
|
userID := GetUserID(c)
|
|
opts := new(service.FileCreateFolderOptions)
|
|
if err := c.BodyParser(opts); err != nil {
|
|
return err
|
|
}
|
|
if err := validator.New().Struct(opts); err != nil {
|
|
return errorpkg.NewRequestBodyValidationError(err)
|
|
}
|
|
parentID := opts.ParentID
|
|
if parentID == nil {
|
|
workspace, err := r.workspaceSvc.Find(opts.WorkspaceID, userID)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
parentID = &workspace.RootID
|
|
}
|
|
res, err := r.fileSvc.Create(service.FileCreateOptions{
|
|
Name: opts.Name,
|
|
Type: model.FileTypeFolder,
|
|
ParentID: parentID,
|
|
WorkspaceID: opts.WorkspaceID,
|
|
}, userID)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return c.Status(http.StatusCreated).JSON(res)
|
|
}
|
|
|
|
// GetByID godoc
|
|
//
|
|
// @Summary Get by ID
|
|
// @Description Get by ID
|
|
// @Tags Files
|
|
// @Id files_get_by_id
|
|
// @Produce json
|
|
// @Param id path string true "ID"
|
|
// @Success 200 {object} service.File
|
|
// @Failure 404 {object} errorpkg.ErrorResponse
|
|
// @Failure 500 {object} errorpkg.ErrorResponse
|
|
// @Router /files/{id} [get]
|
|
func (r *FileRouter) GetByID(c *fiber.Ctx) error {
|
|
userID := GetUserID(c)
|
|
res, err := r.fileSvc.FindByID([]string{c.Params("id")}, userID)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if len(res) == 0 {
|
|
return errorpkg.NewFileNotFoundError(nil)
|
|
}
|
|
return c.JSON(res[0])
|
|
}
|
|
|
|
// GetByPath godoc
|
|
//
|
|
// @Summary Get by Path
|
|
// @Description Get by Path
|
|
// @Tags Files
|
|
// @Id files_get_by_path
|
|
// @Produce json
|
|
// @Param id path string true "ID"
|
|
// @Success 200 {object} service.File
|
|
// @Failure 404 {object} errorpkg.ErrorResponse
|
|
// @Failure 500 {object} errorpkg.ErrorResponse
|
|
// @Router /files/get [get]
|
|
func (r *FileRouter) GetByPath(c *fiber.Ctx) error {
|
|
userID := GetUserID(c)
|
|
if c.Query("path") == "" {
|
|
return errorpkg.NewMissingQueryParamError("path")
|
|
}
|
|
res, err := r.fileSvc.FindByPath(c.Query("path"), userID)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return c.JSON(res)
|
|
}
|
|
|
|
// ListByPath godoc
|
|
//
|
|
// @Summary List by Path
|
|
// @Description List by Path
|
|
// @Tags Files
|
|
// @Id files_list_by_path
|
|
// @Produce json
|
|
// @Param path query string true "Path"
|
|
// @Success 200 {array} service.File
|
|
// @Failure 404 {object} errorpkg.ErrorResponse
|
|
// @Failure 500 {object} errorpkg.ErrorResponse
|
|
// @Router /files/list [get]
|
|
func (r *FileRouter) ListByPath(c *fiber.Ctx) error {
|
|
userID := GetUserID(c)
|
|
if c.Query("path") == "" {
|
|
return errorpkg.NewMissingQueryParamError("path")
|
|
}
|
|
res, err := r.fileSvc.ListByPath(c.Query("path"), userID)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return c.JSON(res)
|
|
}
|
|
|
|
// List godoc
|
|
//
|
|
// @Summary List
|
|
// @Description List
|
|
// @Tags Files
|
|
// @Id files_list
|
|
// @Produce json
|
|
// @Param id path string true "ID"
|
|
// @Param type query string false "Type"
|
|
// @Param page query string false "Page"
|
|
// @Param size query string false "Size"
|
|
// @Param sort_by query string false "Sort By"
|
|
// @Param sort_order query string false "Sort Order"
|
|
// @Param query query string false "Query"
|
|
// @Success 200 {object} service.FileList
|
|
// @Failure 404 {object} errorpkg.ErrorResponse
|
|
// @Failure 500 {object} errorpkg.ErrorResponse
|
|
// @Router /files/{id}/list [get]
|
|
func (r *FileRouter) List(c *fiber.Ctx) error {
|
|
var err error
|
|
var res *service.FileList
|
|
id := c.Params("id")
|
|
userID := GetUserID(c)
|
|
var page int64
|
|
if c.Query("page") == "" {
|
|
page = 1
|
|
} else {
|
|
page, err = strconv.ParseInt(c.Query("page"), 10, 32)
|
|
if err != nil {
|
|
page = 1
|
|
}
|
|
}
|
|
var size int64
|
|
if c.Query("size") == "" {
|
|
size = FileDefaultPageSize
|
|
} else {
|
|
size, err = strconv.ParseInt(c.Query("size"), 10, 32)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
sortBy := c.Query("sort_by")
|
|
if !IsValidSortBy(sortBy) {
|
|
return errorpkg.NewInvalidQueryParamError("sort_by")
|
|
}
|
|
sortOrder := c.Query("sort_order")
|
|
if !IsValidSortOrder(sortOrder) {
|
|
return errorpkg.NewInvalidQueryParamError("sort_order")
|
|
}
|
|
fileType := c.Query("type")
|
|
if fileType != model.FileTypeFile && fileType != model.FileTypeFolder && fileType != "" {
|
|
return errorpkg.NewInvalidQueryParamError("type")
|
|
}
|
|
query := c.Query("query")
|
|
opts := service.FileListOptions{
|
|
Page: uint(page),
|
|
Size: uint(size),
|
|
SortBy: sortBy,
|
|
SortOrder: sortOrder,
|
|
}
|
|
if query != "" {
|
|
bytes, err := base64.StdEncoding.DecodeString(query + strings.Repeat("=", (4-len(query)%4)%4))
|
|
if err != nil {
|
|
return errorpkg.NewInvalidQueryParamError("query")
|
|
}
|
|
if err := json.Unmarshal(bytes, &opts.Query); err != nil {
|
|
return errorpkg.NewInvalidQueryParamError("query")
|
|
}
|
|
res, err = r.fileSvc.Search(id, opts, userID)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
} else {
|
|
if fileType != "" {
|
|
opts.Query = &service.FileQuery{
|
|
Type: &fileType,
|
|
}
|
|
}
|
|
res, err = r.fileSvc.List(id, opts, userID)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
return c.JSON(res)
|
|
}
|
|
|
|
// GetIDs godoc
|
|
//
|
|
// @Summary Get IDs
|
|
// @Description Get IDs
|
|
// @Tags Files
|
|
// @Id files_get_ids
|
|
// @Produce json
|
|
// @Param id path string true "ID"
|
|
// @Success 200 {array} string
|
|
// @Failure 404 {object} errorpkg.ErrorResponse
|
|
// @Failure 500 {object} errorpkg.ErrorResponse
|
|
// @Router /files/{id}/get_ids [get]
|
|
func (r *FileRouter) GetIDs(c *fiber.Ctx) error {
|
|
userID := GetUserID(c)
|
|
res, err := r.fileSvc.GetIDs(c.Params("id"), userID)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return c.JSON(res)
|
|
}
|
|
|
|
// GetPath godoc
|
|
//
|
|
// @Summary Get path
|
|
// @Description Get path
|
|
// @Tags Files
|
|
// @Id files_get_path
|
|
// @Produce json
|
|
// @Param id path string true "ID"
|
|
// @Success 200 {array} service.File
|
|
// @Failure 404 {object} errorpkg.ErrorResponse
|
|
// @Failure 500 {object} errorpkg.ErrorResponse
|
|
// @Router /files/{id}/get_path [get]
|
|
func (r *FileRouter) GetPath(c *fiber.Ctx) error {
|
|
userID := GetUserID(c)
|
|
res, err := r.fileSvc.GetPath(c.Params("id"), userID)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return c.JSON(res)
|
|
}
|
|
|
|
// Copy godoc
|
|
//
|
|
// @Summary Copy
|
|
// @Description Copy
|
|
// @Tags Files
|
|
// @Id files_copy
|
|
// @Produce json
|
|
// @Param id path string true "ID"
|
|
// @Param body body service.FileCopyOptions true "Body"
|
|
// @Failure 404 {object} errorpkg.ErrorResponse
|
|
// @Failure 500 {object} errorpkg.ErrorResponse
|
|
// @Router /files/{id}/copy [post]
|
|
func (r *FileRouter) Copy(c *fiber.Ctx) error {
|
|
userID := GetUserID(c)
|
|
opts := new(service.FileCopyOptions)
|
|
if err := c.BodyParser(opts); err != nil {
|
|
return err
|
|
}
|
|
if err := validator.New().Struct(opts); err != nil {
|
|
return errorpkg.NewRequestBodyValidationError(err)
|
|
}
|
|
res, err := r.fileSvc.Copy(c.Params("id"), opts.IDs, userID)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return c.JSON(res)
|
|
}
|
|
|
|
// Move godoc
|
|
//
|
|
// @Summary Move
|
|
// @Description Move
|
|
// @Tags Files
|
|
// @Id files_move
|
|
// @Produce json
|
|
// @Param id path string true "ID"
|
|
// @Param body body service.FileMoveOptions true "Body"
|
|
// @Failure 404 {object} errorpkg.ErrorResponse
|
|
// @Failure 500 {object} errorpkg.ErrorResponse
|
|
// @Router /files/{id}/move [post]
|
|
func (r *FileRouter) Move(c *fiber.Ctx) error {
|
|
userID := GetUserID(c)
|
|
opts := new(service.FileMoveOptions)
|
|
if err := c.BodyParser(opts); err != nil {
|
|
return err
|
|
}
|
|
if err := validator.New().Struct(opts); err != nil {
|
|
return errorpkg.NewRequestBodyValidationError(err)
|
|
}
|
|
if _, err := r.fileSvc.Move(c.Params("id"), opts.IDs, userID); err != nil {
|
|
return err
|
|
}
|
|
return c.SendStatus(http.StatusNoContent)
|
|
}
|
|
|
|
// Rename godoc
|
|
//
|
|
// @Summary Rename
|
|
// @Description Rename
|
|
// @Tags Files
|
|
// @Id files_rename
|
|
// @Produce json
|
|
// @Param id path string true "ID"
|
|
// @Param body body service.FileRenameOptions true "Body"
|
|
// @Success 200 {object} service.File
|
|
// @Failure 404 {object} errorpkg.ErrorResponse
|
|
// @Failure 500 {object} errorpkg.ErrorResponse
|
|
// @Router /files/{id}/rename [post]
|
|
func (r *FileRouter) Rename(c *fiber.Ctx) error {
|
|
userID := GetUserID(c)
|
|
opts := new(service.FileRenameOptions)
|
|
if err := c.BodyParser(opts); err != nil {
|
|
return err
|
|
}
|
|
if err := validator.New().Struct(opts); err != nil {
|
|
return errorpkg.NewRequestBodyValidationError(err)
|
|
}
|
|
res, err := r.fileSvc.Rename(c.Params("id"), opts.Name, userID)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return c.JSON(res)
|
|
}
|
|
|
|
// Delete godoc
|
|
//
|
|
// @Summary Delete
|
|
// @Description Delete
|
|
// @Tags Files
|
|
// @Id files_delete
|
|
// @Produce json
|
|
// @Param id path string true "ID"
|
|
// @Failure 404 {object} errorpkg.ErrorResponse
|
|
// @Failure 500 {object} errorpkg.ErrorResponse
|
|
// @Router /files/{id} [delete]
|
|
func (r *FileRouter) Delete(c *fiber.Ctx) error {
|
|
userID := GetUserID(c)
|
|
_, err := r.fileSvc.Delete([]string{c.Params("id")}, userID)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return c.SendStatus(http.StatusNoContent)
|
|
}
|
|
|
|
// BatchGet godoc
|
|
//
|
|
// @Summary Batch get
|
|
// @Description Batch get
|
|
// @Tags Files
|
|
// @Id files_batch_get
|
|
// @Produce json
|
|
// @Param body body service.FileBatchGetOptions true "Body"
|
|
// @Success 200 {array} service.File
|
|
// @Failure 500 {object} errorpkg.ErrorResponse
|
|
// @Router /files/batch_get [post]
|
|
func (r *FileRouter) BatchGet(c *fiber.Ctx) error {
|
|
userID := GetUserID(c)
|
|
opts := new(service.FileBatchGetOptions)
|
|
if err := c.BodyParser(opts); err != nil {
|
|
return err
|
|
}
|
|
if err := validator.New().Struct(opts); err != nil {
|
|
return errorpkg.NewRequestBodyValidationError(err)
|
|
}
|
|
res, err := r.fileSvc.FindByID(opts.IDs, userID)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return c.JSON(res)
|
|
}
|
|
|
|
// BatchDelete godoc
|
|
//
|
|
// @Summary Batch delete
|
|
// @Description Batch delete
|
|
// @Tags Files
|
|
// @Id files_batch_delete
|
|
// @Produce json
|
|
// @Param body body service.FileBatchDeleteOptions true "Body"
|
|
// @Success 200 {array} string
|
|
// @Failure 500 {object} errorpkg.ErrorResponse
|
|
// @Router /files/batch_delete [post]
|
|
func (r *FileRouter) BatchDelete(c *fiber.Ctx) error {
|
|
userID := GetUserID(c)
|
|
opts := new(service.FileBatchDeleteOptions)
|
|
if err := c.BodyParser(opts); err != nil {
|
|
return err
|
|
}
|
|
if err := validator.New().Struct(opts); err != nil {
|
|
return errorpkg.NewRequestBodyValidationError(err)
|
|
}
|
|
res, err := r.fileSvc.Delete(opts.IDs, userID)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return c.JSON(res)
|
|
}
|
|
|
|
// GetSize godoc
|
|
//
|
|
// @Summary Get size
|
|
// @Description Get size
|
|
// @Tags Files
|
|
// @Id files_get_size
|
|
// @Produce json
|
|
// @Param id path string true "ID"
|
|
// @Success 200 {object} int
|
|
// @Failure 404 {object} errorpkg.ErrorResponse
|
|
// @Failure 500 {object} errorpkg.ErrorResponse
|
|
// @Router /files/{id}/get_size [get]
|
|
func (r *FileRouter) GetSize(c *fiber.Ctx) error {
|
|
userID := GetUserID(c)
|
|
id := c.Params("id")
|
|
res, err := r.fileSvc.GetSize(id, userID)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return c.JSON(res)
|
|
}
|
|
|
|
// GetItemCount godoc
|
|
//
|
|
// @Summary Get children count
|
|
// @Description Get children count
|
|
// @Tags Files
|
|
// @Id files_get_children_count
|
|
// @Produce json
|
|
// @Param id path string true "ID"
|
|
// @Success 200 {object} int
|
|
// @Failure 404 {object} errorpkg.ErrorResponse
|
|
// @Failure 500 {object} errorpkg.ErrorResponse
|
|
// @Router /files/{id}/get_item_count [get]
|
|
func (r *FileRouter) GetItemCount(c *fiber.Ctx) error {
|
|
userID := GetUserID(c)
|
|
res, err := r.fileSvc.GetItemCount(c.Params("id"), userID)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return c.JSON(res)
|
|
}
|
|
|
|
// GrantUserPermission godoc
|
|
//
|
|
// @Summary Grant user permission
|
|
// @Description Grant user permission
|
|
// @Tags Files
|
|
// @Id files_grant_user_permission
|
|
// @Produce json
|
|
// @Param id path string true "ID"
|
|
// @Param body body service.FileGrantUserPermissionOptions true "Body"
|
|
// @Failure 404 {object} errorpkg.ErrorResponse
|
|
// @Failure 500 {object} errorpkg.ErrorResponse
|
|
// @Router /files/grant_user_permission [post]
|
|
func (r *FileRouter) GrantUserPermission(c *fiber.Ctx) error {
|
|
userID := GetUserID(c)
|
|
opts := new(service.FileGrantUserPermissionOptions)
|
|
if err := c.BodyParser(opts); err != nil {
|
|
return err
|
|
}
|
|
if err := validator.New().Struct(opts); err != nil {
|
|
return errorpkg.NewRequestBodyValidationError(err)
|
|
}
|
|
if err := r.fileSvc.GrantUserPermission(opts.IDs, opts.UserID, opts.Permission, userID); err != nil {
|
|
return err
|
|
}
|
|
return c.SendStatus(http.StatusNoContent)
|
|
}
|
|
|
|
// RevokeUserPermission godoc
|
|
//
|
|
// @Summary Revoke user permission
|
|
// @Description Revoke user permission
|
|
// @Tags Files
|
|
// @Id files_revoke_user_permission
|
|
// @Produce json
|
|
// @Param id path string true "ID"
|
|
// @Param body body service.FileRevokeUserPermissionOptions true "Body"
|
|
// @Failure 404 {object} errorpkg.ErrorResponse
|
|
// @Failure 500 {object} errorpkg.ErrorResponse
|
|
// @Router /files/revoke_user_permission [post]
|
|
func (r *FileRouter) RevokeUserPermission(c *fiber.Ctx) error {
|
|
userID := GetUserID(c)
|
|
opts := new(service.FileRevokeUserPermissionOptions)
|
|
if err := c.BodyParser(opts); err != nil {
|
|
return err
|
|
}
|
|
if err := validator.New().Struct(opts); err != nil {
|
|
return errorpkg.NewRequestBodyValidationError(err)
|
|
}
|
|
if err := r.fileSvc.RevokeUserPermission(opts.IDs, opts.UserID, userID); err != nil {
|
|
return err
|
|
}
|
|
return c.SendStatus(http.StatusNoContent)
|
|
}
|
|
|
|
// GrantGroupPermission godoc
|
|
//
|
|
// @Summary Grant group permission
|
|
// @Description Grant group permission
|
|
// @Tags Files
|
|
// @Id files_grant_group_permission
|
|
// @Produce json
|
|
// @Param id path string true "ID"
|
|
// @Param body body service.FileGrantGroupPermissionOptions true "Body"
|
|
// @Failure 404 {object} errorpkg.ErrorResponse
|
|
// @Failure 500 {object} errorpkg.ErrorResponse
|
|
// @Router /files/grant_group_permission [post]
|
|
func (r *FileRouter) GrantGroupPermission(c *fiber.Ctx) error {
|
|
userID := GetUserID(c)
|
|
opts := new(service.FileGrantGroupPermissionOptions)
|
|
if err := c.BodyParser(opts); err != nil {
|
|
return err
|
|
}
|
|
if err := validator.New().Struct(opts); err != nil {
|
|
return errorpkg.NewRequestBodyValidationError(err)
|
|
}
|
|
if err := r.fileSvc.GrantGroupPermission(opts.IDs, opts.GroupID, opts.Permission, userID); err != nil {
|
|
return err
|
|
}
|
|
return c.SendStatus(http.StatusNoContent)
|
|
}
|
|
|
|
// RevokeGroupPermission godoc
|
|
//
|
|
// @Summary Revoke group permission
|
|
// @Description Revoke group permission
|
|
// @Tags Files
|
|
// @Id files_revoke_group_permission
|
|
// @Produce json
|
|
// @Param id path string true "ID"
|
|
// @Param body body service.FileRevokeGroupPermissionOptions true "Body"
|
|
// @Failure 404 {object} errorpkg.ErrorResponse
|
|
// @Failure 500 {object} errorpkg.ErrorResponse
|
|
// @Router /files/{id}/revoke_group_permission [post]
|
|
func (r *FileRouter) RevokeGroupPermission(c *fiber.Ctx) error {
|
|
userID := GetUserID(c)
|
|
opts := new(service.FileRevokeGroupPermissionOptions)
|
|
if err := c.BodyParser(opts); err != nil {
|
|
return err
|
|
}
|
|
if err := validator.New().Struct(opts); err != nil {
|
|
return errorpkg.NewRequestBodyValidationError(err)
|
|
}
|
|
if err := r.fileSvc.RevokeGroupPermission(opts.IDs, opts.GroupID, userID); err != nil {
|
|
return err
|
|
}
|
|
return c.SendStatus(http.StatusNoContent)
|
|
}
|
|
|
|
// GetUserPermissions godoc
|
|
//
|
|
// @Summary Get user permissions
|
|
// @Description Get user permissions
|
|
// @Tags Files
|
|
// @Id files_get_user_permissions
|
|
// @Produce json
|
|
// @Param id path string true "ID"
|
|
// @Success 200 {array} service.UserPermission
|
|
// @Failure 404 {object} errorpkg.ErrorResponse
|
|
// @Failure 500 {object} errorpkg.ErrorResponse
|
|
// @Router /files/{id}/get_user_permissions [get]
|
|
func (r *FileRouter) GetUserPermissions(c *fiber.Ctx) error {
|
|
userID := GetUserID(c)
|
|
res, err := r.fileSvc.GetUserPermissions(c.Params("id"), userID)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return c.JSON(res)
|
|
}
|
|
|
|
// GetGroupPermissions godoc
|
|
//
|
|
// @Summary Get group permissions
|
|
// @Description Get group permissions
|
|
// @Tags Files
|
|
// @Id files_get_group_permissions
|
|
// @Produce json
|
|
// @Param id path string true "ID"
|
|
// @Success 200 {array} service.GroupPermission
|
|
// @Failure 404 {object} errorpkg.ErrorResponse
|
|
// @Failure 500 {object} errorpkg.ErrorResponse
|
|
// @Router /files/{id}/get_group_permissions [get]
|
|
func (r *FileRouter) GetGroupPermissions(c *fiber.Ctx) error {
|
|
userID := GetUserID(c)
|
|
res, err := r.fileSvc.GetGroupPermissions(c.Params("id"), userID)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return c.JSON(res)
|
|
}
|
|
|
|
type FileDownloadRouter struct {
|
|
fileSvc *service.FileService
|
|
accessTokenCookieName string
|
|
}
|
|
|
|
func NewFileDownloadRouter() *FileDownloadRouter {
|
|
return &FileDownloadRouter{
|
|
fileSvc: service.NewFileService(),
|
|
accessTokenCookieName: "voltaserve_access_token",
|
|
}
|
|
}
|
|
|
|
func (r *FileDownloadRouter) AppendNonJWTRoutes(g fiber.Router) {
|
|
g.Get("/:id/original:ext", r.DownloadOriginal)
|
|
g.Get("/:id/preview:ext", r.DownloadPreview)
|
|
}
|
|
|
|
// DownloadOriginal godoc
|
|
//
|
|
// @Summary Download original
|
|
// @Description Download original
|
|
// @Tags Files
|
|
// @Id files_download_original
|
|
// @Produce json
|
|
// @Param id path string true "ID"
|
|
// @Param access_token query string true "Access Token"
|
|
// @Failure 404 {object} errorpkg.ErrorResponse
|
|
// @Failure 500 {object} errorpkg.ErrorResponse
|
|
// @Router /files/{id}/original{ext} [get]
|
|
func (r *FileDownloadRouter) DownloadOriginal(c *fiber.Ctx) error {
|
|
accessToken := c.Cookies(r.accessTokenCookieName)
|
|
if accessToken == "" {
|
|
accessToken = c.Query("access_token")
|
|
if accessToken == "" {
|
|
return errorpkg.NewFileNotFoundError(nil)
|
|
}
|
|
}
|
|
userID, err := r.getUserID(accessToken)
|
|
if err != nil {
|
|
return c.SendStatus(http.StatusNotFound)
|
|
}
|
|
buf, file, snapshot, err := r.fileSvc.DownloadOriginalBuffer(c.Params("id"), userID)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if filepath.Ext(snapshot.GetOriginal().Key) != c.Params("ext") {
|
|
return errorpkg.NewS3ObjectNotFoundError(nil)
|
|
}
|
|
bytes := buf.Bytes()
|
|
c.Set("Content-Type", infra.DetectMimeFromBytes(bytes))
|
|
c.Set("Content-Disposition", fmt.Sprintf("filename=\"%s\"", file.GetName()))
|
|
return c.Send(bytes)
|
|
}
|
|
|
|
// DownloadPreview godoc
|
|
//
|
|
// @Summary Download preview
|
|
// @Description Download preview
|
|
// @Tags Files
|
|
// @Id files_download_preview
|
|
// @Produce json
|
|
// @Param id path string true "ID"
|
|
// @Param access_token query string true "Access Token"
|
|
// @Failure 404 {object} errorpkg.ErrorResponse
|
|
// @Failure 500 {object} errorpkg.ErrorResponse
|
|
// @Router /files/{id}/preview{ext} [get]
|
|
func (r *FileDownloadRouter) DownloadPreview(c *fiber.Ctx) error {
|
|
accessToken := c.Cookies(r.accessTokenCookieName)
|
|
if accessToken == "" {
|
|
accessToken = c.Query("access_token")
|
|
if accessToken == "" {
|
|
return errorpkg.NewFileNotFoundError(nil)
|
|
}
|
|
}
|
|
userID, err := r.getUserID(accessToken)
|
|
if err != nil {
|
|
return c.SendStatus(http.StatusNotFound)
|
|
}
|
|
buf, file, snapshot, err := r.fileSvc.DownloadPreviewBuffer(c.Params("id"), userID)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if filepath.Ext(snapshot.GetPreview().Key) != c.Params("ext") {
|
|
return errorpkg.NewS3ObjectNotFoundError(nil)
|
|
}
|
|
bytes := buf.Bytes()
|
|
c.Set("Content-Type", infra.DetectMimeFromBytes(bytes))
|
|
c.Set("Content-Disposition", fmt.Sprintf("filename=\"%s\"", file.GetName()))
|
|
return c.Send(bytes)
|
|
}
|
|
|
|
func (r *FileDownloadRouter) getUserID(accessToken string) (string, error) {
|
|
token, err := jwt.Parse(accessToken, func(token *jwt.Token) (interface{}, error) {
|
|
if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
|
|
return nil, fmt.Errorf("unexpected signing method: %v", token.Header["alg"])
|
|
}
|
|
return []byte(config.GetConfig().Security.JWTSigningKey), nil
|
|
})
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
if claims, ok := token.Claims.(jwt.MapClaims); ok && token.Valid {
|
|
return claims["sub"].(string), nil
|
|
} else {
|
|
return "", errors.New("cannot find sub claim")
|
|
}
|
|
}
|
|
|
|
type ConversionWebhookRouter struct {
|
|
fileSvc *service.FileService
|
|
}
|
|
|
|
func NewConversionWebhookRouter() *ConversionWebhookRouter {
|
|
return &ConversionWebhookRouter{
|
|
fileSvc: service.NewFileService(),
|
|
}
|
|
}
|
|
|
|
func (r *ConversionWebhookRouter) AppendInternalRoutes(g fiber.Router) {
|
|
g.Post("/conversion_webhook/update_snapshot", r.UpdateSnapshot)
|
|
}
|
|
|
|
// UpdateSnapshot godoc
|
|
//
|
|
// @Summary Update snapshot
|
|
// @Description Update snapshot
|
|
// @Tags Files
|
|
// @Id files_conversion_webhook_update_snapshot
|
|
// @Produce json
|
|
// @Param body body service.SnapshotUpdateOptions true "Body"
|
|
// @Success 201
|
|
// @Failure 401 {object} errorpkg.ErrorResponse
|
|
// @Failure 500 {object} errorpkg.ErrorResponse
|
|
// @Router /files/conversion_webhook/update_snapshot [post]
|
|
func (r *ConversionWebhookRouter) UpdateSnapshot(c *fiber.Ctx) error {
|
|
apiKey := c.Query("api_key")
|
|
if apiKey == "" {
|
|
return errorpkg.NewMissingQueryParamError("api_key")
|
|
}
|
|
opts := new(service.SnapshotUpdateOptions)
|
|
if err := c.BodyParser(opts); err != nil {
|
|
return err
|
|
}
|
|
if err := validator.New().Struct(opts); err != nil {
|
|
return errorpkg.NewRequestBodyValidationError(err)
|
|
}
|
|
if err := r.fileSvc.UpdateSnapshot(*opts, apiKey); err != nil {
|
|
return err
|
|
}
|
|
return c.SendStatus(204)
|
|
}
|