From 69512489a063d8b4fee7070d33027812ae7d4b7f Mon Sep 17 00:00:00 2001 From: carycheng Date: Tue, 21 Aug 2018 16:32:45 -0700 Subject: [PATCH 1/2] files endpoint --- boxsdk/object/__init__.py | 1 + boxsdk/object/base_api_json_object.py | 10 +++ boxsdk/object/item.py | 50 ++++++++++++ boxsdk/object/retention_policy.py | 75 ++++++++++++++++++ boxsdk/object/retention_policy_assignment.py | 7 ++ test/unit/client/test_client.py | 45 +++++++++++ test/unit/object/conftest.py | 12 +++ test/unit/object/test_retention_policy.py | 79 +++++++++++++++++++ .../test_retention_policy_assignment.py | 14 ++++ 9 files changed, 293 insertions(+) create mode 100644 boxsdk/object/retention_policy.py create mode 100644 boxsdk/object/retention_policy_assignment.py create mode 100644 test/unit/object/test_retention_policy.py create mode 100644 test/unit/object/test_retention_policy_assignment.py diff --git a/boxsdk/object/__init__.py b/boxsdk/object/__init__.py index 3d83fbe50..11f3c561b 100644 --- a/boxsdk/object/__init__.py +++ b/boxsdk/object/__init__.py @@ -16,6 +16,7 @@ 'group', 'group_membership', 'recent_item', + 'retention_policy', 'search', 'user', ])) diff --git a/boxsdk/object/base_api_json_object.py b/boxsdk/object/base_api_json_object.py index 00b52dc76..510f76ad9 100644 --- a/boxsdk/object/base_api_json_object.py +++ b/boxsdk/object/base_api_json_object.py @@ -134,3 +134,13 @@ def response_object(self): `dict` """ return copy.deepcopy(self._response_object) + + @property + def object_type(self): + """Return the Box type for the object. + + :rtype: + `unicode` + """ + return self._item_type + diff --git a/boxsdk/object/item.py b/boxsdk/object/item.py index 1050d7736..7b8edc11d 100644 --- a/boxsdk/object/item.py +++ b/boxsdk/object/item.py @@ -357,6 +357,56 @@ def metadata(self, scope='global', template='properties'): """ return Metadata(self._session, self, scope, template) + def create_metadata(self, key_1, scope, template, key_2=None): + """ + Create a metadata instance for a file. + :param key_1: + Key value pair to add to metadata. + :type key_1: + `dict` + :param scope: + The scope of the metadata object. + :type scope: + `unicode` + :param template: + The key of the template + :type template: + `unicode` + """ + url = self.get_url('metadata', scope, template) + body = { + key_1 + } + if key_2 is not None: + body.update(key_2) + headers = {'Content-Type': 'application/json'} + response = self._session.post(url, data=json.dumps(body), headers=headers).json() + return Translator().translate(response['type'])( + self._session, + response['id'], + response, + ) + + def delete_metadata(self, scope, template): + """ + Delete metadata instance on the item. + :param scope: + The scope of the metadata object. + :type scope: + `unicode` + :param template: + The key of the template + :type template: + `unicode` + """ + url = self.get_url('metadata', scope, template) + response = self._session.delete(url, data=json.dumps(body), headers=headers).json() + return Translator().translate(response['type'])( + self._session, + response['id'], + response, + ) + @api_call def add_to_collection(self, collection): """ diff --git a/boxsdk/object/retention_policy.py b/boxsdk/object/retention_policy.py new file mode 100644 index 000000000..18cd637ab --- /dev/null +++ b/boxsdk/object/retention_policy.py @@ -0,0 +1,75 @@ +# coding: utf-8 +from __future__ import unicode_literals + +import json + +from .base_object import BaseObject +from boxsdk.util.translator import Translator +from ..config import API +from ..pagination.marker_based_object_collection import MarkerBasedObjectCollection + + +class RetentionPolicy(BaseObject): + """Represents a Box retention policy.""" + _item_type = 'retention_policy' + + def get_url(self, *args): return self._session.get_url('retention_policies', self._object_id, *args) + + def assign(self, item, fields=None): + """Assign a retention policy to a Box item + :param item: + The item to assign the retention policy on. + :type item: + `object` + :param fields: + List of fields to request. + :type fields: + `Iterable` of `unicode` + """ + url = self._session.get_url('retention_policy_assignments') + body = { + 'policy_id': self.object_id, + 'assign_to': { + 'type': item.object_type, + 'id': item.object_id + } + } + response = self._session.post(url, data=json.dumps(body)).json() + return Translator().translate(response['type'])( + self._session, + response['id'], + response, + ) + + def assignments(self, assignment_type=None, limit=None, marker=None, fields=None): + """Get the assignments for the retention policy. + :param limit: + The maximum number of items to return. + :type limit: + `int` + :param marker: + The position marker at which to begin the response. + :type marker: + `unicode` + :param fields: + List of fields to request. + :type fields: + `Iterable` of `unicode` + :returns: + A list of assignments in the retention policy. + :rtype: + `list` of :class:`RetentionPolicyAssignment` + """ + additional_params = { + 'type': assignment_type, + } + return MarkerBasedObjectCollection( + session=self._session, + url='{0}/retention_policies/{1}/assignments'.format(API.BASE_API_URL, self.object_id), + additional_params=additional_params, + limit=limit, + marker=marker, + fields=fields, + return_full_pages=False + ) + diff --git a/boxsdk/object/retention_policy_assignment.py b/boxsdk/object/retention_policy_assignment.py new file mode 100644 index 000000000..c6b7432c1 --- /dev/null +++ b/boxsdk/object/retention_policy_assignment.py @@ -0,0 +1,7 @@ +# coding: utf-8 +from __future__ import unicode_literals +from .base_object import BaseObject + +class RetentionPolicyAssignment(BaseObject): + """Represents a Box retention policy assignment.""" + _item_type = 'retention_policy_assignment' diff --git a/test/unit/client/test_client.py b/test/unit/client/test_client.py index 4997a7648..6ab03d755 100644 --- a/test/unit/client/test_client.py +++ b/test/unit/client/test_client.py @@ -23,6 +23,7 @@ from boxsdk.object.group import Group from boxsdk.object.user import User from boxsdk.object.group_membership import GroupMembership +from boxsdk.object.retention_policy import RetentionPolicy from boxsdk.pagination.marker_based_object_collection import MarkerBasedObjectCollection @@ -282,6 +283,50 @@ def test_groups_return_the_correct_group_objects( assert group._session == mock_box_session +def test_create_retention_policy(mock_client, mock_box_session): + policy_name = 'Test Retention Policy' + policy_type = 'indefinite' + disposition_action = 'remove_retention' + expected_url = mock_box_session.get_url('retention_policies') + expected_data = { + 'policy_name': policy_name, + 'policy_type': policy_type, + 'disposition_action': disposition_action, + 'can_owner_extend_retention': False, + 'are_owners_notified': False + } + mock_policy = { + 'type': 'retention_policy', + 'id': '1234', + 'policy_name': policy_name, + } + mock_box_session.post.return_value.json.return_value = mock_policy + policy = mock_client.create_retention_policy(policy_name, policy_type, disposition_action) + mock_box_session.post.assert_called_once_with(expected_url, data=json.dumps(expected_data)) + assert policy.id == mock_policy['id'] + assert policy.type == mock_policy['type'] + + +def test_get_retention_policies(mock_client, mock_box_session): + expected_url = mock_box_session.get_url('retention_policies') + mock_policy = { + 'type': 'retention_policy', + 'id': '12345', + 'name': 'Test Retention Policy' + } + mock_box_session.get.return_value.json.return_value = { + 'limit': 100, + 'entries': [mock_policy], + 'next_marker': 'testMarker' + } + policies = mock_client.retention_policies() + policy = policies.next() + mock_box_session.get.assert_called_once_with(expected_url, params={'policy_name': None, 'policy_type': None, 'created_by_user_id': None}) + assert isinstance(policy, RetentionPolicy) + assert policy.id == mock_policy['id'] + assert policy.name == mock_policy['name'] + + def test_create_group_returns_the_correct_group_object(mock_client, mock_box_session, create_group_response): # pylint:disable=redefined-outer-name test_group_name = 'test_group_name' diff --git a/test/unit/object/conftest.py b/test/unit/object/conftest.py index 021e4d384..24048a835 100644 --- a/test/unit/object/conftest.py +++ b/test/unit/object/conftest.py @@ -12,6 +12,8 @@ from boxsdk.object.file import File from boxsdk.object.folder import Folder from boxsdk.object.group import Group +from boxsdk.object.retention_policy import RetentionPolicy +from boxsdk.object.retention_policy_assignment import RetentionPolicyAssignment from boxsdk.object.user import User from boxsdk.object.search import Search @@ -91,6 +93,16 @@ def test_group(mock_box_session, mock_group_id): return Group(mock_box_session, mock_group_id) +@pytest.fixture() +def test_retention_policy(mock_box_session, mock_object_id): + return RetentionPolicy(mock_box_session, mock_object_id) + + +@pytest.fixture() +def test_retention_policy_assignment(mock_box_session, mock_object_id): + return RetentionPolicyAssignment(mock_box_session, mock_object_id) + + @pytest.fixture() def test_search(mock_box_session): return Search(mock_box_session) diff --git a/test/unit/object/test_retention_policy.py b/test/unit/object/test_retention_policy.py new file mode 100644 index 000000000..491e04b53 --- /dev/null +++ b/test/unit/object/test_retention_policy.py @@ -0,0 +1,79 @@ +from __future__ import unicode_literals + +import json + +from boxsdk.config import API +from boxsdk.object.retention_policy import RetentionPolicy +from boxsdk.object.retention_policy_assignment import RetentionPolicyAssignment + + +def test_get(test_retention_policy, mock_box_session): + expected_url = '{0}/retention_policies/{1}'.format(API.BASE_API_URL, test_retention_policy.object_id) + mock_box_session.get.return_value.json.return_value = { + 'type': 'retention_policy', + 'id': test_retention_policy.object_id, + } + retention_policy = test_retention_policy.get() + mock_box_session.get.assert_called_once_with(expected_url, headers=None, params=None) + assert isinstance(retention_policy, RetentionPolicy) + + +def test_update(test_retention_policy, mock_box_session): + new_policy_name = 'New Name' + expected_url = '{0}/retention_policies/{1}'.format(API.BASE_API_URL, test_retention_policy.object_id) + mock_box_session.get.return_value.json.return_value = { + 'type': 'retention_policy', + 'id': test_retention_policy.object_id, + } + retention_policy = test_retention_policy.update_info({ + 'policy_name': new_policy_name + }) + data = { + 'policy_name': new_policy_name + } + mock_box_session.put.assert_called_once_with(expected_url, data=json.dumps(data), headers=None, params=None) + assert isinstance(retention_policy, RetentionPolicy) + + +def test_assign(test_retention_policy, test_folder, mock_box_session): + policy_id = '42' + expected_url = mock_box_session.get_url('retention_policy_assignments') + expected_data = { + 'policy_id': policy_id, + 'assign_to': { + 'type': test_folder.object_type, + 'id': test_folder.object_id, + } + } + mock_assignment = { + 'type': 'retention_policy_assignment', + 'id': '1234', + 'retention_policy': { + 'type': 'retention_policy', + 'id': policy_id + } + } + mock_box_session.post.return_value.json.return_value = mock_assignment + assignment = test_retention_policy.assign(test_folder) + mock_box_session.post.assert_called_once_with(expected_url, data=json.dumps(expected_data)) + assert assignment.id == mock_assignment['id'] + assert assignment.retention_policy['id'] == mock_assignment['retention_policy']['id'] + + +def test_get_assignments(test_retention_policy, mock_box_session): + expected_url = test_retention_policy.get_url('assignments') + mock_assignment = { + 'type': 'retention_policy_assignment', + 'id': '12345' + } + mock_box_session.get.return_value.json.return_value = { + 'limit': 100, + 'entries': [mock_assignment], + 'next_marker': 'testMarter' + } + assignments = test_retention_policy.assignments() + assignment = assignments.next() + mock_box_session.get.assert_called_once_with(expected_url, params={'type': None}) + assert isinstance(assignment, RetentionPolicyAssignment) + assert assignment.id == mock_assignment['id'] + assert assignment.type == mock_assignment['type'] \ No newline at end of file diff --git a/test/unit/object/test_retention_policy_assignment.py b/test/unit/object/test_retention_policy_assignment.py new file mode 100644 index 000000000..a372b7587 --- /dev/null +++ b/test/unit/object/test_retention_policy_assignment.py @@ -0,0 +1,14 @@ +from __future__ import unicode_literals +from boxsdk.config import API +from boxsdk.object.retention_policy_assignment import RetentionPolicyAssignment + + +def test_get_assignment(test_retention_policy_assignment, mock_box_session): + expected_url = '{0}/retention_policy_assignments/{1}'.format(API.BASE_API_URL, test_retention_policy_assignment.object_id) + mock_box_session.get.return_value.json.return_value = { + 'type': 'retention_policy_assignment', + 'id': test_retention_policy_assignment.object_id, + } + retention_policy_assignment = test_retention_policy_assignment.get() + mock_box_session.get.assert_called_once_with(expected_url, headers=None, params=None) + assert isinstance(retention_policy_assignment, RetentionPolicyAssignment) From 237a20d9268e04600aa80f2ed9b509980a032b80 Mon Sep 17 00:00:00 2001 From: carycheng Date: Tue, 21 Aug 2018 16:41:12 -0700 Subject: [PATCH 2/2] removing uncecessary body --- boxsdk/object/item.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/boxsdk/object/item.py b/boxsdk/object/item.py index 7b8edc11d..ee646857a 100644 --- a/boxsdk/object/item.py +++ b/boxsdk/object/item.py @@ -400,7 +400,7 @@ def delete_metadata(self, scope, template): `unicode` """ url = self.get_url('metadata', scope, template) - response = self._session.delete(url, data=json.dumps(body), headers=headers).json() + response = self._session.delete(url, headers=headers).json() return Translator().translate(response['type'])( self._session, response['id'],