diff --git a/Masa.Contrib.sln b/Masa.Contrib.sln index 2cbb866f5..e6962af9e 100644 --- a/Masa.Contrib.sln +++ b/Masa.Contrib.sln @@ -312,6 +312,12 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Masa.Contrib.Dispatcher.Int EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Masa.Contrib.Identity.IdentityModel.Tests", "test\Masa.Contrib.Identity.IdentityModel.Tests\Masa.Contrib.Identity.IdentityModel.Tests.csproj", "{4E237346-F948-46AC-801B-492545978280}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Masa.Contrib.BasicAbility.Mc", "src\BasicAbility\Masa.Contrib.BasicAbility.Mc\Masa.Contrib.BasicAbility.Mc.csproj", "{75A25CF6-9BA4-46F5-8BC3-90396230CB64}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Masa.BuildingBlocks.BasicAbility.Mc", "src\BuildingBlocks\MASA.BuildingBlocks\src\BasicAbility\Masa.BuildingBlocks.BasicAbility.Mc\Masa.BuildingBlocks.BasicAbility.Mc.csproj", "{DA816A33-F164-4456-92DD-A672BAD1A6B1}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Masa.Contrib.BasicAbility.Mc.Tests", "test\Masa.Contrib.BasicAbility.Mc.Tests\Masa.Contrib.BasicAbility.Mc.Tests.csproj", "{23633E49-F11A-4D14-899A-E2599C8182CE}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -1296,6 +1302,30 @@ Global {4E237346-F948-46AC-801B-492545978280}.Release|Any CPU.Build.0 = Release|Any CPU {4E237346-F948-46AC-801B-492545978280}.Release|x64.ActiveCfg = Release|Any CPU {4E237346-F948-46AC-801B-492545978280}.Release|x64.Build.0 = Release|Any CPU + {75A25CF6-9BA4-46F5-8BC3-90396230CB64}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {75A25CF6-9BA4-46F5-8BC3-90396230CB64}.Debug|Any CPU.Build.0 = Debug|Any CPU + {75A25CF6-9BA4-46F5-8BC3-90396230CB64}.Debug|x64.ActiveCfg = Debug|Any CPU + {75A25CF6-9BA4-46F5-8BC3-90396230CB64}.Debug|x64.Build.0 = Debug|Any CPU + {75A25CF6-9BA4-46F5-8BC3-90396230CB64}.Release|Any CPU.ActiveCfg = Release|Any CPU + {75A25CF6-9BA4-46F5-8BC3-90396230CB64}.Release|Any CPU.Build.0 = Release|Any CPU + {75A25CF6-9BA4-46F5-8BC3-90396230CB64}.Release|x64.ActiveCfg = Release|Any CPU + {75A25CF6-9BA4-46F5-8BC3-90396230CB64}.Release|x64.Build.0 = Release|Any CPU + {DA816A33-F164-4456-92DD-A672BAD1A6B1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {DA816A33-F164-4456-92DD-A672BAD1A6B1}.Debug|Any CPU.Build.0 = Debug|Any CPU + {DA816A33-F164-4456-92DD-A672BAD1A6B1}.Debug|x64.ActiveCfg = Debug|Any CPU + {DA816A33-F164-4456-92DD-A672BAD1A6B1}.Debug|x64.Build.0 = Debug|Any CPU + {DA816A33-F164-4456-92DD-A672BAD1A6B1}.Release|Any CPU.ActiveCfg = Release|Any CPU + {DA816A33-F164-4456-92DD-A672BAD1A6B1}.Release|Any CPU.Build.0 = Release|Any CPU + {DA816A33-F164-4456-92DD-A672BAD1A6B1}.Release|x64.ActiveCfg = Release|Any CPU + {DA816A33-F164-4456-92DD-A672BAD1A6B1}.Release|x64.Build.0 = Release|Any CPU + {23633E49-F11A-4D14-899A-E2599C8182CE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {23633E49-F11A-4D14-899A-E2599C8182CE}.Debug|Any CPU.Build.0 = Debug|Any CPU + {23633E49-F11A-4D14-899A-E2599C8182CE}.Debug|x64.ActiveCfg = Debug|Any CPU + {23633E49-F11A-4D14-899A-E2599C8182CE}.Debug|x64.Build.0 = Debug|Any CPU + {23633E49-F11A-4D14-899A-E2599C8182CE}.Release|Any CPU.ActiveCfg = Release|Any CPU + {23633E49-F11A-4D14-899A-E2599C8182CE}.Release|Any CPU.Build.0 = Release|Any CPU + {23633E49-F11A-4D14-899A-E2599C8182CE}.Release|x64.ActiveCfg = Release|Any CPU + {23633E49-F11A-4D14-899A-E2599C8182CE}.Release|x64.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -1451,6 +1481,9 @@ Global {7C4B88FA-3681-4C29-BC3F-0FDB111C5681} = {FBD326D3-E59C-433E-A88E-14E179E3093D} {592297DE-DA72-452D-9D88-61EE882FE9A6} = {38E6C400-90C0-493E-9266-C1602E229F1B} {4E237346-F948-46AC-801B-492545978280} = {38E6C400-90C0-493E-9266-C1602E229F1B} + {75A25CF6-9BA4-46F5-8BC3-90396230CB64} = {5DFAF4A2-ECB5-46E4-904D-1EA5F48B2D48} + {DA816A33-F164-4456-92DD-A672BAD1A6B1} = {0D34A7F0-DC77-4789-A136-93089CBD15C3} + {23633E49-F11A-4D14-899A-E2599C8182CE} = {38E6C400-90C0-493E-9266-C1602E229F1B} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {40383055-CC50-4600-AD9A-53C14F620D03} diff --git a/src/BasicAbility/Masa.Contrib.BasicAbility.Mc/Constants.cs b/src/BasicAbility/Masa.Contrib.BasicAbility.Mc/Constants.cs new file mode 100644 index 000000000..150f4581d --- /dev/null +++ b/src/BasicAbility/Masa.Contrib.BasicAbility.Mc/Constants.cs @@ -0,0 +1,10 @@ +// Copyright (c) MASA Stack All rights reserved. +// Licensed under the MIT License. See LICENSE.txt in the project root for license information. + +namespace Masa.Contrib.BasicAbility.Mc; + +internal class Constants +{ + public const string DEFAULT_CLIENT_NAME = "masa.contrib.basicability.mc"; +} + diff --git a/src/BasicAbility/Masa.Contrib.BasicAbility.Mc/Infrastructure/Extensions/DictionaryExtensions.cs b/src/BasicAbility/Masa.Contrib.BasicAbility.Mc/Infrastructure/Extensions/DictionaryExtensions.cs new file mode 100644 index 000000000..07faf46c8 --- /dev/null +++ b/src/BasicAbility/Masa.Contrib.BasicAbility.Mc/Infrastructure/Extensions/DictionaryExtensions.cs @@ -0,0 +1,118 @@ +// Copyright (c) MASA Stack All rights reserved. +// Licensed under the MIT License. See LICENSE.txt in the project root for license information. + +namespace System.Collections.Concurrent; + +/// +/// Extension methods for Dictionary. +/// +public static class DictionaryExtensions +{ + /// + /// This method is used to try to get a value in a dictionary if it does exists. + /// + /// Type of the value + /// The collection object + /// Key + /// Value of the key (or default value if key not exists) + /// True if key does exists in the dictionary + internal static bool TryGetValue(this IDictionary dictionary, string key, out T value) + { + object valueObj; + if (dictionary.TryGetValue(key, out valueObj) && valueObj is T) + { + value = (T)valueObj; + return true; + } + + value = default; + return false; + } + + /// + /// Gets a value from the dictionary with given key. Returns default value if can not find. + /// + /// Dictionary to check and get + /// Key to find the value + /// Type of the key + /// Type of the value + /// Value if found, default if can not found. + public static TValue? GetOrDefault(this IDictionary dictionary, TKey key) + { + return dictionary.TryGetValue(key, out var obj) ? obj : default; + } + + /// + /// Gets a value from the dictionary with given key. Returns default value if can not find. + /// + /// Dictionary to check and get + /// Key to find the value + /// Type of the key + /// Type of the value + /// Value if found, default if can not found. + public static TValue? GetOrDefault(this IReadOnlyDictionary dictionary, TKey key) + { + return dictionary.TryGetValue(key, out var obj) ? obj : default; + } + + /// + /// Gets a value from the dictionary with given key. Returns default value if can not find. + /// + /// Dictionary to check and get + /// Key to find the value + /// Type of the key + /// Type of the value + /// Value if found, default if can not found. + public static TValue? GetOrDefault(this ConcurrentDictionary dictionary, TKey key) + { + return dictionary.TryGetValue(key, out var obj) ? obj : default; + } + + /// + /// Gets a value from the dictionary with given key. Returns default value if can not find. + /// + /// Dictionary to check and get + /// Key to find the value + /// A factory method used to create the value if not found in the dictionary + /// Type of the key + /// Type of the value + /// Value if found, default if can not found. + public static TValue GetOrAdd(this IDictionary dictionary, [NotNull] TKey key, Func factory) + { + TValue obj; + if (dictionary.TryGetValue(key, out obj)) + { + return obj; + } + + return dictionary[key] = factory(key); + } + + /// + /// Gets a value from the dictionary with given key. Returns default value if can not find. + /// + /// Dictionary to check and get + /// Key to find the value + /// A factory method used to create the value if not found in the dictionary + /// Type of the key + /// Type of the value + /// Value if found, default if can not found. + public static TValue GetOrAdd(this IDictionary dictionary, [NotNull] TKey key, Func factory) + { + return dictionary.GetOrAdd(key, k => factory()); + } + + /// + /// Gets a value from the concurrent dictionary with given key. Returns default value if can not find. + /// + /// Concurrent dictionary to check and get + /// Key to find the value + /// A factory method used to create the value if not found in the dictionary + /// Type of the key + /// Type of the value + /// Value if found, default if can not found. + public static TValue GetOrAdd(this ConcurrentDictionary dictionary, [NotNull] TKey key, Func factory) + { + return dictionary.GetOrAdd(key, k => factory()); + } +} diff --git a/src/BasicAbility/Masa.Contrib.BasicAbility.Mc/Infrastructure/Extensions/ExtraPropertiesExtensions.cs b/src/BasicAbility/Masa.Contrib.BasicAbility.Mc/Infrastructure/Extensions/ExtraPropertiesExtensions.cs new file mode 100644 index 000000000..85bade60a --- /dev/null +++ b/src/BasicAbility/Masa.Contrib.BasicAbility.Mc/Infrastructure/Extensions/ExtraPropertiesExtensions.cs @@ -0,0 +1,61 @@ +// Copyright (c) MASA Stack All rights reserved. +// Licensed under the MIT License. See LICENSE.txt in the project root for license information. + +namespace System.Collections.Concurrent; + +public static class ExtraPropertiesExtensions +{ + public static bool HasProperty(this ExtraPropertyDictionary source, string name) + { + return source.ContainsKey(name); + } + + public static object GetProperty(this ExtraPropertyDictionary source, string name, object defaultValue = null) + { + return source.GetOrDefault(name) + ?? defaultValue; + } + + public static TProperty GetProperty(this ExtraPropertyDictionary source, string name, TProperty defaultValue = default) + { + var value = source.GetProperty(name); + if (value == null) + { + return defaultValue; + } + + if (TypeHelper.IsPrimitiveExtended(typeof(TProperty), includeEnums: true)) + { + var conversionType = typeof(TProperty); + if (TypeHelper.IsNullable(conversionType)) + { + conversionType = conversionType.GetFirstGenericArgumentIfNullable(); + } + + if (conversionType == typeof(Guid)) + { + return (TProperty)TypeDescriptor.GetConverter(conversionType).ConvertFromInvariantString(value.ToString()); + } + + if (conversionType == typeof(DateTimeOffset)) + { + return (TProperty)TypeDescriptor.GetConverter(conversionType).ConvertFromInvariantString(value.ToString()); + } + + return (TProperty)Convert.ChangeType(value?.ToString(), conversionType, CultureInfo.InvariantCulture); + } + + throw new Exception("GetProperty does not support non-primitive types. Use non-generic GetProperty method and handle type casting manually."); + } + + public static TSource SetProperty( + this TSource source, + string name, + object value) + where TSource : ExtraPropertyDictionary + { + source[name] = value; + + return source; + } +} diff --git a/src/BasicAbility/Masa.Contrib.BasicAbility.Mc/Infrastructure/Helper/TypeHelper.cs b/src/BasicAbility/Masa.Contrib.BasicAbility.Mc/Infrastructure/Helper/TypeHelper.cs new file mode 100644 index 000000000..e75189fea --- /dev/null +++ b/src/BasicAbility/Masa.Contrib.BasicAbility.Mc/Infrastructure/Helper/TypeHelper.cs @@ -0,0 +1,170 @@ +// Copyright (c) MASA Stack All rights reserved. +// Licensed under the MIT License. See LICENSE.txt in the project root for license information. + +namespace Masa.Contrib.BasicAbility.Mc.Infrastructure.Helper; + +public static class TypeHelper +{ + private static readonly HashSet FloatingTypes = new HashSet + { + typeof(float), + typeof(double), + typeof(decimal) + }; + + private static readonly HashSet NonNullablePrimitiveTypes = new HashSet + { + typeof(byte), + typeof(short), + typeof(int), + typeof(long), + typeof(sbyte), + typeof(ushort), + typeof(uint), + typeof(ulong), + typeof(bool), + typeof(float), + typeof(decimal), + typeof(DateTime), + typeof(DateTimeOffset), + typeof(TimeSpan), + typeof(Guid) + }; + + public static bool IsNonNullablePrimitiveType(Type type) + { + return NonNullablePrimitiveTypes.Contains(type); + } + + public static bool IsFunc(object obj) + { + if (obj == null) + { + return false; + } + + var type = obj.GetType(); + if (!type.GetTypeInfo().IsGenericType) + { + return false; + } + + return type.GetGenericTypeDefinition() == typeof(Func<>); + } + + public static bool IsFunc(object obj) + { + return obj != null && obj.GetType() == typeof(Func); + } + + public static bool IsPrimitiveExtended(Type type, bool includeNullables = true, bool includeEnums = false) + { + if (IsPrimitiveExtendedInternal(type, includeEnums)) + { + return true; + } + + if (includeNullables && IsNullable(type) && type.GenericTypeArguments.Any()) + { + return IsPrimitiveExtendedInternal(type.GenericTypeArguments[0], includeEnums); + } + + return false; + } + + public static bool IsNullable(Type type) + { + return type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>); + } + + public static Type GetFirstGenericArgumentIfNullable(this Type t) + { + if (t.GetGenericArguments().Length > 0 && t.GetGenericTypeDefinition() == typeof(Nullable<>)) + { + return t.GetGenericArguments().FirstOrDefault(); + } + + return t; + } + + private static bool IsPrimitiveExtendedInternal(Type type, bool includeEnums) + { + if (type.IsPrimitive) + { + return true; + } + + if (includeEnums && type.IsEnum) + { + return true; + } + + return type == typeof(string) || + type == typeof(decimal) || + type == typeof(DateTimeOffset) || + type == typeof(DateTimeOffset) || + type == typeof(TimeSpan) || + type == typeof(Guid); + } + + public static T? GetDefaultValue() + { + return default; + } + + public static object? GetDefaultValue(Type type) + { + if (type.IsValueType) + { + return Activator.CreateInstance(type); + } + + return null; + } + + public static bool IsFloatingType(Type type, bool includeNullable = true) + { + if (FloatingTypes.Contains(type)) + { + return true; + } + + if (includeNullable && + IsNullable(type) && + FloatingTypes.Contains(type.GenericTypeArguments[0])) + { + return true; + } + + return false; + } + + public static object ConvertFrom(object value) + { + return ConvertFrom(typeof(TTargetType), value); + } + + public static object ConvertFrom(Type targetType, object value) + { + return TypeDescriptor + .GetConverter(targetType) + .ConvertFrom(value); + } + + public static Type StripNullable(Type type) + { + return IsNullable(type) + ? type.GenericTypeArguments[0] + : type; + } + + public static bool IsDefaultValue(object obj) + { + if (obj == null) + { + return true; + } + + return obj.Equals(GetDefaultValue(obj.GetType())); + } +} diff --git a/src/BasicAbility/Masa.Contrib.BasicAbility.Mc/Masa.Contrib.BasicAbility.Mc.csproj b/src/BasicAbility/Masa.Contrib.BasicAbility.Mc/Masa.Contrib.BasicAbility.Mc.csproj new file mode 100644 index 000000000..dc5193a50 --- /dev/null +++ b/src/BasicAbility/Masa.Contrib.BasicAbility.Mc/Masa.Contrib.BasicAbility.Mc.csproj @@ -0,0 +1,17 @@ + + + + net6.0 + enable + enable + + + + + + + + + + + diff --git a/src/BasicAbility/Masa.Contrib.BasicAbility.Mc/McClient.cs b/src/BasicAbility/Masa.Contrib.BasicAbility.Mc/McClient.cs new file mode 100644 index 000000000..60f2c4a9e --- /dev/null +++ b/src/BasicAbility/Masa.Contrib.BasicAbility.Mc/McClient.cs @@ -0,0 +1,26 @@ +// Copyright (c) MASA Stack All rights reserved. +// Licensed under the MIT License. See LICENSE.txt in the project root for license information. + +namespace Masa.Contrib.BasicAbility.Mc; + +public class McClient: IMcClient +{ + public McClient(ICallerProvider callerProvider) + { + ChannelService = new ChannelService(callerProvider); + MessageTaskService = new MessageTaskService(callerProvider); + MessageTemplateService = new MessageTemplateService(callerProvider); + ReceiverGroupService = new ReceiverGroupService(callerProvider); + WebsiteMessageService = new WebsiteMessageService(callerProvider); + } + + public IChannelService ChannelService { get; } + + public IMessageTaskService MessageTaskService { get; } + + public IMessageTemplateService MessageTemplateService { get; } + + public IReceiverGroupService ReceiverGroupService { get; } + + public IWebsiteMessageService WebsiteMessageService { get; } +} diff --git a/src/BasicAbility/Masa.Contrib.BasicAbility.Mc/Service/ChannelService.cs b/src/BasicAbility/Masa.Contrib.BasicAbility.Mc/Service/ChannelService.cs new file mode 100644 index 000000000..4698a5e7e --- /dev/null +++ b/src/BasicAbility/Masa.Contrib.BasicAbility.Mc/Service/ChannelService.cs @@ -0,0 +1,27 @@ +// Copyright (c) MASA Stack All rights reserved. +// Licensed under the MIT License. See LICENSE.txt in the project root for license information. + +namespace Masa.Contrib.BasicAbility.Mc.Service; + +public class ChannelService : IChannelService +{ + readonly ICallerProvider _callerProvider; + readonly string _party = "api/channel"; + + public ChannelService(ICallerProvider callerProvider) + { + _callerProvider = callerProvider; + } + + public async Task GetAsync(Guid id) + { + var requestUri = $"{_party}/{id}"; + return await _callerProvider.GetAsync(requestUri); + } + + public async Task> GetListAsync(GetChannelModel options) + { + var requestUri = $"{_party}"; + return await _callerProvider.GetAsync>(requestUri, options) ?? new(); + } +} diff --git a/src/BasicAbility/Masa.Contrib.BasicAbility.Mc/Service/MessageTaskService.cs b/src/BasicAbility/Masa.Contrib.BasicAbility.Mc/Service/MessageTaskService.cs new file mode 100644 index 000000000..8afe18b0c --- /dev/null +++ b/src/BasicAbility/Masa.Contrib.BasicAbility.Mc/Service/MessageTaskService.cs @@ -0,0 +1,33 @@ +// Copyright (c) MASA Stack All rights reserved. +// Licensed under the MIT License. See LICENSE.txt in the project root for license information. + +namespace Masa.Contrib.BasicAbility.Mc.Service; + +public class MessageTaskService : IMessageTaskService +{ + readonly ICallerProvider _callerProvider; + readonly string _party = "api/message-task"; + + public MessageTaskService(ICallerProvider callerProvider) + { + _callerProvider = callerProvider; + } + + public async Task GetAsync(Guid id) + { + var requestUri = $"{_party}/{id}"; + return await _callerProvider.GetAsync(requestUri); + } + + public async Task SendOrdinaryMessageAsync(SendOrdinaryMessageModel options) + { + var requestUri = $"{_party}"; + await _callerProvider.PostAsync(requestUri, (MessageTaskUpsertModel)options); + } + + public async Task SendTemplateMessageAsync(SendTemplateMessageModel options) + { + var requestUri = $"{_party}"; + await _callerProvider.PostAsync(requestUri, (MessageTaskUpsertModel)options); + } +} diff --git a/src/BasicAbility/Masa.Contrib.BasicAbility.Mc/Service/MessageTemplateService.cs b/src/BasicAbility/Masa.Contrib.BasicAbility.Mc/Service/MessageTemplateService.cs new file mode 100644 index 000000000..5a110ce81 --- /dev/null +++ b/src/BasicAbility/Masa.Contrib.BasicAbility.Mc/Service/MessageTemplateService.cs @@ -0,0 +1,27 @@ +// Copyright (c) MASA Stack All rights reserved. +// Licensed under the MIT License. See LICENSE.txt in the project root for license information. + +namespace Masa.Contrib.BasicAbility.Mc.Service; + +public class MessageTemplateService : IMessageTemplateService +{ + readonly ICallerProvider _callerProvider; + readonly string _party = "api/message-template"; + + public MessageTemplateService(ICallerProvider callerProvider) + { + _callerProvider = callerProvider; + } + + public async Task GetAsync(Guid id) + { + var requestUri = $"{_party}/{id}"; + return await _callerProvider.GetAsync(requestUri); + } + + public async Task> GetListAsync(GetMessageTemplateModel options) + { + var requestUri = $"{_party}"; + return await _callerProvider.GetAsync>(requestUri, options) ?? new(); + } +} diff --git a/src/BasicAbility/Masa.Contrib.BasicAbility.Mc/Service/ReceiverGroupService.cs b/src/BasicAbility/Masa.Contrib.BasicAbility.Mc/Service/ReceiverGroupService.cs new file mode 100644 index 000000000..a6b6606ab --- /dev/null +++ b/src/BasicAbility/Masa.Contrib.BasicAbility.Mc/Service/ReceiverGroupService.cs @@ -0,0 +1,27 @@ +// Copyright (c) MASA Stack All rights reserved. +// Licensed under the MIT License. See LICENSE.txt in the project root for license information. + +namespace Masa.Contrib.BasicAbility.Mc.Service; + +public class ReceiverGroupService : IReceiverGroupService +{ + readonly ICallerProvider _callerProvider; + readonly string _party = "api/receiver-group"; + + public ReceiverGroupService(ICallerProvider callerProvider) + { + _callerProvider = callerProvider; + } + + public async Task GetAsync(Guid id) + { + var requestUri = $"{_party}/{id}"; + return await _callerProvider.GetAsync(requestUri); + } + + public async Task> GetListAsync(GetReceiverGroupModel options) + { + var requestUri = $"{_party}"; + return await _callerProvider.GetAsync>(requestUri, options) ?? new(); + } +} diff --git a/src/BasicAbility/Masa.Contrib.BasicAbility.Mc/Service/WebsiteMessageService.cs b/src/BasicAbility/Masa.Contrib.BasicAbility.Mc/Service/WebsiteMessageService.cs new file mode 100644 index 000000000..261c82556 --- /dev/null +++ b/src/BasicAbility/Masa.Contrib.BasicAbility.Mc/Service/WebsiteMessageService.cs @@ -0,0 +1,60 @@ +namespace Masa.Contrib.BasicAbility.Mc.Service; + +public class WebsiteMessageService : IWebsiteMessageService +{ + readonly ICallerProvider _callerProvider; + readonly string _party = "api/website-message"; + + public WebsiteMessageService(ICallerProvider callerProvider) + { + _callerProvider = callerProvider; + } + + public async Task CheckAsync() + { + var requestUri = $"{_party}/Check"; + await _callerProvider.PostAsync(requestUri, null); + } + + public async Task DeleteAsync(Guid id) + { + var requestUri = $"{_party}/{id}"; + await _callerProvider.DeleteAsync(requestUri, null); + } + + public async Task GetAsync(Guid id) + { + var requestUri = $"{_party}/{id}"; + return await _callerProvider.GetAsync(requestUri); + } + + public async Task> GetChannelListAsync() + { + var requestUri = $"{_party}/GetChannelList"; + return await _callerProvider.GetAsync>(requestUri)??new(); + } + + public async Task> GetListAsync(GetWebsiteMessageModel options) + { + var requestUri = $"{_party}"; + return await _callerProvider.GetAsync>(requestUri, options) ?? new(); + } + + public async Task> GetNoticeListAsync(GetNoticeListModel options) + { + var requestUri = $"{_party}/GetNoticeList"; + return await _callerProvider.GetAsync>(requestUri, options) ?? new(); + } + + public async Task ReadAsync(ReadWebsiteMessageModel options) + { + var requestUri = $"{_party}/Read"; + await _callerProvider.PostAsync(requestUri, options); + } + + public async Task SetAllReadAsync(ReadAllWebsiteMessageModel options) + { + var requestUri = $"{_party}/SetAllRead"; + await _callerProvider.PostAsync(requestUri, options); + } +} diff --git a/src/BasicAbility/Masa.Contrib.BasicAbility.Mc/ServiceCollectionExtensions.cs b/src/BasicAbility/Masa.Contrib.BasicAbility.Mc/ServiceCollectionExtensions.cs new file mode 100644 index 000000000..5d3866f56 --- /dev/null +++ b/src/BasicAbility/Masa.Contrib.BasicAbility.Mc/ServiceCollectionExtensions.cs @@ -0,0 +1,43 @@ +// Copyright (c) MASA Stack All rights reserved. +// Licensed under the MIT License. See LICENSE.txt in the project root for license information. + +namespace Microsoft.Extensions.DependencyInjection; + +public static class ServiceCollectionExtensions +{ + public static IServiceCollection AddMcClient(this IServiceCollection services, string mcServiceBaseAddress) + { + if (string.IsNullOrWhiteSpace(mcServiceBaseAddress)) + { + throw new ArgumentNullException(nameof(mcServiceBaseAddress)); + } + + return services.AddMcClient(callerOptions => + { + callerOptions.UseHttpClient(builder => + { + builder.Name = DEFAULT_CLIENT_NAME; + builder.Configure = opt => opt.BaseAddress = new Uri(mcServiceBaseAddress); + }); + }); + } + + public static IServiceCollection AddMcClient(this IServiceCollection services, Action callerOptions) + { + ArgumentNullException.ThrowIfNull(callerOptions, nameof(callerOptions)); + + if (services.Any(service => service.ServiceType == typeof(IMcClient))) + return services; + + services.AddCaller(callerOptions.Invoke); + + services.AddSingleton(serviceProvider => + { + var callProvider = serviceProvider.GetRequiredService().CreateClient(DEFAULT_CLIENT_NAME); + var mcCaching = new McClient(callProvider); + return mcCaching; + }); + + return services; + } +} diff --git a/src/BasicAbility/Masa.Contrib.BasicAbility.Mc/_Imports.cs b/src/BasicAbility/Masa.Contrib.BasicAbility.Mc/_Imports.cs new file mode 100644 index 000000000..8f0f9087a --- /dev/null +++ b/src/BasicAbility/Masa.Contrib.BasicAbility.Mc/_Imports.cs @@ -0,0 +1,16 @@ +// Copyright (c) MASA Stack All rights reserved. +// Licensed under the MIT License. See LICENSE.txt in the project root for license information. + +global using Masa.BuildingBlocks.BasicAbility.Mc; +global using Masa.BuildingBlocks.BasicAbility.Mc.Service; +global using Masa.BuildingBlocks.BasicAbility.Mc.Model; +global using Masa.Contrib.BasicAbility.Mc; +global using static Masa.Contrib.BasicAbility.Mc.Constants; +global using Masa.Contrib.BasicAbility.Mc.Infrastructure.Helper; +global using Masa.Contrib.BasicAbility.Mc.Service; +global using Masa.Utils.Caller.Core; +global using Masa.Utils.Caller.HttpClient; +global using System.ComponentModel; +global using System.Diagnostics.CodeAnalysis; +global using System.Globalization; +global using System.Reflection; diff --git a/src/BuildingBlocks/MASA.BuildingBlocks b/src/BuildingBlocks/MASA.BuildingBlocks index c23cac480..da00ccea9 160000 --- a/src/BuildingBlocks/MASA.BuildingBlocks +++ b/src/BuildingBlocks/MASA.BuildingBlocks @@ -1 +1 @@ -Subproject commit c23cac480f83f5f9cc4970e38e782ff8270fe8e2 +Subproject commit da00ccea99a5f3efb0b4d8750ccbb59ab44fa2ef diff --git a/test/Masa.Contrib.BasicAbility.Mc.Tests/ChannelServiceTest.cs b/test/Masa.Contrib.BasicAbility.Mc.Tests/ChannelServiceTest.cs new file mode 100644 index 000000000..4fd23e9ba --- /dev/null +++ b/test/Masa.Contrib.BasicAbility.Mc.Tests/ChannelServiceTest.cs @@ -0,0 +1,36 @@ +// Copyright (c) MASA Stack All rights reserved. +// Licensed under the MIT License. See LICENSE.txt in the project root for license information. + +namespace Masa.Contrib.BasicAbility.Mc.Tests; + +[TestClass] +public class ChannelServiceTest +{ + [TestMethod] + public async Task TestGetAsync() + { + var data = new ChannelModel(); + Guid channelId = Guid.NewGuid(); + var requestUri = $"api/channel/{channelId}"; + var callerProvider = new Mock(); + callerProvider.Setup(provider => provider.GetAsync(requestUri, default)).ReturnsAsync(data).Verifiable(); + var channelService = new Mock(callerProvider.Object); + var result = await channelService.Object.GetAsync(channelId); + callerProvider.Verify(provider => provider.GetAsync(requestUri, default), Times.Once); + Assert.IsTrue(result is not null); + } + + [TestMethod] + public async Task TestGetListAsync() + { + var options = new GetChannelModel(); + var data = new PaginatedListModel(); + var requestUri = $"api/channel"; + var callerProvider = new Mock(); + callerProvider.Setup(provider => provider.GetAsync>(requestUri, options, default)).ReturnsAsync(data).Verifiable(); + var channelService = new Mock(callerProvider.Object); + var result = await channelService.Object.GetListAsync(options); + callerProvider.Verify(provider => provider.GetAsync>(requestUri, options, default), Times.Once); + Assert.IsTrue(result is not null); + } +} diff --git a/test/Masa.Contrib.BasicAbility.Mc.Tests/Masa.Contrib.BasicAbility.Mc.Tests.csproj b/test/Masa.Contrib.BasicAbility.Mc.Tests/Masa.Contrib.BasicAbility.Mc.Tests.csproj new file mode 100644 index 000000000..226f1c111 --- /dev/null +++ b/test/Masa.Contrib.BasicAbility.Mc.Tests/Masa.Contrib.BasicAbility.Mc.Tests.csproj @@ -0,0 +1,23 @@ + + + + net6.0 + enable + + false + + + + + + + + + + + + + + + + diff --git a/test/Masa.Contrib.BasicAbility.Mc.Tests/McClientTest.cs b/test/Masa.Contrib.BasicAbility.Mc.Tests/McClientTest.cs new file mode 100644 index 000000000..6ab73c254 --- /dev/null +++ b/test/Masa.Contrib.BasicAbility.Mc.Tests/McClientTest.cs @@ -0,0 +1,32 @@ +// Copyright (c) MASA Stack All rights reserved. +// Licensed under the MIT License. See LICENSE.txt in the project root for license information. + +namespace Masa.Contrib.BasicAbility.Mc.Tests; + +[TestClass] +public class McClientTest +{ + [TestMethod] + public void TestAddMcClient() + { + var services = new ServiceCollection(); + services.AddMcClient("https://localhost:18102"); + var mcClient = services.BuildServiceProvider().GetRequiredService(); + + Assert.IsNotNull(mcClient); + } + + [TestMethod] + public void TestAddMcClientShouldThrowArgumentNullException() + { + var services = new ServiceCollection(); + Assert.ThrowsException(() => services.AddMcClient(mcServiceBaseAddress: null!)); + } + + [TestMethod] + public void TestAddMcClientShouldThrowArgumentNullException2() + { + var services = new ServiceCollection(); + Assert.ThrowsException(() => services.AddMcClient(callerOptions: null!)); + } +} diff --git a/test/Masa.Contrib.BasicAbility.Mc.Tests/MessageTaskServiceTest.cs b/test/Masa.Contrib.BasicAbility.Mc.Tests/MessageTaskServiceTest.cs new file mode 100644 index 000000000..a018bfc5d --- /dev/null +++ b/test/Masa.Contrib.BasicAbility.Mc.Tests/MessageTaskServiceTest.cs @@ -0,0 +1,46 @@ +// Copyright (c) MASA Stack All rights reserved. +// Licensed under the MIT License. See LICENSE.txt in the project root for license information. + +namespace Masa.Contrib.BasicAbility.Mc.Tests; + +[TestClass] +public class MessageTaskServiceTest +{ + [TestMethod] + public async Task TestGetAsync() + { + var data = new MessageTaskModel(); + Guid id = Guid.NewGuid(); + var requestUri = $"api/message-task/{id}"; + var callerProvider = new Mock(); + callerProvider.Setup(provider => provider.GetAsync(requestUri, default)).ReturnsAsync(data).Verifiable(); + var messageTaskService = new Mock(callerProvider.Object); + var result = await messageTaskService.Object.GetAsync(id); + callerProvider.Verify(provider => provider.GetAsync(requestUri, default), Times.Once); + Assert.IsTrue(result is not null); + } + + [TestMethod] + public async Task TestSendOrdinaryMessageAsync() + { + var options = new SendOrdinaryMessageModel(); + var requestUri = $"api/message-task"; + var callerProvider = new Mock(); + callerProvider.Setup(provider => provider.PostAsync(requestUri, It.IsAny(), true, default)).Verifiable(); + var messageTaskService = new Mock(callerProvider.Object); + await messageTaskService.Object.SendOrdinaryMessageAsync(options); + callerProvider.Verify(provider => provider.PostAsync(requestUri, It.IsAny(), true, default), Times.Once); + } + + [TestMethod] + public async Task TestSendTemplateMessageAsync() + { + var options = new SendTemplateMessageModel(); + var requestUri = $"api/message-task"; + var callerProvider = new Mock(); + callerProvider.Setup(provider => provider.PostAsync(requestUri, It.IsAny(), true, default)).Verifiable(); + var messageTaskService = new Mock(callerProvider.Object); + await messageTaskService.Object.SendTemplateMessageAsync(options); + callerProvider.Verify(provider => provider.PostAsync(requestUri, It.IsAny(), true, default), Times.Once); + } +} diff --git a/test/Masa.Contrib.BasicAbility.Mc.Tests/MessageTemplateServiceTest.cs b/test/Masa.Contrib.BasicAbility.Mc.Tests/MessageTemplateServiceTest.cs new file mode 100644 index 000000000..85aee36d3 --- /dev/null +++ b/test/Masa.Contrib.BasicAbility.Mc.Tests/MessageTemplateServiceTest.cs @@ -0,0 +1,36 @@ +// Copyright (c) MASA Stack All rights reserved. +// Licensed under the MIT License. See LICENSE.txt in the project root for license information. + +namespace Masa.Contrib.BasicAbility.Mc.Tests; + +[TestClass] +public class MessageTemplateServiceTest +{ + [TestMethod] + public async Task TestGetAsync() + { + var data = new MessageTemplateModel(); + Guid id = Guid.NewGuid(); + var requestUri = $"api/message-template/{id}"; + var callerProvider = new Mock(); + callerProvider.Setup(provider => provider.GetAsync(requestUri, default)).ReturnsAsync(data).Verifiable(); + var messageTemplateService = new Mock(callerProvider.Object); + var result = await messageTemplateService.Object.GetAsync(id); + callerProvider.Verify(provider => provider.GetAsync(requestUri, default), Times.Once); + Assert.IsTrue(result is not null); + } + + [TestMethod] + public async Task TestGetListAsync() + { + var options = new GetMessageTemplateModel(); + var data = new PaginatedListModel(); + var requestUri = $"api/message-template"; + var callerProvider = new Mock(); + callerProvider.Setup(provider => provider.GetAsync>(requestUri, options, default)).ReturnsAsync(data).Verifiable(); + var messageTemplateService = new Mock(callerProvider.Object); + var result = await messageTemplateService.Object.GetListAsync(options); + callerProvider.Verify(provider => provider.GetAsync>(requestUri, options, default), Times.Once); + Assert.IsTrue(result is not null); + } +} diff --git a/test/Masa.Contrib.BasicAbility.Mc.Tests/ReceiverGroupServiceTest.cs b/test/Masa.Contrib.BasicAbility.Mc.Tests/ReceiverGroupServiceTest.cs new file mode 100644 index 000000000..50be6cad0 --- /dev/null +++ b/test/Masa.Contrib.BasicAbility.Mc.Tests/ReceiverGroupServiceTest.cs @@ -0,0 +1,36 @@ +// Copyright (c) MASA Stack All rights reserved. +// Licensed under the MIT License. See LICENSE.txt in the project root for license information. + +namespace Masa.Contrib.BasicAbility.Mc.Tests; + +[TestClass] +public class ReceiverGroupServiceTest +{ + [TestMethod] + public async Task TestGetAsync() + { + var data = new ReceiverGroupModel(); + Guid id = Guid.NewGuid(); + var requestUri = $"api/receiver-group/{id}"; + var callerProvider = new Mock(); + callerProvider.Setup(provider => provider.GetAsync(requestUri, default)).ReturnsAsync(data).Verifiable(); + var receiverGroupService = new Mock(callerProvider.Object); + var result = await receiverGroupService.Object.GetAsync(id); + callerProvider.Verify(provider => provider.GetAsync(requestUri, default), Times.Once); + Assert.IsTrue(result is not null); + } + + [TestMethod] + public async Task TestGetListAsync() + { + var options = new GetReceiverGroupModel(); + var data = new PaginatedListModel(); + var requestUri = $"api/receiver-group"; + var callerProvider = new Mock(); + callerProvider.Setup(provider => provider.GetAsync>(requestUri, options, default)).ReturnsAsync(data).Verifiable(); + var receiverGroupService = new Mock(callerProvider.Object); + var result = await receiverGroupService.Object.GetListAsync(options); + callerProvider.Verify(provider => provider.GetAsync>(requestUri, options, default), Times.Once); + Assert.IsTrue(result is not null); + } +} diff --git a/test/Masa.Contrib.BasicAbility.Mc.Tests/WebsiteMessageServiceTest.cs b/test/Masa.Contrib.BasicAbility.Mc.Tests/WebsiteMessageServiceTest.cs new file mode 100644 index 000000000..8a2a7035e --- /dev/null +++ b/test/Masa.Contrib.BasicAbility.Mc.Tests/WebsiteMessageServiceTest.cs @@ -0,0 +1,110 @@ +// Copyright (c) MASA Stack All rights reserved. +// Licensed under the MIT License. See LICENSE.txt in the project root for license information. + +namespace Masa.Contrib.BasicAbility.Mc.Tests; + +[TestClass] +public class WebsiteMessageServiceTest +{ + [TestMethod] + public async Task TestGetAsync() + { + var data = new WebsiteMessageModel(); + Guid id = Guid.NewGuid(); + var requestUri = $"api/website-message/{id}"; + var callerProvider = new Mock(); + callerProvider.Setup(provider => provider.GetAsync(requestUri, default)).ReturnsAsync(data).Verifiable(); + var websiteMessageService = new Mock(callerProvider.Object); + var result = await websiteMessageService.Object.GetAsync(id); + callerProvider.Verify(provider => provider.GetAsync(requestUri, default), Times.Once); + Assert.IsTrue(result is not null); + } + + [TestMethod] + public async Task TestGetListAsync() + { + var options = new GetWebsiteMessageModel(); + var data = new PaginatedListModel(); + var requestUri = $"api/website-message"; + var callerProvider = new Mock(); + callerProvider.Setup(provider => provider.GetAsync>(requestUri, options, default)).ReturnsAsync(data).Verifiable(); + var websiteMessageService = new Mock(callerProvider.Object); + var result = await websiteMessageService.Object.GetListAsync(options); + callerProvider.Verify(provider => provider.GetAsync>(requestUri, options, default), Times.Once); + Assert.IsTrue(result is not null); + } + + [TestMethod] + public async Task TestCheckAsync() + { + var requestUri = $"api/website-message/Check"; + var callerProvider = new Mock(); + callerProvider.Setup(provider => provider.PostAsync(requestUri, null, true, default)).Verifiable(); + var websiteMessageService = new Mock(callerProvider.Object); + await websiteMessageService.Object.CheckAsync(); + callerProvider.Verify(provider => provider.PostAsync(requestUri, null, true, default), Times.Once); + } + + [TestMethod] + public async Task TestDeleteAsync() + { + Guid id = Guid.NewGuid(); + var requestUri = $"api/website-message/{id}"; + var callerProvider = new Mock(); + callerProvider.Setup(provider => provider.DeleteAsync(requestUri, null, true, default)).Verifiable(); + var websiteMessageService = new Mock(callerProvider.Object); + await websiteMessageService.Object.DeleteAsync(id); + callerProvider.Verify(provider => provider.DeleteAsync(requestUri, null, true, default), Times.Once); + } + + [TestMethod] + public async Task TestGetChannelListAsync() + { + var data = new List(); + var requestUri = $"api/website-message/GetChannelList"; + var callerProvider = new Mock(); + callerProvider.Setup(provider => provider.GetAsync>(requestUri, default)).ReturnsAsync(data).Verifiable(); + var websiteMessageService = new Mock(callerProvider.Object); + var result = await websiteMessageService.Object.GetChannelListAsync(); + callerProvider.Verify(provider => provider.GetAsync>(requestUri, default), Times.Once); + Assert.IsTrue(result is not null); + } + + [TestMethod] + public async Task TestGetNoticeListAsync() + { + var options = new GetNoticeListModel(); + var data = new List(); + var requestUri = $"api/website-message/GetNoticeList"; + var callerProvider = new Mock(); + callerProvider.Setup(provider => provider.GetAsync>(requestUri, options, default)).ReturnsAsync(data).Verifiable(); + var websiteMessageService = new Mock(callerProvider.Object); + var result = await websiteMessageService.Object.GetNoticeListAsync(options); + callerProvider.Verify(provider => provider.GetAsync>(requestUri, options, default), Times.Once); + Assert.IsTrue(result is not null); + } + + [TestMethod] + public async Task TestReadAsync() + { + var options = new ReadWebsiteMessageModel(); + var requestUri = $"api/website-message/Read"; + var callerProvider = new Mock(); + callerProvider.Setup(provider => provider.PostAsync(requestUri, options, true, default)).Verifiable(); + var websiteMessageService = new Mock(callerProvider.Object); + await websiteMessageService.Object.ReadAsync(options); + callerProvider.Verify(provider => provider.PostAsync(requestUri, options, true, default), Times.Once); + } + + [TestMethod] + public async Task TestSetAllReadAsync() + { + var options = new ReadAllWebsiteMessageModel(); + var requestUri = $"api/website-message/SetAllRead"; + var callerProvider = new Mock(); + callerProvider.Setup(provider => provider.PostAsync(requestUri, options, true, default)).Verifiable(); + var websiteMessageService = new Mock(callerProvider.Object); + await websiteMessageService.Object.SetAllReadAsync(options); + callerProvider.Verify(provider => provider.PostAsync(requestUri, options, true, default), Times.Once); + } +} diff --git a/test/Masa.Contrib.BasicAbility.Mc.Tests/_Imports.cs b/test/Masa.Contrib.BasicAbility.Mc.Tests/_Imports.cs new file mode 100644 index 000000000..7a153ef0b --- /dev/null +++ b/test/Masa.Contrib.BasicAbility.Mc.Tests/_Imports.cs @@ -0,0 +1,14 @@ +// Copyright (c) MASA Stack All rights reserved. +// Licensed under the MIT License. See LICENSE.txt in the project root for license information. + +global using Microsoft.VisualStudio.TestTools.UnitTesting; +global using System.Threading.Tasks; +global using Masa.BuildingBlocks.BasicAbility.Mc.Model; +global using Masa.Utils.Caller.Core; +global using Moq; +global using System; +global using Masa.Contrib.BasicAbility.Mc.Service; +global using Masa.BuildingBlocks.Ddd.Domain.Repositories; +global using Masa.BuildingBlocks.BasicAbility.Mc; +global using Microsoft.Extensions.DependencyInjection; +global using System.Collections.Generic;