From 6c40c0414bfd70400c1365ca00d04b406a5fb119 Mon Sep 17 00:00:00 2001 From: vas3k Date: Mon, 29 Jul 2024 17:30:47 +0200 Subject: [PATCH] feat: profile publicity levels --- frontend/html/comments/list.html | 4 +- frontend/html/comments/types/private.html | 5 ++ frontend/html/comments/types/reply.html | 4 +- frontend/html/posts/show/post.html | 4 +- frontend/html/users/edit/profile.html | 75 ++++++++++++++------- frontend/static/css/components/comments.css | 2 +- users/forms/profile.py | 20 ++++-- users/migrations/0030_auto_20240729_1343.py | 25 +++++++ users/models/user.py | 17 ++++- 9 files changed, 120 insertions(+), 36 deletions(-) create mode 100644 frontend/html/comments/types/private.html create mode 100644 users/migrations/0030_auto_20240729_1343.py diff --git a/frontend/html/comments/list.html b/frontend/html/comments/list.html index f741eeaae..344ee6bd3 100644 --- a/frontend/html/comments/list.html +++ b/frontend/html/comments/list.html @@ -1,6 +1,8 @@ {% load comments %} {% for tree in comments|comment_tree %} - {% if tree.comment.author_id in muted_user_ids %} + {% if not request.me and tree.comment.author.profile_publicity_level == "private" %} + {% include "comments/types/private.html" with comment=tree.comment replies=tree.replies %} + {% elif tree.comment.author_id in muted_user_ids %} {% include "comments/types/muted.html" with comment=tree.comment replies=tree.replies %} {% elif tree.comment.is_pinned %} {% include "comments/types/bold.html" with comment=tree.comment replies=tree.replies %} diff --git a/frontend/html/comments/types/private.html b/frontend/html/comments/types/private.html new file mode 100644 index 000000000..347b28579 --- /dev/null +++ b/frontend/html/comments/types/private.html @@ -0,0 +1,5 @@ +
+
+ 🕵️ Юзер скрыл свои комментарии от публичного просмотра... +
+
diff --git a/frontend/html/comments/types/reply.html b/frontend/html/comments/types/reply.html index 4fee6b068..0b7ac319d 100644 --- a/frontend/html/comments/types/reply.html +++ b/frontend/html/comments/types/reply.html @@ -2,7 +2,9 @@ {% load posts %} {% load comments %} -{% if comment.author_id in muted_user_ids %} +{% if not request.me and comment.author.profile_publicity_level == "private" %} + {% include "comments/types/private.html" with comment=comment replies=replies %} +{% elif comment.author_id in muted_user_ids %} {% include "comments/types/muted.html" with comment=comment replies=replies %} {% else %}
diff --git a/frontend/html/posts/show/post.html b/frontend/html/posts/show/post.html index 852073e43..c18f86af2 100644 --- a/frontend/html/posts/show/post.html +++ b/frontend/html/posts/show/post.html @@ -100,7 +100,9 @@

{% endif %}
- {% include "users/widgets/card.html" with user=post.author %} + {% if request.me or post.author.profile_publicity_level != "private" %} + {% include "users/widgets/card.html" with user=post.author %} + {% endif %} {% if post.coauthors %} {% for coauthor in post.coauthors_with_details %} diff --git a/frontend/html/users/edit/profile.html b/frontend/html/users/edit/profile.html index c3bda393c..e4e03aef0 100644 --- a/frontend/html/users/edit/profile.html +++ b/frontend/html/users/edit/profile.html @@ -85,7 +85,7 @@

- +
@@ -93,34 +93,63 @@
🥷 Публичность профиля
-
- {% if form.is_profile_public.errors %} - {{ form.is_profile_public.errors }} - {% endif %} +
+

+ Эта настройка влияет только на то, как видят вас люди, не зарегистрированные в Клубе. Для членов Клуба ваш профиль, интро и контакты всегда доступны. +

- {% if user.is_profile_public %} -

+

+ {% if user.profile_publicity_level == 'public' %} Сейчас ваш профиль ОТКРЫТ для большого интернета по ссылке: {{ settings.APP_HOST }}{% url "profile" user.slug %} -

-

- Его могут индексировать поисковики и видеть люди без регистрации в Клубе. Можете посмотреть как он выглядит со стороны через инкогнито-мод в вашем браузере. -

- {% else %} -

- Сейчас ваш профиль ЗАКРЫТ для большого интернета. Его могут просматривать только члены Клуба. -

-

- Вы можете сделать его видимым наружу. Комментарии при этом останутся скрытыми, но ваши контакты, интро, посты и награды будут видны всем. -

- {% endif %} + {% else %} + Сейчас ваш профиль СКРЫТ от большого интернета. + {% endif %} + + Ваши комментарии в публичных постах {% if user.profile_publicity_level == 'private' %}НЕ ВИДНЫ{% else %}ВИДНЫ{% endif %}. +

+
- {% if user.is_profile_public %} - - {% else %} - +
+ {% if form.profile_publicity_level.errors %} + {{ form.profile_publicity_level.errors }} {% endif %} + +
+
+
+ {{ form.profile_publicity_level.0.tag }} + +
+
+ {{ form.profile_publicity_level.1.tag }} + +
+
+ {{ form.profile_publicity_level.2.tag }} + +
+
+
+ +

