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 upload and delete support for Avatar API #829

Merged
merged 9 commits into from
May 26, 2022
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
1 change: 1 addition & 0 deletions Box.V2.Core/Box.V2.Core.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
</ItemGroup>

<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.StaticFiles" Version="2.2.0" />
<PackageReference Include="Microsoft.CSharp" Version="4.7.0" />
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.1.1" PrivateAssets="All" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
Expand Down
3 changes: 3 additions & 0 deletions Box.V2.Test.Integration/Box.V2.Test.Integration.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@
<None Update="config.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="TestData\smallpic.png">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="TestData\smalltest.pdf">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
Expand Down
2 changes: 1 addition & 1 deletion Box.V2.Test.Integration/BoxFilesManagerIntegrationTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,7 @@ await Retry(async () =>
var response = await AdminClient.FilesManager.GetInformationAsync(uploadedFile.Id, new List<string>() { "disposition_at" });

Assert.IsTrue(newDispositionDate.IsEqualUpToSeconds(response.DispositionAt.Value));
}, 5, 5000);
});
}

[TestMethod]
Expand Down
46 changes: 46 additions & 0 deletions Box.V2.Test.Integration/BoxUsersManagerIntegrationTest.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using Box.V2.Models;
Expand Down Expand Up @@ -69,5 +70,50 @@ public async Task DeleteEnterpriseUserAsync_ForExistingUser_ShouldDeleteThisUser
var appUsers = await AdminClient.UsersManager.GetEnterpriseUsersAsync();
Assert.IsFalse(appUsers.Entries.Any(item => item.Id == newUser.Id));
}

[TestMethod]
public async Task UploadUserAvatar_UsingFileStream_ShouldReturnUploadedAvatarUris()
{
var user = await CreateEnterpriseUser();

using (var fileStream = new FileStream(GetSmallPicturePath(), FileMode.OpenOrCreate))
{
var response = await AdminClient.UsersManager.AddOrUpdateUserAvatarAsync(user.Id, fileStream);

Assert.IsNotNull(response.PicUrls.Preview);
Assert.IsNotNull(response.PicUrls.Small);
Assert.IsNotNull(response.PicUrls.Large);
}
}

[TestMethod]
public async Task UploadUserAvatar_UsingFileStreamWithExplicitFilename_ShouldReturnUploadedAvatarUris()
{
var user = await CreateEnterpriseUser();

using (var fileStream = new FileStream(GetSmallPicturePath(), FileMode.OpenOrCreate))
{
var response = await AdminClient.UsersManager.AddOrUpdateUserAvatarAsync(user.Id, fileStream, "newAvatar.png");

Assert.IsNotNull(response.PicUrls.Preview);
Assert.IsNotNull(response.PicUrls.Small);
Assert.IsNotNull(response.PicUrls.Large);
}
}

[TestMethod]
public async Task DeleteAvatar_ForExistingUserAvatar_ShouldReturnSuccessStatusCode()
{
var user = await CreateEnterpriseUser();

using (var fileStream = new FileStream(GetSmallPicturePath(), FileMode.OpenOrCreate))
{
var response = await AdminClient.UsersManager.AddOrUpdateUserAvatarAsync(user.Id, fileStream);
}

var deleteAvatarResponse = await AdminClient.UsersManager.DeleteUserAvatarAsync(user.Id);

Assert.IsTrue(deleteAvatarResponse);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
using System.IO;
using System.Threading.Tasks;
using Box.V2.Models;

namespace Box.V2.Test.Integration.Configuration.Commands.DisposableCommands
{
public class CreateUserAvatarCommand : CommandBase, IDisposableCommand
{
private readonly string _userId;
private readonly string _filePath;

public BoxUploadAvatarResponse Response;

public CreateUserAvatarCommand(string userId, string filePath,
CommandScope scope = CommandScope.Test, CommandAccessLevel accessLevel = CommandAccessLevel.Admin) : base(scope, accessLevel)
{
_userId = userId;
_filePath = filePath;
}

public async Task<string> Execute(IBoxClient client)
{
using (var fileStream = new FileStream(_filePath, FileMode.OpenOrCreate))
{
Response = await client.UsersManager.AddOrUpdateUserAvatarAsync(_userId, fileStream);
}

return "0";
}

public async Task Dispose(IBoxClient client)
{
await client.UsersManager.DeleteUserAvatarAsync(_userId);
}
}
}
18 changes: 15 additions & 3 deletions Box.V2.Test.Integration/Configuration/IntegrationTestBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ protected static Task<BoxUser> CreateNewUser(IBoxClient client)
{
var userRequest = new BoxUserRequest
{
Name = "IT App User - " + Guid.NewGuid().ToString(),
Name = "IT App User - " + Guid.NewGuid().ToString(),
IsPlatformAccessOnly = true
};
var user = client.UsersManager.CreateEnterpriseUserAsync(userRequest);
Expand Down Expand Up @@ -166,7 +166,7 @@ public static async Task<string> ExecuteCommand(IDisposableCommand command)
IBoxClient client = GetClient(command);

var resourceId = await command.Execute(client);
if(command.Scope == CommandScope.Test)
if (command.Scope == CommandScope.Test)
{
TestCommands.Push(command);
}
Expand Down Expand Up @@ -200,6 +200,11 @@ public static string GetSmallFileV2Path()
return string.Format(AppDomain.CurrentDomain.BaseDirectory + "/TestData/smalltestV2.pdf");
}

public static string GetSmallPicturePath()
{
return string.Format(AppDomain.CurrentDomain.BaseDirectory + "/TestData/smallpic.png");
}

public static string ReadFromJson(string path)
{
var filePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, path);
Expand Down Expand Up @@ -345,7 +350,14 @@ public static async Task<BoxFile> CreateNewFileVersion(string fileId)
return createNewFileVersionCommand.File;
}

