Skip to content

Commit

Permalink
Merge d1d26e7 into 75206f5
Browse files Browse the repository at this point in the history
  • Loading branch information
lukaszsocha2 committed Sep 13, 2022
2 parents 75206f5 + d1d26e7 commit d531b47
Show file tree
Hide file tree
Showing 8 changed files with 111 additions and 16 deletions.
10 changes: 10 additions & 0 deletions boxsdk/client/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -862,6 +862,7 @@ def create_retention_policy(
can_owner_extend_retention: Optional[bool] = None,
are_owners_notified: Optional[bool] = None,
custom_notification_recipients: Iterable['User'] = None,
retention_type: Optional[str] = None
) -> 'RetentionPolicy':
"""
Create a retention policy for the given enterprise.
Expand All @@ -880,6 +881,13 @@ def create_retention_policy(
The owner or co-owner will get notified when a file is nearing expiration.
:param custom_notification_recipients:
A custom list of user mini objects that should be notified when a file is nearing expiration.
:param retention_type:
Specifies the retention type. It can be one of the values:
- `modifiable`: You can modify the retention policy. For example, you can add or remove folders,
shorten or lengthen the policy duration, or delete the assignment.
- `non_modifiable`: You can modify the retention policy only in a limited way: add a folder,
lengthen the duration, retire the policy, change the disposition action or notification settings.
You cannot perform other actions, such as deleting the assignment or shortening the policy duration.
:return:
The newly created Retention Policy
"""
Expand All @@ -900,6 +908,8 @@ def create_retention_policy(
if custom_notification_recipients is not None:
user_list = [{'type': user.object_type, 'id': user.object_id} for user in custom_notification_recipients]
retention_attributes['custom_notification_recipients'] = user_list
if retention_type is not None:
retention_attributes['retention_type'] = retention_type
box_response = self._session.post(url, data=json.dumps(retention_attributes))
response = box_response.json()
return self.translator.translate(
Expand Down
5 changes: 3 additions & 2 deletions test/integration_new/context_managers/box_retention_policy.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

class BoxRetentionPolicy:

DEFAULT_RETENTION_POLICY_NAME = "retention_policy_for_integration_tests"
DEFAULT_RETENTION_POLICY_NAME = "modifiable_retention_policy_for_integration_tests"

def __init__(
self,
Expand All @@ -25,7 +25,8 @@ def __init__(
self._retention_policy: RetentionPolicy = USER_CLIENT.create_retention_policy(
policy_name=name,
disposition_action=disposition_action,
retention_length=retention_length
retention_length=retention_length,
retention_type='modifiable'
)

def __enter__(self) -> RetentionPolicy:
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
from typing import Any, Union

from boxsdk.object.enterprise import Enterprise
from boxsdk.object.folder import Folder
from boxsdk.object.metadata_template import MetadataTemplate
from boxsdk.object.retention_policy import RetentionPolicy
from boxsdk.object.retention_policy_assignment import RetentionPolicyAssignment


class BoxRetentionPolicyAssignment:

def __init__(
self,
retention_policy: RetentionPolicy,
assignee: Union['Folder', 'Enterprise', 'MetadataTemplate']
):
self._retention_policy_assignment = retention_policy.assign(assignee)

def __enter__(self) -> RetentionPolicyAssignment:
return self._retention_policy_assignment

def __exit__(self, exc_type: Any, exc_val: Any, exc_tb: Any) -> None:
self._retention_policy_assignment.delete()
22 changes: 11 additions & 11 deletions test/integration_new/object/file_itest.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import pytz

from boxsdk import BoxAPIException
from test.integration_new.context_managers.box_retention_policy_assigment import BoxRetentionPolicyAssignment
from test.integration_new.context_managers.box_retention_policy import BoxRetentionPolicy
from test.integration_new import util
from test.integration_new.context_managers.box_test_file import BoxTestFile
Expand Down Expand Up @@ -252,17 +253,16 @@ def test_copy(test_file, parent_folder):
def test_set_disposition_at(parent_folder, small_file_path):
with BoxRetentionPolicy(disposition_action='permanently_delete', retention_length=1) as retention_policy:
with BoxTestFolder(name=f'{FILE_TESTS_DIRECTORY_NAME} {datetime.now()}') as folder_under_retention:
retention_policy.assign(folder_under_retention)
with BoxRetentionPolicyAssignment(retention_policy=retention_policy, assignee=folder_under_retention):
with BoxTestFile(parent_folder=folder_under_retention, file_path=small_file_path) as file_under_retention:
old_disposition_str = file_under_retention.get(fields=('disposition_at',)).disposition_at
old_disposition_datetime = parser.parse(old_disposition_str)

with BoxTestFile(parent_folder=folder_under_retention, file_path=small_file_path) as file_under_retention:
old_disposition_str = file_under_retention.get(fields=('disposition_at',)).disposition_at
old_disposition_datetime = parser.parse(old_disposition_str)
new_disposition_date = datetime.now().replace(microsecond=0).astimezone(pytz.utc) + timedelta(days=2)
file_under_retention.set_disposition_at(new_disposition_date)

new_disposition_date = datetime.now().replace(microsecond=0).astimezone(pytz.utc) + timedelta(days=2)
file_under_retention.set_disposition_at(new_disposition_date)
updated_disposition_str = file_under_retention.get(fields=('disposition_at',)).disposition_at
updated_disposition_datetime = parser.parse(updated_disposition_str)

updated_disposition_str = file_under_retention.get(fields=('disposition_at',)).disposition_at
updated_disposition_datetime = parser.parse(updated_disposition_str)

assert updated_disposition_datetime.astimezone(pytz.utc) == new_disposition_date
assert updated_disposition_datetime.astimezone(pytz.utc) != old_disposition_datetime.astimezone(pytz.utc)
assert updated_disposition_datetime.astimezone(pytz.utc) == new_disposition_date
assert updated_disposition_datetime.astimezone(pytz.utc) != old_disposition_datetime.astimezone(pytz.utc)
36 changes: 36 additions & 0 deletions test/integration_new/object/retention_policy_assignement_itest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
from datetime import datetime
import pytest

from boxsdk import BoxAPIException
from test.integration_new.context_managers.box_retention_policy import BoxRetentionPolicy
from test.integration_new.context_managers.box_test_file import BoxTestFile
from test.integration_new.context_managers.box_test_folder import BoxTestFolder


RETENTION_POLICY_ASSIGNMENT_TESTS_DIRECTORY_NAME = 'retention-policy-assignment-integration-tests'


@pytest.fixture(scope="module", autouse=True)
def parent_folder():
with BoxTestFolder(name=f'{RETENTION_POLICY_ASSIGNMENT_TESTS_DIRECTORY_NAME} {datetime.now()}') as folder:
yield folder


@pytest.fixture(scope="module", autouse=True)
def test_file(parent_folder, small_file_path):
with BoxTestFile(parent_folder=parent_folder, file_path=small_file_path) as file:
yield file


def test_delete_retention_policy_assignment(parent_folder, small_file_path):
with BoxRetentionPolicy(disposition_action='permanently_delete', retention_length=1) as retention_policy:
with BoxTestFolder(name=f'{RETENTION_POLICY_ASSIGNMENT_TESTS_DIRECTORY_NAME} {datetime.now()}') as folder_under_retention:
retention_policy_assignment = retention_policy.assign(folder_under_retention)

assignment = retention_policy_assignment.get()
assert assignment.id is not None

retention_policy_assignment.delete()

with pytest.raises(BoxAPIException):
retention_policy_assignment.get()
12 changes: 10 additions & 2 deletions test/unit/client/test_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -912,6 +912,7 @@ def test_create_retention_policy(mock_client, mock_box_session, mock_user_list):
'id': mock_user_list[1].object_id,
},
],
'retention_type': 'modifiable'
}
mock_policy = {
'type': 'retention_policy',
Expand All @@ -932,6 +933,7 @@ def test_create_retention_policy(mock_client, mock_box_session, mock_user_list):
'id': mock_user_list[1].object_id,
},
],
'retention_type': 'modifiable'
}
mock_box_session.post.return_value.json.return_value = mock_policy
policy = mock_client.create_retention_policy(
Expand All @@ -940,7 +942,8 @@ def test_create_retention_policy(mock_client, mock_box_session, mock_user_list):
retention_length=5,
can_owner_extend_retention=True,
are_owners_notified=False,
custom_notification_recipients=mock_user_list
custom_notification_recipients=mock_user_list,
retention_type='modifiable'
)
mock_box_session.post.assert_called_once_with(expected_url, data=json.dumps(expected_data))
assert policy.object_id == mock_policy['id']
Expand All @@ -949,6 +952,7 @@ def test_create_retention_policy(mock_client, mock_box_session, mock_user_list):
assert policy.disposition_action == mock_policy['disposition_action']
assert policy.can_owner_extend_retention == mock_policy['can_owner_extend_retention']
assert policy.are_owners_notified == mock_policy['are_owners_notified']
assert policy.retention_type == mock_policy['retention_type']
assert isinstance(policy, RetentionPolicy)


