diff --git a/src/backend/workspace_server/src/main/java/com/jootalkpia/workspace_server/controller/WorkSpaceController.java b/src/backend/workspace_server/src/main/java/com/jootalkpia/workspace_server/controller/WorkSpaceController.java index e0bf6027..91ada8e5 100644 --- a/src/backend/workspace_server/src/main/java/com/jootalkpia/workspace_server/controller/WorkSpaceController.java +++ b/src/backend/workspace_server/src/main/java/com/jootalkpia/workspace_server/controller/WorkSpaceController.java @@ -1,8 +1,10 @@ package com.jootalkpia.workspace_server.controller; -import com.jootalkpia.aop.JootalkpiaAuthenticationContext; +//import com.jootalkpia.aop.JootalkpiaAuthenticationContext; import com.jootalkpia.workspace_server.dto.ChannelListDTO; +import com.jootalkpia.workspace_server.dto.SimpleChannel; +import com.jootalkpia.workspace_server.entity.Channels; import com.jootalkpia.workspace_server.service.WorkSpaceService; import com.jootalkpia.workspace_server.util.ValidationUtils; import lombok.RequiredArgsConstructor; @@ -10,7 +12,9 @@ import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; @RestController @@ -20,7 +24,7 @@ public class WorkSpaceController { private final WorkSpaceService workSpaceService; - private final Long userId = JootalkpiaAuthenticationContext.getUserInfo().userId(); + private final Long userId = 1L;//JootalkpiaAuthenticationContext.getUserInfo().userId(); @GetMapping("/{workspaceId}/channels") public ResponseEntity getChannels(@PathVariable Long workspaceId) { @@ -31,4 +35,14 @@ public ResponseEntity getChannels(@PathVariable Long workspaceId ChannelListDTO channelListDTO = workSpaceService.getChannels(userId, workspaceId); return ResponseEntity.ok().body(channelListDTO); } + + @PostMapping("/{workspaceId}/channels") + public ResponseEntity createChannel(@PathVariable Long workspaceId, @RequestParam String channelName) { + // 유효성 검증 + ValidationUtils.validateWorkSpaceId(workspaceId); + log.info("Creating channels for workspace with id: {}", workspaceId); + + SimpleChannel channel = workSpaceService.createChannel(workspaceId, channelName); + return ResponseEntity.ok().body(channel); + } } diff --git a/src/backend/workspace_server/src/main/java/com/jootalkpia/workspace_server/dto/SimpleChannel.java b/src/backend/workspace_server/src/main/java/com/jootalkpia/workspace_server/dto/SimpleChannel.java index 9a7fbd1a..951dfbfc 100644 --- a/src/backend/workspace_server/src/main/java/com/jootalkpia/workspace_server/dto/SimpleChannel.java +++ b/src/backend/workspace_server/src/main/java/com/jootalkpia/workspace_server/dto/SimpleChannel.java @@ -1,11 +1,13 @@ package com.jootalkpia.workspace_server.dto; import java.time.LocalDateTime; +import lombok.AllArgsConstructor; import lombok.Getter; import lombok.Setter; @Getter @Setter +@AllArgsConstructor public class SimpleChannel { private Long channelId; private String channelName; diff --git a/src/backend/workspace_server/src/main/java/com/jootalkpia/workspace_server/entity/BaseEntity.java b/src/backend/workspace_server/src/main/java/com/jootalkpia/workspace_server/entity/BaseEntity.java new file mode 100644 index 00000000..dd556402 --- /dev/null +++ b/src/backend/workspace_server/src/main/java/com/jootalkpia/workspace_server/entity/BaseEntity.java @@ -0,0 +1,21 @@ +package com.jootalkpia.workspace_server.entity; + +import jakarta.persistence.Column; +import jakarta.persistence.MappedSuperclass; +import java.time.LocalDateTime; +import lombok.Getter; +import org.hibernate.annotations.CreationTimestamp; +import org.hibernate.annotations.UpdateTimestamp; + +@Getter +@MappedSuperclass +public abstract class BaseEntity { + + @CreationTimestamp + @Column(name = "created_at", updatable = false) + private LocalDateTime createdAt; + + @UpdateTimestamp + @Column(name = "updated_at") + private LocalDateTime updatedAt; +} diff --git a/src/backend/workspace_server/src/main/java/com/jootalkpia/workspace_server/entity/Channels.java b/src/backend/workspace_server/src/main/java/com/jootalkpia/workspace_server/entity/Channels.java index aa95040a..7db8e514 100644 --- a/src/backend/workspace_server/src/main/java/com/jootalkpia/workspace_server/entity/Channels.java +++ b/src/backend/workspace_server/src/main/java/com/jootalkpia/workspace_server/entity/Channels.java @@ -13,14 +13,17 @@ import java.time.LocalDateTime; import java.util.ArrayList; import java.util.List; +import lombok.Builder; import lombok.Getter; +import lombok.NoArgsConstructor; import org.hibernate.annotations.CreationTimestamp; import org.hibernate.annotations.UpdateTimestamp; @Entity @Table(name = "channels") @Getter -public class Channels { +@NoArgsConstructor +public class Channels extends BaseEntity{ @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(name = "channel_id", nullable = false) @@ -33,14 +36,12 @@ public class Channels { @OneToMany(mappedBy = "channels", cascade = CascadeType.ALL, orphanRemoval = true) private List userChannel = new ArrayList<>(); - @Column(name = "name", length = 100, nullable = false) + @Column(name = "name", length = 100, nullable = false, unique = true) private String name; - @CreationTimestamp - @Column(name = "created_at", updatable = false) - private LocalDateTime createdAt; - - @UpdateTimestamp - @Column(name = "updated_at") - private LocalDateTime updatedAt; + @Builder + public Channels(WorkSpace workSpace, String name) { + this.workSpace = workSpace; + this.name = name; + } } diff --git a/src/backend/workspace_server/src/main/java/com/jootalkpia/workspace_server/entity/Mention.java b/src/backend/workspace_server/src/main/java/com/jootalkpia/workspace_server/entity/Mention.java index 2d9bcc7c..be89730b 100644 --- a/src/backend/workspace_server/src/main/java/com/jootalkpia/workspace_server/entity/Mention.java +++ b/src/backend/workspace_server/src/main/java/com/jootalkpia/workspace_server/entity/Mention.java @@ -16,7 +16,7 @@ @Entity @Table(name = "mention") @Getter -public class Mention { +public class Mention extends BaseEntity{ @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(name = "mention_id", nullable = false) @@ -32,11 +32,4 @@ public class Mention { @Column(name = "is_unread", nullable = false) private Boolean isUnread; - @CreationTimestamp - @Column(name = "created_at", updatable = false) - private LocalDateTime createdAt; - - @UpdateTimestamp - @Column(name = "updated_at") - private LocalDateTime updatedAt; } diff --git a/src/backend/workspace_server/src/main/java/com/jootalkpia/workspace_server/entity/UserChannel.java b/src/backend/workspace_server/src/main/java/com/jootalkpia/workspace_server/entity/UserChannel.java index 6d8d4e5a..021eab81 100644 --- a/src/backend/workspace_server/src/main/java/com/jootalkpia/workspace_server/entity/UserChannel.java +++ b/src/backend/workspace_server/src/main/java/com/jootalkpia/workspace_server/entity/UserChannel.java @@ -20,7 +20,7 @@ @Entity @Table(name = "user_channel") @Getter -public class UserChannel { +public class UserChannel extends BaseEntity { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(name = "user_channel_id", nullable = false) @@ -40,11 +40,4 @@ public class UserChannel { @Column(name = "mute", nullable = false) private Boolean mute; - @CreationTimestamp - @Column(name = "createdAt", updatable = false) - private LocalDateTime createdAt; - - @UpdateTimestamp - @Column(name = "updatedAt") - private LocalDateTime updatedAt; } diff --git a/src/backend/workspace_server/src/main/java/com/jootalkpia/workspace_server/entity/Users.java b/src/backend/workspace_server/src/main/java/com/jootalkpia/workspace_server/entity/Users.java index ebf205a6..f59500d7 100644 --- a/src/backend/workspace_server/src/main/java/com/jootalkpia/workspace_server/entity/Users.java +++ b/src/backend/workspace_server/src/main/java/com/jootalkpia/workspace_server/entity/Users.java @@ -16,7 +16,7 @@ @Table(name = "users") @Getter @Setter -public class Users { +public class Users extends BaseEntity { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @@ -38,11 +38,4 @@ public class Users { @Column(name = "profile_image", length = 100) private String profileImage; - @CreationTimestamp - @Column(name = "created_at", nullable = false, updatable = false) - private LocalDateTime createdAt; - - @UpdateTimestamp - @Column(name = "updated_at", nullable = false) - private LocalDateTime updatedAt; } diff --git a/src/backend/workspace_server/src/main/java/com/jootalkpia/workspace_server/entity/WorkSpace.java b/src/backend/workspace_server/src/main/java/com/jootalkpia/workspace_server/entity/WorkSpace.java index 12636225..fb5b2737 100644 --- a/src/backend/workspace_server/src/main/java/com/jootalkpia/workspace_server/entity/WorkSpace.java +++ b/src/backend/workspace_server/src/main/java/com/jootalkpia/workspace_server/entity/WorkSpace.java @@ -18,7 +18,7 @@ @Entity @Table(name = "work_space") @Getter -public class WorkSpace { +public class WorkSpace extends BaseEntity { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(name = "workspace_id", nullable = false) @@ -33,11 +33,4 @@ public class WorkSpace { @OneToMany(mappedBy = "workSpace", cascade = CascadeType.ALL, orphanRemoval = true) private List channels = new ArrayList<>(); - @CreationTimestamp - @Column(name = "createdAt", updatable = false) - private LocalDateTime createdAt; - - @UpdateTimestamp - @Column(name = "updatedAt") - private LocalDateTime updatedAt; } diff --git a/src/backend/workspace_server/src/main/java/com/jootalkpia/workspace_server/exception/common/CustomException.java b/src/backend/workspace_server/src/main/java/com/jootalkpia/workspace_server/exception/common/CustomException.java index 3227ca9c..10a4778e 100644 --- a/src/backend/workspace_server/src/main/java/com/jootalkpia/workspace_server/exception/common/CustomException.java +++ b/src/backend/workspace_server/src/main/java/com/jootalkpia/workspace_server/exception/common/CustomException.java @@ -8,6 +8,10 @@ public class CustomException extends RuntimeException { private final String code; - private final String message; + + public CustomException(String code, String message) { + super(message); + this.code = code; + } } diff --git a/src/backend/workspace_server/src/main/java/com/jootalkpia/workspace_server/exception/common/ErrorCode.java b/src/backend/workspace_server/src/main/java/com/jootalkpia/workspace_server/exception/common/ErrorCode.java index 248502f4..b9e4b809 100644 --- a/src/backend/workspace_server/src/main/java/com/jootalkpia/workspace_server/exception/common/ErrorCode.java +++ b/src/backend/workspace_server/src/main/java/com/jootalkpia/workspace_server/exception/common/ErrorCode.java @@ -13,9 +13,10 @@ public enum ErrorCode { VALIDATION_FAILED("W40002", "유효성 검증에 실패했습니다."), MISSING_PARAMETER("W40003", "필수 파라미터가 누락되었습니다."), INVALID_PARAMETER("W40004", "잘못된 파라미터가 포함되었습니다."), + DUPLICATE_CHANNEL_NAME("W40005", "동일한 채널명이 이미 해당 워크스페이스에 존재합니다."), // 404 Not Found - _NOT_FOUND("W40401", "등록되지 않은 ~~입니다."), + WORKSPACE_NOT_FOUND("W40401", "등록되지 않은 워크스페이스입니다."), // 500 Internal Server Error diff --git a/src/backend/workspace_server/src/main/java/com/jootalkpia/workspace_server/exception/common/ErrorResponse.java b/src/backend/workspace_server/src/main/java/com/jootalkpia/workspace_server/exception/common/ErrorResponse.java new file mode 100644 index 00000000..986f2944 --- /dev/null +++ b/src/backend/workspace_server/src/main/java/com/jootalkpia/workspace_server/exception/common/ErrorResponse.java @@ -0,0 +1,11 @@ +package com.jootalkpia.workspace_server.exception.common; + +import lombok.AllArgsConstructor; +import lombok.Data; + +@Data +@AllArgsConstructor +public class ErrorResponse { + private String code; + private String message; +} diff --git a/src/backend/workspace_server/src/main/java/com/jootalkpia/workspace_server/exception/common/GlobalExceptionHandler.java b/src/backend/workspace_server/src/main/java/com/jootalkpia/workspace_server/exception/common/GlobalExceptionHandler.java new file mode 100644 index 00000000..39a1dc4c --- /dev/null +++ b/src/backend/workspace_server/src/main/java/com/jootalkpia/workspace_server/exception/common/GlobalExceptionHandler.java @@ -0,0 +1,22 @@ +package com.jootalkpia.workspace_server.exception.common; + +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.bind.annotation.RestControllerAdvice; + +@RestControllerAdvice +public class GlobalExceptionHandler { + + @ExceptionHandler(CustomException.class) + public ResponseEntity handleCustomException(CustomException ex) { + ErrorResponse errorResponse = new ErrorResponse(ex.getCode(), ex.getMessage()); + return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(errorResponse); + } + + @ExceptionHandler(Exception.class) + public ResponseEntity handleGenericException(Exception ex) { + ErrorResponse errorResponse = new ErrorResponse("UNKNOWN_ERROR", "An unexpected error occurred."); + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(errorResponse); + } +} diff --git a/src/backend/workspace_server/src/main/java/com/jootalkpia/workspace_server/repository/UserChannelRepository.java b/src/backend/workspace_server/src/main/java/com/jootalkpia/workspace_server/repository/UserChannelRepository.java index 1578e611..26ba5df5 100644 --- a/src/backend/workspace_server/src/main/java/com/jootalkpia/workspace_server/repository/UserChannelRepository.java +++ b/src/backend/workspace_server/src/main/java/com/jootalkpia/workspace_server/repository/UserChannelRepository.java @@ -3,7 +3,9 @@ import com.jootalkpia.workspace_server.entity.UserChannel; import java.util.Optional; import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; +@Repository public interface UserChannelRepository extends JpaRepository { Optional findByUsersUserIdAndChannelsChannelId(Long userId, Long channelId); } diff --git a/src/backend/workspace_server/src/main/java/com/jootalkpia/workspace_server/service/WorkSpaceService.java b/src/backend/workspace_server/src/main/java/com/jootalkpia/workspace_server/service/WorkSpaceService.java index 4d9ab08f..0c8c54ab 100644 --- a/src/backend/workspace_server/src/main/java/com/jootalkpia/workspace_server/service/WorkSpaceService.java +++ b/src/backend/workspace_server/src/main/java/com/jootalkpia/workspace_server/service/WorkSpaceService.java @@ -4,10 +4,12 @@ import com.jootalkpia.workspace_server.dto.ChannelListDTO; import com.jootalkpia.workspace_server.dto.SimpleChannel; import com.jootalkpia.workspace_server.entity.Channels; +import com.jootalkpia.workspace_server.entity.WorkSpace; import com.jootalkpia.workspace_server.exception.common.CustomException; import com.jootalkpia.workspace_server.exception.common.ErrorCode; import com.jootalkpia.workspace_server.repository.ChannelRepository; import com.jootalkpia.workspace_server.repository.UserChannelRepository; +import com.jootalkpia.workspace_server.repository.WorkSpaceRepository; import java.util.ArrayList; import java.util.List; import lombok.RequiredArgsConstructor; @@ -21,39 +23,79 @@ public class WorkSpaceService { private final ChannelRepository channelRepository; private final UserChannelRepository userChannelRepository; + private final WorkSpaceRepository workSpaceRepository; public ChannelListDTO getChannels(Long userId, Long workspaceId) { // workspaceId로 모든 채널 조회 + List channelList = fetchAllChannels(workspaceId); + + // 채널 분류 + List joinedChannels = classifyChannels(userId, channelList, true); + List unjoinedChannels = classifyChannels(userId, channelList, false); + + return createChannelListDTO(joinedChannels, unjoinedChannels); + } + + private List fetchAllChannels(Long workspaceId) { List channelList = channelRepository.findByWorkSpaceWorkspaceId(workspaceId); if (channelList.isEmpty()) { throw new CustomException(ErrorCode.DATABASE_ERROR.getCode(), ErrorCode.DATABASE_ERROR.getMsg()); } + return channelList; + } - // 가입된 채널과 가입되지 않은 채널을 분류 - List joinedChannels = new ArrayList<>(); - List unjoinedChannels = new ArrayList<>(); - - for (Channels channels : channelList) { - SimpleChannel simpleChannel = new SimpleChannel(); - simpleChannel.setChannelId(channels.getChannelId()); - simpleChannel.setChannelName(channels.getName()); - simpleChannel.setCreatedAt(channels.getCreatedAt()); - - if (isJoinedChannel(userId, channels)) { - joinedChannels.add(simpleChannel); - } else { - unjoinedChannels.add(simpleChannel); + private List classifyChannels(Long userId, List channelList, boolean isJoined) { + List classifiedChannels = new ArrayList<>(); + for (Channels channel : channelList) { + boolean joined = isJoinedChannel(userId, channel); + if (joined == isJoined) { + classifiedChannels.add(new SimpleChannel(channel.getChannelId(), channel.getName(), channel.getCreatedAt())); } } + return classifiedChannels; + } + + private boolean isJoinedChannel(Long userId, Channels channels) { + return userChannelRepository.findByUsersUserIdAndChannelsChannelId(userId, channels.getChannelId()).isPresent(); + } + private ChannelListDTO createChannelListDTO(List joinedChannels, List unjoinedChannels) { ChannelListDTO channelListDTO = new ChannelListDTO(); channelListDTO.setJoinedChannels(joinedChannels); channelListDTO.setUnjoinedChannels(unjoinedChannels); - return channelListDTO; } - private boolean isJoinedChannel(Long userId, Channels channels) { - return userChannelRepository.findByUsersUserIdAndChannelsChannelId(userId, channels.getChannelId()).isPresent(); + public SimpleChannel createChannel(Long workspaceId, String channelName) { + // WorkSpace 객체 조회 + WorkSpace workSpace = fetchWorkSpace(workspaceId); + + // 채널명 unique한지 확인 + if (isChannelNameDuplicate(workspaceId, channelName)) { + throw new CustomException(ErrorCode.DUPLICATE_CHANNEL_NAME.getCode(), ErrorCode.DUPLICATE_CHANNEL_NAME.getMsg()); + } + Channels channel = Channels.builder() + .workSpace(workSpace) + .name(channelName) + .build(); + + channelRepository.save(channel); + + return new SimpleChannel(channel.getChannelId(), channel.getName(), channel.getCreatedAt()); + } + + private boolean isChannelNameDuplicate(Long workspaceId, String channelName) { + List channelList = fetchAllChannels(workspaceId); + for (Channels channel : channelList) { + if (channel.getName().equals(channelName)) { + return true; + } + } + return false; + } + + private WorkSpace fetchWorkSpace(Long workspaceId) { + return workSpaceRepository.findById(workspaceId) + .orElseThrow(() -> new CustomException(ErrorCode.WORKSPACE_NOT_FOUND.getCode(), ErrorCode.WORKSPACE_NOT_FOUND.getMsg())); } }