Skip to content

Commit

Permalink
feat: check nickname API
Browse files Browse the repository at this point in the history
  • Loading branch information
litsynp committed Oct 20, 2023
1 parent a77693e commit 5638b5c
Show file tree
Hide file tree
Showing 13 changed files with 266 additions and 4 deletions.
24 changes: 24 additions & 0 deletions cmd/server/handler/user_handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,30 @@ func (h *UserHandler) RegisterUser(w http.ResponseWriter, r *http.Request) {
commonviews.Created(w, nil, res)
}

// CheckUserNickname godoc
// @Summary 닉네임 중복 여부를 조회합니다.
// @Description
// @Tags users
// @Accept json
// @Produce json
// @Param request body user.CheckNicknameRequest true "사용자 닉네임 중복 조회 요청"
// @Success 200 {object} user.CheckNicknameView
// @Router /users/check/nickname [post]
func (h *UserHandler) CheckUserNickname(w http.ResponseWriter, r *http.Request) {
var checkUserNicknameRequest user.CheckNicknameRequest
if err := commonviews.ParseBody(w, r, &checkUserNicknameRequest); err != nil {
return
}

exists, err := h.userService.ExistsByNickname(checkUserNicknameRequest.Nickname)
if err != nil {
commonviews.InternalServerError(w, nil, err.Error())
return
}

commonviews.OK(w, nil, user.CheckNicknameView{IsAvailable: !exists})
}

// FindUserStatusByEmail godoc
// @Summary 이메일로 유저의 가입 상태를 조회합니다.
// @Description
Expand Down
2 changes: 1 addition & 1 deletion cmd/server/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import (
)

// @title 이웃집멍냥 API 문서
// @version 0.4.0
// @version 0.5.0
// @description 이웃집멍냥 백엔드 API 문서입니다.
// @termsOfService http://swagger.io/terms/

Expand Down
1 change: 1 addition & 0 deletions cmd/server/router.go
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ func NewRouter(app *firebaseinfra.FirebaseApp) *chi.Mux {
})
r.Route("/users", func(r chi.Router) {
r.Post("/", userHandler.RegisterUser)
r.Post("/check/nickname", userHandler.CheckUserNickname)
r.Post("/status", userHandler.FindUserStatusByEmail)
r.Get("/me", userHandler.FindMyProfile)
r.Put("/me", userHandler.UpdateMyProfile)
Expand Down
3 changes: 3 additions & 0 deletions db/migrations/000006_add_users_nickname_uix.down.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
ALTER TABLE
users
DROP CONSTRAINT users_nickname_uix;
4 changes: 4 additions & 0 deletions db/migrations/000006_add_users_nickname_uix.up.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
ALTER TABLE
users
ADD
CONSTRAINT users_nickname_uix UNIQUE (nickname);
5 changes: 5 additions & 0 deletions internal/domain/user/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ type UserServicer interface {
RegisterUser(registerUserRequest *RegisterUserRequest) (*RegisterUserResponse, error)
FindUserByEmail(email string) (*UserWithProfileImage, error)
FindUserByUID(uid string) (*FindUserResponse, error)
ExistsByNickname(nickname string) (bool, error)
FindUserStatusByEmail(email string) (*UserStatus, error)
UpdateUserByUID(uid string, nickname string, profileImageID int) (*UserWithProfileImage, error)
AddPetsToOwner(uid string, addPetsRequest pet.AddPetsToOwnerRequest) ([]pet.PetView, error)
Expand Down Expand Up @@ -81,6 +82,10 @@ func (service *UserService) FindUserByUID(uid string) (*FindUserResponse, error)
}, nil
}

func (service *UserService) ExistsByNickname(nickname string) (bool, error) {
return service.userStore.ExistsByNickname(nickname)
}

func (service *UserService) FindUserStatusByEmail(email string) (*UserStatus, error) {
userStatus, err := service.userStore.FindUserStatusByEmail(email)
if err != nil {
Expand Down
46 changes: 46 additions & 0 deletions internal/domain/user/tests/service_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,52 @@ func TestUserService(t *testing.T) {
})
})

t.Run("ExistsByNickname", func(t *testing.T) {
t.Run("사용자의 닉네임이 존재하지 않을 경우 false를 반환한다", func(t *testing.T) {
tearDown := setUp(t)
defer tearDown(t)

media_service := media.NewMediaService(postgres.NewMediaPostgresStore(db), nil)

service := user.NewUserService(postgres.NewUserPostgresStore(db), postgres.NewPetPostgresStore(db), media_service)

exists, _ := service.ExistsByNickname("non-existent")
if exists {
t.Errorf("got %v want %v", exists, false)
}
})

t.Run("사용자의 닉네임이 존재할 경우 true를 반환한다", func(t *testing.T) {
tearDown := setUp(t)
defer tearDown(t)

media_service := media.NewMediaService(postgres.NewMediaPostgresStore(db), nil)
profile_image, _ := media_service.CreateMedia(&media.Media{
MediaType: media.IMAGE_MEDIA_TYPE,
URL: "http://example.com",
})

service := user.NewUserService(postgres.NewUserPostgresStore(db), postgres.NewPetPostgresStore(db), media_service)

user := &user.RegisterUserRequest{
Email: "[email protected]",
Nickname: "nickname",
Fullname: "fullname",
ProfileImageID: profile_image.ID,
FirebaseProviderType: "kakao",
FirebaseUID: "uid",
}

_, _ = service.RegisterUser(user)

exists, _ := service.ExistsByNickname(user.Nickname)

if !exists {
t.Errorf("got %v want %v", exists, true)
}
})
})

