Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 35 additions & 0 deletions backend/internal/handler/users.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import (
type UsersRepository interface {
FindUser(ctx context.Context, id string) (*models.User, error)
InsertUser(ctx context.Context, user *models.CreateUser) (*models.User, error)
UpdateUser(ctx context.Context, id string, update *models.UpdateUser) (*models.User, error)
}

type UsersHandler struct {
Expand Down Expand Up @@ -52,6 +53,40 @@ func (h *UsersHandler) GetUserByID(c *fiber.Ctx) error {
return c.JSON(user)
}

// UpdateUser godoc
// @Summary Updates a user
// @Description Updates fields on a user
// @Tags users
// @Accept json
// @Produce json
// @Param id path string true "User ID"
// @Param request body models.UpdateUser true "User update data"
// @Success 200 {object} models.User
// @Failure 400 {object} map[string]string
// @Failure 404 {object} map[string]string
// @Failure 500 {object} map[string]string
// @Security BearerAuth
// @Router /users/{id} [put]
func (h *UsersHandler) UpdateUser(c *fiber.Ctx) error {
id := c.Params("id")

var updateUserRequest models.UpdateUser
if err := httpx.BindAndValidate(c, &updateUserRequest); err != nil {
return err
}

user, err := h.repo.UpdateUser(c.Context(), id, &updateUserRequest)
if err != nil {
if errors.Is(err, errs.ErrNotFoundInDB) {
return errs.NotFound("user", "id", id)
}
slog.Error("failed to update user", "id", id, "err", err.Error())
return errs.InternalServerError()
}

return c.JSON(user)
}

// CreateUser godoc
// @Summary Creates a user
// @Description Creates a user with the given data
Expand Down
8 changes: 8 additions & 0 deletions backend/internal/handler/users_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import (
type mockUsersRepository struct {
findUserByIdFunc func(ctx context.Context, id string) (*models.User, error)
insertUserFunc func(ctx context.Context, user *models.CreateUser) (*models.User, error)
updateUserFunc func(ctx context.Context, id string, update *models.UpdateUser) (*models.User, error)
}

// Implement the interface - calls our controllable function
Expand All @@ -37,6 +38,13 @@ func (m *mockUsersRepository) InsertUser(ctx context.Context, user *models.Creat
return nil, nil
}

func (m *mockUsersRepository) UpdateUser(ctx context.Context, id string, update *models.UpdateUser) (*models.User, error) {
if m.updateUserFunc != nil {
return m.updateUserFunc(ctx, id, update)
}
return nil, nil
}

func TestUsersHandler_GetUserByID(t *testing.T) {
t.Parallel()

Expand Down
4 changes: 4 additions & 0 deletions backend/internal/models/users.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@ type CreateUser struct {
PrimaryEmail *string `json:"primary_email,omitempty" validate:"omitempty,email" example:"john@example.com"`
} //@name CreateUser

type UpdateUser struct {
PhoneNumber *string `json:"phone_number,omitempty" validate:"omitempty,notblank" example:"+11234567890"`
} //@name UpdateUser

type CreateUserWebhook struct {
ClerkUser `json:"data"`
}
Expand Down
23 changes: 23 additions & 0 deletions backend/internal/repository/users.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,29 @@ func (r *UsersRepository) InsertUser(ctx context.Context, user *models.CreateUse
return createdUser, nil
}

func (r *UsersRepository) UpdateUser(ctx context.Context, id string, update *models.UpdateUser) (*models.User, error) {
var user models.User

row := r.db.QueryRow(ctx, `
UPDATE users
SET
phone_number = COALESCE($2, phone_number),
updated_at = NOW()
WHERE id = $1
RETURNING id, first_name, last_name, hotel_id, employee_id, profile_picture, role, department, timezone, phone_number, primary_email, created_at, updated_at
`, id, update.PhoneNumber)

err := row.Scan(&user.ID, &user.FirstName, &user.LastName, &user.HotelID, &user.EmployeeID, &user.ProfilePicture, &user.Role, &user.Department, &user.Timezone, &user.PhoneNumber, &user.PrimaryEmail, &user.CreatedAt, &user.UpdatedAt)
if err != nil {
if errors.Is(err, pgx.ErrNoRows) {
return nil, errs.ErrNotFoundInDB
}
return nil, err
}

return &user, nil
}

func (r *UsersRepository) BulkInsertUsers(ctx context.Context, users []*models.CreateUser) error {
batch := &pgx.Batch{}

Expand Down
1 change: 1 addition & 0 deletions backend/internal/service/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,7 @@ func setupRoutes(app *fiber.App, repo *storage.Repository, genkitInstance *aiflo
api.Route("/users", func(r fiber.Router) {
r.Get("/:id", usersHandler.GetUserByID)
r.Post("/", usersHandler.CreateUser)
r.Put("/:id", usersHandler.UpdateUser)
})

// Guest Routes
Expand Down
Loading