Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat/#148 user update #175

Merged
merged 4 commits into from
Feb 26, 2024
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
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,12 @@
import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE;

import io.oeid.mogakgo.core.properties.swagger.error.SwaggerUserErrorExamples;
import io.oeid.mogakgo.domain.user.presentation.dto.req.UserSignUpApiRequest;
import io.oeid.mogakgo.domain.user.presentation.dto.req.UserSignUpApiReq;
import io.oeid.mogakgo.domain.user.presentation.dto.req.UserUpdateApiReq;
import io.oeid.mogakgo.domain.user.presentation.dto.res.UserDevelopLanguageApiRes;
import io.oeid.mogakgo.domain.user.presentation.dto.res.UserPublicApiResponse;
import io.oeid.mogakgo.domain.user.presentation.dto.res.UserSignUpApiResponse;
import io.oeid.mogakgo.domain.user.presentation.dto.res.UserUpdateApiRes;
import io.oeid.mogakgo.exception.dto.ErrorResponse;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
Expand Down Expand Up @@ -43,7 +45,7 @@ public interface UserSwagger {
})
ResponseEntity<UserSignUpApiResponse> userSignUpApi(
@Parameter(hidden = true) Long userId,
UserSignUpApiRequest apiRequest);
UserSignUpApiReq apiRequest);

