Skip to content

Commit eb1dda3

Browse files
committed
Delete comment
1 parent 751f4c1 commit eb1dda3

26 files changed

Lines changed: 380 additions & 44 deletions

src/main/java/alexp/blog/controller/CommentController.java

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import alexp.blog.model.Comment;
44
import alexp.blog.model.Post;
5+
import alexp.blog.service.ActionExpiredException;
56
import alexp.blog.service.CommentService;
67
import alexp.blog.service.PostService;
78
import alexp.blog.service.UserService;
@@ -40,6 +41,7 @@ public String showComments(@PathVariable("postId") Long postId, ModelMap model)
4041
List<Comment> comments = commentService.getPostComments(post);
4142

4243
model.addAttribute("comments", comments);
44+
model.addAttribute("post", post);
4345

4446
return "fragments/comments :: commentList";
4547
}
@@ -65,4 +67,16 @@ public String showComments(@PathVariable("postId") Long postId, ModelMap model)
6567
return "ok";
6668
}
6769

70+
@PreAuthorize("hasRole('ROLE_USER')")
71+
@RequestMapping(value = "/posts/{postId}/comments/{commentId}/delete", method = RequestMethod.POST)
72+
public @ResponseBody String deleteComment(@PathVariable("postId") Long postId, @PathVariable("commentId") Long commentId) {
73+
try {
74+
commentService.deleteComment(commentId);
75+
} catch (ActionExpiredException e) {
76+
return "expired";
77+
}
78+
79+
return "ok";
80+
}
81+
6882
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
package alexp.blog.controller;
2+
3+
import org.springframework.http.HttpStatus;
4+
import org.springframework.web.bind.annotation.ResponseStatus;
5+
6+
@ResponseStatus(value = HttpStatus.FORBIDDEN)
7+
public class ForbiddenException extends RuntimeException {
8+
}

src/main/java/alexp/blog/model/Comment.java

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
import org.hibernate.validator.constraints.NotBlank;
66

77
import javax.persistence.*;
8-
import java.time.LocalDateTime;
8+
import java.time.*;
99
import java.util.Date;
1010

