Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
9067f01
front porting storage policies
Aug 21, 2018
b317656
fixed tests for client and added object_type in base object
Aug 24, 2018
dcba51c
removed extraneous line in storage policy assignment
Aug 24, 2018
c196988
removed extraneous lines from test_storage_policy_assignment
Aug 24, 2018
5654ae0
switched import order
Aug 24, 2018
51ddeff
added docs for storage policy endpoint
Aug 27, 2018
2d80470
fixed docs for storage policy and removed constructors usage
Sep 7, 2018
e6a3e8b
fixed updates to storage policies
Sep 7, 2018
55505d8
updated docs and moved assignment onto user
Sep 10, 2018
52f6bc8
fixed assign on storage policy
Sep 10, 2018
c9fd61b
removedu unused fields
Sep 10, 2018
5bfc330
added limit and marker
Sep 11, 2018
409023d
removed unused fields
Sep 11, 2018
197bace
removed unused import
Sep 11, 2018
b5af4fa
fixed from feedback
Sep 14, 2018
e19babf
changes to storage policy
Sep 16, 2018
1c6d8af
fixed docs for storage policy
Sep 17, 2018
eff576b
removed unused lines
Sep 17, 2018
072f68a
removed unused import
Sep 17, 2018
defb9f1
fixed from feedback
Sep 17, 2018
f60b81c
Merge branch 'master' into storage_policies_v2
Sep 29, 2018
146284a
updates to storage policies
Oct 24, 2018
23ba14a
added tests for storage policy assign method
Oct 24, 2018
ed17f80
Merge branch 'master' into storage_policies_v2
Oct 24, 2018
e90bb38
replace hard coded type
Oct 24, 2018
f0465dd
Merge branch 'storage_policies_v2' of https://github.com/box/box-pyth…
Oct 24, 2018
81cb159
added asserts to test client for storage policies get
Oct 25, 2018
1ef7425
converted translator to use new one
Oct 25, 2018
afc6ee9
added test for storage policy and storage policy constructor returns …
Oct 25, 2018
2885870
Merge branch 'master' into storage_policies_v2
Oct 26, 2018
470b334
Merge branch 'master' into storage_policies_v2
Oct 26, 2018
d262b8c
added end of paging method
Oct 26, 2018
c3d34ce
added additional line spacing between tests in test_client
Oct 26, 2018
8d10cc6
Merge branch 'master' into storage_policies_v2
Oct 26, 2018
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
60 changes: 60 additions & 0 deletions boxsdk/client/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -692,6 +692,66 @@ def create_group(
response_object=response,
)

def storage_policy(self, policy_id):
"""
Initialize a :class:`StoragePolicy` object, whose box id is policy_id.

:param policy_id:
The box ID of the :class:`StoragePolicy` object.
:type policy_id:
`unicode`
:return:
A :class:`StoragePolicy` object with the given entry ID.
:rtype:
:class:`StoragePolicy`
"""
return self.translator.get('storage_policy')(session=self._session, object_id=policy_id)

def storage_policy_assignment(self, assignment_id):
"""
Initialize a :class:`StoragePolicyAssignment` object, whose box id is assignment_id.

:param assignment_id:
The box ID of the :class:`StoragePolicyAssignment` object.
:type assignment_id:
`unicode`
:return:
A :class:`StoragePolicyAssignment` object with the given entry ID.
:rtype:
:class:`StoragePolicyAssignment`
"""
return self.translator.get('storage_policy_assignment')(session=self._session, object_id=assignment_id)

def get_storage_policies(self, limit=None, marker=None, fields=None):
"""
Get the entries in the storage policy using marker-based paging.

:param limit:
The maximum number of items to return.
:type limit:
`int` or None
:param marker:
The paging marker to start returning items from when using marker-based paging.
:type marker:
`unicode` or None
:param fields:
List of fields to request.
:type fields:
`Iterable` of `unicode`
:returns:
Returns the storage policies available for the current enterprise.
:rtype:
:class:`BoxObjectCollection`
"""
return MarkerBasedObjectCollection(
session=self._session,
url=self.get_url('storage_policies'),
limit=limit,
marker=marker,
fields=fields,
return_full_pages=False,
)

