user page redesign: add notifications feeds, other minor tweaks

for #442
pull/671/head
Ryan Barrett 2023-10-11 11:28:39 -07:00
rodzic f37baeba58
commit b1b2478b66
Nie znaleziono w bazie danych klucza dla tego podpisu
ID klucza GPG: 6BE31FDF4776E9D4
7 zmienionych plików z 72 dodań i 18 usunięć

Wyświetl plik

@ -110,7 +110,6 @@ def web_user_redirects(**kwargs):
@app.get(f'/ap/@<id>', defaults={'protocol': 'ap'})
def profile(protocol, id):
load_user(protocol, id)
query = Object.query(Object.users == g.user.key)
objects, before, after = fetch_objects(query, by=Object.updated)
num_followers, num_following = count_followers()
@ -120,7 +119,6 @@ def profile(protocol, id):
@app.get(f'/<any({",".join(PROTOCOLS)}):protocol>/<id>/home')
def home(protocol, id):
load_user(protocol, id)
query = Object.query(Object.feed == g.user.key)
objects, before, after = fetch_objects(query, by=Object.created)
return render_template('home.html', **TEMPLATE_VARS, **locals())
@ -132,6 +130,13 @@ def notifications(protocol, id):
query = Object.query(Object.notify == g.user.key)
objects, before, after = fetch_objects(query, by=Object.updated)
format = request.args.get('format')
if format:
return serve_feed(objects=objects, format=format,
title=f'Bridgy Fed notifications for {id}')
# notifications tab UI page
return render_template('notifications.html', **TEMPLATE_VARS, **locals())
@ -163,16 +168,30 @@ def count_followers():
return num_followers, num_following
@app.get(f'/<any({",".join(PROTOCOLS)}):protocol>/<id>/feed')
def feed(protocol, id):
format = request.args.get('format', 'html')
load_user(protocol, id)
query = Object.query(Object.feed == g.user.key)
objects, _, _ = fetch_objects(query, by=Object.created)
return serve_feed(objects=objects, format=request.args.get('format', 'html'),
title=f'Bridgy Fed feed for {id}')
def serve_feed(*, objects, format, title):
"""Generates a feed based on :class:`Object`s.
Args:
objects (sequence of models.Object)
format (str): ``html``, ``atom``, or ``rss``
title (str)
Returns:
str or (str, dict) tuple: Flask response
"""
if format not in ('html', 'atom', 'rss'):
error(f'format {format} not supported; expected html, atom, or rss')
load_user(protocol, id)
query = Object.query(Object.feed == g.user.key)
objects, _, _ = fetch_objects(query, by=Object.created)
activities = [obj.as1 for obj in objects if not obj.deleted]
# hydrate authors, actors, objects from stored Objects
@ -198,7 +217,6 @@ def feed(protocol, id):
'displayName': id,
'url': g.user.web_url(),
}
title = f'Bridgy Fed feed for {id}'
# TODO: inject/merge common.pretty_link into microformats2.render_content
# (specifically into hcard_to_html) somehow to convert Mastodon URLs to @-@

Wyświetl plik

@ -25,7 +25,7 @@
{% endif %}
</li>
{% else %}
<span class="big">None yet. Check back soon!</span>
<span class="big">No one yet. Check back soon!</span>
{% endfor %}
</ul>

Wyświetl plik

@ -56,7 +56,7 @@
</div>
</li>
{% else %}
<span class="big">None yet. Check back soon!</span>
<span class="big">No activity yet. Check back soon!</span>
{% endfor %}
</ul>

Wyświetl plik

@ -3,16 +3,16 @@
{% block title %}{{ g.user.handle_or_id() }}'s feed - Bridgy Fed{% endblock %}
{% block content %}
<div class="row big">Feed</div>
<div class="h-feed">
<div class="row big p-name">{{ title }}</div>
<link rel="stylesheet" href="/static/feed.css" type="text/css" />
<div class="row h-feed">
<div class="row">
{% for e in entries %}
{{ e|safe }}
{% else %}
Nothing yet. <a href="/#To+use+it">Follow more people</a>, check back soon!
{% endfor %}
</div>
</div>
{% endblock %}

Wyświetl plik

