Skip to content

Commit

Permalink
Merge pull request #565 from woowacourse-teams/dev/be
Browse files Browse the repository at this point in the history
[BE] 코드잽 프로덕션 v1.1.0 배포
  • Loading branch information
HoeSeong123 authored Aug 23, 2024
2 parents 511d0c4 + 153a976 commit c4c8822
Show file tree
Hide file tree
Showing 74 changed files with 1,670 additions and 1,711 deletions.
37 changes: 12 additions & 25 deletions .github/workflows/backend_cd.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,16 @@ name: Backend CD
on:
push:
branches:
- main
- dev/be

jobs:
build:
runs-on: [self-hosted, develop, spring]
runs-on:
- self-hosted
- spring
- ${{ contains(github.ref, 'main') && 'production' || 'develop' }}
steps:
- name: 브랜치명을 통해 개발 환경 알아내기
run: |
cd ${{ secrets.SCRIPT_DIRECTORY }}
bash find-env-by-branch.sh
- name: 체크아웃
uses: actions/checkout@v4

Expand All @@ -23,7 +22,7 @@ jobs:
- name: bootJar로 jar 파일 생성
run: |
./gradlew bootJar
mv build/libs/*.jar ${{ secrets.WORK_DIRECTORY }}/${{ env.ENVIRONMENT }}
mv build/libs/*.jar ${{ secrets.JAR_DIRECTORY }}
working-directory: ./backend

- name: 클린업
Expand All @@ -32,24 +31,12 @@ jobs:

deploy:
needs: build
runs-on: [self-hosted, develop, spring]
runs-on:
- self-hosted
- spring
- ${{ contains(github.ref, 'main') && 'production' || 'develop' }}
steps:
- name: 브랜치명을 통해 개발 환경 알아내기
run: |
cd ${{ secrets.SCRIPT_DIRECTORY }}
bash find-env-by-branch.sh
- name: 실행 프로세스 확인
run: |
cd ${{ secrets.SCRIPT_DIRECTORY }}
bash check-old-pids.sh
- name: 배포 스크립트 실행
run: |
cd ${{ secrets.SCRIPT_DIRECTORY }}
RUNNER_TRACKING_ID="" && bash start.sh ${{ env.ENVIRONMENT }}
- name: 실행 프로세스 확인으로 배포 검증
run: |
cd ${{ secrets.SCRIPT_DIRECTORY }}
bash verify-deploy.sh
cd ${{ secrets.ZAP_DIRECTORY }}
docker compose restart
35 changes: 0 additions & 35 deletions .github/workflows/backend_cd_prod.yml

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import codezap.member.domain.Member;

public record LoginResponse(
long memberId,
Long memberId,
String name
) {
public static LoginResponse from(Member member) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ public String createCredential(Member member) {
@Override
public Member extractMember(String credential) {
String[] nameAndPassword = BasicAuthDecoder.decodeBasicAuth(credential);
Member member = memberRepository.fetchByname(nameAndPassword[0]);
Member member = memberRepository.fetchByName(nameAndPassword[0]);
checkMatchPassword(member, nameAndPassword[1]);
return member;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ public LoginAndCredentialDto login(LoginRequest loginRequest) {
}

private Member getVerifiedMember(String name, String password) {
Member member = memberRepository.fetchByname(name);
Member member = memberRepository.fetchByName(name);
validateCorrectPassword(member, password);
return member;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@
import codezap.category.dto.request.UpdateCategoryRequest;
import codezap.category.dto.response.CreateCategoryResponse;
import codezap.category.dto.response.FindAllCategoriesResponse;
import codezap.category.service.CategoryService;
import codezap.category.service.facade.MemberCategoryApplicationService;
import codezap.category.service.facade.MemberCategoryTemplateApplicationService;
import codezap.global.validation.ValidationSequence;
import codezap.member.dto.MemberDto;
import lombok.RequiredArgsConstructor;
Expand All @@ -29,24 +30,24 @@
@RequestMapping("/categories")
public class CategoryController implements SpringDocCategoryController {

private final CategoryService categoryService;
private final MemberCategoryApplicationService memberCategoryApplicationService;
private final MemberCategoryTemplateApplicationService memberCategoryTemplateApplicationService;

@PostMapping
public ResponseEntity<CreateCategoryResponse> createCategory(
@AuthenticationPrinciple MemberDto memberDto,
@Validated(ValidationSequence.class) @RequestBody CreateCategoryRequest createCategoryRequest
) {
CreateCategoryResponse response = categoryService.create(memberDto, createCategoryRequest);
return ResponseEntity.created(URI.create("/categories/" + response.id()))
.body(response);
CreateCategoryResponse createdCategory = memberCategoryApplicationService.create(memberDto, createCategoryRequest);
return ResponseEntity.created(URI.create("/categories/" + createdCategory.id()))
.body(createdCategory);
}

@GetMapping
public ResponseEntity<FindAllCategoriesResponse> getCategories(
@AuthenticationPrinciple MemberDto memberDto,
@RequestParam Long memberId
) {
return ResponseEntity.ok(categoryService.findAllByMember(memberId));
return ResponseEntity.ok(memberCategoryApplicationService.findAllByMember(memberId));
}

@PutMapping("/{id}")
Expand All @@ -55,13 +56,13 @@ public ResponseEntity<Void> updateCategory(
@PathVariable Long id,
@Validated(ValidationSequence.class) @RequestBody UpdateCategoryRequest updateCategoryRequest
) {
categoryService.update(memberDto, id, updateCategoryRequest);
memberCategoryApplicationService.update(memberDto, id, updateCategoryRequest);
return ResponseEntity.ok().build();
}

@DeleteMapping("/{id}")
public ResponseEntity<Void> deleteCategory(@AuthenticationPrinciple MemberDto memberDto, @PathVariable Long id) {
categoryService.deleteById(memberDto, id);
memberCategoryTemplateApplicationService.deleteById(memberDto, id);
return ResponseEntity.noContent()
.build();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ public interface SpringDocCategoryController {
@Header(name = "생성된 카테고리의 API 경로", example = "/categories/1")})
@ApiErrorResponse(status = HttpStatus.BAD_REQUEST, instance = "/categories", errorCases = {
@ErrorCase(description = "모든 필드 중 null인 값이 있는 경우", exampleMessage = "카테고리 이름이 null 입니다."),
@ErrorCase(description = "카테고리 이름이 255자를 초과한 경우", exampleMessage = "카테고리 이름은 최대 255자까지 입력 가능합니다."),
@ErrorCase(description = "카테고리 이름이 15자를 초과한 경우", exampleMessage = "카테고리 이름은 최대 15자까지 입력 가능합니다."),
@ErrorCase(description = "동일한 이름의 카테고리가 존재하는 경우", exampleMessage = "이름이 Spring 인 카테고리가 이미 존재합니다."),
})
ResponseEntity<CreateCategoryResponse> createCategory(
Expand All @@ -42,20 +42,18 @@ ResponseEntity<CreateCategoryResponse> createCategory(
@Operation(summary = "카테고리 목록 조회", description = "생성된 모든 카테고리를 조회합니다.")
@ApiResponse(responseCode = "200", description = "조회 성공",
content = {@Content(schema = @Schema(implementation = FindAllCategoriesResponse.class))})
ResponseEntity<FindAllCategoriesResponse> getCategories(MemberDto memberDto, Long memberId);
ResponseEntity<FindAllCategoriesResponse> getCategories(Long memberId);

@SecurityRequirement(name = "쿠키 인증 토큰")
@Operation(summary = "카테고리 수정", description = "해당하는 식별자의 카테고리를 수정합니다.")
@ApiResponse(responseCode = "200", description = "카테고리 수정 성공")
@ApiErrorResponse(status = HttpStatus.BAD_REQUEST, instance = "/categories/1", errorCases = {
@ErrorCase(description = "해당하는 id 값인 카테고리가 없는 경우",
exampleMessage = "식별자 1에 해당하는 카테고리가 존재하지 않습니다."),
@ErrorCase(description = "동일한 이름의 카테고리가 존재하는 경우",
exampleMessage = "이름이 Spring 인 카테고리가 이미 존재합니다."),
@ErrorCase(description = "카테고리 이름이 15자를 초과한 경우", exampleMessage = "카테고리 이름은 최대 15자까지 입력 가능합니다."),
@ErrorCase(description = "해당하는 id 값인 카테고리가 없는 경우", exampleMessage = "식별자 1에 해당하는 카테고리가 존재하지 않습니다."),
@ErrorCase(description = "동일한 이름의 카테고리가 존재하는 경우", exampleMessage = "이름이 Spring 인 카테고리가 이미 존재합니다."),
})
@ApiErrorResponse(status = HttpStatus.FORBIDDEN, instance = "/categories/1", errorCases = {
@ErrorCase(description = "카테고리를 수정할 권한이 없는 경우",
exampleMessage = "해당 카테고리를 수정 또는 삭제할 권한이 없는 유저입니다.")
@ErrorCase(description = "카테고리를 수정할 권한이 없는 경우", exampleMessage = "해당 카테고리를 수정 또는 삭제할 권한이 없는 유저입니다.")
})
ResponseEntity<Void> updateCategory(MemberDto memberDto, Long id, UpdateCategoryRequest updateCategoryRequest);

Expand Down
9 changes: 9 additions & 0 deletions backend/src/main/java/codezap/category/domain/Category.java
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,10 @@
import jakarta.persistence.Table;
import jakarta.persistence.UniqueConstraint;

import org.springframework.http.HttpStatus;

import codezap.global.auditing.BaseTimeEntity;
import codezap.global.exception.CodeZapException;
import codezap.member.domain.Member;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
Expand Down Expand Up @@ -62,6 +65,12 @@ public void updateName(String name) {
this.name = name;
}

public void validateAuthorization(Member member) {
if (!member.equals(this.member)) {
throw new CodeZapException(HttpStatus.UNAUTHORIZED, "해당 카테고리에 대한 권한이 없습니다.");
}
}

@Override
public boolean equals(Object o) {
if (this == o) {
Expand Down
49 changes: 15 additions & 34 deletions backend/src/main/java/codezap/category/service/CategoryService.java
Original file line number Diff line number Diff line change
Expand Up @@ -12,43 +12,44 @@
import codezap.category.repository.CategoryRepository;
import codezap.global.exception.CodeZapException;
import codezap.member.domain.Member;
import codezap.member.dto.MemberDto;
import codezap.member.repository.MemberRepository;
import codezap.template.repository.TemplateRepository;
import lombok.RequiredArgsConstructor;

@Service
@RequiredArgsConstructor
public class CategoryService {

private final CategoryRepository categoryRepository;
private final TemplateRepository templateRepository;
private final MemberRepository memberRepository;

@Transactional
public CreateCategoryResponse create(MemberDto memberDto, CreateCategoryRequest createCategoryRequest) {
public CreateCategoryResponse create(Member member, CreateCategoryRequest createCategoryRequest) {
String categoryName = createCategoryRequest.name();
Member member = memberRepository.fetchById(memberDto.id());
validateDuplicatedCategory(categoryName, member);
Category category = categoryRepository.save(new Category(categoryName, member));
return CreateCategoryResponse.from(category);
}
}

public FindAllCategoriesResponse findAllByMember(Long memberId) {
Member member = memberRepository.fetchById(memberId);
public FindAllCategoriesResponse findAllByMember(Member member) {
return FindAllCategoriesResponse.from(categoryRepository.findAllByMemberOrderById(member));
}

public FindAllCategoriesResponse findAll() {
return FindAllCategoriesResponse.from(categoryRepository.findAll());
}

public Category fetchById(Long id) {
return categoryRepository.fetchById(id);
}

public void validateExistsById(Long id) {
if (!categoryRepository.existsById(id)) {
throw new CodeZapException(HttpStatus.NOT_FOUND, "식별자 " + id + "에 해당하는 카테고리가 존재하지 않습니다.");
}
}

@Transactional
public void update(MemberDto memberDto, Long id, UpdateCategoryRequest updateCategoryRequest) {
Member member = memberRepository.fetchById(memberDto.id());
public void update(Member member, Long id, UpdateCategoryRequest updateCategoryRequest) {
validateDuplicatedCategory(updateCategoryRequest.name(), member);
Category category = categoryRepository.fetchById(id);
validateAuthorizeMember(category, member);
category.validateAuthorization(member);
category.updateName(updateCategoryRequest.name());
}

Expand All @@ -57,24 +58,4 @@ private void validateDuplicatedCategory(String categoryName, Member member) {
throw new CodeZapException(HttpStatus.CONFLICT, "이름이 " + categoryName + "인 카테고리가 이미 존재합니다.");
}
}

public void deleteById(MemberDto memberDto, Long id) {
Category category = categoryRepository.fetchById(id);
Member member = memberRepository.fetchById(memberDto.id());
validateAuthorizeMember(category, member);

if (templateRepository.existsByCategoryId(id)) {
throw new CodeZapException(HttpStatus.BAD_REQUEST, "템플릿이 존재하는 카테고리는 삭제할 수 없습니다.");
}
if (category.getIsDefault()) {
throw new CodeZapException(HttpStatus.BAD_REQUEST, "기본 카테고리는 삭제할 수 없습니다.");
}
categoryRepository.deleteById(id);
}

private void validateAuthorizeMember(Category category, Member member) {
if (!category.getMember().equals(member)) {
throw new CodeZapException(HttpStatus.FORBIDDEN, "해당 카테고리를 수정 또는 삭제할 권한이 없는 유저입니다.");
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package codezap.category.service;

import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import codezap.category.domain.Category;
import codezap.category.repository.CategoryRepository;
import codezap.global.exception.CodeZapException;
import codezap.member.domain.Member;
import codezap.template.repository.TemplateRepository;
import lombok.RequiredArgsConstructor;

@Service
@RequiredArgsConstructor
public class CategoryTemplateService {

private final CategoryRepository categoryRepository;
private final TemplateRepository templateRepository;

@Transactional
public void deleteById(Member member, Long id) {
Category category = categoryRepository.fetchById(id);
validateAuthorizeMember(category, member);

if (templateRepository.existsByCategoryId(id)) {
throw new CodeZapException(HttpStatus.BAD_REQUEST, "템플릿이 존재하는 카테고리는 삭제할 수 없습니다.");
}
if (category.getIsDefault()) {
throw new CodeZapException(HttpStatus.BAD_REQUEST, "기본 카테고리는 삭제할 수 없습니다.");
}
categoryRepository.deleteById(id);
}

private void validateAuthorizeMember(Category category, Member member) {
if (!category.getMember().equals(member)) {
throw new CodeZapException(HttpStatus.FORBIDDEN, "해당 카테고리를 수정 또는 삭제할 권한이 없는 유저입니다.");
}
}
}
Loading

0 comments on commit c4c8822

Please sign in to comment.