1111
@Entity
@@ -33,6 +33,23 @@ public class Comment {
3333
@JoinColumn(name = "post_id", nullable = false)
3434
private Post post;
3535

36+
@Column(nullable = false)
37+
private boolean deleted = false;
38+
39+
public boolean userCanDelete() {
40+
return LocalDateTime.now().isBefore(maxDeleteTime());
41+
}
42+
43+
public LocalDateTime maxDeleteTime() {
44+
return dateTime.plusMinutes(2);
45+
}
46+
47+
// should refactor to store dates in UTC in database
48+
49+
public long maxDeleteTimeUnixTimestamp() {
50+
return maxDeleteTime().atZone(ZoneId.systemDefault()).toInstant().toEpochMilli();
51+
}
52+
3653
public Long getId() {
3754
return Id;
3855
}
@@ -77,4 +94,11 @@ public void setPost(Post post) {
7794
this.post = post;
7895
}
7996

97+
public boolean isDeleted() {
98+
return deleted;
99+
}
100+
101+
public void setDeleted(boolean deleted) {
102+
this.deleted = deleted;
103+
}
80104
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
package alexp.blog.service;
2+
3+
public class ActionExpiredException extends Exception {
4+
5+
public ActionExpiredException(String message) {
6+
super(message);
7+
}
8+
}

src/main/java/alexp/blog/service/CommentService.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,5 +9,9 @@ public interface CommentService {
99

1010
List<Comment> getPostComments(Post post);
1111

12+
Comment getComment(Long id);
13+
1214
void saveNewComment(Comment comment, Post post);
15+
16+
void deleteComment(Long commentId) throws ActionExpiredException;
1317
}

src/main/java/alexp/blog/service/CommentServiceImpl.java

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package alexp.blog.service;
22

3+
import alexp.blog.controller.ForbiddenException;
34
import alexp.blog.model.Comment;
45
import alexp.blog.model.Post;
56
import alexp.blog.repository.CommentRepository;
@@ -24,6 +25,11 @@ public List<Comment> getPostComments(Post post) {
2425
return post.getComments();
2526
}
2627

28+
@Override
29+
public Comment getComment(Long id) {
30+
return commentRepository.findOne(id);
31+
}
32+
2733
@Override
2834
public void saveNewComment(Comment comment, Post post) {
2935
comment.setDateTime(LocalDateTime.now());
@@ -34,4 +40,23 @@ public void saveNewComment(Comment comment, Post post) {
3440

3541
commentRepository.saveAndFlush(comment);
3642
}
43+
44+
@Override
45+
public void deleteComment(Long commentId) throws ActionExpiredException {
46+
Comment comment = getComment(commentId);
47+
48+
boolean isAdmin = userService.isAdmin();
49+
50+
if (!isAdmin && !userService.currentUser().getUsername().equals(comment.getUser().getUsername())) {
51+
throw new ForbiddenException();
52+
}
53+
54+
if (!isAdmin && !comment.userCanDelete()) {
55+
throw new ActionExpiredException("delete time exceeded");
56+
}
57+
58+
comment.setDeleted(true);
59+
60+
commentRepository.saveAndFlush(comment);
61+
}
3762
}

src/main/resources/dummy-data.sql

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1670,6 +1670,6 @@ INSERT INTO posts_tags(post_id, tag_id) VALUES (85, 4);
16701670
INSERT INTO posts_tags(post_id, tag_id) VALUES (85, 5);
16711671

16721672

1673-
INSERT INTO comments(commentText, dateTime, post_id, user_id) VALUES('Great post! Keep it up!', '2015-04-03 14:30:58', 85, 2);
1674-
INSERT INTO comments(commentText, dateTime, post_id, user_id) VALUES('Yeah, I learnt **so much** here.', '2015-04-03 16:35:58', 85, 3);
1675-
INSERT INTO comments(commentText, dateTime, post_id, user_id) VALUES('Thank you.:)', '2015-04-03 19:00:58', 85, 1);
1673+
INSERT INTO comments(commentText, dateTime, post_id, user_id, deleted) VALUES('Great post! Keep it up!', '2015-04-03 14:30:58', 85, 2, 0);
1674+
INSERT INTO comments(commentText, dateTime, post_id, user_id, deleted) VALUES('Yeah, I learnt **so much** here.', '2015-04-03 16:35:58', 85, 3, 0);
1675+
INSERT INTO comments(commentText, dateTime, post_id, user_id, deleted) VALUES('Thank you.:)', '2015-04-03 19:00:58', 85, 1, 0);

src/main/webapp/WEB-INF/templates/fragments/comments.html

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,27 @@
99
<body>
1010
<th:block th:fragment="commentList">
1111
<div class="comment" th:each="comment : ${comments}">
12-
<a class="comment-title" th:href="@{|/users/${comment.user.username}|}" th:text="${comment.user.username}"></a>
12+
<a th:unless="${comment.deleted}" class="comment-title" th:href="@{|/users/${comment.user.username}|}" th:text="${comment.user.username}"></a>
13+
<span th:if="${comment.deleted}" class="deleted">[deleted]</span>
14+
1315
<span class="post-date" th:text="${#temporals.format(comment.dateTime, 'MMM dd, yyyy HH:mm')}"></span>
1416

15-
<div class="comment-content" th:utext="${comment.getCommentTextHtml()}"></div>
17+
<div>
18+
<div class="comment-content" th:classappend="${comment.deleted} ? 'deleted'" th:utext="${comment.deleted} ? '[deleted]' : ${comment.getCommentTextHtml()}"></div>
19+
</div>
20+
21+
<div class="post-actions" th:if="${#authorization.expression('isAuthenticated()')}">
22+
<th:block th:unless="${comment.deleted}">
23+
<a th:if="${#authorization.expression('hasRole(''ROLE_ADMIN'')') or (#authentication.name == comment.user.username and comment.userCanDelete())}"
24+
href="javascript:void(0)"
25+
data-action="deleteComment"
26+
th:attr="data-href=@{|/posts/${post.id}/comments/${comment.id}/delete|},
27+
data-maxDate=(${#authorization.expression('hasRole(''ROLE_ADMIN'')')} ? '' : ${comment.maxDeleteTimeUnixTimestamp()})">delete</a>
28+
</th:block>
29+
</div>
30+
<div class="commentaction-loading-indicator" style="display: none">
31+
<img th:src="@{/images/ajax-loader.gif}" />
32+
</div>
1633
</div>
1734
</th:block>
1835

src/main/webapp/WEB-INF/templates/posts.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ <h2 th:text="${tag}"></h2>
4040
</div>
4141

4242
<div class="post-actions">
43-
<a th:href="@{|/posts/${post.id}#comments|}"
43+
<a class="comments-link" th:href="@{|/posts/${post.id}#comments|}"
4444
th:text="${post.comments.size() == 0} ? 'comments' : (${post.comments.size()} + ' comment' + (${post.comments.size() &gt; 1} ? 's' : ''))"></a>
4545

4646
<a sec:authorize="hasRole('ROLE_ADMIN')" th:href="@{|/posts/${post.id}/edit|}">edit</a>

src/main/webapp/WEB-INF/web.xml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,10 @@
3737
<error-code>404</error-code>
3838
<location>/404</location>
3939
</error-page>
40+
<error-page>
41+
<error-code>403</error-code>
42+
<location>/403</location>
43+
</error-page>
4044
<error-page>
4145
<location>/error</location>
4246
</error-page>

0 commit comments

Comments
 (0)