Skip to content

Commit

Permalink
Allow comments on news articles
Browse files Browse the repository at this point in the history
  • Loading branch information
anorthall committed Oct 28, 2023
1 parent 98b8aca commit 2ec6fe5
Show file tree
Hide file tree
Showing 13 changed files with 219 additions and 16 deletions.
38 changes: 37 additions & 1 deletion app/comments/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
from django.core.exceptions import ValidationError
from django.urls import reverse

from .models import Comment
from .models import Comment, NewsComment

User = get_user_model()

Expand Down Expand Up @@ -54,3 +54,39 @@ def save(self, commit=True) -> Comment:
if commit:
new.save()
return new


class NewsCommentForm(forms.Form):
content = forms.CharField(widget=forms.Textarea(attrs={"rows": 4}))

def __init__(self, request, news, *args, **kwargs):
super().__init__(*args, **kwargs)
self.request = request
self.news = news

self.helper = FormHelper()
self.helper.form_method = "post"
self.helper.form_class = ""
self.helper.form_show_errors = False
self.helper.form_show_labels = False
self.helper.form_action = reverse(
"comments:news_add", kwargs={"slug": news.slug}
)
self.helper.add_input(Submit("submit", "Add comment"))

def clean_content(self) -> str:
content = self.cleaned_data.get("content")
if len(content) > 2000:
raise ValidationError(
"Your comment must be less than 2000 characters long."
)
return content

def save(self, commit=True) -> Comment:
content = self.cleaned_data.get("content")
new = NewsComment.objects.create(
content=content, news=self.news, author=self.request.user
)
if commit:
new.save()
return new
62 changes: 62 additions & 0 deletions app/comments/migrations/0002_alter_comment_options_newscomment.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
# Generated by Django 4.2.6 on 2023-10-27 02:53

import uuid

import django.db.models.deletion
from django.conf import settings
from django.db import migrations, models


class Migration(migrations.Migration):
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
("core", "0004_alter_news_slug"),
("comments", "0001_initial"),
]

operations = [
migrations.AlterModelOptions(
name="comment",
options={"ordering": ["-added"], "verbose_name_plural": "trip comments"},
),
migrations.CreateModel(
name="NewsComment",
fields=[
(
"id",
models.BigAutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
("content", models.TextField()),
(
"uuid",
models.UUIDField(default=uuid.uuid4, editable=False, unique=True),
),
("added", models.DateTimeField(auto_now_add=True)),
("updated", models.DateTimeField(auto_now=True)),
(
"article",
models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
related_name="comments",
to="core.news",
),
),
(
"author",
models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
to=settings.AUTH_USER_MODEL,
),
),
],
options={
"verbose_name_plural": "news comments",
"ordering": ["-added"],
},
),
]
17 changes: 17 additions & 0 deletions app/comments/migrations/0003_rename_article_newscomment_news.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# Generated by Django 4.2.6 on 2023-10-27 03:10

from django.db import migrations


class Migration(migrations.Migration):
dependencies = [
("comments", "0002_alter_comment_options_newscomment"),
]

operations = [
migrations.RenameField(
model_name="newscomment",
old_name="article",
new_name="news",
),
]
26 changes: 24 additions & 2 deletions app/comments/models.py
Original file line number Diff line number Diff line change
@@ -1,24 +1,46 @@
import uuid

from core.models import News
from django.conf import settings
from django.db import models
from logger.models import Trip


class Comment(models.Model):
class BaseComment(models.Model):
content = models.TextField()
author = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
trip = models.ForeignKey(Trip, on_delete=models.CASCADE, related_name="comments")

uuid = models.UUIDField(unique=True, editable=False, default=uuid.uuid4)
added = models.DateTimeField(auto_now_add=True)
updated = models.DateTimeField(auto_now=True)

class Meta:
abstract = True


class Comment(BaseComment):
trip = models.ForeignKey(Trip, on_delete=models.CASCADE, related_name="comments")

class Meta:
ordering = ["-added"]
verbose_name_plural = "trip comments"

def __str__(self):
return f"Comment by {self.author} on {self.trip}"

def get_absolute_url(self):
return self.trip.get_absolute_url()


class NewsComment(BaseComment):
news = models.ForeignKey(News, on_delete=models.CASCADE, related_name="comments")

class Meta:
ordering = ["-added"]
verbose_name_plural = "news comments"

def __str__(self):
return f"Comment by {self.author} on {self.article.title}"

def get_absolute_url(self):
return self.article.get_absolute_url()
6 changes: 6 additions & 0 deletions app/comments/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,10 @@
path("add/<uuid:uuid>/", views.AddComment.as_view(), name="add"),
path("delete/<uuid:uuid>/", views.DeleteComment.as_view(), name="delete"),
path("htmx/<uuid:uuid>/", views.HTMXTripComment.as_view(), name="htmx_comments"),
path("news/add/<slug:slug>/", views.AddNewsComment.as_view(), name="news_add"),
path(
"news/delete/<uuid:uuid>/",
views.DeleteNewsComment.as_view(),
name="news_delete",
),
]
43 changes: 41 additions & 2 deletions app/comments/views.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from comments.forms import CommentForm
from comments.models import Comment
from comments.forms import CommentForm, NewsCommentForm
from comments.models import Comment, NewsComment
from core.logging import log_trip_action
from core.models import News
from django.contrib import messages
from django.contrib.auth.mixins import LoginRequiredMixin
from django.core.exceptions import PermissionDenied
Expand Down Expand Up @@ -112,3 +113,41 @@ def post(self, request, uuid):
else:
raise PermissionDenied
return redirect(comment.trip.get_absolute_url())


