Skip to content
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 @@ -4,10 +4,12 @@
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.properties.ConfigurationPropertiesScan;
import org.springframework.data.jpa.repository.config.EnableJpaAuditing;
import org.springframework.scheduling.annotation.EnableScheduling;

@SpringBootApplication
@ConfigurationPropertiesScan
@EnableJpaAuditing
@EnableScheduling
public class Nbe57202TeamApplication {

public static void main(String[] args) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,11 @@ public enum ErrorCode {
UNAUTHORIZED_POST_ACCESS(UNAUTHORIZED, "POST-002", "게시글에 대한 권한이 없습니다."),
LIKE_ALREADY_EXIST(BAD_REQUEST, "POST-003", "좋아요가 이미 존재합니다."),
NOT_FOUND_LIKE(NOT_FOUND, "POST-004", "해당 좋아요가 존재하지 않습니다."),
RECRUITMENT_NOT_AVAILABLE(BAD_REQUEST, "POST-005", "모집 중인 게시글에만 지원 가능합니다."),
NOT_FOUND_RECRUITMENT_FIELD(NOT_FOUND, "POST-006", "해당 모집 분야가 존재하지 않습니다."),
RECRUITMENT_CLOSED(BAD_REQUEST, "POST-007", "해당 모집 분야는 마감되었습니다."),
ALREADY_APPLIED(BAD_REQUEST, "POST-008", "이미 지원한 분야입니다."),
CANNOT_APPLY_TO_OWN_POST(BAD_REQUEST, "POST-009", "본인 글에는 지원할 수 없습니다."),

// CHAT MESSAGE
CHAT_MESSAGE_CONTENT_BLANK(BAD_REQUEST, "CHAT-00", "메세지 내용이 비어있습니다."),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,13 @@
import static org.springframework.http.HttpStatus.CREATED;
import static org.springframework.util.CollectionUtils.isEmpty;

import com.fasterxml.jackson.databind.ObjectMapper;

import io.twogether.nbe_5_7_2_02team.post.dto.request.PostApplyRequest;
import io.twogether.nbe_5_7_2_02team.post.dto.request.PostCreateRequest;
import io.twogether.nbe_5_7_2_02team.post.dto.request.PostGetRequest;
import io.twogether.nbe_5_7_2_02team.post.dto.request.PostUpdateRequest;
import io.twogether.nbe_5_7_2_02team.post.dto.request.RecruitmentFieldRequest;
import io.twogether.nbe_5_7_2_02team.post.dto.response.PostDetailResponse;
import io.twogether.nbe_5_7_2_02team.post.dto.response.PostGetResponse;
import io.twogether.nbe_5_7_2_02team.post.dto.response.PostResponse;
Expand All @@ -25,8 +29,14 @@
import org.springframework.web.bind.annotation.PatchMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestPart;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

import java.util.Arrays;
import java.util.List;

@RestController
@RequiredArgsConstructor
Expand All @@ -38,7 +48,23 @@ public class PostController {
@PostMapping(consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
public ResponseEntity<PostResponse> createPost(
@AuthenticationPrincipal UserDetails userDetails,
@Valid @ModelAttribute PostCreateRequest request) {
@ModelAttribute @Valid PostCreateRequest request) {

if (request.getRecruitmentFieldsJson() != null
&& !request.getRecruitmentFieldsJson().isBlank()) {
try {
ObjectMapper mapper = new ObjectMapper();
List<RecruitmentFieldRequest> fields =
Arrays.asList(
mapper.readValue(
request.getRecruitmentFieldsJson(),
RecruitmentFieldRequest[].class));
request.setRecruitmentFields(fields);
} catch (Exception e) {
// TODO: 커스텀 Exception으로 변경
throw new RuntimeException("Invalid recruitmentFieldsJson", e);
}
}

PostResponse response =
postService.createPost(request, Long.parseLong(userDetails.getUsername()));
Expand All @@ -48,9 +74,11 @@ public ResponseEntity<PostResponse> createPost(
@PatchMapping(value = "/{postId}", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
public ResponseEntity<PostResponse> updatePost(
@PathVariable Long postId,
@ModelAttribute PostUpdateRequest request,
@RequestPart("post") PostUpdateRequest request,
@RequestPart(value = "images", required = false) List<MultipartFile> images,
@AuthenticationPrincipal UserDetails userDetails) {

request.setImages(images);
PostResponse response =
postService.updatePost(postId, request, Long.parseLong(userDetails.getUsername()));
return ResponseEntity.ok(response);
Expand Down Expand Up @@ -106,4 +134,15 @@ public ResponseEntity<Void> unlikePost(
postService.unlikePost(postId, Long.parseLong(userDetails.getUsername()));
return ResponseEntity.ok().build();
}

@PostMapping("/{postId}/apply")
public ResponseEntity<Void> applyToField(
@PathVariable Long postId,
@RequestBody @Valid PostApplyRequest request,
@AuthenticationPrincipal UserDetails userDetails) {

postService.apply(
postId, request.getFieldName(), Long.parseLong(userDetails.getUsername()));
return ResponseEntity.ok().build();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package io.twogether.nbe_5_7_2_02team.post.dao;

import io.twogether.nbe_5_7_2_02team.member.domain.Member;
import io.twogether.nbe_5_7_2_02team.post.domain.PostApplication;
import io.twogether.nbe_5_7_2_02team.post.domain.RecruitmentField;

import org.springframework.data.jpa.repository.JpaRepository;

public interface PostApplicationRepository extends JpaRepository<PostApplication, Long> {

boolean existsByMemberAndField(Member member, RecruitmentField field);
}
Original file line number Diff line number Diff line change
@@ -1,15 +1,20 @@
package io.twogether.nbe_5_7_2_02team.post.dao;

import io.twogether.nbe_5_7_2_02team.post.domain.Post;
import io.twogether.nbe_5_7_2_02team.post.domain.RecruitmentStatus;

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;

import java.time.LocalDate;
import java.util.List;

public interface PostRepository extends JpaRepository<Post, Long>, PostRepositoryFilter {

@Query("SELECT p FROM Post p WHERE p.member.id = :memberId")
List<Post> findAllByMemberId(@Param("memberId") Long memberId);

List<Post> findByRecruitmentStatusAndRecruitmentDeadlineBefore(
RecruitmentStatus status, LocalDate deadline);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package io.twogether.nbe_5_7_2_02team.post.dao;

import io.twogether.nbe_5_7_2_02team.post.domain.RecruitmentField;

import org.springframework.data.jpa.repository.JpaRepository;

public interface RecruitmentFieldRepository extends JpaRepository<RecruitmentField, Long> {}
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
import lombok.NoArgsConstructor;
import lombok.Setter;

import java.time.LocalDate;
import java.util.ArrayList;
import java.util.List;

Expand All @@ -30,9 +31,15 @@ public class Post extends BaseEntity {
@Column(nullable = false)
private String content;

@Setter
@Enumerated(EnumType.STRING)
private RecruitmentStatus recruitmentStatus;

@Setter private LocalDate recruitmentDeadline;

@OneToMany(mappedBy = "post", cascade = CascadeType.ALL, orphanRemoval = true)
private List<RecruitmentField> recruitmentFields = new ArrayList<>();

@OneToMany(mappedBy = "post", cascade = CascadeType.ALL, orphanRemoval = true)
private List<PostTag> postTags = new ArrayList<>();

Expand Down Expand Up @@ -66,6 +73,6 @@ public Post(
public void update(String title, String content, RecruitmentStatus status) {
if (title != null) this.title = title;
if (content != null) this.content = content;
if (recruitmentStatus != null) this.recruitmentStatus = status;
if (status != null) this.recruitmentStatus = status;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package io.twogether.nbe_5_7_2_02team.post.domain;

import io.twogether.nbe_5_7_2_02team.member.domain.Member;

import jakarta.persistence.Entity;
import jakarta.persistence.FetchType;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.ManyToOne;

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

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

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

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "member_id", nullable = false)
private Member member;

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "post_id", nullable = false)
private Post post;

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "field_id", nullable = false)
private RecruitmentField field;

@Builder
public PostApplication(Member member, Post post, RecruitmentField field) {
this.member = member;
this.post = post;
this.field = field;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
package io.twogether.nbe_5_7_2_02team.post.domain;

import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.FetchType;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.ManyToOne;

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

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

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

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "post_id")
private Post post;

@Column(nullable = false)
private String fieldName;

@Column(nullable = false)
private int totalCount;

@Column(nullable = false)
private int currentCount = 0;

@Column(nullable = false)
private boolean closed = false;

@Builder
public RecruitmentField(
Post post, String fieldName, int totalCount, int currentCount, boolean closed) {
this.post = post;
this.fieldName = fieldName;
this.totalCount = totalCount;
this.currentCount = currentCount;
this.closed = closed;
}

public void close() {
this.closed = true;
}

public void increaseCount() {
this.currentCount++;
if (this.currentCount >= this.totalCount) {
this.closed = true;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package io.twogether.nbe_5_7_2_02team.post.dto.request;

import com.fasterxml.jackson.annotation.JsonProperty;

import jakarta.validation.constraints.NotBlank;

import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;

@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
public class PostApplyRequest {

@NotBlank(message = "모집 분야는 필수입니다.")
@JsonProperty("fieldName")
private String fieldName;
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
package io.twogether.nbe_5_7_2_02team.post.dto.request;

import com.fasterxml.jackson.annotation.JsonIgnore;

import io.twogether.nbe_5_7_2_02team.post.domain.RecruitmentStatus;

import jakarta.validation.constraints.FutureOrPresent;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Size;
Expand All @@ -12,6 +15,7 @@

import org.springframework.web.multipart.MultipartFile;

import java.time.LocalDate;
import java.util.ArrayList;
import java.util.List;

Expand All @@ -29,8 +33,15 @@ public class PostCreateRequest {
@NotNull(message = "모집 상태는 필수입니다.")
private RecruitmentStatus recruitmentStatus;

@FutureOrPresent(message = "마감일은 오늘 이후의 날짜여야 합니다.")
private LocalDate recruitmentDeadline;

@Size(max = 10, message = "이미지는 최대 10개까지만 업로드할 수 있습니다.")
private List<MultipartFile> images;

private List<String> tags = new ArrayList<>();

private String recruitmentFieldsJson;

@JsonIgnore private List<RecruitmentFieldRequest> recruitmentFields = new ArrayList<>();
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@

import org.springframework.web.multipart.MultipartFile;

import java.time.LocalDate;
import java.util.ArrayList;
import java.util.List;

@Getter
Expand All @@ -18,6 +20,8 @@ public class PostUpdateRequest {
private String title;
private String content;
private RecruitmentStatus recruitmentStatus;
private LocalDate recruitmentDeadline;
private List<MultipartFile> images;
private List<String> tags;
private List<RecruitmentFieldRequest> recruitmentFields = new ArrayList<>();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package io.twogether.nbe_5_7_2_02team.post.dto.request;

import jakarta.validation.constraints.Min;
import jakarta.validation.constraints.NotBlank;

import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;

@Getter
@Setter
@NoArgsConstructor
public class RecruitmentFieldRequest {

@NotBlank private String fieldName;

@Min(1)
private int totalCount;
}
Loading