Skip to content

Commit d884a28

Browse files
authored
[feat] 조직도 API 추가
* feat: 엔티티 파일 생성 * feat: 회장단 생성 DTO * feat: 회장단 레포지토리 생성 * feat: 회장단 서비스 생성 * feat: 임원진 컨트롤러 생성 * rename: 파일 이름 수정 -> 파일 이름 맨앞 대문자 수정 * feat: 임원진 요청 Dto 생성 및 작성 * feat: 임원진 멤버 생성 서비스 기능 추가 * comment: 주석 수정 * feat: 임원진 멤버 생성 컨트롤러 추가 * feat: 임원진 서비스 테스트 파일 추가 * rename: 스키마 이름 수정 * feat: 임원진 응답 Dto 파일 생성 * rename: 코드 수정 * feat: 임원진 수정 요청 DTO * feat: 임원진 조회 ( 이름, 역할, 깃허브 주소 반환 ) 기능 추가 * feat: 임원진 멤버 조회 테스트 코드 추가 * feat: 임원진 멤버 수정 기능 추가 * feat: 임원진 멤버 수정 테스트 추가 * feat: 임원진 멤버 삭제 기능 추가 * feat: 임원진 멤버 삭제 테스트 추가 * rename: 엔드포인트 네이밍 규칙 적용 * rename: 파일이름 오탈자 수정 * feat: enum 파일 추가 * feat: 커스텀 에러 추가 및 예외처리 적용 * feat: ExecutiveService 인터페이스 구현 및 기존 파일 이름 변경 (DASOMBE-14) * feat: 임원진 전체 조회 기능 추가 (DASOMBE-14) * feat: 생성, 수정, 삭제 어드민 권한 추가 (DASOMBE-14) * rename: 오탈자 수정 (DASOMBE-14) * feat: DTO 요청 데이터 수정 (DASOMBE-14) * feat: 조회 실패 테스트 추가 (DASOMBE-14) * feat: 실패 테스트 케이스 추가 ( 삭제, 생성 ) (DASOMBE-14)
1 parent adf631c commit d884a28

File tree

14 files changed

+562
-1
lines changed

14 files changed

+562
-1
lines changed

