ultisuite-backend/internal/api/drive/public_handlers.go
R3D347HR4Y d4ccf7eb6e
Some checks are pending
CI / Go tests (push) Waiting to run
CI / Integration tests (push) Waiting to run
CI / DB migrations (push) Waiting to run
hocuspocus lol 2
2026-06-09 14:30:34 +02:00

200 lines
6.0 KiB
Go

package drive
import (
"io"
"net/http"
"strconv"
"strings"
"github.com/go-chi/chi/v5"
"github.com/ultisuite/ulti-backend/internal/api/apiresponse"
"github.com/ultisuite/ulti-backend/internal/api/apivalidate"
)
func (h *Handler) PublicRoutes() chi.Router {
r := chi.NewRouter()
r.Get("/shares/{token}", h.GetPublicShare)
r.Get("/shares/{token}/preview", h.PreviewPublicShare)
r.Get("/shares/{token}/download/*", h.DownloadPublicShare)
r.Put("/shares/{token}/files/*", h.UploadPublicShare)
r.Post("/shares/{token}/folders/*", h.CreatePublicShareFolder)
r.Delete("/shares/{token}/files/*", h.DeletePublicShareItem)
r.Post("/shares/{token}/rename", h.RenamePublicShareItem)
if h.publicOffice != nil {
h.publicOffice.RegisterPublicShareRoutes(r)
}
if h.publicRichText != nil {
h.publicRichText.RegisterPublicShareRoutes(r)
}
return r
}
func publicSharePassword(r *http.Request) string {
return strings.TrimSpace(r.URL.Query().Get("password"))
}
func (h *Handler) GetPublicShare(w http.ResponseWriter, r *http.Request) {
token := strings.TrimSpace(chi.URLParam(r, "token"))
if token == "" {
apivalidate.WriteValidationError(w, r, apivalidate.NewValidationError(
apivalidate.FieldDetail{Field: "token", Message: "required"},
))
return
}
path := strings.TrimSpace(r.URL.Query().Get("path"))
if path == "" {
path = "/"
}
view, err := h.svc.GetPublicShare(r.Context(), token, path, publicSharePassword(r))
if err != nil {
writeDriveError(w, r, err)
return
}
apiresponse.WriteJSON(w, http.StatusOK, view)
}
func (h *Handler) DownloadPublicShare(w http.ResponseWriter, r *http.Request) {
token := strings.TrimSpace(chi.URLParam(r, "token"))
if token == "" {
apivalidate.WriteValidationError(w, r, apivalidate.NewValidationError(
apivalidate.FieldDetail{Field: "token", Message: "required"},
))
return
}
filePath := strings.TrimSpace(chi.URLParam(r, "*"))
if filePath == "" {
filePath = "/"
}
body, contentType, err := h.svc.DownloadPublicShare(r.Context(), token, filePath, publicSharePassword(r))
if err != nil {
writeDriveError(w, r, err)
return
}
defer body.Close()
w.Header().Set("Content-Type", contentType)
_, _ = io.Copy(w, body)
}
func (h *Handler) PreviewPublicShare(w http.ResponseWriter, r *http.Request) {
token := strings.TrimSpace(chi.URLParam(r, "token"))
if token == "" {
apivalidate.WriteValidationError(w, r, apivalidate.NewValidationError(
apivalidate.FieldDetail{Field: "token", Message: "required"},
))
return
}
filePath := strings.TrimSpace(r.URL.Query().Get("path"))
if filePath == "" {
apivalidate.WriteValidationError(w, r, apivalidate.NewValidationError(
apivalidate.FieldDetail{Field: "path", Message: "required"},
))
return
}
width, _ := strconv.Atoi(r.URL.Query().Get("w"))
height, _ := strconv.Atoi(r.URL.Query().Get("h"))
body, contentType, err := h.svc.PreviewPublicShare(r.Context(), token, filePath, publicSharePassword(r), width, height)
if err != nil {
writeDriveError(w, r, err)
return
}
defer body.Close()
if contentType != "" {
w.Header().Set("Content-Type", contentType)
}
_, _ = io.Copy(w, body)
}
func (h *Handler) UploadPublicShare(w http.ResponseWriter, r *http.Request) {
token := strings.TrimSpace(chi.URLParam(r, "token"))
filePath := strings.TrimSpace(chi.URLParam(r, "*"))
if token == "" || filePath == "" {
apivalidate.WriteValidationError(w, r, apivalidate.NewValidationError(
apivalidate.FieldDetail{Field: "path", Message: "required"},
))
return
}
if !strings.HasPrefix(filePath, "/") {
filePath = "/" + filePath
}
if err := h.svc.UploadPublicShare(r.Context(), token, filePath, publicSharePassword(r), r.Body, r.Header.Get("Content-Type")); err != nil {
writeDriveError(w, r, err)
return
}
w.WriteHeader(http.StatusCreated)
}
func (h *Handler) CreatePublicShareFolder(w http.ResponseWriter, r *http.Request) {
token := strings.TrimSpace(chi.URLParam(r, "token"))
folderPath := strings.TrimSpace(chi.URLParam(r, "*"))
if token == "" || folderPath == "" {
apivalidate.WriteValidationError(w, r, apivalidate.NewValidationError(
apivalidate.FieldDetail{Field: "path", Message: "required"},
))
return
}
if !strings.HasPrefix(folderPath, "/") {
folderPath = "/" + folderPath
}
if err := h.svc.CreatePublicShareFolder(r.Context(), token, folderPath, publicSharePassword(r)); err != nil {
writeDriveError(w, r, err)
return
}
w.WriteHeader(http.StatusCreated)
}
func (h *Handler) DeletePublicShareItem(w http.ResponseWriter, r *http.Request) {
token := strings.TrimSpace(chi.URLParam(r, "token"))
filePath := strings.TrimSpace(chi.URLParam(r, "*"))
if token == "" || filePath == "" {
apivalidate.WriteValidationError(w, r, apivalidate.NewValidationError(
apivalidate.FieldDetail{Field: "path", Message: "required"},
))
return
}
if !strings.HasPrefix(filePath, "/") {
filePath = "/" + filePath
}
if err := h.svc.DeletePublicShareItem(r.Context(), token, filePath, publicSharePassword(r)); err != nil {
writeDriveError(w, r, err)
return
}
w.WriteHeader(http.StatusNoContent)
}
type publicRenameRequest struct {
Path string `json:"path"`
NewName string `json:"new_name"`
}
func (h *Handler) RenamePublicShareItem(w http.ResponseWriter, r *http.Request) {
token := strings.TrimSpace(chi.URLParam(r, "token"))
if token == "" {
apivalidate.WriteValidationError(w, r, apivalidate.NewValidationError(
apivalidate.FieldDetail{Field: "token", Message: "required"},
))
return
}
var req publicRenameRequest
if err := apivalidate.DecodeJSON(w, r, 32<<10, &req); err != nil {
return
}
if strings.TrimSpace(req.Path) == "" || strings.TrimSpace(req.NewName) == "" {
apivalidate.WriteValidationError(w, r, apivalidate.NewValidationError(
apivalidate.FieldDetail{Field: "path", Message: "required"},
apivalidate.FieldDetail{Field: "new_name", Message: "required"},
))
return
}
if err := h.svc.RenamePublicShareItem(r.Context(), token, req.Path, req.NewName, publicSharePassword(r)); err != nil {
writeDriveError(w, r, err)
return
}
w.WriteHeader(http.StatusNoContent)
}