diff options
Diffstat (limited to 'mediagoblin/federation/views.py')
-rw-r--r-- | mediagoblin/federation/views.py | 216 |
1 files changed, 161 insertions, 55 deletions
diff --git a/mediagoblin/federation/views.py b/mediagoblin/federation/views.py index 5b27144d..4c0593fc 100644 --- a/mediagoblin/federation/views.py +++ b/mediagoblin/federation/views.py @@ -20,10 +20,11 @@ import mimetypes from werkzeug.datastructures import FileStorage -from mediagoblin.decorators import oauth_required +from mediagoblin.decorators import oauth_required, require_active_login from mediagoblin.federation.decorators import user_has_privilege -from mediagoblin.db.models import User, MediaEntry, MediaComment -from mediagoblin.tools.response import redirect, json_response, json_error +from mediagoblin.db.models import User, MediaEntry, MediaComment, Activity +from mediagoblin.tools.response import redirect, json_response, json_error, \ + render_404, render_to_response from mediagoblin.meddleware.csrf import csrf_exempt from mediagoblin.submit.lib import new_upload_entry, api_upload_request, \ api_add_to_feed @@ -139,7 +140,7 @@ def feed_endpoint(request): return json_error("No such 'user' with id '{0}'".format(username), 404) if request.data: - data = json.loads(request.data) + data = json.loads(request.data.decode()) else: data = {"verb": None, "object": {}} @@ -354,21 +355,8 @@ def feed_endpoint(request): "items": [], } - - # Look up all the media to put in the feed (this will be changed - # when we get real feeds/inboxes/outboxes/activites) - for media in MediaEntry.query.all(): - item = { - "verb": "post", - "object": media.serialize(request), - "actor": media.get_uploader.serialize(request), - "content": "{0} posted a picture".format(request.user.username), - "id": media.id, - } - item["updated"] = item["object"]["updated"] - item["published"] = item["object"]["published"] - item["url"] = item["object"]["url"] - feed["items"].append(item) + for activity in Activity.query.filter_by(actor=request.user.id): + feed["items"].append(activity.serialize(request)) feed["totalItems"] = len(feed["items"]) return json_response(feed) @@ -376,7 +364,7 @@ def feed_endpoint(request): @oauth_required def object_endpoint(request): """ Lookup for a object type """ - object_type = request.matchdict["objectType"] + object_type = request.matchdict["object_type"] try: object_id = int(request.matchdict["id"]) except ValueError: @@ -408,17 +396,17 @@ def object_comments(request): media = MediaEntry.query.filter_by(id=request.matchdict["id"]).first() if media is None: return json_error("Can't find '{0}' with ID '{1}'".format( - request.matchdict["objectType"], + request.matchdict["object_type"], request.matchdict["id"] ), 404) - comments = response.serialize(request) + comments = media.serialize(request) comments = comments.get("replies", { "totalItems": 0, "items": [], "url": request.urlgen( "mediagoblin.federation.object.comments", - objectType=media.objectType, + object_type=media.object_type, id=media.id, qualified=True ) @@ -432,42 +420,129 @@ def object_comments(request): return json_response(comments) ## -# Well known +# RFC6415 - Web Host Metadata ## def host_meta(request): - """ /.well-known/host-meta - provide URLs to resources """ - links = [] + """ + This provides the host-meta URL information that is outlined + in RFC6415. By default this should provide XRD+XML however + if the client accepts JSON we will provide that over XRD+XML. + The 'Accept' header is used to decude this. - links.append({ - "ref": "registration_endpoint", - "href": request.urlgen( - "mediagoblin.oauth.client_register", - qualified=True - ), - }) - links.append({ - "ref": "http://apinamespace.org/oauth/request_token", - "href": request.urlgen( - "mediagoblin.oauth.request_token", - qualified=True - ), - }) - links.append({ - "ref": "http://apinamespace.org/oauth/authorize", - "href": request.urlgen( - "mediagoblin.oauth.authorize", - qualified=True - ), - }) - links.append({ - "ref": "http://apinamespace.org/oauth/access_token", - "href": request.urlgen( - "mediagoblin.oauth.access_token", - qualified=True - ), - }) + A client should use this endpoint to determine what URLs to + use for OAuth endpoints. + """ + + links = [ + { + "rel": "lrdd", + "type": "application/json", + "href": request.urlgen( + "mediagoblin.webfinger.well-known.webfinger", + qualified=True + ) + }, + { + "rel": "registration_endpoint", + "href": request.urlgen( + "mediagoblin.oauth.client_register", + qualified=True + ), + }, + { + "rel": "http://apinamespace.org/oauth/request_token", + "href": request.urlgen( + "mediagoblin.oauth.request_token", + qualified=True + ), + }, + { + "rel": "http://apinamespace.org/oauth/authorize", + "href": request.urlgen( + "mediagoblin.oauth.authorize", + qualified=True + ), + }, + { + "rel": "http://apinamespace.org/oauth/access_token", + "href": request.urlgen( + "mediagoblin.oauth.access_token", + qualified=True + ), + }, + { + "rel": "http://apinamespace.org/activitypub/whoami", + "href": request.urlgen( + "mediagoblin.webfinger.whoami", + qualified=True + ), + }, + ] + + if "application/json" in request.accept_mimetypes: + return json_response({"links": links}) + + # provide XML+XRD + return render_to_response( + request, + "mediagoblin/federation/host-meta.xml", + {"links": links}, + mimetype="application/xrd+xml" + ) + +def lrdd_lookup(request): + """ + This is the lrdd endpoint which can lookup a user (or + other things such as activities). This is as specified by + RFC6415. + + The cleint must provide a 'resource' as a GET parameter which + should be the query to be looked up. + """ + + if "resource" not in request.args: + return json_error("No resource parameter", status=400) + + resource = request.args["resource"] + + if "@" in resource: + # Lets pull out the username + resource = resource[5:] if resource.startswith("acct:") else resource + username, host = resource.split("@", 1) + + # Now lookup the user + user = User.query.filter_by(username=username).first() + + if user is None: + return json_error( + "Can't find 'user' with username '{0}'".format(username)) + + return json_response([ + { + "rel": "http://webfinger.net/rel/profile-page", + "href": user.url_for_self(request.urlgen), + "type": "text/html" + }, + { + "rel": "self", + "href": request.urlgen( + "mediagoblin.federation.user", + username=user.username, + qualified=True + ) + }, + { + "rel": "activity-outbox", + "href": request.urlgen( + "mediagoblin.federation.feed", + username=user.username, + qualified=True + ) + } + ]) + else: + return json_error("Unrecognized resource parameter", status=404) - return json_response({"links": links}) def whoami(request): """ /api/whoami - HTTP redirect to API profile """ @@ -481,3 +556,34 @@ def whoami(request): ) return redirect(request, location=profile) + +@require_active_login +def activity_view(request): + """ /<username>/activity/<id> - Display activity + + This should display a HTML presentation of the activity + this is NOT an API endpoint. + """ + # Get the user object. + username = request.matchdict["username"] + user = User.query.filter_by(username=username).first() + + activity_id = request.matchdict["id"] + + if request.user is None: + return render_404(request) + + activity = Activity.query.filter_by( + id=activity_id, + author=user.id + ).first() + if activity is None: + return render_404(request) + + return render_to_response( + request, + "mediagoblin/federation/activity.html", + {"activity": activity} + ) + + |