src/main/java/dmu/dasom/api/domain/common/exception/ErrorCode.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,8 @@ public enum ErrorCode {
3636
SLOT_NOT_ACTIVE(400, "C027", "해당 슬롯이 비활성화 되었습니다."),
3737
FILE_ENCODE_FAIL(400, "C028", "파일 인코딩에 실패하였습니다."),
3838
RECRUITMENT_NOT_ACTIVE(400, "C029", "모집 기간이 아닙니다."),
39-
NOT_FOUND_PARTICIPANT(400, "C030", "참가자를 찾을 수 없습니다.")
39+
NOT_FOUND_PARTICIPANT(400, "C030", "참가자를 찾을 수 없습니다."),
40+
EXECUTIVE_NOT_FOUND(400, "C031", "임원진을 찾을 수 없습니다."),
4041
;
4142

4243
private final int status;
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
package dmu.dasom.api.domain.executive.controller;
2+
3+
import dmu.dasom.api.domain.executive.dto.*;
4+
import dmu.dasom.api.domain.executive.service.ExecutiveServiceImpl;
5+
import io.swagger.v3.oas.annotations.Operation;
6+
import io.swagger.v3.oas.annotations.tags.Tag;
7+
import jakarta.validation.Valid;
8+
import jakarta.validation.constraints.Min;
9+
import lombok.RequiredArgsConstructor;
10+
import org.springframework.http.ResponseEntity;
11+
import org.springframework.security.access.prepost.PreAuthorize;
12+
import org.springframework.web.bind.annotation.*;
13+
14+
import java.util.List;
15+
16+
@Tag(name = "EXECUTIVE API", description = "임원진 API")
17+
@RestController
18+
@RequiredArgsConstructor
19+
@RequestMapping("/api/executives")
20+
public class ExecutiveController {
21+
22+
private final ExecutiveServiceImpl executiveService;
23+
24+
@Operation(summary = "임원진 조회")
25+
@GetMapping("/{id}")
26+
public ResponseEntity<ExecutiveResponseDto> getExecutiveById(@PathVariable @Min(1) Long id) {
27+
return ResponseEntity.ok(executiveService.getExecutiveById(id));
28+
}
29+
30+
@Operation(summary = "임원진 전체 조회")
31+
@GetMapping
32+
public ResponseEntity<List<ExecutiveListResponseDto>> getAllExecutives() {
33+
return ResponseEntity.ok(executiveService.getAllExecutives());
34+
}
35+
36+
@Operation(summary = "임원진 생성")
37+
@PreAuthorize("hasRole('ADMIN')")
38+
@PostMapping
39+
public ResponseEntity<ExecutiveCreationResponseDto> createExecutive(@Valid @RequestBody ExecutiveRequestDto requestDto) {
40+
return ResponseEntity.status(201).body(executiveService.createExecutive(requestDto));
41+
}
42+
43+
@Operation(summary = "임원진 삭제")
44+
@PreAuthorize("hasRole('ADMIN')")
45+
@DeleteMapping("/{id}")
46+
// Void 사용 이유?
47+
// DELETE 요청 같이 성공/실패만 확인하면 되는 경우 사용
48+
public ResponseEntity<Void> deleteExecutive(@PathVariable @Min(1) Long id) {
49+
executiveService.deleteExective(id);
50+
return ResponseEntity.ok().build();
51+
}
52+
53+
@Operation(summary = "임원진 수정")
54+
@PreAuthorize("hasRole('ADMIN')")
55+
@PutMapping("/{id}")
56+
public ResponseEntity<ExecutiveResponseDto> updateExecutive(@PathVariable @Min(1) Long id,
57+
@Valid @RequestBody ExecutiveUpdateRequestDto requestDto) {
58+
return ResponseEntity.ok(executiveService.updateExecutive(id, requestDto));
59+
}
60+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
package dmu.dasom.api.domain.executive.dto;
2+
3+
import io.swagger.v3.oas.annotations.media.Schema;
4+
import jakarta.validation.constraints.NotNull;
5+
import lombok.AllArgsConstructor;
6+
import lombok.Getter;
7+
import lombok.NoArgsConstructor;
8+
9+
@Getter
10+
@NoArgsConstructor
11+
@AllArgsConstructor
12+
@Schema(name = "ExecutiveCreationResponseDto", description = "회장단 생성 응답 DTO")
13+
public class ExecutiveCreationResponseDto {
14+
15+
@NotNull
16+
@Schema(description = "회장단 ID", example = "1")
17+
private Long id;
18+
19+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
package dmu.dasom.api.domain.executive.dto;
2+
3+
import io.swagger.v3.oas.annotations.media.Schema;
4+
import lombok.AllArgsConstructor;
5+
import lombok.Builder;
6+
import lombok.Getter;
7+
import lombok.NoArgsConstructor;
8+
9+
@Getter
10+
@NoArgsConstructor
11+
@AllArgsConstructor
12+
@Builder
13+
@Schema(name = "ExecutiveListResponseDto", description = "임원진 목록 응답 Dto")
14+
public class ExecutiveListResponseDto {
15+
16+
@Schema(description = "임원진 ID", example = "1")
17+
private Long id;
18+
19+
@Schema(description = "임원진 이름", example = "김다솜")
20+
private String name;
21+
22+
@Schema(description = "임원진 직책", example = "회장")
23+
private String position;
24+
25+
@Schema(description = "임원진 깃허브 주소", example = "https://github.com/dasom")
26+
private String githubUrl;
27+
28+
}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
package dmu.dasom.api.domain.executive.dto;
2+
3+
import dmu.dasom.api.domain.executive.entity.ExecutiveEntity;
4+
import io.swagger.v3.oas.annotations.media.Schema;
5+
import jakarta.validation.constraints.NotBlank;
6+
import jakarta.validation.constraints.Size;
7+
import lombok.AllArgsConstructor;
8+
import lombok.Getter;
9+
import lombok.NoArgsConstructor;
10+
11+
@Getter
12+
@NoArgsConstructor
13+
@AllArgsConstructor
14+
@Schema(name = "ExecutiveRequestDto", description = "임원진 요청 DTO")
15+
public class ExecutiveRequestDto {
16+
17+
private Long id;
18+
19+
@NotBlank(message = "임원진 이름은 필수 입력 사항입니다.")
20+
@Size(max = 50, message = "임원진 이름은 최대 50자입니다.")
21+
@Schema(description = "임원진 이름", example = "김다솜")
22+
private String name;
23+
24+
@NotBlank(message = "임원진 역할은 필수 입력 사항입니다.")
25+
@Schema(description = "임원진 역할", example = "회장")
26+
private String position;
27+
28+
private String githubUrl;
29+
30+
public ExecutiveEntity toEntity() {
31+
return ExecutiveEntity.builder()
32+
.name(this.name)
33+
.position(this.position)
34+
.githubUrl(this.githubUrl)
35+
.build();
36+
}
37+
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
package dmu.dasom.api.domain.executive.dto;
2+
3+
import io.swagger.v3.oas.annotations.media.Schema;
4+
import lombok.AllArgsConstructor;
5+
import lombok.Builder;
6+
import lombok.Getter;
7+
import lombok.NoArgsConstructor;
8+
9+
@Getter
10+
@NoArgsConstructor
11+
@AllArgsConstructor
12+
@Builder
13+
@Schema(name = "ExecutiveResponseDto", description = "임원진 응답 DTO")
14+
public class ExecutiveResponseDto {
15+
16+
@Schema(description = "임원진 ID", example = "1")
17+
private Long id;
18+
19+
@Schema(description = "임원진 이름", example = "김다솜")
20+
private String name;
21+
22+
@Schema(description = "임원진 직책", example = "회장")
23+
private String position;
24+
25+
@Schema(description = "임원진 깃허브", example = "https://github.com/dasom")
26+
private String githubUrl;
27+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
package dmu.dasom.api.domain.executive.dto;
2+
3+
import io.swagger.v3.oas.annotations.media.Schema;
4+
import jakarta.validation.constraints.Size;
5+
import lombok.AllArgsConstructor;
6+
import lombok.Getter;
7+
import lombok.NoArgsConstructor;
8+
9+
@Getter
10+
@NoArgsConstructor
11+
@AllArgsConstructor
12+
@Schema(name = "ExecutiveUpdateRequestDto", description = "임원진 멤버 수정 요청 DTO")
13+
public class ExecutiveUpdateRequestDto {
14+
15+
@Size(max = 50, message = "임원진 이름은 최대 50자입니다.")
16+
@Schema(description = "수정할 임원진 이름", example = "김다솜", nullable = true)
17+
private String name;
18+
19+
@Schema(description = "수정할 임원진 직책", example = "회장", nullable = true)
20+
private String position;
21+
22+
@Schema(description = "수정할 임원진 깃허브 주소", example = "https://github.com/dasom", nullable = true)
23+
private String githubUrl;
24+
}
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
package dmu.dasom.api.domain.executive.entity;
2+
3+
import dmu.dasom.api.domain.common.BaseEntity; // BaseEntity 상속 받음
4+
import dmu.dasom.api.domain.executive.dto.ExecutiveListResponseDto;
5+
import dmu.dasom.api.domain.executive.dto.ExecutiveResponseDto;
6+
import io.swagger.v3.oas.annotations.media.Schema;
7+
import jakarta.persistence.*; // JPA 어노테이션 패키지 ( DB 매핑 관련 )
8+
import lombok.*; // 보일러플레이트 코드 자동 생성 라이브러리
9+
10+
@Getter
11+
@Entity
12+
@Table(name = "executive")
13+
@NoArgsConstructor
14+
@AllArgsConstructor
15+
@Builder
16+
@Schema(description = "조직도 엔티티")
17+
public class ExecutiveEntity extends BaseEntity {
18+
19+
@Id
20+
@GeneratedValue(strategy = GenerationType.IDENTITY)
21+
private Long id;
22+
23+
// 이름
24+
@Column(nullable = false, length = 50)
25+
private String name;
26+
27+
// 직책
28+
@Column(nullable=false, length = 50)
29+
private String position;
30+
31+
// 깃허브 주소
32+
@Column(nullable=false, length = 255)
33+
private String githubUrl;
34+
35+
// 엔티티 업데이트 메소드
36+
public void update(String name, String position, String githubUrl) {
37+
this.name = name;
38+
this.position = position;
39+
this.githubUrl = githubUrl;
40+
}
41+
42+
// 엔티티 -> DTO 변환 책임
43+
public ExecutiveResponseDto toResponseDto() {
44+
return ExecutiveResponseDto.builder()
45+
.id(this.id)
46+
.name(this.name)
47+
.position(this.position)
48+
.githubUrl(this.githubUrl)
49+
.build();
50+
}
51+
52+
// 임원진 전체 목록 조회
53+
public ExecutiveListResponseDto toListResponseDto() {
54+
return ExecutiveListResponseDto.builder()
55+
.id(this.id)
56+
.name(this.name)
57+
.position(this.position)
58+
.githubUrl(this.githubUrl)
59+
.build();
60+
}
61+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
package dmu.dasom.api.domain.executive.enums;
2+
3+
import lombok.AllArgsConstructor;
4+
import lombok.Getter;
5+
6+
// enum + 문자열 매핑
7+
@AllArgsConstructor
8+
@Getter
9+
public enum Role {
10+
11+
ROLE_PRESIDENT("PRESIDENT"), // 회장
12+
ROLE_VICE_PRESIDENT("VICE_PRESIDENT"), // 부회장
13+
ROLE_TECHNICAL_MANAGER("TECHNICAL_MANAGER"), // 기술팀장
14+
ROLE_ACADEMIC_MANAGER("ACADEMIC_MANAGER"), // 학술팀장
15+
ROLE_ACADEMIC_SENIOR("ACADEMIC_SENIOR"), // 학술차장
16+
ROLE_PUBLIC_RELATIONS_MANAGER("PUBLIC_RELATIONS_MANAGER"), // 홍보팀장
17+
ROLE_CLERK("CLERK"), // 서기
18+
ROLE_MANAGER("MANAGER"), // 총무
19+
ROLE_SUB_MANAGER("SUB_MANAGER"), // 부총무
20+
;
21+
22+
private String name;
23+
24+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
package dmu.dasom.api.domain.executive.repository;
2+
3+
import dmu.dasom.api.domain.executive.entity.ExecutiveEntity;
4+
import org.springframework.data.jpa.repository.JpaRepository;
5+
import org.springframework.stereotype.Repository;
6+
7+
@Repository
8+
public interface ExecutiveRepository extends JpaRepository<ExecutiveEntity, Long> {
9+
10+
// 회장단 레포지토리
11+
12+
}

0 commit comments

Comments
 (0)