diff --git a/src/TagzApp.Blazor.Client/Components/Admin/Blazot.Config.Ui.razor b/src/TagzApp.Blazor.Client/Components/Admin/Blazot.Config.Ui.razor index 07cf15ed..70cfcc23 100644 --- a/src/TagzApp.Blazor.Client/Components/Admin/Blazot.Config.Ui.razor +++ b/src/TagzApp.Blazor.Client/Components/Admin/Blazot.Config.Ui.razor @@ -1,108 +1,109 @@ @using System.ComponentModel.DataAnnotations @using System.Text.Json -@inject ToastService ToastService - - - - - - -
-
-
- - -
-
-
- - -
-
-
- - -
-
-
- - -
-
Default Headers:
-
- @* Generate a set of textboxes to collect values for the DefaultHeaders dictionary in ViewModel*@ - - -
-
-
- -
-
-
- - -
-
-
- - -
- -
-
- -
-
- - - -
+ + + + +
+
+
+ + +
+
+
+ + +
+
+
+ + +
+
+
+ + +
+
Default Headers:
+
+ @* Generate a set of textboxes to collect values for the DefaultHeaders dictionary in ViewModel*@ + + +
+
+
+ +
+
+
+ + +
+
+
+ + +
+
+
+ +
+
+ + +
@code { - - [Parameter, EditorRequired] - public ISocialMediaProvider Provider { get; set; } = null!; - - public (SocialMediaStatus Status, string Message) Health { get; set; } = (SocialMediaStatus.Unknown, string.Empty); - - - public ViewModel Model { get; set; } = new(); + [Inject] private ToastService ToastService { get; set; } = null!; + [Parameter, EditorRequired] public ISocialMediaProvider Provider { get; set; } = null!; + private (SocialMediaStatus Status, string Message) _Health = (SocialMediaStatus.Unknown, string.Empty); + private ViewModel _Model = new(); protected override async Task OnParametersSetAsync() { var providerConfiguration = await Provider.GetConfiguration(ConfigureTagzAppFactory.Current); - var headers = providerConfiguration.GetConfigurationByKey("DefaultHeaders"); - var headerDictionary = string.IsNullOrEmpty(headers) ? new() : JsonSerializer.Deserialize>(headers); + var headerDictionary = JsonSerializer.Deserialize>(headers) ?? new Dictionary(); + int.TryParse(providerConfiguration.GetConfigurationByKey(nameof(_Model.WindowRequests)), out var windowRequests); + int.TryParse(providerConfiguration.GetConfigurationByKey(nameof(_Model.WindowSeconds)), out var windowSeconds); - Model = new ViewModel + _Model = new ViewModel { - BaseAddress = providerConfiguration.GetConfigurationByKey("BaseAddress"), + ApiKey = providerConfiguration.GetConfigurationByKey(nameof(_Model.ApiKey)), + SecretAuthKey = providerConfiguration.GetConfigurationByKey(nameof(_Model.SecretAuthKey)), + WindowRequests = windowRequests, + WindowSeconds = windowSeconds, + BaseAddress = providerConfiguration.GetConfigurationByKey(nameof(_Model.BaseAddress)), DefaultHeaders = headerDictionary, - Timeout = TimeSpan.Parse(providerConfiguration.GetConfigurationByKey("Timeout")), - UseHttp2 = string.IsNullOrEmpty(providerConfiguration.GetConfigurationByKey("UseHttp2")) ? false : bool.Parse(providerConfiguration.GetConfigurationByKey("UseHttp2")), - Enabled = string.IsNullOrEmpty(providerConfiguration.GetConfigurationByKey("Enabled")) ? false : bool.Parse(providerConfiguration.GetConfigurationByKey("Enabled")) + Timeout = TimeSpan.Parse(providerConfiguration.GetConfigurationByKey(nameof(_Model.Timeout))), + UseHttp2 = !string.IsNullOrWhiteSpace(providerConfiguration.GetConfigurationByKey(nameof(_Model.UseHttp2))) && bool.Parse(providerConfiguration.GetConfigurationByKey(nameof(_Model.UseHttp2))), + Enabled = !string.IsNullOrWhiteSpace(providerConfiguration.GetConfigurationByKey(nameof(_Model.Enabled))) && bool.Parse(providerConfiguration.GetConfigurationByKey(nameof(_Model.Enabled))) }; - Health = await Provider.GetHealth(); + _Health = await Provider.GetHealth(); + await InvokeAsync(StateHasChanged); await base.OnParametersSetAsync(); } - private async Task SaveConfig() + private async Task SaveConfigAsync() { var providerConfiguration = await Provider.GetConfiguration(ConfigureTagzAppFactory.Current); - Model.DefaultHeaders.Remove(string.Empty); + _Model.DefaultHeaders.Remove(string.Empty); - providerConfiguration.SetConfigurationByKey("BaseAddress", Model.BaseAddress); - providerConfiguration.SetConfigurationByKey("Timeout", Model.Timeout.ToString()); - providerConfiguration.SetConfigurationByKey("DefaultHeaders", JsonSerializer.Serialize(Model.DefaultHeaders)); - providerConfiguration.SetConfigurationByKey("UseHttp2", Model.UseHttp2.ToString()); - providerConfiguration.SetConfigurationByKey("Enabled", Model.Enabled.ToString()); + providerConfiguration.SetConfigurationByKey(nameof(_Model.BaseAddress), _Model.BaseAddress); + providerConfiguration.SetConfigurationByKey(nameof(_Model.ApiKey), _Model.ApiKey); + providerConfiguration.SetConfigurationByKey(nameof(_Model.SecretAuthKey), _Model.SecretAuthKey); + providerConfiguration.SetConfigurationByKey(nameof(_Model.WindowRequests), _Model.WindowRequests.ToString()); + providerConfiguration.SetConfigurationByKey(nameof(_Model.WindowSeconds), _Model.WindowSeconds.ToString()); + providerConfiguration.SetConfigurationByKey(nameof(_Model.Timeout), _Model.Timeout.ToString()); + providerConfiguration.SetConfigurationByKey(nameof(_Model.DefaultHeaders), JsonSerializer.Serialize(_Model.DefaultHeaders)); + providerConfiguration.SetConfigurationByKey(nameof(_Model.UseHttp2), _Model.UseHttp2.ToString()); + providerConfiguration.SetConfigurationByKey(nameof(_Model.Enabled), _Model.Enabled.ToString()); await Provider.SaveConfiguration(ConfigureTagzAppFactory.Current, providerConfiguration); ToastService.Add($"Saved {providerConfiguration.Name} Configuration", MessageSeverity.Success); @@ -110,18 +111,17 @@ public class ViewModel { - // add properties for each of the fields you want to edit - [Required] - public string ApiKey { get; set; } + [Required] + public string ApiKey { get; set; } = string.Empty; - [Required] - public string BaseAddress { get; set; } + [Required] + public string BaseAddress { get; set; } = string.Empty; public Dictionary DefaultHeaders { get; set; } = new(); - [Required] - public string SecretAuthKey { get; set; } + [Required] + public string SecretAuthKey { get; set; } = string.Empty; [Required] public TimeSpan Timeout { get; set; } @@ -135,8 +135,5 @@ public int WindowRequests { get; set; } public bool Enabled { get; set; } - } - - } diff --git a/src/TagzApp.Providers.Blazot/Configuration/BlazotConfiguration.cs b/src/TagzApp.Providers.Blazot/Configuration/BlazotConfiguration.cs index a53e2db3..f91b9845 100644 --- a/src/TagzApp.Providers.Blazot/Configuration/BlazotConfiguration.cs +++ b/src/TagzApp.Providers.Blazot/Configuration/BlazotConfiguration.cs @@ -1,4 +1,5 @@ using TagzApp.Communication.Configuration; +using TagzApp.Providers.Blazot.Constants; namespace TagzApp.Providers.Blazot.Configuration; @@ -7,9 +8,9 @@ public class BlazotConfiguration : HttpClientOptions, IProviderConfiguration /// /// Declare the section name used. /// - public const string AppSettingsSection = "providers:blazot"; + public const string AppSettingsSection = BlazotConstants.ProviderId; - public bool Enabled { get; set; } = false; + public bool Enabled { get; set; } /// /// Blazot issued API Key. @@ -24,38 +25,40 @@ public class BlazotConfiguration : HttpClientOptions, IProviderConfiguration /// /// The number of seconds in the rate limit window. /// - public int WindowSeconds { get; set; } = 60; + public int WindowSeconds { get; set; } = 300; /// /// The number of requests the account allows within the window. /// - public int WindowRequests { get; set; } + public int WindowRequests { get; set; } = 5; /// /// Provider Description /// - public string Description => "Interact with the Blazot social media service"; - public string Name => "Blazot"; + public string Description => BlazotConstants.Description; - public string[] Keys => ["ApiKey", "SecretAuthKey", "WindowSeconds", "WindowRequests", "BaseAddress", "Timeout", "DefaultHeaders", "UseHttp2"]; + public string Name => BlazotConstants.DisplayName; + + public string[] Keys => [nameof(Enabled), nameof(ApiKey), nameof(SecretAuthKey), nameof(WindowSeconds), nameof(WindowRequests), nameof(BaseAddress), nameof(Timeout), nameof(DefaultHeaders), nameof(UseHttp2)]; public BlazotConfiguration() { - BaseAddress = new Uri("https://api.blazot.com"); + BaseAddress = new Uri(BlazotConstants.BaseAddress); } public string GetConfigurationByKey(string key) { return key switch { - "ApiKey" => ApiKey, - "SecretAuthKey" => SecretAuthKey, - "WindowSeconds" => WindowSeconds.ToString(), - "WindowRequests" => WindowRequests.ToString(), - "BaseAddress" => BaseAddress?.ToString() ?? string.Empty, - "Timeout" => Timeout.ToString(), - "DefaultHeaders" => DefaultHeaders?.Serialize() ?? string.Empty, - "UseHttp2" => UseHttp2.ToString(), + nameof(ApiKey) => ApiKey, + nameof(SecretAuthKey) => SecretAuthKey, + nameof(WindowSeconds) => WindowSeconds.ToString(), + nameof(WindowRequests) => WindowRequests.ToString(), + nameof(BaseAddress) => BaseAddress?.ToString() ?? string.Empty, + nameof(Timeout) => Timeout.ToString(), + nameof(DefaultHeaders) => DefaultHeaders?.Serialize() ?? string.Empty, + nameof(UseHttp2) => UseHttp2.ToString(), + nameof(Enabled) => Enabled.ToString(), _ => string.Empty }; } @@ -66,32 +69,33 @@ public void SetConfigurationByKey(string key, string value) // Set the property with the same name as the key submitted and don't use reflection switch (key) { - case "ApiKey": + case nameof(ApiKey): ApiKey = value; break; - case "SecretAuthKey": + case nameof(SecretAuthKey): SecretAuthKey = value; break; - case "WindowSeconds": + case nameof(WindowSeconds): WindowSeconds = int.Parse(value); break; - case "WindowRequests": + case nameof(WindowRequests): WindowRequests = int.Parse(value); break; - case "BaseAddress": + case nameof(BaseAddress): BaseAddress = new Uri(value); break; - case "Timeout": + case nameof(Timeout): Timeout = TimeSpan.Parse(value); break; - case "DefaultHeaders": + case nameof(DefaultHeaders): DefaultHeaders = DeserializeHeaders(value); break; - case "UseHttp2": + case nameof(UseHttp2): UseHttp2 = bool.Parse(value); break; + case nameof(Enabled): + Enabled = bool.Parse(value); + break; } - - } } diff --git a/src/TagzApp.Providers.Blazot/Constants/BlazotConstants.cs b/src/TagzApp.Providers.Blazot/Constants/BlazotConstants.cs index a1163fac..9b9a7c33 100644 --- a/src/TagzApp.Providers.Blazot/Constants/BlazotConstants.cs +++ b/src/TagzApp.Providers.Blazot/Constants/BlazotConstants.cs @@ -12,6 +12,23 @@ internal static class BlazotConstants /// public const string BaseAppAddress = "https://blazot.com"; - public const string ProviderId = "BLAZOT"; + /// + /// The provider id used in the database for provider system configuration. + /// + public const string ProviderId = "provider-blazot"; + + /// + /// The provider name used as an identifier in the database content entries. + /// + public const string Provider = "BLAZOT"; + + /// + /// The display name. + /// public const string DisplayName = "Blazot"; + + /// + /// The provider description. + /// + public const string Description = "Interact with the Blazot social media service."; } diff --git a/src/TagzApp.Providers.Blazot/Converters/ContentConverter.cs b/src/TagzApp.Providers.Blazot/Converters/ContentConverter.cs index bc4a9ae5..4252afaf 100644 --- a/src/TagzApp.Providers.Blazot/Converters/ContentConverter.cs +++ b/src/TagzApp.Providers.Blazot/Converters/ContentConverter.cs @@ -46,7 +46,7 @@ public IEnumerable ConvertToContent(List? transmissions, var content = new Content { - Provider = BlazotConstants.ProviderId, + Provider = BlazotConstants.Provider, ProviderId = transmission.TransmissionId.ToString(), Author = new Creator { @@ -102,6 +102,14 @@ public IEnumerable ConvertToContent(List? transmissions, }; } + if (!string.IsNullOrWhiteSpace(transmission.AnimatedMedia?.Url)) + { + content.PreviewCard = new Card + { + ImageUri = new Uri(transmission.AnimatedMedia.Url) + }; + } + return content; } catch (Exception ex) diff --git a/src/TagzApp.Providers.Blazot/Formatters/LinkFormatters.cs b/src/TagzApp.Providers.Blazot/Formatters/LinkFormatters.cs index 81c0e64d..10eee8e5 100644 --- a/src/TagzApp.Providers.Blazot/Formatters/LinkFormatters.cs +++ b/src/TagzApp.Providers.Blazot/Formatters/LinkFormatters.cs @@ -14,9 +14,9 @@ public static string FormatBodyLinks(string bodyText) if (string.IsNullOrWhiteSpace(bodyText)) return bodyText; - bodyText = LinkFormatters.AddHashTagLinks(bodyText); - bodyText = LinkFormatters.AddWebLinks(bodyText); - bodyText = LinkFormatters.AddMentionLinks(bodyText); + bodyText = AddHashTagLinks(bodyText); + bodyText = AddMentionLinks(bodyText); + bodyText = AddWebLinks(bodyText); return bodyText; } @@ -40,6 +40,9 @@ public static string AddHashTagLinks(string bodyText) public static string AddWebLinks(string bodyText) { + // Had issues with & breaking URL links when in query parameters. + bodyText = bodyText.Replace("&", "&"); + return LinkRegex.Replace(bodyText, delegate (Match m) { var fullLink = AddHttpIfMissing(m.Value); diff --git a/src/TagzApp.Providers.Blazot/Models/AnimatedMedia.cs b/src/TagzApp.Providers.Blazot/Models/AnimatedMedia.cs new file mode 100644 index 00000000..06fc7292 --- /dev/null +++ b/src/TagzApp.Providers.Blazot/Models/AnimatedMedia.cs @@ -0,0 +1,10 @@ +namespace TagzApp.Providers.Blazot.Models; + +public class AnimatedMedia +{ + public string Url { get; set; } = string.Empty; + + public int Width { get; set; } + + public int Height { get; set; } +} diff --git a/src/TagzApp.Providers.Blazot/Models/Transmission.cs b/src/TagzApp.Providers.Blazot/Models/Transmission.cs index 7d651812..0bf11622 100644 --- a/src/TagzApp.Providers.Blazot/Models/Transmission.cs +++ b/src/TagzApp.Providers.Blazot/Models/Transmission.cs @@ -39,5 +39,7 @@ public class Transmission public WebLink WebLink { get; set; } public Transmission? RelayedTransmission { get; set; } + + public AnimatedMedia? AnimatedMedia { get; set; } } #pragma warning restore CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. diff --git a/src/TagzApp.UnitTest/Blazot/TestData/LinkData.cs b/src/TagzApp.UnitTest/Blazot/TestData/LinkData.cs index 3497eb2e..21aef323 100644 --- a/src/TagzApp.UnitTest/Blazot/TestData/LinkData.cs +++ b/src/TagzApp.UnitTest/Blazot/TestData/LinkData.cs @@ -8,6 +8,10 @@ public class LinkData : IEnumerable private static readonly string _LinkString = "Blazot - your launchpad to the social universe - https://blazot.com"; private static readonly string _StartLinkString = "https://blazot.com - Link at very beginning"; private static readonly string _LinkHashtagComboString = "#dotnet https://blazot.com"; + private static readonly string _LinkHashtagComboString2 = "Just a test. #dotnet https://blazot.com"; + private static readonly string _LinkWithHashSymbol = "Testing. https://github.com/dotnet/aspnetcore/issues/51046#issuecomment-2034933362"; + private static readonly string _LinkWithQueryParam = "Testing. https://www.youtube.com/live/ubX-a6_V_ao?si=CesC5nZrAI5quccu"; + private static readonly string _LinkWithQueryParam2 = "Testing. https://www.youtube.com/live/hrXAkNsjaoI?feature=shared&t=541"; private static readonly string _SimplePunctuationString = "I'm a test message"; private static readonly string _HashTagTouching = "I'm a test message
#dotnet"; private static readonly string _TypicalString = "I'm a test message #dotnet"; @@ -21,6 +25,10 @@ public class LinkData : IEnumerable new object[] {HttpUtility.HtmlEncode(_LinkString), "Blazot - your launchpad to the social universe - https://blazot.com" }, new object[] {HttpUtility.HtmlEncode(_StartLinkString), "https://blazot.com - Link at very beginning" }, new object[] {HttpUtility.HtmlEncode(_LinkHashtagComboString), "#dotnet https://blazot.com" }, + new object[] {HttpUtility.HtmlEncode(_LinkHashtagComboString2), "Just a test. #dotnet https://blazot.com" }, + new object[] {HttpUtility.HtmlEncode(_LinkWithHashSymbol), "Testing. https://github.com/dotnet/aspnetcore/issues/51046#issuecomment-2034933362" }, + new object[] {HttpUtility.HtmlEncode(_LinkWithQueryParam), "Testing. https://www.youtube.com/live/ubX-a6_V_ao?si=CesC5nZrAI5quccu" }, + new object[] {HttpUtility.HtmlEncode(_LinkWithQueryParam2), "Testing. https://www.youtube.com/live/hrXAkNsjaoI?feature=shared&t=541" }, new object[] {HttpUtility.HtmlEncode(_SimplePunctuationString), "I'm a test message"}, new object[] {HttpUtility.HtmlEncode(_HashTagTouching), "I'm a test message <br/>#dotnet" }, new object[] {HttpUtility.HtmlEncode(_TypicalString), "I'm a test message #dotnet" },