diff --git a/controllers/authController.go b/controllers/authController.go index 4c39476..568d0ef 100644 --- a/controllers/authController.go +++ b/controllers/authController.go @@ -16,9 +16,10 @@ import ( func Signup(c *gin.Context) { var body struct { - Username string - Email string - Password string + Username string + DisplayName string + Email string + Password string } if err := c.Bind(&body); err != nil { @@ -37,9 +38,10 @@ func Signup(c *gin.Context) { } user := models.User{ - Username: body.Username, - Email: body.Email, - Password: string(hashedPassword), + Username: body.Username, + DisplayName: body.DisplayName, + Email: body.Email, + Password: string(hashedPassword), } result := initializers.DB.Create(&user) diff --git a/controllers/fileController.go b/controllers/fileController.go deleted file mode 100644 index 81d968b..0000000 --- a/controllers/fileController.go +++ /dev/null @@ -1,36 +0,0 @@ -package controllers - -import ( - "azote-backend/initializers" - "azote-backend/models" - "github.com/gin-gonic/gin" - "github.com/google/uuid" - "net/http" - "strings" -) - -func UploadFile(c *gin.Context) { - file, _ := c.FormFile("file") - splitName := strings.Split(file.Filename, ".") - path := "assets/images/" + uuid.New().String() + "." + splitName[len(splitName)-1] - if err := c.SaveUploadedFile(file, path); err != nil { - c.JSON(http.StatusInternalServerError, gin.H{"error": "Unknown error"}) - return - } - - f := models.File{ - FileName: path, - } - - result := initializers.DB.Create(&f) - if result.Error != nil { - c.JSON(http.StatusInternalServerError, gin.H{ - "error": "An internal server error occurred", - }) - return - } - - c.JSON(http.StatusAccepted, gin.H{ - "recipeId": "feur", - }) -} diff --git a/controllers/postController.go b/controllers/postController.go new file mode 100644 index 0000000..c9b2a88 --- /dev/null +++ b/controllers/postController.go @@ -0,0 +1,118 @@ +package controllers + +import ( + "azote-backend/initializers" + "azote-backend/models" + "errors" + "github.com/gin-gonic/gin" + "github.com/google/uuid" + "github.com/h2non/filetype" + "mime/multipart" + "net/http" + "os" + "path/filepath" + "strings" +) + +func CreatePost(c *gin.Context) { + form, _ := c.MultipartForm() + uploadedFiles := form.File["files"] + var body struct { + Text string + } + + if err := c.Bind(&body); err != nil { + c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid request format"}) + return + } + + if len(uploadedFiles) == 0 { + c.JSON(http.StatusBadRequest, gin.H{ + "error": "No files were uploaded.", + }) + return + } + + files, err := uploadFiles(c, uploadedFiles) + if err != nil { + c.JSON(http.StatusInternalServerError, gin.H{ + "error": err.Error(), + }) + return + } + + currentUserId := c.GetString("userId") + id, _ := uuid.Parse(currentUserId) + post := models.Post{ + Text: body.Text, + Files: files, + Author: id, + } + + result := initializers.DB.Create(&post) + if result.Error != nil { + + for _, f := range files { + filePath := filepath.Join("assets", f.FileName) + if os.Remove(filePath) != nil { + c.JSON(http.StatusInternalServerError, gin.H{ + "error": "Internal server error", + }) + } + + if initializers.DB.Delete(&f).Error != nil { + c.JSON(http.StatusInternalServerError, gin.H{ + "error": "Internal server error", + }) + } + } + + c.JSON(http.StatusInternalServerError, gin.H{ + "error": "Unknown DB error", + }) + return + } + + c.JSON(http.StatusAccepted, gin.H{ + "post": post, + }) + +} + +func uploadFiles(c *gin.Context, uploadedFiles []*multipart.FileHeader) ([]models.File, error) { + var files []models.File + + for _, file := range uploadedFiles { + + osFile, _ := file.Open() + buffer := make([]byte, 261) + _, err := osFile.Read(buffer) + if err != nil { + return nil, err + } + + if !filetype.IsImage(buffer) && !filetype.IsAudio(buffer) && !filetype.IsVideo(buffer) { + return nil, errors.New("file is not an image, audio or video") + } + + splitName := strings.Split(file.Filename, ".") + newName := uuid.New().String() + "." + splitName[len(splitName)-1] + path := "assets/" + newName + + if err := c.SaveUploadedFile(file, path); err != nil { + return nil, err + } + + mFile := models.File{ + FileName: newName, + } + result := initializers.DB.Create(&mFile) + if result.Error != nil { + return nil, errors.New("database error") + } + + files = append(files, mFile) + } + + return files, nil +} diff --git a/go.mod b/go.mod index c256c31..5b97081 100644 --- a/go.mod +++ b/go.mod @@ -16,6 +16,7 @@ require ( github.com/goccy/go-json v0.10.2 // indirect github.com/golang-jwt/jwt v3.2.2+incompatible // indirect github.com/google/uuid v1.5.0 // indirect + github.com/h2non/filetype v1.1.3 // indirect github.com/jinzhu/inflection v1.0.0 // indirect github.com/jinzhu/now v1.1.5 // indirect github.com/joho/godotenv v1.5.1 // indirect diff --git a/go.sum b/go.sum index 129c3c8..6f28e06 100644 --- a/go.sum +++ b/go.sum @@ -33,6 +33,8 @@ github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzq github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/uuid v1.5.0 h1:1p67kYwdtXjb0gL0BPiP1Av9wiZPo5A8z2cWkTZ+eyU= github.com/google/uuid v1.5.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/h2non/filetype v1.1.3 h1:FKkx9QbD7HR/zjK1Ia5XiBsq9zdLi5Kf3zGyFTAFkGg= +github.com/h2non/filetype v1.1.3/go.mod h1:319b3zT68BvV+WRj7cwy856M2ehB3HqNOt6sy1HndBY= github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E= github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ= diff --git a/main.go b/main.go index 8c28a2e..d04bfd3 100644 --- a/main.go +++ b/main.go @@ -4,6 +4,7 @@ import ( "azote-backend/api" "azote-backend/controllers" "azote-backend/initializers" + "azote-backend/middleware" "github.com/gin-gonic/gin" "log" "os" @@ -31,7 +32,8 @@ func main() { // Files api.Router.Static("assets", "./assets/images") - // Posts + // Posts (middleware to add) + api.Api.POST("/posts", middleware.RequireAuth, controllers.CreatePost) // Starting err := api.Router.Run() diff --git a/middleware/requireAuth.go b/middleware/requireAuth.go index 8174673..c706cc5 100644 --- a/middleware/requireAuth.go +++ b/middleware/requireAuth.go @@ -1,11 +1,8 @@ package middleware import ( - "azote-backend/initializers" - "azote-backend/models" "azote-backend/tokens" "github.com/gin-gonic/gin" - "github.com/google/uuid" "net/http" "time" ) @@ -23,13 +20,6 @@ func RequireAuth(c *gin.Context) { return } - var user models.User - initializers.DB.First(&user, "id = ?", session.Bearer) - if user.ID == uuid.Nil { - c.AbortWithStatus(http.StatusUnauthorized) - return - } - - c.Set("user", user) + c.Set("userId", session.Bearer.String()) c.Next() } diff --git a/models/userModel.go b/models/userModel.go index affc965..00f3619 100644 --- a/models/userModel.go +++ b/models/userModel.go @@ -7,14 +7,15 @@ import ( ) type User struct { - ID uuid.UUID `gorm:"type:char(36);primary_key;"` - CreatedAt time.Time - UpdatedAt time.Time - Avatar File `gorm:"foreignKey:UserID;"` - Username string `gorm:"unique"` - Email string `gorm:"unique"` - Password string `json:"-"` - Posts []Post `gorm:"foreignKey:Author;constraint:OnUpdate:CASCADE,OnDelete:SET NULL;"` + ID uuid.UUID `gorm:"type:char(36);primary_key;"` + CreatedAt time.Time + UpdatedAt time.Time + Avatar File `gorm:"foreignKey:UserID;"` + Username string `gorm:"unique"` + DisplayName string + Email string `gorm:"unique"` + Password string `json:"-"` + Posts []Post `gorm:"foreignKey:Author;constraint:OnUpdate:CASCADE,OnDelete:SET NULL;"` } func (user *User) BeforeCreate(tx *gorm.DB) (err error) { diff --git a/tokens/tokenParser.go b/tokens/tokenParser.go index 2b664f1..b8889a7 100644 --- a/tokens/tokenParser.go +++ b/tokens/tokenParser.go @@ -19,12 +19,12 @@ type UserSession struct { } func ParseToken(c *gin.Context) (UserSession, error) { - tokenString, err := c.Cookie("Authorization") - if len(tokenString) == 0 || err != nil { - return UserSession{}, errors.New("cookie not found") + tokenString := c.GetHeader("Authorization") + if len(tokenString) == 0 { + return UserSession{}, errors.New("header not found") } - token, err := jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) { + token, _ := jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) { if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok { return nil, fmt.Errorf("unexpected signing method: %v", token.Header["alg"]) }