mirror of
https://codeberg.org/rimu/pyfedi
synced 2025-02-03 00:31:25 -08:00
notifications
This commit is contained in:
parent
48dac0fc3a
commit
20f5c7b7f8
8 changed files with 73 additions and 15 deletions
|
@ -4,7 +4,7 @@ import os
|
||||||
from datetime import timedelta
|
from datetime import timedelta
|
||||||
from random import randint
|
from random import randint
|
||||||
from typing import Union, Tuple
|
from typing import Union, Tuple
|
||||||
from flask import current_app, request, g
|
from flask import current_app, request, g, url_for
|
||||||
from sqlalchemy import text
|
from sqlalchemy import text
|
||||||
from app import db, cache, constants, celery
|
from app import db, cache, constants, celery
|
||||||
from app.models import User, Post, Community, BannedInstances, File, PostReply, AllowedInstances, Instance, utcnow, \
|
from app.models import User, Post, Community, BannedInstances, File, PostReply, AllowedInstances, Instance, utcnow, \
|
||||||
|
@ -20,7 +20,8 @@ from PIL import Image, ImageOps
|
||||||
from io import BytesIO
|
from io import BytesIO
|
||||||
|
|
||||||
from app.utils import get_request, allowlist_html, html_to_markdown, get_setting, ap_datetime, markdown_to_html, \
|
from app.utils import get_request, allowlist_html, html_to_markdown, get_setting, ap_datetime, markdown_to_html, \
|
||||||
is_image_url, domain_from_url, gibberish, ensure_directory_exists, markdown_to_text, head_request, post_ranking
|
is_image_url, domain_from_url, gibberish, ensure_directory_exists, markdown_to_text, head_request, post_ranking, \
|
||||||
|
shorten_string
|
||||||
|
|
||||||
|
|
||||||
def public_key():
|
def public_key():
|
||||||
|
@ -466,6 +467,7 @@ def post_json_to_model(post_json, user, community) -> Post:
|
||||||
notify = Notification(title='Suspicious content', url=post.ap_id, user_id=community_member.user_id, author_id=user.id)
|
notify = Notification(title='Suspicious content', url=post.ap_id, user_id=community_member.user_id, author_id=user.id)
|
||||||
db.session.add(notify)
|
db.session.add(notify)
|
||||||
already_notified.add(community_member.user_id)
|
already_notified.add(community_member.user_id)
|
||||||
|
|
||||||
if domain.notify_admins:
|
if domain.notify_admins:
|
||||||
for admin in Site.admins():
|
for admin in Site.admins():
|
||||||
if admin.id not in already_notified:
|
if admin.id not in already_notified:
|
||||||
|
@ -911,12 +913,36 @@ def create_post_reply(activity_log: ActivityPubLog, community: Community, in_rep
|
||||||
if post_id is not None:
|
if post_id is not None:
|
||||||
post = Post.query.get(post_id)
|
post = Post.query.get(post_id)
|
||||||
if post.comments_enabled:
|
if post.comments_enabled:
|
||||||
|
anchor = None
|
||||||
|
if not parent_comment_id:
|
||||||
|
notification_target = post
|
||||||
|
else:
|
||||||
|
notification_target = PostReply.query.get(parent_comment_id)
|
||||||
|
|
||||||
|
if notification_target.author.has_blocked_user(post_reply.user_id):
|
||||||
|
activity_log.exception_message = 'Replier blocked, reply discarded'
|
||||||
|
activity_log.result = 'ignored'
|
||||||
|
return None
|
||||||
|
|
||||||
db.session.add(post_reply)
|
db.session.add(post_reply)
|
||||||
post.reply_count += 1
|
post.reply_count += 1
|
||||||
community.post_reply_count += 1
|
community.post_reply_count += 1
|
||||||
community.last_active = post.last_active = utcnow()
|
community.last_active = post.last_active = utcnow()
|
||||||
activity_log.result = 'success'
|
activity_log.result = 'success'
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
|
|
||||||
|
# send notification to the post/comment being replied to
|
||||||
|
if notification_target.notify_author and post_reply.user_id != notification_target.user_id and notification_target.author.ap_id is None:
|
||||||
|
if isinstance(notification_target, PostReply):
|
||||||
|
anchor = f"comment_{post_reply.id}"
|
||||||
|
notification = Notification(title='Reply from ' + post_reply.author.display_name(),
|
||||||
|
user_id=notification_target.user_id,
|
||||||
|
author_id=post_reply.user_id,
|
||||||
|
url=url_for('activitypub.post_ap', post_id=post.id, _anchor=anchor))
|
||||||
|
db.session.add(notification)
|
||||||
|
notification_target.author.unread_notifications += 1
|
||||||
|
db.session.commit()
|
||||||
|
|
||||||
if user.reputation > 100:
|
if user.reputation > 100:
|
||||||
vote = PostReplyVote(user_id=1, author_id=post_reply.user_id,
|
vote = PostReplyVote(user_id=1, author_id=post_reply.user_id,
|
||||||
post_reply_id=post_reply.id,
|
post_reply_id=post_reply.id,
|
||||||
|
|
|
@ -433,10 +433,11 @@ def community_report(community_id: int):
|
||||||
# todo: find all instance admin(s). for now just load User.id == 1
|
# todo: find all instance admin(s). for now just load User.id == 1
|
||||||
admins = [User.query.get_or_404(1)]
|
admins = [User.query.get_or_404(1)]
|
||||||
for admin in admins:
|
for admin in admins:
|
||||||
notification = Notification(user_id=admin.id, title=_('A post has been reported'),
|
notification = Notification(user_id=admin.id, title=_('A community has been reported'),
|
||||||
url=community.local_url(),
|
url=community.local_url(),
|
||||||
author_id=current_user.id)
|
author_id=current_user.id)
|
||||||
db.session.add(notification)
|
db.session.add(notification)
|
||||||
|
admin.unread_notifications += 1
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
|
|
||||||
# todo: federate report to originating instance
|
# todo: federate report to originating instance
|
||||||
|
|
|
@ -54,14 +54,19 @@ def show_post(post_id: int):
|
||||||
resp.set_cookie('sesion', '17489047567495', expires=datetime(year=2099, month=12, day=30))
|
resp.set_cookie('sesion', '17489047567495', expires=datetime(year=2099, month=12, day=30))
|
||||||
return resp
|
return resp
|
||||||
|
|
||||||
|
if post.author.has_blocked_user(current_user.id):
|
||||||
|
flash(_('You cannot reply to %(name)s', name=post.author.display_name()))
|
||||||
|
return redirect(url_for('activitypub.post_ap', post_id=post_id))
|
||||||
|
|
||||||
reply = PostReply(user_id=current_user.id, post_id=post.id, community_id=community.id, body=form.body.data,
|
reply = PostReply(user_id=current_user.id, post_id=post.id, community_id=community.id, body=form.body.data,
|
||||||
body_html=markdown_to_html(form.body.data), body_html_safe=True,
|
body_html=markdown_to_html(form.body.data), body_html_safe=True,
|
||||||
from_bot=current_user.bot, up_votes=1, nsfw=post.nsfw, nsfl=post.nsfl,
|
from_bot=current_user.bot, up_votes=1, nsfw=post.nsfw, nsfl=post.nsfl,
|
||||||
notify_author=form.notify_author.data)
|
notify_author=form.notify_author.data)
|
||||||
if post.notify_author and current_user.id != post.user_id: # todo: check if replier is blocked
|
if post.notify_author and current_user.id != post.user_id:
|
||||||
notification = Notification(title=_('Reply: ') + shorten_string(form.body.data, 42), user_id=post.user_id,
|
notification = Notification(title=_('Reply from %(name)s ', name=current_user.display_name()), user_id=post.user_id,
|
||||||
author_id=current_user.id, url=url_for('activitypub.post_ap', post_id=post.id))
|
author_id=current_user.id, url=url_for('activitypub.post_ap', post_id=post.id))
|
||||||
db.session.add(notification)
|
db.session.add(notification)
|
||||||
|
post.author.unread_notifications += 1
|
||||||
post.last_active = community.last_active = utcnow()
|
post.last_active = community.last_active = utcnow()
|
||||||
post.reply_count += 1
|
post.reply_count += 1
|
||||||
community.post_reply_count += 1
|
community.post_reply_count += 1
|
||||||
|
@ -363,6 +368,11 @@ def add_reply(post_id: int, comment_id: int):
|
||||||
in_reply_to = PostReply.query.get_or_404(comment_id)
|
in_reply_to = PostReply.query.get_or_404(comment_id)
|
||||||
mods = post.community.moderators()
|
mods = post.community.moderators()
|
||||||
is_moderator = current_user.is_authenticated and any(mod.user_id == current_user.id for mod in mods)
|
is_moderator = current_user.is_authenticated and any(mod.user_id == current_user.id for mod in mods)
|
||||||
|
|
||||||
|
if in_reply_to.author.has_blocked_user(current_user.id):
|
||||||
|
flash(_('You cannot reply to %(name)s', name=in_reply_to.author.display_name()))
|
||||||
|
return redirect(url_for('activitypub.post_ap', post_id=post_id))
|
||||||
|
|
||||||
form = NewReplyForm()
|
form = NewReplyForm()
|
||||||
if form.validate_on_submit():
|
if form.validate_on_submit():
|
||||||
current_user.last_seen = utcnow()
|
current_user.last_seen = utcnow()
|
||||||
|
@ -374,22 +384,21 @@ def add_reply(post_id: int, comment_id: int):
|
||||||
notify_author=form.notify_author.data)
|
notify_author=form.notify_author.data)
|
||||||
db.session.add(reply)
|
db.session.add(reply)
|
||||||
if in_reply_to.notify_author and current_user.id != in_reply_to.user_id and in_reply_to.author.ap_id is None: # todo: check if replier is blocked
|
if in_reply_to.notify_author and current_user.id != in_reply_to.user_id and in_reply_to.author.ap_id is None: # todo: check if replier is blocked
|
||||||
notification = Notification(title=_('Reply: ') + shorten_string(form.body.data, 42), user_id=in_reply_to.user_id,
|
notification = Notification(title=_('Reply from %(name)s', name=current_user.display_name()), user_id=in_reply_to.user_id,
|
||||||
author_id=current_user.id, url=url_for('activitypub.post_ap', post_id=post.id))
|
author_id=current_user.id, url=url_for('activitypub.post_ap', post_id=post.id))
|
||||||
db.session.add(notification)
|
db.session.add(notification)
|
||||||
|
in_reply_to.author.unread_notifications += 1
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
reply.ap_id = reply.profile_id()
|
reply.ap_id = reply.profile_id()
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
if current_user.reputation > 100:
|
if current_user.reputation > 100:
|
||||||
reply_vote = PostReplyVote(user_id=1, author_id=current_user.id, post_reply_id=reply.id,
|
reply_vote = PostReplyVote(user_id=1, author_id=current_user.id, post_reply_id=reply.id, effect=1.0)
|
||||||
effect=1.0)
|
|
||||||
reply.up_votes += 1
|
reply.up_votes += 1
|
||||||
reply.score += 1
|
reply.score += 1
|
||||||
reply.ranking += 1
|
reply.ranking += 1
|
||||||
db.session.add(reply_vote)
|
db.session.add(reply_vote)
|
||||||
elif current_user.reputation < -100:
|
elif current_user.reputation < -100:
|
||||||
reply_vote = PostReplyVote(user_id=1, author_id=current_user.id, post_reply_id=reply.id,
|
reply_vote = PostReplyVote(user_id=1, author_id=current_user.id, post_reply_id=reply.id, effect=-1.0)
|
||||||
effect=-1.0)
|
|
||||||
reply.score -= 1
|
reply.score -= 1
|
||||||
reply.ranking -= 1
|
reply.ranking -= 1
|
||||||
db.session.add(reply_vote)
|
db.session.add(reply_vote)
|
||||||
|
|
|
@ -198,6 +198,10 @@
|
||||||
content: "\e967";
|
content: "\e967";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.fe-bell {
|
||||||
|
position: relative;
|
||||||
|
top: 1px;
|
||||||
|
}
|
||||||
.fe-bell::before {
|
.fe-bell::before {
|
||||||
content: "\e91e";
|
content: "\e91e";
|
||||||
}
|
}
|
||||||
|
|
|
@ -225,6 +225,11 @@ nav, etc which are used site-wide */
|
||||||
content: "\e967";
|
content: "\e967";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.fe-bell {
|
||||||
|
position: relative;
|
||||||
|
top: 1px;
|
||||||
|
}
|
||||||
|
|
||||||
.fe-bell::before {
|
.fe-bell::before {
|
||||||
content: "\e91e";
|
content: "\e91e";
|
||||||
}
|
}
|
||||||
|
|
|
@ -224,6 +224,11 @@
|
||||||
content: "\e967";
|
content: "\e967";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.fe-bell {
|
||||||
|
position: relative;
|
||||||
|
top: 1px;
|
||||||
|
}
|
||||||
|
|
||||||
.fe-bell::before {
|
.fe-bell::before {
|
||||||
content: "\e91e";
|
content: "\e91e";
|
||||||
}
|
}
|
||||||
|
|
|
@ -96,8 +96,15 @@
|
||||||
<li class="nav-item"><a class="nav-link" href="/admin/">{{ _('Admin') }}</a></li>
|
<li class="nav-item"><a class="nav-link" href="/admin/">{{ _('Admin') }}</a></li>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<li class="nav-item"><a class="nav-link" href="/auth/logout">{{ _('Log out') }}</a></li>
|
<li class="nav-item"><a class="nav-link" href="/auth/logout">{{ _('Log out') }}</a></li>
|
||||||
<li class="nav-item"><a class="nav-link" href="/notifications"><span class="fe fe-bell"></span>
|
<li class="nav-item">
|
||||||
{{ current_user.unread_notifications if current_user.unread_notifications else '' }}</a></li>
|
<a class="nav-link" href="/notifications">
|
||||||
|
{% if current_user.unread_notifications %}
|
||||||
|
<span class="fe fe-bell red"></span> <span class="red">{{ current_user.unread_notifications }}</span>
|
||||||
|
{% else %}
|
||||||
|
<span class="fe fe-bell"></span>
|
||||||
|
{% endif %}
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -286,6 +286,7 @@ def report_profile(actor):
|
||||||
if admin.id not in already_notified:
|
if admin.id not in already_notified:
|
||||||
notify = Notification(title='Reported user', url=user.ap_id, user_id=admin.id, author_id=current_user.id)
|
notify = Notification(title='Reported user', url=user.ap_id, user_id=admin.id, author_id=current_user.id)
|
||||||
db.session.add(notify)
|
db.session.add(notify)
|
||||||
|
admin.unread_notifications += 1
|
||||||
user.reports += 1
|
user.reports += 1
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
|
|
||||||
|
@ -426,12 +427,12 @@ def ban_purge_profile(actor):
|
||||||
@bp.route('/notifications', methods=['GET', 'POST'])
|
@bp.route('/notifications', methods=['GET', 'POST'])
|
||||||
@login_required
|
@login_required
|
||||||
def notifications():
|
def notifications():
|
||||||
"""Remove notifications older than 30 days"""
|
"""Remove notifications older than 90 days"""
|
||||||
db.session.query(Notification).filter(
|
db.session.query(Notification).filter(
|
||||||
Notification.created_at < utcnow() - timedelta(days=30)).delete()
|
Notification.created_at < utcnow() - timedelta(days=90)).delete()
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
|
|
||||||
# Update unread notifications count
|
# Update unread notifications count, just to be sure
|
||||||
current_user.unread_notifications = Notification.query.filter_by(user_id=current_user.id, read=False).count()
|
current_user.unread_notifications = Notification.query.filter_by(user_id=current_user.id, read=False).count()
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue