From d1480c6b9e68dfd39450e1c11672d491042d91dd Mon Sep 17 00:00:00 2001 From: Huib Piguillet Date: Fri, 3 Dec 2021 12:57:01 +0100 Subject: [PATCH] API-748 - Add logic to be able to pass metaproperty options during save & modify media (#70) * Added ITypeToDictionaryConverter * Added converter for metaproperty options * Added "metaproperty" param to queries * Version update to 2.2.10 --- .../Converters/ITypeToDictionaryConverter.cs | 29 ++++++ .../MetapropertyOptionsConverter.cs | 24 +++++ Bynder/Sdk/Bynder.Sdk.csproj | 12 +-- Bynder/Sdk/Query/Asset/ModifyMediaQuery.cs | 20 +++- Bynder/Sdk/Query/Decoder/QueryDecoder.cs | 49 +++++----- Bynder/Sdk/Query/Upload/SaveMediaQuery.cs | 17 ++++ .../MetapropertyOptionsConverterTest.cs | 53 +++++++++++ Bynder/Test/Query/Decoder/QueryDecoderTest.cs | 93 +++++++++++++++---- 8 files changed, 250 insertions(+), 47 deletions(-) create mode 100644 Bynder/Sdk/Api/Converters/ITypeToDictionaryConverter.cs create mode 100644 Bynder/Sdk/Api/Converters/MetapropertyOptionsConverter.cs create mode 100644 Bynder/Test/Api/Converters/MetapropertyOptionsConverterTest.cs diff --git a/Bynder/Sdk/Api/Converters/ITypeToDictionaryConverter.cs b/Bynder/Sdk/Api/Converters/ITypeToDictionaryConverter.cs new file mode 100644 index 0000000..6043497 --- /dev/null +++ b/Bynder/Sdk/Api/Converters/ITypeToDictionaryConverter.cs @@ -0,0 +1,29 @@ +// Copyright (c) Bynder. All rights reserved. +// Licensed under the MIT License. See LICENSE file in the project root for full license information. + +using System; +using System.Collections.Generic; + +namespace Bynder.Sdk.Api.Converters +{ + /// + /// Interface for type converters used to decode specific + /// parameters to strings + /// + public interface ITypeToDictionaryConverter + { + /// + /// Checks if the converter can convert a specific type + /// + /// Type to convert from + /// true if it can convert the type + bool CanConvert(Type typeToConvert); + + /// + /// Converts the value to string + /// + /// value to be converted + /// converted string value + IDictionary Convert(object value); + } +} diff --git a/Bynder/Sdk/Api/Converters/MetapropertyOptionsConverter.cs b/Bynder/Sdk/Api/Converters/MetapropertyOptionsConverter.cs new file mode 100644 index 0000000..fd603f9 --- /dev/null +++ b/Bynder/Sdk/Api/Converters/MetapropertyOptionsConverter.cs @@ -0,0 +1,24 @@ +using System; +using System.Collections.Generic; +using System.Linq; + +namespace Bynder.Sdk.Api.Converters +{ + public class MetapropertyOptionsConverter : ITypeToDictionaryConverter + { + + public bool CanConvert(Type typeToConvert) + { + return typeof(IDictionary>).IsAssignableFrom(typeToConvert); + } + + public IDictionary Convert(object value) + { + return ((IDictionary>)value).ToDictionary( + item => item.Key, + item => string.Join(",", item.Value) + ); + } + + } +} diff --git a/Bynder/Sdk/Bynder.Sdk.csproj b/Bynder/Sdk/Bynder.Sdk.csproj index 5b3a8f2..600a317 100644 --- a/Bynder/Sdk/Bynder.Sdk.csproj +++ b/Bynder/Sdk/Bynder.Sdk.csproj @@ -1,13 +1,13 @@ netstandard2.1;net48 - 2.2.9.0 - 2.2.9.0 + 2.2.10.0 + 2.2.10.0 Bynder Bynder.Sdk Copyright © Bynder true - 2.2.9 + 2.2.10 BynderDevops The main goal of this SDK is to speed up the integration of Bynder customers who use C# making it easier to connect to the Bynder API (http://docs.bynder.apiary.io/) and executing requests on it. BynderLogo.png @@ -17,7 +17,7 @@ true BynderDevops https://github.com/Bynder/bynder-c-sharp-sdk - The UploadFile call now returns data about the created asset. + Added "transformBaseUrl" field to Media model. Added functionality to create and delete asset usage records. Added functionality to pass metaproperty options during save & modify media. The main goal of this SDK is to speed up the integration of Bynder customers who use C# making it easier to connect to the Bynder API (http://docs.bynder.apiary.io/) and executing requests on it. Bynder API C# SDK Bynder.Sdk @@ -37,7 +37,7 @@ - - + + diff --git a/Bynder/Sdk/Query/Asset/ModifyMediaQuery.cs b/Bynder/Sdk/Query/Asset/ModifyMediaQuery.cs index 8c753a6..fe571b7 100644 --- a/Bynder/Sdk/Query/Asset/ModifyMediaQuery.cs +++ b/Bynder/Sdk/Query/Asset/ModifyMediaQuery.cs @@ -1,5 +1,5 @@ -using System; -using System.Collections.Generic; +using System.Collections.Generic; +using Bynder.Sdk.Api.Converters; using Bynder.Sdk.Query.Decoder; namespace Bynder.Sdk.Query.Asset @@ -52,6 +52,22 @@ public ModifyMediaQuery(string mediaId) /// [ApiField("isPublic")] public bool IsPublic { get; set; } + + /// + /// Metaproperty options to set on the asset. + /// + [ApiField("metaproperty", Converter = typeof(MetapropertyOptionsConverter))] + public IDictionary> MetapropertyOptions { get; set; } + + /// + /// Add a set of options to a metaproperty + /// + /// metaproperty ID + /// set of options + public void AddMetapropertyOptions(string metapropertyId, IList optionIds) + { + MetapropertyOptions.Add(metapropertyId, optionIds); + } } } diff --git a/Bynder/Sdk/Query/Decoder/QueryDecoder.cs b/Bynder/Sdk/Query/Decoder/QueryDecoder.cs index e970363..345219b 100644 --- a/Bynder/Sdk/Query/Decoder/QueryDecoder.cs +++ b/Bynder/Sdk/Query/Decoder/QueryDecoder.cs @@ -41,20 +41,33 @@ public IDictionary GetParameters(object query) /// property type information /// query object /// collection to add the converted values - private void ConvertProperty(PropertyInfo propertyInfo, object query, IDictionary collection) + private void ConvertProperty(PropertyInfo propertyInfo, object query, IDictionary parameters) { - var attributes = propertyInfo.GetCustomAttributes(true); - foreach (var attribute in attributes) + foreach (var attribute in propertyInfo.GetCustomAttributes(true)) { - if (attribute is ApiField nameAttr) + if (attribute is ApiField apiField) { object value = propertyInfo.GetValue(query); - if (value != null) + if (value == null) { - var convertedValue = ConvertPropertyValue(nameAttr, propertyInfo.PropertyType, value); - if (!string.IsNullOrEmpty(convertedValue)) + return; + } + + if (apiField.Converter == null) + { + AddParam(parameters, apiField.ApiName, value.ToString()); + } + else if (Activator.CreateInstance(apiField.Converter) is ITypeToStringConverter stringConverter + && stringConverter.CanConvert(propertyInfo.PropertyType)) + { + AddParam(parameters, apiField.ApiName, stringConverter.Convert(value)); + } + else if (Activator.CreateInstance(apiField.Converter) is ITypeToDictionaryConverter dictConverter + && dictConverter.CanConvert(propertyInfo.PropertyType)) + { + foreach (var item in dictConverter.Convert(value)) { - collection.Add(nameAttr.ApiName, convertedValue); + AddParam(parameters, $"{apiField.ApiName}.{item.Key}", item.Value); } } @@ -64,21 +77,13 @@ private void ConvertProperty(PropertyInfo propertyInfo, object query, IDictionar } } - /// - /// Function called to convert property values to string. If no converter is - /// specified, then .ToString is called. - /// - /// API field attribute - /// property type information - /// current value - /// converted value - private string ConvertPropertyValue(ApiField apiField, Type propertyType, object value) + private void AddParam(IDictionary parameters, string key, string value) { - return apiField.Converter != null - && Activator.CreateInstance(apiField.Converter) is ITypeToStringConverter converter - && converter.CanConvert(propertyType) - ? converter.Convert(value) - : value.ToString(); + if (!string.IsNullOrEmpty(value)) + { + parameters.Add(key, value); + } } + } } diff --git a/Bynder/Sdk/Query/Upload/SaveMediaQuery.cs b/Bynder/Sdk/Query/Upload/SaveMediaQuery.cs index 0f48b5d..0d8e01b 100644 --- a/Bynder/Sdk/Query/Upload/SaveMediaQuery.cs +++ b/Bynder/Sdk/Query/Upload/SaveMediaQuery.cs @@ -42,5 +42,22 @@ internal class SaveMediaQuery /// [ApiField("tags", Converter = typeof(ListConverter))] public IList Tags { get; set; } + + /// + /// Metaproperty options to set on the asset. + /// + [ApiField("metaproperty", Converter = typeof(MetapropertyOptionsConverter))] + public IDictionary> MetapropertyOptions { get; set; } = new Dictionary>(); + + /// + /// Add a set of options to a metaproperty + /// + /// metaproperty ID + /// set of options + public void AddMetapropertyOptions(string metapropertyId, IList optionIds) + { + MetapropertyOptions.Add(metapropertyId, optionIds); + } + } } diff --git a/Bynder/Test/Api/Converters/MetapropertyOptionsConverterTest.cs b/Bynder/Test/Api/Converters/MetapropertyOptionsConverterTest.cs new file mode 100644 index 0000000..1902b1d --- /dev/null +++ b/Bynder/Test/Api/Converters/MetapropertyOptionsConverterTest.cs @@ -0,0 +1,53 @@ +using System.Collections.Generic; +using Bynder.Sdk.Api.Converters; +using Xunit; + +namespace Bynder.Test.Api.Converters +{ + public class MetapropertyOptionsConverterTest + { + [Fact] + public void CanConvertOnlyWhenTypeIsDateTimeOffset() + { + var converter = new MetapropertyOptionsConverter(); + Assert.False(converter.CanConvert(typeof(int))); + Assert.False(converter.CanConvert(typeof(string))); + Assert.False(converter.CanConvert(typeof(bool))); + Assert.True(converter.CanConvert(typeof(IDictionary>))); + } + + [Fact] + public void ConvertReturnsStringWithDate() + { + const string metaprop1 = "metaprop1"; + const string metaprop1option1 = "metaprop1option1"; + const string metaprop1option2 = "metaprop1option2"; + const string metaprop1option3 = "metaprop1option3"; + + const string metaprop2 = "metaprop2"; + const string metaprop2option1 = "metaprop2option1"; + const string metaprop2option2 = "metaprop2option2"; + const string metaprop2option3 = "metaprop2option3"; + + const string metaprop3 = "metaprop3"; + const string metaprop3option1 = "metaprop3option1"; + const string metaprop3option2 = "metaprop3option2"; + const string metaprop3option3 = "metaprop3option3"; + + var converter = new MetapropertyOptionsConverter(); + var converted = converter.Convert(new Dictionary> + { + { metaprop1, new List { metaprop1option1, metaprop1option2, metaprop1option3 } }, + { metaprop2, new List { metaprop2option1, metaprop2option2, metaprop2option3 } }, + { metaprop3, new List { metaprop3option1, metaprop3option2, metaprop3option3 } } + }); + var expected = new Dictionary + { + { metaprop1, $"{metaprop1option1},{metaprop1option2},{metaprop1option3}" }, + { metaprop2, $"{metaprop2option1},{metaprop2option2},{metaprop2option3}" }, + { metaprop3, $"{metaprop3option1},{metaprop3option2},{metaprop3option3}" } + }; + Assert.Equal(expected, converted); + } + } +} diff --git a/Bynder/Test/Query/Decoder/QueryDecoderTest.cs b/Bynder/Test/Query/Decoder/QueryDecoderTest.cs index fa9e5b0..2749eb6 100644 --- a/Bynder/Test/Query/Decoder/QueryDecoderTest.cs +++ b/Bynder/Test/Query/Decoder/QueryDecoderTest.cs @@ -2,6 +2,7 @@ // Licensed under the MIT License. See LICENSE file in the project root for full license information. using System; +using System.Collections.Generic; using Bynder.Sdk.Api.Converters; using Bynder.Sdk.Query.Decoder; using Xunit; @@ -10,6 +11,23 @@ namespace Bynder.Test.Api { public class QueryDecoderTest { + private const string _stringItem1ApiField = "string1ApiField"; + private const string _stringItem2ApiField = "string2ApiField"; + private const string _dictItemApiField = "dictApiField"; + + private const string _item = "item"; + private const string _stringItem1 = "string1"; + private const string _stringItem2 = "string2"; + + private const string _converted = "converted"; + + private const string _dictKey1 = "dictKey1"; + private const string _dictKey2 = "dictKey2"; + private const string _dictKey3 = "dictKey3"; + private const string _dictValue1 = "dictValue1"; + private const string _dictValue2 = "dictValue2"; + private const string _dictValue3 = "dictValue3"; + /// /// Tests that returns /// only the parameters properties that have the attribute. @@ -20,16 +38,16 @@ public void WhenQueryPassedThenOnlyAPIFieldAttributesAreReturned() var queryDecoder = new QueryDecoder(); var parameters = queryDecoder.GetParameters(new StubQuery { - Item1 = "1", - Item2 = "2", - Item3 = "3" + Item = _item, + StringItem1 = _stringItem1, + StringItem2 = _stringItem2 }); - // Property Item3 should not appear as it does not have APIField attribute + // Unannotated property should not appear as it does not have APIField attribute Assert.Equal(2, parameters.Count); - Assert.Equal("1", parameters["Item1"]); - Assert.Equal("2", parameters["Item2"]); + Assert.Equal(_stringItem1, parameters[_stringItem1ApiField]); + Assert.Equal(_stringItem2, parameters[_stringItem2ApiField]); } /// @@ -42,10 +60,14 @@ public void WhenQueryAttributeHasConverterThenParameterValueIsConverted() var queryDecoder = new QueryDecoder(); var parameters = queryDecoder.GetParameters(new StubConverterQuery { - Item1 = "1" + StringItem = _stringItem1, + DictItem = 42 }); - Assert.Equal("Converted", parameters["Item1"]); + Assert.Equal(_converted, parameters[_stringItem1ApiField]); + Assert.Equal(_dictValue1, parameters[$"{_dictItemApiField}.{_dictKey1}"]); + Assert.Equal(_dictValue2, parameters[$"{_dictItemApiField}.{_dictKey2}"]); + Assert.Equal(_dictValue3, parameters[$"{_dictItemApiField}.{_dictKey3}"]); } /// @@ -56,25 +78,25 @@ private class StubQuery /// /// Stub property. /// - [ApiField("Item1")] - public string Item1 { get; set; } + [ApiField(_stringItem1ApiField)] + public string StringItem1 { get; set; } /// /// Stub property. /// - [ApiField("Item2")] - public string Item2 { get; set; } + [ApiField(_stringItem2ApiField)] + public string StringItem2 { get; set; } /// /// Stub property. /// - public string Item3 { get; set; } + public string Item { get; set; } } /// /// Stub converter only used for testing purposes. /// - private class StubDecoder : ITypeToStringConverter + private class StubStringConverter : ITypeToStringConverter { /// /// Check . @@ -93,7 +115,38 @@ public bool CanConvert(Type typeToConvert) /// Check public string Convert(object value) { - return "Converted"; + return _converted; + } + } + + /// + /// Stub converter only used for testing purposes. + /// + private class StubDictionaryConverter : ITypeToDictionaryConverter + { + /// + /// Check . + /// + /// Check + /// Check + public bool CanConvert(Type typeToConvert) + { + return true; + } + + /// + /// Check . + /// + /// Check + /// Check + public IDictionary Convert(object value) + { + return new Dictionary + { + { _dictKey1, _dictValue1 }, + { _dictKey2, _dictValue2 }, + { _dictKey3, _dictValue3 } + }; } } @@ -105,8 +158,14 @@ private class StubConverterQuery /// /// Stub property. /// - [ApiField("Item1", Converter = typeof(StubDecoder))] - public string Item1 { get; set; } + [ApiField(_stringItem1ApiField, Converter = typeof(StubStringConverter))] + public string StringItem { get; set; } + + /// + /// Stub property. + /// + [ApiField(_dictItemApiField, Converter = typeof(StubDictionaryConverter))] + public int DictItem { get; set; } } } }