I refactored Govor.Console to use the command pattern. Here's what I did:

- I implemented a command-based architecture for Govor.Console.
- Each of your actions (e.g., login, send friend request, list friends) is now encapsulated in its own command class inheriting from BaseCommand.
- I integrated friend-related functionalities (search, list, send/accept/reject request, block/unblock) using a mix of SignalR Hub and REST API calls.
- I included admin functionalities for managing friendships (list all, list user's, remove).
- I added a /help (-h) command to display available commands and their usage.
- I refactored Program.cs to handle command parsing and execution.
- I updated FriendsClient.cs, removing methods now handled directly by commands via SignalR.
- I added SignalR event handlers for real-time notifications (friend requests, accepts, etc.).
This commit is contained in:
google-labs-jules[bot]
2025-07-11 05:47:22 +00:00
parent e8e2078514
commit b42c7d6de6
19 changed files with 1030 additions and 202 deletions
@@ -0,0 +1,41 @@
using System;
using System.Threading.Tasks;
namespace Govor.ConsoleClient.Commands
{
public class AcceptFriendRequestCommand : BaseCommand
{
public override async Task ExecuteAsync(string? argument)
{
if (!EnsureLoggedIn() || !EnsureHubConnection()) return;
Guid friendshipId;
if (string.IsNullOrWhiteSpace(argument) || !Guid.TryParse(argument, out friendshipId))
{
Console.Write("Введите ID заявки, которую хотите принять: ");
var input = Console.ReadLine();
if (string.IsNullOrWhiteSpace(input) || !Guid.TryParse(input, out friendshipId))
{
Console.WriteLine("[Ошибка] Неверный или пустой ID заявки.");
return;
}
}
try
{
// API uses Hub for this: AcceptFriendRequest(Guid friendshipId)
await HubConnection.InvokeAsync("AcceptFriendRequest", friendshipId);
Console.WriteLine("Заявка в друзья принята.");
}
catch (Exception ex)
{
Console.WriteLine($"[Ошибка принятия заявки] {ex.Message}");
}
}
public override string GetHelp()
{
return "/accept [ID_заявки] - Принять входящую заявку в друзья. Если ID не указан, запросит ввод.";
}
}
}
@@ -0,0 +1,60 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Net.Http.Json;
using System.Threading.Tasks;
using Govor.Contracts.DTOs; // Required for FriendshipDto
namespace Govor.ConsoleClient.Commands
{
public class AdminListAllFriendshipsCommand : BaseCommand
{
public override async Task ExecuteAsync(string? argument)
{
if (!EnsureLoggedIn()) return;
// Consider adding an admin role check here if possible,
// though the API itself is protected by [Authorize(Roles = "Admin")]
Console.WriteLine("Получение всех дружеских связей (только для администраторов)...");
try
{
var response = await HttpClientService.GetAsync("api/admin/Friendships");
if (response.StatusCode == System.Net.HttpStatusCode.Forbidden)
{
Console.WriteLine("[Ошибка] Доступ запрещен. Эта команда только для администраторов.");
return;
}
response.EnsureSuccessStatusCode();
var friendships = await response.Content.ReadFromJsonAsync<List<FriendshipDto>>();
if (friendships != null && friendships.Any())
{
Console.WriteLine("Все дружеские связи в системе:");
foreach (var f in friendships)
{
Console.WriteLine($"- ID: {f.Id}, Пользователь1: {f.RequesterId}, Пользователь2: {f.AddresseeId}, Статус: {f.Status}");
}
}
else
{
Console.WriteLine("Дружеские связи не найдены в системе.");
}
}
catch (HttpRequestException httpEx) when (httpEx.StatusCode == System.Net.HttpStatusCode.Forbidden)
{
Console.WriteLine("[Ошибка] Доступ запрещен. Эта команда только для администраторов.");
}
catch (Exception ex)
{
Console.WriteLine($"[Ошибка] {ex.Message}");
}
}
public override string GetHelp()
{
return "/adminlistallfs - (Админ) Показать все дружеские связи в системе.";
}
}
}
@@ -0,0 +1,70 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Net.Http.Json;
using System.Threading.Tasks;
using Govor.Contracts.DTOs; // Required for FriendshipDto
namespace Govor.ConsoleClient.Commands
{
public class AdminListUserFriendshipsCommand : BaseCommand
{
public override async Task ExecuteAsync(string? argument)
{
if (!EnsureLoggedIn()) return;
Guid userId;
if (string.IsNullOrWhiteSpace(argument) || !Guid.TryParse(argument, out userId))
{
Console.Write("Введите ID пользователя для просмотра его связей: ");
var input = Console.ReadLine();
if (string.IsNullOrWhiteSpace(input) || !Guid.TryParse(input, out userId))
{
Console.WriteLine("[Ошибка] Неверный или пустой ID пользователя.");
return;
}
}
Console.WriteLine($"Получение всех связей для пользователя {userId} (только для администраторов)...");
try
{
var response = await HttpClientService.GetAsync($"api/admin/Friendships/{userId}");
if (response.StatusCode == System.Net.HttpStatusCode.Forbidden)
{
Console.WriteLine("[Ошибка] Доступ запрещен. Эта команда только для администраторов.");
return;
}
response.EnsureSuccessStatusCode();
var friendships = await response.Content.ReadFromJsonAsync<List<FriendshipDto>>();
if (friendships != null && friendships.Any())
{
Console.WriteLine($"Дружеские связи для пользователя {userId}:");
foreach (var f in friendships)
{
Console.WriteLine($"- ID: {f.Id}, Пользователь1: {f.RequesterId}, Пользователь2: {f.AddresseeId}, Статус: {f.Status}");
}
}
else
{
Console.WriteLine($"Дружеские связи для пользователя {userId} не найдены.");
}
}
catch (HttpRequestException httpEx) when (httpEx.StatusCode == System.Net.HttpStatusCode.Forbidden)
{
Console.WriteLine("[Ошибка] Доступ запрещен. Эта команда только для администраторов.");
}
catch (Exception ex)
{
Console.WriteLine($"[Ошибка] {ex.Message}");
}
}
public override string GetHelp()
{
return "/adminlistuserfs [ID_пользователя] - (Админ) Показать все дружеские связи для указанного пользователя. Если ID не указан, запросит ввод.";
}
}
}
@@ -0,0 +1,64 @@
using System;
using System.Net.Http;
using System.Threading.Tasks;
namespace Govor.ConsoleClient.Commands
{
public class AdminRemoveFriendshipCommand : BaseCommand
{
public override async Task ExecuteAsync(string? argument)
{
if (!EnsureLoggedIn()) return;
Guid friendshipId;
if (string.IsNullOrWhiteSpace(argument) || !Guid.TryParse(argument, out friendshipId))
{
Console.Write("Введите ID дружеской связи для удаления: ");
var input = Console.ReadLine();
if (string.IsNullOrWhiteSpace(input) || !Guid.TryParse(input, out friendshipId))
{
Console.WriteLine("[Ошибка] Неверный или пустой ID связи.");
return;
}
}
Console.WriteLine($"Удаление дружеской связи {friendshipId} (только для администраторов)...");
try
{
// The API endpoint is: [HttpPost] public async Task<IActionResult> RemoveFriendship(Guid Id)
// It expects the Id in the query string, like: api/admin/Friendships?Id=GUID
// Or it might be a POST with x-www-form-urlencoded data or JSON body, need to check API implementation.
// Based on `[HttpPost] public async Task<IActionResult> RemoveFriendship(Guid Id)`, it's likely a query parameter or form data.
// Let's assume query parameter for now as it's simpler for HttpPost.
var response = await HttpClientService.PostAsync($"api/admin/Friendships?Id={friendshipId}", null);
if (response.StatusCode == System.Net.HttpStatusCode.Forbidden)
{
Console.WriteLine("[Ошибка] Доступ запрещен. Эта команда только для администраторов.");
return;
}
response.EnsureSuccessStatusCode();
Console.WriteLine($"Дружеская связь {friendshipId} успешно удалена.");
}
catch (HttpRequestException httpEx) when (httpEx.StatusCode == System.Net.HttpStatusCode.Forbidden)
{
Console.WriteLine("[Ошибка] Доступ запрещен. Эта команда только для администраторов.");
}
catch (HttpRequestException httpEx) when (httpEx.StatusCode == System.Net.HttpStatusCode.NotFound)
{
Console.WriteLine($"[Ошибка] Дружеская связь с ID {friendshipId} не найдена.");
}
catch (Exception ex)
{
Console.WriteLine($"[Ошибка] {ex.Message}");
}
}
public override string GetHelp()
{
return "/adminremovefs [ID_связи] - (Админ) Удалить дружескую связь по ее ID. Если ID не указан, запросит ввод.";
}
}
}
+65
View File
@@ -0,0 +1,65 @@
using System;
using System.Threading.Tasks;
namespace Govor.ConsoleClient.Commands
{
public abstract class BaseCommand : ICommand
{
protected static FriendsClient? FriendsClient { get; private set; }
protected static HttpClientService HttpClientService { get; private set; }
protected static Func<string?> GetAuthToken { get; private set; }
protected static Action<string> SetAuthToken { get; private set; }
protected static Func<Task> InitializeHubConnectionAsync { get; private set; }
protected static Microsoft.AspNetCore.SignalR.Client.HubConnection? HubConnection => _hubConnection?.Invoke();
private static Func<Microsoft.AspNetCore.SignalR.Client.HubConnection?> _hubConnection;
public static void InitializeServices(
FriendsClient? friendsClient,
HttpClientService httpClientService,
Func<string?> getAuthToken,
Action<string> setAuthToken,
Func<Task> initializeHubConnectionAsync,
Func<Microsoft.AspNetCore.SignalR.Client.HubConnection?> hubConnection)
{
FriendsClient = friendsClient;
HttpClientService = httpClientService;
GetAuthToken = getAuthToken;
SetAuthToken = setAuthToken;
InitializeHubConnectionAsync = initializeHubConnectionAsync;
_hubConnection = hubConnection;
}
public abstract Task ExecuteAsync(string? argument);
public abstract string GetHelp();
protected boolEnsureLoggedIn()
{
if (GetAuthToken() == null)
{
System.Console.WriteLine("[Ошибка] Сначала войдите в систему. Используйте /login или /reg.");
return false;
}
if (FriendsClient == null && !(this is LoginCommand || this is RegisterCommand)) // FriendsClient might not be needed for auth commands
{
// Attempt to re-initialize FriendsClient if token exists but client is null
// This can happen if the app was closed and token was persisted, but client was not re-instantiated.
// However, the current setup in Program.cs initializes FriendsClient after login/reg.
// This check is more of a safeguard.
System.Console.WriteLine("[Ошибка] Клиент для работы с друзьями не инициализирован. Попробуйте войти снова.");
return false;
}
return true;
}
protected boolEnsureHubConnection()
{
if (HubConnection == null || HubConnection.State != Microsoft.AspNetCore.SignalR.Client.HubConnectionState.Connected)
{
System.Console.WriteLine("[Ошибка] SignalR соединение не установлено. Попробуйте войти снова или проверьте соединение.");
return false;
}
return true;
}
}
}
@@ -0,0 +1,42 @@
using System;
using System.Threading.Tasks;
namespace Govor.ConsoleClient.Commands
{
public class BlockUserCommand : BaseCommand
{
public override async Task ExecuteAsync(string? argument)
{
if (!EnsureLoggedIn() || !EnsureHubConnection()) return;
Guid targetUserId;
if (string.IsNullOrWhiteSpace(argument) || !Guid.TryParse(argument, out targetUserId))
{
Console.Write("Введите ID пользователя, которого хотите заблокировать: ");
var input = Console.ReadLine();
if (string.IsNullOrWhiteSpace(input) || !Guid.TryParse(input, out targetUserId))
{
Console.WriteLine("[Ошибка] Неверный или пустой ID пользователя.");
return;
}
}
try
{
// API uses Hub for this: BlockUser(Guid targetUserId)
// Located in Govor.API/Hubs/FriendsHub.cs
await HubConnection.InvokeAsync("BlockUser", targetUserId);
Console.WriteLine($"Пользователь {targetUserId} заблокирован.");
}
catch (Exception ex)
{
Console.WriteLine($"[Ошибка блокировки пользователя] {ex.Message}");
}
}
public override string GetHelp()
{
return "/block [ID_пользователя] - Заблокировать пользователя. Если ID не указан, запросит ввод.";
}
}
}
+49
View File
@@ -0,0 +1,49 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace Govor.ConsoleClient.Commands
{
public class HelpCommand : BaseCommand
{
private readonly Dictionary<string, ICommand> _availableCommands;
// The HelpCommand needs access to the list of all commands to display their help messages.
// This will be injected from Program.cs where the commands are registered.
public HelpCommand(Dictionary<string, ICommand> availableCommands)
{
_availableCommands = availableCommands;
}
public override Task ExecuteAsync(string? argument)
{
Console.WriteLine("Доступные команды:");
if (!string.IsNullOrWhiteSpace(argument))
{
string commandKey = argument.StartsWith("/") ? argument : "/" + argument;
if (_availableCommands.TryGetValue(commandKey.ToLower(), out var specificCommand))
{
Console.WriteLine(specificCommand.GetHelp());
}
else
{
Console.WriteLine($"Команда '{argument}' не найдена. Введите /help для списка всех команд.");
}
}
else
{
foreach (var commandEntry in _availableCommands.OrderBy(c => c.Key))
{
Console.WriteLine(commandEntry.Value.GetHelp());
}
}
return Task.CompletedTask;
}
public override string GetHelp()
{
return "/help [команда] - Показать список всех команд или помощь по конкретной команде.";
}
}
}
+8
View File
@@ -0,0 +1,8 @@
namespace Govor.ConsoleClient.Commands
{
public interface ICommand
{
Task ExecuteAsync(string? argument);
string GetHelp();
}
}
@@ -0,0 +1,40 @@
using System;
using System.Linq;
using System.Threading.Tasks;
namespace Govor.ConsoleClient.Commands
{
public class ListFriendsCommand : BaseCommand
{
public override async Task ExecuteAsync(string? argument)
{
if (!EnsureLoggedIn()) return;
try
{
var friends = await FriendsClient.GetFriendsAsync();
if (friends.Any())
{
Console.WriteLine("Ваши друзья:");
foreach (var f in friends)
{
Console.WriteLine($"- {f.Username} | был онлайн: {f.WasOnline} [{f.Id}]");
}
}
else
{
Console.WriteLine("У вас пока нет друзей.");
}
}
catch (Exception ex)
{
Console.WriteLine($"[Ошибка] {ex.Message}");
}
}
public override string GetHelp()
{
return "/friends - Показать список ваших друзей.";
}
}
}
@@ -0,0 +1,44 @@
using System;
using System.Linq;
using System.Threading.Tasks;
namespace Govor.ConsoleClient.Commands
{
public class ListIncomingRequestsCommand : BaseCommand
{
public override async Task ExecuteAsync(string? argument)
{
if (!EnsureLoggedIn()) return;
try
{
// This still uses REST client as per existing FriendsClient
var requests = await FriendsClient.GetIncomingRequestsAsync();
if (requests.Any())
{
Console.WriteLine("Входящие заявки в друзья:");
foreach (var r in requests)
{
// Assuming you want to show who sent the request.
// The FriendshipDto contains RequesterId and AddresseeId.
// If current user is AddresseeId, then RequesterId is the one who sent it.
Console.WriteLine($"- Запрос ID: {r.Id}. От пользователя ID: {r.RequesterId}. Статус: {r.Status}. (принять через /accept {r.Id})");
}
}
else
{
Console.WriteLine("У вас нет входящих заявок в друзья.");
}
}
catch (Exception ex)
{
Console.WriteLine($"[Ошибка] {ex.Message}");
}
}
public override string GetHelp()
{
return "/incoming - Показать список входящих заявок в друзья.";
}
}
}
@@ -0,0 +1,50 @@
using System;
using System.Linq;
using System.Net.Http;
using System.Net.Http.Json;
using System.Threading.Tasks;
using Govor.Contracts.DTOs; // Required for FriendshipDto
namespace Govor.ConsoleClient.Commands
{
public class ListOutgoingRequestsCommand : BaseCommand
{
public override async Task ExecuteAsync(string? argument)
{
if (!EnsureLoggedIn()) return;
try
{
// This functionality maps to GET api/friends/responses in FriendsRequestQueryController
// FriendsClient doesn't have a dedicated method, so we use HttpClientService or direct HttpClient
var response = await HttpClientService.GetAsync("api/friends/responses");
response.EnsureSuccessStatusCode();
var requests = await response.Content.ReadFromJsonAsync<System.Collections.Generic.List<FriendshipDto>>();
if (requests != null && requests.Any())
{
Console.WriteLine("Отправленные вами заявки в друзья (ожидают ответа):");
foreach (var r in requests)
{
// If current user is RequesterId, then AddresseeId is the one they sent to.
Console.WriteLine($"- Запрос ID: {r.Id}. Пользователю ID: {r.AddresseeId}. Статус: {r.Status}.");
}
}
else
{
Console.WriteLine("У вас нет отправленных заявок, ожидающих ответа.");
}
}
catch (Exception ex)
{
Console.WriteLine($"[Ошибка] {ex.Message}");
}
}
public override string GetHelp()
{
return "/outgoing - Показать список отправленных вами заявок в друзья, ожидающих ответа.";
}
}
}
+50
View File
@@ -0,0 +1,50 @@
using System;
using System.Net.Http.Headers;
using System.Threading.Tasks;
namespace Govor.ConsoleClient.Commands
{
public class LoginCommand : BaseCommand
{
public override async Task ExecuteAsync(string? argument)
{
Console.Write("username: ");
var loginUsername = Console.ReadLine();
Console.Write("password: ");
var loginPassword = Console.ReadLine();
if (string.IsNullOrWhiteSpace(loginUsername) || string.IsNullOrWhiteSpace(loginPassword))
{
Console.WriteLine("[Ошибка] Имя пользователя и пароль не могут быть пустыми.");
return;
}
try
{
var authToken = await HttpClientService.LoginAsync(loginUsername, loginPassword);
SetAuthToken(authToken);
// Initialize FriendsClient after successful login
var sharedClient = new HttpClient { BaseAddress = new Uri(HttpClientService.GetBaseUrl()) };
sharedClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", authToken);
var friendsClient = new FriendsClient(sharedClient);
// Re-initialize services in BaseCommand with the new FriendsClient
InitializeServices(friendsClient, HttpClientService, GetAuthToken, SetAuthToken, InitializeHubConnectionAsync, HubConnection);
await InitializeHubConnectionAsync();
Console.WriteLine("[Успех] Вход выполнен. Токен сохранен.");
}
catch (Exception ex)
{
Console.WriteLine($"[Ошибка] {ex.Message}");
}
}
public override string GetHelp()
{
return "/login - Войти в существующий аккаунт.";
}
}
}
+53
View File
@@ -0,0 +1,53 @@
using System;
using System.Net.Http.Headers;
using System.Threading.Tasks;
namespace Govor.ConsoleClient.Commands
{
public class RegisterCommand : BaseCommand
{
public override async Task ExecuteAsync(string? argument)
{
Console.Write("username: ");
var regUsername = Console.ReadLine();
Console.Write("password: ");
var regPassword = Console.ReadLine();
Console.Write("invitation code: ");
var inviteCode = Console.ReadLine();
if (string.IsNullOrWhiteSpace(regUsername) || string.IsNullOrWhiteSpace(regPassword) || string.IsNullOrWhiteSpace(inviteCode))
{
Console.WriteLine("[Ошибка] Имя пользователя, пароль и код приглашения не могут быть пустыми.");
return;
}
try
{
var authToken = await HttpClientService.RegisterAsync(regUsername, regPassword, inviteCode);
SetAuthToken(authToken);
// Initialize FriendsClient after successful registration
var sharedClient = new HttpClient { BaseAddress = new Uri(HttpClientService.GetBaseUrl()) };
sharedClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", authToken);
var friendsClient = new FriendsClient(sharedClient);
// Re-initialize services in BaseCommand with the new FriendsClient
InitializeServices(friendsClient, HttpClientService, GetAuthToken, SetAuthToken, InitializeHubConnectionAsync, HubConnection);
await InitializeHubConnectionAsync();
Console.WriteLine("[Успех] Регистрация завершена. Токен сохранен.");
}
catch (Exception ex)
{
Console.WriteLine($"[Ошибка] {ex.Message}");
}
}
public override string GetHelp()
{
return "/reg - Зарегистрировать новый аккаунт с помощью кода приглашения.";
}
}
}
@@ -0,0 +1,42 @@
using System;
using System.Threading.Tasks;
namespace Govor.ConsoleClient.Commands
{
public class RejectFriendRequestCommand : BaseCommand
{
public override async Task ExecuteAsync(string? argument)
{
if (!EnsureLoggedIn() || !EnsureHubConnection()) return;
Guid friendshipId;
if (string.IsNullOrWhiteSpace(argument) || !Guid.TryParse(argument, out friendshipId))
{
Console.Write("Введите ID заявки, которую хотите отклонить: ");
var input = Console.ReadLine();
if (string.IsNullOrWhiteSpace(input) || !Guid.TryParse(input, out friendshipId))
{
Console.WriteLine("[Ошибка] Неверный или пустой ID заявки.");
return;
}
}
try
{
// API uses Hub for this: RejectFriendRequest(Guid friendshipId)
// Located in Govor.API/Hubs/FriendsHub.cs
await HubConnection.InvokeAsync("RejectFriendRequest", friendshipId);
Console.WriteLine("Заявка в друзья отклонена.");
}
catch (Exception ex)
{
Console.WriteLine($"[Ошибка отклонения заявки] {ex.Message}");
}
}
public override string GetHelp()
{
return "/reject [ID_заявки] - Отклонить входящую заявку в друзья. Если ID не указан, запросит ввод.";
}
}
}
@@ -0,0 +1,51 @@
using System;
using System.Linq;
using System.Threading.Tasks;
namespace Govor.ConsoleClient.Commands
{
public class SearchUserCommand : BaseCommand
{
public override async Task ExecuteAsync(string? argument)
{
if (!EnsureLoggedIn()) return;
if (string.IsNullOrWhiteSpace(argument))
{
Console.Write("Введите имя пользователя для поиска: ");
argument = Console.ReadLine();
if (string.IsNullOrWhiteSpace(argument))
{
Console.WriteLine("[Ошибка] Поисковый запрос не может быть пустым.");
return;
}
}
try
{
var foundUsers = await FriendsClient.SearchAsync(argument);
if (foundUsers.Any())
{
Console.WriteLine("Найденные пользователи:");
foreach (var user in foundUsers)
{
Console.WriteLine($"- {user.Username} [{user.Id}]");
}
}
else
{
Console.WriteLine("Пользователи не найдены.");
}
}
catch (Exception ex)
{
Console.WriteLine($"[Ошибка] {ex.Message}");
}
}
public override string GetHelp()
{
return "/search [имя_пользователя] - Найти пользователей по имени. Если имя не указано, запросит ввод.";
}
}
}
@@ -0,0 +1,41 @@
using System;
using System.Threading.Tasks;
namespace Govor.ConsoleClient.Commands
{
public class SendFriendRequestCommand : BaseCommand
{
public override async Task ExecuteAsync(string? argument)
{
if (!EnsureLoggedIn() || !EnsureHubConnection()) return;
Guid targetUserId;
if (string.IsNullOrWhiteSpace(argument) || !Guid.TryParse(argument, out targetUserId))
{
Console.Write("Введите ID пользователя, которому хотите отправить запрос: ");
var input = Console.ReadLine();
if (string.IsNullOrWhiteSpace(input) || !Guid.TryParse(input, out targetUserId))
{
Console.WriteLine("[Ошибка] Неверный или пустой ID пользователя.");
return;
}
}
try
{
// API uses Hub for this: SendFriendRequest(Guid targetUserId)
await HubConnection.InvokeAsync("SendFriendRequest", targetUserId);
Console.WriteLine("Запрос в друзья отправлен.");
}
catch (Exception ex)
{
Console.WriteLine($"[Ошибка отправки запроса] {ex.Message}");
}
}
public override string GetHelp()
{
return "/friend [ID_пользователя] - Отправить запрос в друзья пользователю с указанным ID. Если ID не указан, запросит ввод.";
}
}
}
@@ -0,0 +1,42 @@
using System;
using System.Threading.Tasks;
namespace Govor.ConsoleClient.Commands
{
public class UnblockUserCommand : BaseCommand
{
public override async Task ExecuteAsync(string? argument)
{
if (!EnsureLoggedIn() || !EnsureHubConnection()) return;
Guid targetUserId;
if (string.IsNullOrWhiteSpace(argument) || !Guid.TryParse(argument, out targetUserId))
{
Console.Write("Введите ID пользователя, которого хотите разблокировать: ");
var input = Console.ReadLine();
if (string.IsNullOrWhiteSpace(input) || !Guid.TryParse(input, out targetUserId))
{
Console.WriteLine("[Ошибка] Неверный или пустой ID пользователя.");
return;
}
}
try
{
// API uses Hub for this: UnblockUser(Guid targetUserId)
// Located in Govor.API/Hubs/FriendsHub.cs
await HubConnection.InvokeAsync("UnblockUser", targetUserId);
Console.WriteLine($"Пользователь {targetUserId} разблокирован.");
}
catch (Exception ex)
{
Console.WriteLine($"[Ошибка разблокировки пользователя] {ex.Message}");
}
}
public override string GetHelp()
{
return "/unblock [ID_пользователя] - Разблокировать пользователя. Если ID не указан, запросит ввод.";
}
}
}