From 2688a92a0a26b424e1e123ad3f9d5847cec039c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=94=D0=BC=D0=B8=D1=82=D1=80=D0=B8=D0=B9?= Date: Tue, 12 Apr 2022 21:20:39 +0300 Subject: [PATCH] =?UTF-8?q?=D0=94=D0=BE=D0=B4=D0=B5=D0=BB=D0=B0=D0=BB=20?= =?UTF-8?q?=D0=BA=D0=BE=D0=BC=D0=BC=D0=B5=D0=BD=D1=82=D0=B0=D1=80=D0=B8?= =?UTF-8?q?=D0=B8=20=D0=B8=20"=D1=80=D0=B5=D0=B3=D0=B8=D1=81=D1=82=D1=80?= =?UTF-8?q?=D0=B0=D1=86=D0=B8=D1=8E"?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- blog/comments/admin.py | 6 +- blog/comments/migrations/0001_initial.py | 15 +++-- .../migrations/0002_alter_comment_reply.py | 18 ------ blog/comments/models.py | 57 ++++++++++++++---- blog/comments/views.py | 54 ++++++++++++++--- blog/db.sqlite3 | Bin 139264 -> 167936 bytes blog/posts/templates/posts/post.html | 46 ++++++++++---- blog/posts/views.py | 7 ++- blog/static/css/main.css | 14 +++++ blog/static/js/comment_reply.js | 29 +++++++++ blog/templates/base.html | 1 + 11 files changed, 190 insertions(+), 57 deletions(-) delete mode 100644 blog/comments/migrations/0002_alter_comment_reply.py create mode 100644 blog/static/css/main.css create mode 100644 blog/static/js/comment_reply.js diff --git a/blog/comments/admin.py b/blog/comments/admin.py index 8c38f3f..f769d34 100644 --- a/blog/comments/admin.py +++ b/blog/comments/admin.py @@ -1,3 +1,7 @@ from django.contrib import admin +from .models import Comment -# Register your models here. + +@admin.register(Comment) +class CommentAdmin(admin.ModelAdmin): + pass diff --git a/blog/comments/migrations/0001_initial.py b/blog/comments/migrations/0001_initial.py index 568a138..c8ed12b 100644 --- a/blog/comments/migrations/0001_initial.py +++ b/blog/comments/migrations/0001_initial.py @@ -1,7 +1,8 @@ -# Generated by Django 4.0.3 on 2022-04-09 12:38 +# Generated by Django 4.0.3 on 2022-04-12 13:43 from django.db import migrations, models import django.db.models.deletion +import django.utils.timezone class Migration(migrations.Migration): @@ -18,19 +19,21 @@ class Migration(migrations.Migration): fields=[ ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('author_name', models.CharField(max_length=60, verbose_name='Имя автора')), - ('author_secret_hash', models.CharField(max_length=256, verbose_name='Хеш секрета')), + ('author_secret_hash', models.CharField(blank=True, max_length=256, null=True, verbose_name='Хеш секрета')), ], + options={ + 'unique_together': {('author_name', 'author_secret_hash')}, + }, ), migrations.CreateModel( name='Comment', fields=[ ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('author_name', models.CharField(max_length=60, verbose_name='имя автора')), - ('author_secret', models.CharField(blank=True, max_length=128, verbose_name='секретная строка')), - ('reply', models.IntegerField(blank=True)), ('comment_text', models.TextField()), - ('date', models.DateTimeField()), + ('date', models.DateTimeField(default=django.utils.timezone.now)), + ('author', models.ForeignKey(default='аноним', on_delete=django.db.models.deletion.CASCADE, to='comments.commentauthor')), ('post', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='posts.post')), + ('reply', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='comments.comment')), ], ), ] diff --git a/blog/comments/migrations/0002_alter_comment_reply.py b/blog/comments/migrations/0002_alter_comment_reply.py deleted file mode 100644 index cc7f019..0000000 --- a/blog/comments/migrations/0002_alter_comment_reply.py +++ /dev/null @@ -1,18 +0,0 @@ -# Generated by Django 4.0.3 on 2022-04-09 13:01 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('comments', '0001_initial'), - ] - - operations = [ - migrations.AlterField( - model_name='comment', - name='reply', - field=models.IntegerField(null=True), - ), - ] diff --git a/blog/comments/models.py b/blog/comments/models.py index b3912fa..d067d97 100644 --- a/blog/comments/models.py +++ b/blog/comments/models.py @@ -1,20 +1,8 @@ from django.db import models from posts.models import Post -from datetime import datetime from django.utils import timezone -class Comment(models.Model): - """Класс для комента.""" - - post = models.ForeignKey(Post, on_delete=models.CASCADE) - author_name = models.CharField("имя автора", max_length=60) - author_secret = models.CharField("секретная строка", max_length=128, blank=True) - reply = models.ForeignKey("self", on_delete=models.SET_NULL, blank=True, null=True) - comment_text = models.TextField() - date = models.DateTimeField(default=timezone.now) - - class CommentAuthor(models.Model): """Валидация автора коммента. @@ -25,4 +13,47 @@ class CommentAuthor(models.Model): """ author_name = models.CharField("Имя автора", max_length=60) - author_secret_hash = models.CharField("Хеш секрета", max_length=256) + author_secret_hash = models.CharField( + "Хеш секрета", max_length=256, blank=True, null=True + ) + + def __str__(self): + return self.author_name + + class Meta: + # сделать сочетание полей уникальным + unique_together = (("author_name"),) + + def is_valid(self) -> bool: + if self.author_name and self.author_secret_hash: + return True + + +def get_anonym_id() -> int: + # тут бы еще проверку на существование такого пользователя. Если + # его нет - создать + obj, result = CommentAuthor.objects.get_or_create(author_name="Anonym") + return obj.id + + +class Comment(models.Model): + """Класс для комента.""" + + post = models.ForeignKey(Post, on_delete=models.CASCADE) + author = models.ForeignKey( + CommentAuthor, on_delete=models.CASCADE, default=get_anonym_id + ) + nickname = models.CharField("имя автора", max_length=60, blank=True, null=True) + reply = models.ForeignKey("self", on_delete=models.SET_NULL, blank=True, null=True) + comment_text = models.TextField() + date = models.DateTimeField(default=timezone.now) + + def is_anonym(self) -> bool: + if self.author.id == get_anonym_id(): + return True + + else: + return False + + def __str__(self): + return f"{self.author_name}: {self.comment_text[:100]}" diff --git a/blog/comments/views.py b/blog/comments/views.py index 6c8caea..0c8a2b2 100644 --- a/blog/comments/views.py +++ b/blog/comments/views.py @@ -1,13 +1,17 @@ from django.shortcuts import render, reverse from posts.models import Post from django.http import Http404, HttpResponseRedirect -from .models import Comment +from .models import Comment, CommentAuthor from datetime import datetime from django.core.exceptions import ObjectDoesNotExist +from django.db import IntegrityError +import hashlib + +from typing import Union def leave_comment(request, post_id): - parent: Comment + parent: Union[Comment, None] try: post = Post.objects.get(id=post_id) @@ -30,10 +34,46 @@ def leave_comment(request, post_id): except ObjectDoesNotExist: parent = None - post.comment_set.create( - author_name=request.POST["name"], - comment_text=request.POST["text"], - reply=parent, - ) + # обработка секрета Перед записью в базу, нужно извлечь записи по + # нику. Где поле author_secret_hash не null, нужно вычислить и + # сравнить хэши; если хеши валидные то пишем в базу (еще раз уник не запишется); + + # если не передан секрет, то пользователь Anonym + # если секрет не совпал, то польозхватель Anonym + + author = get_or_create_author(request.POST["name"], request.POST["secret"]) + nickname = request.POST["name"] + + if not author: + post.comment_set.create( + nickname=nickname, + comment_text=request.POST["text"], + reply=parent, + ) + else: + post.comment_set.create( + author=author, + nickname=nickname, + comment_text=request.POST["text"], + reply=parent, + ) return HttpResponseRedirect(reverse("posts:detail", args=(post.id,))) + + +def get_or_create_author(name: str, secret: str) -> Union[CommentAuthor, None]: + + if secret == "": + return None + + hash = hashlib.md5(secret.encode("utf-8")).hexdigest() + + try: + author, result = CommentAuthor.objects.get_or_create( + author_name=name, author_secret_hash=hash + ) + except IntegrityError: + # если имя/хеш не совпадают, то игнорируем такого автора и отображаем ником + author = None + + return author diff --git a/blog/db.sqlite3 b/blog/db.sqlite3 index 31134cd89c266685c2890102f70b2635cc54c170..61d65d256058b05eddef6beeaa6834f433730800 100644 GIT binary patch literal 167936 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 literal 139264 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Опубликован: {{ post.pub_date | date:'Y-m-d, H:i' }}
{{ post.text }}
-
-

