notifications

This commit is contained in:
rimu 2024-01-06 11:01:44 +13:00
parent 48dac0fc3a
commit 20f5c7b7f8
8 changed files with 73 additions and 15 deletions

View file

@ -4,7 +4,7 @@ import os
from datetime import timedelta
from random import randint
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 app import db, cache, constants, celery
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 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():
@ -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)
db.session.add(notify)
already_notified.add(community_member.user_id)
if domain.notify_admins:
for admin in Site.admins():
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:
post = Post.query.get(post_id)
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)
post.reply_count += 1
community.post_reply_count += 1
community.last_active = post.last_active = utcnow()
activity_log.result = 'success'
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:
vote = PostReplyVote(user_id=1, author_id=post_reply.user_id,
post_reply_id=post_reply.id,

View file

@ -433,10 +433,11 @@ def community_report(community_id: int):
# todo: find all instance admin(s). for now just load User.id == 1
admins = [User.query.get_or_404(1)]
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(),
author_id=current_user.id)
db.session.add(notification)
admin.unread_notifications += 1
db.session.commit()
# todo: federate report to originating instance

View file

@ -54,14 +54,19 @@ def show_post(post_id: int):
resp.set_cookie('sesion', '17489047567495', expires=datetime(year=2099, month=12, day=30))
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,
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,
notify_author=form.notify_author.data)
if post.notify_author and current_user.id != post.user_id: # todo: check if replier is blocked
notification = Notification(title=_('Reply: ') + shorten_string(form.body.data, 42), user_id=post.user_id,
if post.notify_author and current_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))
db.session.add(notification)
post.author.unread_notifications += 1
post.last_active = community.last_active = utcnow()
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)
mods = post.community.moderators()
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()
if form.validate_on_submit():
current_user.last_seen = utcnow()
@ -374,22 +384,21 @@ def add_reply(post_id: int, comment_id: int):
notify_author=form.notify_author.data)
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
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))
db.session.add(notification)
in_reply_to.author.unread_notifications += 1
db.session.commit()
reply.ap_id = reply.profile_id()
db.session.commit()
if current_user.reputation > 100:
reply_vote = PostReplyVote(user_id=1, author_id=current_user.id, post_reply_id=reply.id,
effect=1.0)
reply_vote = PostReplyVote(user_id=1, author_id=current_user.id, post_reply_id=reply.id, effect=1.0)
reply.up_votes += 1
reply.score += 1
reply.ranking += 1
db.session.add(reply_vote)
elif current_user.reputation < -100:
reply_vote = PostReplyVote(user_id=1, author_id=current_user.id, post_reply_id=reply.id,
effect=-1.0)
reply_vote = PostReplyVote(user_id=1, author_id=current_user.id, post_reply_id=reply.id, effect=-1.0)
reply.score -= 1
reply.ranking -= 1
db.session.add(reply_vote)

View file

@ -198,6 +198,10 @@
content: "\e967";
}
.fe-bell {
position: relative;
top: 1px;
}
.fe-bell::before {
content: "\e91e";
}

View file

@ -225,6 +225,11 @@ nav, etc which are used site-wide */
content: "\e967";
}
.fe-bell {
position: relative;
top: 1px;
}
.fe-bell::before {
content: "\e91e";
}

View file

@ -224,6 +224,11 @@
content: "\e967";
}
.fe-bell {
position: relative;
top: 1px;
}
.fe-bell::before {
content: "\e91e";
}

View file

@ -96,8 +96,15 @@
<li class="nav-item"><a class="nav-link" href="/admin/">{{ _('Admin') }}</a></li>
{% 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="/notifications"><span class="fe fe-bell"></span>
{{ current_user.unread_notifications if current_user.unread_notifications else '' }}</a></li>
<li class="nav-item">
<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 %}
</ul>
</div>

View file

@ -286,6 +286,7 @@ def report_profile(actor):
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)
db.session.add(notify)
admin.unread_notifications += 1
user.reports += 1
db.session.commit()
@ -426,12 +427,12 @@ def ban_purge_profile(actor):
@bp.route('/notifications', methods=['GET', 'POST'])
@login_required
def notifications():
"""Remove notifications older than 30 days"""
"""Remove notifications older than 90 days"""
db.session.query(Notification).filter(
Notification.created_at < utcnow() - timedelta(days=30)).delete()
Notification.created_at < utcnow() - timedelta(days=90)).delete()
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()
db.session.commit()