Exemple #1
0
def feed(request):
    """ Handles the user's outbox - /api/user/<username>/feed """
    user = request.matchdict["username"]
    requested_user = User.query.filter_by(username=user).first()

    # check if the user exists
    if requested_user is None:
        return json_error("No such 'user' with id '{0}'".format(user), 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 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
                )

            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(
            "Unsupported HTTP method {0}".format(request.method),
            status=501
        )

    feed_url = request.urlgen(
        "mediagoblin.federation.feed",
        username=request.user.username,
        qualified=True
    )

    feed = {
        "displayName": "Activities by {user}@{host}".format(
            user=request.user.username,
            host=request.host
        ),
        "objectTypes": ["activity"],
        "url": feed_url,
        "links": {
            "first": {
                "href": feed_url,
            },
            "self": {
                "href": request.url,
            },
            "prev": {
                "href": feed_url,
            },
            "next": {
                "href": feed_url,
            }
        },
        "author": request.user.serialize(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": request.user.serialize(request),
            "content": "{0} posted a picture".format(request.user.username),
            "id": 1,
        }
        item["updated"] = item["object"]["updated"]
        item["published"] = item["object"]["published"]
        item["url"] = item["object"]["url"]
        feed["items"].append(item)
    feed["totalItems"] = len(feed["items"])

    return json_response(feed)
Exemple #2
0
def feed_endpoint(request, outbox=None):
    """ Handles the user's outbox - /api/user/<username>/feed """
    username = request.matchdict["username"]
    requested_user = LocalUser.query.filter(LocalUser.username==username).first()

    # check if the user exists
    if requested_user is None:
        return json_error("No such 'user' with id '{0}'".format(username), 404)

    if request.data:
        data = json.loads(request.data.decode())
    else:
        data = {"verb": None, "object": {}}


    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.")

        # Check that the verb is valid
        if data["verb"] not in ["post", "update", "delete"]:
            return json_error("Verb not yet implemented", 501)

        # 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
            )

        # 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 = TextComment(actor=request.user.id)
                comment.unserialize(data["object"], request)
                comment.save()

                # Create activity for comment
                generator = create_generator(request)
                activity = create_activity(
                    verb="post",
                    actor=request.user,
                    obj=comment,
                    target=comment.get_reply_to(),
                    generator=generator
                )

                return json_response(activity.serialize(request))

            elif obj.get("objectType", None) == "image":
                # Posting an image to the feed
                media_id = extract_url_arguments(
                    url=data["object"]["id"],
                    urlmap=request.app.url_map
                )["id"]

                # Build public_id
                public_id = request.urlgen(
                    "mediagoblin.api.object",
                    object_type=obj["objectType"],
                    id=media_id,
                    qualified=True
                )

                media = MediaEntry.query.filter_by(
                    public_id=public_id
                ).first()

                if media is None:
                    return json_response(
                        "No such 'image' with id '{0}'".format(media_id),
                        status=404
                    )

                if media.actor != 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)
                    )


                # Add location if one exists
                if "location" in data:
                    Location.create(data["location"], self)

                media.save()
                activity = api_add_to_feed(request, media)

                return json_response(activity.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)
                )

        # 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 = extract_url_arguments(
                url=obj["id"],
                urlmap=request.app.url_map
            )["id"]

            public_id = request.urlgen(
                "mediagoblin.api.object",
                object_type=obj["objectType"],
                id=obj_id,
                qualified=True
            )

            # 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 = TextComment.query.filter_by(
                    public_id=public_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.actor != request.user.id:
                    return json_error(
                        "Only author of comment is able to update comment.",
                        status=403
                    )

                if not comment.unserialize(data["object"], request):
                    return json_error(
                        "Invalid 'comment' with id '{0}'".format(obj["id"])
                    )

                comment.save()

                # Create an update activity
                generator = create_generator(request)
                activity = create_activity(
                    verb="update",
                    actor=request.user,
                    obj=comment,
                    generator=generator
                )

                return json_response(activity.serialize(request))

            elif obj["objectType"] == "image":
                image = MediaEntry.query.filter_by(
                    public_id=public_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.actor != 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.generate_slug()
                image.save()

                # Create an update activity
                generator = create_generator(request)
                activity = create_activity(
                    verb="update",
                    actor=request.user,
                    obj=image,
                    generator=generator
                )

                return json_response(activity.serialize(request))
            elif obj["objectType"] == "person":
                # check this is the same user
                if "id" not in obj or obj["id"] != requested_user.id:
                    return json_error(
                        "Incorrect user id, unable to update"
                    )

                requested_user.unserialize(obj)
                requested_user.save()

                generator = create_generator(request)
                activity = create_activity(
                    verb="update",
                    actor=request.user,
                    obj=requested_user,
                    generator=generator
                )

                return json_response(activity.serialize(request))

        elif data["verb"] == "delete":
            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.")

            # Parse out the object ID
            obj_id = extract_url_arguments(
                url=obj["id"],
                urlmap=request.app.url_map
            )["id"]

            public_id = request.urlgen(
                "mediagoblin.api.object",
                object_type=obj["objectType"],
                id=obj_id,
                qualified=True
            )

            if obj.get("objectType", None) == "comment":
                # Find the comment asked for
                comment = TextComment.query.filter_by(
                    public_id=public_id,
                    actor=request.user.id
                ).first()

                if comment is None:
                    return json_error(
                        "No such 'comment' with id '{0}'.".format(obj_id)
                    )

                # Make a delete activity
                generator = create_generator(request)
                activity = create_activity(
                    verb="delete",
                    actor=request.user,
                    obj=comment,
                    generator=generator
                )

                # Unfortunately this has to be done while hard deletion exists
                context = activity.serialize(request)

                # now we can delete the comment
                comment.delete()

                return json_response(context)

            if obj.get("objectType", None) == "image":
                # Find the image
                entry = MediaEntry.query.filter_by(
                    public_id=public_id,
                    actor=request.user.id
                ).first()

                if entry is None:
                    return json_error(
                        "No such 'image' with id '{0}'.".format(obj_id)
                    )

                # Make the delete activity
                generator = create_generator(request)
                activity = create_activity(
                    verb="delete",
                    actor=request.user,
                    obj=entry,
                    generator=generator
                )

                # This is because we have hard deletion
                context = activity.serialize(request)

                # Now we can delete the image
                entry.delete()

                return json_response(context)

    elif request.method != "GET":
        return json_error(
            "Unsupported HTTP method {0}".format(request.method),
            status=501
        )

    feed = {
        "displayName": "Activities by {user}@{host}".format(
            user=request.user.username,
            host=request.host
        ),
        "objectTypes": ["activity"],
        "url": request.base_url,
        "links": {"self": {"href": request.url}},
        "author": request.user.serialize(request),
        "items": [],
    }

    # Create outbox
    if outbox is None:
        outbox = Activity.query.filter_by(actor=request.user.id)
    else:
        outbox = outbox.filter_by(actor=request.user.id)

    # We want the newest things at the top (issue: #1055)
    outbox = outbox.order_by(Activity.published.desc())

    # Limit by the "count" (default: 20)
    limit = request.args.get("count", 20)

    try:
        limit = int(limit)
    except ValueError:
        limit = 20

    # The upper most limit should be 200
    limit = limit if limit < 200 else 200

    # apply the limit
    outbox = outbox.limit(limit)

    # Offset (default: no offset - first <count>  result)
    outbox = outbox.offset(request.args.get("offset", 0))

    # Build feed.
    for activity in outbox:
        try:
            feed["items"].append(activity.serialize(request))
        except AttributeError:
            # This occurs because of how we hard-deletion and the object
            # no longer existing anymore. We want to keep the Activity
            # in case someone wishes to look it up but we shouldn't display
            # it in the feed.
            pass
    feed["totalItems"] = len(feed["items"])

    return json_response(feed)
Exemple #3
0
def feed_endpoint(request, outbox=None):
    """ Handles the user's outbox - /api/user/<username>/feed """
    username = request.matchdict["username"]
    requested_user = LocalUser.query.filter(
        LocalUser.username == username).first()

    # check if the user exists
    if requested_user is None:
        return json_error("No such 'user' with id '{0}'".format(username), 404)

    if request.data:
        data = json.loads(request.data.decode())
    else:
        data = {"verb": None, "object": {}}

    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.")

        # Check that the verb is valid
        if data["verb"] not in ["post", "update", "delete"]:
            return json_error("Verb not yet implemented", 501)

        # 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)

        # 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 = TextComment(actor=request.user.id)
                comment.unserialize(data["object"], request)
                comment.save()

                # Create activity for comment
                generator = create_generator(request)
                activity = create_activity(verb="post",
                                           actor=request.user,
                                           obj=comment,
                                           target=comment.get_reply_to(),
                                           generator=generator)

                return json_response(activity.serialize(request))

            elif obj.get("objectType", None) == "image":
                # Posting an image to the feed
                media_id = extract_url_arguments(
                    url=data["object"]["id"], urlmap=request.app.url_map)["id"]

                # Build public_id
                public_id = request.urlgen("mediagoblin.api.object",
                                           object_type=obj["objectType"],
                                           id=media_id,
                                           qualified=True)

                media = MediaEntry.query.filter_by(public_id=public_id).first()

                if media is None:
                    return json_response(
                        "No such 'image' with id '{0}'".format(media_id),
                        status=404)

                if media.actor != 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))

                # Add location if one exists
                if "location" in data:
                    Location.create(data["location"], self)

                media.save()
                activity = api_add_to_feed(request, media)

                return json_response(activity.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))

        # 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 = extract_url_arguments(url=obj["id"],
                                           urlmap=request.app.url_map)["id"]

            public_id = request.urlgen("mediagoblin.api.object",
                                       object_type=obj["objectType"],
                                       id=obj_id,
                                       qualified=True)

            # 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 = TextComment.query.filter_by(
                    public_id=public_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.actor != request.user.id:
                    return json_error(
                        "Only author of comment is able to update comment.",
                        status=403)

                if not comment.unserialize(data["object"], request):
                    return json_error("Invalid 'comment' with id '{0}'".format(
                        obj["id"]))

                comment.save()

                # Create an update activity
                generator = create_generator(request)
                activity = create_activity(verb="update",
                                           actor=request.user,
                                           obj=comment,
                                           generator=generator)

                return json_response(activity.serialize(request))

            elif obj["objectType"] == "image":
                image = MediaEntry.query.filter_by(public_id=public_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.actor != 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.generate_slug()
                image.save()

                # Create an update activity
                generator = create_generator(request)
                activity = create_activity(verb="update",
                                           actor=request.user,
                                           obj=image,
                                           generator=generator)

                return json_response(activity.serialize(request))
            elif obj["objectType"] == "person":
                # check this is the same user
                if "id" not in obj or obj["id"] != requested_user.id:
                    return json_error("Incorrect user id, unable to update")

                requested_user.unserialize(obj)
                requested_user.save()

                generator = create_generator(request)
                activity = create_activity(verb="update",
                                           actor=request.user,
                                           obj=requested_user,
                                           generator=generator)

                return json_response(activity.serialize(request))

        elif data["verb"] == "delete":
            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.")

            # Parse out the object ID
            obj_id = extract_url_arguments(url=obj["id"],
                                           urlmap=request.app.url_map)["id"]

            public_id = request.urlgen("mediagoblin.api.object",
                                       object_type=obj["objectType"],
                                       id=obj_id,
                                       qualified=True)

            if obj.get("objectType", None) == "comment":
                # Find the comment asked for
                comment = TextComment.query.filter_by(
                    public_id=public_id, actor=request.user.id).first()

                if comment is None:
                    return json_error(
                        "No such 'comment' with id '{0}'.".format(obj_id))

                # Make a delete activity
                generator = create_generator(request)
                activity = create_activity(verb="delete",
                                           actor=request.user,
                                           obj=comment,
                                           generator=generator)

                # Unfortunately this has to be done while hard deletion exists
                context = activity.serialize(request)

                # now we can delete the comment
                comment.delete()

                return json_response(context)

            if obj.get("objectType", None) == "image":
                # Find the image
                entry = MediaEntry.query.filter_by(
                    public_id=public_id, actor=request.user.id).first()

                if entry is None:
                    return json_error(
                        "No such 'image' with id '{0}'.".format(obj_id))

                # Make the delete activity
                generator = create_generator(request)
                activity = create_activity(verb="delete",
                                           actor=request.user,
                                           obj=entry,
                                           generator=generator)

                # This is because we have hard deletion
                context = activity.serialize(request)

                # Now we can delete the image
                entry.delete()

                return json_response(context)

    elif request.method != "GET":
        return json_error("Unsupported HTTP method {0}".format(request.method),
                          status=501)

    feed = {
        "displayName":
        "Activities by {user}@{host}".format(user=request.user.username,
                                             host=request.host),
        "objectTypes": ["activity"],
        "url":
        request.base_url,
        "links": {
            "self": {
                "href": request.url
            }
        },
        "author":
        request.user.serialize(request),
        "items": [],
    }

    # Create outbox
    if outbox is None:
        outbox = Activity.query.filter_by(actor=requested_user.id)
    else:
        outbox = outbox.filter_by(actor=requested_user.id)

    # We want the newest things at the top (issue: #1055)
    outbox = outbox.order_by(Activity.published.desc())

    # Limit by the "count" (default: 20)
    limit = request.args.get("count", 20)

    try:
        limit = int(limit)
    except ValueError:
        limit = 20

    # The upper most limit should be 200
    limit = limit if limit < 200 else 200

    # apply the limit
    outbox = outbox.limit(limit)

    # Offset (default: no offset - first <count>  result)
    offset = request.args.get("offset", 0)
    try:
        offset = int(offset)
    except ValueError:
        offset = 0
    outbox = outbox.offset(offset)

    # Build feed.
    for activity in outbox:
        try:
            feed["items"].append(activity.serialize(request))
        except AttributeError:
            # This occurs because of how we hard-deletion and the object
            # no longer existing anymore. We want to keep the Activity
            # in case someone wishes to look it up but we shouldn't display
            # it in the feed.
            pass
    feed["totalItems"] = len(feed["items"])

    return json_response(feed)
def feed_endpoint(request):
    """ Handles the user's outbox - /api/user/<username>/feed """
    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(username), 404)

    if request.data:
        data = json.loads(request.data.decode())
    else:
        data = {"verb": None, "object": {}}


    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.")

        # Check that the verb is valid
        if data["verb"] not in ["post", "update"]:
            return json_error("Verb not yet implemented", 501)

        # 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
            )

        # 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)
                    )


                # Add location if one exists
                if "location" in data:
                    Location.create(data["location"], self)

                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)
                )

        # 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.generate_slug()
                image.save()

                activity = {
                    "verb": "update",
                    "object": image.serialize(request),
                }
                return json_response(activity)
            elif obj["objectType"] == "person":
                # check this is the same user
                if "id" not in obj or obj["id"] != requested_user.id:
                    return json_error(
                        "Incorrect user id, unable to update"
                    )

                requested_user.unserialize(obj)
                requested_user.save()

    elif request.method != "GET":
        return json_error(
            "Unsupported HTTP method {0}".format(request.method),
            status=501
        )

    feed_url = request.urlgen(
        "mediagoblin.federation.feed",
        username=request.user.username,
        qualified=True
    )

    feed = {
        "displayName": "Activities by {user}@{host}".format(
            user=request.user.username,
            host=request.host
        ),
        "objectTypes": ["activity"],
        "url": feed_url,
        "links": {
            "first": {
                "href": feed_url,
            },
            "self": {
                "href": request.url,
            },
            "prev": {
                "href": feed_url,
            },
            "next": {
                "href": feed_url,
            }
        },
        "author": request.user.serialize(request),
        "items": [],
    }

    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)