Bugfixes by @cwt (#42)

* check for missing actor in stream item

* reply on my own status

* fix img exceed div

* check for "actor" key in item.meta before render

* force UTF-8 text encoding

* check if a is a dict or string

* check d object must be dict to get url or id

* json/atom/rss feed

* handle missing root_id

* fix newer-link hover

* fix older-link position

* quick hack to support peertube video

* enable IndieAuth endpoint

* fix 500 when remote follow
This commit is contained in:
Thomas Sileo 2019-02-24 21:04:09 +01:00 committed by GitHub
parent 1926ba92fa
commit 1a7a02a221
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 72 additions and 22 deletions

View file

@ -523,8 +523,8 @@ def gen_feed():
fg.logo(ME.get("icon", {}).get("url")) fg.logo(ME.get("icon", {}).get("url"))
fg.language("en") fg.language("en")
for item in DB.activities.find( for item in DB.activities.find(
{"box": Box.OUTBOX.value, "type": "Create"}, limit=50 {"box": Box.OUTBOX.value, "type": "Create", "meta.deleted": False}, limit=10
): ).sort("_id", -1):
fe = fg.add_entry() fe = fg.add_entry()
fe.id(item["activity"]["object"].get("url")) fe.id(item["activity"]["object"].get("url"))
fe.link(href=item["activity"]["object"].get("url")) fe.link(href=item["activity"]["object"].get("url"))
@ -537,11 +537,11 @@ def json_feed(path: str) -> Dict[str, Any]:
"""JSON Feed (https://jsonfeed.org/) document.""" """JSON Feed (https://jsonfeed.org/) document."""
data = [] data = []
for item in DB.activities.find( for item in DB.activities.find(
{"box": Box.OUTBOX.value, "type": "Create"}, limit=50 {"box": Box.OUTBOX.value, "type": "Create", "meta.deleted": False}, limit=10
): ).sort("_id", -1):
data.append( data.append(
{ {
"id": item["id"], "id": item["activity"]["id"],
"url": item["activity"]["object"].get("url"), "url": item["activity"]["object"].get("url"),
"content_html": item["activity"]["object"]["content"], "content_html": item["activity"]["object"]["content"],
"content_text": html2text(item["activity"]["object"]["content"]), "content_text": html2text(item["activity"]["object"]["content"]),

73
app.py
View file

@ -189,7 +189,10 @@ ALLOWED_TAGS = [
def clean_html(html): def clean_html(html):
return bleach.clean(html, tags=ALLOWED_TAGS) try:
return bleach.clean(html, tags=ALLOWED_TAGS)
except:
return ""
_GRIDFS_CACHE: Dict[Tuple[Kind, str, Optional[int]], str] = {} _GRIDFS_CACHE: Dict[Tuple[Kind, str, Optional[int]], str] = {}
@ -282,9 +285,12 @@ def domain(url):
@app.template_filter() @app.template_filter()
def url_or_id(d): def url_or_id(d):
if "url" in d: if isinstance(d, dict):
return d["url"] if ("url" in d) and isinstance(d["url"], str):
return d["id"] return d["url"]
else:
return d["id"]
return ""
@app.template_filter() @app.template_filter()
@ -367,7 +373,9 @@ def _is_img(filename):
@app.template_filter() @app.template_filter()
def not_only_imgs(attachment): def not_only_imgs(attachment):
for a in attachment: for a in attachment:
if not _is_img(a["url"]): if isinstance(a, dict) and not _is_img(a["url"]):
return True
if isinstance(a, str) and not _is_img(a):
return True return True
return False return False
@ -961,7 +969,10 @@ def _build_thread(data, include_children=True):
): ):
_flatten(snode, level=level + 1) _flatten(snode, level=level + 1)
_flatten(idx[root_id]) try:
_flatten(idx[root_id])
except KeyError:
app.logger.info(f"{root_id} is not there! skipping")
return thread return thread
@ -1524,7 +1535,15 @@ def _user_api_arg(key: str, **kwargs):
def _user_api_get_note(from_outbox: bool = False): def _user_api_get_note(from_outbox: bool = False):
oid = _user_api_arg("id") oid = _user_api_arg("id")
app.logger.info(f"fetching {oid}") app.logger.info(f"fetching {oid}")
note = ap.parse_activity(get_backend().fetch_iri(oid), expected=ActivityType.NOTE) try:
note = ap.parse_activity(get_backend().fetch_iri(oid), expected=ActivityType.NOTE)
except:
try:
note = ap.parse_activity(get_backend().fetch_iri(oid), expected=ActivityType.VIDEO)
except:
raise ActivityNotFoundError(
"Expected Note or Video ActivityType, but got something else"
)
if from_outbox and not note.id.startswith(ID): if from_outbox and not note.id.startswith(ID):
raise NotFromOutboxError( raise NotFromOutboxError(
f"cannot load {note.id}, id must be owned by the server" f"cannot load {note.id}, id must be owned by the server"
@ -1876,12 +1895,8 @@ def followers():
) )
raw_followers, older_than, newer_than = paginated_query(DB.activities, q) raw_followers, older_than, newer_than = paginated_query(DB.activities, q)
followers = [] followers = [doc["meta"]["actor"]
for doc in raw_followers: for doc in raw_followers if "actor" in doc.get("meta", {})]
try:
followers.append(doc["meta"]["actor"])
except Exception:
pass
return render_template( return render_template(
"followers.html", "followers.html",
followers_data=followers, followers_data=followers,
@ -1909,7 +1924,9 @@ def following():
abort(404) abort(404)
following, older_than, newer_than = paginated_query(DB.activities, q) following, older_than, newer_than = paginated_query(DB.activities, q)
following = [(doc["remote_id"], doc["meta"]["object"]) for doc in following] following = [(doc["remote_id"], doc["meta"]["object"])
for doc in following
if "remote_id" in doc and "object" in doc.get("meta", {})]
return render_template( return render_template(
"following.html", "following.html",
following_data=following, following_data=following,
@ -2070,7 +2087,7 @@ def indieauth_flow():
return redirect(red) return redirect(red)
# @app.route('/indieauth', methods=['GET', 'POST']) @app.route('/indieauth', methods=['GET', 'POST'])
def indieauth_endpoint(): def indieauth_endpoint():
if request.method == "GET": if request.method == "GET":
if not session.get("logged_in"): if not session.get("logged_in"):
@ -2167,3 +2184,29 @@ def token_endpoint():
"client_id": payload["client_id"], "client_id": payload["client_id"],
} }
) )
@app.route("/feed.json")
def json_feed():
return Response(
response=json.dumps(
activitypub.json_feed("/feed.json")
),
headers={"Content-Type": "application/json"},
)
@app.route("/feed.atom")
def atom_feed():
return Response(
response=activitypub.gen_feed().atom_str(),
headers={"Content-Type": "application/atom+xml"},
)
@app.route("/feed.rss")
def rss_feed():
return Response(
response=activitypub.gen_feed().rss_str(),
headers={"Content-Type": "application/rss+xml"},
)

View file

@ -40,10 +40,11 @@ a:hover {
.lcolor { .lcolor {
color: $color-light; color: $color-light;
} }
.older-link, .newer-linker, .older-link:hover, .newer-link:hover { .older-link, .newer-link, .older-link:hover, .newer-link:hover {
text-decoration: none; text-decoration: none;
padding: 3px; padding: 3px;
} }
.older-link { float: left }
.newer-link { float: right } .newer-link { float: right }
.clear { clear: both; } .clear { clear: both; }
.remote-follow-button { .remote-follow-button {
@ -210,6 +211,7 @@ a:hover {
.note-wrapper { .note-wrapper {
flex: 1; flex: 1;
padding-left: 15px; padding-left: 15px;
overflow: hidden;
} }
.bottom-bar { margin-top:10px; } .bottom-bar { margin-top:10px; }

View file

@ -34,6 +34,7 @@
{% for item in outbox_data %} {% for item in outbox_data %}
{% if item | has_type('Announce') %} {% if item | has_type('Announce') %}
{% if "actor" in item.meta %}
{% set boost_actor = item.meta.actor %} {% set boost_actor = item.meta.actor %}
{% if session.logged_in %} {% if session.logged_in %}
<div style="margin-left:65px;padding-bottom:5px;margin-bottom:15px;"> <div style="margin-left:65px;padding-bottom:5px;margin-bottom:15px;">
@ -50,6 +51,7 @@
<span class="bar-item-no-hover"><a style="color:#808080;" href="{{ boost_actor.url | get_url }}">{{ boost_actor.name }}</a> boosted</span> <span class="bar-item-no-hover"><a style="color:#808080;" href="{{ boost_actor.url | get_url }}">{{ boost_actor.name }}</a> boosted</span>
</p> </p>
{% endif %} {% endif %}
{% endif %}
{% if item.meta.object %} {% if item.meta.object %}
{{ utils.display_note(item.meta.object, ui=False, meta={'actor': item.meta.object_actor}) }} {{ utils.display_note(item.meta.object, ui=False, meta={'actor': item.meta.object_actor}) }}
{% endif %} {% endif %}

View file

@ -8,6 +8,7 @@
<div id="notes"> <div id="notes">
{% for item in inbox_data %} {% for item in inbox_data %}
{% if 'actor' in item.meta %}
{% if item | has_type('Create') %} {% if item | has_type('Create') %}
{{ utils.display_note(item.activity.object, ui=True, meta=item.meta) }} {{ utils.display_note(item.activity.object, ui=True, meta=item.meta) }}
{% else %} {% else %}
@ -53,6 +54,7 @@
{% endif %} {% endif %}
{% endif %}
{% endif %} {% endif %}
{% endfor %} {% endfor %}

View file

@ -129,7 +129,6 @@
{% if session.logged_in %} {% if session.logged_in %}
{% if ui%} {% if ui%}
<a class="bar-item" href="/admin/new?reply={{ aid }}">reply</a>
{% if meta.boosted %} {% if meta.boosted %}
<form action="/api/undo" class="action-form" method="POST"> <form action="/api/undo" class="action-form" method="POST">
<input type="hidden" name="redirect" value="{{ redir }}"> <input type="hidden" name="redirect" value="{{ redir }}">
@ -195,6 +194,7 @@
<button type="submit" class="bar-item">block</button> <button type="submit" class="bar-item">block</button>
</form> </form>
{% endif %} {% endif %}
<a class="bar-item" href="/admin/new?reply={{ aid }}">reply</a>
{% endif %} {% endif %}

View file

@ -48,6 +48,7 @@ def fetch_og_metadata(user_agent, links):
logger.debug(f"skipping {l}") logger.debug(f"skipping {l}")
continue continue
r.encoding = 'UTF-8'
html = r.text html = r.text
try: try:
data = dict(opengraph.OpenGraph(html=html)) data = dict(opengraph.OpenGraph(html=html))