class AddNewsComment(LoginRequiredMixin, View):
def post(self, request, slug):
news = get_object_or_404(News, slug=slug)
form = NewsCommentForm(self.request, news, request.POST)

if form.is_valid():
form.save()
messages.success(
request,
"Your comment has been added.",
)
else:
if form.errors.get("content", None):
for error in form.errors["content"]:
messages.error(request, error)
else:
messages.error(
request,
"There was an error adding your comment. Please try again.",
)

return redirect(news.get_absolute_url())


class DeleteNewsComment(LoginRequiredMixin, View):
def post(self, request, uuid):
comment = get_object_or_404(NewsComment, uuid=uuid)
if comment.author == request.user or request.user.is_superuser:
comment.delete()
messages.success(
request,
"The comment has been deleted.",
)
else:
raise PermissionDenied
return redirect(comment.news.get_absolute_url())
6 changes: 6 additions & 0 deletions app/core/views.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
from comments.forms import NewsCommentForm
from django.contrib.auth import get_user_model
from django.views.generic import DetailView, TemplateView

Expand Down Expand Up @@ -32,6 +33,11 @@ class NewsDetail(DetailView):
template_name = "core/news_detail.html"
context_object_name = "news"

def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context["comment_form"] = NewsCommentForm(self.request, self.object)
return context


class HTTP400(TemplateView):
template_name = "400.html"
Expand Down
10 changes: 5 additions & 5 deletions app/templates/comments/_comments.html
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@
{% load crispy_forms_tags %}
{% load markdownify %}

{% if trip.user.allow_comments %}
{% if trip.comments.count > 0 %}
{% for comment in trip.comments.all %}
{% if comment_obj.user.allow_comments or comment_obj_type == "news" %}
{% if comment_obj.comments.count > 0 %}
{% for comment in comment_obj.comments.all %}
{% if forloop.counter > 1 %}<hr class="my-4">{% endif %}

<div class="m-0 comment-display">
Expand All @@ -23,7 +23,7 @@
</p>
</div>
{% if user.is_authenticated %}
{% if user == comment.author or user == trip.user or user.is_superuser %}
{% if user == comment.author or user == comment_obj.user or user.is_superuser %}
<div class="modal fade" id="deleteComment{{ comment.uuid }}" tabindex="-1">
<div class="modal-dialog">
<div class="modal-content">
Expand All @@ -36,7 +36,7 @@ <h1 class="modal-title fs-5">Delete comment</h1>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button>
<form action="{% url 'comments:delete' comment.uuid %}" method="post">
{% if comment_obj_type == "news" %}<form action="{% url 'comments:news_delete' comment.uuid %}" method="post">{% else %}<form action="{% url 'comments:delete' comment.uuid %}" method="post">{% endif %}
{% csrf_token %}
<button type="submit" class="btn btn-danger">Delete comment</button>
</form>
Expand Down
2 changes: 1 addition & 1 deletion app/templates/comments/_comments_card.html
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
</div>

<div class="card-body">
{% include "comments/_comments.html" %}
{% include "comments/_comments.html" with comment_obj=trip %}
</div>
</div>
{% endif %}
2 changes: 1 addition & 1 deletion app/templates/core/_news_item.html
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
{% load markdownify %}
{% load humanize %}

<div class="mb-5">
<div class="mb-3">
<h4 class="subtitle fs-3 mb-1 pb-1" id="news{{ news.id }}">
<a class="text-decoration-none text-black" href="{{ news.get_absolute_url }}">
{{ news.title }}
Expand Down
14 changes: 13 additions & 1 deletion app/templates/core/news.html
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,19 @@
{% block main %}
<div class="mw-45">
{% for item in news %}
{% include "core/_news_item.html" with news=item %}
<article class="mb-5">
{% include "core/_news_item.html" with news=item %}

<a class="link-primary text-decoration-none" href="{{ item.get_absolute_url }}">
<i class="bi bi-box-arrow-up-right me-1"></i> View article
</a>

<span class="mx-2">&middot;</span>

<a class="link-primary text-decoration-none" href="{{ item.get_absolute_url }}">
<i class="bi bi-chat me-1"></i> {{ item.comments.all|length }} comment{{ item.comments.all|length|pluralize }}
</a>
</article>
{% endfor %}
</div>
{% endblock %}
7 changes: 5 additions & 2 deletions app/templates/core/news_detail.html
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,16 @@
{% load markdownify %}

{% block title %}{{ news.title }}{% endblock %}
{% block display_title %}News{% endblock %}
{% block display_title_container %}{% endblock %}
{% block description %}Information about the latest updates to caves.app.{% endblock %}

{% block main %}
<div class="mw-45">
{% include "core/_news_item.html" %}

<a href="{% url 'core:news' %}" class="btn btn-primary"><i class="bi bi-arrow-left"></i>&nbsp; Back to all news</a>
<h5 class="mb-3 mt-5">Comments</h5>
{% include "comments/_comments.html" with comment_obj=news comment_obj_type="news" %}

<a href="{% url 'core:news' %}" class="btn btn-outline-primary mt-3"><i class="bi bi-arrow-left"></i>&nbsp; Back to all news</a>
</div>
{% endblock %}
2 changes: 1 addition & 1 deletion app/templates/logger/trip_detail.html
Original file line number Diff line number Diff line change
Expand Up @@ -243,6 +243,6 @@ <h5 class="m-0">
</h5>
{% include "logger/_htmx_trip_follow.html" %}
</div>
{% include "comments/_comments.html" %}
{% include "comments/_comments.html" with comment_obj=trip %}
{% endif %}
{% endblock %}

0 comments on commit 2ec6fe5

Please sign in to comment.