Refactorize to enable code sharing for comments
This commit is contained in:
parent
98c517421c
commit
d4a9faef3e
14 changed files with 158 additions and 117 deletions
0
comments/__init__.py
Normal file
0
comments/__init__.py
Normal file
5
comments/admin.py
Normal file
5
comments/admin.py
Normal file
|
@ -0,0 +1,5 @@
|
|||
from django.contrib import admin
|
||||
|
||||
|
||||
class CommentAdmin(admin.ModelAdmin):
|
||||
list_display = ("created_on", "author", "commented_object", "text")
|
5
comments/apps.py
Normal file
5
comments/apps.py
Normal file
|
@ -0,0 +1,5 @@
|
|||
from django.apps import AppConfig
|
||||
|
||||
|
||||
class CommentsConfig(AppConfig):
|
||||
name = 'comments'
|
0
comments/migrations/__init__.py
Normal file
0
comments/migrations/__init__.py
Normal file
23
comments/models.py
Normal file
23
comments/models.py
Normal file
|
@ -0,0 +1,23 @@
|
|||
from django.db import models
|
||||
from accounts.models import User
|
||||
|
||||
|
||||
class AbstractComment(models.Model):
|
||||
commented_object = None # Fill this with a foreign key in subclasses
|
||||
author = models.ForeignKey(
|
||||
User, on_delete=models.CASCADE, verbose_name="auteur·ice"
|
||||
)
|
||||
text = models.TextField(verbose_name="texte")
|
||||
created_on = models.DateTimeField(
|
||||
auto_now_add=True, verbose_name="date de publication"
|
||||
)
|
||||
modified_on = models.DateTimeField(
|
||||
auto_now=True, verbose_name="date de modification"
|
||||
)
|
||||
|
||||
class Meta:
|
||||
abstract = True
|
||||
ordering = ["created_on"]
|
||||
|
||||
def __str__(self):
|
||||
return "({}) {}: {}".format(self.commented_object, self.author, self.text)
|
39
comments/templates/comments.html
Normal file
39
comments/templates/comments.html
Normal file
|
@ -0,0 +1,39 @@
|
|||
{% for comment in comments %}
|
||||
{% if comment == edited_comment %}
|
||||
<form id="edited_comment" class="comment" method="post">
|
||||
<div class="meta">
|
||||
<span class="author">{{ comment.author }}</span>
|
||||
<span class="date">posté le {{ comment.created_on|date }} à {{ comment.created_on|time }}</span>
|
||||
<a href="{{ comment.commented_object.get_absolute_url }}" title="Annuler la modification"><i class="fa fa-ban" aria-hidden="true"></i></a>
|
||||
</div>
|
||||
|
||||
{% csrf_token %}
|
||||
<textarea name="comment_text" required>{{ comment.text }}</textarea>
|
||||
<button type="submit"><i class="fa fa-pencil" aria-hidden="true"></i> Modifier mon commentaire</button>
|
||||
</form>
|
||||
{% else %}
|
||||
<div class="comment">
|
||||
<div class="meta">
|
||||
<span class="author">{{ comment.author }}</span>
|
||||
<span class="date">posté le {{ comment.created_on|date }} à {{ comment.created_on|time }}{% if comment.created_on|date:"YmdHi" != comment.modified_on|date:"YmdHi" %}, dernière modification le {{ comment.modified_on|date }} à {{ comment.modified_on|time }}{% endif %}</span>
|
||||
{% if comment.author == request.user %}
|
||||
<a href="{{ comment.get_modification_url }}#edited_comment" title="Éditer mon commentaire"><i class="fa fa-pencil" aria-hidden="true"></i></a>
|
||||
{% endif %}
|
||||
</div>
|
||||
{{ comment.text|linebreaks }}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% empty %}
|
||||
<p>(Aucun commentaire sur ce jeu)</p>
|
||||
{% endfor %}
|
||||
{% if not edited_comment %}
|
||||
{% if request.user.is_authenticated %}
|
||||
<form class="comment" method="post" action="{{ add_comment_url }}">
|
||||
{% csrf_token %}
|
||||
<textarea name="comment_text" placeholder="Ajouter un commentaire" required></textarea>
|
||||
<button type="submit"><i class="fa fa-paper-plane" aria-hidden="true"></i> Envoyer le commentaire</button>
|
||||
</form>
|
||||
{% else %}
|
||||
<p><a href="{% url "accounts:login" %}?next={{ request.get_full_path }}">Connectez-vous</a> pour ajouter un commentaire.</p>
|
||||
{% endif %}
|
||||
{% endif %}
|
3
comments/tests.py
Normal file
3
comments/tests.py
Normal file
|
@ -0,0 +1,3 @@
|
|||
from django.test import TestCase
|
||||
|
||||
# Create your tests here.
|
59
comments/views.py
Normal file
59
comments/views.py
Normal file
|
@ -0,0 +1,59 @@
|
|||
from django.views.generic import TemplateView, RedirectView
|
||||
from django.views.generic.detail import SingleObjectMixin
|
||||
from django.contrib.auth.mixins import LoginRequiredMixin
|
||||
from django.contrib import messages
|
||||
from django.http import Http404
|
||||
from django.core.exceptions import PermissionDenied
|
||||
from django.shortcuts import redirect, get_object_or_404
|
||||
|
||||
|
||||
class AddCommentView(LoginRequiredMixin, SingleObjectMixin, RedirectView):
|
||||
permanent = False
|
||||
|
||||
def get_redirect_url(self, *args, **kwargs):
|
||||
req_dict = self.request.POST
|
||||
if "comment_text" in req_dict:
|
||||
comment_text = req_dict["comment_text"]
|
||||
|
||||
comment = self.comment_model(
|
||||
commented_object=self.get_object(),
|
||||
author=self.request.user,
|
||||
text=comment_text,
|
||||
)
|
||||
comment.save()
|
||||
messages.success(self.request, "Commentaire ajouté")
|
||||
else:
|
||||
messages.error(
|
||||
self.request, "Pas de texte pour le commentaire dans la requête"
|
||||
)
|
||||
|
||||
return super().get_redirect_url(*args, **kwargs)
|
||||
|
||||
|
||||
class ModifyCommentView(LoginRequiredMixin, SingleObjectMixin, TemplateView):
|
||||
def dispatch(self, *args, **kwargs):
|
||||
comment_id = kwargs.pop("comment_id")
|
||||
self.object = self.get_object()
|
||||
self.comment = get_object_or_404(self.comment_model, id=comment_id)
|
||||
if self.comment.commented_object != self.object:
|
||||
raise Http404()
|
||||
if self.comment.author != self.request.user:
|
||||
raise PermissionDenied()
|
||||
return super().dispatch(*args, **kwargs)
|
||||
|
||||
def post(self, *args, **kwargs):
|
||||
req_dict = self.request.POST
|
||||
if "comment_text" in req_dict:
|
||||
self.comment.text = req_dict["comment_text"]
|
||||
self.comment.save()
|
||||
messages.success(self.request, "Commentaire modifié")
|
||||
else:
|
||||
messages.error(
|
||||
self.request, "Pas de texte pour le commentaire dans la requête"
|
||||
)
|
||||
return redirect(self.success_pattern_name, **kwargs)
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super().get_context_data(**kwargs)
|
||||
context["edited_comment"] = self.comment
|
||||
return context
|
|
@ -25,12 +25,13 @@ INSTALLED_APPS = [
|
|||
"django.contrib.sessions",
|
||||
"django.contrib.messages",
|
||||
"django.contrib.staticfiles",
|
||||
"django_cas_ng",
|
||||
"markdownx",
|
||||
"haystack",
|
||||
"website",
|
||||
"inventory",
|
||||
"django_cas_ng",
|
||||
"accounts",
|
||||
"comments",
|
||||
"inventory",
|
||||
]
|
||||
|
||||
MIDDLEWARE = [
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
from django.contrib import admin
|
||||
from .models import Category, Tag, Game, GameComment
|
||||
from comments.admin import CommentAdmin
|
||||
|
||||
admin.site.register(Category)
|
||||
admin.site.register(Tag)
|
||||
admin.site.register(Game)
|
||||
admin.site.register(GameComment)
|
||||
admin.site.register(GameComment, CommentAdmin)
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
# Generated by Django 3.1.2 on 2020-12-21 01:20
|
||||
# Generated by Django 3.1.2 on 2020-12-27 17:01
|
||||
|
||||
import autoslug.fields
|
||||
from django.conf import settings
|
||||
|
@ -70,7 +70,7 @@ class Migration(migrations.Migration):
|
|||
('created_on', models.DateTimeField(auto_now_add=True, verbose_name='date de publication')),
|
||||
('modified_on', models.DateTimeField(auto_now=True, verbose_name='date de modification')),
|
||||
('author', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL, verbose_name='auteur·ice')),
|
||||
('game', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='comments', to='inventory.game', verbose_name='jeu')),
|
||||
('commented_object', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='comments', to='inventory.game', verbose_name='jeu')),
|
||||
],
|
||||
options={
|
||||
'verbose_name': 'commentaire sur un jeu',
|
||||
|
|
|
@ -2,7 +2,7 @@ from django.db import models
|
|||
from django.urls import reverse
|
||||
from django.core.exceptions import ValidationError
|
||||
from autoslug import AutoSlugField
|
||||
from accounts.models import User
|
||||
from comments.models import AbstractComment
|
||||
|
||||
|
||||
class Category(models.Model):
|
||||
|
@ -95,25 +95,17 @@ class Game(models.Model):
|
|||
return reverse("inventory:game", args=(self.slug,))
|
||||
|
||||
|
||||
class GameComment(models.Model):
|
||||
game = models.ForeignKey(
|
||||
class GameComment(AbstractComment):
|
||||
commented_object = models.ForeignKey(
|
||||
Game, on_delete=models.CASCADE, related_name="comments", verbose_name="jeu"
|
||||
)
|
||||
author = models.ForeignKey(
|
||||
User, on_delete=models.CASCADE, verbose_name="auteur·ice"
|
||||
)
|
||||
text = models.TextField(verbose_name="texte")
|
||||
created_on = models.DateTimeField(
|
||||
auto_now_add=True, verbose_name="date de publication"
|
||||
)
|
||||
modified_on = models.DateTimeField(
|
||||
auto_now=True, verbose_name="date de modification"
|
||||
)
|
||||
|
||||
class Meta:
|
||||
ordering = ["created_on"]
|
||||
verbose_name = "commentaire sur un jeu"
|
||||
verbose_name_plural = "commentaires sur des jeux"
|
||||
|
||||
def __str__(self):
|
||||
return "({}) {}: {}".format(self.game, self.author, self.text)
|
||||
def get_modification_url(self):
|
||||
return reverse(
|
||||
"inventory:modify_game_comment", args=(self.commented_object.slug, self.id)
|
||||
)
|
||||
|
|
|
@ -38,43 +38,6 @@
|
|||
{% endif %}
|
||||
|
||||
<h2>Commentaires et propositions de variantes</h2>
|
||||
{% for comment in game.comments.all %}
|
||||
{% if comment == edited_comment %}
|
||||
<form id="edited_comment" class="comment" method="post">
|
||||
<div class="meta">
|
||||
<span class="author">{{ comment.author }}</span>
|
||||
<span class="date">posté le {{ comment.created_on|date }} à {{ comment.created_on|time }}</span>
|
||||
<a href="{% url "inventory:game" game.slug %}" title="Annuler la modification"><i class="fa fa-ban" aria-hidden="true"></i></a>
|
||||
</div>
|
||||
|
||||
{% csrf_token %}
|
||||
<textarea name="comment_text" required>{{ comment.text }}</textarea>
|
||||
<button type="submit"><i class="fa fa-pencil" aria-hidden="true"></i> Modifier mon commentaire</button>
|
||||
</form>
|
||||
{% else %}
|
||||
<div class="comment">
|
||||
<div class="meta">
|
||||
<span class="author">{{ comment.author }}</span>
|
||||
<span class="date">posté le {{ comment.created_on|date }} à {{ comment.created_on|time }}{% if comment.created_on|date:"YmdHi" != comment.modified_on|date:"YmdHi" %}, dernière modification le {{ comment.modified_on|date }} à {{ comment.modified_on|time }}{% endif %}</span>
|
||||
{% if comment.author == request.user %}
|
||||
<a href="{% url "inventory:modify_game_comment" game.slug comment.id %}#edited_comment" title="Éditer mon commentaire"><i class="fa fa-pencil" aria-hidden="true"></i></a>
|
||||
{% endif %}
|
||||
</div>
|
||||
{{ comment.text|linebreaks }}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% empty %}
|
||||
(Aucun commentaire sur ce jeu)
|
||||
{% endfor %}
|
||||
{% if not edited_comment %}
|
||||
{% if request.user.is_authenticated %}
|
||||
<form class="comment" method="post" action="{% url "inventory:add_game_comment" game.slug %}">
|
||||
{% csrf_token %}
|
||||
<textarea name="comment_text" placeholder="Ajouter un commentaire à propos de {{ game.title }}" required></textarea>
|
||||
<button type="submit"><i class="fa fa-paper-plane" aria-hidden="true"></i> Envoyer le commentaire</button>
|
||||
</form>
|
||||
{% else %}
|
||||
<a href="{% url "accounts:login" %}?next={{ request.get_full_path }}">Connectez-vous</a> pour ajouter un commentaire.
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% url "inventory:add_game_comment" game.slug as add_comment_url %}
|
||||
{% include "comments.html" with comments=game.comments.all %}
|
||||
{% endblock %}
|
||||
|
|
|
@ -1,19 +1,8 @@
|
|||
from django.views.generic import (
|
||||
TemplateView,
|
||||
ListView,
|
||||
DetailView,
|
||||
RedirectView,
|
||||
)
|
||||
from django.views.generic.detail import SingleObjectMixin
|
||||
from django.contrib.auth.mixins import LoginRequiredMixin
|
||||
from django.urls import reverse
|
||||
from django.shortcuts import redirect, get_object_or_404
|
||||
from django.contrib import messages
|
||||
from django.http import Http404
|
||||
from django.core.exceptions import PermissionDenied
|
||||
from django.views.generic import TemplateView, ListView, DetailView
|
||||
from haystack.generic_views import SearchView
|
||||
from haystack.forms import SearchForm
|
||||
from haystack.query import SearchQuerySet
|
||||
from comments.views import AddCommentView, ModifyCommentView
|
||||
from .models import Category, Tag, Game, GameComment
|
||||
|
||||
|
||||
|
@ -59,53 +48,14 @@ class InventorySearchView(SearchView):
|
|||
return SearchQuerySet().models(Category, Tag, Game)
|
||||
|
||||
|
||||
class AddGameCommentView(LoginRequiredMixin, SingleObjectMixin, RedirectView):
|
||||
class AddGameCommentView(AddCommentView):
|
||||
model = Game
|
||||
permanent = False
|
||||
|
||||
def get_redirect_url(self, *args, **kwargs):
|
||||
req_dict = self.request.POST
|
||||
if "comment_text" in req_dict:
|
||||
comment_text = req_dict["comment_text"]
|
||||
|
||||
game = self.get_object()
|
||||
game.comments.create(author=self.request.user, text=comment_text)
|
||||
messages.success(self.request, "Commentaire ajouté")
|
||||
else:
|
||||
messages.error(
|
||||
self.request, "Pas de texte pour le commentaire dans la requête"
|
||||
)
|
||||
|
||||
return reverse("inventory:game", kwargs=kwargs)
|
||||
comment_model = GameComment
|
||||
pattern_name = "inventory:game"
|
||||
|
||||
|
||||
class ModifyGameCommentView(LoginRequiredMixin, SingleObjectMixin, TemplateView):
|
||||
class ModifyGameCommentView(ModifyCommentView):
|
||||
model = Game
|
||||
comment_model = GameComment
|
||||
template_name = "inventory/game.html"
|
||||
|
||||
def dispatch(self, *args, **kwargs):
|
||||
comment_id = kwargs["comment_id"]
|
||||
self.object = self.get_object()
|
||||
self.comment = get_object_or_404(GameComment, id=comment_id)
|
||||
if self.comment.game != self.object:
|
||||
raise Http404()
|
||||
if self.comment.author != self.request.user:
|
||||
raise PermissionDenied()
|
||||
return super().dispatch(*args, **kwargs)
|
||||
|
||||
def post(self, *args, **kwargs):
|
||||
req_dict = self.request.POST
|
||||
if "comment_text" in req_dict:
|
||||
self.comment.text = req_dict["comment_text"]
|
||||
self.comment.save()
|
||||
messages.success(self.request, "Commentaire modifié")
|
||||
else:
|
||||
messages.error(
|
||||
self.request, "Pas de texte pour le commentaire dans la requête"
|
||||
)
|
||||
return redirect("inventory:game", slug=kwargs["slug"])
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super().get_context_data(**kwargs)
|
||||
context["edited_comment"] = self.comment
|
||||
return context
|
||||
success_pattern_name = "inventory:game"
|
||||
|
|
Loading…
Add table
Reference in a new issue