public static async Task Retry(Func<Task> action, int retries = 3, int sleep = 1000)
public static async Task<BoxUploadAvatarResponse> CreateUserAvatar(string userId)
{
var createAvatarCommand = new CreateUserAvatarCommand(userId, GetSmallPicturePath());
await ExecuteCommand(createAvatarCommand);
return createAvatarCommand.Response;
}

public static async Task Retry(Func<Task> action, int retries = 5, int sleep = 5000)
{
var retryCount = 0;
while (retryCount < retries)
Expand Down
Binary file added Box.V2.Test.Integration/TestData/smallpic.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions Box.V2.Test/Box.V2.Test.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,9 @@
<None Update="Fixtures\BoxSignRequest\GetSignRequest200.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Fixtures\BoxUsers\AddOrUpdateUserAvatar200.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="TestData\smalltest.pdf">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
Expand Down
91 changes: 91 additions & 0 deletions Box.V2.Test/BoxUsersManagerTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -720,5 +720,96 @@ public async Task GetUserAvatar_ValidResponse_ValidStream()

}
}

[TestMethod]
public async Task AddOrUpdateUserAvatar_ValidResponse_ValidStream()
{
/*** Arrange ***/
var responseString = LoadFixtureFromJson("Fixtures/BoxUsers/AddOrUpdateUserAvatar200.json");
BoxMultiPartRequest boxRequest = null;
Handler.Setup(h => h.ExecuteAsync<BoxUploadAvatarResponse>(It.IsAny<IBoxRequest>()))
.Returns(Task.FromResult<IBoxResponse<BoxUploadAvatarResponse>>(new BoxResponse<BoxUploadAvatarResponse>()
{
Status = ResponseStatus.Success,
ContentString = responseString
}))
.Callback<IBoxRequest>(r => boxRequest = r as BoxMultiPartRequest);

var fakeStream = new Mock<Stream>();
var fileName = "newAvatar.png";

/*** Act ***/
BoxUploadAvatarResponse response = await _usersManager.AddOrUpdateUserAvatarAsync("11111", fakeStream.Object, fileName);

/*** Assert ***/
Assert.IsNotNull(boxRequest);
Assert.AreEqual(RequestMethod.Post, boxRequest.Method);
Assert.AreEqual(new Uri("https://api.box.com/2.0/users/11111/avatar"), boxRequest.AbsoluteUri.AbsoluteUri);
Assert.IsNotNull(boxRequest.Parts[0] as BoxFileFormPart);
Assert.AreEqual(fileName, (boxRequest.Parts[0] as BoxFileFormPart).FileName);
Assert.AreEqual("image/png", (boxRequest.Parts[0] as BoxFileFormPart).ContentType);
Assert.IsTrue(ReferenceEquals(fakeStream.Object, (boxRequest.Parts[0] as BoxFileFormPart).Value));

Assert.IsNotNull(response.PicUrls);
Assert.IsNotNull(response.PicUrls.Preview);
Assert.IsNotNull(response.PicUrls.Small);
Assert.IsNotNull(response.PicUrls.Large);
}

