Add activity endpoint support

This commit is contained in:
Pete 2013-08-19 18:12:29 +01:00
parent 55778dcd83
commit 707eb270ee
9 changed files with 278 additions and 24 deletions

View file

@ -5,7 +5,7 @@ except ImportError:
from tests.functional import test_base from tests.functional import test_base
class TestActionss(test_base.TestBase): class TestActions(test_base.TestBase):
testcase_name = "action API" testcase_name = "action API"
# TODO: Enable this test (and write more) once the Actions API is working. # TODO: Enable this test (and write more) once the Actions API is working.

View file

@ -0,0 +1,50 @@
try:
import unittest2 as unittest # Python2.6
except ImportError:
import unittest
from tests.functional import test_base
class TestActivities(test_base.TestBase):
testcase_name = "activity API"
def test_list(self):
"""
Upload three photos, and check that three corresponding activities
are created.
"""
self._delete_all()
self._create_test_photos(tag=False)
photos = self.client.photos.list()
# Check that each activity is for a valid test photo
activities = self.client.activities.list()
self.assertEqual(len(activities), len(self.photos))
for activity in activities:
self.assertIn(activity.data.id, [photo.id for photo in photos])
# The purge endpoint currently reports a 500: Internal Server Error
@unittest.expectedFailure
def test_purge(self):
""" Test that the purge endpoint deletes all activities """
activities = self.client.activities.list()
self.assertNotEqual(activities, [])
self.client.activities.purge()
self.assertEqual(activities, [])
def test_view(self):
""" Test that the view endpoint is working correctly """
activity = self.client.activities.list()[0]
fields = activity.get_fields().copy()
# Check that the view method returns the same data as the list
activity.view()
self.assertEqual(fields, activity.get_fields())
# Check using the Trovebox class
activity = self.client.activity.view(activity)
self.assertEqual(fields, activity.get_fields())
# Check passing the activity ID to the Trovebox class
activity = self.client.activity.view(activity.id)
self.assertEqual(fields, activity.get_fields())

View file

@ -124,7 +124,7 @@ class TestBase(unittest.TestCase):
logging.info("Finished %s\n", self.id()) logging.info("Finished %s\n", self.id())
@classmethod @classmethod
def _create_test_photos(cls): def _create_test_photos(cls, tag=True):
""" Upload three test photos """ """ Upload three test photos """
album = cls.client.album.create(cls.TEST_ALBUM) album = cls.client.album.create(cls.TEST_ALBUM)
photos = [ photos = [
@ -139,6 +139,7 @@ class TestBase(unittest.TestCase):
albums=album.id), albums=album.id),
] ]
# Add the test tag, removing any autogenerated tags # Add the test tag, removing any autogenerated tags
if tag:
for photo in photos: for photo in photos:
photo.update(tags=cls.TEST_TAG) photo.update(tags=cls.TEST_TAG)

View file

