Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Add support for modifiable retention policies & enable deleting retention policy assignment #856

Merged
merged 14 commits into from
Sep 13, 2022
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
using System;
using System.Threading.Tasks;
using Box.V2.Exceptions;
using Box.V2.Models;
using Box.V2.Models.Request;
using Box.V2.Test.Integration.Configuration;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace Box.V2.Test.Integration
{
[TestClass]
public class BoxRetentionPolicyManagerIntegrationTest : TestInFolder
{
[TestMethod]
public async Task CreateRetentionPolicyAssignmentAsync_ForRetentionPolicyAssignmentRequest_ShouldSuccess()
{
var adminFolder = await CreateFolderAsAdmin("0");
var retentionPolicy = await CreateRetentionPolicy();
var policyAssignmentReq = new BoxRetentionPolicyAssignmentRequest()
{
PolicyId = retentionPolicy.Id,
AssignTo = new BoxRequestEntity()
{
Id = adminFolder.Id,
Type = BoxType.folder
}
};
var policyAssignment = await AdminClient.RetentionPoliciesManager.CreateRetentionPolicyAssignmentAsync(policyAssignmentReq);
Assert.AreEqual(retentionPolicy.Id, policyAssignment.RetentionPolicy.Id);
Assert.AreEqual(adminFolder.Id, policyAssignment.AssignedTo.Id);

var result = await AdminClient.RetentionPoliciesManager.DeleteRetentionPolicyAssignmentAsync(policyAssignment.Id);
Assert.IsTrue(result);
}
}
}
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using System;
using System.Threading.Tasks;
using Box.V2.Models;
using Box.V2.Models.Request;
Expand Down Expand Up @@ -26,23 +27,49 @@ public async Task<string> Execute(IBoxClient client)
PolicyType = "finite",
RetentionLength = 1,
DispositionAction = DispositionAction.permanently_delete.ToString(),
RetentionType = BoxRetentionType.modifiable
};
try
{
var response = await client.RetentionPoliciesManager.CreateRetentionPolicyAsync(retentionPolicyRequest);
Policy = response;
}
catch (Exception ex)
{
// TODO: 12-09-2022, @mcong
// There is an error on backend side, which will return 409 status code "conflict"
// but retention policy still created.
// Delete this try-catch after the issue is fixed.
var policies = await client.RetentionPoliciesManager.GetRetentionPoliciesAsync(_policyName);
if (policies.Entries.Count == 1)
mwwoda marked this conversation as resolved.
Show resolved Hide resolved
{
// Retention policy already created.
var policy = policies.Entries[0];
var response = await client.RetentionPoliciesManager.GetRetentionPolicyAsync(policy.Id);
Policy = response;
}
else
{
throw ex;
}

var response = await client.RetentionPoliciesManager.CreateRetentionPolicyAsync(retentionPolicyRequest);
Policy = response;
}
PolicyId = Policy.Id;

var assignmentRequest = new BoxRetentionPolicyAssignmentRequest()
if (_folderId != null)
{
PolicyId = PolicyId,
AssignTo = new BoxRequestEntity()
var assignmentRequest = new BoxRetentionPolicyAssignmentRequest()
{
Type = BoxType.folder,
Id = _folderId
}
};
PolicyId = PolicyId,
AssignTo = new BoxRequestEntity()
{
Type = BoxType.folder,
Id = _folderId
}
};

await client.RetentionPoliciesManager.CreateRetentionPolicyAssignmentAsync(assignmentRequest);
await client.RetentionPoliciesManager.CreateRetentionPolicyAssignmentAsync(assignmentRequest);
}

return PolicyId;
}
Expand All @@ -53,8 +80,17 @@ public async Task Dispose(IBoxClient client)
{
Status = "retired"
};

await client.RetentionPoliciesManager.UpdateRetentionPolicyAsync(PolicyId, retentionPolicyRequest);
try
{
await client.RetentionPoliciesManager.UpdateRetentionPolicyAsync(PolicyId, retentionPolicyRequest);
}
catch
{
// TODO: 12-09-2022, @mcong
// There is an error on backend side, which will return 500 status code "Internal Server Error"
// but retention policy still updated.
// Delete this try-catch after the issue is fixed.
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -263,7 +263,7 @@ public static MemoryStream CreateBigFileInMemoryStream()
return CreateFileInMemoryStream(50000000);
}