@Operation(summary = "νšŒμ› μ‚­μ œ", description = "νšŒμ›μ„ μ‚­μ œν•  λ•Œ μ‚¬μš©ν•˜λŠ” API")
@ApiResponses(value = {
Expand Down Expand Up @@ -80,4 +82,27 @@ ResponseEntity<UserSignUpApiResponse> userSignUpApi(
})
ResponseEntity<List<UserDevelopLanguageApiRes>> userDevelopLanguageApi(
@Parameter(hidden = true) Long userId);


@Operation(summary = "νšŒμ› 정보 μˆ˜μ •", description = "νšŒμ› 정보λ₯Ό μˆ˜μ •ν•  λ•Œ μ‚¬μš©ν•˜λŠ” API")
@ApiResponses(value = {
@ApiResponse(responseCode = "200", description = "νšŒμ› 정보 μˆ˜μ • 성곡",
content = @Content(schema = @Schema(implementation = UserUpdateApiRes.class))),
@ApiResponse(responseCode = "400", description = "μš”μ²­ν•œ 데이터가 μœ νš¨ν•˜μ§€ μ•ŠμŒ",
content = @Content(
mediaType = APPLICATION_JSON_VALUE,
schema = @Schema(implementation = ErrorResponse.class),
examples = {
@ExampleObject(name = "E020103", value = SwaggerUserErrorExamples.INVALID_USER_NAME),
@ExampleObject(name = "E020105", value = SwaggerUserErrorExamples.USER_WANTED_JOB_DUPLICATE),
@ExampleObject(name = "E020109", value = SwaggerUserErrorExamples.USER_AVATAR_URL_NOT_NULL)
})),
@ApiResponse(responseCode = "404", description = "ν•΄λ‹Ή μœ μ €κ°€ μ‘΄μž¬ν•˜μ§€ μ•ŠμŒ",
content = @Content(
mediaType = APPLICATION_JSON_VALUE,
schema = @Schema(implementation = ErrorResponse.class),
examples = @ExampleObject(name = "E020301", value = SwaggerUserErrorExamples.USER_NOT_FOUND))),
})
ResponseEntity<UserUpdateApiRes> userUpdateApi(@Parameter(hidden = true) Long userId,
UserUpdateApiReq request);
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ public class SwaggerUserErrorExamples {
public static final String INVALID_USER_NAME = "{\"timestamp\":\"2024-02-17T10:07:31.404Z\",\"statusCode\":400,\"code\":\"E020103\",\"message\":\"μœ μ € 이름은 λΉ„μ–΄μžˆμ„ 수 μ—†μŠ΅λ‹ˆλ‹€.\"}";
public static final String USER_AVAILABLE_LIKE_COUNT_IS_ZERO = "{\"timestamp\":\"2024-02-17T10:07:31.404Z\",\"statusCode\":400,\"code\":\"E020107\",\"message\":\"당일 μ‚¬μš© κ°€λŠ₯ν•œ μ°”λŸ¬λ³΄κΈ° μš”μ²­μ„ λͺ¨λ‘ μ†Œμ§„ν–ˆμŠ΅λ‹ˆλ‹€.\"}";
public static final String USER_AVAILABLE_LIKE_COUNT_IS_FULL = "{\"timestamp\":\"2024-02-17T10:07:31.404Z\",\"statusCode\":400,\"code\":\"E020108\",\"message\":\"당일 μ‚¬μš© κ°€λŠ₯ν•œ μ°”λŸ¬λ³΄κΈ° μ΅œλŒ€ μš”μ²­ 횟수λ₯Ό μ΄ˆκ³Όν™œ 수 μ—†μŠ΅λ‹ˆλ‹€.\"}";

public static final String USER_AVATAR_URL_NOT_NULL = "{\"timestamp\":\"2024-02-17T10:07:31.404Z\",\"statusCode\":400,\"code\":\"E020109\",\"message\":\"μœ μ € ν”„λ‘œν•„ μ΄λ―Έμ§€λŠ” λΉ„μ–΄μžˆμ„ 수 μ—†μŠ΅λ‹ˆλ‹€.\"}";
private SwaggerUserErrorExamples() {
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package io.oeid.mogakgo.domain.achievement.infrastructure;

import io.oeid.mogakgo.domain.achievement.domain.Achievement;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

@Repository
public interface AchievementJpaRepository extends JpaRepository<Achievement, Long> {

}
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,17 @@

import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotBlank;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;

@Schema(description = "FCM 토큰 등둝 μš”μ²­")
@Getter
@AllArgsConstructor(access = AccessLevel.PRIVATE)
@AllArgsConstructor
@NoArgsConstructor
public class FCMTokenApiRequest {

@Schema(description = "FCM 토큰", example = "d4774fVVUuS3wdHHnGMYEj:APA91bFjQD6WXu8z5B0bliub661jwRshGvoCafMTYkm0cX9bZCbaUIa6ybycBT8WqkEN9j-qIYgFGB2zNnNosluquDhatUZmpbst87qo0oT8P2Id39xtWV0jhXpwSdIoLyZtdD0G9s5f", implementation = String.class, type = "string")
@NotBlank(message = "FCM 토큰은 ν•„μˆ˜μž…λ‹ˆλ‹€.")
private final String fcmToken;
private String fcmToken;
}
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
package io.oeid.mogakgo.domain.user.application;

import io.oeid.mogakgo.domain.achievement.domain.Achievement;
import io.oeid.mogakgo.domain.achievement.infrastructure.AchievementJpaRepository;
import io.oeid.mogakgo.domain.profile.application.ProfileCardService;
import io.oeid.mogakgo.domain.profile.application.dto.req.UserProfileCardReq;
import io.oeid.mogakgo.domain.user.application.dto.req.UserSignUpRequest;
import io.oeid.mogakgo.domain.user.application.dto.req.UserUpdateReq;
import io.oeid.mogakgo.domain.user.application.dto.res.UserDevelopLanguageRes;
import io.oeid.mogakgo.domain.user.application.dto.res.UserProfileResponse;
import io.oeid.mogakgo.domain.user.application.dto.res.UserSignUpResponse;
import io.oeid.mogakgo.domain.user.application.dto.res.UserUpdateRes;
import io.oeid.mogakgo.domain.user.domain.User;
import io.oeid.mogakgo.domain.user.domain.UserDevelopLanguageTag;
import io.oeid.mogakgo.domain.user.domain.UserWantedJobTag;
Expand Down Expand Up @@ -34,6 +38,7 @@ public class UserService {
private final UserWantedJobTagJpaRepository userWantedJobTagRepository;
private final UserDevelopLanguageTagJpaRepository userDevelopLanguageTagRepository;
private final UserGithubUtil userGithubUtil;
private final AchievementJpaRepository achievementRepository;

@Transactional
public UserSignUpResponse userSignUp(UserSignUpRequest userSignUpRequest) {
Expand Down Expand Up @@ -76,6 +81,24 @@ public UserProfileResponse getUserProfile(Long userId) {
return UserProfileResponse.from(user);
}

// TODO: 이후 AchievementException κ΅¬ν˜„ μ‹œ μΆ”κ°€ ν•„μš”!
public UserUpdateRes updateUserInfos(Long userId, UserUpdateReq request) {
User user = userCommonService.getUserById(userId);
Achievement achievement = achievementRepository.findById(request.getAchievementId())
.orElseThrow();
user.updateUserInfos(request.getUsername(), request.getAvatarUrl(), request.getBio(),
achievement);
validateWantedJobDuplicate(request.getWantedJobs());
for (WantedJob wantedJob : request.getWantedJobs()) {
userWantedJobTagRepository.save(UserWantedJobTag.builder()
.user(user)
.wantedJob(wantedJob)
.build());
}
profileCardService.create(UserProfileCardReq.of(user));
return UserUpdateRes.from(user);
}

@Transactional
public void deleteUser(Long userId) {
User user = userCommonService.getUserById(userId);
Expand All @@ -89,11 +112,5 @@ private void validateWantedJobDuplicate(List<WantedJob> wantedJobs) {
}
}

private void validateDevelopLanguageDuplicate(List<DevelopLanguage> developLanguages) {
Set<DevelopLanguage> developLanguageSet = new HashSet<>(developLanguages);
if (developLanguageSet.size() != developLanguages.size()) {
throw new UserException(ErrorCode400.USER_DEVELOP_LANGUAGE_DUPLICATE);
}
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package io.oeid.mogakgo.domain.user.application.dto.req;

import io.oeid.mogakgo.domain.user.domain.enums.WantedJob;
import io.oeid.mogakgo.domain.user.presentation.dto.req.UserUpdateApiReq;
import java.util.List;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Getter;

@Getter
@AllArgsConstructor(access = AccessLevel.PRIVATE)
public class UserUpdateReq {

private final String username;
private final String bio;
private final String avatarUrl;
private List<WantedJob> wantedJobs;
private final Long achievementId;

public static UserUpdateReq from(UserUpdateApiReq request) {
return new UserUpdateReq(
request.getUsername(),
request.getBio(),
request.getAvatarUrl(),
request.getWantedJobs().stream().map(WantedJob::valueOf).toList(),
request.getAchievementId()
);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package io.oeid.mogakgo.domain.user.application.dto.res;

import io.oeid.mogakgo.domain.user.domain.User;
import io.oeid.mogakgo.domain.user.domain.UserWantedJobTag;
import io.oeid.mogakgo.domain.user.domain.enums.WantedJob;
import java.util.List;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Getter;

@Getter
@AllArgsConstructor(access = AccessLevel.PRIVATE)
public class UserUpdateRes {
private String username;
private String bio;
private String avatarUrl;
private List<WantedJob> wantedJobs;
private Long achievementId;

public static UserUpdateRes from(User user){
return new UserUpdateRes(
user.getUsername(),
user.getBio(),
user.getAvatarUrl(),
user.getUserWantedJobTags().stream().map(UserWantedJobTag::getWantedJob).toList(),
user.getAchievement().getId()
);
}
}
19 changes: 19 additions & 0 deletions src/main/java/io/oeid/mogakgo/domain/user/domain/User.java
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,14 @@ public void updateRegion(Region region) {
}
}

public void updateUserInfos(String username, String avatarUrl, String bio, Achievement achievement) {
updateUsername(username);
this.avatarUrl = verifyAvatarUrl(avatarUrl);
this.bio = bio;
this.achievement = achievement;
deleteAllWantJobTags();
}

//TODO : μΆ”ν›„ κ΅¬ν˜„ ν•„μš”
public void decreaseJandiRate() {
return;
Expand All @@ -208,4 +216,15 @@ public void decreaseJandiRate() {
private boolean validateAvailableRegionUpdate(Region region) {
return this.region == null || !this.region.equals(region);
}

private String verifyAvatarUrl(String avatarUrl) {
if (avatarUrl == null || avatarUrl.isBlank()) {
throw new UserException(ErrorCode400.USER_AVATAR_URL_NOT_NULL);
}
return avatarUrl;
}




}
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,13 @@
import io.oeid.mogakgo.common.annotation.UserId;
import io.oeid.mogakgo.common.swagger.template.UserSwagger;
import io.oeid.mogakgo.domain.user.application.UserService;
import io.oeid.mogakgo.domain.user.presentation.dto.req.UserSignUpApiRequest;
import io.oeid.mogakgo.domain.user.application.dto.req.UserUpdateReq;
import io.oeid.mogakgo.domain.user.presentation.dto.req.UserSignUpApiReq;
import io.oeid.mogakgo.domain.user.presentation.dto.req.UserUpdateApiReq;
import io.oeid.mogakgo.domain.user.presentation.dto.res.UserDevelopLanguageApiRes;
import io.oeid.mogakgo.domain.user.presentation.dto.res.UserPublicApiResponse;
import io.oeid.mogakgo.domain.user.presentation.dto.res.UserSignUpApiResponse;
import io.oeid.mogakgo.domain.user.presentation.dto.res.UserUpdateApiRes;
import jakarta.validation.Valid;
import java.util.List;
import lombok.RequiredArgsConstructor;
Expand All @@ -31,20 +34,27 @@ public ResponseEntity<UserPublicApiResponse> userGetApi(@UserId Long userId) {
return ResponseEntity.ok(UserPublicApiResponse.fromByUserProfile(response));
}

@PatchMapping("/sign")
public ResponseEntity<UserSignUpApiResponse> userSignUpApi(@UserId Long userId,
@RequestBody @Valid UserSignUpApiRequest apiRequest) {
var response = userService.userSignUp(apiRequest.toRequest(userId));
return ResponseEntity.ok(UserSignUpApiResponse.from(response));
}

@GetMapping("/develop-language")
public ResponseEntity<List<UserDevelopLanguageApiRes>> userDevelopLanguageApi(
@UserId Long userId) {
var response = userService.updateUserDevelopLanguages(userId);
return ResponseEntity.ok(response.stream().map(UserDevelopLanguageApiRes::from).toList());
}

@PatchMapping
public ResponseEntity<UserUpdateApiRes> userUpdateApi(@UserId Long userId,
@RequestBody @Valid UserUpdateApiReq request) {
var result = userService.updateUserInfos(userId, UserUpdateReq.from(request));
return ResponseEntity.ok(UserUpdateApiRes.from(result));
}

@PatchMapping("/sign")
public ResponseEntity<UserSignUpApiResponse> userSignUpApi(@UserId Long userId,
@RequestBody @Valid UserSignUpApiReq apiRequest) {
var response = userService.userSignUp(apiRequest.toRequest(userId));
return ResponseEntity.ok(UserSignUpApiResponse.from(response));
}

@DeleteMapping
public ResponseEntity<Void> userDeleteApi(@UserId Long userId) {
userService.deleteUser(userId);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
@Getter
@AllArgsConstructor
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class UserSignUpApiRequest {
public class UserSignUpApiReq {

@Schema(description = "νšŒμ›λͺ…", example = "거루", implementation = String.class)
@NotBlank(message = "username은 ν•„μˆ˜μž…λ‹ˆλ‹€.")
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package io.oeid.mogakgo.domain.user.presentation.dto.req;

import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Size;
import java.util.List;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import org.hibernate.validator.constraints.URL;

@Schema(description = "μœ μ € 정보 μˆ˜μ • μš”μ²­")
@Getter
@NoArgsConstructor
@AllArgsConstructor
public class UserUpdateApiReq {

@Schema(description = "μœ μ € 이름", example = "tidavid1")
@NotBlank
private String username;
@Schema(description = "μœ μ € μ†Œκ°œ", example = "μ•ˆλ…•ν•˜μ„Έμš”", nullable = true)
private String bio;
@Schema(description = "μœ μ € ν”„λ‘œν•„ 이미지 URL", example = "https://avatars.githubusercontent.com/u/12345678?v=4")
@URL
private String avatarUrl;
@Schema(description = "μ„ ν˜Έν•˜λŠ” 직ꡰ", example = "[\"BACKEND\", \"FRONTEND\"]")
@Size(min = 1, max = 3)
private List<String> wantedJobs;
@Schema(description = "업적 ID", example = "1")
@NotNull
private Long achievementId;
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
public class UserSignUpApiResponse {

@Schema(description = "νšŒμ› ID", example = "1")
private Long userId;
private Long id;
@Schema(description = "νšŒμ› 이름", example = "거루")
private String username;
@Schema(description = "κΉƒν—ˆλΈŒ ID", example = "tidavid1")
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package io.oeid.mogakgo.domain.user.presentation.dto.res;

import io.oeid.mogakgo.domain.user.application.dto.res.UserUpdateRes;
import io.oeid.mogakgo.domain.user.domain.enums.WantedJob;
import io.swagger.v3.oas.annotations.media.Schema;
import java.util.List;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;

@Schema(description = "μœ μ € 정보 μˆ˜μ • 응닡")
@Getter
@AllArgsConstructor(access = AccessLevel.PRIVATE)
@NoArgsConstructor
public class UserUpdateApiRes {

@Schema(description = "μœ μ € 이름", example = "tidavid1")
private String username;
@Schema(description = "μœ μ € μ†Œκ°œ", example = "μ•ˆλ…•ν•˜μ„Έμš”")
private String bio;
@Schema(description = "μœ μ € ν”„λ‘œν•„ 이미지 URL", example = "https://avatars.githubusercontent.com/u/1?v=4")
private String avatarUrl;
@Schema(description = "μœ μ €κ°€ μ›ν•˜λŠ” 직ꡰ", example = "[\"BACKEND\", \"FRONTEND\"]")
private List<String> wantedJobs;
@Schema(description = "μœ μ €μ˜ 업적 ID", example = "1")
private Long achievementId;

public static UserUpdateApiRes from(UserUpdateRes userUpdateRes) {
return new UserUpdateApiRes(
userUpdateRes.getUsername(),
userUpdateRes.getBio(),
userUpdateRes.getAvatarUrl(),
userUpdateRes.getWantedJobs().stream().map(WantedJob::getJobName).toList(),
userUpdateRes.getAchievementId()
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ public enum ErrorCode400 implements ErrorCode {
USER_AVAILABLE_LIKE_COUNT_IS_ZERO("E020107", "당일 μ‚¬μš©ν•  수 μžˆλŠ” μ°”λŸ¬λ³΄κΈ° μš”μ²­μ„ λͺ¨λ‘ μ†Œμ§„ν–ˆμŠ΅λ‹ˆλ‹€."),
USER_AVAILABLE_LIKE_AMOUNT_IS_FULL("E020108", "ν”„λ‘œν•„ μΉ΄λ“œμ˜ μ°”λŸ¬λ³΄κΈ° μš”μ²­μ˜ μ΅œλŒ€ 횟수λ₯Ό λ„˜μ„ 수 μ—†μŠ΅λ‹ˆλ‹€."),
USER_ID_NOT_NULL("E020001", "μœ μ € μ•„μ΄λ””λŠ” ν•„μˆ˜κ°’μž…λ‹ˆλ‹€."),
USER_AVATAR_URL_NOT_NULL("E020109", "μœ μ € ν”„λ‘œν•„ μ΄λ―Έμ§€λŠ” ν•„μˆ˜κ°’μž…λ‹ˆλ‹€."),

PROFILE_CARD_LIKE_ALREADY_EXIST("E040102", "이미 μ°”λŸ¬λ³΄κΈ° μš”μ²­μ„ μ „μ†‘ν•œ ν”„λ‘œν•„ μΉ΄λ“œμ— μ°”λŸ¬λ³΄κΈ° μš”μ²­μ„ 전솑할 수 μ—†μŠ΅λ‹ˆλ‹€."),
INVALID_PROFILE_CARD_LIKE_RECEIVER_INFO("E040103", "μ°”λŸ¬λ³΄κΈ° μš”μ²­μ˜ μ‚¬μš©μžκ°€ μ‘΄μž¬ν•˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€."),
Expand Down
Loading