Skip to content

Commit

Permalink
SAC-5 Update User PATCH (#28)
Browse files Browse the repository at this point in the history
Co-authored-by: Melody Yu <[email protected]>
Co-authored-by: Garrett Ladley <[email protected]>
Co-authored-by: Zackary Lassetter <[email protected]>
Co-authored-by: edwinliiiii <[email protected]>
Co-authored-by: edwinliiiii <[email protected]>
Co-authored-by: garrettladley <[email protected]>
Co-authored-by: David Oduneye <[email protected]>
Co-authored-by: David Oduneye <[email protected]>
  • Loading branch information
9 people authored Jan 22, 2024
1 parent 83bb7cf commit de0127b
Show file tree
Hide file tree
Showing 23 changed files with 429 additions and 231 deletions.
13 changes: 8 additions & 5 deletions backend/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,10 @@ require (
gorm.io/gorm v1.25.5
)

require github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
require (
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
github.com/mcnijman/go-emailaddress v1.1.1 // indirect
)

require (
github.com/KyleBanks/depth v1.2.1 // indirect
Expand Down Expand Up @@ -61,11 +64,11 @@ require (
github.com/valyala/tcplisten v1.0.0 // indirect
go.uber.org/atomic v1.9.0 // indirect
go.uber.org/multierr v1.9.0 // indirect
golang.org/x/crypto v0.17.0
golang.org/x/crypto v0.18.0 // indirect
golang.org/x/exp v0.0.0-20230905200255-921286631fa9 // indirect
golang.org/x/net v0.19.0 // indirect
golang.org/x/sys v0.15.0 // indirect
golang.org/x/text v0.14.0
golang.org/x/net v0.20.0 // indirect
golang.org/x/sys v0.16.0 // indirect
golang.org/x/text v0.14.0 // indirect
golang.org/x/tools v0.13.0 // indirect
gopkg.in/ini.v1 v1.67.0 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
Expand Down
9 changes: 9 additions & 0 deletions backend/go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,8 @@ github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWE
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U=
github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
github.com/mcnijman/go-emailaddress v1.1.1 h1:AGhgVDG3tCDaL0/Vc6erlPQjDuDN3dAT7rRdgFtetr0=
github.com/mcnijman/go-emailaddress v1.1.1/go.mod h1:5whZrhS8Xp5LxO8zOD35BC+b76kROtsh+dPomeRt/II=
github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
Expand Down Expand Up @@ -158,6 +160,8 @@ golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5y
golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU=
golang.org/x/crypto v0.17.0 h1:r8bRNjWL3GshPW3gkd+RpvzWrZAwPS49OmTGZ/uhM4k=
golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4=
golang.org/x/crypto v0.18.0 h1:PGVlW0xEltQnzFZ55hkuX5+KLyrMYhHld1YHO4AKcdc=
golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg=
golang.org/x/exp v0.0.0-20230905200255-921286631fa9 h1:GoHiUyI/Tp2nVkLI2mCxVkOjsbSXD66ic0XW0js0R9g=
golang.org/x/exp v0.0.0-20230905200255-921286631fa9/go.mod h1:S2oDrQGGwySpoQPVqRShND87VCbxmc6bL1Yd2oYrm6k=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
Expand All @@ -166,6 +170,7 @@ golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/mod v0.9.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/mod v0.12.0 h1:rmsUpXtvNzj340zd98LZ4KntptpfRHwpFOHG188oHXc=
golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/net v0.0.0-20180911220305-26e67e76b6c3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210421230115-4e50805a0758/go.mod h1:72T/g9IO56b78aLF+1Kcs5dz7/ng1VjMUvfKvpfy+jM=
Expand All @@ -175,6 +180,8 @@ golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc=
golang.org/x/net v0.19.0 h1:zTwKpTd2XuCqf8huc7Fo2iSy+4RHPd10s4KzeTnVr1c=
golang.org/x/net v0.19.0/go.mod h1:CfAk/cbD4CthTvqiEl8NpboMuiuOYsAr/7NOjZJtv1U=
golang.org/x/net v0.20.0 h1:aCL9BSgETF1k+blQaYUBx9hJ9LOGP3gAVemcZlf1Kpo=
golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
Expand All @@ -191,6 +198,8 @@ golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc=
golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.16.0 h1:xWw16ngr6ZMtmxDyKyIgsE93KNKz5HKmMa3b8ALHidU=
golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.3.0/go.mod h1:q750SLmJuPmVoN1blW3UFBPREJfb1KmY3vwxfr+nFDA=
Expand Down
17 changes: 5 additions & 12 deletions backend/src/controllers/category.go
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
package controllers

import (
"fmt"

"github.com/GenerateNU/sac/backend/src/models"
"github.com/GenerateNU/sac/backend/src/services"
"github.com/GenerateNU/sac/backend/src/utilities"

"github.com/gofiber/fiber/v2"
)
Expand All @@ -31,21 +30,15 @@ func NewCategoryController(categoryService services.CategoryServiceInterface) *C
// @Failure 500 {string} string "failed to create category"
// @Router /api/v1/category/ [post]
func (t *CategoryController) CreateCategory(c *fiber.Ctx) error {
var categoryBody models.CreateCategoryRequestBody
var categoryBody models.CategoryRequestBody

if err := c.BodyParser(&categoryBody); err != nil {
fmt.Print(err)
return fiber.NewError(fiber.StatusBadRequest, "failed to process the request")
}

category := models.Category{
Name: categoryBody.Name,
return utilities.Error(c, fiber.StatusBadRequest, "failed to process the request")
}

newCategory, err := t.categoryService.CreateCategory(category)

newCategory, err := t.categoryService.CreateCategory(categoryBody)
if err != nil {
return err
return utilities.Error(c, fiber.StatusInternalServerError, err.Error())
}

return c.Status(fiber.StatusCreated).JSON(newCategory)
Expand Down
27 changes: 12 additions & 15 deletions backend/src/controllers/tag.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package controllers
import (
"github.com/GenerateNU/sac/backend/src/models"
"github.com/GenerateNU/sac/backend/src/services"
"github.com/GenerateNU/sac/backend/src/utilities"

"github.com/gofiber/fiber/v2"
)
Expand All @@ -29,16 +30,15 @@ func NewTagController(tagService services.TagServiceInterface) *TagController {
// @Failure 500 {string} string "failed to create tag"
// @Router /api/v1/tags/ [post]
func (t *TagController) CreateTag(c *fiber.Ctx) error {
var tagBody models.CreateTagRequestBody
var tagBody models.TagRequestBody

if err := c.BodyParser(&tagBody); err != nil {
return fiber.NewError(fiber.StatusBadRequest, "failed to process the request")
return utilities.Error(c, fiber.StatusBadRequest, "failed to process the request")
}

dbTag, err := t.tagService.CreateTag(tagBody)

if err != nil {
return err
return utilities.Error(c, fiber.StatusInternalServerError, err.Error())
}

return c.Status(fiber.StatusCreated).JSON(&dbTag)
Expand All @@ -59,9 +59,8 @@ func (t *TagController) CreateTag(c *fiber.Ctx) error {
// @Router /api/v1/tags/{id} [get]
func (t *TagController) GetTag(c *fiber.Ctx) error {
tag, err := t.tagService.GetTag(c.Params("id"))

if err != nil {
return err
return utilities.Error(c, fiber.StatusInternalServerError, err.Error())
}

return c.Status(fiber.StatusOK).JSON(&tag)
Expand All @@ -84,16 +83,15 @@ func (t *TagController) GetTag(c *fiber.Ctx) error {
// @Failure 500 {string} string "failed to update tag"
// @Router /api/v1/tags/{id} [patch]
func (t *TagController) UpdateTag(c *fiber.Ctx) error {
var tagBody models.UpdateTagRequestBody
var tagBody models.TagRequestBody

if err := c.BodyParser(&tagBody); err != nil {
return fiber.NewError(fiber.StatusBadRequest, "failed to process the request")
return utilities.Error(c, fiber.StatusBadRequest, "failed to process the request")
}

tag, err := t.tagService.UpdateTag(c.Params("id"), tagBody)

if err != nil {
return err
return utilities.Error(c, fiber.StatusInternalServerError, err.Error())
}

return c.Status(fiber.StatusOK).JSON(&tag)
Expand All @@ -106,17 +104,16 @@ func (t *TagController) UpdateTag(c *fiber.Ctx) error {
// @ID delete-tag
// @Tags tag
// @Param id path int true "Tag ID"
// @Success 204
// @Success 204 {string} string "no content"
// @Failure 400 {string} string "failed to validate id"
// @Failure 404 {string} string "failed to find tag"
// @Failure 404 {string} string "tag not found"
// @Failure 500 {string} string "failed to delete tag"
// @Router /api/v1/tags/{id} [delete]
func (t *TagController) DeleteTag(c *fiber.Ctx) error {
err := t.tagService.DeleteTag(c.Params("id"))

if err != nil {
return err
return utilities.Error(c, fiber.StatusInternalServerError, err.Error())
}

return c.SendStatus(fiber.StatusNoContent)
}
}
53 changes: 42 additions & 11 deletions backend/src/controllers/user.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
package controllers

import (
"github.com/GenerateNU/sac/backend/src/models"
"github.com/GenerateNU/sac/backend/src/services"

"github.com/GenerateNU/sac/backend/src/utilities"
"github.com/gofiber/fiber/v2"
)

Expand All @@ -26,31 +27,61 @@ func NewUserController(userService services.UserServiceInterface) *UserControlle
// @Router /api/v1/users/ [get]
func (u *UserController) GetAllUsers(c *fiber.Ctx) error {
users, err := u.userService.GetAllUsers()

if err != nil {
return err
return utilities.Error(c, fiber.StatusInternalServerError, err.Error())
}

return c.Status(fiber.StatusOK).JSON(users)
}

// GetUser godoc
//
// @Summary Gets specific user
// @Description Returns specific user
// @ID get-user
// @Summary Gets a user
// @Description Returns a user
// @ID get-user-by-id
// @Tags user
// @Produce json
// @Param id path string true "User ID"
// @Success 200 {object} models.User
// @Failure 400 {string} string "failed to validate id"
// @Failure 404 {string} string "failed to find user"
// @Failure 500 {string} string
// @Router /api/v1/users/ [get]
// @Failure 404 {string} string "user not found"
// @Failure 400 {string} string "failed to validate id"
// @Failure 500 {string} string "failed to get user"
// @Router /api/v1/users/:id [get]
func (u *UserController) GetUser(c *fiber.Ctx) error {
user, err := u.userService.GetUser(c.Params("id"))
if err != nil {
return err
return utilities.Error(c, fiber.StatusInternalServerError, err.Error())
}

return c.Status(fiber.StatusOK).JSON(user)
}

// UpdateUser godoc
//
// @Summary Updates a user
// @Description Updates a user
// @ID update-user-by-id
// @Tags user
// @Produce json
// @Success 200 {object} models.User
// @Failure 404 {string} string "user not found"
// @Failure 400 {string} string "invalid request body"
// @Failure 400 {string} string "failed to validate id"
// @Failure 500 {string} string "database error"
// @Failure 500 {string} string "failed to hash password"
// @Router /api/v1/users/:id [patch]
func (u *UserController) UpdateUser(c *fiber.Ctx) error {
var user models.UserRequestBody

if err := c.BodyParser(&user); err != nil {
return utilities.Error(c, fiber.StatusBadRequest, "invalid request body")
}

updatedUser, err := u.userService.UpdateUser(c.Params("id"), user)
if err != nil {
return utilities.Error(c, fiber.StatusInternalServerError, err.Error())
}

// Return the updated user details
return c.Status(fiber.StatusOK).JSON(updatedUser)
}
2 changes: 1 addition & 1 deletion backend/src/models/category.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,6 @@ type Category struct {
Tag []Tag `gorm:"constraint:OnUpdate:CASCADE,OnDelete:CASCADE;" json:"-" validate:"-"`
}

type CreateCategoryRequestBody struct {
type CategoryRequestBody struct {
Name string `gorm:"type:varchar(255)" json:"category_name" validate:"required,max=255"`
}
12 changes: 2 additions & 10 deletions backend/src/models/tag.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,7 @@ type Tag struct {
Event []Event `gorm:"many2many:event_tags;constraint:OnUpdate:CASCADE,OnDelete:CASCADE;" json:"-" validate:"-"`
}

type PartialTag struct {
type TagRequestBody struct {
Name string `json:"name" validate:"required,max=255"`
CategoryID uint `json:"category_id" validate:"required,min=1"`
}

type CreateTagRequestBody struct {
PartialTag
}

type UpdateTagRequestBody struct {
PartialTag
}
}
10 changes: 10 additions & 0 deletions backend/src/models/user.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,3 +56,13 @@ type User struct {
RSVP []Event `gorm:"many2many:user_event_rsvps;constraint:OnUpdate:CASCADE,OnDelete:CASCADE;" json:"-" validate:"-"`
Waitlist []Event `gorm:"many2many:user_event_waitlists;constraint:OnUpdate:CASCADE,OnDelete:CASCADE;" json:"-" validate:"-"`
}

type UserRequestBody struct {
NUID string `json:"nuid" validate:"required,len=9"`
FirstName string `json:"first_name" validate:"required,max=255"`
LastName string `json:"last_name" validate:"required,max=255"`
Email string `json:"email" validate:"required,email,neu_email,max=255"`
Password string `json:"password" validate:"required,password"`
College College `json:"college" validate:"required,oneof=CAMD DMSB KCCS CE BCHS SL CPS CS CSSH"`
Year Year `json:"year" validate:"required,min=1,max=6"`
}
6 changes: 4 additions & 2 deletions backend/src/server/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package server
import (
"github.com/GenerateNU/sac/backend/src/controllers"
"github.com/GenerateNU/sac/backend/src/services"
"github.com/GenerateNU/sac/backend/src/utilities"
"github.com/go-playground/validator/v10"
"github.com/goccy/go-json"

Expand All @@ -27,7 +28,7 @@ func Init(db *gorm.DB) *fiber.App {

validate := validator.New(validator.WithRequiredStructEnabled())
// MARK: Custom validator tags can be registered here.
// validate.RegisterValidation("my_custom_validator", MyCustomValidatorFunc)
utilities.RegisterCustomValidators(validate)

utilityRoutes(app)

Expand Down Expand Up @@ -69,6 +70,7 @@ func userRoutes(router fiber.Router, userService services.UserServiceInterface)

users.Get("/", userController.GetAllUsers)
users.Get("/:id", userController.GetUser)
users.Patch("/:id", userController.UpdateUser)
}

func categoryRoutes(router fiber.Router, categoryService services.CategoryServiceInterface) {
Expand All @@ -84,8 +86,8 @@ func tagRoutes(router fiber.Router, tagService services.TagServiceInterface) {

tags := router.Group("/tags")

tags.Post("/", tagController.CreateTag)
tags.Get("/:id", tagController.GetTag)
tags.Post("/", tagController.CreateTag)
tags.Patch("/:id", tagController.UpdateTag)
tags.Delete("/:id", tagController.DeleteTag)
}
19 changes: 13 additions & 6 deletions backend/src/services/category.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,29 +3,36 @@ package services
import (
"github.com/GenerateNU/sac/backend/src/models"
"github.com/GenerateNU/sac/backend/src/transactions"
"github.com/GenerateNU/sac/backend/src/utilities"
"github.com/go-playground/validator/v10"

"github.com/gofiber/fiber/v2"
"golang.org/x/text/cases"
"golang.org/x/text/language"

"github.com/gofiber/fiber/v2"
"gorm.io/gorm"
)

type CategoryServiceInterface interface {
CreateCategory(category models.Category) (*models.Category, error)
CreateCategory(categoryBody models.CategoryRequestBody) (*models.Category, error)
}

type CategoryService struct {
DB *gorm.DB
Validate *validator.Validate
}

func (c *CategoryService) CreateCategory(category models.Category) (*models.Category, error) {
if err := c.Validate.Struct(category); err != nil {
return nil, fiber.NewError(fiber.StatusBadRequest, "failed to validate the data")
func (c *CategoryService) CreateCategory(categoryBody models.CategoryRequestBody) (*models.Category, error) {
if err := c.Validate.Struct(categoryBody); err != nil {
return nil, fiber.ErrBadRequest
}

category, err := utilities.MapResponseToModel(categoryBody, &models.Category{})
if err != nil {
return nil, fiber.ErrInternalServerError
}

category.Name = cases.Title(language.English).String(category.Name)

return transactions.CreateCategory(c.DB, category)
return transactions.CreateCategory(c.DB, *category)
}
Loading

0 comments on commit de0127b

Please sign in to comment.