Skip to content

Commit

Permalink
v3-tags (#97)
Browse files Browse the repository at this point in the history
* targetframework now net8.0, packages upgraded

* Make it possible to get a list of tags by keyword

* Allow changing tags of an existing Media item

* Make it possible to remove tags from an asset

* changed TagsSample to showcase the new tags-related features

* updated gitignore

* updated gitignore to the toptotal standard, added launchSettings to help developers run the samples

* fixed merge conflict
  • Loading branch information
quirijnslings authored Sep 18, 2024
1 parent b87e130 commit 1ecd14f
Show file tree
Hide file tree
Showing 7 changed files with 166 additions and 49 deletions.
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -402,4 +402,4 @@ FodyWeavers.xsd
### VisualStudio Patch ###
# Additional files built by Visual Studio

# End of https://www.toptal.com/developers/gitignore/api/visualstudio
# End of https://www.toptal.com/developers/gitignore/api/visualstudio
74 changes: 66 additions & 8 deletions Bynder/Sample/TagsSample.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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
{
Expand All @@ -33,25 +34,82 @@ 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}");
Console.WriteLine($"Tag MediaCount: {tag.MediaCount}");
}

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<string> mediasAddTag = new List<string>
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)
Expand Down
79 changes: 41 additions & 38 deletions Bynder/Sdk/Query/Asset/GetTagsQuery.cs
Original file line number Diff line number Diff line change
@@ -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
{
/// <summary>
/// Maximum number of results.
/// </summary>
[ApiField("limit")]
public int Limit { get; set; }

/// <summary>
/// Offset page for results: return the N-th set of limit-results.
/// </summary>
[ApiField("page")]
public int Page { get; set; }

/// <summary>
/// <para>Order of the returned list of tags. </para>
/// <para>See <see cref="TagsOrderBy"/> for possible values.</para>
/// </summary>
[ApiField("orderBy", Converter = typeof(TagsOrderByConverter))]
public TagsOrderBy OrderBy { get; set; }

/// <summary>
/// Search on matching names.
/// </summary>
[ApiField("keyword")]
public string Keyword { get; set; }

/// <summary>
/// Minimum media count that the returned tags should have.
/// </summary>
[ApiField("mincount")]
public int MinCount { get; set; }

}
}
public class GetTagsQuerySimple
{
/// <summary>
/// Maximum number of results.
/// </summary>
[ApiField("limit")]
public int Limit { get; set; }

/// <summary>
/// Offset page for results: return the N-th set of limit-results.
/// </summary>
[ApiField("page")]
public int Page { get; set; }

/// <summary>
/// <para>Order of the returned list of tags. </para>
/// <para>See <see cref="TagsOrderBy"/> for possible values.</para>
/// </summary>
[ApiField("orderBy", Converter = typeof(TagsOrderByConverter))]
public TagsOrderBy OrderBy { get; set; }

/// <summary>
/// Search on matching names.
/// </summary>
[ApiField("keyword")]
public string Keyword { get; set; }
}
public class GetTagsQuery : GetTagsQuerySimple
{

/// <summary>
/// Minimum media count that the returned tags should have.
/// </summary>
[ApiField("mincount")]
public int MinCount { get; set; }

}
}
9 changes: 8 additions & 1 deletion Bynder/Sdk/Query/Asset/ModifyMediaQuery.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using System.Collections.Generic;
using System.Collections.Generic;
using Bynder.Sdk.Api.Converters;
using Bynder.Sdk.Query.Decoder;

Expand Down Expand Up @@ -68,6 +68,13 @@ public void AddMetapropertyOptions(string metapropertyId, IList<string> optionId
{
MetapropertyOptions.Add(metapropertyId, optionIds);
}

/// <summary>
/// Tags that will be added to the asset
/// </summary>
[ApiField("tags", Converter = typeof(ListConverter))]
public IList<string> Tags { get; set; }

}
}

23 changes: 22 additions & 1 deletion Bynder/Sdk/Service/Asset/AssetService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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
{
Expand Down Expand Up @@ -179,11 +180,17 @@ public async Task<Status> ModifyMediaAsync(ModifyMediaQuery query)
/// <returns>Check <see cref="IAssetService"/> for more information</returns>
public async Task<IList<Tag>> 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<IList<Tag>>
{
Path = "/api/v4/tags/",
HTTPMethod = HttpMethod.Get,
Query = query
Query = queryToUse
}).ConfigureAwait(false);
}

Expand All @@ -201,6 +208,20 @@ public async Task<Status> AddTagToMediaAsync(AddTagToMediaQuery query)
}).ConfigureAwait(false);
}

/// <summary>
/// Check <see cref="IAssetService"/> for more information
/// </summary>
/// <returns>Check <see cref="IAssetService"/> for more information</returns>
public async Task<Status> RemoveTagFromMediaAsync(string tagId, IEnumerable<string> 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);
}

/// <summary>
/// Create an asset usage operation to track usage of Bynder assets in third party applications.
/// </summary>
Expand Down
9 changes: 9 additions & 0 deletions Bynder/Sdk/Service/Asset/IAssetService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,15 @@ public interface IAssetService
/// <exception cref="HttpRequestException">Can be thrown when requests to server can't be completed or HTTP code returned by server is an error</exception>
Task<Status> AddTagToMediaAsync(AddTagToMediaQuery query);

/// <summary>
/// Remove tags from asset
/// </summary>
/// <param name="tagId">Id of the tag to remove</param>
/// <param name="assetIds">Ids of the assets from which the tag should be removed</param>
/// <returns>Task representing the upload</returns>
/// <exception cref="HttpRequestException">Can be thrown when requests to server can't be completed or HTTP code returned by server is an error</exception>
Task<Status> RemoveTagFromMediaAsync(string tagId, IEnumerable<string> assetIds);

/// <summary>
/// Create an asset usage operation to track usage of Bynder assets in third party applications.
/// </summary>
Expand Down
19 changes: 19 additions & 0 deletions Bynder/Test/Service/Asset/AssetServiceTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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<ApiRequest>()))
.ReturnsAsync(result);
var query = new GetTagsQuery { Keyword = "test" };
await _assetService.GetTagsAsync(query);

_apiRequestSenderMock.Verify(sender => sender.SendRequestAsync(
It.Is<ApiRequest<IList<Tag>>>(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()
{
Expand Down

0 comments on commit 1ecd14f

Please sign in to comment.