Skip to content

Commit 30e2fcb

Browse files
authored
feat: Add support for modifiable retention policies & enable deleting retention policy assignment (#1093)
Closes: SDK-2025
1 parent 001c2d4 commit 30e2fcb

11 files changed

Lines changed: 234 additions & 45 deletions

src/intTest/java/com/box/sdk/BoxRetentionPolicyAssignmentIT.java

Lines changed: 37 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
import static com.box.sdk.UniqueTestFolder.uploadTwoFileVersionsToSpecifiedFolder;
1212
import static org.hamcrest.MatcherAssert.assertThat;
1313
import static org.hamcrest.Matchers.hasSize;
14+
import static org.junit.Assert.assertFalse;
1415
import static org.junit.Assert.assertTrue;
1516
import static org.mockito.Mockito.mock;
1617

@@ -41,37 +42,52 @@ public static void tearDown() {
4142
}
4243

4344
@Test
44-
public void attachPolicyToFileAndGetFilesUnderRetention() {
45+
public void attachPolicyToFileAndGetFilesUnderRetentionAndDeleteAttachment() {
4546
//given
4647
BoxAPIConnection api = jwtApiForServiceAccount();
4748
BoxFolder.Info folder = getUniqueFolder(api)
4849
.createFolder(randomizeName("attachPolicyToFileAndGetFilesUnderRetention"));
49-
BoxRetentionPolicyAssignment.Info assignment = createAssignmentToFolder(api, policy.getID(), folder.getID());
50+
BoxRetentionPolicyAssignment.Info assignmentInfo = createAssignmentToFolder(
51+
api, policy.getID(), folder.getID()
52+
);
5053
BoxFile boxFile = uploadFileWithSomeContent("file_with_retention.txt", folder.getResource());
5154

5255
//when
56+
BoxRetentionPolicyAssignment assignment = new BoxRetentionPolicyAssignment(api, assignmentInfo.getID());
5357
Iterable<BoxFile.Info> filesUnderRetention =
54-
new BoxRetentionPolicyAssignment(api, assignment.getID()).getFilesUnderRetention(5);
58+
new BoxRetentionPolicyAssignment(api, assignmentInfo.getID()).getFilesUnderRetention(5);
5559

5660
//then
57-
Optional<BoxFile.Info> matchingFileWithRetention =
61+
Optional<BoxFile.Info> matchingFileWithRetention1 =
5862
StreamSupport.stream(filesUnderRetention.spliterator(), false)
5963
.filter(f -> f.getID().equals(boxFile.getID()))
6064
.findFirst();
61-
assertTrue(matchingFileWithRetention.isPresent());
65+
assertTrue(matchingFileWithRetention1.isPresent());
66+
67+
//when
68+
assignment.delete();
69+
70+
//then
71+
Optional<BoxFile.Info> matchingFileWithRetention2 =
72+
StreamSupport.stream(filesUnderRetention.spliterator(), false)
73+
.filter(f -> f.getID().equals(boxFile.getID()))
74+
.findFirst();
75+
assertFalse(matchingFileWithRetention2.isPresent());
6276

6377
//cleanup
6478
deleteFolder(folder.getResource());
6579
}
6680

6781
@Test
68-
public void attachPolicyToFileAndGetFileVersionsUnderRetention() {
82+
public void attachPolicyToFileAndGetFileVersionsUnderRetentionAndDeleteAttachment() {
6983
//given
7084
BoxAPIConnection api = jwtApiForServiceAccount();
7185
BoxFolder folder = getUniqueFolder(api)
7286
.createFolder(randomizeName("attachPolicyToFileAndGetFileVersionsUnderRetention"))
7387
.getResource();
74-
BoxRetentionPolicyAssignment.Info assignment = createAssignmentToFolder(api, policy.getID(), folder.getID());
88+
BoxRetentionPolicyAssignment.Info assignmentInfo = createAssignmentToFolder(
89+
api, policy.getID(), folder.getID()
90+
);
7591
BoxFile boxFile = uploadTwoFileVersionsToSpecifiedFolder(
7692
"file_with_retention.txt",
7793
"v1",
@@ -81,15 +97,25 @@ public void attachPolicyToFileAndGetFileVersionsUnderRetention() {
8197
);
8298

8399
//when
84-
Iterable<BoxFile.Info> filesVersionsUnderRetention =
85-
new BoxRetentionPolicyAssignment(api, assignment.getID()).getFileVersionsUnderRetention(5);
100+
BoxRetentionPolicyAssignment assignment = new BoxRetentionPolicyAssignment(api, assignmentInfo.getID());
101+
Iterable<BoxFile.Info> filesVersionsUnderRetention = assignment.getFileVersionsUnderRetention(5);
86102

87103
//then
88-
List<BoxFile.Info> matchingFileWithRetention =
104+
List<BoxFile.Info> matchingFileWithRetention1 =
89105
StreamSupport.stream(filesVersionsUnderRetention.spliterator(), false)
90106
.filter(f -> f.getID().equals(boxFile.getID()))
91107
.collect(Collectors.toList());
92-
assertThat(matchingFileWithRetention, hasSize(1));
108+
assertThat(matchingFileWithRetention1, hasSize(1));
109+
110+
//when
111+
assignment.delete();
112+
113+
//then
114+
List<BoxFile.Info> matchingFileWithRetention2 =
115+
StreamSupport.stream(filesVersionsUnderRetention.spliterator(), false)
116+
.filter(f -> f.getID().equals(boxFile.getID()))
117+
.collect(Collectors.toList());
118+
assertTrue(matchingFileWithRetention2.isEmpty());
93119

94120
//cleanup
95121
deleteFolder(folder);

src/intTest/java/com/box/sdk/RetentionPolicyUtils.java

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,16 @@ static BoxRetentionPolicy findOrCreate(
2626
static BoxRetentionPolicy getOneDayRetentionPolicy(BoxAPIConnection api) {
2727
return findOrCreate(
2828
api,
29-
"One day",
30-
() -> BoxRetentionPolicy.createFinitePolicy(api, randomizeName("One day"), 1, PermanentlyDelete)
29+
"One day modifiable",
30+
() -> createModifiableFinitePolicy(api)
31+
);
32+
}
33+
34+
static BoxRetentionPolicy.Info createModifiableFinitePolicy(BoxAPIConnection api) {
35+
RetentionPolicyParams optionalParams = new RetentionPolicyParams();
36+
optionalParams.setRetentionType(RetentionPolicyParams.RetentionType.MODIFIABLE);
37+
return BoxRetentionPolicy.createFinitePolicy(
38+
api, randomizeName("One day modifiable"), 1, PermanentlyDelete, optionalParams
3139
);
3240
}
3341
}

src/main/java/com/box/sdk/BoxRetentionPolicy.java

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -231,6 +231,7 @@ private static BoxRetentionPolicy.Info createRetentionPolicy(
231231
requestJSON.add("can_owner_extend_retention", optionalParams.getCanOwnerExtendRetention());
232232
requestJSON.add("are_owners_notified", optionalParams.getAreOwnersNotified());
233233
requestJSON.add("description", optionalParams.getDescription());
234+
requestJSON.add("retention_type", optionalParams.getRetentionType().toJSONString());
234235

235236
List<BoxUser.Info> customNotificationRecipients = optionalParams.getCustomNotificationRecipients();
236237
if (customNotificationRecipients.size() > 0) {
@@ -531,6 +532,11 @@ public class Info extends BoxResource.Info {
531532
*/
532533
private String description;
533534

535+
/**
536+
* @see #getRetentionType()
537+
*/
538+
private RetentionPolicyParams.RetentionType retentionType;
539+
534540
private List<BoxUser.Info> customNotificationRecipients;
535541

536542
/**
@@ -607,6 +613,15 @@ public int getRetentionLength() {
607613
return this.retentionLength;
608614
}
609615

616+
/**
617+
*
618+
* @param retentionLength The length of the retention policy.
619+
*/
620+
public void setRetentionLength(int retentionLength) {
621+
this.retentionLength = retentionLength;
622+
this.addPendingChange("retention_length", retentionLength);
623+
}
624+
610625
/**
611626
* Gets the disposition action of the retention policy.
612627
* This action can be "permanently_delete", or "remove_retention".
@@ -711,6 +726,30 @@ public void setDescription(String description) {
711726
this.addPendingChange("description", description);
712727
}
713728

729+
/**
730+
*
731+
* @return retention type. It can be one of values: `modifiable` or `non-modifiable`.
732+
*
733+
* `modifiable` means that you can modify the retention policy. For example, you can add or remove folders,
734+
* shorten or lengthen the policy duration, or delete the assignment.
735+
*
736+
* `non-modifiable` means that can modify the retention policy only in a limited way: add a folder,
737+
* lengthen the duration, retire the policy, change the disposition action or notification settings.
738+
* You cannot perform other actions, such as deleting the assignment or shortening the policy duration.
739+
*/
740+
public RetentionPolicyParams.RetentionType getRetentionType() {
741+
return retentionType;
742+
}
743+
744+
/**
745+
*
746+
* It is not possible to set retention type to `modifiable` once it was set to `non-modifiable`.
747+
*/
748+
public void setRetentionTypeToNonModifiable() {
749+
this.retentionType = RetentionPolicyParams.RetentionType.NON_MODIFIABLE;
750+
this.addPendingChange("retention_type", retentionType.toJSONString());
751+
}
752+
714753
/**
715754
* Gets the list of users to be notified of a retained file when near expiration.
716755
*
@@ -765,6 +804,8 @@ void parseJSONMember(JsonObject.Member member) {
765804
this.areOwnersNotified = value.asBoolean();
766805
} else if (memberName.equals("description")) {
767806
this.description = value.asString();
807+
} else if (memberName.equals("retention_type")) {
808+
this.retentionType = RetentionPolicyParams.RetentionType.fromJSONString(value.asString());
768809
} else if (memberName.equals("custom_notification_recipients")) {
769810
List<BoxUser.Info> recipients = new ArrayList<BoxUser.Info>();
770811
for (JsonValue userJSON : value.asArray()) {

src/main/java/com/box/sdk/BoxRetentionPolicyAssignment.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -256,6 +256,15 @@ protected BoxFile.Info factory(JsonObject jsonObject) {
256256
};
257257
}
258258

259+
/**
260+
* Deletes retention policy assignment.
261+
*/
262+
public void delete() {
263+
URL url = RETENTION_POLICY_ASSIGNMENT_URL_TEMPLATE.build(this.getAPI().getBaseURL(), this.getID());
264+
BoxAPIRequest request = new BoxAPIRequest(this.getAPI(), url, "DELETE");
265+
request.send();
266+
}
267+
259268
/**
260269
* Contains information about the retention policy.
261270
*/

src/main/java/com/box/sdk/RetentionPolicyParams.java

Lines changed: 63 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,11 @@ public class RetentionPolicyParams {
3030
*/
3131
private List<BoxUser.Info> customNotificationRecipients;
3232

33+
/**
34+
* @see #getCustomNotificationRecipients()
35+
*/
36+
private RetentionType retentionType;
37+
3338
/**
3439
* Creates optional retention policy params with default values.
3540
*/
@@ -38,6 +43,7 @@ public RetentionPolicyParams() {
3843
this.areOwnersNotified = false;
3944
this.customNotificationRecipients = new ArrayList<>();
4045
this.description = "";
46+
this.retentionType = RetentionType.MODIFIABLE;
4147
}
4248

4349
/**
@@ -79,6 +85,29 @@ public String getDescription() {
7985
return this.description;
8086
}
8187

88+
/**
89+
*
90+
* @return retention type. It can be one of values: `modifiable` or `non-modifiable`.
91+
*
92+
* `modifiable` means that you can modify the retention policy. For example, you can add or remove folders,
93+
* shorten or lengthen the policy duration, or delete the assignment.
94+
*
95+
* `non-modifiable` means that can modify the retention policy only in a limited way: add a folder,
96+
* lengthen the duration, retire the policy, change the disposition action or notification settings.
97+
* You cannot perform other actions, such as deleting the assignment or shortening the policy duration.
98+
*/
99+
public RetentionType getRetentionType() {
100+
return retentionType;
101+
}
102+
103+
/**
104+
*
105+
* @param retentionType The retention type: `modifiable` or `non-modifiable`.
106+
*/
107+
public void setRetentionType(RetentionType retentionType) {
108+
this.retentionType = retentionType;
109+
}
110+
82111
/**
83112
* Set additional text description of the retention policy.
84113
*
@@ -123,5 +152,38 @@ public void addCustomNotificationRecipient(String userID) {
123152
public void addCustomNotificationRecipient(BoxUser user) {
124153
this.customNotificationRecipients.add(user.new Info());
125154
}
126-
}
127155

156+
/**
157+
* The type of retention.
158+
*/
159+
public enum RetentionType {
160+
/**
161+
* You can modify the retention policy. For example, you can add or remove folders,
162+
* shorten or lengthen the policy duration, or delete the assignment.
163+
* Use this type if your retention policy is not related to any regulatory purposes.
164+
*/
165+
MODIFIABLE("modifiable"),
166+
167+
/**
168+
* You can modify the retention policy only in a limited way: add a folder, lengthen the duration,
169+
* retire the policy, change the disposition action or notification settings.
170+
* You cannot perform other actions, such as deleting the assignment or shortening the policy duration.
171+
* Use this type to ensure compliance with regulatory retention policies.
172+
*/
173+
NON_MODIFIABLE("non_modifiable");
174+
175+
private final String jsonValue;
176+
177+
RetentionType(String jsonValue) {
178+
this.jsonValue = jsonValue;
179+
}
180+
181+
static RetentionType fromJSONString(String jsonValue) {
182+
return RetentionType.valueOf(jsonValue.toUpperCase());
183+
}
184+
185+
String toJSONString() {
186+
return this.jsonValue;
187+
}
188+
}
189+
}

src/test/Fixtures/BoxRetentionPolicy/CreateRetentionPolicy201.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,5 +22,6 @@
2222
},
2323
"created_at": "2018-04-23T10:17:14-07:00",
2424
"modified_at": "2018-04-23T10:17:14-07:00",
25-
"description": "description"
25+
"description": "description",
26+
"retention_type": "modifiable"
2627
}

src/test/Fixtures/BoxRetentionPolicy/GetAllRetentionPolicies200.json

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,17 @@
22
"entries": [
33
{
44
"type": "retention_policy",
5+
"disposition_action": "remove_retention",
56
"id": "12345",
6-
"policy_name": "A Retention Policy"
7+
"policy_name": "A Retention Policy",
8+
"retention_length": "30"
79
},
810
{
911
"type": "retention_policy",
12+
"disposition_action": "permanently_delete",
1013
"id": "32421",
11-
"policy_name": "A Retention Policy 2"
14+
"policy_name": "A Retention Policy 2",
15+
"retention_length": "1"
1216
}
1317
],
1418
"limit": 1000

src/test/Fixtures/BoxRetentionPolicy/GetRetentionPolicyInfo200.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,5 +22,6 @@
2222
},
2323
"created_at": "2018-04-09T15:16:39-07:00",
2424
"modified_at": "2018-04-09T15:16:39-07:00",
25-
"description": "description"
25+
"description": "description",
26+
"retention_type": "non_modifiable"
2627
}

src/test/Fixtures/BoxRetentionPolicy/UpdateRetentionPolicyInfo200.json

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@
22
"type": "retention_policy",
33
"id": "12345",
44
"policy_name": "New Policy Name",
5-
"policy_type": "indefinite",
6-
"retention_length": "indefinite",
5+
"policy_type": "finite",
6+
"retention_length": "44",
77
"disposition_action": "remove_retention",
88
"can_owner_extend_retention": false,
99
"status": "retired",
@@ -22,5 +22,6 @@
2222
},
2323
"created_at": "2018-04-23T10:17:14-07:00",
2424
"modified_at": "2018-04-23T11:07:29-07:00",
25-
"description": "updated description"
25+
"description": "updated description",
26+
"retention_type": "non_modifiable"
2627
}

0 commit comments

Comments
 (0)