Expand All @@ -963,6 +967,7 @@ def test_create_infinte_retention_policy(mock_client, mock_box_session):
'policy_type': policy_type,
'can_owner_extend_retention': False,
'are_owners_notified': False,
'retention_type': 'non_modifiable',
}
mock_policy = {
'type': 'retention_policy',
Expand All @@ -972,14 +977,16 @@ def test_create_infinte_retention_policy(mock_client, mock_box_session):
'disposition_action': disposition_action,
'can_owner_extend_retention': False,
'are_owners_notified': False,
'retention_type': 'non_modifiable',
}
mock_box_session.post.return_value.json.return_value = mock_policy
policy = mock_client.create_retention_policy(
policy_name=policy_name,
disposition_action=disposition_action,
retention_length=float('inf'),
can_owner_extend_retention=False,
are_owners_notified=False
are_owners_notified=False,
retention_type='non_modifiable'
)
mock_box_session.post.assert_called_once_with(expected_url, data=json.dumps(expected_data))
assert policy.object_id == mock_policy['id']
Expand All @@ -988,6 +995,7 @@ def test_create_infinte_retention_policy(mock_client, mock_box_session):
assert policy.disposition_action == mock_policy['disposition_action']
assert policy.can_owner_extend_retention == mock_policy['can_owner_extend_retention']
assert policy.are_owners_notified == mock_policy['are_owners_notified']
assert policy.retention_type == mock_policy['retention_type']
assert isinstance(policy, RetentionPolicy)


