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

Add folder lock functionality #725

Merged
merged 9 commits into from
Mar 15, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
99 changes: 99 additions & 0 deletions Box.V2.Test/BoxFoldersManagerTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.Linq;
Expand Down Expand Up @@ -963,5 +964,103 @@ public async Task RemoveWatermarkFromFolder_ValidResponse_RemovedWatermark()
Assert.AreEqual(true, result);

}

[TestMethod]
[TestCategory("CI-UNIT-TEST")]
public async Task GetFolderLocks_ValidResponse()
{
/*** Arrange ***/
string responseString = "{\"entries\":[{\"folder\":{\"id\":\"12345\",\"etag\":\"1\",\"type\":\"folder\",\"sequence_id\":\"3\",\"name\":\"Contracts\"},\"id\":\"12345678\",\"type\":\"folder_lock\",\"created_by\":{\"id\":\"11446498\",\"type\":\"user\"},\"created_at\":\"2020-09-14T23:12:53Z\",\"locked_operations\":{\"move\":true,\"delete\":true},\"lock_type\":\"freeze\"}],\"limit\":1000,\"next_marker\":null}";
IBoxRequest boxRequest = null;
Handler.Setup(h => h.ExecuteAsync<BoxCollection<BoxFolderLock>>(It.IsAny<IBoxRequest>()))
.Returns(Task.FromResult<IBoxResponse<BoxCollection<BoxFolderLock>>>(new BoxResponse<BoxCollection<BoxFolderLock>>()
{
Status = ResponseStatus.Success,
ContentString = responseString
}))
.Callback<IBoxRequest>(r => boxRequest = r);

/*** Act ***/
string id = "5010739069";
BoxCollection<BoxFolderLock> result = await _foldersManager.GetLocksAsync(id);

/*** Assert ***/
//Request check
Assert.IsNotNull(boxRequest);
Assert.AreEqual(RequestMethod.Get, boxRequest.Method);
Assert.AreEqual(Constants.FolderLocksEndpointString + "?folder_id=" + id, boxRequest.AbsoluteUri.AbsoluteUri);

//Response check
Assert.AreEqual("12345678", result.Entries[0].Id);
Assert.AreEqual("freeze", result.Entries[0].LockType);
Assert.AreEqual(true, result.Entries[0].LockedOperations.Delete);

}

[TestMethod]
[TestCategory("CI-UNIT-TEST")]
public async Task CreateFolderLock_ValidResponse()
{
/*** Arrange ***/
string responseString = "{\"id\":12345678,\"type\":\"folder_lock\",\"created_at\":\"2020-09-14T23:12:53Z\",\"created_by\":{\"id\":11446498,\"type\":\"user\"},\"folder\":{\"id\":12345,\"type\":\"folder\",\"etag\":1,\"name\":\"Contracts\",\"sequence_id\":3},\"lock_type\":\"freeze\",\"locked_operations\":{\"delete\":true,\"move\":true}}";
IBoxRequest boxRequest = null;
Handler.Setup(h => h.ExecuteAsync<BoxFolderLock>(It.IsAny<IBoxRequest>()))
.Returns(Task.FromResult<IBoxResponse<BoxFolderLock>>(new BoxResponse<BoxFolderLock>()
{
Status = ResponseStatus.Success,
ContentString = responseString
}))
.Callback<IBoxRequest>(r => boxRequest = r);

/*** Act ***/
string id = "5010739069";
BoxFolderLock result = await _foldersManager.CreateLockAsync(id);

/*** Assert ***/
//Request check
Assert.IsNotNull(boxRequest);
Assert.AreEqual(RequestMethod.Post, boxRequest.Method);
Assert.AreEqual(Constants.FolderLocksEndpointString, boxRequest.AbsoluteUri.AbsoluteUri);
JObject payload = JObject.Parse(boxRequest.Payload);
Assert.AreEqual("folder", payload["folder"]["type"]);
Assert.AreEqual(id, payload["folder"]["id"]);
Assert.AreEqual(true, payload["locked_operations"]["move"]);
Assert.AreEqual(true, payload["locked_operations"]["delete"]);

//Response check
Assert.AreEqual("12345678", result.Id);
Assert.AreEqual("freeze", result.LockType);
Assert.AreEqual(true, result.LockedOperations.Delete);

}