@ -4,8 +4,8 @@
{% block subtabs %}
<div class="row">
Subscribe:
<a href="{{ g.user.user_page_path('feed') }}">HTML</a>
&middot; <a href="{{ g.user.user_page_path('feed?format=atom') }}">Atom</a>
&middot; <a href="{{ g.user.user_page_path('feed?format=rss') }}">RSS</a>
<a href="{{ g.user.user_page_path('notifications?format=html') }}">HTML</a>
&middot; <a href="{{ g.user.user_page_path('notifications?format=atom') }}">Atom</a>
&middot; <a href="{{ g.user.user_page_path('notifications?format=rss') }}">RSS</a>
</div>
{% endblock subtabs %}

Wyświetl plik

@ -40,7 +40,8 @@
{{ g.user.user_link()|safe }}
&middot;
<nobr>
<a href="{{ g.user.web_url() }}" title="{{ g.user.__class__.__name__ }}">
<a href="{{ g.user.web_url() }}"
title="{{ g.user.__class__.__name__ }} (native)">
<span class="logo">{{ g.user.LOGO_HTML }}</span>
{{ g.user.handle_or_id() }}</a>

Wyświetl plik

@ -181,6 +181,37 @@ class PagesTest(TestCase):
got = self.client.get('/web/user.com/home')
self.assert_equals(200, got.status_code)
def test_notifications_fake(self):
self.make_user('fake:foo', cls=Fake)
got = self.client.get('/fa/fake:foo/notifications')
self.assert_equals(200, got.status_code)
def test_notifications_objects(self):
self.add_objects()
got = self.client.get('/web/user.com/notifications')
self.assert_equals(200, got.status_code)
def test_notifications_rss(self):
self.add_objects()
got = self.client.get('/web/user.com/notifications?format=rss')
self.assert_equals(200, got.status_code)
self.assert_equals(rss.CONTENT_TYPE, got.headers['Content-Type'])
self.assert_equals(self.EXPECTED, contents(rss.to_activities(got.text)))
def test_notifications_atom(self):
self.add_objects()
got = self.client.get('/web/user.com/notifications?format=atom')
self.assert_equals(200, got.status_code)
self.assert_equals(atom.CONTENT_TYPE, got.headers['Content-Type'])
self.assert_equals(self.EXPECTED, contents(atom.atom_to_activities(got.text)))
def test_notifications_html(self):
self.add_objects()
got = self.client.get('/web/user.com/notifications?format=html')
self.assert_equals(200, got.status_code)
self.assert_equals(self.EXPECTED,
contents(microformats2.html_to_activities(got.text)))
def test_followers_fake(self):
self.make_user('fake:foo', cls=Fake)
got = self.client.get('/fa/fake:foo/followers')
@ -294,12 +325,14 @@ class PagesTest(TestCase):
def test_feed_atom_empty(self):
got = self.client.get('/web/user.com/feed?format=atom')
self.assert_equals(200, got.status_code)
self.assert_equals(atom.CONTENT_TYPE, got.headers['Content-Type'])
self.assert_equals([], atom.atom_to_activities(got.text))
def test_feed_atom(self):
self.add_objects()
got = self.client.get('/web/user.com/feed?format=atom')
self.assert_equals(200, got.status_code)
self.assert_equals(atom.CONTENT_TYPE, got.headers['Content-Type'])
self.assert_equals(self.EXPECTED, contents(atom.atom_to_activities(got.text)))
# NOTE's and MENTION's authors; check for two instances
@ -315,12 +348,14 @@ class PagesTest(TestCase):
def test_feed_rss_empty(self):
got = self.client.get('/web/user.com/feed?format=rss')
self.assert_equals(200, got.status_code)
self.assert_equals(rss.CONTENT_TYPE, got.headers['Content-Type'])
self.assert_equals([], rss.to_activities(got.text))
def test_feed_rss(self):
self.add_objects()
got = self.client.get('/web/user.com/feed?format=rss')
self.assert_equals(200, got.status_code)
self.assert_equals(rss.CONTENT_TYPE, got.headers['Content-Type'])
self.assert_equals(self.EXPECTED, contents(rss.to_activities(got.text)))
# NOTE's and MENTION's authors; check for two instances