Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/feature/9' into feature/9
Browse files Browse the repository at this point in the history
  • Loading branch information
jhsseonn committed Feb 10, 2024
2 parents 6d7e588 + 6f23115 commit 17c0c8d
Show file tree
Hide file tree
Showing 26 changed files with 947 additions and 50 deletions.
3 changes: 3 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,9 @@ dependencies {
// fcm
implementation 'com.google.firebase:firebase-admin:6.8.1'

// thymeleaf
implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'

// etc
implementation 'org.springframework.boot:spring-boot-starter-validation'
implementation 'org.springframework.boot:spring-boot-starter-web'
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package com.backend.blooming.admin.application;

import com.backend.blooming.admin.controller.dto.CreateUserRequest;
import com.backend.blooming.authentication.infrastructure.oauth.OAuthType;
import com.backend.blooming.themecolor.domain.ThemeColor;
import com.backend.blooming.user.domain.Email;
import com.backend.blooming.user.domain.Name;
import com.backend.blooming.user.domain.User;
import com.backend.blooming.user.infrastructure.repository.UserRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.UUID;

@Service
@Transactional
@RequiredArgsConstructor
public class AdminPageService {

private static final String DEFAULT_EMAIL = "[email protected]";
private final UserRepository userRepository;

public Long createUser(final CreateUserRequest request) {
final User user = User.builder()
.oAuthId(UUID.randomUUID().toString())
.oAuthType(OAuthType.KAKAO)
.name(new Name(request.name()))
.email(processEmail(request.email()))
.color(ThemeColor.valueOf(request.theme()))
.statusMessage(request.statusMessage())
.build();

return userRepository.save(user)
.getId();
}

private Email processEmail(final String email) {
if (email == null || email.isEmpty()) {
return new Email(DEFAULT_EMAIL);
}

return new Email(email);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
package com.backend.blooming.admin.controller;

import com.backend.blooming.admin.application.AdminPageService;
import com.backend.blooming.admin.controller.dto.CreateGoalRequest;
import com.backend.blooming.admin.controller.dto.CreateUserRequest;
import com.backend.blooming.admin.controller.dto.FriendStatus;
import com.backend.blooming.admin.controller.dto.RequestFriendRequest;
import com.backend.blooming.admin.controller.dto.UpdateFriendRequest;
import com.backend.blooming.admin.controller.exception.InvalidFriendStatusException;
import com.backend.blooming.friend.application.FriendService;
import com.backend.blooming.friend.application.exception.NotFoundFriendRequestException;
import com.backend.blooming.friend.infrastructure.repository.FriendRepository;
import com.backend.blooming.goal.application.GoalService;
import com.backend.blooming.goal.application.dto.CreateGoalDto;
import com.backend.blooming.themecolor.domain.ThemeColor;
import com.backend.blooming.user.domain.User;
import com.backend.blooming.user.infrastructure.repository.UserRepository;
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import org.springframework.context.annotation.Profile;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
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 java.util.Arrays;
import java.util.List;

@Profile("test | local | dev")
@Controller
@RequestMapping("/admin")
@RequiredArgsConstructor
public class AdminPageController {

private final AdminPageService adminPageService;
private final UserRepository userRepository;
private final FriendService friendService;
private final FriendRepository friendRepository;
private final GoalService goalService;

@GetMapping
public String adminPage(final Model model) {
model.addAttribute("themes", getThemes());
model.addAttribute("users", getUsers());

return "admin/test";
}

private static List<String> getThemes() {
return Arrays.stream(ThemeColor.values())
.map(ThemeColor::name)
.toList();
}

private List<User> getUsers() {
return userRepository.findAll();
}

@PostMapping("/user")
public ResponseEntity<Void> createUser(@RequestBody @Valid CreateUserRequest request) {
adminPageService.createUser(request);

return ResponseEntity.noContent()
.build();
}

@PostMapping("/friend")
public ResponseEntity<Void> requestFriend(@RequestBody RequestFriendRequest request) {
friendService.request(request.requestUser(), request.requestedUser());

return ResponseEntity.noContent()
.build();
}

@PatchMapping("/friend")
public ResponseEntity<Void> updateFriendStatus(@RequestBody UpdateFriendRequest request) {
final Long friendId = getFriendId(request);
updateByStatus(request, friendId);

return ResponseEntity.noContent()
.build();
}

private Long getFriendId(final UpdateFriendRequest request) {
final Long friendId = friendRepository.findByRequestUserIdAndRequestedUserId(
request.requestUser(),
request.requestedUser()
);

if (friendId == null) {
throw new NotFoundFriendRequestException();
}

return friendId;
}

private void updateByStatus(final UpdateFriendRequest request, final Long friendId) {
final FriendStatus friendStatus = FriendStatus.valueOf(request.status());

if (FriendStatus.FRIEND.equals(friendStatus)) {
friendService.accept(request.requestedUser(), friendId);
return;
}
if (FriendStatus.DELETE_BY_REQUEST.equals(friendStatus)) {
friendService.delete(request.requestUser(), friendId);
return;
}
if (FriendStatus.DELETE_BY_REQUESTED.equals(friendStatus)) {
friendService.delete(request.requestedUser(), friendId);
return;
}

throw new InvalidFriendStatusException();
}

@PostMapping("/goal")
public ResponseEntity<Void> createGoal(@RequestBody @Valid CreateGoalRequest request) {
goalService.createGoal(convertToDto(request));

return ResponseEntity.noContent()
.build();
}

private CreateGoalDto convertToDto(final CreateGoalRequest request) {
return new CreateGoalDto(
request.name(),
request.memo(),
request.startDate(),
request.endDate(),
request.manager(),
List.of(request.manager(), request.team())
);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package com.backend.blooming.admin.controller.dto;

import jakarta.validation.constraints.NotEmpty;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Positive;

import java.time.LocalDate;

public record CreateGoalRequest(
@NotEmpty(message = "이름이 입력되지 않았습니다.")
String name,

String memo,

@NotNull(message = "시작일이 입력되지 않았습니다.")
LocalDate startDate,

@NotNull(message = "종료일이 입력되지 않았습니다.")
LocalDate endDate,

@NotNull(message = "골 생성자가 설정되지 않았습니다.")
@Positive(message = "골 생성자의 아이디가 잘못됐습니다.")
Long manager,

@NotNull(message = "팀원이 설정되지 않았습니다.")
@Positive(message = "팀원의 아이디가 잘못됐습니다.")
Long team
) {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package com.backend.blooming.admin.controller.dto;

import jakarta.validation.constraints.NotEmpty;

public record CreateUserRequest(
@NotEmpty(message = "사용자 이름을 입력되지 않았습니다.")
String name,
String email,
String theme,
String statusMessage
) {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package com.backend.blooming.admin.controller.dto;

public enum FriendStatus {

FRIEND,
DELETE_BY_REQUEST,
DELETE_BY_REQUESTED
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package com.backend.blooming.admin.controller.dto;

import jakarta.validation.constraints.NotEmpty;
import jakarta.validation.constraints.Positive;

public record RequestFriendRequest(
@NotEmpty(message = "친구 요청자가 입력되지 않았습니다.")
@Positive(message = "친구 요청자의 아이디가 잘못됐습니다.")
Long requestUser,

@NotEmpty(message = "친구 요청 수신자가 입력되지 않았습니다.")
@Positive(message = "친구 요청 수신자의 아이디가 잘못됐습니다.")
Long requestedUser
) {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package com.backend.blooming.admin.controller.dto;

import jakarta.validation.constraints.NotEmpty;
import jakarta.validation.constraints.Positive;

public record UpdateFriendRequest(
@NotEmpty(message = "친구 요청자가 입력되지 않았습니다.")
@Positive(message = "친구 요청자의 아이디가 잘못됐습니다.")
Long requestUser,

@NotEmpty(message = "친구 요청 수신자가 입력되지 않았습니다.")
@Positive(message = "친구 요청 수신자의 아이디가 잘못됐습니다.")
Long requestedUser,

@NotEmpty(message = "친구 요청 상태가 입력되지 않았습니다.")
String status
) {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package com.backend.blooming.admin.controller.exception;

import com.backend.blooming.exception.BloomingException;
import com.backend.blooming.exception.ExceptionMessage;

public class InvalidFriendStatusException extends BloomingException {

public InvalidFriendStatusException() {
super(ExceptionMessage.INVALID_FRIEND_STATUS);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@ public class AuthenticationWebMvcConfiguration implements WebMvcConfigurer {
@Override
public void addInterceptors(final InterceptorRegistry registry) {
registry.addInterceptor(authenticationInterceptor)
.addPathPatterns("/**");
.addPathPatterns("/**")
.excludePathPatterns("/admin/**");
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ public enum ExceptionMessage {
NOT_FOUND_DEVICE_TOKEN("디바이스 토큰을 찾을 수 없습니다."),

// 친구
SELF_REQUEST_NOT_ALLOWED("자신에게는 친구 요청할 수 없습니다."),
ALREADY_REQUESTED_FRIEND("이미 친구를 요청한 사용자입니다."),
NOT_FOUND_FRIEND_REQUEST("해당 친구 요청을 조회할 수 없습니다."),
FRIEND_ACCEPTANCE_FORBIDDEN("친구 요청을 수락할 권한이 없습니다."),
Expand All @@ -52,7 +53,10 @@ public enum ExceptionMessage {
INVALID_USER_TO_PARTICIPATE("골에 참여할 수 없는 사용자입니다. 골에는 친구인 사용자만 초대할 수 있습니다."),
DELETE_GOAL_FORBIDDEN("골을 삭제할 권한이 없습니다."),
UPDATE_GOAL_FORBIDDEN("골을 수정할 권한이 없습니다."),
UPDATE_TEAMS_FORBIDDEN("골 참여자 목록은 비어있을 수 없습니다.");
UPDATE_TEAMS_FORBIDDEN("골 참여자 목록은 비어있을 수 없습니다."),

// 관리자 페이지
INVALID_FRIEND_STATUS("잘못된 친구 상태입니다.");

private final String message;
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@
import com.backend.blooming.authentication.infrastructure.exception.OAuthException;
import com.backend.blooming.authentication.infrastructure.exception.UnsupportedOAuthTypeException;
import com.backend.blooming.exception.dto.ExceptionResponse;
import com.backend.blooming.friend.application.exception.AlreadyRequestedFriendException;
import com.backend.blooming.friend.application.exception.DeleteFriendForbiddenException;
import com.backend.blooming.friend.application.exception.FriendAcceptanceForbiddenException;
import com.backend.blooming.friend.application.exception.FriendRequestNotAllowedException;
import com.backend.blooming.friend.application.exception.NotFoundFriendRequestException;
import com.backend.blooming.goal.application.exception.DeleteGoalForbiddenException;
import com.backend.blooming.goal.application.exception.InvalidGoalException;
Expand Down Expand Up @@ -136,9 +136,9 @@ public ResponseEntity<ExceptionResponse> handleNotFoundGoalException(
.body(new ExceptionResponse(exception.getMessage()));
}

@ExceptionHandler(AlreadyRequestedFriendException.class)
@ExceptionHandler(FriendRequestNotAllowedException.class)
public ResponseEntity<ExceptionResponse> handleAlreadyRequestedFriendException(
final AlreadyRequestedFriendException exception
final FriendRequestNotAllowedException exception
) {
logger.warn(String.format(LOG_MESSAGE_FORMAT, exception.getClass().getSimpleName(), exception.getMessage()));

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@

import com.backend.blooming.friend.application.dto.FriendType;
import com.backend.blooming.friend.application.dto.ReadFriendsDto;
import com.backend.blooming.friend.application.exception.AlreadyRequestedFriendException;
import com.backend.blooming.friend.application.exception.DeleteFriendForbiddenException;
import com.backend.blooming.friend.application.exception.FriendAcceptanceForbiddenException;
import com.backend.blooming.friend.application.exception.FriendRequestNotAllowedException;
import com.backend.blooming.friend.application.exception.NotFoundFriendRequestException;
import com.backend.blooming.friend.domain.Friend;
import com.backend.blooming.friend.infrastructure.repository.FriendRepository;
Expand All @@ -28,7 +28,7 @@ public class FriendService {
private final NotificationService notificationService;

public Long request(final Long userId, final Long friendId) {
validateFriendStatus(userId, friendId);
validateRequestFriend(userId, friendId);

final User user = getUser(userId);
final User friendUser = getUser(friendId);
Expand All @@ -40,9 +40,12 @@ public Long request(final Long userId, final Long friendId) {
return friend.getId();
}

private void validateFriendStatus(final Long userId, final Long friendId) {
private void validateRequestFriend(final Long userId, final Long friendId) {
if (userId.equals(friendId)) {
throw new FriendRequestNotAllowedException.SelfRequestNotAllowedException();
}
if (friendRepository.existsByRequestFriend(userId, friendId)) {
throw new AlreadyRequestedFriendException();
throw new FriendRequestNotAllowedException.AlreadyRequestedFriendException();
}
}

Expand Down

This file was deleted.

Loading

0 comments on commit 17c0c8d

Please sign in to comment.