@ -18,7 +18,7 @@ class TestPhotos(test_base.TestBase):
# Check that they're gone # Check that they're gone
self.assertEqual(self.client.photos.list(), []) self.assertEqual(self.client.photos.list(), [])
# Re-upload the photos, one of them using Bas64 encoding # Re-upload the photos, one of them using Base64 encoding
ret_val = self.client.photo.upload("tests/data/test_photo1.jpg", ret_val = self.client.photo.upload("tests/data/test_photo1.jpg",
title=self.TEST_TITLE) title=self.TEST_TITLE)
self.client.photo.upload("tests/data/test_photo2.jpg", self.client.photo.upload("tests/data/test_photo2.jpg",

View file

@ -0,0 +1,103 @@
from __future__ import unicode_literals
import json
import mock
try:
import unittest2 as unittest # Python2.6
except ImportError:
import unittest
import trovebox
class TestActivities(unittest.TestCase):
test_host = "test.example.com"
test_photos_dict = [{"id": "photo1"},
{"id": "photo2"}]
test_activities_dict = [{"id": "1",
"data": test_photos_dict[0],
"type": "photo_upload"},
{"id": "2",
"data": test_photos_dict[1],
"type": "photo_update"}]
def setUp(self):
self.client = trovebox.Trovebox(host=self.test_host)
self.test_photos = [trovebox.objects.photo.Photo(self.client, photo)
for photo in self.test_photos_dict]
self.test_activities = [trovebox.objects.activity.Activity(self.client, activity)
for activity in self.test_activities_dict]
@staticmethod
def _return_value(result, message="", code=200):
return {"message": message, "code": code, "result": result}
@staticmethod
def _view_wrapper(result):
""" The view method returns data enclosed in a dict and JSON encoded """
result["data"] = json.dumps(result["data"])
return {"0": result}
class TestActivitiesList(TestActivities):
@mock.patch.object(trovebox.Trovebox, 'get')
def test_activities_list(self, mock_get):
"""Check that the activity list is returned correctly"""
mock_get.return_value = self._return_value(self.test_activities_dict)
result = self.client.activities.list()
mock_get.assert_called_with("/activities/list.json")
self.assertEqual(len(result), 2)
self.assertEqual(result[0].id, "1")
self.assertEqual(result[0].type, "photo_upload")
self.assertEqual(result[0].data.id, "photo1")
self.assertEqual(result[1].id, "2")
self.assertEqual(result[1].type, "photo_update")
self.assertEqual(result[1].data.id, "photo2")
class TestActivitiesPurge(TestActivities):
@mock.patch.object(trovebox.Trovebox, 'post')
def test_activity_purge(self, mock_get):
"""Test activity purging """
mock_get.return_value = self._return_value(True)
result = self.client.activities.purge(foo="bar")
mock_get.assert_called_with("/activities/purge.json", foo="bar")
self.assertEqual(result, True)
@mock.patch.object(trovebox.Trovebox, 'post')
def test_activity_purge_failure(self, mock_post):
"""Test activity purging """
mock_post.return_value = self._return_value(False)
with self.assertRaises(trovebox.TroveboxError):
result = self.client.activities.purge(foo="bar")
class TestActivityView(TestActivities):
@mock.patch.object(trovebox.Trovebox, 'get')
def test_activity_view(self, mock_get):
"""Check that a activity can be viewed"""
mock_get.return_value = self._return_value(self._view_wrapper(
self.test_activities_dict[1]))
result = self.client.activity.view(self.test_activities[0],
foo="bar")
mock_get.assert_called_with("/activity/1/view.json", foo="bar")
self.assertEqual(result.get_fields(), self.test_activities_dict[1])
@mock.patch.object(trovebox.Trovebox, 'get')
def test_activity_view_id(self, mock_get):
"""Check that a activity can be viewed using its ID"""
mock_get.return_value = self._return_value(self._view_wrapper(
self.test_activities_dict[1]))
result = self.client.activity.view("1", foo="bar")
mock_get.assert_called_with("/activity/1/view.json", foo="bar")
self.assertEqual(result.get_fields(), self.test_activities_dict[1])
@mock.patch.object(trovebox.Trovebox, 'get')
def test_activity_object_view(self, mock_get):
"""
Check that a activity can be viewed
when using the activity object directly
"""
mock_get.return_value = self._return_value(self._view_wrapper(
self.test_activities_dict[1]))
activity = self.test_activities[0]
activity.view(foo="bar")
mock_get.assert_called_with("/activity/1/view.json", foo="bar")
self.assertEqual(activity.get_fields(), self.test_activities_dict[1])

View file

@ -1,6 +1,18 @@
diff --unified --recursive '--exclude=.pylint-ignores.patch' original/api/api_activity.py patched/api/api_activity.py
--- original/api/api_activity.py 2013-08-19 17:59:15.592149000 +0100
+++ patched/api/api_activity.py 2013-08-19 18:08:39.950947589 +0100
@@ -22,7 +22,7 @@
raise TroveboxError("Purge response returned False")
return True
-class ApiActivity(object):
+class ApiActivity(object): # pylint: disable=R0903
""" Definitions of /activity/ API endpoints """
def __init__(self, client):
self._client = client
diff --unified --recursive '--exclude=.pylint-ignores.patch' original/api/api_album.py patched/api/api_album.py diff --unified --recursive '--exclude=.pylint-ignores.patch' original/api/api_album.py patched/api/api_album.py
--- original/api/api_album.py 2013-08-19 16:08:00.231047000 +0100 --- original/api/api_album.py 2013-08-19 16:09:53.539609000 +0100
+++ patched/api/api_album.py 2013-08-19 16:09:30.263494209 +0100 +++ patched/api/api_album.py 2013-08-19 18:08:20.118849270 +0100
@@ -3,7 +3,7 @@ @@ -3,7 +3,7 @@
""" """
from trovebox.objects.album import Album from trovebox.objects.album import Album
@ -11,8 +23,8 @@ diff --unified --recursive '--exclude=.pylint-ignores.patch' original/api/api_al
def __init__(self, client): def __init__(self, client):
self._client = client self._client = client
diff --unified --recursive '--exclude=.pylint-ignores.patch' original/api/api_tag.py patched/api/api_tag.py diff --unified --recursive '--exclude=.pylint-ignores.patch' original/api/api_tag.py patched/api/api_tag.py
--- original/api/api_tag.py 2013-08-19 16:08:00.231047000 +0100 --- original/api/api_tag.py 2013-08-19 16:09:53.539609000 +0100
+++ patched/api/api_tag.py 2013-08-19 16:09:30.263494209 +0100 +++ patched/api/api_tag.py 2013-08-19 18:08:20.118849270 +0100
@@ -3,7 +3,7 @@ @@ -3,7 +3,7 @@
""" """
from trovebox.objects.tag import Tag from trovebox.objects.tag import Tag
@ -23,8 +35,8 @@ diff --unified --recursive '--exclude=.pylint-ignores.patch' original/api/api_ta
def __init__(self, client): def __init__(self, client):
self._client = client self._client = client
diff --unified --recursive '--exclude=.pylint-ignores.patch' original/auth.py patched/auth.py diff --unified --recursive '--exclude=.pylint-ignores.patch' original/auth.py patched/auth.py
--- original/auth.py 2013-08-19 16:08:00.231047000 +0100 --- original/auth.py 2013-08-19 16:09:53.543609000 +0100
+++ patched/auth.py 2013-08-19 16:09:30.263494209 +0100 +++ patched/auth.py 2013-08-19 18:08:20.118849270 +0100
@@ -4,7 +4,7 @@ @@ -4,7 +4,7 @@
from __future__ import unicode_literals from __future__ import unicode_literals
import os import os
@ -56,8 +68,8 @@ diff --unified --recursive '--exclude=.pylint-ignores.patch' original/auth.py pa
parser.readfp(buf) # Python2 parser.readfp(buf) # Python2
diff --unified --recursive '--exclude=.pylint-ignores.patch' original/http.py patched/http.py diff --unified --recursive '--exclude=.pylint-ignores.patch' original/http.py patched/http.py
--- original/http.py 2013-08-19 16:09:27.459480000 +0100 --- original/http.py 2013-08-19 16:09:53.543609000 +0100
+++ patched/http.py 2013-08-19 16:09:46.311573793 +0100 +++ patched/http.py 2013-08-19 18:08:20.118849270 +0100
@@ -7,18 +7,18 @@ @@ -7,18 +7,18 @@
import requests_oauthlib import requests_oauthlib
import logging import logging
@ -91,8 +103,8 @@ diff --unified --recursive '--exclude=.pylint-ignores.patch' original/http.py pa
token='', token_secret='', api_version=None): token='', token_secret='', api_version=None):
diff --unified --recursive '--exclude=.pylint-ignores.patch' original/__init__.py patched/__init__.py diff --unified --recursive '--exclude=.pylint-ignores.patch' original/__init__.py patched/__init__.py
--- original/__init__.py 2013-08-19 16:09:12.971408000 +0100 --- original/__init__.py 2013-08-19 17:02:22.951226000 +0100
+++ patched/__init__.py 2013-08-19 16:09:30.263494209 +0100 +++ patched/__init__.py 2013-08-19 18:08:36.194928993 +0100
@@ -2,7 +2,7 @@ @@ -2,7 +2,7 @@
__init__.py : Trovebox package top level __init__.py : Trovebox package top level
""" """
@ -102,7 +114,16 @@ diff --unified --recursive '--exclude=.pylint-ignores.patch' original/__init__.p
from ._version import __version__ from ._version import __version__
from trovebox.api import api_photo from trovebox.api import api_photo
from trovebox.api import api_tag from trovebox.api import api_tag
@@ -23,7 +23,7 @@ @@ -12,7 +12,7 @@
LATEST_API_VERSION = 2
-class Trovebox(Http):
+class Trovebox(Http): # pylint: disable=R0902
"""
Client library for Trovebox
If no parameters are specified, config is loaded from the default
@@ -24,7 +24,7 @@
This should be used to ensure that your application will continue to work This should be used to ensure that your application will continue to work
even if the Trovebox API is updated to a new revision. even if the Trovebox API is updated to a new revision.
""" """
@ -112,8 +133,8 @@ diff --unified --recursive '--exclude=.pylint-ignores.patch' original/__init__.p
token='', token_secret='', token='', token_secret='',
api_version=None): api_version=None):
diff --unified --recursive '--exclude=.pylint-ignores.patch' original/main.py patched/main.py diff --unified --recursive '--exclude=.pylint-ignores.patch' original/main.py patched/main.py
--- original/main.py 2013-08-19 16:08:00.235047000 +0100 --- original/main.py 2013-08-19 16:09:53.543609000 +0100
+++ patched/main.py 2013-08-19 16:09:30.263494209 +0100 +++ patched/main.py 2013-08-19 18:08:20.118849270 +0100
@@ -26,7 +26,7 @@ @@ -26,7 +26,7 @@
################################################################# #################################################################
@ -141,8 +162,8 @@ diff --unified --recursive '--exclude=.pylint-ignores.patch' original/main.py pa
if options.verbose: if options.verbose:
diff --unified --recursive '--exclude=.pylint-ignores.patch' original/objects/tag.py patched/objects/tag.py diff --unified --recursive '--exclude=.pylint-ignores.patch' original/objects/tag.py patched/objects/tag.py
--- original/objects/tag.py 2013-08-19 16:08:00.235047000 +0100 --- original/objects/tag.py 2013-08-19 16:09:53.543609000 +0100
+++ patched/objects/tag.py 2013-08-19 16:09:30.263494209 +0100 +++ patched/objects/tag.py 2013-08-19 18:08:20.118849270 +0100
@@ -1,8 +1,8 @@ @@ -1,8 +1,8 @@
-""" -"""
+""" # pylint: disable=R0801 +""" # pylint: disable=R0801
@ -155,8 +176,8 @@ diff --unified --recursive '--exclude=.pylint-ignores.patch' original/objects/ta
from urllib import quote # Python2 from urllib import quote # Python2
diff --unified --recursive '--exclude=.pylint-ignores.patch' original/objects/trovebox_object.py patched/objects/trovebox_object.py diff --unified --recursive '--exclude=.pylint-ignores.patch' original/objects/trovebox_object.py patched/objects/trovebox_object.py
--- original/objects/trovebox_object.py 2013-08-19 16:08:00.235047000 +0100 --- original/objects/trovebox_object.py 2013-08-19 16:09:53.543609000 +0100
+++ patched/objects/trovebox_object.py 2013-08-19 16:09:30.263494209 +0100 +++ patched/objects/trovebox_object.py 2013-08-19 18:08:20.118849270 +0100
@@ -1,10 +1,10 @@ @@ -1,10 +1,10 @@
""" """
Base object supporting the storage of custom fields as attributes Base object supporting the storage of custom fields as attributes
@ -171,8 +192,8 @@ diff --unified --recursive '--exclude=.pylint-ignores.patch' original/objects/tr
self._trovebox = trovebox self._trovebox = trovebox
self._json_dict = json_dict self._json_dict = json_dict
diff --unified --recursive '--exclude=.pylint-ignores.patch' original/_version.py patched/_version.py diff --unified --recursive '--exclude=.pylint-ignores.patch' original/_version.py patched/_version.py
--- original/_version.py 2013-08-19 16:08:00.235047000 +0100 --- original/_version.py 2013-08-19 16:09:53.543609000 +0100
+++ patched/_version.py 2013-08-19 16:09:30.263494209 +0100 +++ patched/_version.py 2013-08-19 18:08:20.118849270 +0100
@@ -1,2 +1,2 @@ @@ -1,2 +1,2 @@
- -
+ # pylint: disable=C0111 + # pylint: disable=C0111