Комменты

+
+

Комментарии ({{ comments_count }})

{% for comment in comments %}
{% if comment.reply %} -

[{{comment.id}}] {{ comment.author_name }} отвечает {{ comment.reply.author_name }}:

+

{% if comment.is_anonym %} + {{ comment.nickname }} + {% else %} + {{ comment.author }} + {% endif %} + отвечает {{ comment.reply.author_name }}:

{{ comment.reply.comment_text }}
{% else %} -

[{{comment.id}}] {{ comment.author_name }} говорит:

+

+ {% if comment.is_anonym %} + {{ comment.nickname }} + {% else %} + {{ comment.author }} + {% endif %} + говорит:

{% endif %} +

{{ comment.comment_text }}

- Ответить + Ответить
{% endfor %} -
+ {% csrf_token %} +
- +
- +
-
- +
+ + + +
- +
@@ -63,6 +83,10 @@ + + + + {% endautoescape %} {% endblock %} diff --git a/blog/posts/views.py b/blog/posts/views.py index de993e5..42702c5 100644 --- a/blog/posts/views.py +++ b/blog/posts/views.py @@ -18,4 +18,9 @@ def detail(request, post_id): # вынести отсюда все. Также надо обработать текст поста тут. post = get_object_or_404(Post, pk=post_id) comments = post.comment_set.all() - return render(request, "posts/post.html", {"post": post, "comments": comments}) + comments_count = comments.count() + return render( + request, + "posts/post.html", + {"post": post, "comments": comments, "comments_count": comments_count}, + ) diff --git a/blog/static/css/main.css b/blog/static/css/main.css new file mode 100644 index 0000000..3d90349 --- /dev/null +++ b/blog/static/css/main.css @@ -0,0 +1,14 @@ +.is-red { + color: #eb2c65; +} + +.is-green { + color: #3846BA; + text-color: #3846BA; +} + +.is-auth-user { + color: #3FBE7B; + text-color: #3FBE7B; + +} diff --git a/blog/static/js/comment_reply.js b/blog/static/js/comment_reply.js new file mode 100644 index 0000000..f5300d2 --- /dev/null +++ b/blog/static/js/comment_reply.js @@ -0,0 +1,29 @@ +// Получить элемент e +function reply(el) { + + document.getElementById("reply_to").value = el; + + repl_name = document.getElementById(el + "_author_name").innerText + console.log(repl_name); + + document.getElementById("reply_to_name").innerText = repl_name; + + document.getElementById("comment_text_form").focus(); + + // показываем лейбл для ответа + document.getElementById("reply_to_name_field").style.display = "block"; + // скрываем лейбл для простого комментария + document.getElementById("pure_comment_label").style.display = "none"; +} + +function abort_reply() { + console.log("Галя, отмена!") + document.getElementById("reply_to").value = ''; + + // показываем лейбл для ответа + document.getElementById("reply_to_name_field").style.display = "none"; + // скрываем лейбл для простого комментария + document.getElementById("pure_comment_label").style.display = "block"; + + +} diff --git a/blog/templates/base.html b/blog/templates/base.html index 4506b62..b698cfd 100644 --- a/blog/templates/base.html +++ b/blog/templates/base.html @@ -8,6 +8,7 @@ + {% block content %}{% endblock %}