kopia lustrzana https://github.com/snarfed/bridgy-fed
rodzic
023f2aa536
commit
4e0fb6536c
|
@ -19,6 +19,13 @@ indexes:
|
|||
- name: updated
|
||||
direction: desc
|
||||
|
||||
- kind: Response
|
||||
properties:
|
||||
- name: direction
|
||||
- name: domain
|
||||
- name: created
|
||||
direction: desc
|
||||
|
||||
- kind: Follower
|
||||
properties:
|
||||
- name: dest
|
||||
|
|
39
pages.py
39
pages.py
|
@ -7,6 +7,7 @@ import urllib.parse
|
|||
|
||||
from flask import redirect, render_template, request
|
||||
from google.cloud.ndb.stats import KindStat
|
||||
from granary import as2, atom, microformats2, rss
|
||||
from oauth_dropins.webutil import flask_util, logs, util
|
||||
from oauth_dropins.webutil.flask_util import error
|
||||
from oauth_dropins.webutil.util import json_dumps, json_loads
|
||||
|
@ -108,6 +109,44 @@ def following(domain):
|
|||
)
|
||||
|
||||
|
||||
@app.get(f'/user/<regex("{common.DOMAIN_RE}"):domain>/feed')
|
||||
def feed(domain):
|
||||
format = request.args.get('format', 'html')
|
||||
if format not in ('html', 'atom', 'rss'):
|
||||
error(f'format {format} not supported; expected html, atom, or rss')
|
||||
|
||||
as2_activities, _, _ = Activity.query(
|
||||
Activity.domain == domain, Activity.direction == 'in'
|
||||
).order(-Activity.created
|
||||
).fetch_page(PAGE_SIZE)
|
||||
as1_activities = [as2.to_as1(json_loads(a.source_as2))
|
||||
for a in as2_activities
|
||||
if a.source_as2]
|
||||
as1_activities = [a for a in as1_activities
|
||||
if a.get('verb') not in ('like', 'update', 'follow')]
|
||||
|
||||
actor = {
|
||||
'displayName': domain,
|
||||
'url': f'https://{domain}',
|
||||
}
|
||||
title = f'Bridgy Fed feed for {domain}'
|
||||
extra = '<link rel="stylesheet" href="/static/feed.css" type="text/css" />'
|
||||
if not as1_activities:
|
||||
extra += '\n<p>Nothing yet. Follow more people, check back soon!</p>'
|
||||
|
||||
if format == 'html':
|
||||
return microformats2.activities_to_html(as1_activities, extra=extra,
|
||||
body_class='h-feed')
|
||||
elif format == 'atom':
|
||||
body = atom.activities_to_atom(as1_activities, actor=actor, title=title,
|
||||
request_url=request.url)
|
||||
return body, {'Content-Type': atom.CONTENT_TYPE}
|
||||
elif format == 'rss':
|
||||
body = rss.from_activities(as1_activities, actor=actor, title=title,
|
||||
feed_url=request.url)
|
||||
return body, {'Content-Type': rss.CONTENT_TYPE}
|
||||
|
||||
|
||||
@app.get('/responses') # deprecated
|
||||
def recent_deprecated():
|
||||
return redirect('/recent', code=301)
|
||||
|
|
|
@ -0,0 +1,24 @@
|
|||
/** From Bridgy's mf2 handlers:
|
||||
* https://github.com/snarfed/bridgy/blob/0b4b37cab61257510b45aee5b0678ba53af69d80/handlers.py#L43-L70
|
||||
*
|
||||
* Also see:
|
||||
* https://github.com/kevinmarks/unmung/blob/master/styles/hfeed.css
|
||||
* https://github.com/kevinmarks/unmung/blob/master/styles/mastoview.css
|
||||
*/
|
||||
body {
|
||||
font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
|
||||
}
|
||||
|
||||
.p-uid {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.u-photo {
|
||||
max-width: 50px;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.e-content {
|
||||
margin-top: 10px;
|
||||
font-size: 1.3em;
|
||||
}
|
|
@ -11,6 +11,9 @@
|
|||
<h3 style="display: inline">
|
||||
| <a href="/user/{{ domain }}/followers">{{ followers }} follower{% if followers != '1' %}s{% endif %}</a>
|
||||
| <a href="/user/{{ domain }}/following">following {{ following }}</a>
|
||||
| <a href="/user/{{ domain }}/feed">HTML</a>,
|
||||
<a href="/user/{{ domain }}/feed?format=atom">Atom</a>,
|
||||
<a href="/user/{{ domain }}/feed?format=rss">RSS</a> feeds
|
||||
</h3>
|
||||
</div>
|
||||
|
||||
|
|
|
@ -0,0 +1,69 @@
|
|||
"""Unit tests for pages.py."""
|
||||
from oauth_dropins.webutil import util
|
||||
from oauth_dropins.webutil.util import json_dumps, json_loads
|
||||
from granary import as2, atom, microformats2, rss
|
||||
|
||||
from models import Follower, Activity
|
||||
from . import testutil
|
||||
from .test_activitypub import LIKE, MENTION, NOTE, REPLY
|
||||
|
||||
|
||||
def contents(activities):
|
||||
return [a['object']['content'] for a in activities]
|
||||
|
||||
|
||||
class PagesTest(testutil.TestCase):
|
||||
|
||||
EXPECTED = contents([as2.to_as1(REPLY), as2.to_as1(NOTE)])
|
||||
|
||||
@staticmethod
|
||||
def add_activities():
|
||||
Activity(id='a', domain=['foo.com'], direction='in',
|
||||
source_as2=json_dumps(NOTE)).put()
|
||||
# different domain
|
||||
Activity(id='b', domain=['bar.org'], direction='in',
|
||||
source_as2=json_dumps(MENTION)).put()
|
||||
# empty, should be skipped
|
||||
Activity(id='c', domain=['foo.com'], direction='in').put()
|
||||
Activity(id='d', domain=['foo.com'], direction='in',
|
||||
source_as2=json_dumps(REPLY)).put()
|
||||
# wrong direction
|
||||
Activity(id='e', domain=['foo.com'], direction='out',
|
||||
source_as2=json_dumps(NOTE)).put()
|
||||
# skip Likes
|
||||
Activity(id='f', domain=['foo.com'], direction='in',
|
||||
source_as2=json_dumps(LIKE)).put()
|
||||
|
||||
def test_feed_html_empty(self):
|
||||
got = self.client.get('/user/foo.com/feed')
|
||||
self.assert_equals(200, got.status_code)
|
||||
self.assert_equals([], microformats2.html_to_activities(got.text))
|
||||
|
||||
def test_feed_html(self):
|
||||
self.add_activities()
|
||||
got = self.client.get('/user/foo.com/feed')
|
||||
self.assert_equals(200, got.status_code)
|
||||
self.assert_equals(self.EXPECTED,
|
||||
contents(microformats2.html_to_activities(got.text)))
|
||||
|
||||
def test_feed_atom_empty(self):
|
||||
got = self.client.get('/user/foo.com/feed?format=atom')
|
||||
self.assert_equals(200, got.status_code)
|
||||
self.assert_equals([], atom.atom_to_activities(got.text))
|
||||
|
||||
def test_feed_atom(self):
|
||||
self.add_activities()
|
||||
got = self.client.get('/user/foo.com/feed?format=atom')
|
||||
self.assert_equals(200, got.status_code)
|
||||
self.assert_equals(self.EXPECTED, contents(atom.atom_to_activities(got.text)))
|
||||
|
||||
def test_feed_rss_empty(self):
|
||||
got = self.client.get('/user/foo.com/feed?format=rss')
|
||||
self.assert_equals(200, got.status_code)
|
||||
self.assert_equals([], rss.to_activities(got.text))
|
||||
|
||||
def test_feed_rss(self):
|
||||
self.add_activities()
|
||||
got = self.client.get('/user/foo.com/feed?format=rss')
|
||||
self.assert_equals(200, got.status_code)
|
||||
self.assert_equals(self.EXPECTED, contents(rss.to_activities(got.text)))
|
|
@ -43,7 +43,7 @@ class RenderTest(testutil.TestCase):
|
|||
<html>
|
||||
<head><meta charset="utf-8">
|
||||
<meta http-equiv="refresh" content="0;url=abc"></head>
|
||||
<body>
|
||||
<body class="">
|
||||
<article class="h-entry">
|
||||
<span class="p-uid">http://this/reply</span>
|
||||
<a class="u-url" href="http://this/reply">http://this/reply</a>
|
||||
|
|
Ładowanie…
Reference in New Issue