notification subscription - user toggle

This commit is contained in:
rimu 2024-04-19 20:06:08 +12:00
parent d9422411ea
commit fb34de8da3
4 changed files with 57 additions and 6 deletions

View file

@ -19,7 +19,7 @@ import jwt
import os import os
from app.constants import SUBSCRIPTION_NONMEMBER, SUBSCRIPTION_MEMBER, SUBSCRIPTION_MODERATOR, SUBSCRIPTION_OWNER, \ from app.constants import SUBSCRIPTION_NONMEMBER, SUBSCRIPTION_MEMBER, SUBSCRIPTION_MODERATOR, SUBSCRIPTION_OWNER, \
SUBSCRIPTION_BANNED, SUBSCRIPTION_PENDING SUBSCRIPTION_BANNED, SUBSCRIPTION_PENDING, NOTIF_USER
# datetime.utcnow() is depreciated in Python 3.12 so it will need to be swapped out eventually # datetime.utcnow() is depreciated in Python 3.12 so it will need to be swapped out eventually
@ -880,6 +880,18 @@ class User(UserMixin, db.Model):
else: else:
return '@' + self.user_name + '@' + self.ap_domain return '@' + self.user_name + '@' + self.ap_domain
# True if user_id wants to be notified about posts by self
def notify_new_posts(self, user_id):
existing_notification = NotificationSubscription.query.filter(NotificationSubscription.entity_id == self.id,
NotificationSubscription.user_id == user_id,
NotificationSubscription.type == NOTIF_USER).first()
return existing_notification is not None
# ids of all the users who want to be notified when self makes a post
def notification_subscribers(self):
return db.session.execute(text('SELECT user_id FROM "notification_subscription" WHERE entity_id = :user_id AND type = :type '),
{'user_id': self.id, 'type': NOTIF_USER}).scalars()
class ActivityLog(db.Model): class ActivityLog(db.Model):
id = db.Column(db.Integer, primary_key=True) id = db.Column(db.Integer, primary_key=True)

View file

@ -0,0 +1,5 @@
<a href="/user/{{ user.id }}/notification" rel="nofollow" aria-live="assertive"
aria-label="{{ 'Notify about new posts by this person' if user.notify_new_posts(current_user.id) else 'Do not notify about new posts' }}"
class="fe {{ 'fe-bell' if user.notify_new_posts(current_user.id) else 'fe-no-bell' }} no-underline"
hx-post="/user/{{ user.id }}/notification" hx-trigger="click throttle:1s" hx-swap="outerHTML"
title="{{ _('Notify about every new post by this person.') }}"></a>

View file

@ -22,7 +22,11 @@
</nav> </nav>
</div> </div>
<img class="community_icon_big bump_up rounded-circle" src="{{ user.avatar_image() }}" alt="{{ _('Profile pic') }}" /> <img class="community_icon_big bump_up rounded-circle" src="{{ user.avatar_image() }}" alt="{{ _('Profile pic') }}" />
<h1 class="mt-2">{{ user.display_name() if user.is_local() else user.display_name() + ', ' + user.ap_id }}</h1> <h1 class="mt-2">{{ user.display_name() if user.is_local() else user.display_name() + ', ' + user.ap_id }}
{% if current_user.is_authenticated %}
{% include 'user/_notification_toggle.html' %}
{% endif %}
</h1>
{% elif user.avatar_image() != '' %} {% elif user.avatar_image() != '' %}
<div class="row"> <div class="row">
<div class="col-2"> <div class="col-2">
@ -39,7 +43,11 @@
{% endif %} {% endif %}
</div> </div>
<div class="col-10"> <div class="col-10">
<h1 class="mt-3">{{ user.display_name() if user.is_local() else user.display_name() + ', ' + user.ap_id }}</h1> <h1 class="mt-3">{{ user.display_name() if user.is_local() else user.display_name() + ', ' + user.ap_id }}
{% if current_user.is_authenticated %}
{% include 'user/_notification_toggle.html' %}
{% endif %}
</h1>
</div> </div>
</div> </div>
{% else %} {% else %}
@ -50,7 +58,11 @@
<li class="breadcrumb-item active">{{ user.link()|shorten }}</li> <li class="breadcrumb-item active">{{ user.link()|shorten }}</li>
</ol> </ol>
</nav> </nav>
<h1 class="mt-2">{{ user.display_name() if user.is_local() else user.display_name() + ', ' + user.ap_id }}</h1> <h1 class="mt-2">{{ user.display_name() if user.is_local() else user.display_name() + ', ' + user.ap_id }}
{% if current_user.is_authenticated %}
{% include 'user/_notification_toggle.html' %}
{% endif %}
</h1>
{% endif %} {% endif %}
{% if current_user.is_authenticated and current_user != user %} {% if current_user.is_authenticated and current_user != user %}
<div class="profile_action_buttons"> <div class="profile_action_buttons">