Expand Down
9 changes: 8 additions & 1 deletion test/unit/object/test_retention_policy.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,23 +25,30 @@ def test_get(test_retention_policy, mock_box_session):

def test_update(test_retention_policy, mock_box_session):
new_policy_name = 'New Name'
new_retention_type = 'modifiable'
new_retention_length = 60
expected_url = f'{API.BASE_API_URL}/retention_policies/{test_retention_policy.object_id}'
mock_box_session.put.return_value.json.return_value = {
'type': test_retention_policy.object_type,
'id': test_retention_policy.object_id,
'policy_name': new_policy_name,
'policy_type': 'finite',
'retention_length': '10',
'retention_length': new_retention_length,
'retention_type': new_retention_type,
}
data = {
'policy_name': new_policy_name,
'retention_type': new_retention_type,
'retention_length': new_retention_length
}
retention_policy = test_retention_policy.update_info(data=data)
mock_box_session.put.assert_called_once_with(expected_url, data=json.dumps(data), headers=None, params=None)
assert isinstance(retention_policy, RetentionPolicy)
assert retention_policy['type'] == test_retention_policy.object_type
assert retention_policy['id'] == test_retention_policy.object_id
assert retention_policy['policy_name'] == new_policy_name
assert retention_policy['retention_type'] == new_retention_type
assert retention_policy['retention_length'] == new_retention_length


def test_assign(test_retention_policy, test_folder, mock_box_session):
Expand Down
10 changes: 10 additions & 0 deletions test/unit/object/test_retention_policy_assignment.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,3 +73,13 @@ def test_get_file_versions_under_retention(test_retention_policy_assignment, tes
mock_box_session.get.assert_called_once_with(target_url, params=params)
assert isinstance(file_version_under_retention, FileVersion)
assert file_version_under_retention.object_id == test_file_version.object_id


def test_delete_assignment(test_retention_policy_assignment, mock_box_session):
expected_url = f'{API.BASE_API_URL}/retention_policy_assignments/{test_retention_policy_assignment.object_id}'
mock_box_session.delete.return_value.ok = True

is_assignment_deleted = test_retention_policy_assignment.delete()
mock_box_session.delete.assert_called_once_with(expected_url, expect_json_response=False, params={}, headers=None)

assert is_assignment_deleted

0 comments on commit d531b47

Please sign in to comment.