Skip to content

Commit

Permalink
Edit or delete comments (#305)
Browse files Browse the repository at this point in the history
* ignore custom settings file

* create view for udpating comment

* create views for deleting comments

* add comment_update and comment_delete to urls

* add date_updated field to comment model

* comment_date_updated

* add author field to commentform

* remove author field from commentform

* change comment url from comments/ to comment/

* import comment model in views file

* reduce comment buttons to 10px

* add edit and delete buttons under comments

* rename add_comment.html to comment.html

* update comment.html to handle editing and creating

* create success url for leaving comments

* comment out create-comment endpoint

* delete create-comment endpoint

* seperate template for updating comment

* update commentUpdateView

* run black test

* delete js code from post_detail.html

* properly configure gitignore

* add unit tests for update and delete urls

* Merge master into edit delete comments (#309)

* Fix failing test

* add tests

* Refactor add comment code (#307)

* update urls for editing and deleting comments

* use form for delete button to POST post slug

* use class-based view for delete endpoint

* run black tests

* update tests for comments ednpoints

* update commentUpdateView

* comment-out comment tests

* delete views import for updating/deleting comments

* Add test

* import comment model and form

* remove comment form and model imports

* add view tests for update_comment

* add view test for deleting posts

* import comment model

* fix error in test_update_comment

* add url tests for updating/deleting comments

* comment test_profliew_view test

* comment test_profile_view

* run ruff checks

* modified:   django_project/tests/test_views.py

* uncomment profile view tests

* rename user in test

* improve styling on comment edit and delete buttons

* refactoring

* refactoring

---------

Co-authored-by: John Solly <[email protected]>
Co-authored-by: John Solly <[email protected]>
  • Loading branch information
3 people authored Jul 20, 2023
1 parent 333043d commit 430718c
Show file tree
Hide file tree
Showing 14 changed files with 294 additions and 115 deletions.
5 changes: 4 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -32,5 +32,8 @@ migration_backup

# Other
logs/
.vscode/

db.sqlite3
db.sqlite3-journal
db.sqlite3-journal

17 changes: 17 additions & 0 deletions django_project/blog/migrations/0033_comment_date_updated.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# Generated by Django 4.2.2 on 2023-06-28 13:44

from django.db import migrations, models


class Migration(migrations.Migration):
dependencies = [
("blog", "0032_remove_comment_body_comment_content"),
]

operations = [
migrations.AddField(
model_name="comment",
name="date_updated",
field=models.DateTimeField(auto_now=True),
),
]
1 change: 1 addition & 0 deletions django_project/blog/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ class Comment(models.Model):
author = models.ForeignKey(User, on_delete=models.CASCADE)
content = CKEditor5Field(blank=True, null=True, config_name="extends")
date_posted = models.DateTimeField(auto_now_add=True)
date_updated = models.DateTimeField(auto_now=True)

class Meta:
ordering = ["date_posted"]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,4 @@ <h3>Comment</h3>
</section>

{% endblock content %}



10 changes: 10 additions & 0 deletions django_project/blog/templates/blog/comment/update_comment.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{% extends 'blog/post/post_detail.html' %}

{% block content %}
<h2>Update Comment</h2>
<form method="post">
{% csrf_token %}
{{ form.as_p }}
<button type="submit">Update</button>
</form>
{% endblock content %}
14 changes: 12 additions & 2 deletions django_project/blog/templates/blog/post/post_detail.html
Original file line number Diff line number Diff line change
Expand Up @@ -70,18 +70,28 @@ <h2>Comments</h2>
</small>
</div>
<div class="comment-content">{{ comment.content|safe }}</div>
{% if comment.author == request.user %}
<span class="comment-actions">
<a href="{% url 'comment-update' comment.id %}" class="btn btn-dark comment-btn comment-edit">Edit</a>
<form class="comment-delete-form" method="POST" action="{% url 'comment-delete' comment.id %}" >
{% csrf_token %}
<button type="submit" class="btn btn-red comment-btn comment-delete">Delete</button>
</form>
</span>
{% endif %}
</li>
</ul>
{% endfor %}
{% else %}
<p class="post-date sml-margin-top-bottom">No comments yet.</p>
{% endif %}
</section>
<!-- End of Comments Section -->

<!-- create comments section-->
{% include 'blog/post/add_comment.html' %}
{% include 'blog/comment/add_comment.html' %}
<!-- End of Create Comments section-->
<!-- End of Comments Section -->


<a href="{% url 'home' %}" id="post-back-to-home-button" class="btn btn-dark">
Back to Home
Expand Down
18 changes: 15 additions & 3 deletions django_project/blog/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
HomeView,
CreatePostView,
CreateCommentView,
CommentUpdateView,
CommentDeleteView,
PostDetailView,
PostUpdateView,
PostDeleteView,
Expand Down Expand Up @@ -36,14 +38,24 @@
path("post/<slug:slug>/", PostDetailView.as_view(), name="post-detail"),
path("post/<slug:slug>/update", PostUpdateView.as_view(), name="post-update"),
path("post/<slug:slug>/delete", PostDeleteView.as_view(), name="post-delete"),
path("category/<slug:slug>/", CategoryView.as_view(), name="blog-category"),
path("portfolio/", PortfolioView.as_view(), name="portfolio"),
path("search/", SearchView.as_view(), name="blog-search"),
path(
"post/<slug:slug>/comment/new",
CreateCommentView.as_view(),
name="comment-create",
),
path("category/<slug:slug>/", CategoryView.as_view(), name="blog-category"),
path("portfolio/", PortfolioView.as_view(), name="portfolio"),
path("search/", SearchView.as_view(), name="blog-search"),
path(
"comment/<int:comment_id>/update",
CommentUpdateView.as_view(),
name="comment-update",
),
path(
"comment/<int:comment_id>/delete",
CommentDeleteView.as_view(),
name="comment-delete",
),
]
if settings.DEBUG: # pragma: no cover
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
120 changes: 74 additions & 46 deletions django_project/blog/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
from .forms import PostForm, CommentForm
from .utils import answer_question
from django.contrib.postgres.search import SearchVector, SearchQuery, SearchRank
from django.shortcuts import get_object_or_404
from django.shortcuts import get_object_or_404, redirect
from django.contrib.auth.mixins import UserPassesTestMixin, LoginRequiredMixin
from django.urls import reverse_lazy
from django.views.generic import (
Expand All @@ -11,6 +11,7 @@
CreateView,
UpdateView,
DeleteView,
View,
)
from django.views.decorators.csrf import csrf_exempt
from django.http import HttpResponse
Expand Down Expand Up @@ -169,7 +170,7 @@ def get_context_data(self, *args, **kwargs):

class CategoryView(ListView):
model = Post
template_name = "blog/post/categories.html" # <app>/<model>_<viewtype>.html
template_name = "blog/categories.html" # <app>/<model>_<viewtype>.html
context_object_name = "posts" # The default is object_list
paginate_by = 3

Expand All @@ -194,7 +195,7 @@ def get_context_data(self, *args, **kwargs):
def get_template_names(self):
if self.request.htmx:
return "blog/parts/posts.html"
return "blog/post/categories.html"
return "blog/categories.html"


class PortfolioView(ListView):
Expand Down Expand Up @@ -257,7 +258,7 @@ def get_context_data(self, *args, **kwargs):

class SearchView(ListView):
model = Post
template_name = "blog/post/search_posts.html"
template_name = "blog/search_posts.html"
context_object_name = "posts"
paginate_by = 10

Expand Down Expand Up @@ -336,21 +337,88 @@ def test_func(self):
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context["title"] = "Create a New Post"
context["description"] = "Create a new blog post."
return context


class PostUpdateView(UserPassesTestMixin, UpdateView):
model = Post
form_class = PostForm
template_name = "blog/post/edit_post.html"

def form_valid(self, form):
form.instance.author = self.request.user
return super().form_valid(form)

def test_func(self):
post = self.get_object()
if self.request.user == post.author:
return True

def get_context_data(self, *args, **kwargs):
context = super().get_context_data(*args, **kwargs)
post = self.get_object()
context["post"] = post
context["title"] = f"Edit {post.title}"
return context


class PostDeleteView(UserPassesTestMixin, DeleteView):
model = Post
success_url = reverse_lazy("home")

def test_func(self):
post = self.get_object()
if self.request.user == post.author:
return True
return False


class CreateCommentView(LoginRequiredMixin, CreateView):
model = Comment
form_class = CommentForm
template_name = "blog/add_comment.html"
template_name = "blog/comment/add_comment.html"

def form_valid(self, form):
form.instance.post = Post.objects.get(slug=self.kwargs["slug"])
form.instance.author = self.request.user
return super().form_valid(form)


class CommentUpdateView(LoginRequiredMixin, UpdateView):
model = Comment
form_class = CommentForm
template_name = "blog/comment/update_comment.html"
context_object_name = "comment"

def get_success_url(self):
return reverse_lazy("post-detail", kwargs={"slug": self.object.post.slug})

def form_valid(self, form):
form.instance.author = self.request.user
return super().form_valid(form)

def get_object(self):
comment_id = self.kwargs.get("comment_id")
comment = get_object_or_404(Comment, id=comment_id)
return comment

def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
comment = self.get_object()
context["post"] = comment.post
context["title"] = f"Edit Comment #{comment.id}"
context["description"] = f"Edit Comment #{comment.id}"
return context


class CommentDeleteView(LoginRequiredMixin, View):
def post(self, request, comment_id):
comment = get_object_or_404(Comment, id=comment_id)
if comment.author == request.user:
comment.delete()
return redirect("post-detail", slug=comment.post.slug)


def generate_gpt_input_value(request, post_id):
blog_post = get_object_or_404(Post, id=post_id)
prompt_dict = {
Expand Down Expand Up @@ -402,43 +470,3 @@ def answer_question_with_GPT(request):
response = f"<div class='messages__item messages__item--bot'>{completion}</div>"

return HttpResponse(response)


class PostUpdateView(UserPassesTestMixin, UpdateView):
model = Post
form_class = PostForm
template_name = "blog/post/edit_post.html"

def form_valid(self, form):
form.instance.author = self.request.user
return super().form_valid(form)

def test_func(self):
post = self.get_object()
if self.request.user == post.author:
return True

def get_context_data(self, *args, **kwargs):
context = super().get_context_data(*args, **kwargs)
post = self.get_object()
context["post"] = post
context["title"] = f"Edit {post.title}"
return context


class PostDeleteView(UserPassesTestMixin, DeleteView):
model = Post
success_url = reverse_lazy("home")

def test_func(self):
post = self.get_object()
if self.request.user == post.author:
return True

def get_context_data(self, *args, **kwargs):
context = super().get_context_data(*args, **kwargs)
post = self.get_object()
context["post"] = post
context["title"] = f"Delete {post.title}"
context["description"] = f"Delete {post.title} from the blog."
return context
9 changes: 9 additions & 0 deletions django_project/staticfiles/css/main.css
Original file line number Diff line number Diff line change
Expand Up @@ -1442,6 +1442,15 @@ img {
.comment {
list-style-type: none;
}

.comment-delete-form {
display: inline;
}
.content-section {
margin-bottom: 30px;
}

.comment-btn {
padding: 3px 8px;
font-size: 8px;
}
12 changes: 12 additions & 0 deletions django_project/tests/test_models.py
Original file line number Diff line number Diff line change
Expand Up @@ -102,3 +102,15 @@ def test_comment_print(self):
self.assertEqual(
str(comment), f"Comment '{comment.content}' by {self.test_user.username}"
)

def test_comment_absolute_url(self):
test_post = create_post()
comment = Comment.objects.create(
post=test_post,
author=self.test_user,
content="Lorem ipsum dolor sit amet, consectetur adipiscing elit.",
)
self.assertEqual(
comment.get_absolute_url(),
f"/post/{test_post.slug}/",
)
14 changes: 13 additions & 1 deletion django_project/tests/test_urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@
SearchView,
PortfolioView,
StatusView,
CommentUpdateView,
CommentDeleteView,
)
from django_project.views import (
works_cited_view,
Expand All @@ -29,7 +31,7 @@
MyPasswordResetDoneView,
MyPasswordResetCompleteView,
)
from .utils import create_user, create_post
from .utils import create_user, create_post, create_comment


def get_url(url_name):
Expand Down Expand Up @@ -130,3 +132,13 @@ def test_password_reset_complete_url_is_resolved(self):

# def test_captcha_url_is_resolved(self):
# self.assertEqual(resolve(reverse("logout")).func.view_class, MyLogoutView)

def test_comment_update_url_is_resolved(self):
comment_on_test_post = create_comment(self.test_post, self.test_user)
url = reverse("comment-update", args=[comment_on_test_post.id])
self.assertEqual(resolve(url).func.view_class, CommentUpdateView)

def test_comment_delete_url_is_resolved(self):
comment_on_test_post = create_comment(self.test_post, self.test_user)
url = reverse("comment-delete", args=[comment_on_test_post.id])
self.assertEqual(resolve(url).func.view_class, CommentDeleteView)
Loading

0 comments on commit 430718c

Please sign in to comment.