Skip to content

Commit

Permalink
Merge pull request #97 from studio-recoding/dev
Browse files Browse the repository at this point in the history
[🚀feat] 7차 배포
  • Loading branch information
JeonHaeseung authored May 27, 2024
2 parents 09cfa24 + 26009dd commit d04d5c8
Show file tree
Hide file tree
Showing 31 changed files with 185 additions and 39 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.stereotype.Component;

import java.io.IOException;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,6 @@
import Ness.Backend.domain.auth.security.AuthDetails;
import Ness.Backend.domain.member.entity.Member;
import Ness.Backend.global.error.ErrorCode;
import static Ness.Backend.global.error.FilterExceptionHandler.setResponse;

import com.auth0.jwt.exceptions.SignatureVerificationException;
import com.auth0.jwt.exceptions.TokenExpiredException;
import jakarta.servlet.FilterChain;
Expand All @@ -19,11 +17,12 @@
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;
import org.springframework.stereotype.Component;

import java.io.IOException;
import java.util.Collections;

import static Ness.Backend.global.error.FilterExceptionHandler.setResponse;

/* 사용자의 권한 부여
* 요청에 포함된 JWT 토큰을 검증하고, 토큰에서 추출한 권한 정보를 기반으로 사용자에 대한 권한을 확인
* 모든 사용자가 모든 리소스에 대한 권한을 가지는 것은 아님-특정 리소스에 대한 권한만 가지도록 해야 함*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.web.client.HttpServerErrorException;

import java.time.LocalDateTime;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,6 @@
import io.swagger.v3.oas.annotations.Operation;
import lombok.RequiredArgsConstructor;
import org.springframework.http.HttpStatus;
import org.springframework.http.HttpStatusCode;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

@RestController
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

import Ness.Backend.domain.member.entity.Member;
import lombok.Data;
import lombok.RequiredArgsConstructor;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.CorsConfigurationSource;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,4 +38,11 @@ public ResponseEntity<?> putUserCategory(@AuthUser Member member, @RequestBody P
categoryService.putUserCategory(member.getId(), putCategoryDto);
return new ResponseEntity<>(HttpStatusCode.valueOf(200));
}

@DeleteMapping("")
@Operation(summary = "사용자가 만든 카테고리 삭제", description = "사용자가 만든 카테고리를 삭제합니다.")
public ResponseEntity<?> putUserCategory(@AuthUser Member member, @RequestParam Long categoryId){
categoryService.deleteUserCategory(member.getId(), categoryId);
return new ResponseEntity<>(HttpStatusCode.valueOf(200));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import Ness.Backend.domain.category.entity.Category;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import org.springframework.stereotype.Repository;

import java.util.List;
Expand All @@ -21,4 +22,12 @@ public interface CategoryRepository extends JpaRepository<Category, Long> {
List<Category> findCategoriesByMember_idAndNameExcludeId(Long memberId, String name, Long categoryId);

List<Category> findCategoriesByMember_idAndName(Long memberId, String name);

@Query(value = "SELECT * FROM category " +
"WHERE member_id = :memberId " +
"AND is_default_none = :isDefaultNone " +
"LIMIT 1",
nativeQuery = true)
Category findCategoryByMember_idAndIsDefaultNone(@Param("memberId") Long memberId,
@Param("isDefaultNone") boolean isDefaultNone);
}
50 changes: 45 additions & 5 deletions src/main/java/Ness/Backend/domain/category/CategoryService.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,22 +7,29 @@
import Ness.Backend.domain.category.entity.Category;
import Ness.Backend.domain.member.MemberRepository;
import Ness.Backend.domain.member.entity.Member;
import Ness.Backend.domain.schedule.ScheduleRepository;
import Ness.Backend.domain.schedule.entity.Schedule;
import Ness.Backend.global.error.exception.DefaultCategoryException;
import Ness.Backend.global.error.exception.DuplicateCategoryException;
import Ness.Backend.global.error.exception.UnauthorizedAccessException;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.Objects;

@Service
@RequiredArgsConstructor
@Slf4j
@Transactional(readOnly = true)
@Transactional
public class CategoryService {
private final CategoryRepository categoryRepository;
private final MemberRepository memberRepository;
private final ScheduleRepository scheduleRepository;
/* 특정 유저의 카테고리 전부 가져오기 */
@Transactional(readOnly = true)
public GetCategoryListDto getUserCategory(Long memberId) {
List<Category> categoryList = categoryRepository.findCategoriesByMember_id(memberId);

Expand All @@ -37,7 +44,6 @@ public GetCategoryListDto getUserCategory(Long memberId) {
}

/* 카테고리 새롭게 만들기(유저에 의해서만 직접 생성) */
@Transactional
public void postUserCategory(Long memberId, PostCategoryDto postCategoryDto){
List<Category> categoryList = categoryRepository.findCategoriesByMember_idAndName(memberId, postCategoryDto.getName());
if(categoryList.isEmpty()){
Expand All @@ -58,17 +64,51 @@ public void postUserCategory(Long memberId, PostCategoryDto postCategoryDto){
}

/* 카테고리 수정하기 */
@Transactional
public void putUserCategory(Long memberId, PutCategoryDto putCategoryDto){
Category changeCategory = categoryRepository.findCategoryById(putCategoryDto.getId());
checkCategoryAuth(memberId, changeCategory);

List<Category> categoryList = categoryRepository.findCategoriesByMember_idAndNameExcludeId(memberId, putCategoryDto.getName(), putCategoryDto.getId());

if(categoryList.isEmpty()){
//중복되지 않은 카테고리일 경우는 변경사항 저장 가능
Category category = categoryRepository.findCategoryById(putCategoryDto.getId());
category.changeCategory(putCategoryDto.getName(), putCategoryDto.getColor());
log.info(putCategoryDto.getId() + "번 카테고리 " + changeCategory.getName() + " 수정");
changeCategory.changeCategory(putCategoryDto.getName(), putCategoryDto.getColor());
}
else {
throw new DuplicateCategoryException();
}
}

/* 카테고리 삭제하기 */
@Transactional
public void deleteUserCategory(Long memberId, Long categoryId){
Category deleteCategory = categoryRepository.findCategoryById(categoryId);
checkCategoryAuth(memberId,deleteCategory);

if(deleteCategory.isDefaultNone()){
//디폴트 미분류 카테고리는 삭제 불가
throw new DefaultCategoryException();
} else{
//디폴트 카테고리 찾기
Category defaultCategory = categoryRepository.findCategoryByMember_idAndIsDefaultNone(memberId, true);

//삭제할 카테고리의 일정은 모두 디폴트로 옮기기
List<Schedule> changeScheduleList = scheduleRepository.findSchedulesByCategory_Id(categoryId);

changeScheduleList.forEach(
schedule -> schedule.changeCategory(defaultCategory));

//해당 카테고리 삭제
log.info(categoryId + "번 카테고리 " + deleteCategory.getName() + " 삭제");
categoryRepository.delete(deleteCategory);
}
}

//자기 자신의 리소스를 접근하고 있는지 확인
private void checkCategoryAuth(Long memberId, Category category){
if(!Objects.equals(memberId, category.getMember().getId())){
throw new UnauthorizedAccessException("권한이 없습니다. 해당 카테고리는 다른 유저가 권한을 가지고 있습니다.");
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

@Entity
@Getter
Expand All @@ -24,6 +25,9 @@ public class Category {
//카테고리별 색상
private String color;

//디폴트로는 false
private boolean isDefaultNone;

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "member_id", nullable = false)
private Member member;
Expand All @@ -37,9 +41,10 @@ public void changeCategory(String name, String color){
}

@Builder
public Category(Member member, String name, String color){
public Category(Member member, String name, String color, boolean isDefaultNone){
this.member = member;
this.name = name;
this.color = color;
this.isDefaultNone = Objects.requireNonNullElse(isDefaultNone, false);
}
}
38 changes: 36 additions & 2 deletions src/main/java/Ness/Backend/domain/member/MemberService.java
Original file line number Diff line number Diff line change
Expand Up @@ -42,14 +42,48 @@ public Member createMember(String email, String password, String picture, String
.build();

//디폴트 미분류 카테고리가 있어야 함, 맴버 생성시 자동 만들어주기
Category category = Category.builder()
//회색
Category noneCategory = Category.builder()
.member(member)
.name("\uD83C\uDF40미분류")
.color("#D9D9D9")
.isDefaultNone(true)
.build();

//초록
Category studyCategory = Category.builder()
.member(member)
.name("\uD83D\uDCD6공부")
.color("#00C09E")
.build();

//하늘
Category workoutCategory = Category.builder()
.member(member)
.name("\uD83C\uDFC3\u200D\uFE0F운동")
.color("#759CFF")
.build();

//핑크
Category restCategory = Category.builder()
.member(member)
.name("\uD83D\uDEDF여가")
.color("#FF75C8")
.build();

//주황
Category meetingCategory = Category.builder()
.member(member)
.name("\uD83D\uDC65약속")
.color("#FFB775")
.build();

profileRepository.save(profile);
categoryRepository.save(category);
categoryRepository.save(noneCategory);
categoryRepository.save(studyCategory);
categoryRepository.save(workoutCategory);
categoryRepository.save(restCategory);
categoryRepository.save(meetingCategory);
return memberRepository.save(member);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@


import Ness.Backend.domain.member.entity.Member;
import Ness.Backend.domain.profile.dto.request.PutProfileDto;
import Ness.Backend.domain.profile.dto.request.PatchPersonaDto;
import Ness.Backend.domain.profile.dto.request.PutProfileDto;
import Ness.Backend.domain.profile.dto.response.GetProfileDto;
import Ness.Backend.global.auth.AuthUser;
import io.swagger.v3.oas.annotations.Operation;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ public interface ReportActivityRepository extends JpaRepository<ReportActivity,
// 특정 맴버의 오늘 하루 생성된 데이터만 반환
@Query( value = "SELECT * FROM report_activity " +
"WHERE member_id = :memberId " +
"AND DATE(created_date) = CURDATE() " +
"AND DATE(CONVERT_TZ(created_date, '+00:00', '+09:00')) = CURDATE() " +
"ORDER BY created_date ASC",
nativeQuery = true)
List<ReportActivity> findTodayReportActivityByMember_Id(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ public interface ReportMemoryRepository extends JpaRepository<ReportMemory, Long
// 특정 맴버의 오늘 하루 생성된 데이터만 반환
@Query( value = "SELECT * FROM report_memory " +
"WHERE member_id = :memberId " +
"AND DATE(created_date) = CURDATE() " +
"AND DATE(CONVERT_TZ(created_date, '+00:00', '+09:00')) = CURDATE() " +
"ORDER BY created_date ASC",
nativeQuery = true)
ReportMemory findTodayReportMemoryByMember_Id(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,15 @@
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;

import java.util.List;

public interface ReportRecommendRepository extends JpaRepository<ReportRecommend, Long> {
// 특정 맴버의 오늘 하루 생성된 한줄 추천 데이터만 반환
@Query( value = "SELECT * FROM report_recommend " +
"WHERE member_id = :memberId " +
"AND DATE(created_date) = CURDATE() " +
"AND DATE(CONVERT_TZ(created_date, '+00:00', '+09:00')) = CURDATE() " +
"ORDER BY created_date ASC",
nativeQuery = true)
ReportRecommend findTodayReportRecommendByMember_Id(
List<ReportRecommend> findTodayReportRecommendByMember_Id(
@Param("memberId") Long memberId);
}
11 changes: 9 additions & 2 deletions src/main/java/Ness/Backend/domain/report/ReportService.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
import Ness.Backend.domain.report.entity.ReportMemory;
import Ness.Backend.domain.report.entity.ReportRecommend;
import Ness.Backend.domain.report.entity.ReportTag;
import Ness.Backend.global.error.ErrorCode;
import Ness.Backend.global.error.exception.NotFoundException;
import Ness.Backend.global.fastApi.FastApiMemoryApi;
import Ness.Backend.global.fastApi.FastApiRecommendApi;
import Ness.Backend.global.fastApi.FastApiTagApi;
Expand Down Expand Up @@ -148,9 +150,9 @@ public PostFastApiAiTagListDto postNewAiTag(Long id, ZonedDateTime today){
public PostFastApiAiRecommendActivityDto getRecommendActivity(Long memberId){
// 오늘 날짜 가져오기
ZonedDateTime now = getToday();
ReportRecommend reportRecommend = reportRecommendRepository.findTodayReportRecommendByMember_Id(memberId);
List<ReportRecommend> reportRecommends = reportRecommendRepository.findTodayReportRecommendByMember_Id(memberId);

if(reportRecommend == null){
if(reportRecommends.isEmpty()){
//새로운 한 줄 추천 및 엑티비티 생성하기
PostFastApiAiRecommendActivityDto aiDto = postNewAiRecommend(memberId, now);
aiDto.setAnswer(parseAiRecommend(aiDto.getAnswer()));
Expand All @@ -177,9 +179,14 @@ public PostFastApiAiRecommendActivityDto getRecommendActivity(Long memberId){
}
return aiDto;
} else{
ReportRecommend reportRecommend = reportRecommends.stream()
.findFirst()
.orElseThrow(() -> new NotFoundException(ErrorCode.MISMATCH_REPORT_RECOMMEND.getMessage()));

List<ReportActivity> reportActivities = reportActivityRepository.findTodayReportActivityByMember_Id(memberId);

List<PostFastApiAiActivityDto> postFastApiAiActivityDtos = reportActivities.stream()
.limit(3) // 처음 세 개의 원소만 선택
.map(activity -> PostFastApiAiActivityDto.builder()
.activity(activity.getActivityText())
.imageTag(activity.getImageTag())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ public interface ReportTagRepository extends JpaRepository<ReportTag, Long> {
//매 월 1일마다 특정 멤버가 생성한 보고서 태그 데이터를 가져오는 역할
@Query( value = "SELECT * FROM report_tag " +
"WHERE member_id = :memberId " +
"AND EXTRACT(YEAR_MONTH FROM CONVERT_TZ(created_date, 'UTC', 'Asia/Seoul')) = EXTRACT(YEAR_MONTH FROM NOW()) " +
"AND EXTRACT(DAY FROM CONVERT_TZ(created_date, 'UTC', 'Asia/Seoul')) = 1;",
"AND EXTRACT(YEAR_MONTH FROM CONVERT_TZ(created_date, '+00:00', '+09:00')) = EXTRACT(YEAR_MONTH FROM NOW()) " +
"AND EXTRACT(DAY FROM CONVERT_TZ(created_date, '+00:00', '+09:00')) = 1;",
nativeQuery = true)
List<ReportTag> findLastMonthReportTagByMember_Id(
@Param("memberId") Long memberId);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,4 +36,6 @@ List<Schedule> findOneDaySchedulesByMember_Id(

//스케쥴 ID로 특정 스케쥴 찾아주기
Schedule findScheduleById(Long scheduleId);

List<Schedule> findSchedulesByCategory_Id(Long categoryId);
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@
import Ness.Backend.domain.member.MemberRepository;
import Ness.Backend.domain.member.entity.Member;
import Ness.Backend.domain.schedule.dto.request.*;
import Ness.Backend.domain.schedule.dto.response.GetScheduleListDto;
import Ness.Backend.domain.schedule.dto.response.GetScheduleDetailDto;
import Ness.Backend.domain.schedule.dto.response.GetScheduleDto;
import Ness.Backend.domain.schedule.dto.response.GetScheduleListDto;
import Ness.Backend.domain.schedule.entity.Schedule;
import Ness.Backend.global.fastApi.FastApiDeleteScheduleApi;
import Ness.Backend.global.fastApi.FastApiPostScheduleApi;
Expand Down Expand Up @@ -236,6 +236,7 @@ public GetScheduleListDto makeScheduleListDto(List<Schedule> scheduleList){
.id(schedule.getId())
.category(schedule.getCategory().getName())
.categoryNum(schedule.getCategory().getId())
.categoryColor(schedule.getCategory().getColor())
.info(schedule.getInfo())
.startTime(schedule.getStartTime())
.endTime(schedule.getEndTime())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonProperty;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
Expand Down
Loading

0 comments on commit d04d5c8

Please sign in to comment.