Skip to content

Commit e626e9c

Browse files
committed
fix: forum
1 parent 1f0e932 commit e626e9c

File tree

11 files changed

+259
-5
lines changed

11 files changed

+259
-5
lines changed

apps/jobboard-backend/src/main/java/org/bounswe/jobboardbackend/forum/controller/ForumController.java

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,42 @@ public ResponseEntity<Void> deletePost(@PathVariable Long id, @AuthenticationPri
5959
return ResponseEntity.noContent().build();
6060
}
6161

62+
@PostMapping("/posts/{id}/upvote")
63+
public ResponseEntity<Void> upvotePost(@PathVariable Long id, @AuthenticationPrincipal UserDetails userDetails) {
64+
User user = getUser(userDetails);
65+
forumService.upvotePost(id, user);
66+
return ResponseEntity.ok().build();
67+
}
68+
69+
@DeleteMapping("/posts/{id}/upvote")
70+
public ResponseEntity<Void> removePostUpvote(@PathVariable Long id,
71+
@AuthenticationPrincipal UserDetails userDetails) {
72+
User user = getUser(userDetails);
73+
forumService.removePostUpvote(id, user);
74+
return ResponseEntity.ok().build();
75+
}
76+
77+
@PostMapping("/posts/{id}/downvote")
78+
public ResponseEntity<Void> downvotePost(@PathVariable Long id, @AuthenticationPrincipal UserDetails userDetails) {
79+
User user = getUser(userDetails);
80+
forumService.downvotePost(id, user);
81+
return ResponseEntity.ok().build();
82+
}
83+
84+
@DeleteMapping("/posts/{id}/downvote")
85+
public ResponseEntity<Void> removePostDownvote(@PathVariable Long id,
86+
@AuthenticationPrincipal UserDetails userDetails) {
87+
User user = getUser(userDetails);
88+
forumService.removePostDownvote(id, user);
89+
return ResponseEntity.ok().build();
90+
}
91+
92+
@PostMapping("/posts/{id}/report")
93+
public ResponseEntity<Void> reportPost(@PathVariable Long id) {
94+
forumService.reportPost(id);
95+
return ResponseEntity.ok().build();
96+
}
97+
6298
@PostMapping("/posts/{id}/comments")
6399
public ResponseEntity<CommentResponse> createComment(@PathVariable Long id,
64100
@AuthenticationPrincipal UserDetails userDetails,
@@ -113,4 +149,10 @@ public ResponseEntity<Void> removeDownvote(@PathVariable Long commentId,
113149
forumService.removeDownvote(commentId, user);
114150
return ResponseEntity.ok().build();
115151
}
152+
153+
@PostMapping("/comments/{commentId}/report")
154+
public ResponseEntity<Void> reportComment(@PathVariable Long commentId) {
155+
forumService.reportComment(commentId);
156+
return ResponseEntity.ok().build();
157+
}
116158
}

