diff --git a/contrib/Makefile b/contrib/Makefile
index deb55bcc6..5ccf773a1 100644
--- a/contrib/Makefile
+++ b/contrib/Makefile
@@ -14,7 +14,7 @@ reinstall: copy-binaries
@echo "đź’Ż backend started"
reinstall-prod:
- make reinstall APP_INSTALL_ENV= APP_INSTALL_PREFIX= APP_INSTALL_ENV=production
+ make reinstall APP_INSTALL_PREFIX= APP_INSTALL_ENV=production
generated/$(APP_INSTALL_PREFIX)yavscOrg.service:
generated/$(APP_INSTALL_PREFIX)yavscBlogs.service:
diff --git a/contrib/template.vhost b/contrib/template.vhost
index ea2c2cb6d..b4c9c139e 100644
--- a/contrib/template.vhost
+++ b/contrib/template.vhost
@@ -57,5 +57,25 @@ server {
proxy_read_timeout 100s;
proxy_buffering off;
}
+
+ # SignalR (ChatHub) : WebSocket exige Upgrade/Connection et un timeout
+ # long, sinon la connexion tombe au premier silence ou l'upgrade échoue.
+ # Connection est fixé à "upgrade" (pas de map $connection_upgrade, qui
+ # exigerait une directive map {} globale hors de ce vhost) : SignalR
+ # négocie toujours un upgrade sur ce chemin, et la négociation initiale
+ # (POST /negotiate, sans en-tête Upgrade) n'est pas affectée par cet
+ # en-tête côté Kestrel.
+ location /chathub {
+ proxy_pass $BACKEND_SCHEME://$HTTP_HOST:$BACKEND_PORT;
+ proxy_http_version 1.1;
+ proxy_set_header Upgrade $http_upgrade;
+ proxy_set_header Connection "upgrade";
+ proxy_set_header Host $host;
+ proxy_set_header X-Real-IP $remote_addr;
+ proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
+ proxy_set_header X-Forwarded-Proto $scheme;
+ proxy_read_timeout 3600s;
+ proxy_buffering off;
+ }
include server-status.conf;
-}
\ No newline at end of file
+}
diff --git a/src/PostIt/PostIt.Android/Properties/AndroidManifest.xml b/src/PostIt/PostIt.Android/Properties/AndroidManifest.xml
index 46f0bc9bb..256555df1 100644
--- a/src/PostIt/PostIt.Android/Properties/AndroidManifest.xml
+++ b/src/PostIt/PostIt.Android/Properties/AndroidManifest.xml
@@ -4,6 +4,7 @@
+ android:networkSecurityConfig="@xml/network_security_config"
+ android:hardwareAccelerated="true">
diff --git a/src/PostIt/PostIt.Android/Resources/network_security_config.xml b/src/PostIt/PostIt.Android/Resources/xml/network_security_config.xml
similarity index 100%
rename from src/PostIt/PostIt.Android/Resources/network_security_config.xml
rename to src/PostIt/PostIt.Android/Resources/xml/network_security_config.xml
diff --git a/src/PostIt/PostIt.Tests/EstimateEditionPageViewModelTests.cs b/src/PostIt/PostIt.Tests/EstimateEditionPageViewModelTests.cs
index 17efd391b..31c82387d 100644
--- a/src/PostIt/PostIt.Tests/EstimateEditionPageViewModelTests.cs
+++ b/src/PostIt/PostIt.Tests/EstimateEditionPageViewModelTests.cs
@@ -1,4 +1,5 @@
using System.Net.Http;
+using PostIt.Models;
using PostIt.ViewModels;
using Yavsc;
using Yavsc.Api.Client;
diff --git a/src/PostIt/PostIt.Tests/StatusBarTests.cs b/src/PostIt/PostIt.Tests/StatusBarTests.cs
index 4053dbaf3..15889e0b0 100644
--- a/src/PostIt/PostIt.Tests/StatusBarTests.cs
+++ b/src/PostIt/PostIt.Tests/StatusBarTests.cs
@@ -2,6 +2,7 @@ using Avalonia.Controls;
using Avalonia.Headless.XUnit;
using Avalonia.VisualTree;
using PostIt.Controls;
+using PostIt.Models;
using PostIt.ViewModels;
namespace PostIt.Tests;
@@ -21,7 +22,9 @@ public class StatusBarTests
[AvaloniaFact]
public void Status_message_is_rendered_by_a_SelectableTextBlock()
{
- var bar = new StatusBar { DataContext = StatusNotice.Error("Échec de la suppression : boom") };
+ var bar = new StatusBar {
+ DataContext =
+ StatusNotice.Error("Échec de la suppression : boom") };
var window = new Window { Content = bar };
window.Show();
@@ -32,4 +35,4 @@ public class StatusBarTests
Assert.NotNull(message);
Assert.Equal("Échec de la suppression : boom", message!.Text);
}
-}
\ No newline at end of file
+}
diff --git a/src/PostIt/PostIt/Controls/StatusBar.axaml b/src/PostIt/PostIt/Controls/StatusBar.axaml
index 2f46fee33..b279ce5ea 100644
--- a/src/PostIt/PostIt/Controls/StatusBar.axaml
+++ b/src/PostIt/PostIt/Controls/StatusBar.axaml
@@ -10,16 +10,18 @@
Padding="8">
-
+ FontWeight="Bold"
+ Foreground="{Binding Foreground}"
+ VerticalAlignment="Top"/>
+ Foreground="{Binding Foreground}"
+ TextWrapping="Wrap"
+ VerticalAlignment="Center"/>
+
diff --git a/src/PostIt/PostIt/Models/ChatMessageDto.cs b/src/PostIt/PostIt/Models/ChatMessageDto.cs
new file mode 100644
index 000000000..b93ccbe29
--- /dev/null
+++ b/src/PostIt/PostIt/Models/ChatMessageDto.cs
@@ -0,0 +1,14 @@
+namespace PostIt.ViewModels.Chat
+{
+ ///
+ /// DTO minimal calqué sur l'objet anonyme émis par le hub
+ /// ({ Name, Room, Message }) via l'événement
+ /// ReceiveMessage.
+ ///
+ public class ChatMessageDto
+ {
+ public string? Name { get; set; }
+ public string? Room { get; set; }
+ public string? Message { get; set; }
+ }
+}
diff --git a/src/PostIt/PostIt/Models/ChatRoomInfo.cs b/src/PostIt/PostIt/Models/ChatRoomInfo.cs
new file mode 100644
index 000000000..548371157
--- /dev/null
+++ b/src/PostIt/PostIt/Models/ChatRoomInfo.cs
@@ -0,0 +1,11 @@
+using System.Collections.Generic;
+
+namespace PostIt.ViewModels.Chat
+{
+ // DTO minimal calqué sur votre logique serveur ChatRoomInfo
+ public class ChatRoomInfo
+ {
+ public string? Name { get; set; }
+ public List Users { get; set; } = new();
+ }
+}
diff --git a/src/PostIt/PostIt/Models/IWithLabel.cs b/src/PostIt/PostIt/Models/IWithLabel.cs
new file mode 100644
index 000000000..b76f912db
--- /dev/null
+++ b/src/PostIt/PostIt/Models/IWithLabel.cs
@@ -0,0 +1,6 @@
+namespace PostIt.ViewModels;
+
+internal interface IWithLabel
+{
+ string Label { get; }
+}
diff --git a/src/PostIt/PostIt/Models/StatusNotice.cs b/src/PostIt/PostIt/Models/StatusNotice.cs
deleted file mode 100644
index c50ac3503..000000000
--- a/src/PostIt/PostIt/Models/StatusNotice.cs
+++ /dev/null
@@ -1,35 +0,0 @@
-namespace PostIt.ViewModels;
-
-public enum StatusSeverity
-{
- Info,
- Warning,
- Error
-}
-
-public sealed class StatusNotice
-{
- public string Message { get; }
- public StatusSeverity Severity { get; }
- public string Glyph { get; }
- public string Background { get; }
- public string BorderBrush { get; }
- public string Foreground { get; }
-
- public StatusNotice(string message, StatusSeverity severity)
- {
- Message = string.IsNullOrWhiteSpace(message) ? "Pret." : message;
- Severity = severity;
-
- (Glyph, Background, BorderBrush, Foreground) = severity switch
- {
- StatusSeverity.Error => ("!", "#7F1D1D", "#C62828", "#e1f0f6"),
- StatusSeverity.Warning => ("~", "#7C4A03", "#E6A700", "#eaeaea"),
- _ => ("i", "#E8F0FE", "#5B8DEF", "#1E3A8A"),
- };
- }
-
- public static StatusNotice Info(string message) => new(message, StatusSeverity.Info);
- public static StatusNotice Warning(string message) => new(message, StatusSeverity.Warning);
- public static StatusNotice Error(string message) => new(message, StatusSeverity.Error);
-}
diff --git a/src/PostIt/PostIt/Models/StatusSeverity.cs b/src/PostIt/PostIt/Models/StatusSeverity.cs
new file mode 100644
index 000000000..eb6ef4502
--- /dev/null
+++ b/src/PostIt/PostIt/Models/StatusSeverity.cs
@@ -0,0 +1,8 @@
+namespace PostIt.Models;
+
+public enum StatusSeverity
+{
+ Info,
+ Warning,
+ Error
+}
diff --git a/src/PostIt/PostIt/ViewModels/ACL/CirclesPageViewModel.cs b/src/PostIt/PostIt/ViewModels/ACL/CirclesPageViewModel.cs
index cd068b4f4..6201c061b 100644
--- a/src/PostIt/PostIt/ViewModels/ACL/CirclesPageViewModel.cs
+++ b/src/PostIt/PostIt/ViewModels/ACL/CirclesPageViewModel.cs
@@ -5,7 +5,7 @@ using Avalonia;
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using Microsoft.Extensions.DependencyInjection;
-using PostIt.Helpers;
+using PostIt.Models;
using PostIt.Services;
using Yavsc.Api.Client;
using Yavsc.Api.Client.Dtos;
diff --git a/src/PostIt/PostIt/ViewModels/ACL/PostAclDialogViewModel.cs b/src/PostIt/PostIt/ViewModels/ACL/PostAclDialogViewModel.cs
index be1b220fa..43ed60823 100644
--- a/src/PostIt/PostIt/ViewModels/ACL/PostAclDialogViewModel.cs
+++ b/src/PostIt/PostIt/ViewModels/ACL/PostAclDialogViewModel.cs
@@ -12,6 +12,7 @@ using Yavsc.Api.Client.Dtos;
using Yavsc.Abstract.BlogSpot;
using Yavsc.Abstract.Identity.Security;
using System.Net.Http;
+using PostIt.Models;
namespace PostIt.ViewModels;
diff --git a/src/PostIt/PostIt/ViewModels/Activity/ActivitiesPageViewModel.cs b/src/PostIt/PostIt/ViewModels/Activity/ActivitiesPageViewModel.cs
index bd13faf9b..1890309ec 100644
--- a/src/PostIt/PostIt/ViewModels/Activity/ActivitiesPageViewModel.cs
+++ b/src/PostIt/PostIt/ViewModels/Activity/ActivitiesPageViewModel.cs
@@ -8,6 +8,7 @@ using Avalonia;
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using PostIt.Helpers;
+using PostIt.Models;
using Yavsc.Abstract.Workflow;
using Yavsc.Api.Client;
diff --git a/src/PostIt/PostIt/ViewModels/Activity/BillingQueriesPageViewModel.cs b/src/PostIt/PostIt/ViewModels/Activity/BillingQueriesPageViewModel.cs
index f1b05b749..5cd373708 100644
--- a/src/PostIt/PostIt/ViewModels/Activity/BillingQueriesPageViewModel.cs
+++ b/src/PostIt/PostIt/ViewModels/Activity/BillingQueriesPageViewModel.cs
@@ -12,6 +12,7 @@ using PostIt.Helpers;
using Yavsc;
using Yavsc.Api.Client;
using Yavsc.Abstract.Workflow;
+using PostIt.Models;
namespace PostIt.ViewModels;
diff --git a/src/PostIt/PostIt/ViewModels/Activity/BillingQueryDetailsPageViewModel.cs b/src/PostIt/PostIt/ViewModels/Activity/BillingQueryDetailsPageViewModel.cs
index c9f122dce..0df05b21a 100644
--- a/src/PostIt/PostIt/ViewModels/Activity/BillingQueryDetailsPageViewModel.cs
+++ b/src/PostIt/PostIt/ViewModels/Activity/BillingQueryDetailsPageViewModel.cs
@@ -388,4 +388,4 @@ public partial class BillingQueryDetailsPageViewModel : ViewModelBase, IActionSt
QueryStatus.Success => "V",
_ => "i",
};
-}
\ No newline at end of file
+}
diff --git a/src/PostIt/PostIt/ViewModels/Activity/CommandFormsPageViewModel.cs b/src/PostIt/PostIt/ViewModels/Activity/CommandFormsPageViewModel.cs
index 533fbc380..14e7e74b9 100644
--- a/src/PostIt/PostIt/ViewModels/Activity/CommandFormsPageViewModel.cs
+++ b/src/PostIt/PostIt/ViewModels/Activity/CommandFormsPageViewModel.cs
@@ -6,6 +6,7 @@ using Avalonia;
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using PostIt.Helpers;
+using PostIt.Models;
using Yavsc.Abstract.Workflow;
using Yavsc.Api.Client;
diff --git a/src/PostIt/PostIt/ViewModels/Activity/EstimateEditionPageViewModel.cs b/src/PostIt/PostIt/ViewModels/Activity/EstimateEditionPageViewModel.cs
index 1f1e4b4be..f8f94436a 100644
--- a/src/PostIt/PostIt/ViewModels/Activity/EstimateEditionPageViewModel.cs
+++ b/src/PostIt/PostIt/ViewModels/Activity/EstimateEditionPageViewModel.cs
@@ -10,6 +10,7 @@ using Avalonia;
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using PostIt.Helpers;
+using PostIt.Models;
using Yavsc.Api.Client;
namespace PostIt.ViewModels;
diff --git a/src/PostIt/PostIt/ViewModels/Activity/EstimateListPageViewModel.cs b/src/PostIt/PostIt/ViewModels/Activity/EstimateListPageViewModel.cs
index c90a6d884..766dda903 100644
--- a/src/PostIt/PostIt/ViewModels/Activity/EstimateListPageViewModel.cs
+++ b/src/PostIt/PostIt/ViewModels/Activity/EstimateListPageViewModel.cs
@@ -9,6 +9,7 @@ using Avalonia;
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using PostIt.Helpers;
+using PostIt.Models;
using Yavsc.Api.Client;
namespace PostIt.ViewModels;
diff --git a/src/PostIt/PostIt/ViewModels/Activity/ProviderOngoingRequestsPageViewModel.cs b/src/PostIt/PostIt/ViewModels/Activity/ProviderOngoingRequestsPageViewModel.cs
index 7fd84fd88..360bf54ad 100644
--- a/src/PostIt/PostIt/ViewModels/Activity/ProviderOngoingRequestsPageViewModel.cs
+++ b/src/PostIt/PostIt/ViewModels/Activity/ProviderOngoingRequestsPageViewModel.cs
@@ -13,6 +13,7 @@ using PostIt.Helpers;
using Yavsc;
using Yavsc.Abstract.Workflow;
using Yavsc.Api.Client;
+using PostIt.Models;
namespace PostIt.ViewModels;
diff --git a/src/PostIt/PostIt/ViewModels/Blogs/BlogsViewModel.cs b/src/PostIt/PostIt/ViewModels/Blogs/BlogsViewModel.cs
index a1e016e7f..6fe6eccc9 100644
--- a/src/PostIt/PostIt/ViewModels/Blogs/BlogsViewModel.cs
+++ b/src/PostIt/PostIt/ViewModels/Blogs/BlogsViewModel.cs
@@ -12,6 +12,7 @@ using Yavsc.Api.Client;
using Yavsc.Abstract.Files;
using PostIt.Helpers;
using AvaloniaEdit.Document;
+using PostIt.Models;
namespace PostIt.ViewModels;
diff --git a/src/PostIt/PostIt/ViewModels/Chat/ChatViewModel.cs b/src/PostIt/PostIt/ViewModels/Chat/ChatViewModel.cs
index 8a70b507d..e72f07655 100644
--- a/src/PostIt/PostIt/ViewModels/Chat/ChatViewModel.cs
+++ b/src/PostIt/PostIt/ViewModels/Chat/ChatViewModel.cs
@@ -4,18 +4,37 @@ using System.Threading.Tasks;
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using Microsoft.AspNetCore.SignalR.Client;
+using Microsoft.Extensions.DependencyInjection;
+using PostIt.Models;
+using PostIt.Services;
+using Yavsc;
namespace PostIt.ViewModels.Chat
{
+ ///
+ /// ViewModel pour la gestion du chat,
+ /// incluant la connexion au Hub SignalR,
+ /// la gestion des salons et des utilisateurs connectés.
+ ///
public partial class ChatViewModel : ViewModelBase
{
+ private readonly Settings _settings;
+ private readonly YavscApiClient? _api;
+
+ // Le paramètre optionnel permet l'instanciation design-time
+ // (Design.DataContext dans ChatPage.axaml) sans conteneur DI.
+ public ChatViewModel(YavscApiClient? api = null)
+ {
+ var app = App.Current as App;
+ _settings = app!.ServiceProvider!.GetRequiredService(); // Assurez-vous que _settings est initialisé avant utilisation.
+ _api = api;
+ Status = new StatusNotice("Déconnecté", StatusSeverity.Info,
+ new RelayCheckCommand("Connecter", async () => await ConnectAsync()));
+ }
+
private HubConnection? _connection;
- [ObservableProperty]
- public partial string ServerUrl { get; protected set; } = "https://yavsc.pschneider.fr/chathub";
-
-
[ObservableProperty]
public partial string CurrentRoom { get; set; } = "General";
@@ -24,7 +43,6 @@ namespace PostIt.ViewModels.Chat
[ObservableProperty]
public partial StatusNotice Status { get; set; }
- = new StatusNotice("Déconnecté", StatusSeverity.Info);
[ObservableProperty]
public partial bool IsConnected { get; set; } = false;
@@ -40,20 +58,61 @@ namespace PostIt.ViewModels.Chat
[RelayCommand]
public async Task JoinRoomCommand() => await JoinRoomAsync();
- [RelayCommand]
- public async Task ChangeNickCommand() => await ChangeNickAsync();
-
public override bool CanNavigateNext { get; protected set; } = false;
public override bool CanNavigatePrevious { get; protected set; } = true;
+ private async Task DisconnectAsync()
+ {
+ if (_connection != null)
+ {
+ await _connection.StopAsync();
+ await _connection.DisposeAsync();
+ _connection = null;
+ }
+ IsConnected = false;
+ Status = new StatusNotice("Déconnecté", StatusSeverity.Info,
+ new RelayCheckCommand("Connecter", async () => await ConnectAsync()));
+ }
+
private async Task ConnectAsync()
{
try
{
- Status = new StatusNotice("Connexion en cours...", StatusSeverity.Info);
+ Status = new StatusNotice("Connexion en cours...", StatusSeverity.Info,
+ new RelayCheckCommand("Vérifier la connexion", async () => await CheckConnectionAsync()));
+
+ if (_api == null || !_api.HasValidSession)
+ {
+ Status = new StatusNotice("Session expirée : reconnectez-vous avant d'ouvrir le chat.", StatusSeverity.Error,
+ new RelayCheckCommand("Reconnecter", async () => await ConnectAsync()));
+ return;
+ }
+
+ // Le hub est mappé à la racine du service ("/chathub"),
+ // pas sous le préfixe versionné "/api/v1" : on le retire.
+ var hubBase = _settings.ApiUrl.TrimEnd('/');
+ if (hubBase.EndsWith("/api/v1", StringComparison.OrdinalIgnoreCase))
+ hubBase = hubBase[..^"/api/v1".Length];
+ var hubUrl = hubBase + "/" + Constants.ChatHubPath;
_connection = new HubConnectionBuilder()
- .WithUrl(ServerUrl)
+ .WithUrl(hubUrl,
+
+ options =>
+ {
+ // Le hub est [Authorize] : on attache le Bearer OIDC.
+ // AccessTokenProvider est rappelé à chaque reconnexion,
+ // donc on tente un refresh silencieux Ă chaque appel.
+ // Un refresh mort (invalid_grant) ne doit pas faire
+ // échouer StartAsync avec une exception interne : on
+ // renvoie le token courant (éventuellement expiré) et
+ // le serveur répondra un 401 propre, surfacé à l'UI.
+ options.AccessTokenProvider = async () =>
+ {
+ await _api.TrySilentLoginAsync();
+ return _api.CurrentAccessToken;
+ };
+ })
.WithAutomaticReconnect()
.Build();
@@ -88,15 +147,20 @@ namespace PostIt.ViewModels.Chat
await _connection.StartAsync();
IsConnected = true;
- Status = new StatusNotice("Connecté au Hub SignalR", StatusSeverity.Info);
+ Status = new StatusNotice("Connecté au Hub SignalR", StatusSeverity.Info, new RelayCheckCommand("Déconnecter", async () => await DisconnectAsync()));
}
catch (Exception ex)
{
- Status = new StatusNotice($"Erreur : {ex.Message}", StatusSeverity.Error);
+ Status = new StatusNotice($"Erreur : {ex.Message}", StatusSeverity.Error, new RelayCheckCommand("Reconnecter", async () => await ConnectAsync()));
IsConnected = false;
}
}
+ private async Task CheckConnectionAsync()
+ {
+ throw new NotImplementedException();
+ }
+
private async Task JoinRoomAsync()
{
if (_connection == null || string.IsNullOrWhiteSpace(CurrentRoom)) return;
@@ -115,21 +179,5 @@ namespace PostIt.ViewModels.Chat
Messages.Add($"Erreur Join: {ex.Message}");
}
}
-
- private async Task ChangeNickAsync()
- {
- if (_connection == null || string.IsNullOrWhiteSpace(NickName)) return;
-
- try
- {
- // Appel de la méthode publique 'Nick' du Hub (void)
- await _connection.InvokeAsync("Nick", NickName);
- Messages.Add($"Demande de changement de pseudo vers '{NickName}' envoyée.");
- }
- catch (Exception ex)
- {
- Messages.Add($"Erreur Nick: {ex.Message}");
- }
- }
}
}
diff --git a/src/PostIt/PostIt/ViewModels/Chat/RelayCheckCommand.cs b/src/PostIt/PostIt/ViewModels/Chat/RelayCheckCommand.cs
new file mode 100644
index 000000000..909d7a859
--- /dev/null
+++ b/src/PostIt/PostIt/ViewModels/Chat/RelayCheckCommand.cs
@@ -0,0 +1,33 @@
+using System;
+using System.Threading.Tasks;
+using System.Windows.Input;
+
+namespace PostIt.ViewModels.Chat
+{
+ internal class RelayCheckCommand : ICommand, IWithLabel
+ {
+ public string Label { get; }
+ private Func value;
+
+ public RelayCheckCommand(string v, Func value)
+ {
+ this.Label = v;
+ this.value = value;
+ }
+
+ public event EventHandler? CanExecuteChanged;
+
+ public bool CanExecute(object? parameter)
+ {
+ return value != null;
+ }
+
+ public void Execute(object? parameter)
+ {
+ if (value != null)
+ {
+ _ = value();
+ }
+ }
+ }
+}
diff --git a/src/PostIt/PostIt/ViewModels/Commands/BillingCommandPageViewModel.cs b/src/PostIt/PostIt/ViewModels/Commands/BillingCommandPageViewModel.cs
index 5ad2b08f4..4898c9560 100644
--- a/src/PostIt/PostIt/ViewModels/Commands/BillingCommandPageViewModel.cs
+++ b/src/PostIt/PostIt/ViewModels/Commands/BillingCommandPageViewModel.cs
@@ -2,6 +2,7 @@ using System;
using System.Threading.Tasks;
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
+using PostIt.Models;
using Yavsc;
using Yavsc.Abstract.Workflow;
using Yavsc.Api.Client;
diff --git a/src/PostIt/PostIt/ViewModels/Commands/BrushViewModel.cs b/src/PostIt/PostIt/ViewModels/Commands/BrushViewModel.cs
index 72d9ce8ea..1b1847e96 100644
--- a/src/PostIt/PostIt/ViewModels/Commands/BrushViewModel.cs
+++ b/src/PostIt/PostIt/ViewModels/Commands/BrushViewModel.cs
@@ -6,6 +6,7 @@ using System.Net;
using System.Net.Http;
using System.Threading.Tasks;
using CommunityToolkit.Mvvm.ComponentModel;
+using PostIt.Models;
using Yavsc.Abstract.Workflow;
using Yavsc.Api.Client;
using Yavsc.Models.Billing;
diff --git a/src/PostIt/PostIt/ViewModels/Layout/ActionStatusViewModelExtensions.cs b/src/PostIt/PostIt/ViewModels/Layout/ActionStatusViewModelExtensions.cs
index 614d477c8..9fe286ac0 100644
--- a/src/PostIt/PostIt/ViewModels/Layout/ActionStatusViewModelExtensions.cs
+++ b/src/PostIt/PostIt/ViewModels/Layout/ActionStatusViewModelExtensions.cs
@@ -1,3 +1,5 @@
+using PostIt.Models;
+
namespace PostIt.ViewModels;
public interface IActionStatusViewModel
@@ -29,4 +31,4 @@ public static class ActionStatusViewModelExtensions
_ => StatusNotice.Info(normalizedMessage),
};
}
-}
\ No newline at end of file
+}
diff --git a/src/PostIt/PostIt/ViewModels/MyFiles/MyFilesViewModel.cs b/src/PostIt/PostIt/ViewModels/MyFiles/MyFilesViewModel.cs
index cc4b46828..169b29b16 100644
--- a/src/PostIt/PostIt/ViewModels/MyFiles/MyFilesViewModel.cs
+++ b/src/PostIt/PostIt/ViewModels/MyFiles/MyFilesViewModel.cs
@@ -7,6 +7,7 @@ using Avalonia;
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using PostIt.Helpers;
+using PostIt.Models;
using Yavsc.Api.Client;
namespace PostIt.ViewModels;
@@ -226,4 +227,4 @@ public partial class MyFilesViewModel : ViewModelBase, IActionStatusViewModel
var idx = current.LastIndexOf('/');
return idx < 0 ? string.Empty : current[..idx];
}
-}
\ No newline at end of file
+}
diff --git a/src/PostIt/PostIt/ViewModels/Settings/Settings.cs b/src/PostIt/PostIt/ViewModels/Settings/Settings.cs
index c034437b8..72eea5d35 100644
--- a/src/PostIt/PostIt/ViewModels/Settings/Settings.cs
+++ b/src/PostIt/PostIt/ViewModels/Settings/Settings.cs
@@ -9,6 +9,7 @@ using System.Net.Http;
using System.Text.Json;
using System.Text.Json.Serialization;
using System.Globalization;
+using PostIt.Models;
[assembly: InternalsVisibleTo("PostIt.Tests")]
diff --git a/src/PostIt/PostIt/ViewModels/StatusNotice.cs b/src/PostIt/PostIt/ViewModels/StatusNotice.cs
new file mode 100644
index 000000000..a14f1a87b
--- /dev/null
+++ b/src/PostIt/PostIt/ViewModels/StatusNotice.cs
@@ -0,0 +1,43 @@
+using System.Windows.Input;
+using PostIt.Models;
+
+namespace PostIt.ViewModels;
+
+public sealed class StatusNotice
+{
+ public string Message { get; }
+ public StatusSeverity Severity { get; }
+ public string Glyph { get; }
+ public string Background { get; }
+ public string BorderBrush { get; }
+ public string Foreground { get; }
+
+ public bool HasCheckCommand { get; }
+
+ public ICommand? CheckCommand { get; }
+
+ public string CheckCommandLabel { get; }
+
+ public StatusNotice(string message, StatusSeverity severity, ICommand? checkCommand)
+ {
+ Message = string.IsNullOrWhiteSpace(message) ? "Pret." : message;
+ Severity = severity;
+
+ (Glyph, Background, BorderBrush, Foreground) = severity switch
+ {
+ StatusSeverity.Error => ("!", "#7F1D1D", "#C62828", "#e1f0f6"),
+ StatusSeverity.Warning => ("~", "#7C4A03", "#E6A700", "#eaeaea"),
+ _ => ("i", "#E8F0FE", "#5B8DEF", "#1E3A8A"),
+ };
+ HasCheckCommand = checkCommand != null;
+ CheckCommand = checkCommand;
+ CheckCommandLabel = HasCheckCommand ? "Check" :
+ checkCommand == null ?
+ string.Empty :
+ checkCommand is IWithLabel labeled ? labeled.Label : string.Empty;
+ }
+
+ public static StatusNotice Info(string message, ICommand? checkCommand = null) => new(message, StatusSeverity.Info, checkCommand);
+ public static StatusNotice Warning(string message, ICommand? checkCommand = null) => new(message, StatusSeverity.Warning, checkCommand);
+ public static StatusNotice Error(string message, ICommand? checkCommand = null) => new(message, StatusSeverity.Error, checkCommand);
+}
diff --git a/src/PostIt/PostIt/Views/Chat/ChatPage.axaml b/src/PostIt/PostIt/Views/Chat/ChatPage.axaml
index 0ac7e818c..55251f544 100644
--- a/src/PostIt/PostIt/Views/Chat/ChatPage.axaml
+++ b/src/PostIt/PostIt/Views/Chat/ChatPage.axaml
@@ -1,4 +1,5 @@
+ x:DataType="vm:ChatViewModel"
+ >
+
+
+
-
+
-
+
-
-
-
-
-
-
+
+
+
+
+
+
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
+
+
+
+
+
-
-
+
+
+
+
diff --git a/src/PostIt/PostIt/Views/Chat/ChatPage.axaml.cs b/src/PostIt/PostIt/Views/Chat/ChatPage.axaml.cs
index 5be61b86c..f73e1f827 100644
--- a/src/PostIt/PostIt/Views/Chat/ChatPage.axaml.cs
+++ b/src/PostIt/PostIt/Views/Chat/ChatPage.axaml.cs
@@ -7,4 +7,5 @@ public partial class ChatPage : ContentPage
{
InitializeComponent();
}
+
}
diff --git a/src/PostIt/PostIt/Views/Layout/MainView.axaml b/src/PostIt/PostIt/Views/Layout/MainView.axaml
index 92f53eb54..94b1d98bc 100644
--- a/src/PostIt/PostIt/Views/Layout/MainView.axaml
+++ b/src/PostIt/PostIt/Views/Layout/MainView.axaml
@@ -16,6 +16,7 @@
diff --git a/src/PostIt/PostIt/Views/Layout/SettingsPage.axaml.cs b/src/PostIt/PostIt/Views/Layout/SettingsPage.axaml.cs
index b50245919..9df94960d 100644
--- a/src/PostIt/PostIt/Views/Layout/SettingsPage.axaml.cs
+++ b/src/PostIt/PostIt/Views/Layout/SettingsPage.axaml.cs
@@ -8,6 +8,7 @@ using System.Threading.Tasks;
using Avalonia.Controls;
using Avalonia.Platform.Storage;
using Microsoft.Extensions.DependencyInjection;
+using PostIt.Models;
using PostIt.Services;
using PostIt.ViewModels;
diff --git a/src/Yavsc.Abstract/Chat/ChatHubConstants.cs b/src/Yavsc.Abstract/Chat/ChatHubConstants.cs
index c673e6fae..e51e77e63 100644
--- a/src/Yavsc.Abstract/Chat/ChatHubConstants.cs
+++ b/src/Yavsc.Abstract/Chat/ChatHubConstants.cs
@@ -4,10 +4,8 @@ namespace Yavsc.Abstract.Chat
{
public static class ChatHubConstants
{
- public const string HubGroupAuthenticated = "authenticated";
- public const string HubGroupAnonymous = "anonymous";
public const string HubGroupCops= "cops";
- public const string HubGroupRomsPrefix = "room_";
+ public const string HubGroupRoomsPrefix = "room_";
public const int MaxChanelName = 255;
public const string HubGroupFollowingPrefix = "fol ";
@@ -21,6 +19,6 @@ namespace Yavsc.Abstract.Chat
public const string HopWontKickOp = "Half operator cannot kick any operator";
public const string LabAuthChatUser = "Authenticated chat user";
public const string NoKickOnCop = "No, you won´t, you´ĺl never do kick a cop, it is the bad.";
- public const string LabNoJoinNoSend = "LabnoJoinNoSend";
+ public const string LabNoJoinNoSend = "LabNoJoinNoSend";
}
}
diff --git a/src/Yavsc.Abstract/Constants.cs b/src/Yavsc.Abstract/Constants.cs
index a2649491c..ca871f9d5 100644
--- a/src/Yavsc.Abstract/Constants.cs
+++ b/src/Yavsc.Abstract/Constants.cs
@@ -13,6 +13,7 @@ namespace Yavsc
public const string BlogTagPath = "blogtag";
public const string CirclePath = "circle";
public const string CommentsPath = "blogcomments";
+ public const string ChatHubPath = "chathub";
public static readonly Scope[] SiteScopes = {
new Scope { Id = "profile", Description = "Your profile informations" },
diff --git a/src/Yavsc.Api/Program.cs b/src/Yavsc.Api/Program.cs
index 8daff34d9..03c93e446 100644
--- a/src/Yavsc.Api/Program.cs
+++ b/src/Yavsc.Api/Program.cs
@@ -11,6 +11,7 @@ using Yavsc.Models;
using Yavsc;
using Yavsc.Server.Helpers;
using Yavsc.Services;
+using Yavsc.Server.Hubs;
internal class Program
{
@@ -114,13 +115,11 @@ internal class Program
.UseRouting()
.UseAuthentication()
.UseAuthorization()
- .UseCors("default")
- ;
+ .UseCors("default");
app.MapIdentityApi().RequireAuthorization("ApiScope");
app.MapDefaultControllerRoute();
-
-
app.UseSession();
+ app.MapHub("/" + Constants.ChatHubPath);
await app.RunAsync();
}
}
diff --git a/src/Yavsc.Org/Controllers/Accounting/ManageController.cs b/src/Yavsc.Org/Controllers/Accounting/ManageController.cs
index e09bbb5a4..32357c2c5 100644
--- a/src/Yavsc.Org/Controllers/Accounting/ManageController.cs
+++ b/src/Yavsc.Org/Controllers/Accounting/ManageController.cs
@@ -400,7 +400,7 @@ namespace Yavsc.Controllers
public IActionResult SetUserName()
{
- return View(new SetUserNameViewModel() { UserName = User.Identity.Name });
+ return View(new SetUserNameViewModel() { UserName = User.GetUserName() });
}
[HttpPost]
diff --git a/src/Yavsc.Org/Extensions/HostingExtensions.cs b/src/Yavsc.Org/Extensions/HostingExtensions.cs
index cc593b860..563a74789 100644
--- a/src/Yavsc.Org/Extensions/HostingExtensions.cs
+++ b/src/Yavsc.Org/Extensions/HostingExtensions.cs
@@ -1053,8 +1053,6 @@ public static class HostingExtensions
app.UseCors("default");
app.MapDefaultControllerRoute();
app.MapStaticAssets(staticAssetsManifestPath);
- //app.MapRazorPages();
- app.MapHub("/chathub");
WorkflowHelpers.ConfigureBillingService();
diff --git a/src/Yavsc.Server/Helpers/ServiceExtensions.cs b/src/Yavsc.Server/Helpers/ServiceExtensions.cs
index 397eada85..db5dbe983 100644
--- a/src/Yavsc.Server/Helpers/ServiceExtensions.cs
+++ b/src/Yavsc.Server/Helpers/ServiceExtensions.cs
@@ -128,7 +128,29 @@ public static class ServiceExtensions
options.ClaimsIssuer = authority;
options.Audience = audiences[0];
+ // Sending the access token in the query string is required when using WebSockets or ServerSentEvents
+ // due to a limitation in Browser APIs. We restrict it to only calls to the
+ // SignalR hub in this code.
+ // See https://docs.microsoft.com/aspnet/core/signalr/security#access-token-logging
+ // for more information about security considerations when using
+ // the query string to transmit the access token.
+ options.Events = new JwtBearerEvents
+ {
+ OnMessageReceived = context =>
+ {
+ var accessToken = context.Request.Query["access_token"];
+ // If the request is for our hub...
+ var path = context.HttpContext.Request.Path;
+ if (!string.IsNullOrEmpty(accessToken) &&
+ (path.StartsWithSegments("/hubs/chat")))
+ {
+ // Read the token out of the query string
+ context.Token = accessToken;
+ }
+ return Task.CompletedTask;
+ }
+ };
// Dev: every Yavsc resource service (Yavsc.Api, Yavsc.Blogs,
// Yavsc.Org itself) validates JWTs against the OP that runs
// on https://localhost:5001 with a self-signed dev cert.
diff --git a/src/Yavsc.Server/Hubs/ChatHub.cs b/src/Yavsc.Server/Hubs/ChatHub.cs
index 799f7441c..61640b7e3 100644
--- a/src/Yavsc.Server/Hubs/ChatHub.cs
+++ b/src/Yavsc.Server/Hubs/ChatHub.cs
@@ -24,6 +24,7 @@
using Microsoft.AspNetCore.SignalR;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Localization;
+
#pragma warning disable CS4014 // Dans la mesure où cet appel n'est pas attendu, l'exécution de la méthode actuelle continue avant la fin de l'appel
namespace Yavsc.Server.Hubs
@@ -36,6 +37,8 @@ namespace Yavsc.Server.Hubs
using Yavsc.Models.Chat;
using Yavsc.Server.Helpers;
using Yavsc.Services;
+
+ [Authorize]
public partial class ChatHub : Hub, IDisposable
{
private readonly ApplicationDbContext _dbContext;
@@ -53,100 +56,70 @@ namespace Yavsc.Server.Hubs
_dbContext = dbContext;
_localizer = stringLocalizerFactory.Create(typeof(ChatHub));
- _cxManager = connexionManager;
- _cxManager.SetErrorHandler ((context, error) =>
+ _cxManager = connexionManager;
+ _cxManager.SetErrorHandler((context, error) =>
{
NotifyUser(NotificationTypes.Error, context, error);
});
_logger = loggerFactory.CreateLogger();
- InputValidator = new HubInputValidator(_localizer) {
+ InputValidator = new HubInputValidator(_localizer)
+ {
- NotifyUser = async (type, target, msg) => await this.NotifyUser(type, target, msg) };
- }
-
- void SetUserName(string cxId, string userName)
- {
- _cxManager.SetUserName(cxId, userName);
+ NotifyUser = async (type, target, msg) => await this.NotifyUser(type, target, msg)
+ };
}
public override async Task OnConnectedAsync()
{
- bool isAuth = Context.User?.Identity?.IsAuthenticated ?? false;
+ var user = Context.User;
bool isCop = false;
- string userName = setUserName();
- if (isAuth)
+ string userName = user.GetUserName();
+
+ _logger.LogInformation(_localizer.GetString(ChatHubConstants.LabAuthChatUser));
+
+ var userId = _dbContext.Users.First(u => u.UserName == userName).Id;
+
+ await Clients.Group(ChatHubConstants.HubGroupFollowingPrefix + userId).SendAsync("notifyUser", NotificationTypes.Connected, userName, null);
+ isCop = Context.User.IsInMsRole(Constants.AdminGroupName);
+ if (isCop)
{
-
- var group = isAuth ?
- ChatHubConstants.HubGroupAuthenticated : ChatHubConstants.HubGroupAnonymous;
- // Log ("Cx: " + group);
- await Groups.AddToGroupAsync(Context.ConnectionId, group);
- _logger.LogInformation(_localizer.GetString(ChatHubConstants.LabAuthChatUser));
-
- var userId = _dbContext.Users.First(u => u.UserName == Context.User.Identity.Name).Id;
-
- await Clients.Group(ChatHubConstants.HubGroupFollowingPrefix + userId).SendAsync("notifyUser", NotificationTypes.Connected, userName, null);
- isCop = Context.User.IsInMsRole(Constants.AdminGroupName) ;
- if (isCop)
- {
- await Groups.AddToGroupAsync(Context.ConnectionId, ChatHubConstants.HubGroupCops);
- }
-
- foreach (var uid in _dbContext.CircleMembers.Select(m => m.MemberId))
- {
- await Groups.AddToGroupAsync(Context.ConnectionId, ChatHubConstants.HubGroupFollowingPrefix + uid);
- }
+ await Groups.AddToGroupAsync(Context.ConnectionId, ChatHubConstants.HubGroupCops);
}
- else
+
+ foreach (var uid in _dbContext.CircleMembers.Select(m => m.MemberId))
{
- await Groups.AddToGroupAsync(Context.ConnectionId, ChatHubConstants.HubGroupAnonymous);
+ await Groups.AddToGroupAsync(Context.ConnectionId, ChatHubConstants.HubGroupFollowingPrefix + uid);
}
_cxManager.OnConnected(Context.ConnectionId, isCop);
await base.OnConnectedAsync();
}
- string setUserName(string queryUname = "anon")
- {
- if (Context.User != null)
- if (Context.User.Identity.IsAuthenticated)
- {
- SetUserName(Context.ConnectionId, Context.User.Identity.Name);
- return Context.User.Identity.Name;
- }
- anonymousSequence++;
- var anonymousName = $"{ChatHubConstants.AnonymousUserNamePrefix}{queryUname}{anonymousSequence}";
- SetUserName(Context.ConnectionId, anonymousName);
- return anonymousName;
- }
-
- static long anonymousSequence = 0;
-
public override async Task OnDisconnectedAsync(Exception ex)
{
- string userName = Context.User?.Identity.Name;
+ string userName = Context.User?.GetUserName();
if (userName != null)
{
var user = _dbContext.Users.FirstOrDefault(u => u.UserName == userName);
- var userId = user.Id;
- await Clients.Group(ChatHubConstants.HubGroupFollowingPrefix + userId).SendAsync("notifyUser", NotificationTypes.DisConnected, userName, null);
+ if (user != null)
+ {
+ var userId = user.Id;
+ await Clients.Group(ChatHubConstants.HubGroupFollowingPrefix + userId).SendAsync("notifyUser", NotificationTypes.DisConnected, userName, null);
+ }
_cxManager.OnDisconnected(Context.ConnectionId);
}
- await base.OnDisconnectedAsync(ex);
+ await base.OnDisconnectedAsync(ex);
}
-
- public async Task Nick(string nickName)
+ ///
+ /// Renvoie le login résolu côté serveur (claim name de
+ /// l'organisation Yavsc.Org, via ).
+ /// Permet au client d'afficher l'identité réellement authentifiée,
+ /// sans jamais faire confiance Ă un pseudo fourni par le client.
+ ///
+ public string WhoAmI()
{
- if (!InputValidator.ValidateUserName(nickName)) return;
-
- var candidate = "?" + nickName;
- if (_cxManager.IsConnected(candidate))
- {
- await NotifyUser(NotificationTypes.ExistingUserName, nickName, "aborting");
- return;
- }
- _cxManager.SetUserName( Context.ConnectionId, candidate);
+ return Context.User?.GetUserName() ?? string.Empty;
}
bool IsPresent(string roomName, string userName)
@@ -159,11 +132,11 @@ namespace Yavsc.Server.Hubs
_logger.LogInformation($"Join:{roomName}");
if (!InputValidator.ValidateRoomName(roomName))
{
- _logger.LogError("!InputValidator.ValidateRoomName(roomName)");
+ _logger.LogError("!InputValidator.ValidateRoomName(roomName)");
return null;
}
- var roomGroupName = ChatHubConstants.HubGroupRomsPrefix + roomName;
+ var roomGroupName = ChatHubConstants.HubGroupRoomsPrefix + roomName;
var user = _cxManager.GetUserName(Context.ConnectionId);
await Groups.AddToGroupAsync(Context.ConnectionId, roomGroupName);
ChatRoomInfo channelInfo;
@@ -172,7 +145,9 @@ namespace Yavsc.Server.Hubs
_logger.LogInformation($"Joining");
channelInfo = _cxManager.Join(roomName, Context.ConnectionId);
await Clients.Group(roomGroupName).SendAsync("notifyRoom", NotificationTypes.UserJoin, roomName, user);
- } else {
+ }
+ else
+ {
_logger.LogInformation($"already present");
// in case in an additional connection,
// one only send info on room without
@@ -185,14 +160,13 @@ namespace Yavsc.Server.Hubs
return channelInfo;
}
- [Authorize]
public void Register(string room)
{
- if (!InputValidator.ValidateRoomName(room)) return ;
+ if (!InputValidator.ValidateRoomName(room)) return;
var existent = _dbContext.ChatRoom.Any(r => r.Name == room);
if (existent)
{
- NotifyUserInRoom(NotificationTypes.Error, room, "already registered.");
+ NotifyUserInRoom(NotificationTypes.Error, room, "already registered.");
return;
}
Debug.Assert(Context.User != null);
@@ -212,27 +186,25 @@ namespace Yavsc.Server.Hubs
_dbContext.SaveChanges(user.Id);
}
- [Authorize]
- public void KickBan(string roomName, string userName, string reason)
+ public void KickBan(string roomName, string userName, string reason)
{
- if (!InputValidator.ValidateRoomName(roomName)) return ;
- if (!InputValidator.ValidateUserName(userName)) return ;
+ if (!InputValidator.ValidateRoomName(roomName)) return;
+ if (!InputValidator.ValidateUserName(userName)) return;
if (!InputValidator.ValidateReason(reason)) return;
Kick(roomName, userName, reason);
Ban(roomName, userName, reason);
}
- [Authorize]
- public async Task Kick(string roomName, string userName, string reason)
+ public async Task Kick(string roomName, string userName, string reason)
{
- if (!InputValidator.ValidateRoomName(roomName)) return ;
- if (!InputValidator.ValidateUserName(userName)) return ;
+ if (!InputValidator.ValidateRoomName(roomName)) return;
+ if (!InputValidator.ValidateUserName(userName)) return;
if (!InputValidator.ValidateReason(reason)) return;
ChatRoomInfo channelInfo;
- var roomGroupName = ChatHubConstants.HubGroupRomsPrefix + roomName;
+ var roomGroupName = ChatHubConstants.HubGroupRoomsPrefix + roomName;
if (_cxManager.TryGetChanInfo(roomName, out channelInfo))
{
- if (!_cxManager.IsPresent(roomName,userName))
+ if (!_cxManager.IsPresent(roomName, userName))
{
NotifyErrorToCallerInRoom(roomName, $"{userName} was not found in {roomName}.");
return;
@@ -242,44 +214,44 @@ namespace Yavsc.Server.Hubs
if (!_cxManager.Kick(Context.ConnectionId, userName, roomName, reason)) return;
}
var cxIds = _cxManager.GetConnexionIds(userName);
- if (cxIds!=null) foreach(var cx in cxIds)
+ if (cxIds != null) foreach (var cx in cxIds)
await Groups.RemoveFromGroupAsync(cx, roomGroupName);
await Clients.Group(roomGroupName).SendAsync("notifyRoom", NotificationTypes.Kick, roomName, $"{userName}: {reason}");
}
- [Authorize]
- public void Ban(string roomName, string userName, string reason)
+ public void Ban(string roomName, string userName, string reason)
{
- if (!InputValidator.ValidateRoomName(roomName)) return ;
- if (!InputValidator.ValidateUserName(userName)) return ;
+ if (!InputValidator.ValidateRoomName(roomName)) return;
+ if (!InputValidator.ValidateUserName(userName)) return;
if (!InputValidator.ValidateReason(reason)) return;
var cxIds = _cxManager.GetConnexionIds(userName);
throw new NotImplementedException();
}
- [Authorize]
- public void GLine(string userName, string reason)
+ [Authorize(Constants.AdminGroupName)]
+ public void GLine(string userName, string reason)
{
- if (!InputValidator.ValidateUserName(userName)) return ;
+ if (!InputValidator.ValidateUserName(userName)) return;
if (!InputValidator.ValidateReason(reason)) return;
throw new NotImplementedException();
}
- public void Part(string roomName, string reason)
+ public void Part(string roomName, string reason)
{
- if (!InputValidator.ValidateRoomName(roomName)) return ;
+ if (!InputValidator.ValidateRoomName(roomName)) return;
if (!InputValidator.ValidateReason(reason)) return;
- if (_cxManager.Part(Context.ConnectionId, roomName, reason))
- {
- var roomGroupName = ChatHubConstants.HubGroupRomsPrefix + roomName;
+ if (_cxManager.Part(Context.ConnectionId, roomName, reason))
+ {
+ var roomGroupName = ChatHubConstants.HubGroupRoomsPrefix + roomName;
var group = Clients.Group(roomGroupName);
var userName = _cxManager.GetUserName(Context.ConnectionId);
group.SendAsync("notifyRoom", NotificationTypes.UserPart, roomName, $"{userName}: {reason}");
Groups.RemoveFromGroupAsync(Context.ConnectionId, roomGroupName);
- }
- else {
- _logger.LogError("Could not part");
- }
+ }
+ else
+ {
+ _logger.LogError("Could not part");
+ }
}
void NotifyErrorToCallerInRoom(string room, string reason)
@@ -288,19 +260,21 @@ namespace Yavsc.Server.Hubs
_logger.LogError($"NotifyErrorToCallerInRoom: {room}, {reason}");
}
- public async Task Send(string roomName, string message)
+ public async Task Send(string roomName, string message)
{
_logger.LogInformation($"Send {roomName} {message}");
- if (!InputValidator.ValidateRoomName(roomName)) {
+ if (!InputValidator.ValidateRoomName(roomName))
+ {
_logger.LogError($"Invalid roomName : {roomName}");
- return ;
+ return;
}
- if (!InputValidator.ValidateMessage(message)) {
+ if (!InputValidator.ValidateMessage(message))
+ {
_logger.LogError($"Invalid message : {message}");
- return ;
+ return;
}
- var groupName = ChatHubConstants.HubGroupRomsPrefix + roomName;
- ChatRoomInfo channelInfo ;
+ var groupName = ChatHubConstants.HubGroupRoomsPrefix + roomName;
+ ChatRoomInfo channelInfo;
if (!_cxManager.TryGetChanInfo(roomName, out channelInfo))
{
_logger.LogError($"No such room : {roomName}");
@@ -317,7 +291,7 @@ namespace Yavsc.Server.Hubs
return;
}
var group = Clients.Group(groupName);
- var msg = new { Name = userName, Room = roomName, Message = message};
+ var msg = new { Name = userName, Room = roomName, Message = message };
await group.SendAsync("ReceiveMessage", msg);
}
@@ -332,8 +306,7 @@ namespace Yavsc.Server.Hubs
await Clients.Caller.SendAsync("notifyUserInRoom", type, room, message);
}
- [Authorize]
- public async Task SendPV(string userName, string message)
+ public async Task SendPV(string userName, string message)
{
// Authorized code
Debug.Assert(Context.User != null);
@@ -342,17 +315,17 @@ namespace Yavsc.Server.Hubs
if (!InputValidator.ValidateUserName(userName))
{
_logger.LogError($"Invalid username : {userName}");
- return ;
+ return;
}
if (!InputValidator.ValidateMessage(message))
{
_logger.LogError($"Invalid message : {message}");
- return ;
+ return;
}
_logger.LogInformation($"Message form is validated.");
- var identityUserName = Context.User.GetUserName();
+ var identityUserName = Context.User.GetUserName();
- if (userName[0] != '?' && Context.User!=null)
+ if (userName[0] != '?' && Context.User != null)
if (!Context.User.IsInMsRole(Constants.AdminGroupName))
{
@@ -373,7 +346,7 @@ namespace Yavsc.Server.Hubs
_logger.LogInformation("getting cx id´s");
var cxIds = _cxManager.GetConnexionIds(userName);
- if (cxIds==null || cxIds.Count()==0)
+ if (cxIds == null || cxIds.Count() == 0)
_logger.LogError($"No such connected user : {userName}");
else foreach (var connectionId in cxIds)
{
@@ -385,18 +358,18 @@ namespace Yavsc.Server.Hubs
}
}
- [Authorize]
- public async Task SendStream(string connectionId, long streamId, string message)
+ public async Task SendStream(string connectionId, long streamId, string message)
{
// Authorized code
Debug.Assert(Context.User != null);
Debug.Assert(Context.User.Identity != null);
if (!InputValidator.ValidateMessage(message)) return;
- var sender = Context.User.Identity.Name;
+ var sender = Context.User.GetUserName();
var cli = Clients.Client(connectionId);
await cli.SendAsync("addStreamInfo", sender, streamId, message);
}
}
}
-#pragma warning restore CS4014 // Dans la mesure où cet appel n'est pas attendu, l'exécution de la méthode actuelle continue avant la fin de l'appel
+
+#pragma warning restore CS4014
diff --git a/src/Yavsc.Server/Interfaces/IConnexionManager.cs b/src/Yavsc.Server/Interfaces/IConnexionManager.cs
index 434054249..cf7c601e1 100644
--- a/src/Yavsc.Server/Interfaces/IConnexionManager.cs
+++ b/src/Yavsc.Server/Interfaces/IConnexionManager.cs
@@ -3,8 +3,6 @@ using Yavsc.ViewModels.Chat;
namespace Yavsc.Services
{
public interface IConnexionManager {
- void SetUserName(string cxId, string userName);
-
string GetUserName (string cxId);
void OnConnected(string cxId, bool isCop);
bool IsConnected(string candidate);
diff --git a/src/Yavsc.Server/Services/HubConnectionManager.cs b/src/Yavsc.Server/Services/HubConnectionManager.cs
index 05ed49dda..e442151a1 100644
--- a/src/Yavsc.Server/Services/HubConnectionManager.cs
+++ b/src/Yavsc.Server/Services/HubConnectionManager.cs
@@ -53,23 +53,6 @@ namespace Yavsc.Services
_localizer = stringLocFactory.Create(typeof(HubConnectionManager));
}
- public void SetUserName(string cxId, string userName)
- {
- string oldUname;
- if (ChatUserNames.TryGetValue(cxId, out oldUname))
- {
- // this is a rename
- if (oldUname == userName) return;
- ChatCxIds[userName] = ChatCxIds[oldUname];
- ChatCxIds[oldUname] = null;
- }
- else
- {
- // this is a connexion
- ChatCxIds[userName] = new List() { cxId };
- }
- ChatUserNames[cxId] = userName;
- }
// Username must have been set before calling this method.
public void OnConnected(string cxId, bool isCop)
{