[TestMethod]
[TestCategory("CI-UNIT-TEST")]
public async Task DeleteFolderLock_ValidResponse()
{
/*** Arrange ***/
string responseString = "";
IBoxRequest boxRequest = null;
Handler.Setup(h => h.ExecuteAsync<BoxFolderLock>(It.IsAny<IBoxRequest>()))
.Returns(Task.FromResult<IBoxResponse<BoxFolderLock>>(new BoxResponse<BoxFolderLock>()
{
Status = ResponseStatus.Success,
ContentString = responseString
}))
.Callback<IBoxRequest>(r => boxRequest = r);

/*** Act ***/
string id = "5010739069";
bool result = await _foldersManager.DeleteLockAsync(id);

/*** Assert ***/
//Request check
Assert.IsNotNull(boxRequest);
Assert.AreEqual(RequestMethod.Delete, boxRequest.Method);
Assert.AreEqual(Constants.FolderLocksEndpointString + id, boxRequest.AbsoluteUri.AbsoluteUri);

//Response check
Assert.AreEqual(true, result);
}
}
}
2 changes: 2 additions & 0 deletions Box.V2.Test/BoxResourceManagerTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ public abstract class BoxResourceManagerTest
protected Uri MetadataQueryUri = new Uri(Constants.MetadataQueryEndpointString);
protected Uri UserUri = new Uri(Constants.UserEndpointString);
protected Uri InviteUri = new Uri(Constants.BoxApiUriString + Constants.InviteString);
protected Uri FolderLocksUri = new Uri(Constants.FolderLocksEndpointString);

protected BoxResourceManagerTest()
{
Expand All @@ -41,6 +42,7 @@ protected BoxResourceManagerTest()
Config.SetupGet(x => x.MetadataQueryUri).Returns(MetadataQueryUri);
Config.SetupGet(x => x.UserEndpointUri).Returns(UserUri);
Config.SetupGet(x => x.InviteEndpointUri).Returns(InviteUri);
Config.SetupGet(x => x.FolderLocksEndpointUri).Returns(FolderLocksUri);

AuthRepository = new AuthRepository(Config.Object, Service, Converter, new OAuthSession("fakeAccessToken", "fakeRefreshToken", 3600, "bearer"));
}
Expand Down
2 changes: 2 additions & 0 deletions Box.V2/Box.V2.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,8 @@
<Compile Include="Models\BoxEnterprise.cs" />
<Compile Include="Models\BoxEnterpriseEvent.cs" />
<Compile Include="Models\BoxFolderEventSource.cs" />
<Compile Include="Models\BoxFolderLock.cs" />
<Compile Include="Models\BoxFolderLockOperations.cs" />
<Compile Include="Models\BoxGroupEventSource.cs" />
<Compile Include="Models\BoxMetadataCascadePolicy.cs" />
<Compile Include="Models\BoxGroupFileCollaborationEventSource.cs" />
Expand Down
4 changes: 4 additions & 0 deletions Box.V2/Config/BoxConfig.cs
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,10 @@ public static IBoxConfig CreateFromJsonString(string jsonString)
/// </summary>
public virtual Uri ZipDownloadsEndpointUri { get { return new Uri(BoxApiUri, Constants.ZipDownloadsString); } }
/// <summary>
/// Gets the folder locks endpoint URI.
/// </summary>
public virtual Uri FolderLocksEndpointUri { get { return new Uri(BoxApiUri, Constants.FolderLocksString); } }
/// <summary>
/// The web proxy for HttpRequestHandler
/// </summary>
public IWebProxy WebProxy { get; set; }
Expand Down
4 changes: 4 additions & 0 deletions Box.V2/Config/Constants.cs
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,8 @@ public static class Constants
public const string StoragePolicyAssignmentsString = @"storage_policy_assignments/";
public const string StoragePolicyAssignmentsForTargetString = @"storage_policy_assignments";
public const string ZipDownloadsString = @"zip_downloads";
public const string FolderLocksString = @"folder_locks/";


