diff --git a/backend/handlers/handle_activity.go b/backend/handlers/handle_activity.go deleted file mode 100644 index dd0a742..0000000 --- a/backend/handlers/handle_activity.go +++ /dev/null @@ -1,43 +0,0 @@ -package handlers - -import ( - "log" - "net/http" - - "adam-french.co.uk/backend/models" - "github.com/gin-gonic/gin" -) - -type CreateActivityInput struct { - Type string `json:"type" binding:"required"` - Name string `json:"name" binding:"required"` - Link *string `json:"link"` -} - -func (store *Store) GetActivity(ctx *gin.Context) { - var activitys []models.Activity - if err := store.DB.Order("Created_At DESC").Find(&activitys).Error; err != nil { - log.Println(err) - ctx.JSON(http.StatusInternalServerError, gin.H{"error": "internal error"}) - return - } - ctx.JSON(http.StatusOK, activitys) -} - -func (store *Store) CreateActivity(ctx *gin.Context) { - var input CreateActivityInput - if err := ctx.ShouldBindBodyWithJSON(&input); err != nil { - ctx.JSON(http.StatusBadRequest, gin.H{"error": "invalid request body"}) - return - } - - activity := models.Activity{Type: input.Type, Name: input.Name, Link: input.Link} - tx := store.DB.Create(&activity) - if tx.Error != nil { - log.Println(tx.Error) - ctx.JSON(http.StatusInternalServerError, gin.H{"error": "internal error"}) - return - } - - ctx.JSON(http.StatusCreated, activity) -} diff --git a/backend/handlers/handle_auth.go b/backend/handlers/handle_auth.go index 806272c..7b140d4 100644 --- a/backend/handlers/handle_auth.go +++ b/backend/handlers/handle_auth.go @@ -10,6 +10,11 @@ import ( "golang.org/x/crypto/bcrypt" ) +type UserCredentials struct { + Username string `json:"username" binding:"required"` + Password string `json:"password" binding:"required"` +} + func (store *Store) AuthMiddlewear(ctx *gin.Context) { access_token, err := ctx.Cookie("access_token") if err != nil { diff --git a/backend/handlers/handle_favorites.go b/backend/handlers/handle_favorites.go deleted file mode 100644 index c4b77ab..0000000 --- a/backend/handlers/handle_favorites.go +++ /dev/null @@ -1,43 +0,0 @@ -package handlers - -import ( - "log" - "net/http" - - "adam-french.co.uk/backend/models" - "github.com/gin-gonic/gin" -) - -type CreateFavoriteInput struct { - Type string `json:"type" binding:"required"` - Name string `json:"name" binding:"required"` - Link *string `json:"link"` -} - -func (store *Store) GetFavorites(ctx *gin.Context) { - var favorites []models.Favorite - if err := store.DB.Order("Created_At DESC").Find(&favorites).Error; err != nil { - log.Println(err) - ctx.JSON(http.StatusInternalServerError, gin.H{"error": "internal error"}) - return - } - ctx.JSON(http.StatusOK, favorites) -} - -func (store *Store) CreateFavorite(ctx *gin.Context) { - var input CreateFavoriteInput - if err := ctx.ShouldBindBodyWithJSON(&input); err != nil { - ctx.JSON(http.StatusBadRequest, gin.H{"error": "invalid request body"}) - return - } - - favorite := models.Favorite{Type: input.Type, Name: input.Name, Link: input.Link} - tx := store.DB.Create(&favorite) - if tx.Error != nil { - log.Println(tx.Error) - ctx.JSON(http.StatusInternalServerError, gin.H{"error": "internal error"}) - return - } - - ctx.JSON(http.StatusCreated, favorite) -} diff --git a/backend/handlers/handle_post.go b/backend/handlers/handle_post.go deleted file mode 100644 index e6489d3..0000000 --- a/backend/handlers/handle_post.go +++ /dev/null @@ -1,171 +0,0 @@ -package handlers - -import ( - "log" - "net/http" - "strconv" - - "adam-french.co.uk/backend/models" - "github.com/gin-gonic/gin" - "github.com/golang-jwt/jwt/v5" -) - -type CreatePostInput struct { - Title string `json:"title" binding:"required"` - Content string `json:"content" binding:"required"` -} - -func (store *Store) GetPosts(ctx *gin.Context) { - var posts []models.Post - if err := store.DB.Preload("Author").Order("Created_At DESC").Find(&posts).Error; err != nil { - log.Println(err) - ctx.JSON(http.StatusInternalServerError, gin.H{"error": "internal error"}) - return - } - ctx.JSON(http.StatusOK, posts) -} - -func (store *Store) GetPost(ctx *gin.Context) { - postIDStr := ctx.Param("id") - - postID, err := strconv.ParseUint(postIDStr, 10, 64) - if err != nil { - ctx.JSON(http.StatusBadRequest, "invalid id") - return - } - - post := models.Post{ID: uint(postID)} - if err := store.DB.First(&post).Error; err != nil { - log.Println(err) - ctx.JSON(http.StatusNotFound, gin.H{"error": "not found"}) - return - } - - ctx.JSON(http.StatusOK, post) -} - -func (store *Store) CreatePost(ctx *gin.Context) { - var input CreatePostInput - if err := ctx.ShouldBindBodyWithJSON(&input); err != nil { - ctx.JSON(http.StatusBadRequest, gin.H{"error": "invalid request body"}) - return - } - - claimsVal, ok := ctx.Get("userClaims") - if !ok { - ctx.JSON(http.StatusUnauthorized, gin.H{"error": "unauthorized"}) - return - } - - claims, ok := claimsVal.(*jwt.MapClaims) - if !ok { - ctx.JSON(http.StatusInternalServerError, gin.H{"error": "internal error"}) - return - } - - userIDF, ok := (*claims)["id"].(float64) - if !ok { - ctx.JSON(http.StatusInternalServerError, gin.H{"error": "internal error"}) - return - } - userID := uint(userIDF) - - // Create post - post := models.Post{Title: input.Title, Content: input.Content, AuthorID: userID} - tx := store.DB.Create(&post) - if tx.Error != nil { - log.Println(tx.Error) - ctx.JSON(http.StatusInternalServerError, gin.H{"error": "internal error"}) - return - } - - ctx.JSON(http.StatusCreated, post) -} - -func (store *Store) UpdatePost(ctx *gin.Context) { - postID := ctx.Param("id") - var post models.Post - if err := store.DB.First(&post, postID).Error; err != nil { - log.Println(err) - ctx.JSON(http.StatusNotFound, gin.H{"error": "not found"}) - return - } - - claimsVal, ok := ctx.Get("userClaims") - if !ok { - ctx.JSON(http.StatusUnauthorized, gin.H{"error": "unauthorized"}) - return - } - - claims, ok := claimsVal.(*jwt.MapClaims) - if !ok { - ctx.JSON(http.StatusInternalServerError, gin.H{"error": "internal error"}) - return - } - - userIDF, ok := (*claims)["id"].(float64) - if !ok { - ctx.JSON(http.StatusInternalServerError, gin.H{"error": "internal error"}) - return - } - userID := uint(userIDF) - - if !(userID == post.AuthorID) { - ctx.JSON(http.StatusUnauthorized, gin.H{"error": "unauthorized"}) - return - } - - var input CreatePostInput - if err := ctx.ShouldBindBodyWithJSON(&input); err != nil { - ctx.JSON(http.StatusBadRequest, gin.H{"error": "invalid request body"}) - return - } - - post.Title = input.Title - post.Content = input.Content - tx := store.DB.Save(&post) - if tx.Error != nil { - log.Println(tx.Error) - ctx.JSON(http.StatusInternalServerError, gin.H{"error": "internal error"}) - return - } - - ctx.JSON(http.StatusOK, post) -} - -func (store *Store) DeletePost(ctx *gin.Context) { - postID := ctx.Param("id") - var post models.Post - if err := store.DB.First(&post, postID).Error; err != nil { - log.Println(err) - ctx.JSON(http.StatusNotFound, gin.H{"error": "not found"}) - return - } - - claimsVal, ok := ctx.Get("userClaims") - if !ok { - ctx.JSON(http.StatusUnauthorized, gin.H{"error": "unauthorized"}) - return - } - - claims, ok := claimsVal.(*jwt.MapClaims) - if !ok { - ctx.JSON(http.StatusInternalServerError, gin.H{"error": "internal error"}) - return - } - - userIDF, ok := (*claims)["id"].(float64) - if !ok { - ctx.JSON(http.StatusInternalServerError, gin.H{"error": "internal error"}) - return - } - userID := uint(userIDF) - - if !(userID == post.AuthorID) { - ctx.JSON(http.StatusUnauthorized, gin.H{"error": "unauthorized"}) - return - } - - store.DB.Delete(&post) - ctx.JSON(http.StatusOK, post) -} diff --git a/backend/handlers/handle_user.go b/backend/handlers/handle_user.go deleted file mode 100644 index 753cb45..0000000 --- a/backend/handlers/handle_user.go +++ /dev/null @@ -1,190 +0,0 @@ -package handlers - -import ( - "net/http" - - "adam-french.co.uk/backend/models" - "github.com/gin-gonic/gin" - "github.com/golang-jwt/jwt/v5" - "golang.org/x/crypto/bcrypt" -) - -type UserCredentials struct { - Username string `json:"username" binding:"required"` - Password string `json:"password" binding:"required"` -} - -type SetAdminInput struct { - Admin *bool `json:"admin" binding:"required"` -} - -func (store *Store) CreateUser(ctx *gin.Context) { - var input UserCredentials - if err := ctx.ShouldBindBodyWithJSON(&input); err != nil { - ctx.JSON(http.StatusBadRequest, err.Error()) - return - } - - hashedPassword, err := bcrypt.GenerateFromPassword([]byte(input.Password), bcrypt.DefaultCost) - if err != nil { - ctx.JSON(http.StatusInternalServerError, err.Error()) - return - } - - user := models.User{Username: input.Username, Password: hashedPassword} - tx := store.DB.Create(&user) - if tx.Error != nil { - ctx.JSON(http.StatusInternalServerError, tx.Error.Error()) - return - } - - ctx.JSON(http.StatusOK, user) -} - -func (store *Store) GetUser(ctx *gin.Context) { - userID := ctx.Param("id") - var user models.User - if err := store.DB.First(&user, userID).Error; err != nil { - ctx.JSON(http.StatusNotFound, err.Error()) - return - } - - ctx.JSON(http.StatusOK, user) -} - -func (store *Store) GetUsers(ctx *gin.Context) { - var users []models.User - if err := store.DB.Find(&users).Error; err != nil { - ctx.JSON(http.StatusInternalServerError, err.Error()) - return - } - ctx.JSON(http.StatusOK, users) -} - -func (store *Store) UpdateUser(ctx *gin.Context) { - claimsVal, ok := ctx.Get("userClaims") - if !ok { - ctx.JSON(http.StatusUnauthorized, gin.H{"error": "user claims could not be found"}) - return - } - - claims, ok := claimsVal.(*jwt.MapClaims) - if !ok { - ctx.JSON(http.StatusInternalServerError, gin.H{"error": "invalid claims"}) - return - } - - userIDF, ok := (*claims)["id"].(float64) - if !ok { - ctx.JSON(http.StatusInternalServerError, gin.H{"error": "invalid user id in claims"}) - return - } - userID := uint(userIDF) - - var user models.User - if err := store.DB.First(&user, userID).Error; err != nil { - ctx.JSON(http.StatusNotFound, err.Error()) - return - } - - ctx.JSON(http.StatusInternalServerError, gin.H{"error": "will be implemented"}) -} - -func (store *Store) SetUserAdmin(ctx *gin.Context) { - claimsVal, ok := ctx.Get("userClaims") - if !ok { - ctx.JSON(http.StatusUnauthorized, gin.H{"error": "user claims could not be found"}) - return - } - claims, ok := claimsVal.(*jwt.MapClaims) - if !ok { - ctx.JSON(http.StatusInternalServerError, gin.H{"error": "invalid claims"}) - return - } - callerIDF, ok := (*claims)["id"].(float64) - if !ok { - ctx.JSON(http.StatusInternalServerError, gin.H{"error": "invalid user id in claims"}) - return - } - callerID := uint(callerIDF) - - targetID := ctx.Param("id") - - var input SetAdminInput - if err := ctx.ShouldBindBodyWithJSON(&input); err != nil { - ctx.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) - return - } - - var user models.User - if err := store.DB.First(&user, targetID).Error; err != nil { - ctx.JSON(http.StatusNotFound, gin.H{"error": "user not found"}) - return - } - - if user.ID == callerID { - ctx.JSON(http.StatusBadRequest, gin.H{"error": "cannot change your own admin status"}) - return - } - - user.Admin = *input.Admin - if err := store.DB.Save(&user).Error; err != nil { - ctx.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) - return - } - - ctx.JSON(http.StatusOK, user) -} - -func (store *Store) DeleteUser(ctx *gin.Context) { - claimsVal, ok := ctx.Get("userClaims") - if !ok { - ctx.JSON(http.StatusUnauthorized, gin.H{"error": "user claims could not be found"}) - return - } - - claims, ok := claimsVal.(*jwt.MapClaims) - if !ok { - ctx.JSON(http.StatusInternalServerError, gin.H{"error": "invalid claims"}) - return - } - - userIDF, ok := (*claims)["id"].(float64) - if !ok { - ctx.JSON(http.StatusInternalServerError, gin.H{"error": "invalid user id in claims"}) - return - } - userID := uint(userIDF) - - var user models.User - if err := store.DB.First(&user, userID).Error; err != nil { - ctx.JSON(http.StatusNotFound, err.Error()) - return - } - - tx := store.DB.Delete(&user) - if tx.Error != nil { - ctx.JSON(http.StatusInternalServerError, tx.Error.Error()) - return - } - - ctx.SetSameSite(http.SameSiteLaxMode) - ctx.SetCookie( - "access_token", - "", - -1, - "/", - store.Auth.Config.Domain, - true, true, - ) - ctx.SetCookie( - "refresh_token", - "", - -1, - "/", - store.Auth.Config.Domain, - true, true, - ) - - ctx.JSON(http.StatusOK, user) -} diff --git a/backend/main.go b/backend/main.go index b741a31..6f1be27 100644 --- a/backend/main.go +++ b/backend/main.go @@ -90,33 +90,10 @@ func main() { protected := r.Group("/", store.AuthMiddlewear) admin := r.Group("/", store.AuthMiddlewear, store.AdminMiddleware) - // FAVORITES - r.GET("/favorites", store.GetFavorites) - admin.POST("/favorites", store.CreateFavorite) - // ROWING r.GET("/rowing", store.GetRowing) admin.POST("/rowing", store.CreateRowing) - // ACTIVITIES - r.GET("/activity", store.GetActivity) - admin.POST("/activity", store.CreateActivity) - - // POSTS - r.GET("/posts", store.GetPosts) - admin.POST("/posts", store.CreatePost) - r.GET("/posts/:id", store.GetPost) - admin.PUT("/posts/:id", store.UpdatePost) - admin.DELETE("/posts/:id", store.DeletePost) - - // USERS - r.GET("/user/:id", store.GetUser) - admin.PUT("/user/:id", store.UpdateUser) - admin.DELETE("/user/:id", store.DeleteUser) - r.GET("/user", store.GetUsers) - admin.POST("/user", store.CreateUser) - admin.PATCH("/user/:id/admin", store.SetUserAdmin) - // AUTH r.POST("/auth/login", store.Login) r.POST("/auth/refresh", store.RefreshToken)