From d43c8fb37902becb49b128a44ad351dd86850181 Mon Sep 17 00:00:00 2001 From: sneakypete81 Date: Sat, 1 Feb 2014 19:08:14 +0000 Subject: [PATCH] Ensure tag update/delete URLs are UTF-8 encoded --- tests/unit/test_tags.py | 24 ++++++++++++++++++++++-- trovebox/api/api_base.py | 10 ++++++++++ trovebox/api/api_tag.py | 9 ++------- 3 files changed, 34 insertions(+), 9 deletions(-) diff --git a/tests/unit/test_tags.py b/tests/unit/test_tags.py index 61292d4..da81717 100644 --- a/tests/unit/test_tags.py +++ b/tests/unit/test_tags.py @@ -10,13 +10,17 @@ import trovebox class TestTags(unittest.TestCase): test_host = "test.example.com" test_tags = None - test_tags_dict = [{"count": 11, "id":"tag1"}, - {"count": 5, "id":"tag2"}] + test_tags_dict = [{"count": 11, "id": "tag1"}, + {"count": 5, "id": "tag2"}] + + test_tag_unicode_dict = {"id": "\xfcmlaut"} def setUp(self): self.client = trovebox.Trovebox(host=self.test_host) self.test_tags = [trovebox.objects.tag.Tag(self.client, tag) for tag in self.test_tags_dict] + self.test_tag_unicode = trovebox.objects.tag.Tag(self.client, + self.test_tag_unicode_dict) @staticmethod def _return_value(result, message="", code=200): @@ -89,6 +93,14 @@ class TestTagDelete(TestTags): self.assertEqual(tag.get_fields(), {}) self.assertEqual(tag.id, None) + @mock.patch.object(trovebox.Trovebox, 'post') + def test_tag_object_delete_unicode(self, mock_post): + """Check that a unicode tag can be deleted using its ID""" + mock_post.return_value = self._return_value(True) + result = self.client.tag.delete(self.test_tag_unicode) + mock_post.assert_called_with("/tag/%C3%BCmlaut/delete.json") + self.assertEqual(result, True) + class TestTagUpdate(TestTags): @mock.patch.object(trovebox.Trovebox, 'post') def test_tag_update(self, mock_post): @@ -118,3 +130,11 @@ class TestTagUpdate(TestTags): self.assertEqual(tag.id, "tag2") self.assertEqual(tag.count, 5) + @mock.patch.object(trovebox.Trovebox, 'post') + def test_tag_object_update_unicode(self, mock_post): + """Check that a unicode tag can be updated using its ID""" + mock_post.return_value = self._return_value(self.test_tag_unicode_dict) + result = self.client.tag.update(self.test_tag_unicode, name="Test") + mock_post.assert_called_with("/tag/%C3%BCmlaut/update.json", name="Test") + self.assertEqual(result.id, "\xfcmlaut") + diff --git a/trovebox/api/api_base.py b/trovebox/api/api_base.py index 5aaf16c..52b06e8 100644 --- a/trovebox/api/api_base.py +++ b/trovebox/api/api_base.py @@ -1,6 +1,11 @@ """ api_base.py: Base class for all API classes """ +try: + from urllib.parse import quote # Python3 +except ImportError: + from urllib import quote # Python2 + class ApiBase(object): """ Base class for all API objects """ @@ -27,6 +32,11 @@ class ApiBase(object): except AttributeError: return obj + @staticmethod + def _quote_url(string): + """ Make a string suitable for insertion into a URL """ + return quote(string.encode('utf-8')) + @staticmethod def _result_to_list(result): """ Handle the case where the result contains no items """ diff --git a/trovebox/api/api_tag.py b/trovebox/api/api_tag.py index 898cffe..eca7916 100644 --- a/trovebox/api/api_tag.py +++ b/trovebox/api/api_tag.py @@ -1,11 +1,6 @@ """ api_tag.py : Trovebox Tag API Classes """ -try: - from urllib.parse import quote # Python3 -except ImportError: - from urllib import quote # Python2 - from trovebox.objects.tag import Tag from .api_base import ApiBase @@ -42,7 +37,7 @@ class ApiTag(ApiBase): Raises a TroveboxError if not. """ return self._client.post("/tag/%s/delete.json" % - quote(self._extract_id(tag)), + self._quote_url(self._extract_id(tag)), **kwds)["result"] def update(self, tag, **kwds): @@ -53,7 +48,7 @@ class ApiTag(ApiBase): Returns the updated tag object. """ result = self._client.post("/tag/%s/update.json" % - quote(self._extract_id(tag)), + self._quote_url(self._extract_id(tag)), **kwds)["result"] return Tag(self._client, result)