/// <summary>
/// The shared items constant
Expand Down Expand Up @@ -109,6 +111,7 @@ public static class Constants
public const string StoragePoliciesEndpointString = BoxApiUriString + StoragePoliciesString;
public const string StoragePolicyAssignmentsEndpointString = BoxApiUriString + StoragePolicyAssignmentsString;
public const string StoragePolicyAssignmentsForTargetEndpointString = BoxApiUriString + StoragePolicyAssignmentsForTargetString;
public const string FolderLocksEndpointString = BoxApiUriString + FolderLocksString;

/*** Endpoint Paths ***/
public const string ItemsPathString = @"{0}/items";
Expand Down Expand Up @@ -184,6 +187,7 @@ public static class Constants
public const string TypeStoragePolicy = "storage_policy";
public const string TypeStoragePolicyAssignment = "storage_policy_assignment";
public const string TypeApplication = "application";
public const string TypeFolderLock = "folder_lock";

/*** File Preview ***/
public const int DefaultRetryDelay = 1000; // milliseconds
Expand Down
5 changes: 4 additions & 1 deletion Box.V2/Config/IBoxConfig.cs
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,10 @@ public interface IBoxConfig
/// Gets the zip downloads endpoint URI.
/// </summary>
Uri ZipDownloadsEndpointUri { get; }

/// <summary>
/// Gets the folder locks endpoint URI.
/// </summary>
Uri FolderLocksEndpointUri { get; }
/// <summary>
/// The web proxy for HttpRequestHandler
/// </summary>
Expand Down
2 changes: 2 additions & 0 deletions Box.V2/Converter/BoxItemConverter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,8 @@ protected override BoxEntity Create(Type objectType, JObject jObject)
return new BoxStoragePolicyAssignment();
case Constants.TypeApplication:
return new BoxApplication();
case Constants.TypeFolderLock:
return new BoxFolderLock();
}
}
//There is an inconsistency in the events API where file sources have slightly different field names
Expand Down
72 changes: 72 additions & 0 deletions Box.V2/Managers/BoxFoldersManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
using Box.V2.Extensions;
using Box.V2.Models;
using Box.V2.Services;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
Expand Down Expand Up @@ -448,5 +449,76 @@ public async Task<bool> RemoveWatermarkAsync(string id)
return response.Status == ResponseStatus.Success;
}

/// <summary>
/// Creates a folder lock on a folder, preventing it from being moved and/or deleted.
/// </summary>
/// <param name="id">Id of the folder to create a lock on</param>
/// <returns>An object representing the lock on the folder</returns>
public async Task<BoxFolderLock> CreateLockAsync(string id)
{
id.ThrowIfNullOrWhiteSpace("id");

JObject bodyObject = new JObject();
JObject folderObject = new JObject();
JObject lockOperationsObject = new JObject();

folderObject.Add("id", id);
folderObject.Add("type", "folder");

lockOperationsObject.Add("move", true);
lockOperationsObject.Add("delete", true);

bodyObject.Add("folder", folderObject);
bodyObject.Add("locked_operations", lockOperationsObject);

BoxRequest request = new BoxRequest(_config.FolderLocksEndpointUri)
.Method(RequestMethod.Post)
.Payload(_converter.Serialize(bodyObject));
request.ContentType = Constants.RequestParameters.ContentTypeJson;

IBoxResponse<BoxFolderLock> response = await ToResponseAsync<BoxFolderLock>(request).ConfigureAwait(false);
return response.ResponseObject;
}

