Skip to content

Commit

Permalink
add username API
Browse files Browse the repository at this point in the history
  • Loading branch information
le-xuan-quynh committed May 4, 2022
1 parent 7d73bf5 commit 33f2ada
Show file tree
Hide file tree
Showing 8 changed files with 120 additions and 0 deletions.
10 changes: 10 additions & 0 deletions internal/database/postgres-repository.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,16 @@ func (repo *postgresRepository) UpdateUserVerificationStatus(ctx context.Context
return nil
}

// CheckUsernameExists checks if the given username exists in the database.
func (repo *postgresRepository) CheckUsernameExists(ctx context.Context, username string) (bool, error) {
query := "select count(*) from users where username = $1"
var count int
if err := repo.db.GetContext(ctx, &count, query, username); err != nil {
return false, err
}
return count > 0, nil
}

// StoreVerificationData adds a mail verification data to db
func (repo *postgresRepository) StoreVerificationData(ctx context.Context, verificationData *VerificationData, isInsert bool) error {
if isInsert {
Expand Down
2 changes: 2 additions & 0 deletions internal/database/repository.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ type UserRepository interface {
GetUserByID(ctx context.Context, id string) (*User, error)
// UpdateUser Update user
UpdateUser(ctx context.Context, user *User) error
// CheckUsernameExists Check if username exists
CheckUsernameExists(ctx context.Context, username string) (bool, error)
// GetProfileByID Get profile by user id
GetProfileByID(ctx context.Context, userId string) (*ProfileData, error)
// UpdateProfile Update profile
Expand Down
6 changes: 6 additions & 0 deletions internal/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ const (
ValidationTokenFailure = 18
ExistUser = 19
CodeInvalid = 20
UsernameRequired = 21
ExistUserName = 22
)

func (e ErrorResponse) Error() string {
Expand Down Expand Up @@ -100,6 +102,10 @@ func (e ErrorResponse) Error() string {
return "User already exists"
case CodeInvalid:
return "Verify code invalid"
case UsernameRequired:
return "Username required"
case ExistUserName:
return "Username already exists"
default:
return "Unknown Error"
}
Expand Down
23 changes: 23 additions & 0 deletions pkg/authorization/endpoints/endpoints.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ type Set struct {
LoginEndpoint endpoint.Endpoint
LogoutEndpoint endpoint.Endpoint
GetUserEndpoint endpoint.Endpoint
UpdateUserNameEndpoint endpoint.Endpoint
GetProfileEndpoint endpoint.Endpoint
UpdateProfileEndpoint endpoint.Endpoint
UpdatePasswordEndpoint endpoint.Endpoint
Expand Down Expand Up @@ -59,6 +60,11 @@ func NewEndpointSet(svc authorization.Service,
getUserEndpoint = middleware.ValidateParamRequest(validator, logger)(getUserEndpoint)
getUserEndpoint = middleware.ValidateAccessToken(auth, logger)(getUserEndpoint)

updateUserNameEndpoint := MakeUpdateUserNameEndpoint(svc)
updateUserNameEndpoint = middleware.RateLimitRequest(tb, logger)(updateUserNameEndpoint)
updateUserNameEndpoint = middleware.ValidateParamRequest(validator, logger)(updateUserNameEndpoint)
updateUserNameEndpoint = middleware.ValidateAccessToken(auth, logger)(updateUserNameEndpoint)

getProfileEndpoint := MakeGetProfileEndpoint(svc)
getProfileEndpoint = middleware.RateLimitRequest(tb, logger)(getProfileEndpoint)
getProfileEndpoint = middleware.ValidateParamRequest(validator, logger)(getProfileEndpoint)
Expand Down Expand Up @@ -101,6 +107,7 @@ func NewEndpointSet(svc authorization.Service,
GetUserEndpoint: getUserEndpoint,
GetProfileEndpoint: getProfileEndpoint,
UpdateProfileEndpoint: updateProfileEndpoint,
UpdateUserNameEndpoint: updateUserNameEndpoint,
UpdatePasswordEndpoint: updatePasswordEndpoint,
GetForgetPasswordCodeEndpoint: getForgetPasswordCodeEndpoint,
ResetPasswordEndpoint: resetPasswordEndpoint,
Expand Down Expand Up @@ -213,6 +220,22 @@ func MakeGetUserEndpoint(svc authorization.Service) endpoint.Endpoint {
}
}

// MakeUpdateUserNameEndpoint returns an endpoint that invokes UpdateUserName on the service.
func MakeUpdateUserNameEndpoint(svc authorization.Service) endpoint.Endpoint {
return func(ctx context.Context, request interface{}) (interface{}, error) {
req, ok := request.(authorization.UpdateUserNameRequest)
if !ok {
cusErr := utils.NewErrorResponse(utils.BadRequest)
return nil, cusErr
}
user, err := svc.UpdateUserName(ctx, &req)
if err != nil {
return nil, err
}
return user, nil
}
}

// MakeGetProfileEndpoint returns an endpoint that invokes GetProfile on the service.
func MakeGetProfileEndpoint(svc authorization.Service) endpoint.Endpoint {
return func(ctx context.Context, request interface{}) (interface{}, error) {
Expand Down
6 changes: 6 additions & 0 deletions pkg/authorization/reqresponse.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,12 @@ type GetUserRequest struct {
AccessToken string `json:"access_token" validate:"required"`
}

// UpdateUserNameRequest is used to update user name
type UpdateUserNameRequest struct {
AccessToken string `json:"access_token" validate:"required"`
Username string `json:"username" validate:"required"`
}

// GetProfileRequest is used to get user profile
type GetProfileRequest struct {
AccessToken string `json:"access_token" validate:"required"`
Expand Down
1 change: 1 addition & 0 deletions pkg/authorization/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ type Service interface {
Login(ctx context.Context, request *LoginRequest) (interface{}, error)
Logout(ctx context.Context, request *LogoutRequest) error
GetUser(ctx context.Context) (interface{}, error)
UpdateUserName(ctx context.Context, request *UpdateUserNameRequest) (interface{}, error)
GetProfile(ctx context.Context) (interface{}, error)
UpdateProfile(ctx context.Context, request *UpdateProfileRequest) (interface{}, error)
UpdatePassword(ctx context.Context, request *UpdatePasswordRequest) (string, error)
Expand Down
28 changes: 28 additions & 0 deletions pkg/authorization/transport/http.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,13 @@ func NewHTTPHandler(ep endpoints.Set) http.Handler {
encodeResponse,
options...,
))
m.Handle("/update-username", httptransport.NewServer(
ep.UpdateUserNameEndpoint,
decodeHTTPUpdateUsernameRequest,
encodeResponse,
options...,
))

m.Handle("/update-password", httptransport.NewServer(
ep.UpdatePasswordEndpoint,
decodeHTTPUpdatePasswordRequest,
Expand Down Expand Up @@ -242,6 +249,27 @@ func decodeHTTPUpdateProfileRequest(_ context.Context, r *http.Request) (interfa
}
}

// decodeHTTPUpdateUsernameRequest decode request
func decodeHTTPUpdateUsernameRequest(_ context.Context, r *http.Request) (interface{}, error) {
if r.Method == "POST" {
var req authorization.UpdateUserNameRequest
err := json.NewDecoder(r.Body).Decode(&req)
if err != nil {
return nil, utils.NewErrorResponse(utils.BadRequest)
}
if req.Username == "" {
return nil, utils.NewErrorResponse(utils.UsernameRequired)
}
if req.AccessToken == "" {
return nil, utils.NewErrorResponse(utils.AccessTokenRequired)
}
return req, nil
} else {
cusErr := utils.NewErrorResponse(utils.MethodNotAllowed)
return nil, cusErr
}
}

// decodeHTTPUpdatePasswordRequest decode request
func decodeHTTPUpdatePasswordRequest(_ context.Context, r *http.Request) (interface{}, error) {
if r.Method == "POST" {
Expand Down
44 changes: 44 additions & 0 deletions pkg/authorization/users-service.go
Original file line number Diff line number Diff line change
Expand Up @@ -393,6 +393,50 @@ func (s *userService) GetProfile(ctx context.Context) (interface{}, error) {
return profileResponse, nil
}

// UpdateUserName updates user name.
func (s *userService) UpdateUserName(ctx context.Context, request *UpdateUserNameRequest) (interface{}, error) {
userID, ok := ctx.Value(middleware.UserIDKey{}).(string)
if !ok {
s.logger.Error("Error getting userID from context")
cusErr := utils.NewErrorResponse(utils.InternalServerError)
return cusErr.Error(), cusErr
}
user, err := s.repo.GetUserByID(ctx, userID)
if err != nil {
s.logger.Error("Cannot get user", "error", err)
cusErr := utils.NewErrorResponse(utils.InternalServerError)
return cusErr.Error(), cusErr
}
// Check if user is banned
if user.Banned {
s.logger.Error("User is banned", "error", err)
cusErr := utils.NewErrorResponse(utils.Forbidden)
return cusErr.Error(), cusErr
}
// Check if username is already taken
if exist, err := s.repo.CheckUsernameExists(ctx, request.Username); exist || err != nil {
s.logger.Error("Username is already taken", "error", err)
cusErr := utils.NewErrorResponse(utils.ExistUserName)
return cusErr.Error(), cusErr
}
// Update user name
user.Username = request.Username
err = s.repo.UpdateUser(ctx, user)
if err != nil {
s.logger.Error("Cannot update user", "error", err)
cusErr := utils.NewErrorResponse(utils.InternalServerError)
return cusErr.Error(), cusErr
}
s.logger.Debug("Update user name success", "email", user.Email)
// Make response data
userResponse := GetUserResponse{
Email: user.Email,
Username: user.Username,
Verified: user.Verified,
}
return userResponse, nil
}

// UpdateProfile updates user profile.
func (s *userService) UpdateProfile(ctx context.Context, request *UpdateProfileRequest) (interface{}, error) {
userID, ok := ctx.Value(middleware.UserIDKey{}).(string)
Expand Down

0 comments on commit 33f2ada

Please sign in to comment.