[TestMethod]
public async Task AddOrUpdateUserAvatar_ValidResponse_ValidFileStream()
{
var responseString = LoadFixtureFromJson("Fixtures/BoxUsers/AddOrUpdateUserAvatar200.json");
BoxMultiPartRequest boxRequest = null;
Handler.Setup(h => h.ExecuteAsync<BoxUploadAvatarResponse>(It.IsAny<IBoxRequest>()))
.Returns(Task.FromResult<IBoxResponse<BoxUploadAvatarResponse>>(new BoxResponse<BoxUploadAvatarResponse>()
{
Status = ResponseStatus.Success,
ContentString = responseString
}))
.Callback<IBoxRequest>(r => boxRequest = r as BoxMultiPartRequest);

var stream = new FileStream("newAvatar.png", FileMode.OpenOrCreate);

BoxUploadAvatarResponse response = await _usersManager.AddOrUpdateUserAvatarAsync("11111", stream);

Assert.IsNotNull(boxRequest);
Assert.AreEqual(RequestMethod.Post, boxRequest.Method);
Assert.AreEqual(new Uri("https://api.box.com/2.0/users/11111/avatar"), boxRequest.AbsoluteUri.AbsoluteUri);
Assert.IsNotNull(boxRequest.Parts[0] as BoxFileFormPart);
Assert.AreEqual("newAvatar.png", (boxRequest.Parts[0] as BoxFileFormPart).FileName);
Assert.AreEqual("image/png", (boxRequest.Parts[0] as BoxFileFormPart).ContentType);
Assert.IsTrue(ReferenceEquals(stream, (boxRequest.Parts[0] as BoxFileFormPart).Value));

Assert.IsNotNull(response.PicUrls);
Assert.IsNotNull(response.PicUrls.Preview);
Assert.IsNotNull(response.PicUrls.Small);
Assert.IsNotNull(response.PicUrls.Large);
}

[TestMethod]
public async Task AddOrUpdateUserAvatar_ValidResponse()
{
/*** Arrange ***/
var responseString = "";
IBoxRequest boxRequest = null;
Handler.Setup(h => h.ExecuteAsync<BoxEntity>(It.IsAny<IBoxRequest>()))
.Returns(Task.FromResult<IBoxResponse<BoxEntity>>(new BoxResponse<BoxEntity>()
{
Status = ResponseStatus.Success,
ContentString = responseString
})).Callback<IBoxRequest>(r => boxRequest = r);

/*** Act ***/
var result = await _usersManager.DeleteUserAvatarAsync("11111");

/*** Assert ***/
/*** Request ***/
Assert.IsNotNull(boxRequest);
Assert.AreEqual(RequestMethod.Delete, boxRequest.Method);
Assert.AreEqual(new Uri("https://api.box.com/2.0/users/11111/avatar"), boxRequest.AbsoluteUri.AbsoluteUri);
/*** Response ***/
Assert.AreEqual(true, result);
}
}
}
18 changes: 18 additions & 0 deletions Box.V2.Test/ContentTypeMapperTest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
using Box.V2.Utility;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace Box.V2.Test
{
[TestClass]
public class ContentTypeMapperTest : BoxResourceManagerTest
{
[TestMethod]
[DataRow("avatar.png", "image/png")]
[DataRow("avatar.jpg", "image/jpeg")]
[DataRow("avatar.jpeg", "image/jpeg")]
public void ContentTypeMapper_ForGivenFilename_ShouldMapToTheCorrectMimeType(string fileName, string mimeType)
{
Assert.AreEqual(ContentTypeMapper.GetContentTypeFromFilename(fileName), mimeType);
}
}
}
7 changes: 7 additions & 0 deletions Box.V2.Test/Fixtures/BoxUsers/AddOrUpdateUserAvatar200.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"pic_urls": {
"large": "https://app.box.com/index.php?rm=pic_storage_auth&pic=euks pac3kv01!lipGQlQQOtCTCoB6zCOArUjVWLFJtLr5tn6aOZMCybhRx0NNuFQbVI36nw jtEk5YjUUz1KVdVuvU2yDhu_ftK_bvxeKP1Ffrx9vKGVvJ-UJc1z32p6n2CmFzzpc gSoX4pnPhFgydAL-u9jDspXUGElr-htDG_HPMiE9DZjqDueOxXHy8xe22wbaPAheC ao1emv8r_fmufaUgSndeMYmyZj-KqOYsLBrBNgdeiK5tZmPOQggAEUmyQPkrd8W92TQ6sSlIp0r",
"preview": "https://app.box.com/index.php?rm=pic_storage_auth&pic=euks! pac3kv01!8UcNPweOOAWj2DtHk_dCQB4wJpzyPkl7mT5nHj5ZdjY92ejYCBBZc95--403b29CW k-8hSo_uBjh5h9QG42Ihu-cOZ-816sej1kof3SOm5gjn7qjMAx89cHjUaNK-6XasRqSNboenjZ 04laZuV9vSH12BZGAYycIZvvQ5R66Go8xG5GTMARf2nBU84c4H_SL5iws-HeBS4oQJWOJh6FBl sSJDSTI74LGXqeZb3EY_As34VFC95F10uozoTOSubZmPYylPlaKXoKWk2f9wYQso1ZTN7sh-Gc 9Kp43zMLhArIWhok0Im6FlRAuWOQ03KYgL-k4L5EZp4Gw6B7uqVRwcBbsTwMIorWq1g",
"small": "https://app.box.com/index.php?rm=pic_storage_auth&pic=euks! pac3kv01!7B6R5cZLmurEV_xB-KkycPk8Oi7oENUX2O_qUtIuO4342CG IldyCto9hqiQP7uxqYU5V2w63Ft4ln4UVVLDtDZu903OqzkflY2O-Lq00 ubA29xU-RJ6b_KzJEWRYgUhX1zEl3dzWo12g8eWRE2rStf123DF7AYahNqM 1BmLmviL_nODc7SDQHedTXPAjxURUAra5BvtLe7B05AizbNXdPlCNp-LNh _S-eZ_RjDXcGO-MkRWd_3BOMHnvjf450t5BfKoJ15WhEfiMlfXH1tmouHXrsC 66cT6-pzF9E40Iir_zThqSlrFxzP_xcmXzHapr_k-0E2qr2TXp4iC396TSlEw"
}
}
3 changes: 3 additions & 0 deletions Box.V2/Box.V2.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@
<HintPath>..\packages\System.IdentityModel.Tokens.Jwt.6.12.2\lib\net45\System.IdentityModel.Tokens.Jwt.dll</HintPath>
</Reference>
<Reference Include="System.Runtime.Serialization" />
<Reference Include="System.Web" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
Expand Down Expand Up @@ -185,6 +186,7 @@
<Compile Include="Models\BoxTaskAssignment.cs" />
<Compile Include="Models\BoxTermsOfService.cs" />
<Compile Include="Models\BoxTermsOfServiceUserStatuses.cs" />
<Compile Include="Models\BoxUploadAvatarResponse.cs" />
<Compile Include="Models\BoxUserFileCollaborationEventSource.cs" />
<Compile Include="Models\BoxUserFolderCollaborationEventSource.cs" />
<Compile Include="Models\BoxTrackingCode.cs" />
Expand Down Expand Up @@ -262,6 +264,7 @@
<Compile Include="Utility\Helper.cs" />
<Compile Include="Utility\IRetryStrategy.cs" />
<Compile Include="Utility\LRUCache.cs" />
<Compile Include="Utility\ContentTypeMapper.cs" />
<Compile Include="Utility\Retry.cs" />
<Compile Include="Wrappers\BoxError.cs" />
<Compile Include="Wrappers\BoxErrorContextInfo.cs" />
Expand Down
50 changes: 50 additions & 0 deletions Box.V2/Managers/BoxUsersManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
using Box.V2.Models;
using Box.V2.Models.Request;
using Box.V2.Services;
using Box.V2.Utility;

