From 4f6053172d0b701a40367e5fd3ba50d5decf1e94 Mon Sep 17 00:00:00 2001 From: glax Date: Mon, 21 Jul 2025 16:39:18 +0200 Subject: [PATCH] Fix NotificationConnectors --- .../NotificationConnectorController.cs | 32 +++++++++---------- .../NotificationConnector.cs | 31 ++++++------------ API/Tranga.cs | 14 ++++---- 3 files changed, 33 insertions(+), 44 deletions(-) diff --git a/API/Controllers/NotificationConnectorController.cs b/API/Controllers/NotificationConnectorController.cs index 157e0f5..70f74ef 100644 --- a/API/Controllers/NotificationConnectorController.cs +++ b/API/Controllers/NotificationConnectorController.cs @@ -48,30 +48,29 @@ public class NotificationConnectorController(NotificationsContext context) : Con /// Creates a new /// /// Formatting placeholders: "%title" and "%text" can be placed in url, header-values and body and will be replaced when notifications are sent - /// + /// ID of the new /// Error during Database Operation [HttpPut] - [ProducesResponseType(Status201Created)] - [ProducesResponseType(Status409Conflict)] + [ProducesResponseType(Status200OK, "text/plain")] [ProducesResponseType(Status500InternalServerError, "text/plain")] public IActionResult CreateConnector([FromBody]NotificationConnector notificationConnector) { - context.NotificationConnectors.Add(notificationConnector); + context.Notifications.Add(new ("Added new Notification Connector!", notificationConnector.Name, NotificationUrgency.High)); if(context.Sync() is { success: false } result) return StatusCode(Status500InternalServerError, result.exceptionMessage); - return Created(); + return Ok(notificationConnector.Name); } /// /// Creates a new Gotify- /// /// Priority needs to be between 0 and 10 - /// + /// ID of the new /// Error during Database Operation [HttpPut("Gotify")] - [ProducesResponseType(Status201Created, "application/json")] + [ProducesResponseType(Status200OK, "text/plain")] [ProducesResponseType(Status500InternalServerError, "text/plain")] public IActionResult CreateGotifyConnector([FromBody]GotifyRecord gotifyData) { @@ -79,7 +78,7 @@ public class NotificationConnectorController(NotificationsContext context) : Con NotificationConnector gotifyConnector = new (gotifyData.Name, gotifyData.Endpoint, - new Dictionary() { { "X-Gotify-IDOnConnector", gotifyData.AppToken } }, + new Dictionary() { { "X-Gotify-Key", gotifyData.AppToken } }, "POST", $"{{\"message\": \"%text\", \"title\": \"%title\", \"Priority\": {gotifyData.Priority}}}"); return CreateConnector(gotifyConnector); @@ -89,10 +88,10 @@ public class NotificationConnectorController(NotificationsContext context) : Con /// Creates a new Ntfy- /// /// Priority needs to be between 1 and 5 - /// + /// ID of the new /// Error during Database Operation [HttpPut("Ntfy")] - [ProducesResponseType(Status201Created, "application/json")] + [ProducesResponseType(Status200OK, "text/plain")] [ProducesResponseType(Status500InternalServerError, "text/plain")] public IActionResult CreateNtfyConnector([FromBody]NtfyRecord ntfyRecord) { @@ -102,14 +101,13 @@ public class NotificationConnectorController(NotificationsContext context) : Con string auth = Convert.ToBase64String(Encoding.UTF8.GetBytes(authHeader)).Replace("=",""); NotificationConnector ntfyConnector = new (ntfyRecord.Name, - $"{ntfyRecord.Endpoint}/{ntfyRecord.Topic}?auth={auth}", + $"{ntfyRecord.Endpoint}?auth={auth}", new Dictionary() { - {"Title", "%title"}, - {"Priority", ntfyRecord.Priority.ToString()}, + {"Authorization", auth} }, "POST", - "%text"); + $"{{\"message\": \"%text\", \"title\": \"%title\", \"Priority\": {ntfyRecord.Priority} \"Topic\": \"{ntfyRecord.Topic}\"}}"); return CreateConnector(ntfyConnector); } @@ -117,10 +115,10 @@ public class NotificationConnectorController(NotificationsContext context) : Con /// Creates a new Pushover- /// /// https://pushover.net/api - /// ID of new connector + /// ID of the new /// Error during Database Operation [HttpPut("Pushover")] - [ProducesResponseType(Status201Created, "application/json")] + [ProducesResponseType(Status200OK, "text/plain")] [ProducesResponseType(Status500InternalServerError, "text/plain")] public IActionResult CreatePushoverConnector([FromBody]PushoverRecord pushoverRecord) { @@ -154,6 +152,6 @@ public class NotificationConnectorController(NotificationsContext context) : Con if(context.Sync() is { success: false } result) return StatusCode(Status500InternalServerError, result.exceptionMessage); - return Created(); + return Ok(); } } \ No newline at end of file diff --git a/API/Schema/NotificationsContext/NotificationConnectors/NotificationConnector.cs b/API/Schema/NotificationsContext/NotificationConnectors/NotificationConnector.cs index a57b2ba..72e37ca 100644 --- a/API/Schema/NotificationsContext/NotificationConnectors/NotificationConnector.cs +++ b/API/Schema/NotificationsContext/NotificationConnectors/NotificationConnector.cs @@ -44,40 +44,29 @@ public class NotificationConnector(string name, string url, Dictionary formattedHeaders = Headers.ToDictionary(h => h.Key, - h => string.Format(formatProvider, h.Value, title, notificationText)); + h => FormatStr(h.Value, title, notificationText)); HttpRequestMessage request = new(System.Net.Http.HttpMethod.Parse(HttpMethod), formattedUrl); foreach (var (key, value) in formattedHeaders) request.Headers.Add(key, value); request.Content = new StringContent(formattedBody); + request.Content.Headers.ContentType = new ("application/json"); Log.Debug($"Request: {request}"); HttpResponseMessage response = Client.Send(request); - Log.Debug($"Response status code: {response.StatusCode}"); + Log.Debug($"Response status code: {response.StatusCode} {response.Content.ReadAsStringAsync().Result}"); } - private class CustomWebhookFormatProvider(string title, string text) : IFormatProvider + private string FormatStr(string str, string title, string text) { - public object? GetFormat(Type? formatType) - { - return this; - } - - public string Format(string fmt, object arg, IFormatProvider provider) - { - if(arg.GetType() != typeof(string)) - return arg.ToString() ?? string.Empty; - - StringBuilder sb = new StringBuilder(fmt); - sb.Replace("%title", title); - sb.Replace("%text", text); + StringBuilder sb = new (str); + sb.Replace("%title", title); + sb.Replace("%text", text); - return sb.ToString(); - } + return sb.ToString(); } public override string ToString() => $"{GetType().Name} {Name}"; diff --git a/API/Tranga.cs b/API/Tranga.cs index 76d726e..406fb15 100644 --- a/API/Tranga.cs +++ b/API/Tranga.cs @@ -71,7 +71,7 @@ public static class Tranga return mangaConnector != null; } - internal static readonly Dictionary PeriodicWorkers = new (); + internal static readonly ConcurrentDictionary PeriodicWorkers = new (); public static void AddWorker(BaseWorker worker) { @@ -84,8 +84,9 @@ public static class Tranga private static void AddPeriodicWorker(BaseWorker worker, IPeriodic periodic) { Log.Debug($"Adding Periodic {worker}"); - PeriodicWorkers.Add((worker as IPeriodic)!, PeriodicTask(worker, periodic)); - PeriodicWorkers[(worker as IPeriodic)!].Start(); + Task periodicTask = PeriodicTask(worker, periodic); + PeriodicWorkers.TryAdd((worker as IPeriodic)!, periodicTask); + periodicTask.Start(); } private static Task PeriodicTask(BaseWorker worker, IPeriodic periodic) => new (() => @@ -100,8 +101,9 @@ public static class Tranga if (worker.State < WorkerExecutionState.Created) //Failed return; Log.Debug($"Refreshing {worker}"); - PeriodicWorkers[(worker as IPeriodic)!] = PeriodicTask(worker, periodic); - PeriodicWorkers[(worker as IPeriodic)!].Start(); + Task periodicTask = PeriodicTask(worker, periodic); + PeriodicWorkers.AddOrUpdate((worker as IPeriodic)!, periodicTask, (_, _) => periodicTask); + periodicTask.Start(); }; public static void AddWorkers(IEnumerable workers) @@ -149,7 +151,7 @@ public static class Tranga { Log.Debug($"Stopping {worker}"); if(worker is IPeriodic periodicWorker) - PeriodicWorkers.Remove(periodicWorker); + PeriodicWorkers.Remove(periodicWorker, out _); worker.Cancel(); RunningWorkers.Remove(worker, out _); }