Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
…Codiary into refactor/#293-integrate-preview-response
  • Loading branch information
lee-haeseung committed Jan 13, 2025
2 parents e4ef3c9 + 3c8e6fd commit d5ea4f5
Show file tree
Hide file tree
Showing 13 changed files with 131 additions and 14 deletions.
2 changes: 2 additions & 0 deletions src/main/java/com/codiary/backend/BackendApplication.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,12 @@
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.data.jpa.repository.config.EnableJpaAuditing;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.web.bind.annotation.CrossOrigin;

@SpringBootApplication
@EnableJpaAuditing
@EnableScheduling
@CrossOrigin(origins = {"http://localhost:3000", "https://api.codiary.site", "https://www.codiary.site"})
public class BackendApplication {

public static void main(String[] args) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import com.codiary.backend.domain.category.converter.CategoryConverter;
import com.codiary.backend.domain.category.dto.CategoryResponseDTO;
import com.codiary.backend.domain.category.entity.Category;
import com.codiary.backend.domain.category.service.CategoryService;
import com.codiary.backend.domain.member.entity.MemberCategory;
import com.codiary.backend.domain.member.security.CustomMemberDetails;
Expand Down Expand Up @@ -43,4 +44,15 @@ public ApiResponse<String> deleteCategory(@PathVariable("member_category_id") Lo
categoryService.deleteCategory(memberCategoryId, customMemberDetails.getId());
return ApiResponse.onSuccess(SuccessStatus.CATEGORY_OK, "카테고리 삭제가 완료되었습니다.");
}

@Operation(summary = "카테고리 검색", description = "카테고리를 검색합니다.")
@GetMapping("/search")
public ApiResponse<List<CategoryResponseDTO.SimpleCategoryDTO>> searchCategory(
@RequestParam(value = "category", defaultValue = "", required = false) String category,
@AuthenticationPrincipal CustomMemberDetails memberDetails
) {
Long memberId = memberDetails.getId();
List<Category> categories = categoryService.searchCategory(memberId, category);
return ApiResponse.onSuccess(SuccessStatus.POST_OK, CategoryConverter.toSimpleCategoryListDTO(categories));
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.codiary.backend.domain.category.converter;

import com.codiary.backend.domain.category.dto.CategoryResponseDTO;
import com.codiary.backend.domain.category.entity.Category;
import com.codiary.backend.domain.member.entity.MemberCategory;

import java.util.List;
Expand All @@ -19,4 +20,17 @@ public static List<CategoryResponseDTO.MemberCategoryDTO> toMemberCategoryListDT
.map(CategoryConverter::toMemberCategoryDTO)
.toList();
}

public static CategoryResponseDTO.SimpleCategoryDTO toSimpleCategoryDTO(Category category) {
return CategoryResponseDTO.SimpleCategoryDTO.builder()
.categoryId(category.getCategoryId())
.categoryName(category.getName())
.build();
}

public static List<CategoryResponseDTO.SimpleCategoryDTO> toSimpleCategoryListDTO(List<Category> memberCategoryList) {
return memberCategoryList.stream()
.map(CategoryConverter::toSimpleCategoryDTO)
.toList();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,12 @@ public record MemberCategoryDTO(
String categoryName,
Long categoryId
) {}

@Builder
@JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy.class)
@JsonInclude(JsonInclude.Include.NON_NULL)
public record SimpleCategoryDTO(
Long categoryId,
String categoryName
) {}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,10 @@
import com.codiary.backend.domain.category.entity.Category;
import org.springframework.data.jpa.repository.JpaRepository;

import java.util.List;
import java.util.Optional;

public interface CategoryRepository extends JpaRepository<Category, Long> {
Optional<Category> findByName(String name);
List<Category> findByNameContaining(String categoryName);
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.codiary.backend.domain.category.service;

import com.codiary.backend.domain.category.dto.CategoryResponseDTO;
import com.codiary.backend.domain.category.entity.Category;
import com.codiary.backend.domain.category.repository.CategoryRepository;
import com.codiary.backend.domain.member.entity.Member;
Expand Down Expand Up @@ -82,4 +83,12 @@ public Category addCategory(Post post, String categoryName) {
.name(categoryName)
.build()));
}

