223 lines
		
	
	
		
			6.4 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			223 lines
		
	
	
		
			6.4 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| package handlers
 | |
| 
 | |
| import (
 | |
| 	"context"
 | |
| 	"fmt"
 | |
| 	"net/http"
 | |
| 	"strconv"
 | |
| 	"strings"
 | |
| 
 | |
| 	"git.keircn.com/keiran/termcloud/internal/db"
 | |
| 	"github.com/labstack/echo/v4"
 | |
| )
 | |
| 
 | |
| type Handlers struct {
 | |
| 	bucketService *db.BucketService
 | |
| }
 | |
| 
 | |
| func NewHandlers(bucketService *db.BucketService) *Handlers {
 | |
| 	return &Handlers{bucketService: bucketService}
 | |
| }
 | |
| 
 | |
| func (h *Handlers) RootHandler(c echo.Context) error {
 | |
| 	return c.JSON(200, map[string]string{
 | |
| 		"status": "😺",
 | |
| 		"docs":   "https://illfillthisoutlater.com",
 | |
| 	})
 | |
| }
 | |
| 
 | |
| func (h *Handlers) AuthMiddleware(next echo.HandlerFunc) echo.HandlerFunc {
 | |
| 	return func(c echo.Context) error {
 | |
| 		apiKey := c.Request().Header.Get("X-API-Key")
 | |
| 		if apiKey == "" {
 | |
| 			return c.JSON(401, map[string]string{"error": "API key required"})
 | |
| 		}
 | |
| 
 | |
| 		user, err := h.bucketService.GetUserByAPIKey(context.Background(), apiKey)
 | |
| 		if err != nil {
 | |
| 			return c.JSON(401, map[string]string{"error": "Invalid API key"})
 | |
| 		}
 | |
| 
 | |
| 		c.Set("user", user)
 | |
| 		return next(c)
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func (h *Handlers) CreateBucketHandler(c echo.Context) error {
 | |
| 	user := c.Get("user").(*db.User)
 | |
| 
 | |
| 	var req struct {
 | |
| 		Name string `json:"name"`
 | |
| 	}
 | |
| 	if err := c.Bind(&req); err != nil {
 | |
| 		return c.JSON(400, map[string]string{"error": "Invalid request body"})
 | |
| 	}
 | |
| 
 | |
| 	if req.Name == "" {
 | |
| 		return c.JSON(400, map[string]string{"error": "Bucket name is required"})
 | |
| 	}
 | |
| 
 | |
| 	bucket, err := h.bucketService.CreateBucket(context.Background(), req.Name, user.ID)
 | |
| 	if err != nil {
 | |
| 		if strings.Contains(err.Error(), "duplicate key") {
 | |
| 			return c.JSON(409, map[string]string{"error": "Bucket name already exists"})
 | |
| 		}
 | |
| 		return c.JSON(500, map[string]string{"error": "Failed to create bucket"})
 | |
| 	}
 | |
| 
 | |
| 	return c.JSON(201, bucket)
 | |
| }
 | |
| 
 | |
| func (h *Handlers) ListBucketsHandler(c echo.Context) error {
 | |
| 	user := c.Get("user").(*db.User)
 | |
| 
 | |
| 	buckets, err := h.bucketService.GetUserBuckets(context.Background(), user.ID)
 | |
| 	if err != nil {
 | |
| 		return c.JSON(500, map[string]string{"error": "Failed to list buckets"})
 | |
| 	}
 | |
| 
 | |
| 	return c.JSON(200, map[string]any{
 | |
| 		"buckets": buckets,
 | |
| 	})
 | |
| }
 | |
| 
 | |
| func (h *Handlers) DeleteBucketHandler(c echo.Context) error {
 | |
| 	user := c.Get("user").(*db.User)
 | |
| 	bucketName := c.Param("bucket")
 | |
| 
 | |
| 	if err := h.bucketService.DeleteBucket(context.Background(), bucketName, user.ID); err != nil {
 | |
| 		if strings.Contains(err.Error(), "no rows") {
 | |
| 			return c.JSON(404, map[string]string{"error": "Bucket not found"})
 | |
| 		}
 | |
| 		return c.JSON(500, map[string]string{"error": "Failed to delete bucket"})
 | |
| 	}
 | |
| 
 | |
| 	return c.JSON(200, map[string]string{"message": "Bucket deleted successfully"})
 | |
| }
 | |
| 
 | |
| func (h *Handlers) UploadObjectHandler(c echo.Context) error {
 | |
| 	user := c.Get("user").(*db.User)
 | |
| 	bucketName := c.Param("bucket")
 | |
| 	objectKey := c.Param("*")
 | |
| 
 | |
| 	bucket, err := h.bucketService.GetBucket(context.Background(), bucketName, user.ID)
 | |
| 	if err != nil {
 | |
| 		if strings.Contains(err.Error(), "no rows") {
 | |
| 			return c.JSON(404, map[string]string{"error": "Bucket not found"})
 | |
| 		}
 | |
| 		return c.JSON(500, map[string]string{"error": "Failed to get bucket"})
 | |
| 	}
 | |
| 
 | |
| 	file, err := c.FormFile("file")
 | |
| 	if err != nil {
 | |
| 		return c.JSON(400, map[string]string{"error": "Failed to retrieve file"})
 | |
| 	}
 | |
| 
 | |
| 	src, err := file.Open()
 | |
| 	if err != nil {
 | |
| 		return c.JSON(500, map[string]string{"error": "Failed to open file"})
 | |
| 	}
 | |
| 	defer src.Close()
 | |
| 
 | |
| 	contentType := file.Header.Get("Content-Type")
 | |
| 	if contentType == "" {
 | |
| 		contentType = "application/octet-stream"
 | |
| 	}
 | |
| 
 | |
| 	object, err := h.bucketService.UploadObject(context.Background(), bucket.ID, objectKey, file.Size, contentType, src)
 | |
| 	if err != nil {
 | |
| 		if strings.Contains(err.Error(), "storage limit exceeded") {
 | |
| 			return c.JSON(413, map[string]string{"error": "Storage limit exceeded"})
 | |
| 		}
 | |
| 		return c.JSON(500, map[string]string{"error": "Failed to upload object"})
 | |
| 	}
 | |
| 
 | |
| 	return c.JSON(201, object)
 | |
| }
 | |
| 
 | |
| func (h *Handlers) ListObjectsHandler(c echo.Context) error {
 | |
| 	user := c.Get("user").(*db.User)
 | |
| 	bucketName := c.Param("bucket")
 | |
| 
 | |
| 	bucket, err := h.bucketService.GetBucket(context.Background(), bucketName, user.ID)
 | |
| 	if err != nil {
 | |
| 		if strings.Contains(err.Error(), "no rows") {
 | |
| 			return c.JSON(404, map[string]string{"error": "Bucket not found"})
 | |
| 		}
 | |
| 		return c.JSON(500, map[string]string{"error": "Failed to get bucket"})
 | |
| 	}
 | |
| 
 | |
| 	objects, err := h.bucketService.ListObjects(context.Background(), bucket.ID)
 | |
| 	if err != nil {
 | |
| 		return c.JSON(500, map[string]string{"error": "Failed to list objects"})
 | |
| 	}
 | |
| 
 | |
| 	return c.JSON(200, map[string]any{
 | |
| 		"objects": objects,
 | |
| 	})
 | |
| }
 | |
| 
 | |
| func (h *Handlers) GetObjectHandler(c echo.Context) error {
 | |
| 	user := c.Get("user").(*db.User)
 | |
| 	bucketName := c.Param("bucket")
 | |
| 	objectKey := c.Param("*")
 | |
| 
 | |
| 	file, err := h.bucketService.GetObjectFile(context.Background(), bucketName, objectKey, user.ID)
 | |
| 	if err != nil {
 | |
| 		if strings.Contains(err.Error(), "no rows") {
 | |
| 			return c.JSON(404, map[string]string{"error": "Object not found"})
 | |
| 		}
 | |
| 		return c.JSON(500, map[string]string{"error": "Failed to get object"})
 | |
| 	}
 | |
| 	defer file.Close()
 | |
| 
 | |
| 	stat, err := file.Stat()
 | |
| 	if err != nil {
 | |
| 		return c.JSON(500, map[string]string{"error": "Failed to get file info"})
 | |
| 	}
 | |
| 
 | |
| 	c.Response().Header().Set("Content-Length", strconv.FormatInt(stat.Size(), 10))
 | |
| 	c.Response().Header().Set("Content-Disposition", fmt.Sprintf("attachment; filename=\"%s\"", objectKey))
 | |
| 
 | |
| 	return c.Stream(http.StatusOK, "application/octet-stream", file)
 | |
| }
 | |
| func (h *Handlers) DeleteObjectHandler(c echo.Context) error {
 | |
| 	user := c.Get("user").(*db.User)
 | |
| 	bucketName := c.Param("bucket")
 | |
| 	objectKey := c.Param("*")
 | |
| 
 | |
| 	bucket, err := h.bucketService.GetBucket(context.Background(), bucketName, user.ID)
 | |
| 	if err != nil {
 | |
| 		if strings.Contains(err.Error(), "no rows") {
 | |
| 			return c.JSON(404, map[string]string{"error": "Bucket not found"})
 | |
| 		}
 | |
| 		return c.JSON(500, map[string]string{"error": "Failed to get bucket"})
 | |
| 	}
 | |
| 
 | |
| 	if err := h.bucketService.DeleteObject(context.Background(), bucket.ID, objectKey); err != nil {
 | |
| 		return c.JSON(500, map[string]string{"error": "Failed to delete object"})
 | |
| 	}
 | |
| 
 | |
| 	return c.JSON(200, map[string]string{"message": "Object deleted successfully"})
 | |
| }
 | |
| 
 | |
| func (h *Handlers) GetUserInfoHandler(c echo.Context) error {
 | |
| 	user := c.Get("user").(*db.User)
 | |
| 
 | |
| 	buckets, err := h.bucketService.GetUserBuckets(context.Background(), user.ID)
 | |
| 	if err != nil {
 | |
| 		return c.JSON(500, map[string]string{"error": "Failed to get user buckets"})
 | |
| 	}
 | |
| 
 | |
| 	var totalUsage int64
 | |
| 	for _, bucket := range buckets {
 | |
| 		totalUsage += bucket.StorageUsedBytes
 | |
| 	}
 | |
| 
 | |
| 	return c.JSON(200, map[string]any{
 | |
| 		"user":        user,
 | |
| 		"totalUsage":  totalUsage,
 | |
| 		"bucketCount": len(buckets),
 | |
| 	})
 | |
| }
 | 
