Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[feature/#209] 정책 관련 API 구현 #210

Merged
merged 6 commits into from
Jan 8, 2024
Merged
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
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ public class WebSecurityConfig {
private static final String[] AUTH_WHITELIST_SIGNUP = {"/signUp/schedule", "/signUp/questionnaires",
"/signUp/majorInfo"};
private static final String[] AUTH_WHITELIST_CLUB = {"/club/histories", "/club/history/**"};
private static final String[] AUTH_WHITELIST_POLICY = {"/policy/**"};

@Order(1)
@EnableGlobalMethodSecurity(prePostEnabled = true, jsr250Enabled = true)
Expand All @@ -70,6 +71,7 @@ public void configure(AuthenticationManagerBuilder auth) throws Exception {
@Override
public void configure(WebSecurity web) throws Exception {
web.ignoring()
.antMatchers(HttpMethod.GET, AUTH_WHITELIST_POLICY)
.antMatchers(HttpMethod.GET, AUTH_WHITELIST_SIGNUP)
.antMatchers(HttpMethod.GET, AUTH_WHITELIST_CLUB)
.antMatchers(AUTH_WHITELIST_SWAGGER)
Expand Down Expand Up @@ -126,6 +128,9 @@ protected void configure(HttpSecurity http) throws Exception {
// 동아리 연혁 수정
.antMatchers("/club/history/**").hasRole(EXECUTIVES.toString())

// 정책 수정
.antMatchers(HttpMethod.PUT, "/policy/**").hasAnyRole(CHIEF.toString(), VICE_CHIEF.toString())

// 그 외
.anyRequest().hasRole(ANONYMOUS.toString());

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ public abstract class BaseEntity {
@Column(nullable = false, updatable = false, insertable = false, columnDefinition = "DATETIME(0) DEFAULT CURRENT_TIMESTAMP")
private LocalDateTime dateCreated;

@CreatedDate
@LastModifiedDate
@Column(columnDefinition = "DATETIME(0)")
private LocalDateTime dateUpdated;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package com.inhabas.api.domain.policy.domain;

import com.inhabas.api.domain.BaseEntity;
import com.inhabas.api.domain.board.domain.valueObject.Content;
import com.inhabas.api.domain.policy.dto.SavePolicyTernDto;
import lombok.AccessLevel;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;

import javax.persistence.*;

@Entity
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@Table(name = "POLICY_TERM")
@Getter
public class PolicyTerm extends BaseEntity {

@Id
@GeneratedValue
private Long id;

@ManyToOne(fetch = FetchType.LAZY, optional = false)
@JoinColumn(name = "POLICY_TYPE_ID")
private PolicyType policyType;

@Embedded
private Content content;

@Builder
public PolicyTerm(PolicyType policyType, String content) {
this.policyType = policyType;
this.content = new Content(content);
}

public void updatePolicyTerm(SavePolicyTernDto savePolicyTernDto) {
this.content = new Content(savePolicyTernDto.getContent());
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package com.inhabas.api.domain.policy.domain;

import com.inhabas.api.domain.board.domain.valueObject.Title;
import lombok.AccessLevel;
import lombok.Getter;
import lombok.NoArgsConstructor;

import javax.persistence.*;

@Entity
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class PolicyType {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

@Column(name = "TITLE")
private Title title;

public PolicyType(String title) {
this.title = new Title(title);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package com.inhabas.api.domain.policy.dto;

import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;

import javax.validation.constraints.NotNull;

@Getter
@NoArgsConstructor
public class PolicyTermDto {

@NotNull
private String title;

@NotNull
private String content;

@Builder
public PolicyTermDto(String title, String content) {
this.title = title;
this.content = content;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package com.inhabas.api.domain.policy.dto;

import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;

import javax.validation.constraints.NotNull;

@Getter
@NoArgsConstructor
public class SavePolicyTernDto {

@NotNull
private String content;

@Builder
public SavePolicyTernDto(String content) {
this.content = content;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.inhabas.api.domain.policy.respository;

import com.inhabas.api.domain.policy.domain.PolicyTerm;
import org.springframework.data.jpa.repository.JpaRepository;

public interface PolicyTermRepository extends JpaRepository<PolicyTerm, Long> {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package com.inhabas.api.domain.policy.usecase;

import com.inhabas.api.domain.policy.dto.PolicyTermDto;
import com.inhabas.api.domain.policy.dto.SavePolicyTernDto;

public interface PolicyTermService {

PolicyTermDto findPolicyTerm(Long policyTermId);

void updatePolicyTerm(Long policyTermId, SavePolicyTernDto savePolicyTernDto);

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package com.inhabas.api.domain.policy.usecase;

import com.inhabas.api.auth.domain.error.businessException.NotFoundException;
import com.inhabas.api.domain.policy.domain.PolicyTerm;
import com.inhabas.api.domain.policy.dto.PolicyTermDto;
import com.inhabas.api.domain.policy.dto.SavePolicyTernDto;
import com.inhabas.api.domain.policy.respository.PolicyTermRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Service
@RequiredArgsConstructor
public class PolicyTermServiceImpl implements PolicyTermService{

private final PolicyTermRepository policyTermRepository;

@Override
@Transactional(readOnly = true)
public PolicyTermDto findPolicyTerm(Long policyTermId) {

PolicyTerm policyTerm = policyTermRepository.findById(policyTermId).orElseThrow(NotFoundException::new);

return PolicyTermDto.builder()
.title(policyTerm.getPolicyType().getTitle().getValue())
.content(policyTerm.getContent().getValue())
.build();

}

@Override
@Transactional
public void updatePolicyTerm(Long policyTermId, SavePolicyTernDto savePolicyTernDto) {

PolicyTerm policyTerm = policyTermRepository.findById(policyTermId).orElseThrow(NotFoundException::new);
policyTerm.updatePolicyTerm(savePolicyTernDto);

}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
package com.inhabas.api.web;

import com.inhabas.api.auth.domain.error.ErrorResponse;
import com.inhabas.api.domain.policy.dto.PolicyTermDto;
import com.inhabas.api.domain.policy.dto.SavePolicyTernDto;
import com.inhabas.api.domain.policy.usecase.PolicyTermService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.ExampleObject;
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 io.swagger.v3.oas.annotations.security.SecurityRequirements;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import javax.validation.Valid;

@Tag(name = "정책 관리")
@RestController
@RequiredArgsConstructor
public class PolicyTermController {

private final PolicyTermService policyTermService;

@GetMapping("/policy/{policyTermId}")
@SecurityRequirements(value = {})
@Operation(summary = "해당 정책을 조회한다.",
description = "policyTermId는 1,2,3만 존재")
@ApiResponses({
@ApiResponse(responseCode = "200", content = @Content(
schema = @Schema(implementation = PolicyTermDto.class)
)),
@ApiResponse(responseCode = "400 ", description = "입력값이 없거나, 타입이 유효하지 않습니다.", content = @Content(
schema = @Schema(implementation = ErrorResponse.class),
examples = @ExampleObject(
value = "{\"status\": 400, \"code\": \"G003\", \"message\": \"입력값이 없거나, 타입이 유효하지 않습니다.\"}"
)
)),
@ApiResponse(responseCode = "404", description = "데이터가 존재하지 않습니다.", content = @Content(
schema = @Schema(implementation = ErrorResponse.class),
examples = @ExampleObject(
value = "{\"status\": 404, \"code\": \"G004\", \"message\": \"데이터가 존재하지 않습니다.\"}"
)
))
})
public ResponseEntity<PolicyTermDto> findPolicyTerm(@PathVariable Long policyTermId) {

PolicyTermDto policyTermDto = policyTermService.findPolicyTerm(policyTermId);
return ResponseEntity.ok(policyTermDto);

}

@PutMapping("/policy/{policyTermId}")
@Operation(summary = "해당 정책을 수정한다.",
description = "policyTermId는 1,2,3만 존재")
@ApiResponses({
@ApiResponse(responseCode = "204"),
@ApiResponse(responseCode = "400 ", description = "입력값이 없거나, 타입이 유효하지 않습니다.", content = @Content(
schema = @Schema(implementation = ErrorResponse.class),
examples = @ExampleObject(
value = "{\"status\": 400, \"code\": \"G003\", \"message\": \"입력값이 없거나, 타입이 유효하지 않습니다.\"}"
)
)),
@ApiResponse(responseCode = "404", description = "데이터가 존재하지 않습니다.", content = @Content(
schema = @Schema(implementation = ErrorResponse.class),
examples = @ExampleObject(
value = "{\"status\": 404, \"code\": \"G004\", \"message\": \"데이터가 존재하지 않습니다.\"}"
)
))
})
public ResponseEntity<PolicyTermDto> updatePolicyTerm(@PathVariable Long policyTermId,
@Valid @RequestBody SavePolicyTernDto savePolicyTernDto) {

policyTermService.updatePolicyTerm(policyTermId, savePolicyTernDto);
return ResponseEntity.noContent().build();

}

}
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import org.springframework.data.domain.Sort;
import org.springframework.test.util.ReflectionTestUtils;
import org.springframework.transaction.annotation.Transactional;

Expand Down Expand Up @@ -130,13 +131,15 @@ void getClubHistories_Success() {
.dateHistory(LocalDateTime.now())
.build();
List<ClubHistory> clubHistoryList = List.of(clubHistory);
given(clubHistoryRepository.findAll()).willReturn(clubHistoryList);

Sort sort = Sort.by(Sort.Direction.DESC, "dateHistory");
given(clubHistoryRepository.findAll(sort)).willReturn(clubHistoryList);

//when
List<ClubHistoryDto> clubHistoryDtoList = clubHistoryService.getClubHistories();

//then
then(clubHistoryRepository).should().findAll();
then(clubHistoryRepository).should().findAll(sort);
assertThat(clubHistoryDtoList)
.hasSize(1)
.extracting("title", "content")
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package com.inhabas.api.domain.policy.domain;

import com.inhabas.api.auth.domain.error.businessException.InvalidInputException;
import org.assertj.core.api.Assertions;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;

class PolicyTermTest {

@DisplayName("Content는 null 일 수 없다.")
@Test
void Content_Notnull() {
//given
PolicyType policyType = new PolicyType("goodTitle");
String nullString = null;

//then
Assertions.assertThatThrownBy(() -> new PolicyTerm(policyType, nullString))
.isInstanceOf(InvalidInputException.class)
.hasMessage("입력값이 없거나, 타입이 유효하지 않습니다.");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

혹시 이 테스트 성공했는지 궁금합니다. InvalidInputException.class 가 생겼을 때 한국어로 "입력값이 없거나, 타입이 유효하지 않습니다" 라고 나오나요?
왜냐하면 보통 기본 오류들은 영어로 나오는거로 알고 있어서요!

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이 테스트 실행해서 통과한거면 상관은 없습니다!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ExceptionHandler(InvalidInputException.class)
    protected ResponseEntity<ErrorResponse> handleInvalidInputException(InvalidInputException e) {
        log.error("Invalid input value");
        final ErrorResponse response = ErrorResponse.of(INVALID_INPUT_VALUE);
        return new ResponseEntity<>(response, BAD_REQUEST);
    }

errorhandler로 저렇게 동작하도록 했어. ExceptionController 관련 코드 참고

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@whitem4rk 확인했습니다. 감사합니다!


}

@DisplayName("올바른 PolicyTerm을 생성한다.")
@Test
void createPolicyTerm() {
//given
PolicyType policyType = new PolicyType("goodTitle");
String goodContent = "goodContent";

//when
PolicyTerm policyTerm = new PolicyTerm(policyType, goodContent);


//then
Assertions.assertThat(policyTerm.getContent().getValue()).isEqualTo(goodContent);

}

}
Loading
Loading