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:
parent
1926ba92fa
commit
1a7a02a221
7 changed files with 72 additions and 22 deletions
|
@ -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
73
app.py
|
@ -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"},
|
||||||
|
)
|
||||||
|
|
|
@ -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; }
|
||||||
|
|
|
@ -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 %}
|
||||||
|
|
|
@ -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 %}
|
||||||
|
|
||||||
|
|
|
@ -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 %}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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))
|
||||||
|
|
Loading…
Reference in a new issue