public List<Category> searchCategory(Long memberId, String category) {
//validation: 멤버인지 확인
memberRepository.findById(memberId)
.orElseThrow(() -> new GeneralException(ErrorStatus.MEMBER_NOT_FOUND));

return categoryRepository.findByNameContaining(category);
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.codiary.backend.domain.post.controller;

import com.codiary.backend.domain.alert.service.AlertService;
import com.codiary.backend.domain.category.dto.CategoryResponseDTO;
import com.codiary.backend.domain.member.entity.Member;
import com.codiary.backend.domain.member.security.CustomMemberDetails;
import com.codiary.backend.domain.member.service.MemberCommandService;
Expand Down Expand Up @@ -230,7 +231,6 @@ public ApiResponse<Page<PostResponseDTO.PostPreviewDTO>> searchPost(
return ApiResponse.onSuccess(SuccessStatus.POST_OK, PostConverter.toPostListResponseDto(postPage));
}


// 게시글의 카테고리 설정 및 변경
@PatchMapping("/category/{postId}")
@Operation(summary = "게시글의 카테고리 설정 및 변경 API", description = "게시글의 카테고리를 설정 및 변경합니다.")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@ public Page<Post> searchPost(Long memberId, String keyword, Pageable pageable) {
.from(post)
.leftJoin(post.member, member)
.leftJoin(member.image, memberImage)
.leftJoin(post.team, team).fetchJoin()
.orderBy(getOrderBy(pageable.getSort()))
.where(keywordEq(keyword)) // Full-Text Search 조건
.where(canAccess(memberId))
.offset(pageable.getOffset())
Expand All @@ -59,6 +61,7 @@ public Page<Post> searchPost(Long memberId, String keyword, Pageable pageable) {
.select(post.count())
.from(post)
.where(keywordEq(keyword)) // Full-Text Search 조건
.where(canAccess(memberId))
.fetchOne();

return new PageImpl<>(postList, pageable, total);
Expand Down Expand Up @@ -118,11 +121,12 @@ public Page<Post> getLatestPostsOfFollowings(Long memberId, Pageable pageable) {

@Override
public Page<Post> getPostList(Pageable pageable) {
OrderSpecifier[] orderSpecifiers = createPostListOrderSpecifier(pageable.getSort());
OrderSpecifier[] orderSpecifiers = getOrderBy(pageable.getSort());

List<Post> posts = queryFactory
.selectDistinct(post)
.from(post)
.join(post.team, team).fetchJoin()
.where(post.postAccess.eq(PostAccess.ENTIRE))
.orderBy(orderSpecifiers)
.offset(pageable.getOffset())
Expand All @@ -138,7 +142,7 @@ public Page<Post> getPostList(Pageable pageable) {
return new PageImpl<>(posts, pageable, total);
}

private OrderSpecifier[] createPostListOrderSpecifier(Sort sort) {
private OrderSpecifier[] getOrderBy(Sort sort) {
List<OrderSpecifier> orderSpecifiers = new ArrayList<>();

for (Sort.Order order : sort) {
Expand Down Expand Up @@ -174,7 +178,7 @@ public Page<Post> getPostsByCategoryId(Long memberId, Long categoryId, Pageable
.selectDistinct(post)
.from(post)
.where(post.categoriesList.any().categoryId.eq(categoryId).and(canAccess(memberId)))
.orderBy(createPostListOrderSpecifier(pageable.getSort()))
.orderBy(getOrderBy(pageable.getSort()))
.offset(pageable.getOffset())
.limit(pageable.getPageSize())
.fetch();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
import com.codiary.backend.global.apiPayload.ApiResponse;
import com.codiary.backend.global.apiPayload.code.status.SuccessStatus;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.security.SecurityRequirement;
import io.swagger.v3.oas.annotations.tags.Tag;
import java.util.List;
import lombok.RequiredArgsConstructor;
Expand Down Expand Up @@ -157,4 +158,14 @@ public ApiResponse<String> deleteTeamBannerImage(
String response = teamService.deleteTeamBannerImage(teamId, memberId);
return ApiResponse.onSuccess(SuccessStatus.TEAM_OK, response);
}


@GetMapping("/list")
@Operation(summary = "팀 리스트 조회 API", description = "팀 설정을 위한 팀 전체 리스트를 조회합니다.")
public ApiResponse<TeamResponseDTO.TeamPreviewListDTO> findTeams(){
List<Team> teams = teamService.getTeams();
return ApiResponse.onSuccess(SuccessStatus.TEAM_OK, TeamConverter.toTeamPreviewListDTO(teams));
}


}
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import com.codiary.backend.domain.team.entity.TeamProfileImage;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

public class TeamConverter {
public static TeamResponseDTO.TeamDTO toTeamResponseDto(Team team) {
Expand Down Expand Up @@ -96,4 +97,21 @@ public static TeamResponseDTO.TeamImageDTO toTeamImageResponseDTO(TeamBannerImag
.url(bannerImage.getImageUrl())
.build();
}

public static TeamResponseDTO.TeamPreviewDTO toTeamPreviewDTO(Team team) {
return TeamResponseDTO.TeamPreviewDTO.builder()
.teamId(team.getTeamId())
.teamName(team.getName())
.build();
}

public static TeamResponseDTO.TeamPreviewListDTO toTeamPreviewListDTO(List<Team> teamList) {
List<TeamResponseDTO.TeamPreviewDTO> teamPreviewDTOList = IntStream.range(0, teamList.size())
.mapToObj(i->toTeamPreviewDTO(teamList.get(i)))
.collect(Collectors.toList());
return TeamResponseDTO.TeamPreviewListDTO.builder()
.teams(teamPreviewDTOList)
.build();
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,10 @@
import java.util.List;

import io.swagger.v3.oas.annotations.media.Schema;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;

public class TeamResponseDTO {

Expand Down Expand Up @@ -88,4 +91,20 @@ public record TeamMemberDTO(
public record TeamImageDTO(
String url) {
}


@JsonInclude(JsonInclude.Include.NON_NULL)
@JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy.class)
@Builder
public record TeamPreviewDTO (
Long teamId,
String teamName
){}

@JsonInclude(JsonInclude.Include.NON_NULL)
@JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy.class)
@Builder
public record TeamPreviewListDTO (
List<TeamResponseDTO.TeamPreviewDTO> teams
){}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import com.codiary.backend.global.common.uuid.UuidRepository;
import com.codiary.backend.global.s3.AmazonS3Manager;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
Expand Down Expand Up @@ -250,4 +251,9 @@ public String deleteTeamBannerImage(Long teamId, Long memberId) {
// response: 성공을 반환
return "성공적으로 삭제되었습니다!";
}

public List<Team> getTeams() {
return teamRepository.findAllByOrderByTeamIdDesc();
}

}
32 changes: 22 additions & 10 deletions src/main/java/com/codiary/backend/global/config/SecurityConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,10 @@
import lombok.RequiredArgsConstructor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.Customizer;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
Expand Down Expand Up @@ -42,16 +44,18 @@ public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Excepti
//
// return http.build();
return http
.httpBasic(httpBasic -> httpBasic.disable())
.csrf(csrf -> csrf.disable())
.httpBasic(AbstractHttpConfigurer::disable)
.cors(Customizer.withDefaults())
.csrf(AbstractHttpConfigurer::disable)
.sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS))

.authorizeHttpRequests(
authorize -> authorize
.requestMatchers("/error").permitAll()
// Member 관련 접근
.requestMatchers("/api/v2/auth/**").permitAll()
.requestMatchers("/api/v2/oauth/**").permitAll()
.requestMatchers("/api/v2/member/**").permitAll()
// Post 관련 접근
.requestMatchers("/api/v2/post/**").permitAll()
.requestMatchers("/api/v2/post/search").permitAll()
.requestMatchers("/api/v2/post","/api/v2/post/{postId}", "/api/v2/post/visibility/{postId}", "/api/v2/post/coauthor/{postId}", "/api/v2/post/category/{postId}").permitAll()
.requestMatchers("/api/v2/post/title/paging", "/api/v2/post/team/{teamId}/{postId}", "/api/v2/post/team/{teamId}/member/{memberId}/paging", "/api/v2/post/project/{projectId}/team/{teamId}/paging").permitAll()
Expand All @@ -61,22 +65,28 @@ public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Excepti
.requestMatchers("/api/v2/post/latest", "api/v2/post/following").permitAll() // 전체 최신글 조회 & 팔로잉 멤버들의 최신글 조회

// Comment 관련 접근
.requestMatchers("api/v2/comment/**").permitAll()
.requestMatchers("/api/v2/post/{post_id}/comment").permitAll() // 게시물에 댓글 생성, 조회
.requestMatchers("/api/v2/comment/{comment_id}/reply").permitAll() // 댓글에 대댓글 생성, 조회
.requestMatchers("/api/v2/comment/{comment_id}").permitAll() // 댓글 & 대댓글 수정 삭제

// Team 관련 접근
.requestMatchers("/api/v2/team/**").permitAll()
.requestMatchers("/api/v2/team/team_member").permitAll()
.requestMatchers("/api/v2/team/{team_id}/profile_image").permitAll()
.requestMatchers("/api/v2/team/{team_id}/banner_image").permitAll()
// Bookmark 관련 접근
// Calendar 관련 접근

// follow 관련 접근
.requestMatchers("/api/v2/follow/**").permitAll()

// Project 관련 접근
.requestMatchers("/api/v2/project/**").permitAll()
// Category 관련 접근
.requestMatchers("/api/v2/category/**").permitAll()
// 알람 관련 접근
.requestMatchers("/api/v2/connect", "/api/v2/disconnect").permitAll()
.requestMatchers("/api/v2/connect", "/api/v2/disconnect", "/api/v2/alert/**").permitAll()
// 기타 관련 접근
.requestMatchers("/", "/api-docs/**", "/api-docs/swagger-config/*", "/swagger-ui/*", "/swagger-ui/**", "/v3/api-docs/**").permitAll()
.requestMatchers("/**", "/api-docs/**", "/api-docs/swagger-config/*", "/swagger-ui/*", "/swagger-ui/**", "/v3/api-docs/**").permitAll()
.anyRequest().authenticated()
)
.addFilterBefore(new JwtAuthenticationFilter(jwtTokenProvider), EmailPasswordAuthenticationFilter.class).build();
Expand All @@ -93,8 +103,10 @@ public PasswordEncoder passwordEncoder() {
CorsConfigurationSource corsConfigurationSource() {
CorsConfiguration config = new CorsConfiguration();
config.setAllowCredentials(true);
config.setAllowedOriginPatterns(List.of("*", "http://localhost:3000", "https://www.codiary.site"));
config.setAllowedOrigins(List.of("http://localhost:3000", "https://www.codiary.site"));
config.setAllowedOriginPatterns(List.of("http://localhost:3000", "https://www.codiary.site", "https://codiary.site", "https://api.codiary.site",
"http://localhost:3000/", "https://www.codiary.site/", "https://codiary.site/", "https://api.codiary.site/"));
config.setAllowedOrigins(List.of("http://localhost:3000", "https://www.codiary.site", "https://codiary.site", "https://api.codiary.site",
"http://localhost:3000/", "https://www.codiary.site/", "https://codiary.site/", "https://api.codiary.site/"));
config.setAllowedMethods(List.of("GET", "POST", "PUT", "DELETE", "PATCH", "OPTIONS"));
config.setAllowedHeaders(List.of("*"));
config.setExposedHeaders(List.of("*"));
Expand Down

0 comments on commit d5ea4f5

Please sign in to comment.