diff --git a/.gitignore b/.gitignore index d1d96e7..b06db92 100644 --- a/.gitignore +++ b/.gitignore @@ -402,4 +402,4 @@ FodyWeavers.xsd ### VisualStudio Patch ### # Additional files built by Visual Studio -# End of https://www.toptal.com/developers/gitignore/api/visualstudio \ No newline at end of file +# End of https://www.toptal.com/developers/gitignore/api/visualstudio diff --git a/Bynder/Sample/TagsSample.cs b/Bynder/Sample/TagsSample.cs index e64cbba..9c53469 100644 --- a/Bynder/Sample/TagsSample.cs +++ b/Bynder/Sample/TagsSample.cs @@ -10,6 +10,7 @@ using System.Collections.Generic; using Bynder.Sdk.Query.Asset; using Bynder.Sdk.Model; +using Bynder.Sdk.Service.Asset; namespace Bynder.Sample { @@ -33,8 +34,9 @@ private TagsSample(Configuration configuration) { private async Task RunTagsSampleAsync() { + var assetService = _bynderClient.GetAssetService(); Console.WriteLine("Getting tags with a limit of 10: "); - var tags = await _bynderClient.GetAssetService().GetTagsAsync(new GetTagsQuery{Limit = 10}); + var tags = await assetService.GetTagsAsync(new GetTagsQuery{Limit = 10}); foreach(Tag tag in tags){ Console.WriteLine($"Tag Id: {tag.ID}"); Console.WriteLine($"Tag Name: {tag.TagName}"); @@ -42,16 +44,72 @@ private async Task RunTagsSampleAsync() } Console.WriteLine("Enter the media ID to add a tag to: "); - var mediaIdAddTag = Console.ReadLine(); + var mediaId = Console.ReadLine(); Console.WriteLine("Enter the tag ID to add to the media: "); - var tagIdAddToMedia = Console.ReadLine(); - List mediasAddTag = new List + var tagId = Console.ReadLine(); + await assetService.AddTagToMediaAsync(new AddTagToMediaQuery(tagId, [ mediaId ])); + + Console.WriteLine("Hit enter to view the asset (it may take a few seconds before the tag is registered)"); + Console.ReadKey(); + var asset = await assetService.GetMediaInfoAsync(new MediaInformationQuery() { MediaId = mediaId }); + ShowTags(asset); + + Console.WriteLine("Enter a new tag to add to the same media: "); + var anotherTag = Console.ReadLine(); + if (asset.Tags == null) + { + asset.Tags = [anotherTag]; + } + else + { + asset.Tags.Add(anotherTag); + } + + await assetService.ModifyMediaAsync(new ModifyMediaQuery(mediaId) { Tags = asset.Tags } ); + + Console.WriteLine("Hit enter to view the asset (it may take a few seconds before the tag is registered)"); + Console.ReadKey(); + asset = await assetService.GetMediaInfoAsync(new MediaInformationQuery() { MediaId = mediaId }); + ShowTags(asset); + + Console.WriteLine("Hit enter to remove the tags again"); + Console.ReadKey(); + + foreach (var tag in asset.Tags) + { + var matchingTags = await assetService.GetTagsAsync(new GetTagsQuery() { Keyword = tag }); + if (matchingTags.Any()) + { + var tagToRemove = matchingTags.FirstOrDefault(t => t.TagName.Equals(tag, StringComparison.InvariantCultureIgnoreCase)); + Console.WriteLine($"Removing tag {tagToRemove.TagName} with id {tagToRemove.ID}"); + await assetService.RemoveTagFromMediaAsync(tagToRemove.ID, [mediaId]); + } + else + { + Console.WriteLine($"Error: after adding tag with name '{tag}' to asset {mediaId}, tag cannot be found in Bynder"); + } + } + + Console.WriteLine("Hit enter to view the asset (it may take a few seconds before the tags have been removed)"); + Console.ReadKey(); + + asset = await assetService.GetMediaInfoAsync(new MediaInformationQuery() { MediaId = mediaId }); + ShowTags(asset); + + } + + private async void ShowTags(Media asset) + { + if (asset.Tags?.Any() ?? false) + { + Console.WriteLine($"Media with name {asset.Name} now has the following tags: {string.Join(',', asset.Tags)}"); + } + else { - mediaIdAddTag - }; - await _bynderClient.GetAssetService().AddTagToMediaAsync(new AddTagToMediaQuery(tagIdAddToMedia, mediasAddTag)); + Console.WriteLine($"Media with name {asset.Name} has no tags"); + } } - + private async Task AuthenticateWithOAuth2Async(bool useClientCredentials) { if (useClientCredentials) diff --git a/Bynder/Sdk/Query/Asset/GetTagsQuery.cs b/Bynder/Sdk/Query/Asset/GetTagsQuery.cs index 701ec4e..f476ad9 100644 --- a/Bynder/Sdk/Query/Asset/GetTagsQuery.cs +++ b/Bynder/Sdk/Query/Asset/GetTagsQuery.cs @@ -1,41 +1,44 @@ using Bynder.Sdk.Api.Converters; using Bynder.Sdk.Model; -using Bynder.Sdk.Query.Decoder; - -namespace Bynder.Sdk.Query.Asset +using Bynder.Sdk.Query.Decoder; + +namespace Bynder.Sdk.Query.Asset { - public class GetTagsQuery - { - /// - /// Maximum number of results. - /// - [ApiField("limit")] - public int Limit { get; set; } - - /// - /// Offset page for results: return the N-th set of limit-results. - /// - [ApiField("page")] - public int Page { get; set; } - - /// - /// Order of the returned list of tags. - /// See for possible values. - /// - [ApiField("orderBy", Converter = typeof(TagsOrderByConverter))] - public TagsOrderBy OrderBy { get; set; } - - /// - /// Search on matching names. - /// - [ApiField("keyword")] - public string Keyword { get; set; } - - /// - /// Minimum media count that the returned tags should have. - /// - [ApiField("mincount")] - public int MinCount { get; set; } - - } -} + public class GetTagsQuerySimple + { + /// + /// Maximum number of results. + /// + [ApiField("limit")] + public int Limit { get; set; } + + /// + /// Offset page for results: return the N-th set of limit-results. + /// + [ApiField("page")] + public int Page { get; set; } + + /// + /// Order of the returned list of tags. + /// See for possible values. + /// + [ApiField("orderBy", Converter = typeof(TagsOrderByConverter))] + public TagsOrderBy OrderBy { get; set; } + + /// + /// Search on matching names. + /// + [ApiField("keyword")] + public string Keyword { get; set; } + } + public class GetTagsQuery : GetTagsQuerySimple + { + + /// + /// Minimum media count that the returned tags should have. + /// + [ApiField("mincount")] + public int MinCount { get; set; } + + } +} diff --git a/Bynder/Sdk/Query/Asset/ModifyMediaQuery.cs b/Bynder/Sdk/Query/Asset/ModifyMediaQuery.cs index fe571b7..a7e4f65 100644 --- a/Bynder/Sdk/Query/Asset/ModifyMediaQuery.cs +++ b/Bynder/Sdk/Query/Asset/ModifyMediaQuery.cs @@ -1,4 +1,4 @@ -using System.Collections.Generic; +using System.Collections.Generic; using Bynder.Sdk.Api.Converters; using Bynder.Sdk.Query.Decoder; @@ -68,6 +68,13 @@ public void AddMetapropertyOptions(string metapropertyId, IList optionId { MetapropertyOptions.Add(metapropertyId, optionIds); } + + /// + /// Tags that will be added to the asset + /// + [ApiField("tags", Converter = typeof(ListConverter))] + public IList Tags { get; set; } + } } diff --git a/Bynder/Sdk/Service/Asset/AssetService.cs b/Bynder/Sdk/Service/Asset/AssetService.cs index d5e15ba..e02eabf 100644 --- a/Bynder/Sdk/Service/Asset/AssetService.cs +++ b/Bynder/Sdk/Service/Asset/AssetService.cs @@ -11,6 +11,7 @@ using Bynder.Sdk.Model; using Bynder.Sdk.Query.Asset; using Bynder.Sdk.Query.Upload; +using System.Web; namespace Bynder.Sdk.Service.Asset { @@ -179,11 +180,17 @@ public async Task ModifyMediaAsync(ModifyMediaQuery query) /// Check for more information public async Task> GetTagsAsync(GetTagsQuery query) { + var queryToUse = string.IsNullOrEmpty(query.Keyword) ? query : new GetTagsQuerySimple() { + Keyword = query.Keyword, + Limit = query.Limit, + OrderBy = query.OrderBy, + Page = query.Page + }; return await _requestSender.SendRequestAsync(new ApiRequest> { Path = "/api/v4/tags/", HTTPMethod = HttpMethod.Get, - Query = query + Query = queryToUse }).ConfigureAwait(false); } @@ -201,6 +208,20 @@ public async Task AddTagToMediaAsync(AddTagToMediaQuery query) }).ConfigureAwait(false); } + /// + /// Check for more information + /// + /// Check for more information + public async Task RemoveTagFromMediaAsync(string tagId, IEnumerable assetIds) + { + var encodedIdList = HttpUtility.UrlEncode(string.Join(",", assetIds)); + return await _requestSender.SendRequestAsync(new ApiRequest + { + Path = $"/api/v4/tags/{tagId}/media/?deleteIds={encodedIdList}", + HTTPMethod = HttpMethod.Delete, + }).ConfigureAwait(false); + } + /// /// Create an asset usage operation to track usage of Bynder assets in third party applications. /// diff --git a/Bynder/Sdk/Service/Asset/IAssetService.cs b/Bynder/Sdk/Service/Asset/IAssetService.cs index 17b687a..64d554e 100644 --- a/Bynder/Sdk/Service/Asset/IAssetService.cs +++ b/Bynder/Sdk/Service/Asset/IAssetService.cs @@ -106,6 +106,15 @@ public interface IAssetService /// Can be thrown when requests to server can't be completed or HTTP code returned by server is an error Task AddTagToMediaAsync(AddTagToMediaQuery query); + /// + /// Remove tags from asset + /// + /// Id of the tag to remove + /// Ids of the assets from which the tag should be removed + /// Task representing the upload + /// Can be thrown when requests to server can't be completed or HTTP code returned by server is an error + Task RemoveTagFromMediaAsync(string tagId, IEnumerable assetIds); + /// /// Create an asset usage operation to track usage of Bynder assets in third party applications. /// diff --git a/Bynder/Test/Service/Asset/AssetServiceTest.cs b/Bynder/Test/Service/Asset/AssetServiceTest.cs index 4b633c8..2d84958 100644 --- a/Bynder/Test/Service/Asset/AssetServiceTest.cs +++ b/Bynder/Test/Service/Asset/AssetServiceTest.cs @@ -203,6 +203,25 @@ public async Task GetTagsCallsRequestSenderWithValidRequest() )); } + [Fact] + public async Task GetTagsByKeywordCallsRequestSenderWithValidRequest() + { + var result = new Status { Message = "Accepted", StatusCode = 202 }; + _apiRequestSenderMock.Setup(sender => sender.SendRequestAsync(It.IsAny())) + .ReturnsAsync(result); + var query = new GetTagsQuery { Keyword = "test" }; + await _assetService.GetTagsAsync(query); + + _apiRequestSenderMock.Verify(sender => sender.SendRequestAsync( + It.Is>>(req => + req.Path == "/api/v4/tags/" + && req.HTTPMethod == HttpMethod.Get + && req.Query is GetTagsQuerySimple + && (req.Query as GetTagsQuerySimple).Keyword == query.Keyword + ) + )); + } + [Fact] public async Task AddTagToMediaCallsRequestSenderWithValidRequest() {