def terms_of_service(self, tos_id):
"""
Initialize a :class:`TermsOfService` object, whose box id is tos_id.
Expand Down
2 changes: 2 additions & 0 deletions boxsdk/object/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@
'retention_policy',
'retention_policy_assignment',
'search',
'storage_policy',
'storage_policy_assignment',
'terms_of_service',
'terms_of_service_user_status',
'trash',
Expand Down
77 changes: 77 additions & 0 deletions boxsdk/object/storage_policy.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
# coding:utf-8
from __future__ import unicode_literals, absolute_import

import json

from .base_object import BaseObject


class StoragePolicy(BaseObject):
"""Represents the storage policy"""

_item_type = 'storage_policy'

def get_url(self, *args):
"""
Get url for storage policies.
"""
return self._session.get_url('storage_policies', self._object_id, *args)

def assign(self, user):
"""
Checks to see if a user is already assigned a storage policy or if the storage policy assigned
to user belongs to the enterprise. If neither, then update the user storage policy to the new one.

:param user:
The class:`User` to assign the storage policy to
:type user:
:class:`User`
:returns:
Information about the :class:`StoragePolicyAssignment` object.
:rtype:
:class:`StoragePolicyAssignment`
"""
assignment = user.get_storage_policy_assignment()
if assignment.id == self.object_id:
return assignment

if assignment.assigned_to['type'] == 'enterprise':
return self.create_assignment(user)

update_object = {
'storage_policy': {
'type': self.object_type,
'id': self.object_id,
},
}
return assignment.update_info(update_object)

def create_assignment(self, user):
"""
Assign a storage policy to a :class:`User`.

:param user:
The :class:'User` to assign the storage policy to.
:type:
:class:`User`
:returns:
Information about the :class:`StoragePolicyAssignment` object
:rtype:
:class:`StoragePolicyAssignment`
"""
url = self._session.get_url('storage_policy_assignments')
body = {
'storage_policy': {
'type': 'storage_policy',
'id': self.object_id,
},
'assigned_to': {
'type': user.object_type,
'id': user.object_id,
}
}
response = self._session.post(url, data=json.dumps(body)).json()
return self.translator.translate(
session=self._session,
response_object=response,
)
9 changes: 9 additions & 0 deletions boxsdk/object/storage_policy_assignment.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# coding:utf-8
from __future__ import unicode_literals, absolute_import
from .base_object import BaseObject


class StoragePolicyAssignment(BaseObject):
"""Represents the storage policy assignment"""

_item_type = 'storage_policy_assignment'
21 changes: 21 additions & 0 deletions boxsdk/object/user.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,27 @@ class User(BaseObject):

_item_type = 'user'

def get_storage_policy_assignment(self):
"""
Get the storage policy assignment assigned to the user.

:returns:
The :class:`StoragePolicyAssignment` object information
:rtype:
:class:`StoragePolicyAssignment`
"""
url = self._session.get_url('storage_policy_assignments')
additional_params = {
'resolved_for_type': self.object_type,
'resolved_for_id': self.object_id,
}
box_response = self._session.get(url, params=additional_params)
response = box_response.json()['entries'][0]
return self.translator.translate(
session=self._session,
response_object=response,
)

@api_call
def get_group_memberships(self, limit=None, offset=None, fields=None):
"""
Expand Down
91 changes: 91 additions & 0 deletions docs/storage_policy.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
Storage Policy
==============

Allows the enterprise admin to manage the Storage Policies for users in their
enterprise. Used for an enterprise to decide storage location for users based on
where they work/reside.


Get Storage Policy
------------------

Calling `storage_policy.get(fields=None)` will return the storage policy object.

```python
storage_policy_id = '1234'
storage_policy = client.storage_policy(storage_policy_id).get()
```

List Available Storage Policies
-------------------------------

Calling `client.get_storage_policies()` will return an iterable that will page through all of the storage policies. It is possible to specify maxiumum number of items per response and fields to retrieve by caling `client.get_storage_policies(limit=None, fields=None)`.

```python
storage_policies = client.get_storage_policies(limit=100)
for storage_policy in storage_policies:
# Do something
```

Create Storage Policy Assignment
--------------------------------

To create new storage policy assignment call `storage_policy.create_assignment(user)`.

```python
storage_policy_id = '5678'
user = client.user('1234')
storage_policy_assignment = client.storage_policy(storage_policy_id).create_assignment(user)
```

Note: This method only works if the user does not already have an assignment. If the current state of the user is not known, use the `storage_policy.assign(user)` method instead.

Assign a Storage Policy to a User
---------------------------------

To assign a storage policy to a user, call the `storage_policy.assign(user)` method with the user to assign the storage policy to.

```python
user = client.user('1234')
storage_policy_assignment = client.storage_policy('12345').assign(user)
```

