Skip to content
Open
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
402 changes: 402 additions & 0 deletions .logs/app.2026-03-26.log

Large diffs are not rendered by default.

90,483 changes: 90,483 additions & 0 deletions .logs/app.log

Large diffs are not rendered by default.

4 changes: 4 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,10 @@ dependencies {
implementation 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.8.15'
implementation 'org.mapstruct:mapstruct:1.5.5.Final'
annotationProcessor 'org.mapstruct:mapstruct-processor:1.5.5.Final'
implementation 'org.hibernate.validator:hibernate-validator:8.0.1.Final'
implementation 'org.glassfish:jakarta.el:4.0.2'
runtimeOnly 'com.h2database:h2'
implementation 'org.springframework.boot:spring-boot-starter-actuator'
}

tasks.named('test') {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
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 jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
Expand Down Expand Up @@ -50,7 +51,7 @@ public class AuthController {
})

@RequestMapping(value = "/login", method = RequestMethod.POST)
public ResponseEntity<UserDto> login(@RequestBody LoginRequest dto) {
public ResponseEntity<UserDto> login(@RequestBody @Valid LoginRequest dto) {
System.out.println("newUsername = " + dto.username());
System.out.println("password = " + dto.password());
return ResponseEntity
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,31 +33,31 @@ public class BinaryContentController {
private final BinaryContentService binaryContentService;
private final BinaryContentStorage storage;

// 바이너리 파일 생성
// @Operation(summary = "파일 업로드", description = "MultipartFile을 업로드하여 시스템에 저장")
// @ApiResponses(value = {
// @ApiResponse(responseCode = "201", description = "업로드 성공",
// content = @Content(mediaType = "application/json",
// schema = @Schema(implementation = BinaryContentDto.class))),
// @ApiResponse(responseCode = "400", description = "잘못된 요청 파라미터"),
// @ApiResponse(responseCode = "500", description = "서버 내부 오류")
//
// })
// @PostMapping(consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
// public ResponseEntity<BinaryContentDto> create(@RequestPart("file") MultipartFile file)
// throws IOException {
//
// BinaryContentCreateDto newDto = new BinaryContentCreateDto(
// file.getContentType(),
// file.getBytes(),
// file.getSize(),
// file.getOriginalFilename()
// );
//
// return ResponseEntity
// .status(HttpStatus.CREATED)
// .body(binaryContentService.create(newDto));
// }
// 바이너리 파일 생성
@Operation(summary = "파일 업로드", description = "MultipartFile을 업로드하여 시스템에 저장")
@ApiResponses(value = {
@ApiResponse(responseCode = "201", description = "업로드 성공",
content = @Content(mediaType = "application/json",
schema = @Schema(implementation = BinaryContentDto.class))),
@ApiResponse(responseCode = "400", description = "잘못된 요청 파라미터"),
@ApiResponse(responseCode = "500", description = "서버 내부 오류")

})
@PostMapping(consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
public ResponseEntity<BinaryContentDto> create(@RequestPart("file") MultipartFile file)
throws IOException {

BinaryContentCreateDto newDto = new BinaryContentCreateDto(
file.getContentType(),
file.getBytes(),
file.getSize(),
file.getOriginalFilename()
);

return ResponseEntity
.status(HttpStatus.CREATED)
.body(binaryContentService.create(newDto));
}

// 바아너리 파일 1개 조회
@Operation(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,9 @@
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 jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
Expand All @@ -22,6 +24,7 @@
@RequiredArgsConstructor
@RestController
@RequestMapping("/api/channels")
@Slf4j
public class ChannelController {

private final ChannelService channelService;
Expand All @@ -35,10 +38,12 @@ public class ChannelController {
})
@RequestMapping(value = "/public", method = RequestMethod.POST)
public ResponseEntity<ChannelDto> createPublicChannel(
@RequestBody PublicChannelCreateRequest dto) {
return ResponseEntity
.status(HttpStatus.CREATED)
.body(channelService.createPublic(dto));
@RequestBody @Valid PublicChannelCreateRequest dto) {

log.info("PUBLIC 채널 생성 요청: name={}", dto.name());
ChannelDto result = channelService.createPublic(dto);
log.info("PUBLIC 채널 생성 완료: id={}", result.id());
return ResponseEntity.status(HttpStatus.CREATED).body(result);
}

// 비공개 채널 생성
Expand All @@ -49,10 +54,12 @@ public ResponseEntity<ChannelDto> createPublicChannel(
})
@RequestMapping(value = "/private", method = RequestMethod.POST)
public ResponseEntity<ChannelDto> createPrivateChannel(
@RequestBody PrivateChannelCreateRequest dto) {
return ResponseEntity
.status(HttpStatus.CREATED)
.body(channelService.createPrivate(dto));
@RequestBody @Valid PrivateChannelCreateRequest dto) {

log.info("PRIVATE 채널 생성 요청: participantIds={}", dto.participantIds());
ChannelDto result = channelService.createPrivate(dto);
log.info("PRIVATE 채널 생성 완료: id={}", result.id());
return ResponseEntity.status(HttpStatus.CREATED).body(result);
}

// 공개 채널 정보 수정
Expand All @@ -64,10 +71,12 @@ public ResponseEntity<ChannelDto> createPrivateChannel(
})
@RequestMapping(value = "/{channelId}", method = RequestMethod.PATCH)
public ResponseEntity<ChannelDto> updatePublicChannel(@PathVariable UUID channelId,
@RequestBody PublicChannelUpdateRequest dto) {
return ResponseEntity
.status(HttpStatus.OK)
.body(channelService.update(channelId, dto));
@RequestBody @Valid PublicChannelUpdateRequest dto) {

log.info("채널 수정 요청: channelId={}", channelId);
ChannelDto result = channelService.update(channelId, dto);
log.info("채널 수정 완료: channelId={}", channelId);
return ResponseEntity.status(HttpStatus.OK).body(result);
}

// 채널에 멤버 추가
Expand All @@ -93,7 +102,10 @@ public ResponseEntity<ChannelDto> updatePublicChannel(@PathVariable UUID channel
})
@RequestMapping(value = "/{channelId}", method = RequestMethod.DELETE)
public ResponseEntity<Void> delete(@PathVariable UUID channelId) {

log.info("채널 삭제 요청: channelId={}", channelId);
channelService.delete(channelId);
log.info("채널 삭제 완료: channelId={}", channelId);
return ResponseEntity
.status(HttpStatus.NO_CONTENT)
.build();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,12 @@
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 jakarta.validation.Valid;
import java.io.IOException;
import java.time.Instant;
import java.util.ArrayList;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Slice;
Expand All @@ -33,6 +35,7 @@
@RequiredArgsConstructor
@RestController
@RequestMapping("/api/messages")
@Slf4j
public class MessageController {

private final MessageService messageService;
Expand All @@ -46,13 +49,14 @@ public class MessageController {
})
@PostMapping(consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
public ResponseEntity<MessageDto> send(
@RequestPart("messageCreateRequest") MessageCreateRequest dto,
@RequestPart("messageCreateRequest") @Valid MessageCreateRequest dto,
@RequestPart(value = "attachments", required = false) List<MultipartFile> attachments)
throws IOException {

return ResponseEntity
.status(HttpStatus.CREATED)
.body(messageService.create(dto, attachments));
log.info("메시지 전송 요청: authorId={}, channelId={}", dto.authorId(), dto.channelId());
MessageDto result = messageService.create(dto, attachments);
log.info("메시지 전송 완료: id={}", result.id());
return ResponseEntity.status(HttpStatus.CREATED).body(result);
}

// 메시지 수정
Expand All @@ -64,10 +68,12 @@ public ResponseEntity<MessageDto> send(
})
@RequestMapping(value = "/{messageId}", method = RequestMethod.PATCH)
public ResponseEntity<MessageDto> update(@PathVariable UUID messageId,
@RequestBody MessageUpdateRequest dto) {
return ResponseEntity
.status(HttpStatus.OK)
.body(messageService.update(messageId, dto));
@RequestBody @Valid MessageUpdateRequest dto) {

log.info("메시지 수정 요청: messageId={}", messageId);
MessageDto result = messageService.update(messageId, dto);
log.info("메시지 수정 완료: messageId={}", messageId);
return ResponseEntity.status(HttpStatus.OK).body(result);
}

// 메시지 삭제
Expand All @@ -77,10 +83,11 @@ public ResponseEntity<MessageDto> update(@PathVariable UUID messageId,
})
@RequestMapping(value = "/{messageId}", method = RequestMethod.DELETE)
public ResponseEntity<Void> delete(@PathVariable UUID messageId) {

log.info("메시지 삭제 요청: messageId={}", messageId);
messageService.delete(messageId);
return ResponseEntity
.status(HttpStatus.NO_CONTENT)
.build();
log.info("메시지 삭제 완료: messageId={}", messageId);
return ResponseEntity.status(HttpStatus.NO_CONTENT).build();
}

// 조회
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
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 jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
Expand All @@ -32,7 +33,7 @@ public class ReadStatusController {
content = @Content(mediaType = "application/json", schema = @Schema(implementation = ReadStatusDto.class)))
})
@RequestMapping(method = RequestMethod.POST)
public ResponseEntity<ReadStatusDto> create(@RequestBody ReadStatusCreateRequest dto) {
public ResponseEntity<ReadStatusDto> create(@RequestBody @Valid ReadStatusCreateRequest dto) {
return ResponseEntity
.status(HttpStatus.CREATED)
.body(readStatusService.create(dto));
Expand All @@ -47,7 +48,7 @@ public ResponseEntity<ReadStatusDto> create(@RequestBody ReadStatusCreateRequest
})
@RequestMapping(value = "/{readStatusId}", method = RequestMethod.PATCH)
public ResponseEntity<ReadStatusDto> update(@PathVariable UUID readStatusId,
@RequestBody ReadStatusUpdateRequest dto) {
@RequestBody @Valid ReadStatusUpdateRequest dto) {
return ResponseEntity
.status(HttpStatus.OK)
.body(readStatusService.update(readStatusId, dto));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,10 @@
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 jakarta.validation.Valid;
import java.io.IOException;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
Expand All @@ -30,6 +32,7 @@
@RequiredArgsConstructor
@RestController
@RequestMapping("/api/users")
@Slf4j
public class UserController {

private final UserService userService;
Expand All @@ -43,12 +46,14 @@ public class UserController {
content = @Content(mediaType = "application/json", schema = @Schema(implementation = UserDto.class)))
})
@PostMapping(consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
public ResponseEntity<UserDto> join(@RequestPart("userCreateRequest") UserCreateRequest dto,
public ResponseEntity<UserDto> join(
@RequestPart("userCreateRequest") @Valid UserCreateRequest dto,
@RequestPart(value = "profile", required = false) MultipartFile profile) throws IOException {

return ResponseEntity
.status(HttpStatus.CREATED)
.body(userService.create(dto, profile));
log.info("사용자 등록 요청: username={}, email={}", dto.username(), dto.email());
UserDto result = userService.create(dto, profile);
log.info("사용자 등록 완료: username={}, email={}", dto.username(), dto.email());
return ResponseEntity.status(HttpStatus.CREATED).body(result);
}

// 사용자 정보 수정
Expand All @@ -61,12 +66,13 @@ public ResponseEntity<UserDto> join(@RequestPart("userCreateRequest") UserCreate
@RequestMapping(value = "/{userId}", method = RequestMethod.PATCH, consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
public ResponseEntity<UserDto> update(
@PathVariable UUID userId,
@RequestPart("userUpdateRequest") UserUpdateRequest dto,
@RequestPart("userUpdateRequest") @Valid UserUpdateRequest dto,
@RequestPart(value = "profile", required = false) MultipartFile profile) throws IOException {

return ResponseEntity
.status(HttpStatus.OK)
.body(userService.update(userId, dto, profile));
log.info("사용자 수정 요청: userId={}", userId);
UserDto result = userService.update(userId, dto, profile);
log.info("사용자 수정 완료: userId={}", userId);
return ResponseEntity.status(HttpStatus.OK).body(result);
}

// 사용자 삭제
Expand All @@ -76,10 +82,10 @@ public ResponseEntity<UserDto> update(
})
@RequestMapping(value = "/{userId}", method = RequestMethod.DELETE)
public ResponseEntity<Void> delete(@PathVariable UUID userId) {
log.info("사용자 삭제 요청: userId={}", userId);
userService.delete(userId);
return ResponseEntity
.status(HttpStatus.NO_CONTENT)
.build();
log.info("사용자 삭제 완료: userId={}", userId);
return ResponseEntity.status(HttpStatus.NO_CONTENT).build();
}

// 모든 사용자 조회
Expand Down Expand Up @@ -108,7 +114,7 @@ public ResponseEntity<List<UserDto>> findAll() {
})
@RequestMapping(value = "/{userId}/userStatus", method = RequestMethod.PATCH)
public ResponseEntity<UserStatusDto> updateStatus(@PathVariable UUID userId,
@RequestBody UserStatusUpdateRequest dto) {
@RequestBody @Valid UserStatusUpdateRequest dto) {
return ResponseEntity
.status(HttpStatus.OK)
.body(userStatusService.updateByUserId(userId, dto));
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
package com.sprint.mission.discodeit.dto;

import jakarta.validation.constraints.NotBlank;

public record LoginRequest(
@NotBlank(message = "이름은 필수입니다.")
String username,

@NotBlank(message = "비밀번호는 필수입니다.")
String password
) {

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

import com.sprint.mission.discodeit.entity.Channel;
import com.sprint.mission.discodeit.entity.User;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Size;
import java.util.UUID;

public record MessageCreateRequest(
@NotNull(message = "발신자 id는 null일 수 없습니다.")
UUID authorId,

@NotNull(message = "채널 id는 null일 수 없습니다.")
UUID channelId,

@NotBlank(message = "메시지는 공백일 수 없습니다.")
@Size(max = 5000, message = "메시지가 너무 깁니다.")
String content
) {

Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
package com.sprint.mission.discodeit.dto;

import com.sprint.mission.discodeit.entity.BinaryContent;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.Size;
import java.util.List;

public record MessageUpdateRequest(
@NotBlank(message = "메시지는 공백일 수 없습니다.")
@Size(max = 5000, message = "메시지가 너무 깁니다.")
String newContent

) {
Expand Down
Loading