+ ⚠️ Приватность профиля не означает, что ваши данные не смогут украсть злые люди. Эта опция лишь усложняет жизнь ботам, но вас всё так же могут спалить в комментариях другие. +

+ +
diff --git a/frontend/static/css/components/comments.css b/frontend/static/css/components/comments.css index 43255ff83..0c092bbc2 100644 --- a/frontend/static/css/components/comments.css +++ b/frontend/static/css/components/comments.css @@ -383,7 +383,7 @@ } .comment-body-muted { - font-size: 120%; + font-size: 110%; opacity: 0.5; padding-bottom: 20px; } diff --git a/users/forms/profile.py b/users/forms/profile.py index 03e4bd736..5ed05bdae 100644 --- a/users/forms/profile.py +++ b/users/forms/profile.py @@ -40,8 +40,11 @@ class ProfileEditForm(ModelForm): required=True, max_length=128 ) - is_profile_public = forms.BooleanField( - label="Сделать мой профиль публичным", + profile_publicity_level = forms.ChoiceField( + label="Уровень публичности профиля", + choices=User.PUBLICITY_LEVELS, + initial=User.PUBLICITY_LEVEL_NORMAL, + widget=forms.RadioSelect(), required=False, ) @@ -54,16 +57,19 @@ class Meta: "city", "country", "bio", - "is_profile_public", + "profile_publicity_level", ] - def clean_is_profile_public(self): - new_value = self.cleaned_data["is_profile_public"] - old_value = self.instance.is_profile_public + def clean_profile_publicity_level(self): + new_value = self.cleaned_data["profile_publicity_level"] + old_value = self.instance.profile_publicity_level # update intro post visibility settings if new_value != old_value: - Post.objects.filter(author=self.instance, type=Post.TYPE_INTRO).update(is_public=new_value) + if new_value == User.PUBLICITY_LEVEL_PUBLIC: + Post.objects.filter(author=self.instance, type=Post.TYPE_INTRO).update(is_public=True) + else: + Post.objects.filter(author=self.instance, type=Post.TYPE_INTRO).update(is_public=False) return new_value diff --git a/users/migrations/0030_auto_20240729_1343.py b/users/migrations/0030_auto_20240729_1343.py new file mode 100644 index 000000000..9bff89987 --- /dev/null +++ b/users/migrations/0030_auto_20240729_1343.py @@ -0,0 +1,25 @@ +# Generated by Django 3.2.13 on 2024-07-29 13:43 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('users', '0029_auto_20240613_1242'), + ] + + operations = [ + migrations.AddField( + model_name='user', + name='profile_publicity_level', + field=models.CharField(choices=[('private', 'Параноик'), ('normal', 'Обычный'), ('public', 'Публичный')], default='normal', max_length=16), + ), + migrations.RunSQL( + "update users set profile_publicity_level = 'public' where is_profile_public = true;" + ), + migrations.RemoveField( + model_name='user', + name='is_profile_public', + ), + ] diff --git a/users/models/user.py b/users/models/user.py index 0b4606ae5..81bcf0e9c 100644 --- a/users/models/user.py +++ b/users/models/user.py @@ -43,6 +43,15 @@ class User(models.Model, ModelDiffMixin): (ROLE_GOD, "Бог"), ] + PUBLICITY_LEVEL_PRIVATE = "private" + PUBLICITY_LEVEL_NORMAL = "normal" + PUBLICITY_LEVEL_PUBLIC = "public" + PUBLICITY_LEVELS = [ + (PUBLICITY_LEVEL_PRIVATE, "Параноик"), + (PUBLICITY_LEVEL_NORMAL, "Обычный"), + (PUBLICITY_LEVEL_PUBLIC, "Публичный"), + ] + MODERATION_STATUS_INTRO = "intro" MODERATION_STATUS_ON_REVIEW = "on_review" MODERATION_STATUS_REJECTED = "rejected" @@ -99,7 +108,6 @@ class User(models.Model, ModelDiffMixin): stripe_id = models.CharField(max_length=128, null=True) - is_profile_public = models.BooleanField(default=False) is_email_verified = models.BooleanField(default=False) is_email_unsubscribed = models.BooleanField(default=False) is_banned_until = models.DateTimeField(null=True) @@ -110,6 +118,11 @@ class User(models.Model, ModelDiffMixin): db_index=True ) + profile_publicity_level = models.CharField( + max_length=16, choices=PUBLICITY_LEVELS, + default=PUBLICITY_LEVEL_NORMAL, null=False + ) + roles = ArrayField(models.CharField(max_length=32, choices=ROLES), default=list, null=False) deleted_at = models.DateTimeField(null=True) @@ -176,7 +189,7 @@ def get_avatar(self): return self.avatar or settings.DEFAULT_AVATAR def can_view(self, user): - return user or self.is_profile_public + return user or self.profile_publicity_level == self.PUBLICITY_LEVEL_PUBLIC @property def is_banned(self):