namespace Box.V2.Managers
{
Expand Down Expand Up @@ -387,5 +388,54 @@ public async Task<Stream> GetUserAvatar(string userId)
IBoxResponse<Stream> response = await ToResponseAsync<Stream>(request).ConfigureAwait(false);
return response.ResponseObject;
}

/// <summary>
/// Adds or updates a user avatar. Supported formats are JPG, JPEG and PNG. Maximum allowed file size is 1MB and 1024x1024 pixels resolution.
/// </summary>
/// <param name="userId">The Id of the user.</param>
/// <param name="stream">FileStream with avatar image.</param>
/// <returns>Response containing avatar Urls.</returns>
public async Task<BoxUploadAvatarResponse> AddOrUpdateUserAvatarAsync(string userId, FileStream stream)
{
return await AddOrUpdateUserAvatarAsync(userId, stream, Path.GetFileName(stream.Name)).ConfigureAwait(false);
}

/// <summary>
/// Adds or updates a user avatar. Supported formats are JPG, JPEG and PNG. Maximum allowed file size is 1MB and 1024x1024 pixels resolution.
/// </summary>
/// <param name="userId">The Id of the user.</param>
/// <param name="stream">Stream with avatar image.</param>
/// <param name="fileName">Filename of the avatar image.</param>
/// <returns>Response containing avatar Urls.</returns>
public async Task<BoxUploadAvatarResponse> AddOrUpdateUserAvatarAsync(string userId, Stream stream, string fileName)
{
BoxMultiPartRequest request = new BoxMultiPartRequest(_config.UserEndpointUri, userId + "/avatar")
.FormPart(new BoxFileFormPart()
{
Name = "pic",
Value = stream,
FileName = fileName,
ContentType = ContentTypeMapper.GetContentTypeFromFilename(fileName)
});

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

return response.ResponseObject;
}

/// <summary>
/// Deletes a user's avatar image.
/// </summary>
/// <param name="userId">Removes an existing user avatar. You cannot reverse this operation.</param>
/// <returns>True if deletion success.</returns>
public async Task<bool> DeleteUserAvatarAsync(string userId)
{
var request = new BoxRequest(_config.UserEndpointUri, userId + "/avatar")
.Method(RequestMethod.Delete);

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

return response.Status == ResponseStatus.Success;
}
}
}
Loading