View file

@ -8,6 +8,7 @@ from trovebox.api import api_photo
from trovebox.api import api_tag from trovebox.api import api_tag
from trovebox.api import api_album from trovebox.api import api_album
from trovebox.api import api_action from trovebox.api import api_action
from trovebox.api import api_activity
LATEST_API_VERSION = 2 LATEST_API_VERSION = 2
@ -38,3 +39,5 @@ class Trovebox(Http):
self.albums = api_album.ApiAlbums(self) self.albums = api_album.ApiAlbums(self)
self.album = api_album.ApiAlbum(self) self.album = api_album.ApiAlbum(self)
self.action = api_action.ApiAction(self) self.action = api_action.ApiAction(self)
self.activities = api_activity.ApiActivities(self)
self.activity = api_activity.ApiActivity(self)

View file

@ -0,0 +1,36 @@
"""
api_activity.py : Trovebox Activity API Classes
"""
from trovebox.errors import TroveboxError
from trovebox.objects.activity import Activity
class ApiActivities(object):
""" Definitions of /activities/ API endpoints """
def __init__(self, client):
self._client = client
def list(self, **kwds):
""" Returns a list of Activity objects """
activities = self._client.get("/activities/list.json", **kwds)["result"]
return [Activity(self._client, activity) for activity in activities]
def purge(self, **kwds):
""" Purge all activities """
if not self._client.post("/activities/purge.json", **kwds)["result"]:
raise TroveboxError("Purge response returned False")
return True
class ApiActivity(object):
""" Definitions of /activity/ API endpoints """
def __init__(self, client):
self._client = client
def view(self, activity, **kwds):
"""
View an activity's contents.
Returns the requested activity object.
"""
if not isinstance(activity, Activity):
activity = Activity(self._client, {"id": activity})
activity.view(**kwds)
return activity

View file

@ -0,0 +1,40 @@
"""
Representation of an Activity object
"""
import json
from .trovebox_object import TroveboxObject
from .photo import Photo
class Activity(TroveboxObject):
""" Representation of an Activity object """
def __init__(self, trovebox, json_dict):
self.data = None
self.type = None
TroveboxObject.__init__(self, trovebox, json_dict)
self._update_fields_with_objects()
def _update_fields_with_objects(self):
""" Convert dict fields into objects, where appropriate """
# Update the data with photo objects
if self.type is not None:
if self.type.startswith("photo"):
self.data = Photo(self._trovebox, self.data)
else:
raise NotImplementedError("Unrecognised activity type: %s"
% self.type)
def view(self, **kwds):
"""
Requests the full contents of the activity.
Updates the activity's fields with the response.
"""
result = self._trovebox.get("/activity/%s/view.json" %
self.id, **kwds)["result"]
# TBD: Why is the result enclosed/encoded like this?
result = result["0"]
result["data"] = json.loads(result["data"])
self._replace_fields(result)
self._update_fields_with_objects()