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

Feat/9 monthly agenda #15

Merged
merged 14 commits into from
May 23, 2024
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package com.example.rework.MonthlyAgenda.application;

import com.example.rework.MonthlyAgenda.application.dto.MonthlyAgendaRequestDto;
import com.example.rework.MonthlyAgenda.application.dto.MonthlyAgendaResponseDto;
import com.example.rework.config.security.SecurityUtils;

public interface MonthlyAgendaService {
MonthlyAgendaResponseDto.ReadMonthlyAgendaResponseDto readMonthlyAgenda(MonthlyAgendaRequestDto.ReadMonthlyAgendaRequestDto readMonthlyAgendaRequestDto , SecurityUtils securityUtils);

MonthlyAgendaResponseDto.CreateMonthlyAgendaResponseDto createMonthlyAgenda(MonthlyAgendaRequestDto.CreateMonthlyAgendaRequestDto createMonthlyAgendaRequestDto, SecurityUtils securityUtils);

MonthlyAgendaResponseDto.UpdateMonthlyAgendaResponseDto updateMonthlyAgenda(MonthlyAgendaRequestDto.UpdateMonthlyAgendaRequestDto updateMonthlyAgendaRequestDto, SecurityUtils securityUtils);

boolean deleteMonthlyAgenda(Long monthlyAgendaId, SecurityUtils securityUtils);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package com.example.rework.MonthlyAgenda.application.dto;

import lombok.*;

public class MonthlyAgendaRequestDto {
@Getter
@NoArgsConstructor
@AllArgsConstructor
@Builder
public static class ReadMonthlyAgendaRequestDto{
private int year;
private int month;
}

@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@AllArgsConstructor
@Builder
public static class CreateMonthlyAgendaRequestDto{
private String todo;
}

@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@AllArgsConstructor
@Builder
public static class UpdateMonthlyAgendaRequestDto{
private Long agendaId;
private String todo;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package com.example.rework.MonthlyAgenda.application.dto;

import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.*;

import java.time.LocalDateTime;

public class MonthlyAgendaResponseDto {
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@AllArgsConstructor
@Builder
public static class CreateMonthlyAgendaResponseDto {
private Long agendaId;
private String todo;
private boolean state;
}

@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@AllArgsConstructor
@Builder
public static class UpdateMonthlyAgendaResponseDto {
private Long agendaId;
private String todo;
private boolean state;
}

@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@AllArgsConstructor
@Builder
public static class ReadMonthlyAgendaResponseDto {
private Long agendaId;
private String todo;
private boolean state;
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM")
private LocalDateTime createTime;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
package com.example.rework.MonthlyAgenda.application.impl;

import com.example.rework.MonthlyAgenda.application.MonthlyAgendaService;
import com.example.rework.MonthlyAgenda.application.dto.MonthlyAgendaRequestDto.CreateMonthlyAgendaRequestDto;
import com.example.rework.MonthlyAgenda.application.dto.MonthlyAgendaRequestDto.ReadMonthlyAgendaRequestDto;
import com.example.rework.MonthlyAgenda.application.dto.MonthlyAgendaRequestDto.UpdateMonthlyAgendaRequestDto;
import com.example.rework.MonthlyAgenda.application.dto.MonthlyAgendaResponseDto;
import com.example.rework.MonthlyAgenda.domain.MonthlyAgenda;
import com.example.rework.MonthlyAgenda.domain.repository.MonthlyAgendaRepository;
import com.example.rework.config.security.SecurityUtils;
import com.example.rework.global.error.NotFoundAccountException;
import com.example.rework.global.error.NotFoundAgendaException;
import com.example.rework.global.error.UnAuthorizedException;
import com.example.rework.member.domain.Member;
import com.example.rework.member.domain.repository.MemberRepository;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.time.YearMonth;
import java.util.List;
import java.util.Optional;

@Service
@RequiredArgsConstructor
@Slf4j
@Transactional(readOnly = true)
public class MonthlyAgendaServiceImpl implements MonthlyAgendaService {
private final MonthlyAgendaRepository monthlyAgendaRepository;
private final MemberRepository memberRepository;

@Override
public MonthlyAgendaResponseDto.ReadMonthlyAgendaResponseDto readMonthlyAgenda(ReadMonthlyAgendaRequestDto readMonthlyAgendaRequestDto, SecurityUtils securityUtils) {
Optional<Member> curMember = memberRepository.findByUserId(securityUtils.getCurrentUserId());
Long currentUserId = curMember.get().getId();

LocalDateTime start = YearMonth.of(readMonthlyAgendaRequestDto.getYear(), readMonthlyAgendaRequestDto.getMonth()).atDay(1).atStartOfDay();
LocalDateTime end = YearMonth.of(readMonthlyAgendaRequestDto.getYear(), readMonthlyAgendaRequestDto.getMonth()).atEndOfMonth().atTime(23, 59, 59);

Optional<MonthlyAgenda> monthlyAgendaOptional = monthlyAgendaRepository.findByMemberIdAndCreatedAtBetween(currentUserId, start, end);
Copy link
Member

Choose a reason for hiding this comment

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

해당 부분을 orElseThrow로 처리해서 if else 문 안쓰고처리하는방법은 어떨까요!?

Copy link
Member

Choose a reason for hiding this comment

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

아아 빈배열 반환을 위해 저렇게 하신거군요 ! 이해했습니다


if (monthlyAgendaOptional.isPresent()) {
MonthlyAgenda monthlyAgenda = monthlyAgendaOptional.get();
return MonthlyAgendaResponseDto.ReadMonthlyAgendaResponseDto.builder()
.agendaId(monthlyAgenda.getId())
.todo(monthlyAgenda.getTodo())
.state(monthlyAgenda.isState())
.createTime(monthlyAgenda.getCreatedAt())
.build();
} else {
return MonthlyAgendaResponseDto.ReadMonthlyAgendaResponseDto.builder().build();
}


}

@Override
@Transactional
public MonthlyAgendaResponseDto.CreateMonthlyAgendaResponseDto createMonthlyAgenda(CreateMonthlyAgendaRequestDto createMonthlyAgendaRequestDto, SecurityUtils securityUtils) {
Optional<Member> curMember = memberRepository.findByUserId(securityUtils.getCurrentUserId());
Long currentUserId = curMember.get().getId();

Member member = memberRepository.findById(currentUserId)
.orElseThrow(() -> new NotFoundAccountException("Member not found with id: " + currentUserId));

MonthlyAgenda monthlyAgenda = MonthlyAgenda.builder()
.member(member)
.todo(createMonthlyAgendaRequestDto.getTodo())
.state(false)
.build();

MonthlyAgenda returnMonthlyAgenda = monthlyAgendaRepository.save(monthlyAgenda);

return MonthlyAgendaResponseDto.CreateMonthlyAgendaResponseDto.builder()
.agendaId(returnMonthlyAgenda.getId())
.todo(returnMonthlyAgenda.getTodo())
.state(returnMonthlyAgenda.isState())
.build();
}

@Override
@Transactional
public MonthlyAgendaResponseDto.UpdateMonthlyAgendaResponseDto updateMonthlyAgenda(UpdateMonthlyAgendaRequestDto updateMonthlyAgendaRequestDto, SecurityUtils securityUtils) {
Optional<Member> curMember = memberRepository.findByUserId(securityUtils.getCurrentUserId());
Long currentUserId = curMember.get().getId();

Member member = memberRepository.findById(currentUserId)
.orElseThrow(() -> new NotFoundAccountException("Member not found with id: " + currentUserId));
MonthlyAgenda monthlyAgenda = monthlyAgendaRepository.findById(updateMonthlyAgendaRequestDto.getAgendaId())
.orElseThrow(() -> new NotFoundAgendaException("Goal not found with id: " + updateMonthlyAgendaRequestDto.getAgendaId()));

if (!monthlyAgenda.getMember().getId().equals(currentUserId)) {
throw new UnAuthorizedException("유저가 소유한 아젠다가 아닙니다.");
}
monthlyAgenda.setTodo(updateMonthlyAgendaRequestDto.getTodo());

return MonthlyAgendaResponseDto.UpdateMonthlyAgendaResponseDto
.builder()
.agendaId(monthlyAgenda.getId())
.todo(monthlyAgenda.getTodo())
.state(monthlyAgenda.isState())
.build();
}

@Override
@Transactional
public boolean deleteMonthlyAgenda(Long monthlyAgendaId, SecurityUtils securityUtils) {
Optional<Member> curMember = memberRepository.findByUserId(securityUtils.getCurrentUserId());
Long currentUserId = curMember.get().getId();

Member member = memberRepository.findById(currentUserId)
.orElseThrow(() -> new NotFoundAccountException("Member not found with id: " + currentUserId));
MonthlyAgenda monthlyAgenda = monthlyAgendaRepository.findById(monthlyAgendaId)
.orElseThrow(() -> new NotFoundAgendaException("Goal not found with id: " + monthlyAgendaId));

if (!monthlyAgenda.getMember().getId().equals(currentUserId)) {
throw new UnAuthorizedException("유저가 소유한 아젠다가 아닙니다.");
}
monthlyAgendaRepository.deleteById(monthlyAgenda.getId());

return true;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package com.example.rework.MonthlyAgenda.domain;

import com.example.rework.global.base.BaseTimeEntity;
import com.example.rework.member.domain.Member;
import jakarta.persistence.*;
import lombok.*;


@Entity(name = "MONTHLY_AGENDA")
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@AllArgsConstructor
@Builder
public class MonthlyAgenda extends BaseTimeEntity {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "MONTHLY_AGENDA_ID")
private Long id;
@Column(length = 400)
private String todo;
@Column(length = 30, nullable = false)
private boolean state;
@JoinColumn(name = "MEMBER_ID")
@ManyToOne(fetch = FetchType.LAZY)
private Member member;

public void setTodo(String todo) {
this.todo = todo;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package com.example.rework.MonthlyAgenda.domain.repository;

import com.example.rework.MonthlyAgenda.domain.MonthlyAgenda;
import org.springframework.data.jpa.repository.JpaRepository;

import java.time.LocalDateTime;
import java.util.List;
import java.util.Optional;

public interface MonthlyAgendaRepository extends JpaRepository<MonthlyAgenda, Long> {
Optional<MonthlyAgenda> findByMemberIdAndCreatedAtBetween(Long memberId, LocalDateTime start, LocalDateTime end);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package com.example.rework.MonthlyAgenda.presentation;

import com.example.rework.MonthlyAgenda.application.MonthlyAgendaService;
import com.example.rework.MonthlyAgenda.application.dto.MonthlyAgendaRequestDto.*;
import com.example.rework.MonthlyAgenda.application.dto.MonthlyAgendaResponseDto;
import com.example.rework.MonthlyAgenda.restapi.MonthlyAgendaApi;
import com.example.rework.config.security.SecurityUtils;
import com.example.rework.global.common.CommonResDto;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;


@RestController
@RequestMapping("/api/v1/monthlyAgenda")
@RequiredArgsConstructor
@Slf4j
public class MonthlyAgendaController implements MonthlyAgendaApi {
private final MonthlyAgendaService monthlyAgendaService;

@Override
public ResponseEntity<CommonResDto<?>> readMonthlyAgenda(ReadMonthlyAgendaRequestDto readMonthlyAgendaRequestDto, SecurityUtils securityUtils) {
MonthlyAgendaResponseDto.ReadMonthlyAgendaResponseDto result = monthlyAgendaService.readMonthlyAgenda(readMonthlyAgendaRequestDto, securityUtils);
return ResponseEntity.status(HttpStatus.OK).body(new CommonResDto<>(1, "이번달 아젠다 조회에 성고했습니다.", result));
}

@Override
public ResponseEntity<CommonResDto<?>> createMonthlyAgenda(CreateMonthlyAgendaRequestDto createMonthlyAgendaRequestDto, SecurityUtils securityUtils) {
MonthlyAgendaResponseDto.CreateMonthlyAgendaResponseDto result = monthlyAgendaService.createMonthlyAgenda(createMonthlyAgendaRequestDto, securityUtils);
return ResponseEntity.status(HttpStatus.CREATED).body(new CommonResDto<>(1, "이번달 아젠다 생성에 성공했습니다.", result));
}

@Override
public ResponseEntity<CommonResDto<?>> updateMonthlyAgenda(UpdateMonthlyAgendaRequestDto updateMonthlyAgendaRequestDto, SecurityUtils securityUtils) {
MonthlyAgendaResponseDto.UpdateMonthlyAgendaResponseDto result = monthlyAgendaService.updateMonthlyAgenda(updateMonthlyAgendaRequestDto, securityUtils);
return ResponseEntity.status(HttpStatus.OK).body(new CommonResDto<>(1, "이번달 아젠달 수정에 성공했습니다.", result));
}

@Override
public ResponseEntity<CommonResDto<?>> deleteMonthlyAgenda(Long monthlyAgendaId, SecurityUtils securityUtils) {
boolean result = monthlyAgendaService.deleteMonthlyAgenda(monthlyAgendaId, securityUtils);
return ResponseEntity.status(HttpStatus.OK).body(new CommonResDto<>(1, "이번달 아젠다 삭제에 성공했습니다.", result));
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
package com.example.rework.MonthlyAgenda.restapi;

import com.example.rework.config.security.SecurityUtils;
import com.example.rework.global.common.CommonResDto;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.Valid;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import java.security.Principal;

import com.example.rework.MonthlyAgenda.application.dto.MonthlyAgendaRequestDto.*;

@Tag(name = "이번달 아젠다 API", description = "이번달 아젠다 관련 API")
@RestController
@RequestMapping("/api/v1/monthlyAgenda")
@Validated
public interface MonthlyAgendaApi {

@Operation(
summary = "이번달 아젠다 조회",
description = "사용자 정보와 연,월을 받아 해당하는 달의 '이번달 아젠다를' 조회하는 API"
)
@GetMapping("/read")
ResponseEntity<CommonResDto<?>> readMonthlyAgenda(
@RequestBody ReadMonthlyAgendaRequestDto readMonthlyAgendaRequestDto,
SecurityUtils securityUtils
);

@Operation(
summary = "이번달 아젠다 등록",
description = "사용자가 입력한 이번달 아젠다를 저장하는 API"
)
@PostMapping("/create")
Copy link
Member

Choose a reason for hiding this comment

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

restful 규칙: 행위를 포함하지 않는다.
이거 혹시 / 나 행위가 포함되지않도록 하는건 어떨까요?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

요기까지 다 확인했습니다 ㅎㅎ

ResponseEntity<CommonResDto<?>> createMonthlyAgenda(
@Valid
@RequestBody
CreateMonthlyAgendaRequestDto createMonthlyAgendaRequestDto,
SecurityUtils securityUtils
);

@Operation(
summary = "이번달 아젠다 수정",
description = "사용자가 설정한 이번달 아젠다를 수정하는 API"
)
@PutMapping("/update")
Copy link
Member

Choose a reason for hiding this comment

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

restful 규칙: 행위를 포함하지 않는다.
이거 혹시 / 나 행위가 포함되지않도록 하는건 어떨까요?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

넵!

ResponseEntity<CommonResDto<?>> updateMonthlyAgenda(
@RequestBody
UpdateMonthlyAgendaRequestDto updateMonthlyAgendaRequestDto,
SecurityUtils securityUtils
);


@Operation(
summary = "이번달 아젠다 삭제",
description = "이번달 아젠다를 삭제하는 API, 현재는 필요하지 않음."
)
@DeleteMapping("/delete")
Copy link
Member

Choose a reason for hiding this comment

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

restful 규칙: 행위를 포함하지 않는다.
이거 혹시 / 나 행위가 포함되지않도록 하는건 어떨까요?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

좋습니다! 수정하도록 할게요!

ResponseEntity<CommonResDto<?>> deleteMonthlyAgenda(
@RequestParam("monthlyAgendaId") Long monthlyAgendaId,
SecurityUtils securityUtils
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
.authorizeHttpRequests((authorizeRequests) ->
authorizeRequests
.requestMatchers("/api/v1/members/signup", "/api/v1/members/login/**","/api/v1/members/renew-access-token","/api/v1/members/logout").permitAll()
.requestMatchers("/api/v1/monthlyAgenda/**").permitAll()
Copy link
Member

Choose a reason for hiding this comment

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

저 경로 밑에 있는 경로 전부 오픈시키면 로그인 하지않은 유저들도 해당 API에 데이터에 접근할 수 있을 것 같아요! Member 등급 이상인 권한을 가진 유저들만 API해당 접근할 수있도록 수정해주시면 좋을 것같습니다!

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

아 테스트용 설정했는데, 깜빡했습니다.!

.requestMatchers("/api/v1/mails/send/**").hasAuthority("ADMIN")
.requestMatchers("/swagger-ui/**").permitAll()
.requestMatchers("/v3/api-docs/**").permitAll()
Expand Down
Loading
Loading