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]interface{}{ "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]interface{}{ "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]interface{}{ "user": user, "totalUsage": totalUsage, "bucketCount": len(buckets), }) }