diff --git a/src/main/java/com/tiki/server/auth/controller/docs/AuthControllerDocs.java b/src/main/java/com/tiki/server/auth/controller/docs/AuthControllerDocs.java index 85263f64..9f9d45ef 100644 --- a/src/main/java/com/tiki/server/auth/controller/docs/AuthControllerDocs.java +++ b/src/main/java/com/tiki/server/auth/controller/docs/AuthControllerDocs.java @@ -49,11 +49,7 @@ public interface AuthControllerDocs { @ApiResponse(responseCode = "201", description = "성공"), @ApiResponse( responseCode = "401", - description = "유효하지 않은 키", - content = @Content(schema = @Schema(implementation = SuccessResponse.class))), - @ApiResponse( - responseCode = "401", - description = "인증되지 않은 사용자", + description = "유효하지 않은 키, 인증되지 않은 사용자", content = @Content(schema = @Schema(implementation = SuccessResponse.class))), @ApiResponse( responseCode = "404", diff --git a/src/main/java/com/tiki/server/document/controller/DocumentController.java b/src/main/java/com/tiki/server/document/controller/DocumentController.java index 21960d56..671c2ed4 100644 --- a/src/main/java/com/tiki/server/document/controller/DocumentController.java +++ b/src/main/java/com/tiki/server/document/controller/DocumentController.java @@ -22,7 +22,6 @@ import com.tiki.server.document.controller.docs.DocumentControllerDocs; import com.tiki.server.document.dto.request.DocumentsCreateRequest; import com.tiki.server.document.dto.response.DeletedDocumentsGetResponse; -import com.tiki.server.document.dto.response.DocumentsCreateResponse; import com.tiki.server.document.dto.response.DocumentsGetResponse; import com.tiki.server.document.service.DocumentService; diff --git a/src/main/java/com/tiki/server/document/controller/docs/DocumentControllerDocs.java b/src/main/java/com/tiki/server/document/controller/docs/DocumentControllerDocs.java index bc431454..dd8f2e17 100644 --- a/src/main/java/com/tiki/server/document/controller/docs/DocumentControllerDocs.java +++ b/src/main/java/com/tiki/server/document/controller/docs/DocumentControllerDocs.java @@ -1,13 +1,17 @@ package com.tiki.server.document.controller.docs; import java.security.Principal; +import java.util.List; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestParam; import com.tiki.server.common.dto.ErrorResponse; import com.tiki.server.common.dto.SuccessResponse; +import com.tiki.server.document.dto.request.DocumentsCreateRequest; +import com.tiki.server.document.dto.response.DeletedDocumentsGetResponse; import com.tiki.server.document.dto.response.DocumentsGetResponse; import io.swagger.v3.oas.annotations.Operation; @@ -50,12 +54,12 @@ ResponseEntity> getAllDocuments( description = "팀 id", in = ParameterIn.PATH, example = "1" - ) - @PathVariable long teamId, + ) @PathVariable long teamId, @Parameter( name = "type", description = "타임라인 타입", in = ParameterIn.QUERY, + required = true, example = "executive, member" ) @RequestParam String type ); @@ -89,14 +93,190 @@ ResponseEntity deleteDocument( description = "팀 id", in = ParameterIn.PATH, example = "1" - ) - @PathVariable long teamId, + ) @PathVariable long teamId, @Parameter( name = "documentId", description = "문서 id", in = ParameterIn.PATH, example = "1" - ) - @PathVariable long documentId + ) @PathVariable long documentId + ); + + @Operation( + summary = "문서 생성", + description = "문서를 여러 개 생성한다.", + responses = { + @ApiResponse(responseCode = "201", description = "성공"), + @ApiResponse( + responseCode = "4xx", + description = "클라이언트(요청) 오류", + content = @Content(schema = @Schema(implementation = ErrorResponse.class))), + @ApiResponse( + responseCode = "500", + description = "서버 내부 오류", + content = @Content(schema = @Schema(implementation = ErrorResponse.class)))} + ) + ResponseEntity> createDocuments( + @Parameter(hidden = true) Principal principal, + @Parameter( + name = "팀 id", + description = "팀 id", + in = ParameterIn.PATH, + example = "1" + ) @PathVariable long teamId, + @Parameter( + name = "폴더 id", + description = "생성할 파일이 속할 폴더 id", + in = ParameterIn.QUERY, + example = "1" + ) @RequestParam Long folderId, + @RequestBody final DocumentsCreateRequest request + ); + + @Operation( + summary = "문서 조회", + description = "문서를 조회한다.", + responses = { + @ApiResponse(responseCode = "200", description = "성공"), + @ApiResponse( + responseCode = "4xx", + description = "클라이언트(요청) 오류", + content = @Content(schema = @Schema(implementation = ErrorResponse.class))), + @ApiResponse( + responseCode = "500", + description = "서버 내부 오류", + content = @Content(schema = @Schema(implementation = ErrorResponse.class)))} + ) + ResponseEntity> getDocuments( + @Parameter(hidden = true) Principal principal, + @Parameter( + name = "팀 id", + description = "팀 id", + in = ParameterIn.PATH, + example = "1" + ) @PathVariable long teamId, + @Parameter( + name = "폴더 id", + description = "조회할 폴더 id", + in = ParameterIn.QUERY, + example = "1" + ) @RequestParam Long folderId + ); + + @Operation( + summary = "문서 삭제", + description = "문서를 여러 개 삭제한다.", + responses = { + @ApiResponse(responseCode = "204", description = "성공"), + @ApiResponse( + responseCode = "4xx", + description = "클라이언트(요청) 오류", + content = @Content(schema = @Schema(implementation = ErrorResponse.class))), + @ApiResponse( + responseCode = "500", + description = "서버 내부 오류", + content = @Content(schema = @Schema(implementation = ErrorResponse.class)))} + ) + ResponseEntity delete( + @Parameter(hidden = true) Principal principal, + @Parameter( + name = "팀 id", + description = "팀 id", + in = ParameterIn.PATH, + example = "1" + ) @PathVariable long teamId, + @Parameter( + name = "파일 id", + description = "삭제할 파일 id 리스트", + in = ParameterIn.QUERY, + required = true, + example = "[1, 2]" + ) @RequestParam("documentId") List documentIds + ); + + @Operation( + summary = "휴지통 문서 삭제", + description = "휴지통 속 문서를 여러 개 삭제한다.", + responses = { + @ApiResponse(responseCode = "204", description = "성공"), + @ApiResponse( + responseCode = "4xx", + description = "클라이언트(요청) 오류", + content = @Content(schema = @Schema(implementation = ErrorResponse.class))), + @ApiResponse( + responseCode = "500", + description = "서버 내부 오류", + content = @Content(schema = @Schema(implementation = ErrorResponse.class)))} + ) + ResponseEntity deleteTrash( + @Parameter(hidden = true) Principal principal, + @Parameter( + name = "팀 id", + description = "팀 id", + in = ParameterIn.PATH, + example = "1" + ) @PathVariable long teamId, + @Parameter( + name = "파일 id", + description = "삭제할 파일 id 리스트", + in = ParameterIn.QUERY, + required = true, + example = "[1, 2]" + ) @RequestParam("documentId") List deletedDocumentIds + ); + + @Operation( + summary = "휴지통 문서 복구", + description = "휴지통 속 문서를 여러 개 복구한다.", + responses = { + @ApiResponse(responseCode = "204", description = "성공"), + @ApiResponse( + responseCode = "4xx", + description = "클라이언트(요청) 오류", + content = @Content(schema = @Schema(implementation = ErrorResponse.class))), + @ApiResponse( + responseCode = "500", + description = "서버 내부 오류", + content = @Content(schema = @Schema(implementation = ErrorResponse.class)))} + ) + ResponseEntity restore( + @Parameter(hidden = true) Principal principal, + @Parameter( + name = "팀 id", + description = "팀 id", + in = ParameterIn.PATH, + example = "1" + ) @PathVariable long teamId, + @Parameter( + name = "파일 id", + description = "복구할 파일 id 리스트", + in = ParameterIn.QUERY, + required = true, + example = "[1, 2]" + ) @RequestParam("documentId") List deletedDocumentIds + ); + + @Operation( + summary = "휴지통 조회", + description = "휴지통을 조회한다.", + responses = { + @ApiResponse(responseCode = "200", description = "성공"), + @ApiResponse( + responseCode = "4xx", + description = "클라이언트(요청) 오류", + content = @Content(schema = @Schema(implementation = ErrorResponse.class))), + @ApiResponse( + responseCode = "500", + description = "서버 내부 오류", + content = @Content(schema = @Schema(implementation = ErrorResponse.class)))} + ) + ResponseEntity> getTrash( + @Parameter(hidden = true) Principal principal, + @Parameter( + name = "팀 id", + description = "팀 id", + in = ParameterIn.PATH, + example = "1" + ) @PathVariable long teamId ); } diff --git a/src/main/java/com/tiki/server/document/dto/request/DocumentCreateRequest.java b/src/main/java/com/tiki/server/document/dto/request/DocumentCreateRequest.java index 899c5bc6..f53dff20 100644 --- a/src/main/java/com/tiki/server/document/dto/request/DocumentCreateRequest.java +++ b/src/main/java/com/tiki/server/document/dto/request/DocumentCreateRequest.java @@ -1,10 +1,14 @@ package com.tiki.server.document.dto.request; +import io.swagger.v3.oas.annotations.media.Schema; import lombok.NonNull; public record DocumentCreateRequest( + @Schema(description = "파일 이름", example = "tiki.jpg") @NonNull String fileName, + @Schema(description = "파일 url", example = "https://.../tiki.jpg") @NonNull String fileUrl, + @Schema(description = "파일 용량", example = "1.23") double capacity ) { } diff --git a/src/main/java/com/tiki/server/document/entity/Document.java b/src/main/java/com/tiki/server/document/entity/Document.java index 814e8326..429f21b5 100644 --- a/src/main/java/com/tiki/server/document/entity/Document.java +++ b/src/main/java/com/tiki/server/document/entity/Document.java @@ -6,6 +6,7 @@ import static lombok.AccessLevel.PROTECTED; import com.tiki.server.common.entity.BaseTime; +import com.tiki.server.document.dto.request.DocumentCreateRequest; import com.tiki.server.timeblock.entity.TimeBlock; import jakarta.persistence.Column; @@ -56,12 +57,11 @@ public static Document of(final String fileName, final String fileUrl, final Tim .build(); } - public static Document of(final String fileName, final String fileUrl, - final double capacity, final long teamId, final Long folderId) { + public static Document of(final DocumentCreateRequest request, final long teamId, final Long folderId) { return Document.builder() - .fileName(fileName) - .fileUrl(fileUrl) - .capacity(capacity) + .fileName(request.fileName()) + .fileUrl(request.fileUrl()) + .capacity(request.capacity()) .teamId(teamId) .folderId(folderId) .timeBlock(null) // TODO : 타임 블록 생성 api 수정 후 제거 예정 diff --git a/src/main/java/com/tiki/server/document/service/DocumentService.java b/src/main/java/com/tiki/server/document/service/DocumentService.java index 355b48fd..3c863fa2 100644 --- a/src/main/java/com/tiki/server/document/service/DocumentService.java +++ b/src/main/java/com/tiki/server/document/service/DocumentService.java @@ -19,10 +19,13 @@ import com.tiki.server.document.entity.DeletedDocument; import com.tiki.server.document.entity.Document; import com.tiki.server.document.exception.DocumentException; +import com.tiki.server.external.util.S3Handler; import com.tiki.server.folder.adapter.FolderFinder; import com.tiki.server.folder.entity.Folder; import com.tiki.server.memberteammanager.adapter.MemberTeamManagerFinder; import com.tiki.server.memberteammanager.entity.MemberTeamManager; +import com.tiki.server.team.adapter.TeamFinder; +import com.tiki.server.team.entity.Team; import lombok.RequiredArgsConstructor; @@ -37,6 +40,8 @@ public class DocumentService { private final FolderFinder folderFinder; private final MemberTeamManagerFinder memberTeamManagerFinder; private final DeletedDocumentAdapter deletedDocumentAdapter; + private final TeamFinder teamFinder; + private final S3Handler s3Handler; public DocumentsGetResponse getAllDocuments(final long memberId, final long teamId, final String type) { MemberTeamManager memberTeamManager = memberTeamManagerFinder.findByMemberIdAndTeamId(memberId, teamId); @@ -80,6 +85,8 @@ public void delete(final long memberId, final long teamId, final List docu public void deleteTrash(final long memberId, final long teamId, final List documentIds) { memberTeamManagerFinder.findByMemberIdAndTeamId(memberId, teamId); List deletedDocuments = deletedDocumentAdapter.get(documentIds, teamId); + restoreTeamUsage(teamId, deletedDocuments); + deletedDocuments.forEach(deletedDocument -> s3Handler.deleteFile(deletedDocument.getFileName())); deletedDocumentAdapter.deleteAll(deletedDocuments); } @@ -122,12 +129,18 @@ private void checkFileNameIsDuplicated(final String fileName, final DocumentsCre } private void saveDocuments(final long teamId, final Long folderId, final DocumentsCreateRequest request) { - request.documents().forEach(document -> saveDocument(teamId, folderId, document)); + Team team = teamFinder.findById(teamId); + request.documents().forEach(document -> saveDocument(team, folderId, document)); } - private void saveDocument(final long teamId, final Long folderId, final DocumentCreateRequest request) { - Document document = Document.of( - request.fileName(), request.fileUrl(), request.capacity(), teamId, folderId); + private void saveDocument(final Team team, final Long folderId, final DocumentCreateRequest request) { + team.addUsage(request.capacity()); + Document document = Document.of(request, team.getId(), folderId); documentSaver.save(document); } + + private void restoreTeamUsage(final long teamId, final List deletedDocuments) { + Team team = teamFinder.findById(teamId); + team.restoreUsage(deletedDocuments.stream().mapToDouble(DeletedDocument::getCapacity).sum()); + } } diff --git a/src/main/java/com/tiki/server/external/util/S3Handler.java b/src/main/java/com/tiki/server/external/util/S3Handler.java index 588d21e3..1a6bd5b4 100644 --- a/src/main/java/com/tiki/server/external/util/S3Handler.java +++ b/src/main/java/com/tiki/server/external/util/S3Handler.java @@ -12,7 +12,6 @@ import org.springframework.stereotype.Component; import com.tiki.server.external.config.AWSConfig; -import com.tiki.server.external.dto.request.S3DeleteRequest; import com.tiki.server.external.dto.response.PreSignedUrlResponse; import com.tiki.server.external.exception.ExternalException; diff --git a/src/main/java/com/tiki/server/folder/controller/FolderController.java b/src/main/java/com/tiki/server/folder/controller/FolderController.java index 92e1af19..8afb4fa4 100644 --- a/src/main/java/com/tiki/server/folder/controller/FolderController.java +++ b/src/main/java/com/tiki/server/folder/controller/FolderController.java @@ -21,6 +21,7 @@ import com.tiki.server.common.dto.SuccessResponse; import com.tiki.server.common.support.UriGenerator; +import com.tiki.server.folder.controller.docs.FolderControllerDocs; import com.tiki.server.folder.dto.request.FolderCreateRequest; import com.tiki.server.folder.dto.request.FolderNameUpdateRequest; import com.tiki.server.folder.dto.response.FolderCreateResponse; @@ -32,7 +33,7 @@ @RestController @RequiredArgsConstructor @RequestMapping("api/v1") -public class FolderController { +public class FolderController implements FolderControllerDocs { private final FolderService folderService; diff --git a/src/main/java/com/tiki/server/folder/controller/docs/FolderControllerDocs.java b/src/main/java/com/tiki/server/folder/controller/docs/FolderControllerDocs.java new file mode 100644 index 00000000..57086748 --- /dev/null +++ b/src/main/java/com/tiki/server/folder/controller/docs/FolderControllerDocs.java @@ -0,0 +1,150 @@ +package com.tiki.server.folder.controller.docs; + +import java.security.Principal; +import java.util.List; + +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestParam; + +import com.tiki.server.common.dto.ErrorResponse; +import com.tiki.server.common.dto.SuccessResponse; +import com.tiki.server.document.dto.response.DeletedDocumentsGetResponse; +import com.tiki.server.folder.dto.request.FolderCreateRequest; +import com.tiki.server.folder.dto.request.FolderNameUpdateRequest; +import com.tiki.server.folder.dto.response.FolderCreateResponse; +import com.tiki.server.folder.dto.response.FoldersGetResponse; + +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.enums.ParameterIn; +import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.responses.ApiResponse; + +public interface FolderControllerDocs { + + @Operation( + summary = "폴더 조회", + description = "폴더를 여러 개 조회한다.", + responses = { + @ApiResponse(responseCode = "200", description = "성공"), + @ApiResponse( + responseCode = "4xx", + description = "클라이언트(요청) 오류", + content = @Content(schema = @Schema(implementation = ErrorResponse.class))), + @ApiResponse( + responseCode = "500", + description = "서버 내부 오류", + content = @Content(schema = @Schema(implementation = ErrorResponse.class)))} + ) + ResponseEntity> getFolders( + @Parameter(hidden = true) Principal principal, + @Parameter( + name = "팀 id", + description = "팀 id", + in = ParameterIn.PATH, + example = "1" + ) @PathVariable long teamId, + @Parameter( + name = "폴더 id", + description = "조회할 폴더 id", + in = ParameterIn.QUERY, + example = "1" + ) @RequestParam Long folderId + ); + + @Operation( + summary = "폴더 생성", + description = "폴더를 생성한다.", + responses = { + @ApiResponse(responseCode = "201", description = "성공"), + @ApiResponse( + responseCode = "4xx", + description = "클라이언트(요청) 오류", + content = @Content(schema = @Schema(implementation = ErrorResponse.class))), + @ApiResponse( + responseCode = "500", + description = "서버 내부 오류", + content = @Content(schema = @Schema(implementation = ErrorResponse.class)))} + ) + ResponseEntity> createFolder( + @Parameter(hidden = true) Principal principal, + @Parameter( + name = "팀 id", + description = "팀 id", + in = ParameterIn.PATH, + example = "1" + ) @PathVariable long teamId, + @Parameter( + name = "폴더 id", + description = "생성할 폴더가 속할 폴더 id", + in = ParameterIn.QUERY, + example = "1" + ) @RequestParam Long folderId, + @RequestBody FolderCreateRequest request + ); + + @Operation( + summary = "폴더 이름 수정", + description = "폴더 이름을 수정한다.", + responses = { + @ApiResponse(responseCode = "200", description = "성공"), + @ApiResponse( + responseCode = "4xx", + description = "클라이언트(요청) 오류", + content = @Content(schema = @Schema(implementation = ErrorResponse.class))), + @ApiResponse( + responseCode = "500", + description = "서버 내부 오류", + content = @Content(schema = @Schema(implementation = ErrorResponse.class)))} + ) + ResponseEntity> updateFolderName( + @Parameter(hidden = true) Principal principal, + @Parameter( + name = "팀 id", + description = "팀 id", + in = ParameterIn.PATH, + example = "1" + ) @PathVariable long teamId, + @Parameter( + name = "폴더 id", + description = "수정할 폴더 id", + in = ParameterIn.PATH, + example = "1" + ) @PathVariable long folderId, + @RequestBody FolderNameUpdateRequest request + ); + + @Operation( + summary = "폴더 삭제", + description = "폴더를 여러 개 삭제한다.", + responses = { + @ApiResponse(responseCode = "204", description = "성공"), + @ApiResponse( + responseCode = "4xx", + description = "클라이언트(요청) 오류", + content = @Content(schema = @Schema(implementation = ErrorResponse.class))), + @ApiResponse( + responseCode = "500", + description = "서버 내부 오류", + content = @Content(schema = @Schema(implementation = ErrorResponse.class)))} + ) + ResponseEntity delete( + @Parameter(hidden = true) Principal principal, + @Parameter( + name = "팀 id", + description = "팀 id", + in = ParameterIn.PATH, + example = "1" + ) @PathVariable long teamId, + @Parameter( + name = "폴더 id", + description = "삭제할 폴더 id 리스트", + in = ParameterIn.QUERY, + required = true, + example = "[1, 2]" + ) @RequestParam("folderId") List folderIds + ); +} diff --git a/src/main/java/com/tiki/server/folder/dto/request/FolderCreateRequest.java b/src/main/java/com/tiki/server/folder/dto/request/FolderCreateRequest.java index 799af52f..e2979e4c 100644 --- a/src/main/java/com/tiki/server/folder/dto/request/FolderCreateRequest.java +++ b/src/main/java/com/tiki/server/folder/dto/request/FolderCreateRequest.java @@ -1,8 +1,10 @@ package com.tiki.server.folder.dto.request; +import io.swagger.v3.oas.annotations.media.Schema; import lombok.NonNull; public record FolderCreateRequest( + @Schema(description = "폴더 이름", example = "폴더 1") @NonNull String name ) { } diff --git a/src/main/java/com/tiki/server/folder/dto/request/FolderNameUpdateRequest.java b/src/main/java/com/tiki/server/folder/dto/request/FolderNameUpdateRequest.java index 3fe63e98..dfff32e6 100644 --- a/src/main/java/com/tiki/server/folder/dto/request/FolderNameUpdateRequest.java +++ b/src/main/java/com/tiki/server/folder/dto/request/FolderNameUpdateRequest.java @@ -1,8 +1,10 @@ package com.tiki.server.folder.dto.request; +import io.swagger.v3.oas.annotations.media.Schema; import lombok.NonNull; public record FolderNameUpdateRequest( + @Schema(description = "수정할 폴더 이름", example = "수정할 폴더 1") @NonNull String name ) { } \ No newline at end of file diff --git a/src/main/java/com/tiki/server/team/controller/TeamController.java b/src/main/java/com/tiki/server/team/controller/TeamController.java index 22a31e1e..872efe47 100644 --- a/src/main/java/com/tiki/server/team/controller/TeamController.java +++ b/src/main/java/com/tiki/server/team/controller/TeamController.java @@ -6,11 +6,13 @@ import java.security.Principal; import com.tiki.server.common.dto.BaseResponse; -import com.tiki.server.team.controller.dto.request.UpdateTeamIconRequest; -import com.tiki.server.team.controller.dto.request.UpdateTeamNameRequest; +import com.tiki.server.team.dto.request.UpdateTeamIconRequest; +import com.tiki.server.team.dto.request.UpdateTeamNameRequest; +import com.tiki.server.team.dto.response.UsageGetResponse; import com.tiki.server.team.dto.response.CategoriesGetResponse; import com.tiki.server.team.dto.response.TeamsGetResponse; +import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; @@ -100,4 +102,15 @@ public ResponseEntity alterAdmin( teamService.alterAdmin(memberId, teamId, targetId); return ResponseEntity.ok(success(SUCCESS_ALTER_AUTHORITY.getMessage())); } + + @ResponseStatus(HttpStatus.OK) + @GetMapping("/{teamId}/capacity") + public SuccessResponse getCapacityInfo( + final Principal principal, + @PathVariable final long teamId + ) { + long memberId = Long.parseLong(principal.getName()); + UsageGetResponse response = teamService.getCapacityInfo(memberId, teamId); + return success(SUCCESS_GET_CAPACITY_INFO.getMessage(), response); + } } diff --git a/src/main/java/com/tiki/server/team/controller/docs/TeamControllerDocs.java b/src/main/java/com/tiki/server/team/controller/docs/TeamControllerDocs.java index 5a153c51..33909fa6 100644 --- a/src/main/java/com/tiki/server/team/controller/docs/TeamControllerDocs.java +++ b/src/main/java/com/tiki/server/team/controller/docs/TeamControllerDocs.java @@ -3,6 +3,7 @@ import java.security.Principal; import com.tiki.server.common.dto.BaseResponse; +import com.tiki.server.team.dto.response.UsageGetResponse; import com.tiki.server.team.dto.response.CategoriesGetResponse; import com.tiki.server.team.dto.response.TeamsGetResponse; @@ -111,6 +112,33 @@ ResponseEntity deleteTeam( name = "teamId", description = "팀 id", in = ParameterIn.PATH, + required = true, + example = "1" + ) + @PathVariable long teamId + ); + + @Operation( + summary = "팀 용량 정보 조회", + description = "팀 용량 정보를 조회한다.", + responses = { + @ApiResponse(responseCode = "200", description = "성공"), + @ApiResponse( + responseCode = "4xx", + description = "클라이언트(요청) 오류", + content = @Content(schema = @Schema(implementation = ErrorResponse.class))), + @ApiResponse( + responseCode = "500", + description = "서버 내부 오류", + content = @Content(schema = @Schema(implementation = ErrorResponse.class)))} + ) + SuccessResponse getCapacityInfo( + @Parameter(hidden = true) Principal principal, + @Parameter( + name = "teamId", + description = "팀 id", + in = ParameterIn.PATH, + required = true, example = "1" ) @PathVariable long teamId diff --git a/src/main/java/com/tiki/server/team/controller/dto/request/UpdateTeamIconRequest.java b/src/main/java/com/tiki/server/team/dto/request/UpdateTeamIconRequest.java similarity index 50% rename from src/main/java/com/tiki/server/team/controller/dto/request/UpdateTeamIconRequest.java rename to src/main/java/com/tiki/server/team/dto/request/UpdateTeamIconRequest.java index 4a0e039a..4f03c8b9 100644 --- a/src/main/java/com/tiki/server/team/controller/dto/request/UpdateTeamIconRequest.java +++ b/src/main/java/com/tiki/server/team/dto/request/UpdateTeamIconRequest.java @@ -1,8 +1,8 @@ -package com.tiki.server.team.controller.dto.request; +package com.tiki.server.team.dto.request; import jakarta.validation.constraints.NotNull; public record UpdateTeamIconRequest( - @NotNull String iconImageUrl + @NotNull String iconImageUrl ) { } diff --git a/src/main/java/com/tiki/server/team/controller/dto/request/UpdateTeamNameRequest.java b/src/main/java/com/tiki/server/team/dto/request/UpdateTeamNameRequest.java similarity index 50% rename from src/main/java/com/tiki/server/team/controller/dto/request/UpdateTeamNameRequest.java rename to src/main/java/com/tiki/server/team/dto/request/UpdateTeamNameRequest.java index 278810df..be72834f 100644 --- a/src/main/java/com/tiki/server/team/controller/dto/request/UpdateTeamNameRequest.java +++ b/src/main/java/com/tiki/server/team/dto/request/UpdateTeamNameRequest.java @@ -1,8 +1,8 @@ -package com.tiki.server.team.controller.dto.request; +package com.tiki.server.team.dto.request; import jakarta.validation.constraints.NotNull; public record UpdateTeamNameRequest( - @NotNull String newTeamName + @NotNull String newTeamName ) { } diff --git a/src/main/java/com/tiki/server/team/dto/response/TeamGetResponse.java b/src/main/java/com/tiki/server/team/dto/response/TeamGetResponse.java index c40fcef6..58aecbec 100644 --- a/src/main/java/com/tiki/server/team/dto/response/TeamGetResponse.java +++ b/src/main/java/com/tiki/server/team/dto/response/TeamGetResponse.java @@ -4,6 +4,7 @@ import com.tiki.server.team.entity.Category; import com.tiki.server.team.entity.Team; import com.tiki.server.team.vo.TeamVO; + import lombok.Builder; import lombok.NonNull; @@ -11,22 +12,22 @@ @Builder(access = PRIVATE) public record TeamGetResponse( - long teamId, - @NonNull String name, - @NonNull Category category, - @NonNull University univ, - String overview, - String imageUrl + long teamId, + @NonNull String name, + @NonNull Category category, + @NonNull University univ, + String overview, + String imageUrl ) { - public static TeamGetResponse from(TeamVO team) { - return TeamGetResponse.builder() - .teamId(team.teamId()) - .name(team.name()) - .overview(team.overview()) - .category(team.category()) - .univ(team.univ()) - .imageUrl(team.imageUrl()) - .build(); - } + public static TeamGetResponse from(TeamVO team) { + return TeamGetResponse.builder() + .teamId(team.teamId()) + .name(team.name()) + .overview(team.overview()) + .category(team.category()) + .univ(team.univ()) + .imageUrl(team.imageUrl()) + .build(); + } } diff --git a/src/main/java/com/tiki/server/team/dto/response/TeamsGetResponse.java b/src/main/java/com/tiki/server/team/dto/response/TeamsGetResponse.java index 9ee0fa1c..f38f188b 100644 --- a/src/main/java/com/tiki/server/team/dto/response/TeamsGetResponse.java +++ b/src/main/java/com/tiki/server/team/dto/response/TeamsGetResponse.java @@ -1,6 +1,7 @@ package com.tiki.server.team.dto.response; import com.tiki.server.team.vo.TeamVO; + import lombok.Builder; import java.util.List; @@ -9,11 +10,11 @@ @Builder(access = PRIVATE) public record TeamsGetResponse( - List teams + List teams ) { - public static TeamsGetResponse from(List teams) { - return TeamsGetResponse.builder() - .teams(teams.stream().map(TeamGetResponse::from).toList()) - .build(); - } + public static TeamsGetResponse from(List teams) { + return TeamsGetResponse.builder() + .teams(teams.stream().map(TeamGetResponse::from).toList()) + .build(); + } } diff --git a/src/main/java/com/tiki/server/team/dto/response/UsageGetResponse.java b/src/main/java/com/tiki/server/team/dto/response/UsageGetResponse.java new file mode 100644 index 00000000..0dae4afc --- /dev/null +++ b/src/main/java/com/tiki/server/team/dto/response/UsageGetResponse.java @@ -0,0 +1,19 @@ +package com.tiki.server.team.dto.response; + +import static lombok.AccessLevel.PRIVATE; + +import lombok.Builder; + +@Builder(access = PRIVATE) +public record UsageGetResponse( + double capacity, + double usage +) { + + public static UsageGetResponse of(final double capacity, final double usage) { + return UsageGetResponse.builder() + .capacity(capacity) + .usage(usage) + .build(); + } +} diff --git a/src/main/java/com/tiki/server/team/entity/Subscribe.java b/src/main/java/com/tiki/server/team/entity/Subscribe.java new file mode 100644 index 00000000..ad4f6c1c --- /dev/null +++ b/src/main/java/com/tiki/server/team/entity/Subscribe.java @@ -0,0 +1,22 @@ +package com.tiki.server.team.entity; + +import lombok.Getter; + +@Getter +public enum Subscribe { + BASIC(6000, 30000, 30, false), + ADVANCED(13000, 150000, 120, true), + PREMIUM(25000, 500000, 999999, true); + + private final int price; + private final double capacity; + private final int memberLimit; + private final boolean bannerDiscount; + + Subscribe(int price, double capacity, int memberLimit, boolean bannerDiscount) { + this.price = price; + this.capacity = capacity; + this.memberLimit = memberLimit; + this.bannerDiscount = bannerDiscount; + } +} diff --git a/src/main/java/com/tiki/server/team/entity/Team.java b/src/main/java/com/tiki/server/team/entity/Team.java index 5db50789..25766cbb 100644 --- a/src/main/java/com/tiki/server/team/entity/Team.java +++ b/src/main/java/com/tiki/server/team/entity/Team.java @@ -1,5 +1,8 @@ package com.tiki.server.team.entity; +import static com.tiki.server.common.Constants.INIT_NUM; +import static com.tiki.server.team.entity.Subscribe.BASIC; +import static com.tiki.server.team.message.ErrorCode.EXCEED_TEAM_CAPACITY; import static com.tiki.server.team.message.ErrorCode.TOO_SHORT_PERIOD; import static jakarta.persistence.EnumType.STRING; import static jakarta.persistence.GenerationType.IDENTITY; @@ -12,6 +15,7 @@ import com.tiki.server.team.exception.TeamException; import jakarta.persistence.Column; +import jakarta.persistence.Embedded; import jakarta.persistence.Entity; import jakarta.persistence.Enumerated; import jakarta.persistence.GeneratedValue; @@ -45,9 +49,15 @@ public class Team extends BaseTime { @Enumerated(value = STRING) private University univ; + @Enumerated(value = STRING) + private Subscribe subscribe; + + private double usage; + private String imageUrl; private String iconImageUrl; + private LocalDate namingUpdatedAt; public static Team of(TeamCreateRequest request, University univ) { @@ -55,6 +65,8 @@ public static Team of(TeamCreateRequest request, University univ) { .name(request.name()) .category(request.category()) .univ(univ) + .subscribe(BASIC) + .usage(INIT_NUM) .namingUpdatedAt(null) .iconImageUrl(request.iconImageUrl()) .build(); @@ -68,7 +80,7 @@ public void updateName(final String name) { this.namingUpdatedAt = LocalDate.now(); } - public void setIconImageUrl(final String url) { + public void updateIconImageUrl(final String url) { this.iconImageUrl = url; } @@ -76,6 +88,21 @@ public boolean isDefaultImage() { return this.getIconImageUrl().isBlank(); } + public void addUsage(double capacity) { + if (usage + capacity > subscribe.getCapacity()) { + throw new TeamException(EXCEED_TEAM_CAPACITY); + } + usage += capacity; + } + + public void restoreUsage(double capacity) { + usage -= capacity; + } + + public double getCapacity() { + return subscribe.getCapacity(); + } + private boolean canChangeName() { if (namingUpdatedAt == null) { return true; diff --git a/src/main/java/com/tiki/server/team/message/ErrorCode.java b/src/main/java/com/tiki/server/team/message/ErrorCode.java index a80d0766..3aac099a 100644 --- a/src/main/java/com/tiki/server/team/message/ErrorCode.java +++ b/src/main/java/com/tiki/server/team/message/ErrorCode.java @@ -14,6 +14,7 @@ public enum ErrorCode { /* 400 BAD_REQUEST : 잘못된 요청 */ TOO_HIGH_AUTHORIZATION(BAD_REQUEST, "어드민은 진행할 수 없습니다."), TOO_SHORT_PERIOD(BAD_REQUEST, "30일이 지나야 이름을 변경할 수 있습니다."), + EXCEED_TEAM_CAPACITY(BAD_REQUEST, "팀 사용 가능 용량을 초과하였습니다."), /* 403 FORBIDDEN : 권한 없음 */ INVALID_AUTHORIZATION_DELETE(FORBIDDEN, "권한이 없습니다."), diff --git a/src/main/java/com/tiki/server/team/message/SuccessMessage.java b/src/main/java/com/tiki/server/team/message/SuccessMessage.java index 7454e072..ca57403e 100644 --- a/src/main/java/com/tiki/server/team/message/SuccessMessage.java +++ b/src/main/java/com/tiki/server/team/message/SuccessMessage.java @@ -13,7 +13,8 @@ public enum SuccessMessage { SUCCESS_ALTER_AUTHORITY("어드민 권한 위임 성공"), SUCCESS_GET_TEAMS("전체 팀 불러오기 성공"), SUCCESS_GET_CATEGORIES("카테고리 리스트 불러오기 성공"), - SUCCESS_GET_JOINED_TEAM("소속 팀 불러오기 성공"); + SUCCESS_GET_JOINED_TEAM("소속 팀 불러오기 성공"), + SUCCESS_GET_CAPACITY_INFO("팀 용량 정보 조회 성공"); private final String message; } diff --git a/src/main/java/com/tiki/server/team/service/TeamService.java b/src/main/java/com/tiki/server/team/service/TeamService.java index d06c25e9..cf63dddc 100644 --- a/src/main/java/com/tiki/server/team/service/TeamService.java +++ b/src/main/java/com/tiki/server/team/service/TeamService.java @@ -12,6 +12,7 @@ import com.tiki.server.memberteammanager.adapter.MemberTeamManagerFinder; import com.tiki.server.team.adapter.TeamDeleter; import com.tiki.server.team.adapter.TeamFinder; +import com.tiki.server.team.dto.response.UsageGetResponse; import com.tiki.server.team.dto.response.CategoriesGetResponse; import com.tiki.server.team.dto.response.TeamsGetResponse; @@ -29,7 +30,6 @@ import com.tiki.server.team.dto.response.TeamCreateResponse; import com.tiki.server.team.entity.Category; import com.tiki.server.team.entity.Team; -import com.tiki.server.team.exception.TeamException; import com.tiki.server.team.vo.TeamVO; import com.tiki.server.timeblock.adapter.TimeBlockDeleter; @@ -99,7 +99,7 @@ public void updateIconImage(final long memberId, final long teamId, final String checkIsAdmin(memberId, teamId); Team team = teamFinder.findById(teamId); deleteIconUrl(team); - team.setIconImageUrl(iconImageUrl); + team.updateIconImageUrl(iconImageUrl); } @Transactional @@ -110,6 +110,14 @@ public void alterAdmin(final long memberId, final long teamId, final long target newAdmin.updatePositionToAdmin(); } + public UsageGetResponse getCapacityInfo(final long memberId, final long teamId) { + memberTeamManagerFinder.findByMemberIdAndTeamId(memberId, teamId); + Team team = teamFinder.findById(teamId); + double capacity = team.getCapacity(); + double usage = team.getUsage(); + return UsageGetResponse.of(capacity, usage); + } + private MemberTeamManager createMemberTeamManager(final Member member, final Team team, final Position position) { return MemberTeamManager.of(member, team, position); } diff --git a/src/main/java/com/tiki/server/timeblock/controller/docs/TimeBlockControllerDocs.java b/src/main/java/com/tiki/server/timeblock/controller/docs/TimeBlockControllerDocs.java index ba96ee97..13023a62 100644 --- a/src/main/java/com/tiki/server/timeblock/controller/docs/TimeBlockControllerDocs.java +++ b/src/main/java/com/tiki/server/timeblock/controller/docs/TimeBlockControllerDocs.java @@ -64,6 +64,7 @@ ResponseEntity> createTimeBlock( name = "type", description = "타임라인 타입", in = ParameterIn.QUERY, + required = true, example = "executive, member" ) @RequestParam String type, @RequestBody TimeBlockCreateRequest request @@ -108,12 +109,14 @@ ResponseEntity> getTimeline( name = "type", description = "타임라인 타입", in = ParameterIn.QUERY, + required = true, example = "executive, member" ) @RequestParam String type, @Parameter( name = "date", description = "조회할 타임라인의 년도와 월 정보", in = ParameterIn.QUERY, + required = true, example = "2024-07" ) @RequestParam String date ); diff --git a/src/main/java/com/tiki/server/timeblock/entity/BlockType.java b/src/main/java/com/tiki/server/timeblock/entity/BlockType.java index 17cfb8e8..44be82f5 100644 --- a/src/main/java/com/tiki/server/timeblock/entity/BlockType.java +++ b/src/main/java/com/tiki/server/timeblock/entity/BlockType.java @@ -1,5 +1,5 @@ package com.tiki.server.timeblock.entity; public enum BlockType { - MEETING, ACCOUNTING, TASK, NOTICE, STUDY, EVENT + MEETING, RECRUITING, STUDY, EVENT, NOTICE, ETC }