aboutsummaryrefslogtreecommitdiffstats
path: root/mediagoblin/federation/views.py
diff options
context:
space:
mode:
Diffstat (limited to 'mediagoblin/federation/views.py')
-rw-r--r--mediagoblin/federation/views.py216
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}
+ )
+
+