/// <summary>
/// Lists all folder locks for a given folder.
/// </summary>
/// <param name="id">Id of the folder</param>
/// <param name="autoPaginate">Whether or not to auto-paginate to fetch all locks. Currently only one lock can exist per folder.; defaults to false.</param>
/// <returns>A collection of locks on the folder</returns>
public async Task<BoxCollection<BoxFolderLock>> GetLocksAsync(string id, bool autoPaginate = false)
{
id.ThrowIfNullOrWhiteSpace("id");

BoxRequest request = new BoxRequest(_config.FolderLocksEndpointUri)
.Method(RequestMethod.Get)
.Param("folder_id", id);

if (autoPaginate)
{
return await AutoPaginateLimitOffset<BoxFolderLock>(request, 1000);
}
else
{
IBoxResponse<BoxCollection<BoxFolderLock>> response = await ToResponseAsync<BoxCollection<BoxFolderLock>>(request).ConfigureAwait(false);
return response.ResponseObject;
}
}

/// <summary>
/// Delete a folder lock on a folder
/// </summary>
/// <param name="id">Id of the folder lock</param>
/// <returns>True will be returned upon successful deletionr</returns>
public async Task<bool> DeleteLockAsync(string id)
{
id.ThrowIfNullOrWhiteSpace("id");

BoxRequest request = new BoxRequest(_config.FolderLocksEndpointUri, id)
.Method(RequestMethod.Delete);

IBoxResponse<BoxFolderLock> response = await ToResponseAsync<BoxFolderLock>(request).ConfigureAwait(false);
return response.Status == ResponseStatus.Success;
}
}
}
47 changes: 47 additions & 0 deletions Box.V2/Models/BoxFolderLock.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
using Newtonsoft.Json;
using System;

namespace Box.V2.Models
{
/// <summary>
/// Box representation of a folder lock in box
/// </summary>
public class BoxFolderLock : BoxEntity
{
public const string FieldCreatedAt = "created_at";
public const string FieldCreatedBy = "created_by";
public const string FieldFolder = "folder";
public const string FieldLockType = "lock_type";
public const string FieldLockedOperations = "locked_operations";

/// <summary>
/// The time the lock was created
/// </summary>
[JsonProperty(PropertyName = FieldCreatedAt)]
public DateTime? CreatedAt { get; private set; }

/// <summary>
/// The user who created this lock
/// </summary>
[JsonProperty(PropertyName = FieldCreatedBy)]
public BoxUser CreatedBy { get; private set; }

/// <summary>
/// The folder that the lock applies to
/// </summary>
[JsonProperty(PropertyName = FieldFolder)]
public BoxFolder Folder { get; private set; }

/// <summary>
/// The lock type
/// </summary>
[JsonProperty(PropertyName = FieldLockType)]
public string LockType { get; private set; }

/// <summary>
/// The operations locked by a folder lock
/// </summary>
[JsonProperty(PropertyName = FieldLockedOperations)]
public BoxFolderLockOperations LockedOperations { get; private set; }
}
}
26 changes: 26 additions & 0 deletions Box.V2/Models/BoxFolderLockOperations.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
using System;
using Newtonsoft.Json;

namespace Box.V2.Models
{
/// <summary>
/// Box representation of a operations that have been locked on a folder lock in box
/// </summary>
public class BoxFolderLockOperations
{
public const string FieldDelete = "delete";
public const string FieldMove = "move";

/// <summary>
/// Whether deleting the folder is restricted
/// </summary>
[JsonProperty(PropertyName = FieldDelete)]
public bool Delete { get; private set; }

/// <summary>
/// Whether deleting the folder is restricted
/// </summary>
[JsonProperty(PropertyName = FieldMove)]
public bool Move { get; private set; }
}
}
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

- Add filter fields to get file version retentions ([#717](https://github.com/box/box-windows-sdk-v2/pull/717))
- Add support for search param to get shared link items ([#721](https://github.com/box/box-windows-sdk-v2/pull/721))
- Add folder lock functionality ([#725](https://github.com/box/box-windows-sdk-v2/pull/725))

## 3.25.0 [2020-10-19]

Expand Down
Loading