mirror of
https://git.sr.ht/~tsileo/microblog.pub
synced 2024-11-15 03:04:28 +00:00
Cleanup JSON outputs
This commit is contained in:
parent
dad3dae988
commit
681cfe5e54
5 changed files with 58 additions and 75 deletions
8
app.py
8
app.py
|
@ -14,7 +14,6 @@ from flask import Flask
|
||||||
from flask import Response
|
from flask import Response
|
||||||
from flask import abort
|
from flask import abort
|
||||||
from flask import g
|
from flask import g
|
||||||
from flask import jsonify as flask_jsonify
|
|
||||||
from flask import redirect
|
from flask import redirect
|
||||||
from flask import render_template
|
from flask import render_template
|
||||||
from flask import request
|
from flask import request
|
||||||
|
@ -67,6 +66,7 @@ from core.shared import activitypubify
|
||||||
from core.shared import csrf
|
from core.shared import csrf
|
||||||
from core.shared import htmlify
|
from core.shared import htmlify
|
||||||
from core.shared import is_api_request
|
from core.shared import is_api_request
|
||||||
|
from core.shared import jsonify
|
||||||
from core.shared import login_required
|
from core.shared import login_required
|
||||||
from core.shared import noindex
|
from core.shared import noindex
|
||||||
from core.shared import paginated_query
|
from core.shared import paginated_query
|
||||||
|
@ -173,7 +173,7 @@ def handle_value_error(error):
|
||||||
logger.error(
|
logger.error(
|
||||||
f"caught value error for {g.request_id}: {error!r}, {traceback.format_tb(error.__traceback__)}"
|
f"caught value error for {g.request_id}: {error!r}, {traceback.format_tb(error.__traceback__)}"
|
||||||
)
|
)
|
||||||
response = flask_jsonify(message=error.args[0], request_id=g.request_id)
|
response = jsonify({"message": error.args[0], "request_id": g.request_id})
|
||||||
response.status_code = 400
|
response.status_code = 400
|
||||||
return response
|
return response
|
||||||
|
|
||||||
|
@ -183,7 +183,7 @@ def handle_activitypub_error(error):
|
||||||
logger.error(
|
logger.error(
|
||||||
f"caught activitypub error for {g.request_id}: {error!r}, {traceback.format_tb(error.__traceback__)}"
|
f"caught activitypub error for {g.request_id}: {error!r}, {traceback.format_tb(error.__traceback__)}"
|
||||||
)
|
)
|
||||||
response = flask_jsonify({**error.to_dict(), "request_id": g.request_id})
|
response = jsonify({**error.to_dict(), "request_id": g.request_id})
|
||||||
response.status_code = error.status_code
|
response.status_code = error.status_code
|
||||||
return response
|
return response
|
||||||
|
|
||||||
|
@ -193,7 +193,7 @@ def handle_task_error(error):
|
||||||
logger.error(
|
logger.error(
|
||||||
f"caught activitypub error for {g.request_id}: {error!r}, {traceback.format_tb(error.__traceback__)}"
|
f"caught activitypub error for {g.request_id}: {error!r}, {traceback.format_tb(error.__traceback__)}"
|
||||||
)
|
)
|
||||||
response = flask_jsonify({"traceback": error.message, "request_id": g.request_id})
|
response = jsonify({"traceback": error.message, "request_id": g.request_id})
|
||||||
response.status_code = 500
|
response.status_code = 500
|
||||||
return response
|
return response
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
import json
|
|
||||||
import mimetypes
|
import mimetypes
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from datetime import timedelta
|
from datetime import timedelta
|
||||||
|
@ -10,7 +9,6 @@ from typing import List
|
||||||
|
|
||||||
import flask
|
import flask
|
||||||
from bson.objectid import ObjectId
|
from bson.objectid import ObjectId
|
||||||
from flask import Response
|
|
||||||
from flask import abort
|
from flask import abort
|
||||||
from flask import current_app as app
|
from flask import current_app as app
|
||||||
from flask import redirect
|
from flask import redirect
|
||||||
|
@ -41,6 +39,7 @@ from core.meta import _meta
|
||||||
from core.shared import MY_PERSON
|
from core.shared import MY_PERSON
|
||||||
from core.shared import _Response
|
from core.shared import _Response
|
||||||
from core.shared import csrf
|
from core.shared import csrf
|
||||||
|
from core.shared import jsonify
|
||||||
from core.shared import login_required
|
from core.shared import login_required
|
||||||
from core.tasks import Tasks
|
from core.tasks import Tasks
|
||||||
from utils import emojis
|
from utils import emojis
|
||||||
|
@ -124,7 +123,7 @@ def _user_api_response(**kwargs) -> _Response:
|
||||||
if _redirect:
|
if _redirect:
|
||||||
return redirect(_redirect)
|
return redirect(_redirect)
|
||||||
|
|
||||||
resp = flask.jsonify(**kwargs)
|
resp = jsonify(kwargs)
|
||||||
resp.status_code = 201
|
resp.status_code = 201
|
||||||
return resp
|
return resp
|
||||||
|
|
||||||
|
@ -132,7 +131,7 @@ def _user_api_response(**kwargs) -> _Response:
|
||||||
@blueprint.route("/api/key")
|
@blueprint.route("/api/key")
|
||||||
@login_required
|
@login_required
|
||||||
def api_user_key() -> _Response:
|
def api_user_key() -> _Response:
|
||||||
return flask.jsonify(api_key=ADMIN_API_KEY)
|
return jsonify({"api_key": ADMIN_API_KEY})
|
||||||
|
|
||||||
|
|
||||||
@blueprint.route("/note/delete", methods=["POST"])
|
@blueprint.route("/note/delete", methods=["POST"])
|
||||||
|
@ -575,25 +574,24 @@ def api_follow() -> _Response:
|
||||||
def api_debug() -> _Response:
|
def api_debug() -> _Response:
|
||||||
"""Endpoint used/needed for testing, only works in DEBUG_MODE."""
|
"""Endpoint used/needed for testing, only works in DEBUG_MODE."""
|
||||||
if not DEBUG_MODE:
|
if not DEBUG_MODE:
|
||||||
return flask.jsonify(message="DEBUG_MODE is off")
|
return jsonify({"message": "DEBUG_MODE is off"})
|
||||||
|
|
||||||
if request.method == "DELETE":
|
if request.method == "DELETE":
|
||||||
_drop_db()
|
_drop_db()
|
||||||
return flask.jsonify(message="DB dropped")
|
return jsonify(dict(message="DB dropped"))
|
||||||
|
|
||||||
return flask.jsonify(
|
return jsonify(
|
||||||
inbox=DB.activities.count({"box": Box.INBOX.value}),
|
dict(
|
||||||
outbox=DB.activities.count({"box": Box.OUTBOX.value}),
|
inbox=DB.activities.count({"box": Box.INBOX.value}),
|
||||||
outbox_data=without_id(DB.activities.find({"box": Box.OUTBOX.value})),
|
outbox=DB.activities.count({"box": Box.OUTBOX.value}),
|
||||||
|
outbox_data=without_id(DB.activities.find({"box": Box.OUTBOX.value})),
|
||||||
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@blueprint.route("/stream")
|
@blueprint.route("/stream")
|
||||||
@api_required
|
@api_required
|
||||||
def api_stream() -> _Response:
|
def api_stream() -> _Response:
|
||||||
return Response(
|
return jsonify(
|
||||||
response=json.dumps(
|
feed.build_inbox_json_feed("/api/stream", request.args.get("cursor"))
|
||||||
feed.build_inbox_json_feed("/api/stream", request.args.get("cursor"))
|
|
||||||
),
|
|
||||||
headers={"Content-Type": "application/json"},
|
|
||||||
)
|
)
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
import binascii
|
import binascii
|
||||||
import json
|
|
||||||
import os
|
import os
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from datetime import timedelta
|
from datetime import timedelta
|
||||||
|
@ -20,6 +19,7 @@ from config import DB
|
||||||
from config import JWT
|
from config import JWT
|
||||||
from core.shared import _get_ip
|
from core.shared import _get_ip
|
||||||
from core.shared import htmlify
|
from core.shared import htmlify
|
||||||
|
from core.shared import jsonify
|
||||||
from core.shared import login_required
|
from core.shared import login_required
|
||||||
|
|
||||||
blueprint = flask.Blueprint("indieauth", __name__)
|
blueprint = flask.Blueprint("indieauth", __name__)
|
||||||
|
@ -27,11 +27,7 @@ blueprint = flask.Blueprint("indieauth", __name__)
|
||||||
|
|
||||||
def build_auth_resp(payload):
|
def build_auth_resp(payload):
|
||||||
if request.headers.get("Accept") == "application/json":
|
if request.headers.get("Accept") == "application/json":
|
||||||
return Response(
|
return jsonify(payload)
|
||||||
status=200,
|
|
||||||
headers={"Content-Type": "application/json"},
|
|
||||||
response=json.dumps(payload),
|
|
||||||
)
|
|
||||||
return Response(
|
return Response(
|
||||||
status=200,
|
status=200,
|
||||||
headers={"Content-Type": "application/x-www-form-urlencoded"},
|
headers={"Content-Type": "application/x-www-form-urlencoded"},
|
||||||
|
|
|
@ -1,9 +1,7 @@
|
||||||
import json
|
|
||||||
import mimetypes
|
import mimetypes
|
||||||
from typing import Any
|
from typing import Any
|
||||||
|
|
||||||
import flask
|
import flask
|
||||||
from flask import Response
|
|
||||||
from flask import abort
|
from flask import abort
|
||||||
from flask import request
|
from flask import request
|
||||||
from little_boxes import activitypub as ap
|
from little_boxes import activitypub as ap
|
||||||
|
@ -11,6 +9,7 @@ from little_boxes import activitypub as ap
|
||||||
import config
|
import config
|
||||||
from config import DB
|
from config import DB
|
||||||
from core.meta import Box
|
from core.meta import Box
|
||||||
|
from core.shared import jsonify
|
||||||
|
|
||||||
blueprint = flask.Blueprint("well_known", __name__)
|
blueprint = flask.Blueprint("well_known", __name__)
|
||||||
|
|
||||||
|
@ -45,22 +44,21 @@ def wellknown_webfinger() -> Any:
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
|
|
||||||
return Response(
|
return jsonify(out, "application/jrd+json; charset=utf-8")
|
||||||
response=json.dumps(out),
|
|
||||||
headers={"Content-Type": "application/jrd+json; charset=utf-8"},
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
@blueprint.route("/.well-known/nodeinfo")
|
@blueprint.route("/.well-known/nodeinfo")
|
||||||
def wellknown_nodeinfo() -> Any:
|
def wellknown_nodeinfo() -> Any:
|
||||||
"""Exposes the NodeInfo endpoint (http://nodeinfo.diaspora.software/)."""
|
"""Exposes the NodeInfo endpoint (http://nodeinfo.diaspora.software/)."""
|
||||||
return flask.jsonify(
|
return jsonify(
|
||||||
links=[
|
{
|
||||||
{
|
"links": [
|
||||||
"rel": "http://nodeinfo.diaspora.software/ns/schema/2.1",
|
{
|
||||||
"href": f"{config.ID}/nodeinfo",
|
"rel": "http://nodeinfo.diaspora.software/ns/schema/2.1",
|
||||||
}
|
"href": f"{config.ID}/nodeinfo",
|
||||||
]
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@ -73,29 +71,25 @@ def nodeinfo() -> Any:
|
||||||
"type": {"$in": [ap.ActivityType.CREATE.value, ap.ActivityType.ANNOUNCE.value]},
|
"type": {"$in": [ap.ActivityType.CREATE.value, ap.ActivityType.ANNOUNCE.value]},
|
||||||
}
|
}
|
||||||
|
|
||||||
response = json.dumps(
|
out = {
|
||||||
{
|
"version": "2.1",
|
||||||
"version": "2.1",
|
"software": {
|
||||||
"software": {
|
"name": "microblogpub",
|
||||||
"name": "microblogpub",
|
"version": config.VERSION,
|
||||||
"version": config.VERSION,
|
"repository": "https://github.com/tsileo/microblog.pub",
|
||||||
"repository": "https://github.com/tsileo/microblog.pub",
|
|
||||||
},
|
|
||||||
"protocols": ["activitypub"],
|
|
||||||
"services": {"inbound": [], "outbound": []},
|
|
||||||
"openRegistrations": False,
|
|
||||||
"usage": {"users": {"total": 1}, "localPosts": DB.activities.count(q)},
|
|
||||||
"metadata": {
|
|
||||||
"nodeName": f"@{config.USERNAME}@{config.DOMAIN}",
|
|
||||||
"version": config.VERSION,
|
|
||||||
"versionDate": config.VERSION_DATE,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
return Response(
|
|
||||||
headers={
|
|
||||||
"Content-Type": "application/json; profile=http://nodeinfo.diaspora.software/ns/schema/2.1#"
|
|
||||||
},
|
},
|
||||||
response=response,
|
"protocols": ["activitypub"],
|
||||||
|
"services": {"inbound": [], "outbound": []},
|
||||||
|
"openRegistrations": False,
|
||||||
|
"usage": {"users": {"total": 1}, "localPosts": DB.activities.count(q)},
|
||||||
|
"metadata": {
|
||||||
|
"nodeName": f"@{config.USERNAME}@{config.DOMAIN}",
|
||||||
|
"version": config.VERSION,
|
||||||
|
"versionDate": config.VERSION_DATE,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
return jsonify(
|
||||||
|
out,
|
||||||
|
"application/json; profile=http://nodeinfo.diaspora.software/ns/schema/2.1#",
|
||||||
)
|
)
|
||||||
|
|
|
@ -48,7 +48,7 @@ MY_PERSON = ap.Person(**ME)
|
||||||
@lru_cache(512)
|
@lru_cache(512)
|
||||||
def build_resp(resp):
|
def build_resp(resp):
|
||||||
"""Encode the response to gzip if supported by the client."""
|
"""Encode the response to gzip if supported by the client."""
|
||||||
headers = {}
|
headers = {"Cache-Control": "max-age=0, private, must-revalidate"}
|
||||||
accept_encoding = request.headers.get("Accept-Encoding", "")
|
accept_encoding = request.headers.get("Accept-Encoding", "")
|
||||||
if "gzip" in accept_encoding.lower():
|
if "gzip" in accept_encoding.lower():
|
||||||
return (
|
return (
|
||||||
|
@ -59,15 +59,15 @@ def build_resp(resp):
|
||||||
return resp, headers
|
return resp, headers
|
||||||
|
|
||||||
|
|
||||||
|
def jsonify(data, content_type="application/json"):
|
||||||
|
resp, headers = build_resp(json.dumps(data))
|
||||||
|
return Response(headers={**headers, "Content-Type": content_type}, response=resp)
|
||||||
|
|
||||||
|
|
||||||
def htmlify(data):
|
def htmlify(data):
|
||||||
resp, headers = build_resp(data)
|
resp, headers = build_resp(data)
|
||||||
return Response(
|
return Response(
|
||||||
response=resp,
|
response=resp, headers={**headers, "Content-Type": "text/html; charset=utf-8"}
|
||||||
headers={
|
|
||||||
**headers,
|
|
||||||
"Content-Type": "text/html; charset=utf-8",
|
|
||||||
"Cache-Control": "max-age=0, private, must-revalidate",
|
|
||||||
},
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@ -76,12 +76,7 @@ def activitypubify(**data):
|
||||||
data["@context"] = config.DEFAULT_CTX
|
data["@context"] = config.DEFAULT_CTX
|
||||||
resp, headers = build_resp(json.dumps(data))
|
resp, headers = build_resp(json.dumps(data))
|
||||||
return Response(
|
return Response(
|
||||||
response=resp,
|
response=resp, headers={**headers, "Content-Type": "application/activity+json"}
|
||||||
headers={
|
|
||||||
**headers,
|
|
||||||
"Cache-Control": "max-age=0, private, must-revalidate",
|
|
||||||
"Content-Type": "application/activity+json",
|
|
||||||
},
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue