diff options
Diffstat (limited to 'mediagoblin/federation/views.py')
-rw-r--r-- | mediagoblin/federation/views.py | 411 |
1 files changed, 227 insertions, 184 deletions
diff --git a/mediagoblin/federation/views.py b/mediagoblin/federation/views.py index f178a3fb..3d6953a7 100644 --- a/mediagoblin/federation/views.py +++ b/mediagoblin/federation/views.py @@ -31,47 +31,70 @@ from mediagoblin.submit.lib import new_upload_entry, api_upload_request, \ # MediaTypes from mediagoblin.media_types.image import MEDIA_TYPE as IMAGE_MEDIA_TYPE +# Getters +def get_profile(request): + """ + Gets the user's profile for the endpoint requested. + + For example an endpoint which is /api/{username}/feed + as /api/cwebber/feed would get cwebber's profile. This + will return a tuple (username, user_profile). If no user + can be found then this function returns a (None, None). + """ + username = request.matchdict["username"] + user = User.query.filter_by(username=username).first() + + if user is None: + return None, None + + return user, user.serialize(request) + + +# Endpoints @oauth_required -def profile(request, raw=False): +def profile_endpoint(request): """ This is /api/user/<username>/profile - This will give profile info """ - user = request.matchdict["username"] - requested_user = User.query.filter_by(username=user).first() + user, user_profile = get_profile(request) if user is None: + username = request.matchdict["username"] return json_error( - "No such 'user' with id '{0}'".format(user), + "No such 'user' with username '{0}'".format(username), status=404 ) - if raw: - return (requested_user.username, requested_user.serialize(request)) - # user profiles are public so return information - return json_response(requested_user.serialize(request)) + return json_response(user_profile) @oauth_required -def user(request): +def user_endpoint(request): """ This is /api/user/<username> - This will get the user """ - user, user_profile = profile(request, raw=True) - data = { + user, user_profile = get_profile(request) + + if user is None: + username = request.matchdict["username"] + return json_error( + "No such 'user' with username '{0}'".format(username), + status=404 + ) + + return json_response({ "nickname": user.username, "updated": user.created.isoformat(), "published": user.created.isoformat(), "profile": user_profile, - } - - return json_response(data) + }) @oauth_required @csrf_exempt @user_has_privilege(u'uploader') -def uploads(request): +def uploads_endpoint(request): """ Endpoint for file uploads """ - user = request.matchdict["username"] - requested_user = User.query.filter_by(username=user).first() + username = request.matchdict["username"] + requested_user = User.query.filter_by(username=username).first() if requested_user is None: - return json_error("No such 'user' with id '{0}'".format(user), 404) + return json_error("No such 'user' with id '{0}'".format(username), 404) if request.method == "POST": # Ensure that the user is only able to upload to their own @@ -85,7 +108,9 @@ def uploads(request): # Wrap the data in the werkzeug file wrapper if "Content-Type" not in request.headers: return json_error( - "Must supply 'Content-Type' header to upload media.") + "Must supply 'Content-Type' header to upload media." + ) + mimetype = request.headers["Content-Type"] filename = mimetypes.guess_all_extensions(mimetype) filename = 'unknown' + filename[0] if filename else filename @@ -104,156 +129,179 @@ def uploads(request): @oauth_required @csrf_exempt -def feed(request): +def feed_endpoint(request): """ Handles the user's outbox - /api/user/<username>/feed """ - user = request.matchdict["username"] - requested_user = User.query.filter_by(username=user).first() + username = request.matchdict["username"] + requested_user = User.query.filter_by(username=username).first() # check if the user exists if requested_user is None: - return json_error("No such 'user' with id '{0}'".format(user), 404) + return json_error("No such 'user' with id '{0}'".format(username), 404) if request.data: data = json.loads(request.data) else: data = {"verb": None, "object": {}} - # We need to check that the user they're posting to is - # the person that they are. - if request.method in ["POST", "PUT"] and \ - requested_user.id != request.user.id: - - return json_error( - "Not able to post to another users feed.", - status=403 - ) - if request.method == "POST" and data["verb"] == "post": - obj = data.get("object", None) - if obj is None: - return json_error("Could not find 'object' element.") + if request.method in ["POST", "PUT"]: + # Validate that the activity is valid + if "verb" not in data or "object" not in data: + return json_error("Invalid activity provided.") - if obj.get("objectType", None) == "comment": - # post a comment - if not request.user.has_privilege(u'commenter'): - return json_error( - "Privilege 'commenter' required to comment.", - status=403 - ) - - comment = MediaComment(author=request.user.id) - comment.unserialize(data["object"]) - comment.save() - data = {"verb": "post", "object": comment.serialize(request)} - return json_response(data) - - elif obj.get("objectType", None) == "image": - # Posting an image to the feed - media_id = int(data["object"]["id"]) - media = MediaEntry.query.filter_by(id=media_id).first() - if media is None: - return json_response( - "No such 'image' with id '{0}'".format(id=media_id), - status=404 - ) - - if not media.unserialize(data["object"]): - return json_error( - "Invalid 'image' with id '{0}'".format(media_id) - ) - - media.save() - api_add_to_feed(request, media) - - return json_response({ - "verb": "post", - "object": media.serialize(request) - }) - - elif obj.get("objectType", None) is None: - # They need to tell us what type of object they're giving us. - return json_error("No objectType specified.") - else: - # Oh no! We don't know about this type of object (yet) - object_type = obj.get("objectType", None) - return json_error("Unknown object type '{0}'.".format(object_type)) - - elif request.method in ["PUT", "POST"] and data["verb"] == "update": - # Check we've got a valid object - obj = data.get("object", None) - - if obj is None: - return json_error("Could not find 'object' element.") - - if "objectType" not in obj: - return json_error("No objectType specified.") - - if "id" not in obj: - return json_error("Object ID has not been specified.") - - obj_id = obj["id"] - - # Now try and find object - if obj["objectType"] == "comment": - if not request.user.has_privilege(u'commenter'): - return json_error( - "Privilege 'commenter' required to comment.", - status=403 - ) + # Check that the verb is valid + if data["verb"] not in ["post", "update"]: + return json_error("Verb not yet implemented", 501) - comment = MediaComment.query.filter_by(id=obj_id).first() - if comment is None: - return json_error( - "No such 'comment' with id '{0}'.".format(obj_id) - ) - - # Check that the person trying to update the comment is - # the author of the comment. - if comment.author != request.user.id: - return json_error( - "Only author of comment is able to update comment.", - status=403 - ) - - if not comment.unserialize(data["object"]): - return json_error( - "Invalid 'comment' with id '{0}'".format(obj_id) - ) - - comment.save() - - activity = { - "verb": "update", - "object": comment.serialize(request), - } - return json_response(activity) - - elif obj["objectType"] == "image": - image = MediaEntry.query.filter_by(id=obj_id).first() - if image is None: - return json_error( - "No such 'image' with the id '{0}'.".format(obj_id) - ) - - # Check that the person trying to update the comment is - # the author of the comment. - if image.uploader != request.user.id: - return json_error( - "Only uploader of image is able to update image.", - status=403 - ) + # We need to check that the user they're posting to is + # the person that they are. + if requested_user.id != request.user.id: + return json_error( + "Not able to post to another users feed.", + status=403 + ) - if not image.unserialize(obj): + # Handle new posts + if data["verb"] == "post": + obj = data.get("object", None) + if obj is None: + return json_error("Could not find 'object' element.") + + if obj.get("objectType", None) == "comment": + # post a comment + if not request.user.has_privilege(u'commenter'): + return json_error( + "Privilege 'commenter' required to comment.", + status=403 + ) + + comment = MediaComment(author=request.user.id) + comment.unserialize(data["object"]) + comment.save() + data = { + "verb": "post", + "object": comment.serialize(request) + } + return json_response(data) + + elif obj.get("objectType", None) == "image": + # Posting an image to the feed + media_id = int(data["object"]["id"]) + media = MediaEntry.query.filter_by(id=media_id).first() + + if media is None: + return json_response( + "No such 'image' with id '{0}'".format(media_id), + status=404 + ) + + if media.uploader != request.user.id: + return json_error( + "Privilege 'commenter' required to comment.", + status=403 + ) + + + if not media.unserialize(data["object"]): + return json_error( + "Invalid 'image' with id '{0}'".format(media_id) + ) + + media.save() + api_add_to_feed(request, media) + + return json_response({ + "verb": "post", + "object": media.serialize(request) + }) + + elif obj.get("objectType", None) is None: + # They need to tell us what type of object they're giving us. + return json_error("No objectType specified.") + else: + # Oh no! We don't know about this type of object (yet) + object_type = obj.get("objectType", None) return json_error( - "Invalid 'image' with id '{0}'".format(obj_id) + "Unknown object type '{0}'.".format(object_type) ) - image.save() - activity = { - "verb": "update", - "object": image.serialize(request), - } - return json_response(activity) + # Updating existing objects + if data["verb"] == "update": + # Check we've got a valid object + obj = data.get("object", None) + + if obj is None: + return json_error("Could not find 'object' element.") + + if "objectType" not in obj: + return json_error("No objectType specified.") + + if "id" not in obj: + return json_error("Object ID has not been specified.") + + obj_id = obj["id"] + + # Now try and find object + if obj["objectType"] == "comment": + if not request.user.has_privilege(u'commenter'): + return json_error( + "Privilege 'commenter' required to comment.", + status=403 + ) + + comment = MediaComment.query.filter_by(id=obj_id).first() + if comment is None: + return json_error( + "No such 'comment' with id '{0}'.".format(obj_id) + ) + + # Check that the person trying to update the comment is + # the author of the comment. + if comment.author != request.user.id: + return json_error( + "Only author of comment is able to update comment.", + status=403 + ) + + if not comment.unserialize(data["object"]): + return json_error( + "Invalid 'comment' with id '{0}'".format(obj_id) + ) + + comment.save() + + activity = { + "verb": "update", + "object": comment.serialize(request), + } + return json_response(activity) + + elif obj["objectType"] == "image": + image = MediaEntry.query.filter_by(id=obj_id).first() + if image is None: + return json_error( + "No such 'image' with the id '{0}'.".format(obj_id) + ) + + # Check that the person trying to update the comment is + # the author of the comment. + if image.uploader != request.user.id: + return json_error( + "Only uploader of image is able to update image.", + status=403 + ) + + if not image.unserialize(obj): + return json_error( + "Invalid 'image' with id '{0}'".format(obj_id) + ) + image.save() + + activity = { + "verb": "update", + "object": image.serialize(request), + } + return json_response(activity) elif request.method != "GET": return json_error( @@ -299,9 +347,9 @@ def feed(request): item = { "verb": "post", "object": media.serialize(request), - "actor": request.user.serialize(request), + "actor": media.get_uploader.serialize(request), "content": "{0} posted a picture".format(request.user.username), - "id": 1, + "id": media.id, } item["updated"] = item["object"]["updated"] item["published"] = item["object"]["published"] @@ -312,7 +360,7 @@ def feed(request): return json_response(feed) @oauth_required -def object(request, raw_obj=False): +def object_endpoint(request): """ Lookup for a object type """ object_type = request.matchdict["objectType"] try: @@ -333,46 +381,41 @@ def object(request, raw_obj=False): media = MediaEntry.query.filter_by(id=object_id).first() if media is None: - error = "Can't find '{0}' with ID '{1}'".format( - object_type, - object_id - ) return json_error( "Can't find '{0}' with ID '{1}'".format(object_type, object_id), status=404 ) - if raw_obj: - return media - return json_response(media.serialize(request)) @oauth_required def object_comments(request): """ Looks up for the comments on a object """ - media = object(request, raw_obj=True) - response = media - if isinstance(response, MediaEntry): - comments = response.serialize(request) - comments = comments.get("replies", { - "totalItems": 0, - "items": [], - "url": request.urlgen( - "mediagoblin.federation.object.comments", - objectType=media.objectType, - uuid=media.id, - qualified=True - ) - }) - - comments["displayName"] = "Replies to {0}".format(comments["url"]) - comments["links"] = { - "first": comments["url"], - "self": comments["url"], - } - response = json_response(comments) + 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["id"] + ), 404) + + comments = response.serialize(request) + comments = comments.get("replies", { + "totalItems": 0, + "items": [], + "url": request.urlgen( + "mediagoblin.federation.object.comments", + objectType=media.objectType, + id=media.id, + qualified=True + ) + }) - return response + comments["displayName"] = "Replies to {0}".format(comments["url"]) + comments["links"] = { + "first": comments["url"], + "self": comments["url"], + } + return json_response(comments) ## # Well known |