View file

@ -9,10 +9,10 @@ from app import db, cache, celery
from app.activitypub.signature import post_request from app.activitypub.signature import post_request
from app.activitypub.util import default_context, find_actor_or_create from app.activitypub.util import default_context, find_actor_or_create
from app.community.util import save_icon_file, save_banner_file, retrieve_mods_and_backfill from app.community.util import save_icon_file, save_banner_file, retrieve_mods_and_backfill
from app.constants import SUBSCRIPTION_MEMBER, SUBSCRIPTION_PENDING from app.constants import SUBSCRIPTION_MEMBER, SUBSCRIPTION_PENDING, NOTIF_USER
from app.models import Post, Community, CommunityMember, User, PostReply, PostVote, Notification, utcnow, File, Site, \ from app.models import Post, Community, CommunityMember, User, PostReply, PostVote, Notification, utcnow, File, Site, \
Instance, Report, UserBlock, CommunityBan, CommunityJoinRequest, CommunityBlock, Filter, Domain, DomainBlock, \ Instance, Report, UserBlock, CommunityBan, CommunityJoinRequest, CommunityBlock, Filter, Domain, DomainBlock, \
InstanceBlock InstanceBlock, NotificationSubscription
from app.user import bp from app.user import bp
from app.user.forms import ProfileForm, SettingsForm, DeleteAccountForm, ReportUserForm, FilterEditForm from app.user.forms import ProfileForm, SettingsForm, DeleteAccountForm, ReportUserForm, FilterEditForm
from app.user.utils import purge_user_then_delete from app.user.utils import purge_user_then_delete
@ -220,6 +220,26 @@ def change_settings():
joined_communities=joined_communities(current_user.get_id()) joined_communities=joined_communities(current_user.get_id())
) )
@bp.route('/user/<int:user_id>/notification', methods=['GET', 'POST'])
@login_required
def user_notification(user_id: int):
user = User.query.get_or_404(user_id)
existing_notification = NotificationSubscription.query.filter(NotificationSubscription.entity_id == user.id,
NotificationSubscription.user_id == current_user.id,
NotificationSubscription.type == NOTIF_USER).first()
if existing_notification:
db.session.delete(existing_notification)
db.session.commit()
else: # no subscription yet, so make one
if user.id != current_user.id and not user.has_blocked_user(current_user.id):
new_notification = NotificationSubscription(user_id=current_user.id, entity_id=user.id, type=NOTIF_USER)
db.session.add(new_notification)
db.session.commit()
return render_template('user/_notification_toggle.html', user=user)
@bp.route('/u/<actor>/ban', methods=['GET']) @bp.route('/u/<actor>/ban', methods=['GET'])
@login_required @login_required
def ban_profile(actor): def ban_profile(actor):
@ -287,6 +307,8 @@ def block_profile(actor):
if not existing_block: if not existing_block:
block = UserBlock(blocker_id=current_user.id, blocked_id=user.id) block = UserBlock(blocker_id=current_user.id, blocked_id=user.id)
db.session.add(block) db.session.add(block)
db.session.execute(text('DELETE FROM "notification_subscription" WHERE entity_id = :current_user AND user_id = :user_id'),
{'current_user': current_user.id, 'user_id': user.id})
db.session.commit() db.session.commit()
if not user.is_local(): if not user.is_local():