From 8f3f9fa1fb2fa5a0a17d8de2253f6c0d686b76af Mon Sep 17 00:00:00 2001 From: Marcel Baumgartner Date: Wed, 22 Feb 2023 13:55:59 +0100 Subject: [PATCH] Added support chat sync. Added admin support chat pages --- .gitignore | 1 + Moonlight/App/Services/ServerService.cs | 6 +- ...tAdminServer.cs => SupportAdminService.cs} | 9 +- .../Services/Support/SupportServerService.cs | 78 +++++-- Moonlight/Moonlight.csproj | 1 - Moonlight/Program.cs | 2 +- .../Shared/Views/Admin/Support/Index.razor | 157 ++++++++++++++ .../Shared/Views/Admin/Support/View.razor | 194 ++++++++++++++++++ Moonlight/Shared/Views/Support.razor | 136 ++++++------ ....GeneratedMSBuildEditorConfig.editorconfig | 8 + Moonlight/resources/lang/de_de.lang | 9 + 11 files changed, 508 insertions(+), 93 deletions(-) rename Moonlight/App/Services/Support/{SupportAdminServer.cs => SupportAdminService.cs} (91%) create mode 100644 Moonlight/Shared/Views/Admin/Support/Index.razor create mode 100644 Moonlight/Shared/Views/Admin/Support/View.razor diff --git a/.gitignore b/.gitignore index 056f84d..d91cbe4 100644 --- a/.gitignore +++ b/.gitignore @@ -443,3 +443,4 @@ Moonlight/obj/project.assets.json Moonlight/obj/project.nuget.cache Moonlight/obj/project.packagespec.json Moonlight/obj/Debug/net6.0/Moonlight.GeneratedMSBuildEditorConfig.editorconfig +*.editorconfig diff --git a/Moonlight/App/Services/ServerService.cs b/Moonlight/App/Services/ServerService.cs index c869def..aad5504 100644 --- a/Moonlight/App/Services/ServerService.cs +++ b/Moonlight/App/Services/ServerService.cs @@ -1,8 +1,4 @@ -using System.Security.Cryptography; -using System.Text; -using JWT.Algorithms; -using JWT.Builder; -using Logging.Net; +using Logging.Net; using Microsoft.EntityFrameworkCore; using Moonlight.App.Database; using Moonlight.App.Database.Entities; diff --git a/Moonlight/App/Services/Support/SupportAdminServer.cs b/Moonlight/App/Services/Support/SupportAdminService.cs similarity index 91% rename from Moonlight/App/Services/Support/SupportAdminServer.cs rename to Moonlight/App/Services/Support/SupportAdminService.cs index f3eaf44..ce11083 100644 --- a/Moonlight/App/Services/Support/SupportAdminServer.cs +++ b/Moonlight/App/Services/Support/SupportAdminService.cs @@ -3,7 +3,7 @@ using Moonlight.App.Services.Sessions; namespace Moonlight.App.Services.Support; -public class SupportAdminServer +public class SupportAdminService { private readonly SupportServerService SupportServerService; private readonly IdentityService IdentityService; @@ -14,7 +14,7 @@ public class SupportAdminServer private User Self; private User Recipient; - public SupportAdminServer( + public SupportAdminService( SupportServerService supportServerService, IdentityService identityService, MessageService messageService) @@ -60,6 +60,11 @@ public class SupportAdminServer ); } + public async Task Close() + { + await SupportServerService.Close(Recipient); + } + public void Dispose() { MessageService.Unsubscribe($"support.{Recipient.Id}.message", this); diff --git a/Moonlight/App/Services/Support/SupportServerService.cs b/Moonlight/App/Services/Support/SupportServerService.cs index 661bb43..f2b22b7 100644 --- a/Moonlight/App/Services/Support/SupportServerService.cs +++ b/Moonlight/App/Services/Support/SupportServerService.cs @@ -27,38 +27,72 @@ public class SupportServerService : IDisposable Task.Run(async () => { - message.CreatedAt = DateTime.UtcNow; - message.Sender = sender; - message.Recipient = recipient; - message.IsSupport = isSupport; - - SupportMessageRepository.Add(message); - - await MessageService.Emit($"support.{recipient.Id}.message", message); - - if (!recipient.SupportPending) + try { - recipient.SupportPending = true; - UserRepository.Update(recipient); + message.CreatedAt = DateTime.UtcNow; + message.Sender = sender; + message.Recipient = recipient; + message.IsSupport = isSupport; - var systemMessage = new SupportMessage() + SupportMessageRepository.Add(message); + + await MessageService.Emit($"support.{recipient.Id}.message", message); + + if (!recipient.SupportPending) { - Recipient = recipient, - Sender = null, - IsSystem = true, - Message = "The support team has been notified. Please be patient" - }; + recipient.SupportPending = true; + UserRepository.Update(recipient); - SupportMessageRepository.Add(systemMessage); + if (!message.IsSupport) + { + var systemMessage = new SupportMessage() + { + Recipient = recipient, + Sender = null, + IsSystem = true, + Message = "The support team has been notified. Please be patient" + }; - await MessageService.Emit($"support.{recipient.Id}.message", systemMessage); + SupportMessageRepository.Add(systemMessage); - Logger.Info("Support ticket created: " + recipient.Id); - //TODO: Ping or so + await MessageService.Emit($"support.{recipient.Id}.message", systemMessage); + } + + await MessageService.Emit($"support.new", recipient); + + Logger.Info("Support ticket created: " + recipient.Id); + //TODO: Ping or so + } + } + catch (Exception e) + { + Logger.Error("Error sending message"); + Logger.Error(e); } }); } + public async Task Close(User user) + { + var recipient = UserRepository.Get().First(x => x.Id == user.Id); + + recipient.SupportPending = false; + UserRepository.Update(recipient); + + var systemMessage = new SupportMessage() + { + Recipient = recipient, + Sender = null, + IsSystem = true, + Message = "The ticket is now closed. Type a message to open it again" + }; + + SupportMessageRepository.Add(systemMessage); + + await MessageService.Emit($"support.{recipient.Id}.message", systemMessage); + await MessageService.Emit($"support.close", recipient); + } + public Task GetMessages(User r) { var recipient = UserRepository.Get().First(x => x.Id == r.Id); diff --git a/Moonlight/Moonlight.csproj b/Moonlight/Moonlight.csproj index 4b91965..5e319e8 100644 --- a/Moonlight/Moonlight.csproj +++ b/Moonlight/Moonlight.csproj @@ -60,7 +60,6 @@ - diff --git a/Moonlight/Program.cs b/Moonlight/Program.cs index 8a1e08f..f44eede 100644 --- a/Moonlight/Program.cs +++ b/Moonlight/Program.cs @@ -62,7 +62,7 @@ namespace Moonlight // Support builder.Services.AddSingleton(); - builder.Services.AddScoped(); + builder.Services.AddScoped(); builder.Services.AddScoped(); // Helpers diff --git a/Moonlight/Shared/Views/Admin/Support/Index.razor b/Moonlight/Shared/Views/Admin/Support/Index.razor new file mode 100644 index 0000000..7e1d8b1 --- /dev/null +++ b/Moonlight/Shared/Views/Admin/Support/Index.razor @@ -0,0 +1,157 @@ +@page "/admin/support" +@using Moonlight.App.Repositories +@using Moonlight.App.Database.Entities +@using Microsoft.EntityFrameworkCore +@using Moonlight.App.Database +@using Moonlight.App.Services + +@inject SupportMessageRepository SupportMessageRepository +@inject ConfigService ConfigService +@inject MessageService MessageService +@implements IDisposable + + + +
+
+
+
+
+

+ Open tickets +

+
+ @if (Users.Any()) + { + foreach (var user in Users) + { +
+ + + + +
+ + + + @{ + var lastMessage = MessageCache.ContainsKey(user) ? MessageCache[user] : null; + } + + @if (lastMessage == null) + { + No message sent yet + } + else + { + @(lastMessage.Message) + } + +
+
+ } + } + else + { +
+ No support ticket is currently open +
+ } +
+
+
+ +
+ +
+

+ Actions +

+ +
+ + + + + +
+
Project Briefing
+ + +
+ + Check out our + + + + Support Policy + +
+ +
+ +
+
+
+
+
+
+
+
+ +@code +{ + private User[] Users; + private Dictionary MessageCache; + + private LazyLoader? LazyLoader; + + protected override void OnInitialized() + { + MessageCache = new(); + + MessageService.Subscribe("support.new", this, async user => + { + if (LazyLoader != null) + await LazyLoader.Reload(); + }); + + MessageService.Subscribe("support.close", this, async user => + { + if (LazyLoader != null) + await LazyLoader.Reload(); + }); + } + + private Task Load(LazyLoader arg) + { + // We dont want cache here + Users = (new UserRepository(new DataContext(ConfigService))) + .Get() + .Where(x => x.SupportPending) + .ToArray(); + + foreach (var user in Users) + { + var lastMessage = SupportMessageRepository + .Get() + .Include(x => x.Recipient) + .OrderByDescending(x => x.Id) + .FirstOrDefault(x => x.Recipient!.Id == user.Id); + + MessageCache.Add(user, lastMessage); + } + + return Task.CompletedTask; + } + + public void Dispose() + { + MessageService.Unsubscribe("support.new", this); + MessageService.Unsubscribe("support.close", this); + } +} \ No newline at end of file diff --git a/Moonlight/Shared/Views/Admin/Support/View.razor b/Moonlight/Shared/Views/Admin/Support/View.razor new file mode 100644 index 0000000..8300475 --- /dev/null +++ b/Moonlight/Shared/Views/Admin/Support/View.razor @@ -0,0 +1,194 @@ +@page "/admin/support/view/{Id:int}" +@using Moonlight.App.Services.Support +@using Moonlight.App.Database.Entities +@using Moonlight.App.Helpers +@using Moonlight.App.Repositories +@using Moonlight.App.Services + +@inject SupportAdminService SupportAdminService +@inject UserRepository UserRepository +@inject SmartTranslateService SmartTranslateService +@inject ResourceService ResourceService + + + + @if (User == null) + { +
+ User not found +
+ } + else + { +
+
+
+
+
+ +
+ @foreach (var message in Messages) + { + if (message.IsSystem || message.IsSupport) + { +
+
+ + +
+ @if (message.IsSystem) + { + @(message.Message) + } + else + { + @(message.Message) + } +
+
+
+ } + else + { +
+
+
+
+ Avatar +
+
+ + @(message.Sender!.FirstName) @(message.Sender!.LastName) + + @(Formatter.FormatAgoFromDateTime(message.CreatedAt, SmartTranslateService)) +
+
+ +
+ @(message.Message) +
+
+
+ } + } +
+
+
+ +
+
+
+
+

+ User information +

+ +
+ + Firstname: @(User.FirstName) + +
+
+ + Lastname: @(User.LastName) + +
+
+ + Email: @(User.Email) + +
+
+ + + + +
+
+
+
+
+ } +
+
+ +@code +{ + [Parameter] + public int Id { get; set; } + + private User? User; + private SupportMessage[] Messages; + private string Content = ""; + + private async Task Load(LazyLoader arg) + { + User = UserRepository + .Get() + .FirstOrDefault(x => x.Id == Id); + + if (User != null) + { + SupportAdminService.OnNewMessage += OnNewMessage; + + await SupportAdminService.Start(User); + } + } + + private async void OnNewMessage(object? sender, SupportMessage e) + { + Messages = (await SupportAdminService.GetMessages()).Reverse().ToArray(); + await InvokeAsync(StateHasChanged); + } + + private async Task LoadMessages(LazyLoader arg) + { + Messages = (await SupportAdminService.GetMessages()).Reverse().ToArray(); + } + + private async Task Send() + { + await SupportAdminService.SendMessage(Content); + Content = ""; + } + + private async Task CloseTicket() + { + await SupportAdminService.Close(); + } +} \ No newline at end of file diff --git a/Moonlight/Shared/Views/Support.razor b/Moonlight/Shared/Views/Support.razor index f1e4b81..beae23b 100644 --- a/Moonlight/Shared/Views/Support.razor +++ b/Moonlight/Shared/Views/Support.razor @@ -14,80 +14,89 @@
-
- @foreach (var message in Messages) - { - if (message.IsSystem || message.IsSupport) + +
+ @foreach (var message in Messages) { -
-
-
-
- Logo + if (message.IsSystem || message.IsSupport) + { + + } } - else - { -
-
-
-
- @(Formatter.FormatAgoFromDateTime(message.CreatedAt, SmartTranslateService)) - - @(message.Sender!.FirstName) @(message.Sender!.LastName) - -
-
- Avatar -
+
+
+
+
+ Logo
- -
- @(message.Message) +
-
- } - } -
-
-
-
- Logo -
- -
-
- Welcome to the support chat. Ask your question here and we will help you +
+ Welcome to the support chat. Ask your question here and we will help you +
-
+