Update Existing Assignment
--------------------------

Updating a storage policy assignment is done by calling `storage_policy.update_info(update_item)`.

```python
updated_storage_policy = {'storage_policy': {'type': 'storage_policy', 'id': '1234'}}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We might want to consider creating an override for this method to enable just passing in a StoragePolicy (since that's the only thing that can be updated)

updated_assignment = client.storage_policy_assignment('ZW50ZXJwcmldfgeV82MDMwMDQ=').update_info(updated_storage_policy)
```

Get Assignment
--------------

Calling `storage_policy_assignment.get(fields=None)` will return a storage policy assignment object containing information about the assignment.

```python
assignment_id = '1234'
storage_policy_assignment = client.storage_policy_assignment(assignment_id).get()
```

Get Assignment for User
-------------------------

Calling `user.get_storage_policy_assignment()` will return the storage policy assigned to the specified user.

```python
user_id = '1111'
assignment_info = client.user(user_id).get_storage_policy_assignment()
```

Delete Assignment
-----------------

Calling `storage_policy_assignment.delete()` will remove the storage policy assignment from the user.

```python
assignment_id = '1234'
client.storage_policy_assignment(assignment_id).delete()
```
26 changes: 25 additions & 1 deletion test/unit/client/test_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@
from boxsdk.object.folder import Folder
from boxsdk.object.file import File
from boxsdk.object.group import Group
from boxsdk.object.storage_policy import StoragePolicy
from boxsdk.object.storage_policy_assignment import StoragePolicyAssignment
from boxsdk.object.terms_of_service import TermsOfService
from boxsdk.object.user import User
from boxsdk.object.trash import Trash
Expand Down Expand Up @@ -367,7 +369,9 @@ def device_pins_response(device_pin_id_1, device_pin_id_2):
(Group, 'group'),
(GroupMembership, 'group_membership'),
(Enterprise, 'enterprise'),
(Webhook, 'webhook')
(Webhook, 'webhook'),
(StoragePolicy, 'storage_policy'),
(StoragePolicyAssignment, 'storage_policy_assignment'),
])
def test_factory_returns_the_correct_object(mock_client, test_class, factory_method_name):
""" Tests the various id-only factory methods in the Client class """
Expand Down Expand Up @@ -632,6 +636,26 @@ def test_create_enterprise_user_returns_the_correct_user_object(mock_client, moc
assert new_user.name == test_user_name


def test_get_storage_policies(mock_client, mock_box_session):
expected_url = mock_box_session.get_url('storage_policies')
mock_policy = {
'type': 'storage_policy',
'id': '12345',
'name': 'Test Storage Policy'
}
mock_box_session.get.return_value.json.return_value = {
'limit': 100,
'entries': [mock_policy]
}
policies = mock_client.get_storage_policies()
policy = policies.next()
mock_box_session.get.assert_called_once_with(expected_url, params={})
assert isinstance(policy, StoragePolicy)
assert policy.type == 'storage_policy'
assert policy.id == '12345'
assert policy.name == 'Test Storage Policy'


def test_create_terms_of_service(mock_client, mock_box_session):
# pylint:disable=redefined-outer-name
expected_url = "{0}/terms_of_services".format(API.BASE_API_URL)
Expand Down
12 changes: 12 additions & 0 deletions test/unit/object/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@
from boxsdk.object.retention_policy import RetentionPolicy
from boxsdk.object.retention_policy_assignment import RetentionPolicyAssignment
from boxsdk.object.search import Search
from boxsdk.object.storage_policy import StoragePolicy
from boxsdk.object.storage_policy_assignment import StoragePolicyAssignment
from boxsdk.object.terms_of_service import TermsOfService
from boxsdk.object.terms_of_service_user_status import TermsOfServiceUserStatus
from boxsdk.object.collaboration_whitelist import CollaborationWhitelist
Expand Down Expand Up @@ -161,6 +163,16 @@ def test_search(mock_box_session):
return Search(mock_box_session)


@pytest.fixture()
def test_storage_policy(mock_box_session, mock_object_id):
return StoragePolicy(mock_box_session, mock_object_id)


@pytest.fixture()
def test_storage_policy_assignment(mock_box_session, mock_object_id):
return StoragePolicyAssignment(mock_box_session, mock_object_id)


@pytest.fixture()
def test_terms_of_service(mock_box_session, mock_object_id):
return TermsOfService(mock_box_session, mock_object_id)
Expand Down
Loading