Merge remote-tracking branch 'origin/dev' into auth-uploads

This commit is contained in:
grngxd 2025-06-08 19:00:09 +01:00
commit 036d20561e
11 changed files with 596 additions and 581 deletions

View file

@ -1,41 +1,51 @@
package routes
import (
"net/http"
"time"
"github.com/gin-gonic/gin"
"stereo.cat/backend/internal/auth"
"stereo.cat/backend/internal/types"
)
func RegisterAuthRoutes(cfg *types.StereoConfig, api *gin.RouterGroup) {
api.GET("/auth/callback", func(c *gin.Context) {
code := c.Query("code")
t, err := cfg.Client.ExchangeCode(code)
if err != nil {
panic(err)
}
user, err := cfg.Client.GetUser(t)
if err != nil {
panic(err)
}
jwt, err := auth.GenerateJWT(cfg.JWTSecret, user, uint64(time.Now().Add(time.Second*time.Duration(t.ExpiresIn)).Unix()))
if err != nil {
panic(err)
}
c.String(http.StatusOK, jwt)
})
api.GET("/auth/me", auth.JwtMiddleware(cfg.JWTSecret), func(c *gin.Context) {
claims, _ := c.Get("claims")
c.JSON(http.StatusOK, claims)
})
}
package routes
import (
"net/http"
"time"
"github.com/gin-gonic/gin"
"stereo.cat/backend/internal/auth"
"stereo.cat/backend/internal/types"
)
func RegisterAuthRoutes(cfg *types.StereoConfig, api *gin.RouterGroup) {
api.GET("/auth/callback", func(c *gin.Context) {
code := c.Query("code")
t, err := cfg.Client.ExchangeCode(code)
if err != nil {
panic(err)
}
user, err := cfg.Client.GetUser(t)
if err != nil {
panic(err)
}
jwt, err := auth.GenerateJWT(cfg.JWTSecret, user, uint64(time.Now().Add(time.Second*time.Duration(t.ExpiresIn)).Unix()))
if err != nil {
panic(err)
}
res := cfg.Database.FirstOrCreate(&user)
if res.Error != nil {
panic(res.Error)
}
// TODO: redirect to dashboard
c.JSON(http.StatusOK, gin.H{
"jwt": jwt,
"known": res.RowsAffected == 0,
})
})
api.GET("/auth/me", auth.JwtMiddleware(cfg.JWTSecret), func(c *gin.Context) {
claims, _ := c.Get("claims")
c.JSON(http.StatusOK, claims)
})
}

View file

