Skip to content

Commit 0bfb8ca

Browse files
authored
feat: upvote and retract votes for coauthors (vas3k#995)
* feature: upvote and retake vote works for coauthors * refactor: upvote and retake vote inside Post methods
1 parent 76280e8 commit 0bfb8ca

22 files changed

+54
-25
lines changed

frontend/html/comments/types/battle.html

+1-1
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525
initial-is-voted
2626
initial-upvote-timestamp="{{comment.upvoted_at}}"
2727
{% endif %}
28-
{% if not me|can_upvote:comment or upvote_disabled %}is-disabled{% endif %}>
28+
{% if not me|can_upvote_comment:comment or upvote_disabled %}is-disabled{% endif %}>
2929
</comment-upvote>
3030

3131
{% if comment.is_pinned %}

frontend/html/comments/types/bold.html

+1-1
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@
5656
initial-is-voted
5757
initial-upvote-timestamp="{{comment.upvoted_at}}"
5858
{% endif %}
59-
{% if not me|can_upvote:comment or upvote_disabled %}is-disabled{% endif %}>
59+
{% if not me|can_upvote_comment:comment or upvote_disabled %}is-disabled{% endif %}>
6060
</comment-upvote>
6161

6262
{% if comment.is_pinned %}

frontend/html/comments/types/normal.html

+1-1
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@
6363
initial-is-voted
6464
initial-upvote-timestamp="{{comment.upvoted_at}}"
6565
{% endif %}
66-
{% if not me|can_upvote:comment or upvote_disabled %}is-disabled{% endif %}
66+
{% if not me|can_upvote_comment:comment or upvote_disabled %}is-disabled{% endif %}
6767
is-small>
6868
</comment-upvote>
6969

frontend/html/comments/types/reply.html

+1-1
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@
5858
initial-is-voted
5959
initial-upvote-timestamp="{{comment.upvoted_at}}"
6060
{% endif %}
61-
{% if not me|can_upvote:comment or upvote_disabled %}is-disabled{% endif %}
61+
{% if not me|can_upvote_comment:comment or upvote_disabled %}is-disabled{% endif %}
6262
is-inline>
6363
</comment-upvote>
6464
</div>

frontend/html/posts/items/battle.html

+1-1
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@
2828
initial-is-voted
2929
initial-upvote-timestamp={{post.upvoted_at}}
3030
{% endif %}
31-
{% if not me|can_upvote:post or upvote_disabled %}is-disabled{% endif %}>
31+
{% if not me|can_upvote_post:post or upvote_disabled %}is-disabled{% endif %}>
3232
</post-upvote>
3333
</div>
3434
<div class="feed-post-footer">

frontend/html/posts/items/event.html

+1-1
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@
2828
initial-is-voted
2929
initial-upvote-timestamp={{post.upvoted_at}}
3030
{% endif %}
31-
{% if not me|can_upvote:post or upvote_disabled %}is-disabled{% endif %}>
31+
{% if not me|can_upvote_post:post or upvote_disabled %}is-disabled{% endif %}>
3232
</post-upvote>
3333
</div>
3434

frontend/html/posts/items/idea.html

+1-1
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@
2929
initial-is-voted
3030
initial-upvote-timestamp={{post.upvoted_at}}
3131
{% endif %}
32-
{% if not me|can_upvote:post or upvote_disabled %}is-disabled{% endif %}>
32+
{% if not me|can_upvote_post:post or upvote_disabled %}is-disabled{% endif %}>
3333
</post-upvote>
3434
</div>
3535

frontend/html/posts/items/intro.html

+1-1
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
initial-is-voted
2525
initial-upvote-timestamp={{post.upvoted_at}}
2626
{% endif %}
27-
{% if not me|can_upvote:post or upvote_disabled %}is-disabled{% endif %}
27+
{% if not me|can_upvote_post:post or upvote_disabled %}is-disabled{% endif %}
2828
is-inline>
2929
</post-upvote>
3030

frontend/html/posts/items/link.html

+1-1
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727
initial-is-voted
2828
initial-upvote-timestamp={{post.upvoted_at}}
2929
{% endif %}
30-
{% if not me|can_upvote:post or upvote_disabled %}is-disabled{% endif %}>
30+
{% if not me|can_upvote_post:post or upvote_disabled %}is-disabled{% endif %}>
3131
</post-upvote>
3232
</div>
3333

frontend/html/posts/items/post.html

+1-1
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727
initial-is-voted
2828
initial-upvote-timestamp={{post.upvoted_at}}
2929
{% endif %}
30-
{% if not me|can_upvote:post or upvote_disabled %}is-disabled{% endif %}>
30+
{% if not me|can_upvote_post:post or upvote_disabled %}is-disabled{% endif %}>
3131
</post-upvote>
3232
</div>
3333
<div class="feed-post-footer">

frontend/html/posts/items/project.html

+1-1
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@
3131
initial-is-voted
3232
initial-upvote-timestamp={{post.upvoted_at}}
3333
{% endif %}
34-
{% if not me|can_upvote:post or upvote_disabled %}is-disabled{% endif %}>
34+
{% if not me|can_upvote_post:post or upvote_disabled %}is-disabled{% endif %}>
3535
</post-upvote>
3636
</div>
3737

frontend/html/posts/items/question.html

+1-1
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@
2929
initial-is-voted
3030
initial-upvote-timestamp={{post.upvoted_at}}
3131
{% endif %}
32-
{% if not me|can_upvote:post or upvote_disabled %}is-disabled{% endif %}>
32+
{% if not me|can_upvote_post:post or upvote_disabled %}is-disabled{% endif %}>
3333
</post-upvote>
3434
</div>
3535

frontend/html/posts/show/battle.html

+1-1
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@
6060
initial-is-voted
6161
initial-upvote-timestamp={{upvoted_at}}
6262
{% endif %}
63-
{% if not me|can_upvote:post or upvote_disabled %}is-disabled{% endif %}>
63+
{% if not me|can_upvote_post:post or upvote_disabled %}is-disabled{% endif %}>
6464
</post-upvote>
6565
<div class="clearfix20"></div>
6666
</div>

frontend/html/posts/show/intro.html

+1-1
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ <h1 class="post-title">
5252
initial-is-voted
5353
initial-upvote-timestamp={{upvoted_at}}
5454
{% endif %}
55-
{% if not me|can_upvote:post or upvote_disabled %}is-disabled{% endif %}>
55+
{% if not me|can_upvote_post:post or upvote_disabled %}is-disabled{% endif %}>
5656
</post-upvote>
5757
<div class="text-body text-body-type-post e-content">
5858
{% render_post post %}

frontend/html/posts/show/post.html

+1-1
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ <h1 class="post-title">
8686
initial-is-voted
8787
initial-upvote-timestamp={{upvoted_at}}
8888
{% endif %}
89-
{% if not me|can_upvote:post or upvote_disabled %}is-disabled{% endif %}>
89+
{% if not me|can_upvote_post:post or upvote_disabled %}is-disabled{% endif %}>
9090
</post-upvote>
9191
{% endblock %}
9292

frontend/html/posts/show/question.html

+1-1
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
initial-is-voted
1717
initial-upvote-timestamp={{upvoted_at}}
1818
{% endif %}
19-
{% if not me|can_upvote:post or upvote_disabled %}is-disabled{% endif %}>
19+
{% if not me|can_upvote_post:post or upvote_disabled %}is-disabled{% endif %}>
2020
</post-upvote>
2121
</div>
2222
{% endblock %}

gdpr/forget.py

+9
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,15 @@ def delete_user_data(user: User):
4949
# delete draft and unpublished posts
5050
Post.objects.filter(author=user, is_visible=False).delete()
5151

52+
# remove user from coauthors
53+
posts = Post.objects.filter(coauthors__contains=[old_slug])
54+
for post in posts:
55+
try:
56+
post.coauthors.remove(old_slug)
57+
post.save()
58+
except ValueError:
59+
pass
60+
5261
# transfer visible post ownership to "@deleted" user
5362
deleted_user = User.objects.filter(slug=settings.DELETED_USERNAME).first()
5463
if deleted_user:

posts/forms/compose.py

+9-4
Original file line numberDiff line numberDiff line change
@@ -89,15 +89,20 @@ def clean_topic(self):
8989
return topic
9090

9191
def clean_coauthors(self):
92-
coathors = self.cleaned_data.get("coauthors")
93-
if not coathors:
92+
coauthors = self.cleaned_data.get("coauthors")
93+
if not coauthors:
9494
return []
9595

96-
non_existing_coauthors = [coauthor for coauthor in coathors if not User.objects.filter(slug=coauthor).exists()]
96+
seen = set()
97+
duplicated_coauthors = [coauthor for coauthor in coauthors if coauthor in seen or seen.add(coauthor)]
98+
if duplicated_coauthors:
99+
raise ValidationError("Пользователи уже соавторы: {}".format(', '.join(duplicated_coauthors)))
100+
101+
non_existing_coauthors = [coauthor for coauthor in coauthors if not User.objects.filter(slug=coauthor).exists()]
97102
if non_existing_coauthors:
98103
raise ValidationError("Несуществующие пользователи: {}".format(', '.join(non_existing_coauthors)))
99104

100-
return coathors
105+
return coauthors
101106

102107

103108
class PostTextForm(PostForm):

posts/models/post.py

+10
Original file line numberDiff line numberDiff line change
@@ -167,11 +167,21 @@ def increment_view_count(self):
167167
return Post.objects.filter(id=self.id).update(view_count=F("view_count") + 1)
168168

169169
def increment_vote_count(self):
170+
if self.coauthors:
171+
self.increment_coauthors_vote_count()
170172
return Post.objects.filter(id=self.id).update(upvotes=F("upvotes") + 1)
171173

172174
def decrement_vote_count(self):
175+
if self.coauthors:
176+
self.decrement_coauthors_vote_count()
173177
return Post.objects.filter(id=self.id).update(upvotes=F("upvotes") - 1)
174178

179+
def increment_coauthors_vote_count(self):
180+
return User.objects.filter(slug__in=self.coauthors).update(upvotes=F("upvotes") + 1)
181+
182+
def decrement_coauthors_vote_count(self):
183+
return User.objects.filter(slug__in=self.coauthors, upvotes__gt=0).update(upvotes=F("upvotes") - 1)
184+
175185
def can_edit(self, user):
176186
return self.author == user or user.is_moderator or user.slug in self.coauthors
177187

posts/models/votes.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ class Meta:
2525

2626
@classmethod
2727
def upvote(cls, user, post, request=None):
28-
if not user.is_god and user.id == post.author_id:
28+
if not user.is_god and (user.id == post.author_id or user.slug in post.coauthors):
2929
return None, False
3030

3131
post_vote, is_vote_created = PostVote.objects.get_or_create(
@@ -48,7 +48,7 @@ def is_retractable(self):
4848

4949
@classmethod
5050
def retract_vote(cls, request, user, post):
51-
if not user.is_god and user.id == post.author_id:
51+
if not user.is_god and (user.id == post.author_id or user.slug in post.coauthors):
5252
return False
5353

5454
try:

posts/templatetags/posts.py

+7-2
Original file line numberDiff line numberDiff line change
@@ -100,8 +100,13 @@ def link_summary(post):
100100

101101

102102
@register.filter
103-
def can_upvote(user, post_or_comment):
104-
return bool(user and user != post_or_comment.author)
103+
def can_upvote_post(user, post):
104+
return bool(user and user != post.author and user.slug not in post.coauthors)
105+
106+
107+
@register.filter
108+
def can_upvote_comment(user, comment):
109+
return bool(user and user != comment.author)
105110

106111

107112
@register.filter

posts/views/posts.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,7 @@ def upvote_post(request, post_slug):
128128
"post": {
129129
"upvotes": post.upvotes + (1 if is_vote_created else 0),
130130
},
131-
"upvoted_timestamp": int(post_vote.created_at.timestamp() * 1000)
131+
"upvoted_timestamp": int(post_vote.created_at.timestamp() * 1000) if post_vote else 0
132132
}
133133

134134

0 commit comments

Comments
 (0)