Skip to content

Commit

Permalink
paginate get users
Browse files Browse the repository at this point in the history
  • Loading branch information
garrettladley committed Jan 24, 2024
1 parent a8320a4 commit 3fc80e8
Show file tree
Hide file tree
Showing 9 changed files with 84 additions and 66 deletions.
43 changes: 24 additions & 19 deletions backend/src/controllers/user.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package controllers

import (
"strconv"

"github.com/GenerateNU/sac/backend/src/errors"
"github.com/GenerateNU/sac/backend/src/models"
"github.com/GenerateNU/sac/backend/src/services"
Expand All @@ -16,25 +18,6 @@ func NewUserController(userService services.UserServiceInterface) *UserControlle
return &UserController{userService: userService}
}

// GetAllUsers godoc
//
// @Summary Gets all users
// @Description Returns all users
// @ID get-all-users
// @Tags user
// @Produce json
// @Success 200 {object} []models.User
// @Failure 500 {string} string "failed to get all users"
// @Router /api/v1/users/ [get]
func (u *UserController) GetAllUsers(c *fiber.Ctx) error {
users, err := u.userService.GetAllUsers()
if err != nil {
return err.FiberError(c)
}

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

// Create User godoc
//
// @Summary Creates a User
Expand Down Expand Up @@ -62,6 +45,28 @@ func (u *UserController) CreateUser(c *fiber.Ctx) error {
return c.Status(fiber.StatusCreated).JSON(user)
}

// GetAllUsers godoc
//
// @Summary Gets all users
// @Description Returns all users
// @ID get-all-users
// @Tags user
// @Produce json
// @Success 200 {object} []models.User
// @Failure 500 {string} string "failed to get all users"
// @Router /api/v1/users/ [get]
func (u *UserController) GetUsers(c *fiber.Ctx) error {
defaultLimit := 10
defaultPage := 1

categories, err := u.userService.GetUsers(c.Query("limit", strconv.Itoa(defaultLimit)), c.Query("page", strconv.Itoa(defaultPage)))
if err != nil {
return err.FiberError(c)
}

return c.Status(fiber.StatusOK).JSON(&categories)
}

// GetUser godoc
//
// @Summary Gets a user
Expand Down
8 changes: 4 additions & 4 deletions backend/src/errors/category.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,14 @@ var (
StatusCode: fiber.StatusInternalServerError,
Message: "failed to create category",
}
FailedToGetCategory = Error{
StatusCode: fiber.StatusInternalServerError,
Message: "failed to get category",
}
FailedToGetCategories = Error{
StatusCode: fiber.StatusInternalServerError,
Message: "failed to get categories",
}
FailedToGetCategory = Error{
StatusCode: fiber.StatusInternalServerError,
Message: "failed to get category",
}
FailedToUpdateCategory = Error{
StatusCode: fiber.StatusInternalServerError,
Message: "failed to update category",
Expand Down
16 changes: 8 additions & 8 deletions backend/src/errors/user.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,6 @@ var (
StatusCode: fiber.StatusBadRequest,
Message: "failed to validate user",
}
FailedToGetAllUsers = Error{
StatusCode: fiber.StatusInternalServerError,
Message: "failed to get all users",
}
FailedToGetUser = Error{
StatusCode: fiber.StatusInternalServerError,
Message: "failed to get user",
}
FailedToCreateUser = Error{
StatusCode: fiber.StatusInternalServerError,
Message: "failed to create user",
Expand All @@ -23,6 +15,14 @@ var (
StatusCode: fiber.StatusInternalServerError,
Message: "failed to update user",
}
FailedToGetUsers = Error{
StatusCode: fiber.StatusInternalServerError,
Message: "failed to get users",
}
FailedToGetUser = Error{
StatusCode: fiber.StatusInternalServerError,
Message: "failed to get user",
}
FailedToDeleteUser = Error{
StatusCode: fiber.StatusInternalServerError,
Message: "failed to delete user",
Expand Down
2 changes: 1 addition & 1 deletion backend/src/server/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,8 +68,8 @@ func userRoutes(router fiber.Router, userService services.UserServiceInterface)

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

users.Get("/", userController.GetAllUsers)
users.Post("/", userController.CreateUser)
users.Get("/", userController.GetUsers)
users.Get("/:id", userController.GetUser)
users.Patch("/:id", userController.UpdateUser)
users.Delete("/:id", userController.DeleteUser)
Expand Down
2 changes: 1 addition & 1 deletion backend/src/services/category.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@ import (

type CategoryServiceInterface interface {
CreateCategory(categoryBody models.CategoryRequestBody) (*models.Category, *errors.Error)
GetCategory(id string) (*models.Category, *errors.Error)
GetCategories(limit string, page string) ([]models.Category, *errors.Error)
GetCategory(id string) (*models.Category, *errors.Error)
UpdateCategory(id string, params models.CategoryRequestBody) (*models.Category, *errors.Error)
DeleteCategory(id string) *errors.Error
}
Expand Down
25 changes: 19 additions & 6 deletions backend/src/services/user.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ import (
)

type UserServiceInterface interface {
GetAllUsers() ([]models.User, *errors.Error)
CreateUser(userBody models.CreateUserRequestBody) (*models.User, *errors.Error)
GetUsers(limit string, page string) ([]models.User, *errors.Error)
GetUser(id string) (*models.User, *errors.Error)
UpdateUser(id string, userBody models.UpdateUserRequestBody) (*models.User, *errors.Error)
DeleteUser(id string) *errors.Error
Expand All @@ -26,11 +26,6 @@ type UserService struct {
Validate *validator.Validate
}

// Gets all users (including soft deleted users) for testing
func (u *UserService) GetAllUsers() ([]models.User, *errors.Error) {
return transactions.GetAllUsers(u.DB)
}

func (u *UserService) CreateUser(userBody models.CreateUserRequestBody) (*models.User, *errors.Error) {
if err := u.Validate.Struct(userBody); err != nil {
return nil, &errors.FailedToValidateUser
Expand All @@ -52,6 +47,24 @@ func (u *UserService) CreateUser(userBody models.CreateUserRequestBody) (*models
return transactions.CreateUser(u.DB, user)
}

func (u *UserService) GetUsers(limit string, page string) ([]models.User, *errors.Error) {
limitAsInt, err := utilities.ValidateNonNegative(limit)

if err != nil {
return nil, &errors.FailedToValidateLimit
}

pageAsInt, err := utilities.ValidateNonNegative(page)

if err != nil {
return nil, &errors.FailedToValidatePage
}

offset := (*pageAsInt - 1) * *limitAsInt

return transactions.GetUsers(u.DB, *limitAsInt, offset)
}

func (u *UserService) GetUser(id string) (*models.User, *errors.Error) {
idAsUint, err := utilities.ValidateID(id)
if err != nil {
Expand Down
20 changes: 10 additions & 10 deletions backend/src/transactions/category.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,16 @@ func CreateCategory(db *gorm.DB, category models.Category) (*models.Category, *e
return &category, nil
}

func GetCategories(db *gorm.DB, limit int, offset int) ([]models.Category, *errors.Error) {
var categories []models.Category

if err := db.Limit(limit).Offset(offset).Find(&categories).Error; err != nil {
return nil, &errors.FailedToGetCategories
}

return categories, nil
}

func GetCategory(db *gorm.DB, id uint) (*models.Category, *errors.Error) {
var category models.Category

Expand All @@ -36,16 +46,6 @@ func GetCategory(db *gorm.DB, id uint) (*models.Category, *errors.Error) {
return &category, nil
}

func GetCategories(db *gorm.DB, limit int, offset int) ([]models.Category, *errors.Error) {
var categories []models.Category

if err := db.Limit(limit).Offset(offset).Find(&categories).Error; err != nil {
return nil, &errors.FailedToGetCategories
}

return categories, nil
}

func UpdateCategory(db *gorm.DB, id uint, category models.Category) (*models.Category, *errors.Error) {
if err := db.Model(&models.Category{}).Where("id = ?", id).Updates(category).First(&category, id).Error; err != nil {
if stdliberrors.Is(err, gorm.ErrRecordNotFound) {
Expand Down
30 changes: 15 additions & 15 deletions backend/src/transactions/user.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,23 @@ import (
"gorm.io/gorm"
)

func GetAllUsers(db *gorm.DB) ([]models.User, *errors.Error) {
func CreateUser(db *gorm.DB, user *models.User) (*models.User, *errors.Error) {
if err := db.Create(user).Error; err != nil {
if stdliberrors.Is(err, gorm.ErrDuplicatedKey) {
return nil, &errors.UserAlreadyExists
} else {
return nil, &errors.FailedToCreateUser
}
}

return user, nil
}

func GetUsers(db *gorm.DB, limit int, offset int) ([]models.User, *errors.Error) {
var users []models.User

if err := db.Omit("password_hash").Find(&users).Error; err != nil {
return nil, &errors.FailedToGetAllUsers
if err := db.Omit("password_hash").Limit(limit).Offset(offset).Find(&users).Error; err != nil {
return nil, &errors.FailedToGetUsers
}

return users, nil
Expand All @@ -32,18 +44,6 @@ func GetUser(db *gorm.DB, id uint) (*models.User, *errors.Error) {
return &user, nil
}

func CreateUser(db *gorm.DB, user *models.User) (*models.User, *errors.Error) {
if err := db.Create(user).Error; err != nil {
if stdliberrors.Is(err, gorm.ErrDuplicatedKey) {
return nil, &errors.UserAlreadyExists
} else {
return nil, &errors.FailedToCreateUser
}
}

return user, nil
}

func UpdateUser(db *gorm.DB, id uint, user models.User) (*models.User, *errors.Error) {
var existingUser models.User

Expand Down
4 changes: 2 additions & 2 deletions backend/tests/api/user_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import (
"github.com/huandu/go-assert"
)

func TestGetAllUsersWorks(t *testing.T) {
func TestGetUsersWorks(t *testing.T) {
TestRequest{
Method: fiber.MethodGet,
Path: "/api/v1/users/",
Expand All @@ -43,7 +43,7 @@ func TestGetAllUsersWorks(t *testing.T) {
assert.Equal(models.College("KCCS"), respUser.College)
assert.Equal(models.Year(1), respUser.Year)

dbUsers, err := transactions.GetAllUsers(app.Conn)
dbUsers, err := transactions.GetUsers(app.Conn, 1, 0)

assert.NilError(&err)

Expand Down

0 comments on commit 3fc80e8

Please sign in to comment.