@ -1,144 +1,144 @@
package routes
import (
"os"
"path/filepath"
"strings"
"time"
"github.com/gin-gonic/gin"
"github.com/golang-jwt/jwt/v5"
"stereo.cat/backend/internal/auth"
"stereo.cat/backend/internal/types"
)
func RegisterFileRoutes(cfg *types.StereoConfig, api *gin.RouterGroup) {
api.POST("/upload", auth.JwtMiddleware(cfg.JWTSecret), func(c *gin.Context) {
claims := c.MustGet("claims").(jwt.MapClaims)
user := claims["user"].(auth.User)
uid := user.ID
if uid == "" {
c.JSON(401, gin.H{"error": "unauthorized"})
return
}
file, err := c.FormFile("file")
if err != nil {
c.JSON(400, gin.H{"error": "file is required"})
return
}
filePath := filepath.Join(cfg.ImagePath, uid, file.Filename)
if err := os.MkdirAll(filepath.Dir(filePath), os.ModePerm); err != nil {
c.JSON(500, gin.H{"error": "failed to create directory"})
return
}
if err := c.SaveUploadedFile(file, filePath); err != nil {
c.JSON(500, gin.H{"error": "failed to save file"})
return
}
if file.Size <= 0 {
c.JSON(400, gin.H{"error": "file size must be greater than zero"})
return
}
fileMeta := types.File{
ID: uid + "_" + file.Filename,
Path: filePath,
Owner: uid,
CreatedAt: time.Now(),
Size: file.Size,
}
if err := cfg.Database.Create(&fileMeta).Error; err != nil {
c.JSON(500, gin.H{"error": "failed to save file metadata"})
return
}
c.JSON(200, gin.H{"message": "file uploaded successfully", "file_id": fileMeta.ID})
})
api.DELETE("/delete", auth.JwtMiddleware(cfg.JWTSecret), func(c *gin.Context) {
claims := c.MustGet("claims").(jwt.MapClaims)
user := claims["user"].(auth.User)
uid := user.ID
if uid == "" {
c.JSON(401, gin.H{"error": "unauthorized"})
return
}
var response struct {
FileID string `json:"file_id" binding:"required"`
}
if err := c.ShouldBindJSON(&response); err != nil {
c.JSON(400, gin.H{"error": "file_id is required"})
return
}
resfID := response.FileID
if resfID == "" {
c.JSON(400, gin.H{"error": "file_id cannot be empty"})
return
}
parts := strings.SplitN(resfID, "_", 2)
if len(parts) != 2 {
c.JSON(400, gin.H{"error": "invalid file_id format"})
return
}
fileID, filename := parts[0], parts[1]
if fileID != uid {
c.JSON(403, gin.H{"error": "you can only delete your own files"})
return
}
filePath := filepath.Join(cfg.ImagePath, uid, filename)
if err := os.Remove(filePath); err != nil {
c.JSON(500, gin.H{"error": "failed to delete file"})
return
}
if err := cfg.Database.Where("id = ?", resfID).Delete(&types.File{}).Error; err != nil {
c.JSON(500, gin.H{"error": "failed to delete file metadata"})
return
}
c.JSON(200, gin.H{"message": "file deleted successfully"})
})
api.GET("/:name", func(c *gin.Context) {
name := c.Param("name")
parts := strings.SplitN(name, "_", 2)
if len(parts) != 2 {
c.JSON(400, gin.H{"error": "invalid file name"})
return
}
uid, filename := parts[0], parts[1]
path := filepath.Join(cfg.ImagePath, uid, filename)
if _, err := os.Stat(path); err != nil {
c.JSON(404, gin.H{"error": "file not found"})
return
}
c.File(path)
})
api.GET("/list", auth.JwtMiddleware(cfg.JWTSecret), func(c *gin.Context) {
claims := c.MustGet("claims").(jwt.MapClaims)
user := claims["user"].(auth.User)
var files []types.File
if err := cfg.Database.Where("owner = ?", user.ID).Find(&files).Error; err != nil {
c.JSON(500, gin.H{"error": "failed to retrieve files"})
return
}
c.JSON(200, files)
})
}
package routes
import (
"os"
"path/filepath"
"strings"
"time"
"github.com/gin-gonic/gin"
"github.com/golang-jwt/jwt/v5"
"stereo.cat/backend/internal/auth"
"stereo.cat/backend/internal/types"
)
func RegisterFileRoutes(cfg *types.StereoConfig, api *gin.RouterGroup) {
api.POST("/upload", auth.JwtMiddleware(cfg.JWTSecret), func(c *gin.Context) {
claims := c.MustGet("claims").(jwt.MapClaims)
user := claims["user"].(auth.User)
uid := user.ID
if uid == "" {
c.JSON(401, gin.H{"error": "unauthorized"})
return
}
file, err := c.FormFile("file")
if err != nil {
c.JSON(400, gin.H{"error": "file is required"})
return
}
filePath := filepath.Join(cfg.ImagePath, uid, file.Filename)
if err := os.MkdirAll(filepath.Dir(filePath), os.ModePerm); err != nil {
c.JSON(500, gin.H{"error": "failed to create directory"})
return
}
if err := c.SaveUploadedFile(file, filePath); err != nil {
c.JSON(500, gin.H{"error": "failed to save file"})
return
}
if file.Size <= 0 {
c.JSON(400, gin.H{"error": "file size must be greater than zero"})
return
}
fileMeta := types.File{
ID: uid + "_" + file.Filename,
Path: filePath,
Owner: uid,
CreatedAt: time.Now(),
Size: file.Size,
}
if err := cfg.Database.Create(&fileMeta).Error; err != nil {
c.JSON(500, gin.H{"error": "failed to save file metadata"})
return
}
c.JSON(200, gin.H{"message": "file uploaded successfully", "file_id": fileMeta.ID})
})
api.DELETE("/delete", auth.JwtMiddleware(cfg.JWTSecret), func(c *gin.Context) {
claims := c.MustGet("claims").(jwt.MapClaims)
user := claims["user"].(auth.User)
uid := user.ID
if uid == "" {
c.JSON(401, gin.H{"error": "unauthorized"})
return
}
var response struct {
FileID string `json:"file_id" binding:"required"`
}
if err := c.ShouldBindJSON(&response); err != nil {
c.JSON(400, gin.H{"error": "file_id is required"})
return
}
resfID := response.FileID
if resfID == "" {
c.JSON(400, gin.H{"error": "file_id cannot be empty"})
return
}
parts := strings.SplitN(resfID, "_", 2)
if len(parts) != 2 {
c.JSON(400, gin.H{"error": "invalid file_id format"})
return
}
fileID, filename := parts[0], parts[1]
if fileID != uid {
c.JSON(403, gin.H{"error": "you can only delete your own files"})
return
}
filePath := filepath.Join(cfg.ImagePath, uid, filename)
if err := os.Remove(filePath); err != nil {
c.JSON(500, gin.H{"error": "failed to delete file"})
return
}
if err := cfg.Database.Where("id = ?", resfID).Delete(&types.File{}).Error; err != nil {
c.JSON(500, gin.H{"error": "failed to delete file metadata"})
return
}
c.JSON(200, gin.H{"message": "file deleted successfully"})
})
api.GET("/:name", func(c *gin.Context) {
name := c.Param("name")
parts := strings.SplitN(name, "_", 2)
if len(parts) != 2 {
c.JSON(400, gin.H{"error": "invalid file name"})
return
}
uid, filename := parts[0], parts[1]
path := filepath.Join(cfg.ImagePath, uid, filename)
if _, err := os.Stat(path); err != nil {
c.JSON(404, gin.H{"error": "file not found"})
return
}
c.File(path)
})
api.GET("/list", auth.JwtMiddleware(cfg.JWTSecret), func(c *gin.Context) {
claims := c.MustGet("claims").(jwt.MapClaims)
user := claims["user"].(auth.User)
var files []types.File
if err := cfg.Database.Where("owner = ?", user.ID).Find(&files).Error; err != nil {
c.JSON(500, gin.H{"error": "failed to retrieve files"})
return
}
c.JSON(200, files)
})
}