Skip to content

Commit

Permalink
Merge pull request #13 from begin-a-gain/feat/#8
Browse files Browse the repository at this point in the history
fix: modify nickname validation
  • Loading branch information
jioome authored Oct 6, 2024
2 parents ba3d5fd + 7b1749a commit f6524eb
Show file tree
Hide file tree
Showing 8 changed files with 139 additions and 79 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
package begin_a_gain.omokwang.nickname.application;

import begin_a_gain.omokwang.exception.CustomException;
import begin_a_gain.omokwang.exception.ErrorCode;
import begin_a_gain.omokwang.nickname.domain.NicknameUpdateDto;
import begin_a_gain.omokwang.user.dto.User;
import begin_a_gain.omokwang.user.repository.UserRepository;
import java.util.Optional;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@RequiredArgsConstructor
@Service
public class NicknameService {
private static final String INVALID_NICKNAME_MESSAGE = "Invalid nickname: Must be 2-10 characters long and cannot include special characters.";
private static final String NICKNAME_TAKEN_MESSAGE = "Nickname already taken.";

private final UserRepository userRepository;

@Transactional(readOnly = true)
public boolean isNicknameTaken(String nickname) {
return userRepository.existsByNickname(nickname);
}

public boolean isInvalidNickname(String nickname) {
String nicknamePattern = "^[a-zA-Z0-9가-힣]{2,10}$";
return !nickname.matches(nicknamePattern);
}

@Transactional
public void updateNickname(NicknameUpdateDto nicknameUpdateParam) {
long socialId = nicknameUpdateParam.getSocialId();
User user = userRepository.findBySocialId(socialId)
.orElseThrow(() -> new CustomException(ErrorCode.USER_NOT_FOUND));

String nickname = nicknameUpdateParam.getNickname();
user.setNickname(nickname);

userRepository.save(user);
}

public Optional<String> validateNickname(String nickname) {
if (isInvalidNickname(nickname)) {
return Optional.of(INVALID_NICKNAME_MESSAGE);
}

if (isNicknameTaken(nickname)) {
return Optional.of(NICKNAME_TAKEN_MESSAGE);
}

return Optional.empty(); // 닉네임이 유효하고 사용 가능함을 의미
}

public boolean isSignUpComplete(long socialId) {
return userRepository.existsNicknameBySocialId(socialId);
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package begin_a_gain.omokwang.user.dto;
package begin_a_gain.omokwang.nickname.domain;

import lombok.AllArgsConstructor;
import lombok.Getter;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package begin_a_gain.omokwang.user.dto;
package begin_a_gain.omokwang.nickname.dto;

import lombok.AllArgsConstructor;
import lombok.Getter;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package begin_a_gain.omokwang.nickname.dto;

import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;

@Getter
@AllArgsConstructor
@NoArgsConstructor
public class NicknameValidationResponse {
private boolean validNickname;
private boolean isSignupComplete;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
package begin_a_gain.omokwang.nickname.ui;

import begin_a_gain.omokwang.auth.utils.SecurityUtil;
import begin_a_gain.omokwang.nickname.application.NicknameService;
import begin_a_gain.omokwang.nickname.domain.NicknameUpdateDto;
import begin_a_gain.omokwang.nickname.dto.NicknameRequest;
import begin_a_gain.omokwang.nickname.dto.NicknameValidationResponse;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.responses.ApiResponses;
import io.swagger.v3.oas.annotations.tags.Tag;
import java.util.Optional;
import lombok.RequiredArgsConstructor;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PatchMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;

@Tag(name = "Nickname", description = "Nickname API")
@RestController
@RequiredArgsConstructor
public class NicknameController {
private final NicknameService nicknameService;

@Operation(summary = "Check nickname availability", description = "Checks if the provided nickname is valid and available.")
@ApiResponses(value = {
@ApiResponse(responseCode = "200", description = "Nickname is valid and available",
content = @Content(schema = @Schema(implementation = NicknameValidationResponse.class))),
@ApiResponse(responseCode = "400", description = "Invalid nickname or nickname already taken", content = @Content)
})
@PostMapping("/validations/nicknames")
public ResponseEntity<?> checkNickname(@RequestBody NicknameRequest nicknameRequest) {
Optional<String> validationError = nicknameService.validateNickname(nicknameRequest.getNickname());

final long socialId = SecurityUtil.getCurrentUserId();
boolean isSignUpComplete = nicknameService.isSignUpComplete(socialId);
return validationError
.map(error -> ResponseEntity.badRequest().body((Object) error)) // 명시적으로 Object로 캐스팅
.orElseGet(() -> {
NicknameValidationResponse response = new NicknameValidationResponse(true,
isSignUpComplete);
return ResponseEntity.ok(response);
});
}

@Operation(summary = "Update user nickname", description = "nickname 업데이트.")
@ApiResponses(value = {
@ApiResponse(responseCode = "200", description = "Nickname updated successfully")
})
@PatchMapping("/nickname")
public ResponseEntity<String> updateNickname(@RequestBody NicknameRequest nicknameRequest) {
final long userId = SecurityUtil.getCurrentUserId();
String nickname = nicknameRequest.getNickname();
NicknameUpdateDto nicknameUpdateParam = new NicknameUpdateDto(userId, nickname);

nicknameService.updateNickname(nicknameUpdateParam);
return ResponseEntity.ok("Nickname updated.");

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,23 +3,15 @@
import begin_a_gain.omokwang.auth.utils.SecurityUtil;
import begin_a_gain.omokwang.exception.CustomException;
import begin_a_gain.omokwang.exception.ErrorCode;
import begin_a_gain.omokwang.user.dto.NicknameRequest;
import begin_a_gain.omokwang.user.dto.NicknameUpdateDto;
import begin_a_gain.omokwang.user.dto.User;
import begin_a_gain.omokwang.user.service.UserService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.responses.ApiResponses;
import io.swagger.v3.oas.annotations.tags.Tag;
import java.util.Optional;
import lombok.RequiredArgsConstructor;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PatchMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

Expand All @@ -41,34 +33,4 @@ public User info() {
return userService.findBySocialId(userId)
.orElseThrow(() -> new CustomException(ErrorCode.NOT_EXIST_USER));
}

@Operation(summary = "Check nickname availability", description = "Checks if the provided nickname is valid and available.")
@ApiResponses(value = {
@ApiResponse(responseCode = "200", description = "Nickname is valid and available",
content = @Content(schema = @Schema(implementation = NicknameRequest.class))),
@ApiResponse(responseCode = "400", description = "Invalid nickname or nickname already taken", content = @Content)
})
@PostMapping("/validations/nicknames")
public ResponseEntity<String> checkNickname(@RequestBody NicknameRequest nicknameRequest) {
Optional<String> validationError = userService.validateNickname(nicknameRequest.getNickname());

return validationError.map(x -> ResponseEntity.badRequest().body(x))
.orElseGet(() -> ResponseEntity.ok("Nickname is valid and available."));

}

@Operation(summary = "Update user nickname", description = "nickname 업데이트.")
@ApiResponses(value = {
@ApiResponse(responseCode = "200", description = "Nickname updated successfully")
})
@PatchMapping("/nickname")
public ResponseEntity<String> updateNickname(@RequestBody NicknameRequest nicknameRequest) {
final long userId = SecurityUtil.getCurrentUserId();
String nickname = nicknameRequest.getNickname();
NicknameUpdateDto nicknameUpdateParam = new NicknameUpdateDto(userId, nickname);

userService.updateNickname(nicknameUpdateParam);
return ResponseEntity.ok("Nickname updated.");

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,4 +23,7 @@ public interface UserRepository extends JpaRepository<User, Long> {
@Modifying
@Query("UPDATE User u SET u.refreshToken = :refreshToken WHERE u.socialId = :socialId")
void updateRefreshToken(@Param("socialId") Long socialId, @Param("refreshToken") String refreshToken);

@Query("SELECT CASE WHEN u.nickname IS NULL THEN false ELSE true END FROM User u WHERE u.socialId = :socialId")
boolean existsNicknameBySocialId(@Param("socialId") Long socialId);
}
39 changes: 0 additions & 39 deletions src/main/java/begin_a_gain/omokwang/user/service/UserService.java
Original file line number Diff line number Diff line change
@@ -1,20 +1,14 @@
package begin_a_gain.omokwang.user.service;

import begin_a_gain.omokwang.exception.CustomException;
import begin_a_gain.omokwang.exception.ErrorCode;
import begin_a_gain.omokwang.user.dto.NicknameUpdateDto;
import begin_a_gain.omokwang.user.dto.User;
import begin_a_gain.omokwang.user.repository.UserRepository;
import java.util.Optional;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@RequiredArgsConstructor
@Service
public class UserService {
private static final String INVALID_NICKNAME_MESSAGE = "Invalid nickname: Must be 2-10 characters long and cannot include special characters.";
private static final String NICKNAME_TAKEN_MESSAGE = "Nickname already taken.";

private final UserRepository userRepository;

Expand Down Expand Up @@ -44,37 +38,4 @@ public Optional<User> findBySocialIdAndPlatform(Long socialId, String platform)
return userRepository.findBySocialIdAndPlatform(socialId, platform);
}

@Transactional(readOnly = true)
public boolean isNicknameTaken(String nickname) {
return userRepository.existsByNickname(nickname);
}

public boolean isInvalidNickname(String nickname) {
String nicknamePattern = "^[a-zA-Z0-9가-힣]{2,10}$";
return !nickname.matches(nicknamePattern);
}

@Transactional
public void updateNickname(NicknameUpdateDto nicknameUpdateParam) {
long socialId = nicknameUpdateParam.getSocialId();
User user = userRepository.findBySocialId(socialId)
.orElseThrow(() -> new CustomException(ErrorCode.USER_NOT_FOUND));

String nickname = nicknameUpdateParam.getNickname();
user.setNickname(nickname);

userRepository.save(user);
}

public Optional<String> validateNickname(String nickname) {
if (isInvalidNickname(nickname)) {
return Optional.of(INVALID_NICKNAME_MESSAGE);
}

if (isNicknameTaken(nickname)) {
return Optional.of(NICKNAME_TAKEN_MESSAGE);
}

return Optional.empty(); // 닉네임이 유효하고 사용 가능함을 의미
}
}

0 comments on commit f6524eb

Please sign in to comment.