t.Run("FindUserStatusByEmail", func(t *testing.T) {
t.Run("사용자의 상태를 반환한다", func(t *testing.T) {
tearDown := setUp(t)
Expand Down
1 change: 1 addition & 0 deletions internal/domain/user/user.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ type UserStore interface {
CreateUser(request *RegisterUserRequest) (*User, error)
FindUserByEmail(email string) (*UserWithProfileImage, error)
FindUserByUID(uid string) (*UserWithProfileImage, error)
ExistsByNickname(nickname string) (bool, error)
FindUserStatusByEmail(email string) (*UserStatus, error)
UpdateUserByUID(uid string, nickname string, profileImageID int) (*User, error)
}
8 changes: 8 additions & 0 deletions internal/domain/user/view.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,14 @@ type FindUserResponse struct {
FirebaseUID string `json:"fbUid"`
}

type CheckNicknameRequest struct {
Nickname string `json:"nickname" validate:"required"`
}

type CheckNicknameView struct {
IsAvailable bool `json:"isAvailable"`
}

type UserStatusRequest struct {
Email string `json:"email" validate:"required,email"`
}
Expand Down
33 changes: 33 additions & 0 deletions internal/postgres/user_store.go
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,39 @@ func (s *UserPostgresStore) FindUserByUID(uid string) (*user.UserWithProfileImag
return user, nil
}

func (s *UserPostgresStore) ExistsByNickname(nickname string) (bool, error) {
var exists bool

tx, _ := s.db.Begin()
err := tx.QueryRow(`
SELECT
CASE
WHEN EXISTS (
SELECT
1
FROM
users
WHERE
nickname = $1 AND
deleted_at IS NULL
) THEN TRUE
ELSE FALSE
END
`,
nickname,
).Scan(&exists)
if err != nil {
return false, err
}

err = tx.Commit()
if err != nil {
return false, err
}

return exists, nil
}

func (s *UserPostgresStore) FindUserStatusByEmail(email string) (*user.UserStatus, error) {
var userStatus user.UserStatus

Expand Down
54 changes: 53 additions & 1 deletion pkg/docs/docs.go
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,39 @@ const docTemplate = `{
}
}
},
"/users/check/nickname": {
"post": {
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"users"
],
"summary": "닉네임 중복 여부를 조회합니다.",
"parameters": [
{
"description": "사용자 닉네임 중복 조회 요청",
"name": "request",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/user.CheckNicknameRequest"
}
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"$ref": "#/definitions/user.CheckNicknameView"
}
}
}
}
},
"/users/me": {
"get": {
"security": [
Expand Down Expand Up @@ -551,6 +584,25 @@ const docTemplate = `{
}
}
},
"user.CheckNicknameRequest": {
"type": "object",
"required": [
"nickname"
],
"properties": {
"nickname": {
"type": "string"
}
}
},
"user.CheckNicknameView": {
"type": "object",
"properties": {
"isAvailable": {
"type": "boolean"
}
}
},
"user.FindUserResponse": {
"type": "object",
"properties": {
Expand Down Expand Up @@ -731,7 +783,7 @@ const docTemplate = `{

// SwaggerInfo holds exported Swagger Info so clients can modify it
var SwaggerInfo = &swag.Spec{
Version: "0.4.0",
Version: "0.5.0",
Host: "",
BasePath: "/api",
Schemes: []string{},
Expand Down
54 changes: 53 additions & 1 deletion pkg/docs/swagger.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
"name": "Apache 2.0",
"url": "http://www.apache.org/licenses/LICENSE-2.0.html"
},
"version": "0.4.0"
"version": "0.5.0"
},
"basePath": "/api",
"paths": {
Expand Down Expand Up @@ -186,6 +186,39 @@
}
}
},
"/users/check/nickname": {
"post": {
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"users"
],
"summary": "닉네임 중복 여부를 조회합니다.",
"parameters": [
{
"description": "사용자 닉네임 중복 조회 요청",
"name": "request",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/user.CheckNicknameRequest"
}
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"$ref": "#/definitions/user.CheckNicknameView"
}
}
}
}
},
"/users/me": {
"get": {
"security": [
Expand Down Expand Up @@ -544,6 +577,25 @@
}
}
},
"user.CheckNicknameRequest": {
"type": "object",
"required": [
"nickname"
],
"properties": {
"nickname": {
"type": "string"
}
}
},
"user.CheckNicknameView": {
"type": "object",
"properties": {
"isAvailable": {
"type": "boolean"
}
}
},
"user.FindUserResponse": {
"type": "object",
"properties": {
Expand Down
35 changes: 34 additions & 1 deletion pkg/docs/swagger.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,18 @@ definitions:
weight_in_kg:
type: number
type: object
user.CheckNicknameRequest:
properties:
nickname:
type: string
required:
- nickname
type: object
user.CheckNicknameView:
properties:
isAvailable:
type: boolean
type: object
user.FindUserResponse:
properties:
email:
Expand Down Expand Up @@ -258,7 +270,7 @@ info:
url: http://www.apache.org/licenses/LICENSE-2.0.html
termsOfService: http://swagger.io/terms/
title: 이웃집멍냥 API 문서
version: 0.4.0
version: 0.5.0
paths:
/auth/callback/kakao:
get:
Expand Down Expand Up @@ -370,6 +382,27 @@ paths:
summary: 파이어베이스 가입 이후 정보를 입력 받아 유저를 생성합니다.
tags:
- users
/users/check/nickname:
post:
consumes:
- application/json
parameters:
- description: 사용자 닉네임 중복 조회 요청
in: body
name: request
required: true
schema:
$ref: '#/definitions/user.CheckNicknameRequest'
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/user.CheckNicknameView'
summary: 닉네임 중복 여부를 조회합니다.
tags:
- users
/users/me:
get:
produces:
Expand Down

0 comments on commit 5638b5c

Please sign in to comment.