mirror of
https://codeberg.org/rimu/pyfedi
synced 2025-01-23 19:36:56 -08:00
Add 'Account->Activity Alerts' page to show content subscriptions
(not sure of best terminology for these - feel free to rename)
This commit is contained in:
parent
ca9b7a523b
commit
baaf93087d
10 changed files with 241 additions and 3 deletions
|
@ -197,6 +197,7 @@
|
||||||
<li><a class="dropdown-item{% if active_child == 'edit_profile' %} active{% endif %}" href="/user/settings">{{ _('Edit profile & settings') }}</a></li>
|
<li><a class="dropdown-item{% if active_child == 'edit_profile' %} active{% endif %}" href="/user/settings">{{ _('Edit profile & settings') }}</a></li>
|
||||||
<li><a class="dropdown-item{% if active_child == 'chats' %} active{% endif %}" href="/chat">{{ _('Chats') }}</a></li>
|
<li><a class="dropdown-item{% if active_child == 'chats' %} active{% endif %}" href="/chat">{{ _('Chats') }}</a></li>
|
||||||
<li><a class="dropdown-item{% if active_child == 'bookmarks' %} active{% endif %}" href="/bookmarks">{{ _('Bookmarks') }}</a></li>
|
<li><a class="dropdown-item{% if active_child == 'bookmarks' %} active{% endif %}" href="/bookmarks">{{ _('Bookmarks') }}</a></li>
|
||||||
|
<li><a class="dropdown-item{% if active_child == 'alerts' %} active{% endif %}" href="/alerts">{{ _('Activity Alerts') }}</a></li>
|
||||||
{% if current_user.is_authenticated and current_user.hide_read_posts -%}
|
{% if current_user.is_authenticated and current_user.hide_read_posts -%}
|
||||||
<li><a class="dropdown-item{% if active_child == 'read_posts' %} active{% endif %}" href="/read-posts">{{ _('Read Posts') }}</a></li>
|
<li><a class="dropdown-item{% if active_child == 'read_posts' %} active{% endif %}" href="/read-posts">{{ _('Read Posts') }}</a></li>
|
||||||
{% endif -%}
|
{% endif -%}
|
||||||
|
|
35
app/templates/user/alerts.html
Normal file
35
app/templates/user/alerts.html
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
{% if theme() and file_exists('app/templates/themes/' + theme() + '/base.html') %}
|
||||||
|
{% extends 'themes/' + theme() + '/base.html' %}
|
||||||
|
{% else %}
|
||||||
|
{% extends "base.html" %}
|
||||||
|
{% endif %}
|
||||||
|
{% set active_child = 'alerts' %}
|
||||||
|
|
||||||
|
{% block app_content %}
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-12 col-md-8 position-relative main_pane">
|
||||||
|
<nav class="mb-2" aria-label="breadcrumb" id="breadcrumb_nav" title="Navigation">
|
||||||
|
<ol class="breadcrumb">
|
||||||
|
<li class="breadcrumb-item"><a href="/">{{ _('Home') }}</a></li>
|
||||||
|
<li class="breadcrumb-item"><a href="/u/{{ user.link() }}">{{ user.display_name() }}</a></li>
|
||||||
|
<li class="breadcrumb-item active">{{ _('Alerts') }}</li>
|
||||||
|
</ol>
|
||||||
|
</nav>
|
||||||
|
{% include 'user/alerts/_type.html' %}
|
||||||
|
{% include 'user/alerts/_' + type + '.html' %}
|
||||||
|
|
||||||
|
<nav aria-label="Pagination" class="mt-4" role="navigation">
|
||||||
|
{% if prev_url %}
|
||||||
|
<a href="{{ prev_url }}" class="btn btn-primary" rel="nofollow">
|
||||||
|
<span aria-hidden="true">←</span> {{ _('Previous page') }}
|
||||||
|
</a>
|
||||||
|
{% endif %}
|
||||||
|
{% if next_url %}
|
||||||
|
<a href="{{ next_url }}" class="btn btn-primary" rel="nofollow">
|
||||||
|
{{ _('Next page') }} <span aria-hidden="true">→</span>
|
||||||
|
</a>
|
||||||
|
{% endif %}
|
||||||
|
</nav>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
21
app/templates/user/alerts/_comments.html
Normal file
21
app/templates/user/alerts/_comments.html
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
{% include 'user/alerts/_filter.html' %}
|
||||||
|
<div class="post_list">
|
||||||
|
<h2>{{ _('You will be notified of replies to these comments') }}</h2>
|
||||||
|
{% for reply in entities.items %}
|
||||||
|
<div class="h-entry post_teaser tabindex="0">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col">
|
||||||
|
<a href="{{ url_for('activitypub.post_ap', post_id=reply.post_id, _anchor='comment_' + str(reply.id)) }}" aria-label="{{ _('Read replies') }}">{{ reply.body }}</a>
|
||||||
|
</div>
|
||||||
|
<div class="col col-1">
|
||||||
|
{% with comment=dict(comment=reply) %}
|
||||||
|
{% include 'post/_reply_notification_toggle.html' %}
|
||||||
|
{% endwith %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% else %}
|
||||||
|
<p>{{ _('You have not subscribed to any comments. Use the bell icon on each comment to do so.') }}</p>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
|
19
app/templates/user/alerts/_communities.html
Normal file
19
app/templates/user/alerts/_communities.html
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
{% include 'user/alerts/_filter.html' %}
|
||||||
|
<div class="post_list">
|
||||||
|
<h2>{{ _('You will be notified of new posts in these communities') }}</h2>
|
||||||
|
{% for community in entities.items %}
|
||||||
|
<div class="h-entry post_teaser tabindex="0">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col">
|
||||||
|
<a href="{{ url_for('activitypub.community_profile', actor=community.ap_id if community.ap_id is not none else community.name) }}" aria-label="{{ _('Visit Community') }}">{{ community.title }}</a>
|
||||||
|
</div>
|
||||||
|
<div class="col col-1">
|
||||||
|
{% include 'community/_notification_toggle.html' %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% else %}
|
||||||
|
<p>{{ _('You have not subscribed to an alert for new content in any communities. Use the bell icon in each community to do so.') }}</p>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
|
11
app/templates/user/alerts/_filter.html
Normal file
11
app/templates/user/alerts/_filter.html
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
<div class="view_filter btn-group mt-1 mb-2" aria-label="{{ _('Alert filters: ') }}">
|
||||||
|
<a href="/alerts/{{ type }}/all" class="btn {{ 'btn-primary' if filter == 'all' else 'btn-outline-secondary' }}" rel="nofollow noindex" title="{{ _('All authors') }}">
|
||||||
|
{{ _('All') }}
|
||||||
|
</a>
|
||||||
|
<a href="/alerts/{{ type }}/mine" class="btn {{ 'btn-primary' if filter == 'mine' else 'btn-outline-secondary' }}" rel="nofollow noindex" title="{{ _('Only Mine') }}">
|
||||||
|
{{ _('Mine') }}
|
||||||
|
</a>
|
||||||
|
<a href="/alerts/{{ type }}/others" class="btn {{ 'btn-primary' if filter == 'others' else 'btn-outline-secondary' }}" rel="nofollow noindex" title="{{ _('Only Others') }}">
|
||||||
|
{{ _('Others') }}
|
||||||
|
</a>
|
||||||
|
</div>
|
19
app/templates/user/alerts/_posts.html
Normal file
19
app/templates/user/alerts/_posts.html
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
{% include 'user/alerts/_filter.html' %}
|
||||||
|
<div class="post_list">
|
||||||
|
<h2>{{ _('You will be notified of top-level replies to these posts') }}</h2>
|
||||||
|
{% for post in entities.items %}
|
||||||
|
<div class="h-entry post_teaser tabindex="0">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col">
|
||||||
|
<a href="{{ url_for('activitypub.post_ap', post_id=post.id) }}" aria-label="{{ _('Read post') }}">{{ post.title }}</a>
|
||||||
|
</div>
|
||||||
|
<div class="col col-1">
|
||||||
|
{% include 'post/_post_notification_toggle.html' %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% else %}
|
||||||
|
<p>{{ _('You have not subscribed to any posts. Use the bell icon on each post to do so.') }}</p>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
|
18
app/templates/user/alerts/_topics.html
Normal file
18
app/templates/user/alerts/_topics.html
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
<div class="post_list">
|
||||||
|
<h2>{{ _('You will be notified of new posts in communities covered by these topics') }}</h2>
|
||||||
|
{% for topic in entities.items -%}
|
||||||
|
<div class="h-entry post_teaser tabindex="0">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col">
|
||||||
|
<a href="{{ url_for('topic.show_topic', topic_path=topic.machine_name) }}" aria-label="{{ _('Visit Topic') }}">{{ topic.name }}</a>
|
||||||
|
</div>
|
||||||
|
<div class="col col-1">
|
||||||
|
{% include 'topic/_notification_toggle.html' -%}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% else -%}
|
||||||
|
<p>{{ _('You have not subscribed to any topics. Use the bell icon on each topic to do so.') }}</p>
|
||||||
|
{% endfor -%}
|
||||||
|
</div>
|
||||||
|
|
17
app/templates/user/alerts/_type.html
Normal file
17
app/templates/user/alerts/_type.html
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
<div class="btn-group mt-1 mb-2" aria-label="{{ _('Alert type: ') }}">
|
||||||
|
<a href="/alerts/posts/{{ filter }}" class="btn {{ 'btn-primary' if type == 'posts' else 'btn-outline-secondary' }}">
|
||||||
|
{{ _('Posts') }}
|
||||||
|
</a>
|
||||||
|
<a href="/alerts/comments/{{ filter }}" class="btn {{ 'btn-primary' if type == 'comments' else 'btn-outline-secondary' }}">
|
||||||
|
{{ _('Comments') }}
|
||||||
|
</a>
|
||||||
|
<a href="/alerts/communities/{{ filter }}" class="btn {{ 'btn-primary' if type == 'communities' else 'btn-outline-secondary' }}">
|
||||||
|
{{ _('Communities') }}
|
||||||
|
</a>
|
||||||
|
<a href="/alerts/topics/{{ filter }}" class="btn {{ 'btn-primary' if type == 'topics' else 'btn-outline-secondary' }}">
|
||||||
|
{{ _('Topics') }}
|
||||||
|
</a>
|
||||||
|
<a href="/alerts/users/{{ filter }}" class="btn {{ 'btn-primary' if type == 'users' else 'btn-outline-secondary' }}">
|
||||||
|
{{ _('Users') }}
|
||||||
|
</a>
|
||||||
|
</div>
|
18
app/templates/user/alerts/_users.html
Normal file
18
app/templates/user/alerts/_users.html
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
<div class="post_list">
|
||||||
|
<h2>{{ _('You will be notified of new posts by these users') }}</h2>
|
||||||
|
{% for user in entities.items %}
|
||||||
|
<div class="h-entry post_teaser tabindex="0">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col">
|
||||||
|
<a href="{{ url_for('user.show_profile_by_id', user_id=user.id) }}" aria-label="{{ _('Visit User') }}">{{ user.title if user.title else user.user_name }}</a>
|
||||||
|
</div>
|
||||||
|
<div class="col col-1">
|
||||||
|
{% include 'user/_notification_toggle.html' %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% else %}
|
||||||
|
<p>{{ _('You have not subscribed to an alert for new content from any users. Use the bell icon on each person to do so.') }}</p>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
|
|
@ -12,12 +12,11 @@ from app.activitypub.signature import post_request, default_context
|
||||||
from app.activitypub.util import find_actor_or_create
|
from app.activitypub.util import find_actor_or_create
|
||||||
from app.auth.util import random_token
|
from app.auth.util import random_token
|
||||||
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, NOTIF_USER, POST_TYPE_VIDEO, POST_TYPE_LINK, \
|
from app.constants import *
|
||||||
POST_TYPE_IMAGE, POST_TYPE_POLL
|
|
||||||
from app.email import send_verification_email
|
from app.email import send_verification_email
|
||||||
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, NotificationSubscription, PostBookmark, PostReplyBookmark, read_posts
|
InstanceBlock, NotificationSubscription, PostBookmark, PostReplyBookmark, read_posts, Topic
|
||||||
from app.user import bp
|
from app.user import bp
|
||||||
from app.user.forms import ProfileForm, SettingsForm, DeleteAccountForm, ReportUserForm, \
|
from app.user.forms import ProfileForm, SettingsForm, DeleteAccountForm, ReportUserForm, \
|
||||||
FilterForm, KeywordFilterEditForm, RemoteFollowForm, ImportExportForm
|
FilterForm, KeywordFilterEditForm, RemoteFollowForm, ImportExportForm
|
||||||
|
@ -1143,6 +1142,86 @@ def user_bookmarks_comments():
|
||||||
next_url=next_url, prev_url=prev_url)
|
next_url=next_url, prev_url=prev_url)
|
||||||
|
|
||||||
|
|
||||||
|
@bp.route('/alerts')
|
||||||
|
@bp.route('/alerts/<type>/<filter>')
|
||||||
|
@login_required
|
||||||
|
def user_alerts(type='posts', filter='all'):
|
||||||
|
page = request.args.get('page', 1, type=int)
|
||||||
|
low_bandwidth = request.cookies.get('low_bandwidth', '0') == '1'
|
||||||
|
|
||||||
|
if type == 'comments':
|
||||||
|
if filter == 'mine':
|
||||||
|
entities = PostReply.query.filter_by(deleted=False, user_id=current_user.id).\
|
||||||
|
join(NotificationSubscription, NotificationSubscription.entity_id == PostReply.id).\
|
||||||
|
filter_by(type=NOTIF_REPLY, user_id=current_user.id).order_by(desc(NotificationSubscription.created_at))
|
||||||
|
elif filter == 'others':
|
||||||
|
entities = PostReply.query.filter(PostReply.deleted == False, PostReply.user_id != current_user.id).\
|
||||||
|
join(NotificationSubscription, NotificationSubscription.entity_id == PostReply.id).\
|
||||||
|
filter_by(type=NOTIF_REPLY, user_id=current_user.id).order_by(desc(NotificationSubscription.created_at))
|
||||||
|
else: # default to 'all' filter
|
||||||
|
entities = PostReply.query.filter_by(deleted=False).\
|
||||||
|
join(NotificationSubscription, NotificationSubscription.entity_id == PostReply.id).\
|
||||||
|
filter_by(type=NOTIF_REPLY, user_id=current_user.id).order_by(desc(NotificationSubscription.created_at))
|
||||||
|
title = _('Reply Alerts')
|
||||||
|
|
||||||
|
elif type == 'communities':
|
||||||
|
if filter == 'mine':
|
||||||
|
entities = Community.query.\
|
||||||
|
join(CommunityMember, CommunityMember.community_id == Community.id).\
|
||||||
|
filter_by(user_id=current_user.id, is_moderator=True).\
|
||||||
|
join(NotificationSubscription, NotificationSubscription.entity_id == CommunityMember.community_id).\
|
||||||
|
filter_by(type=NOTIF_COMMUNITY, user_id=current_user.id).order_by(desc(NotificationSubscription.created_at))
|
||||||
|
elif filter == 'others':
|
||||||
|
entities = Community.query.\
|
||||||
|
join(CommunityMember, CommunityMember.community_id == Community.id).\
|
||||||
|
filter_by(user_id=current_user.id, is_moderator=False).\
|
||||||
|
join(NotificationSubscription, NotificationSubscription.entity_id == CommunityMember.community_id).\
|
||||||
|
filter_by(type=NOTIF_COMMUNITY, user_id=current_user.id).order_by(desc(NotificationSubscription.created_at))
|
||||||
|
else: # default to 'all' filter
|
||||||
|
entities = Community.query.\
|
||||||
|
join(NotificationSubscription, NotificationSubscription.entity_id == Community.id).\
|
||||||
|
filter_by(type=NOTIF_COMMUNITY, user_id=current_user.id).order_by(desc(NotificationSubscription.created_at))
|
||||||
|
title = _('Community Alerts')
|
||||||
|
|
||||||
|
elif type == 'topics':
|
||||||
|
# ignore filter
|
||||||
|
entities = Topic.query.join(NotificationSubscription, NotificationSubscription.entity_id == Topic.id).\
|
||||||
|
filter_by(type=NOTIF_TOPIC, user_id=current_user.id).order_by(desc(NotificationSubscription.created_at))
|
||||||
|
title = _('Topic Alerts')
|
||||||
|
|
||||||
|
elif type == 'users':
|
||||||
|
# ignore filter
|
||||||
|
entities = User.query.join(NotificationSubscription, NotificationSubscription.entity_id == User.id).\
|
||||||
|
filter_by(type=NOTIF_USER, user_id=current_user.id).order_by(desc(NotificationSubscription.created_at))
|
||||||
|
title = _('User Alerts')
|
||||||
|
|
||||||
|
else: # default to 'posts' type
|
||||||
|
if filter == 'mine':
|
||||||
|
entities = Post.query.filter_by(deleted=False, user_id=current_user.id).\
|
||||||
|
join(NotificationSubscription, NotificationSubscription.entity_id == Post.id).\
|
||||||
|
filter_by(type=NOTIF_POST, user_id=current_user.id).order_by(desc(NotificationSubscription.created_at))
|
||||||
|
elif filter == 'others':
|
||||||
|
entities = Post.query.filter(Post.deleted == False, Post.user_id != current_user.id).\
|
||||||
|
join(NotificationSubscription, NotificationSubscription.entity_id == Post.id).\
|
||||||
|
filter_by(type=NOTIF_POST, user_id=current_user.id).order_by(desc(NotificationSubscription.created_at))
|
||||||
|
else: # default to 'all' filter
|
||||||
|
entities = Post.query.filter_by(deleted=False).\
|
||||||
|
join(NotificationSubscription, NotificationSubscription.entity_id == Post.id).\
|
||||||
|
filter_by(type=NOTIF_POST, user_id=current_user.id).order_by(desc(NotificationSubscription.created_at))
|
||||||
|
title = _('Post Alerts')
|
||||||
|
|
||||||
|
entities = entities.paginate(page=page, per_page=100 if not low_bandwidth else 50, error_out=False)
|
||||||
|
next_url = url_for('user.user_alerts', page=entities.next_num, type=type, filter=filter) if entities.has_next else None
|
||||||
|
prev_url = url_for('user.user_alerts', page=entities.prev_num, type=type, filter=filter) if entities.has_prev and page != 1 else None
|
||||||
|
|
||||||
|
return render_template('user/alerts.html', title=title, entities=entities,
|
||||||
|
low_bandwidth=low_bandwidth, user=current_user, type=type, filter=filter,
|
||||||
|
moderating_communities=moderating_communities(current_user.get_id()),
|
||||||
|
joined_communities=joined_communities(current_user.get_id()),
|
||||||
|
menu_topics=menu_topics(), site=g.site,
|
||||||
|
next_url=next_url, prev_url=prev_url)
|
||||||
|
|
||||||
|
|
||||||
@bp.route('/u/<actor>/fediverse_redirect', methods=['GET', 'POST'])
|
@bp.route('/u/<actor>/fediverse_redirect', methods=['GET', 'POST'])
|
||||||
def fediverse_redirect(actor):
|
def fediverse_redirect(actor):
|
||||||
actor = actor.strip()
|
actor = actor.strip()
|
||||||
|
|
Loading…
Add table
Reference in a new issue