public static async Task<BoxRetentionPolicy> CreateRetentionPolicy(string folderId = "0", CommandScope commandScope = CommandScope.Test)
public static async Task<BoxRetentionPolicy> CreateRetentionPolicy(string folderId = null, CommandScope commandScope = CommandScope.Test)
{
var createRetentionPolicyCommand = new CreateRetentionPolicyCommand(folderId, GetUniqueName("policy"), commandScope);
await ExecuteCommand(createRetentionPolicyCommand);
Expand Down
25 changes: 23 additions & 2 deletions Box.V2.Test/BoxRetentionPoliciesManagerTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ public async Task CreateRetentionPolicy_OptionalParams_Success()
var policyType = "finite";
var policyAction = "permanently_delete";
var notifiedUserID = "12345";
var retentionType = BoxRetentionType.non_modifiable;
var responseString = "{"
+ "\"type\": \"retention_policy\","
+ "\"id\": \"123456789\","
Expand All @@ -51,7 +52,8 @@ public async Task CreateRetentionPolicy_OptionalParams_Success()
+ " \"type\": \"user\","
+ " \"id\": \"" + notifiedUserID + "\""
+ " }"
+ "]"
+ "],"
+ "\"retention_type\": \"non-modifiable\""
+ "}";
Handler.Setup(h => h.ExecuteAsync<BoxRetentionPolicy>(It.IsAny<IBoxRequest>()))
.Returns(Task.FromResult<IBoxResponse<BoxRetentionPolicy>>(new BoxResponse<BoxRetentionPolicy>()
Expand All @@ -64,7 +66,7 @@ public async Task CreateRetentionPolicy_OptionalParams_Success()
var requestParams = new BoxRetentionPolicyRequest
{
AreOwnersNotified = true,
CanOwnerExtendRetention = true
CanOwnerExtendRetention = true,
};
var notifiedUser = new BoxRequestEntity
{
Expand All @@ -76,13 +78,15 @@ public async Task CreateRetentionPolicy_OptionalParams_Success()
requestParams.PolicyType = policyType;
requestParams.RetentionLength = retentionLength;
requestParams.DispositionAction = policyAction;
requestParams.RetentionType = retentionType;
BoxRetentionPolicy results = await _retentionPoliciesManager.CreateRetentionPolicyAsync(requestParams);

/*** Assert ***/
Assert.AreEqual(policyAction, results.DispositionAction);
Assert.AreEqual(policyName, results.PolicyName);
Assert.AreEqual(policyType, results.PolicyType);
Assert.AreEqual(retentionLength.ToString(), results.RetentionLength);
Assert.AreEqual(retentionType, results.RetentionType);
Assert.AreEqual(true, results.CanOwnerExtendRetention);
Assert.AreEqual(true, results.AreOwnersNotified);
Assert.IsNotNull(results.CustomNotificationRecipients);
Expand Down Expand Up @@ -165,6 +169,23 @@ public async Task AssignPolicyToMetadataTemplate_OptionalParams_Success()
Assert.AreEqual(42.ToString(), result.FilterFields[1].Value);
}

[TestMethod]
public async Task DeleteRetentionPolicyAssignment_ValidRequest_Success()
{
/*** Arrange ***/
var responseString = "";
Handler.Setup(h => h.ExecuteAsync<BoxRetentionPolicyAssignment>(It.IsAny<IBoxRequest>()))
.Returns(Task.FromResult<IBoxResponse<BoxRetentionPolicyAssignment>>(new BoxResponse<BoxRetentionPolicyAssignment>()
{
Status = ResponseStatus.Success,
ContentString = responseString
}));
bool result = await _retentionPoliciesManager.DeleteRetentionPolicyAssignmentAsync("12345");

/*** Assert ***/
Assert.IsTrue(result);
}

[TestMethod]
public async Task GetFileVersionRetentions_OptionalParams_Success()
{
Expand Down
15 changes: 15 additions & 0 deletions Box.V2/Managers/BoxRetentionPoliciesManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,21 @@ public async Task<BoxRetentionPolicyAssignment> GetRetentionPolicyAssignmentAsyn
return response.ResponseObject;
}

/// <summary>
/// Used to delete a retention policy assignment.
/// </summary>
/// <param name="retentionPolicyAssignmentId">ID of the retention policy assignment.</param>
/// <returns>True if the retention policy assignment was successfully deleted.</returns>
public async Task<bool> DeleteRetentionPolicyAssignmentAsync(string retentionPolicyAssignmentId)
{
BoxRequest request = new BoxRequest(_config.RetentionPolicyAssignmentsUri, retentionPolicyAssignmentId)
.Method(RequestMethod.Delete);

IBoxResponse<BoxRetentionPolicyAssignment> response = await ToResponseAsync<BoxRetentionPolicyAssignment>(request).ConfigureAwait(false);

return response.Status == ResponseStatus.Success;
}

/// <summary>
/// Retrieves all file version retentions for the given enterprise.
/// </summary>
Expand Down
7 changes: 7 additions & 0 deletions Box.V2/Managers/IBoxRetentionPoliciesManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,13 @@ public interface IBoxRetentionPoliciesManager
/// <returns>The specified retention policy assignment will be returned upon success.</returns>
Task<BoxRetentionPolicyAssignment> GetRetentionPolicyAssignmentAsync(string retentionPolicyAssignmentId, IEnumerable<string> fields = null);

/// <summary>
/// Used to delete a retention policy assignment.
/// </summary>
/// <param name="retentionPolicyAssignmentId">ID of the retention policy assignment.</param>
/// <returns>True if the retention policy assignment was successfully deleted.</returns>
Task<bool> DeleteRetentionPolicyAssignmentAsync(string retentionPolicyAssignmentId);

/// <summary>
/// Retrieves all file version retentions for the given enterprise.
/// </summary>
Expand Down
17 changes: 17 additions & 0 deletions Box.V2/Models/BoxRetentionPolicy.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
using System;
using System.Collections.Generic;
using System.Runtime.Serialization;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;

namespace Box.V2.Models
{
Expand All @@ -20,6 +22,7 @@ public class BoxRetentionPolicy : BoxEntity
public const string FieldCanOwnerExtendRetention = "can_owner_extend_retention";
public const string FieldAreOwnersNotified = "are_owners_notified";
public const string FieldCustomNotificationRecipients = "custom_notification_recipients";
public const string FieldRetentionType = "retention_type";

/// <summary>
/// The name given to the retention policy
Expand Down Expand Up @@ -87,5 +90,19 @@ public class BoxRetentionPolicy : BoxEntity
/// </summary>
[JsonProperty(PropertyName = FieldCustomNotificationRecipients)]
public virtual List<BoxUser> CustomNotificationRecipients { get; set; }

/// <summary>
/// The type of retention policy. Value is one of modifiable or non-modifiable.
/// </summary>
[JsonProperty(PropertyName = FieldRetentionType)]
[JsonConverter(typeof(StringEnumConverter))]
public virtual BoxRetentionType RetentionType { get; set; }
}

public enum BoxRetentionType
{
modifiable,
[EnumMember(Value = "non-modifiable")]
non_modifiable
}
}
9 changes: 9 additions & 0 deletions Box.V2/Models/Request/BoxRetentionPolicyRequest.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System.Collections.Generic;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;

namespace Box.V2.Models.Request
{
Expand Down Expand Up @@ -55,5 +56,13 @@ public class BoxRetentionPolicyRequest
/// </summary>
[JsonProperty(PropertyName = "custom_notification_recipients")]
public List<BoxRequestEntity> CustomNotificationRecipients { get; set; }

/// <summary>
/// Used to determine the type of retention policy, value can be modifiable or non-modifiable
/// When updating a retention policy, you can use non-modifiable type only. You can convert a modifiable policy to non-modifiable, but not the other way around.
/// </summary>
[JsonProperty(PropertyName = "retention_type")]
[JsonConverter(typeof(StringEnumConverter))]
public BoxRetentionType RetentionType { get; set; }
}
}