aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--mediagoblin/db/models.py15
-rw-r--r--mediagoblin/federation/views.py25
-rw-r--r--mediagoblin/media_types/image/__init__.py15
-rw-r--r--mediagoblin/tests/test_api.py177
-rw-r--r--mediagoblin/tests/tools.py58
5 files changed, 187 insertions, 103 deletions
diff --git a/mediagoblin/db/models.py b/mediagoblin/db/models.py
index cc5d0afa..27ca74e0 100644
--- a/mediagoblin/db/models.py
+++ b/mediagoblin/db/models.py
@@ -446,9 +446,8 @@ class MediaEntry(Base, MediaEntryMixin):
)
context = {
- "id": self.id,
+ "id": self.id,
"author": author.serialize(request),
- "displayName": self.title,
"objectType": self.objectType,
"url": url,
"image": {
@@ -464,6 +463,15 @@ class MediaEntry(Base, MediaEntryMixin):
},
}
+ if self.title:
+ context["displayName"] = self.title
+
+ if self.description:
+ context["content"] = self.description
+
+ if self.license:
+ context["license"] = self.license
+
if show_comments:
comments = [comment.serialize(request) for comment in self.get_comments()]
total = len(comments)
@@ -478,7 +486,7 @@ class MediaEntry(Base, MediaEntryMixin):
),
}
- return context
+ return context
class FileKeynames(Base):
"""
@@ -630,6 +638,7 @@ class MediaComment(Base, MediaCommentMixin):
media = MediaEntry.query.filter_by(id=self.media_entry).first()
author = self.get_author
context = {
+ "id": self.id,
"objectType": "comment",
"content": self.content,
"inReplyTo": media.serialize(request, show_comments=False),
diff --git a/mediagoblin/federation/views.py b/mediagoblin/federation/views.py
index 6e4d81d4..c2b02ec0 100644
--- a/mediagoblin/federation/views.py
+++ b/mediagoblin/federation/views.py
@@ -116,15 +116,27 @@ def feed(request):
elif obj.get("objectType", None) == "image":
# Posting an image to the feed
- # NB: This is currently just handing the image back until we have an
- # to send the image to the actual feed
-
media_id = int(data["object"]["id"])
media = MediaEntry.query.filter_by(id=media_id)
if media is None:
error = "No such 'image' with id '{0}'".format(id=media_id)
return json_response(error, status=404)
- media = media[0]
+
+ media = media.first()
+ obj = data["object"]
+
+ if "displayName" in obj:
+ media.title = obj["displayName"]
+
+ if "content" in obj:
+ media.description = obj["content"]
+
+ if "license" in obj:
+ media.license = obj["license"]
+
+ media.save()
+ manager = media.media_manager.api_add_to_feed(request, media)
+
return json_response({
"verb": "post",
"object": media.serialize(request)
@@ -206,6 +218,11 @@ def feed(request):
}
return json_response(activity)
+ elif request.method != "GET":
+ # Currently unsupported
+ error = "Unsupported HTTP method {0}".format(request.method)
+ return json_response({"error": error}, status=501)
+
feed_url = request.urlgen(
"mediagoblin.federation.feed",
username=request.user.username,
diff --git a/mediagoblin/media_types/image/__init__.py b/mediagoblin/media_types/image/__init__.py
index 7b9296fe..96081068 100644
--- a/mediagoblin/media_types/image/__init__.py
+++ b/mediagoblin/media_types/image/__init__.py
@@ -63,10 +63,7 @@ class ImageMediaManager(MediaManagerBase):
""" This handles a image upload request """
# Use the same kind of method from mediagoblin/submit/views:submit_start
entry.media_type = unicode(MEDIA_TYPE)
- entry.title = unicode(request.args.get("title", file_data.filename))
- entry.description = unicode(request.args.get("description", ""))
- entry.license = request.args.get("license", "") # not part of the standard API
-
+ entry.title = file_data.filename
entry.generate_slug()
queue_file = prepare_queue_task(request.app, entry, file_data.filename)
@@ -74,6 +71,16 @@ class ImageMediaManager(MediaManagerBase):
queue_file.write(request.data)
entry.save()
+ return json_response(entry.serialize(request))
+
+ @staticmethod
+ def api_add_to_feed(request, entry):
+ """ Add media to Feed """
+ if entry.title:
+ # Shame we have to do this here but we didn't have the data in
+ # api_upload_request as no filename is usually specified.
+ entry.slug = None
+ entry.generate_slug()
feed_url = request.urlgen(
'mediagoblin.user_pages.atom_feed',
diff --git a/mediagoblin/tests/test_api.py b/mediagoblin/tests/test_api.py
index 21222304..38d4c0d5 100644
--- a/mediagoblin/tests/test_api.py
+++ b/mediagoblin/tests/test_api.py
@@ -23,11 +23,10 @@ from webtest import AppError
from mediagoblin import mg_globals
from .resources import GOOD_JPG
-from mediagoblin.db.models import User
+from mediagoblin.db.models import User, MediaEntry
from mediagoblin.tests.tools import fixture_add_user
from mediagoblin.moderation.tools import take_away_privileges
-from .resources import GOOD_JPG, GOOD_PNG, EVIL_FILE, EVIL_JPG, EVIL_PNG, \
- BIG_BLUE
+from .resources import GOOD_JPG
class TestAPI(object):
@@ -35,8 +34,54 @@ class TestAPI(object):
def setup(self, test_app):
self.test_app = test_app
self.db = mg_globals.database
+
self.user = fixture_add_user(privileges=[u'active', u'uploader'])
+ def _activity_to_feed(self, test_app, activity, headers=None):
+ """ Posts an activity to the user's feed """
+ if headers:
+ headers.setdefault("Content-Type", "application/json")
+ else:
+ headers = {"Content-Type": "application/json"}
+
+ with mock.patch("mediagoblin.decorators.oauth_required", new_callable=self.mocked_oauth_required):
+ response = test_app.post(
+ "/api/user/{0}/feed".format(self.user.username),
+ json.dumps(activity),
+ headers=headers
+ )
+
+ return response, json.loads(response.body)
+
+ def _upload_image(self, test_app, image):
+ """ Uploads and image to MediaGoblin via pump.io API """
+ data = open(image, "rb").read()
+ headers = {
+ "Content-Type": "image/jpeg",
+ "Content-Length": str(len(data))
+ }
+
+
+ with mock.patch("mediagoblin.decorators.oauth_required", new_callable=self.mocked_oauth_required):
+ response = test_app.post(
+ "/api/user/{0}/uploads".format(self.user.username),
+ data,
+ headers=headers
+ )
+ image = json.loads(response.body)
+
+ return response, image
+
+ def _post_image_to_feed(self, test_app, image):
+ """ Posts an already uploaded image to feed """
+ activity = {
+ "verb": "post",
+ "object": image,
+ }
+
+ return self._activity_to_feed(test_app, activity)
+
+
def mocked_oauth_required(self, *args, **kwargs):
""" Mocks mediagoblin.decorator.oauth_required to always validate """
@@ -52,46 +97,63 @@ class TestAPI(object):
def test_can_post_image(self, test_app):
""" Tests that an image can be posted to the API """
# First request we need to do is to upload the image
- data = open(GOOD_JPG, "rb").read()
- headers = {
- "Content-Type": "image/jpeg",
- "Content-Length": str(len(data))
- }
+ response, image = self._upload_image(test_app, GOOD_JPG)
+ # I should have got certain things back
+ assert response.status_code == 200
- with mock.patch("mediagoblin.decorators.oauth_required", new_callable=self.mocked_oauth_required):
- response = test_app.post(
- "/api/user/{0}/uploads".format(self.user.username),
- data,
- headers=headers
- )
- image = json.loads(response.body)
+ assert "id" in image
+ assert "fullImage" in image
+ assert "url" in image["fullImage"]
+ assert "url" in image
+ assert "author" in image
+ assert "published" in image
+ assert "updated" in image
+ assert image["objectType"] == "image"
+ # Check that we got the response we're expecting
+ response, _ = self._post_image_to_feed(test_app, image)
+ assert response.status_code == 200
- # I should have got certain things back
- assert response.status_code == 200
+ def test_upload_image_with_filename(self, test_app):
+ """ Tests that you can upload an image with filename and description """
+ response, data = self._upload_image(test_app, GOOD_JPG)
+ response, data = self._post_image_to_feed(test_app, data)
- assert "id" in image
- assert "fullImage" in image
- assert "url" in image["fullImage"]
- assert "url" in image
- assert "author" in image
- assert "published" in image
- assert "updated" in image
- assert image["objectType"] == "image"
-
- # Now post this to the feed
- activity = {
- "verb": "post",
- "object": image,
- }
+ image = data["object"]
+
+ # Now we need to add a title and description
+ title = "My image ^_^"
+ description = "This is my super awesome image :D"
+ license = "CC-BY-SA"
+
+ image["displayName"] = title
+ image["content"] = description
+ image["license"] = license
+
+ activity = {"verb": "update", "object": image}
+
+ with mock.patch("mediagoblin.decorators.oauth_required", new_callable=self.mocked_oauth_required):
response = test_app.post(
"/api/user/{0}/feed".format(self.user.username),
- activity
+ json.dumps(activity),
+ headers={"Content-Type": "application/json"}
)
- # Check that we got the response we're expecting
- assert response.status_code == 200
+ image = json.loads(response.body)["object"]
+
+ # Check everything has been set on the media correctly
+ media = MediaEntry.query.filter_by(id=image["id"]).first()
+ assert media.title == title
+ assert media.description == description
+ assert media.license == license
+
+ # Check we're being given back everything we should on an update
+ assert image["id"] == media.id
+ assert image["displayName"] == title
+ assert image["content"] == description
+ assert image["license"] == license
+
def test_only_uploaders_post_image(self, test_app):
""" Test that only uploaders can upload images """
@@ -115,3 +177,50 @@ class TestAPI(object):
# Assert that we've got a 403
assert "403 FORBIDDEN" in excinfo.value.message
+
+
+ def test_post_comment(self, test_app):
+ """ Tests that I can post an comment media """
+ # Upload some media to comment on
+ response, data = self._upload_image(test_app, GOOD_JPG)
+ response, data = self._post_image_to_feed(test_app, data)
+
+ content = "Hai this is a comment on this lovely picture ^_^"
+
+ activity = {
+ "verb": "post",
+ "object": {
+ "objectType": "comment",
+ "content": content,
+ "inReplyTo": data["object"],
+ }
+ }
+
+ response, comment_data = self._activity_to_feed(test_app, activity)
+ assert response.status_code == 200
+
+ # Find the objects in the database
+ media = MediaEntry.query.filter_by(id=data["object"]["id"]).first()
+ comment = media.get_comments()[0]
+
+ # Tests that it matches in the database
+ assert comment.author == self.user.id
+ assert comment.content == content
+
+ # Test that the response is what we should be given
+ assert comment.id == comment_data["object"]["id"]
+ assert comment.content == comment_data["object"]["content"]
+
+ def test_profile(self, test_app):
+ """ Tests profile endpoint """
+ uri = "/api/user/{0}/profile".format(self.user.username)
+ with mock.patch("mediagoblin.decorators.oauth_required", new_callable=self.mocked_oauth_required):
+ response = test_app.get(uri)
+ profile = json.loads(response.body)
+
+ assert response.status_code == 200
+
+ assert profile["preferredUsername"] == self.user.username
+ assert profile["objectType"] == "person"
+
+ assert "links" in profile
diff --git a/mediagoblin/tests/tools.py b/mediagoblin/tests/tools.py
index d839373b..57dea7b0 100644
--- a/mediagoblin/tests/tools.py
+++ b/mediagoblin/tests/tools.py
@@ -347,61 +347,3 @@ def fixture_add_comment_report(comment=None, reported_user=None,
return comment_report
-def fixture_add_oauth_client(client_name=None, client_type="native",
- redirect_uri=None, contacts=None):
-
- client_id = random_string(22, OAUTH_ALPHABET)
- client_secret = random_string(43, OAUTH_ALPHABET)
-
- client = Client(
- id=client_id,
- secret=client_secret,
- expirey=None,
- application_type=client_type,
- application_name=client_name,
- contacts=contacts,
- redirect_uri=redirect_uri
- )
- client.save()
-
- return client
-
-def fixture_add_oauth_request_token(user, client=None):
- if client is None:
- client = fixture_add_oauth_client()
-
- rt_token = random_string(22, OAUTH_ALPHABET)
- rt_secret = random_string(43, OAUTH_ALPHABET)
- rt_verifier = random_string(22, OAUTH_ALPHABET)
-
- request_token = RequestToken(
- token=rt_token,
- secret=rt_secret,
- user=user.id,
- used=True,
- authenticated=True,
- verifier=rt_verifier,
- )
- request_token.save()
-
- return request_token
-
-def fixture_add_oauth_access_token(user, client=None, request_token=None):
- if client is None:
- client = fixture_add_oauth_client()
-
- if request_token is None:
- request_token = fixture_add_oauth_request_token(user)
-
- at_token = random_string(22, OAUTH_ALPHABET)
- at_secret = random_string(43, OAUTH_ALPHABET)
-
- access_token = AccessToken(
- token=at_token,
- secret=at_secret,
- user=user.id,
- request_token=request_token.token
- )
- access_token.save()
-
- return access_token