apps/jobboard-backend/src/main/java/org/bounswe/jobboardbackend/forum/dto/CommentResponse.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ public class CommentResponse {
1919
private Instant updatedAt;
2020
private long upvoteCount;
2121
private long downvoteCount;
22+
private boolean reported;
2223

2324
public static CommentResponse from(ForumComment comment, long upvoteCount, long downvoteCount) {
2425
return CommentResponse.builder()
@@ -32,6 +33,7 @@ public static CommentResponse from(ForumComment comment, long upvoteCount, long
3233
.updatedAt(comment.getUpdatedAt())
3334
.upvoteCount(upvoteCount)
3435
.downvoteCount(downvoteCount)
36+
.reported(comment.isReported())
3537
.build();
3638
}
3739
}

apps/jobboard-backend/src/main/java/org/bounswe/jobboardbackend/forum/dto/PostResponse.java

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,13 @@ public class PostResponse {
1919
private Instant createdAt;
2020
private Instant updatedAt;
2121
private int commentCount;
22+
private long upvoteCount;
23+
private long downvoteCount;
24+
private boolean reported;
25+
private List<CommentResponse> comments;
2226

23-
public static PostResponse from(ForumPost post) {
27+
public static PostResponse from(ForumPost post, long upvoteCount, long downvoteCount,
28+
List<CommentResponse> comments) {
2429
return PostResponse.builder()
2530
.id(post.getId())
2631
.title(post.getTitle())
@@ -31,6 +36,10 @@ public static PostResponse from(ForumPost post) {
3136
.createdAt(post.getCreatedAt())
3237
.updatedAt(post.getUpdatedAt())
3338
.commentCount(post.getComments() != null ? post.getComments().size() : 0)
39+
.upvoteCount(upvoteCount)
40+
.downvoteCount(downvoteCount)
41+
.reported(post.isReported())
42+
.comments(comments)
3443
.build();
3544
}
3645
}

apps/jobboard-backend/src/main/java/org/bounswe/jobboardbackend/forum/model/ForumComment.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,10 @@ public class ForumComment {
4646
@Builder.Default
4747
private List<ForumCommentDownvote> downvotes = new ArrayList<>();
4848

49+
@Column(nullable = false)
50+
@Builder.Default
51+
private boolean reported = false;
52+
4953
@CreationTimestamp
5054
@Column(nullable = false, updatable = false)
5155
private Instant createdAt;

apps/jobboard-backend/src/main/java/org/bounswe/jobboardbackend/forum/model/ForumPost.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,18 @@ public class ForumPost {
4343
@Builder.Default
4444
private List<ForumComment> comments = new ArrayList<>();
4545

46+
@OneToMany(mappedBy = "post", cascade = CascadeType.ALL, orphanRemoval = true)
47+
@Builder.Default
48+
private List<ForumPostUpvote> upvotes = new ArrayList<>();
49+
50+
@OneToMany(mappedBy = "post", cascade = CascadeType.ALL, orphanRemoval = true)
51+
@Builder.Default
52+
private List<ForumPostDownvote> downvotes = new ArrayList<>();
53+
54+
@Column(nullable = false)
55+
@Builder.Default
56+
private boolean reported = false;
57+
4658
@CreationTimestamp
4759
@Column(nullable = false, updatable = false)
4860
private Instant createdAt;
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
package org.bounswe.jobboardbackend.forum.model;
2+
3+
import jakarta.persistence.*;
4+
import lombok.*;
5+
import org.bounswe.jobboardbackend.auth.model.User;
6+
import org.hibernate.annotations.CreationTimestamp;
7+
8+
import java.time.Instant;
9+
10+
@Entity
11+
@Table(name = "forum_post_downvotes", uniqueConstraints = {
12+
@UniqueConstraint(columnNames = { "user_id", "post_id" })
13+
})
14+
@Getter
15+
@Setter
16+
@NoArgsConstructor
17+
@AllArgsConstructor
18+
@Builder
19+
public class ForumPostDownvote {
20+
21+
@Id
22+
@GeneratedValue(strategy = GenerationType.IDENTITY)
23+
private Long id;
24+
25+
@ManyToOne(fetch = FetchType.LAZY, optional = false)
26+
@JoinColumn(name = "user_id", nullable = false)
27+
private User user;
28+
29+
@ManyToOne(fetch = FetchType.LAZY, optional = false)
30+
@JoinColumn(name = "post_id", nullable = false)
31+
private ForumPost post;
32+
33+
@CreationTimestamp
34+
@Column(nullable = false, updatable = false)
35+
private Instant createdAt;
36+
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
package org.bounswe.jobboardbackend.forum.model;
2+
3+
import jakarta.persistence.*;
4+
import lombok.*;
5+
import org.bounswe.jobboardbackend.auth.model.User;
6+
import org.hibernate.annotations.CreationTimestamp;
7+
8+
import java.time.Instant;
9+
10+
@Entity
11+
@Table(name = "forum_post_upvotes", uniqueConstraints = {
12+
@UniqueConstraint(columnNames = { "user_id", "post_id" })
13+
})
14+
@Getter
15+
@Setter
16+
@NoArgsConstructor
17+
@AllArgsConstructor
18+
@Builder
19+
public class ForumPostUpvote {
20+
21+
@Id
22+
@GeneratedValue(strategy = GenerationType.IDENTITY)
23+
private Long id;
24+
25+
@ManyToOne(fetch = FetchType.LAZY, optional = false)
26+
@JoinColumn(name = "user_id", nullable = false)
27+
private User user;
28+
29+
@ManyToOne(fetch = FetchType.LAZY, optional = false)
30+
@JoinColumn(name = "post_id", nullable = false)
31+
private ForumPost post;
32+
33+
@CreationTimestamp
34+
@Column(nullable = false, updatable = false)
35+
private Instant createdAt;
36+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
package org.bounswe.jobboardbackend.forum.repository;
2+
3+
import org.bounswe.jobboardbackend.forum.model.ForumPostDownvote;
4+
import org.springframework.data.jpa.repository.JpaRepository;
5+
6+
import java.util.Optional;
7+
8+
public interface ForumPostDownvoteRepository extends JpaRepository<ForumPostDownvote, Long> {
9+
Optional<ForumPostDownvote> findByUserIdAndPostId(Long userId, Long postId);
10+
11+
long countByPostId(Long postId);
12+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
package org.bounswe.jobboardbackend.forum.repository;
2+
3+
import org.bounswe.jobboardbackend.forum.model.ForumPostUpvote;
4+
import org.springframework.data.jpa.repository.JpaRepository;
5+
6+
import java.util.Optional;
7+
8+
public interface ForumPostUpvoteRepository extends JpaRepository<ForumPostUpvote, Long> {
9+
Optional<ForumPostUpvote> findByUserIdAndPostId(Long userId, Long postId);
10+
11+
long countByPostId(Long postId);
12+
}

apps/jobboard-backend/src/main/java/org/bounswe/jobboardbackend/forum/service/ForumService.java

Lines changed: 85 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,14 @@
1010
import org.bounswe.jobboardbackend.forum.model.ForumCommentDownvote;
1111
import org.bounswe.jobboardbackend.forum.model.ForumCommentUpvote;
1212
import org.bounswe.jobboardbackend.forum.model.ForumPost;
13+
import org.bounswe.jobboardbackend.forum.model.ForumPostDownvote;
14+
import org.bounswe.jobboardbackend.forum.model.ForumPostUpvote;
1315
import org.bounswe.jobboardbackend.forum.repository.ForumCommentDownvoteRepository;
1416
import org.bounswe.jobboardbackend.forum.repository.ForumCommentRepository;
1517
import org.bounswe.jobboardbackend.forum.repository.ForumCommentUpvoteRepository;
18+
import org.bounswe.jobboardbackend.forum.repository.ForumPostDownvoteRepository;
1619
import org.bounswe.jobboardbackend.forum.repository.ForumPostRepository;
20+
import org.bounswe.jobboardbackend.forum.repository.ForumPostUpvoteRepository;
1721
import org.springframework.stereotype.Service;
1822
import org.springframework.transaction.annotation.Transactional;
1923

@@ -29,6 +33,8 @@ public class ForumService {
2933
private final ForumCommentRepository commentRepository;
3034
private final ForumCommentUpvoteRepository upvoteRepository;
3135
private final ForumCommentDownvoteRepository downvoteRepository;
36+
private final ForumPostUpvoteRepository postUpvoteRepository;
37+
private final ForumPostDownvoteRepository postDownvoteRepository;
3238

3339
@Transactional
3440
public PostResponse createPost(User author, CreatePostRequest request) {
@@ -40,21 +46,21 @@ public PostResponse createPost(User author, CreatePostRequest request) {
4046
.build();
4147

4248
ForumPost savedPost = postRepository.save(post);
43-
return PostResponse.from(savedPost);
49+
return toPostResponse(savedPost);
4450
}
4551

4652
@Transactional(readOnly = true)
4753
public List<PostResponse> findAllPosts() {
4854
return postRepository.findAll().stream()
49-
.map(PostResponse::from)
55+
.map(this::toPostResponse)
5056
.collect(Collectors.toList());
5157
}
5258

5359
@Transactional(readOnly = true)
5460
public PostResponse findPostById(Long id) {
5561
ForumPost post = postRepository.findById(id)
5662
.orElseThrow(() -> new HandleException(ErrorCode.NOT_FOUND, "Post not found"));
57-
return PostResponse.from(post);
63+
return toPostResponse(post);
5864
}
5965

6066
@Transactional
@@ -77,7 +83,7 @@ public PostResponse updatePost(Long id, User user, UpdatePostRequest request) {
7783
}
7884

7985
ForumPost updatedPost = postRepository.save(post);
80-
return PostResponse.from(updatedPost);
86+
return toPostResponse(updatedPost);
8187
}
8288

8389
@Transactional
@@ -211,4 +217,79 @@ private CommentResponse toCommentResponse(ForumComment comment) {
211217
long downvotes = downvoteRepository.countByCommentId(comment.getId());
212218
return CommentResponse.from(comment, upvotes, downvotes);
213219
}
220+
221+
private PostResponse toPostResponse(ForumPost post) {
222+
long upvotes = postUpvoteRepository.countByPostId(post.getId());
223+
long downvotes = postDownvoteRepository.countByPostId(post.getId());
224+
List<CommentResponse> comments = post.getComments().stream()
225+
.map(this::toCommentResponse)
226+
.collect(Collectors.toList());
227+
return PostResponse.from(post, upvotes, downvotes, comments);
228+
}
229+
230+
@Transactional
231+
public void upvotePost(Long postId, User user) {
232+
ForumPost post = postRepository.findById(postId)
233+
.orElseThrow(() -> new HandleException(ErrorCode.NOT_FOUND, "Post not found"));
234+
235+
if (postUpvoteRepository.findByUserIdAndPostId(user.getId(), postId).isPresent()) {
236+
return;
237+
}
238+
239+
postDownvoteRepository.findByUserIdAndPostId(user.getId(), postId)
240+
.ifPresent(postDownvoteRepository::delete);
241+
242+
ForumPostUpvote upvote = ForumPostUpvote.builder()
243+
.user(user)
244+
.post(post)
245+
.build();
246+
postUpvoteRepository.save(upvote);
247+
}
248+
249+
@Transactional
250+
public void removePostUpvote(Long postId, User user) {
251+
postUpvoteRepository.findByUserIdAndPostId(user.getId(), postId)
252+
.ifPresent(postUpvoteRepository::delete);
253+
}
254+
255+
@Transactional
256+
public void downvotePost(Long postId, User user) {
257+
ForumPost post = postRepository.findById(postId)
258+
.orElseThrow(() -> new HandleException(ErrorCode.NOT_FOUND, "Post not found"));
259+
260+
if (postDownvoteRepository.findByUserIdAndPostId(user.getId(), postId).isPresent()) {
261+
return;
262+
}
263+
264+
postUpvoteRepository.findByUserIdAndPostId(user.getId(), postId)
265+
.ifPresent(postUpvoteRepository::delete);
266+
267+
ForumPostDownvote downvote = ForumPostDownvote.builder()
268+
.user(user)
269+
.post(post)
270+
.build();
271+
postDownvoteRepository.save(downvote);
272+
}
273+
274+
@Transactional
275+
public void removePostDownvote(Long postId, User user) {
276+
postDownvoteRepository.findByUserIdAndPostId(user.getId(), postId)
277+
.ifPresent(postDownvoteRepository::delete);
278+
}
279+
280+
@Transactional
281+
public void reportPost(Long postId) {
282+
ForumPost post = postRepository.findById(postId)
283+
.orElseThrow(() -> new HandleException(ErrorCode.NOT_FOUND, "Post not found"));
284+
post.setReported(true);
285+
postRepository.save(post);
286+
}
287+
288+
@Transactional
289+
public void reportComment(Long commentId) {
290+
ForumComment comment = commentRepository.findById(commentId)
291+
.orElseThrow(() -> new HandleException(ErrorCode.NOT_FOUND, "Comment not found"));
292+
comment.setReported(true);
293+
commentRepository.save(comment);
294+
}
214295
}

0 commit comments

Comments
 (0)