From 0669614a5e5ae358c1adf4d40085e66353084e70 Mon Sep 17 00:00:00 2001 From: Artemy <109195690+stalcker2288969@users.noreply.github.com> Date: Wed, 2 Jul 2025 15:26:27 +0700 Subject: [PATCH] async Task GenerateJwtTokenAsync(User user) --- .../Authentication/JwtServiceTests.cs | 4 +- .../Controllers/AdminStuff/UsersController.cs | 27 ++++++++-- Govor.API/Controllers/MediaController.cs | 50 +++++++++++++++++++ Govor.API/Hubs/ChatsHub.cs | 19 +++---- .../Interfaces/AdminsStuff/UsersService.cs | 7 +++ .../Interfaces/Authentication/IJwtService.cs | 2 +- .../Interfaces/IUsersAdministration.cs | 1 + Govor.Application/Services/AuthService.cs | 4 +- Govor.Application/Services/JwtService.cs | 4 +- .../Requests/MediaUploadRequest.cs | 13 +++++ .../Requests/SignalR/MediaReference.cs | 11 ++++ .../Requests/SignalR/MessageRequest.cs | 9 ++++ Govor.Core/Models/MediaAttachments.cs | 2 - 13 files changed, 131 insertions(+), 22 deletions(-) create mode 100644 Govor.API/Controllers/MediaController.cs create mode 100644 Govor.Contracts/Requests/MediaUploadRequest.cs create mode 100644 Govor.Contracts/Requests/SignalR/MediaReference.cs create mode 100644 Govor.Contracts/Requests/SignalR/MessageRequest.cs diff --git a/Govor.API.Tests/UnitTests/Services/Authentication/JwtServiceTests.cs b/Govor.API.Tests/UnitTests/Services/Authentication/JwtServiceTests.cs index 2eab678..9e4acb8 100644 --- a/Govor.API.Tests/UnitTests/Services/Authentication/JwtServiceTests.cs +++ b/Govor.API.Tests/UnitTests/Services/Authentication/JwtServiceTests.cs @@ -40,14 +40,14 @@ public class JwtServiceTests } [Test] - public void GenerateJwtToken_ShouldReturnValidJwtString() + public async Task GenerateJwtToken_ShouldReturnValidJwtString() { // Arrange var user = _fixture.Create(); var expectedRole = "User"; _invitesServiceMock.Setup(s => s.GetRoleAsync(user)).Returns(Task.FromResult(expectedRole)); // Act - var tokenString = _jwtService.GenerateJwtToken(user); + var tokenString = await _jwtService.GenerateJwtTokenAsync(user); // Assert Assert.That(tokenString, Is.Not.Null.And.Not.Empty); diff --git a/Govor.API/Controllers/AdminStuff/UsersController.cs b/Govor.API/Controllers/AdminStuff/UsersController.cs index fb2e97d..8dd1c6a 100644 --- a/Govor.API/Controllers/AdminStuff/UsersController.cs +++ b/Govor.API/Controllers/AdminStuff/UsersController.cs @@ -24,16 +24,35 @@ public class UsersController : Controller [HttpGet] public async Task AllUsers() { - _logger.LogInformation("Getting all users by administrator"); - var read = await _users.GetAllUsersAsync(); + try + { + _logger.LogInformation("Getting all users by administrator"); + var read = await _users.GetAllUsersAsync(); - return Ok(BuildUserDtos(read)); + return Ok(BuildUserDtos(read)); + } + catch (Exception e) + { + _logger.LogError(e, e.Message); + return StatusCode(500, e.Message); + } + } [HttpGet("{id:guid}")] public async Task GetUserById(Guid id) { - return Ok(id); + try + { + _logger.LogInformation($"Getting user {id} by administrator"); + var read = await _users.GetUserById(id); + return Ok(BuildUserDtos([read]).First()); + } + catch (Exception e) + { + _logger.LogError(e, e.Message); + return StatusCode(500, e.Message); + } } private List BuildUserDtos(IEnumerable users) => users.Select(user => new UserResponse diff --git a/Govor.API/Controllers/MediaController.cs b/Govor.API/Controllers/MediaController.cs new file mode 100644 index 0000000..947c9cf --- /dev/null +++ b/Govor.API/Controllers/MediaController.cs @@ -0,0 +1,50 @@ +using Govor.Application.Interfaces; +using Govor.Contracts.Requests; +using Govor.Core.Models; +using Govor.Core.Repositories.MediasAttachments; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; + +namespace Govor.API.Controllers; + +[ApiController] +[Route("api/media")] +[Authorize(Roles = "User,Admin")] +public class MediaController : Controller +{ + private readonly ILogger _logger; + private readonly IStorageService _storageService; + private readonly IMediaAttachmentsRepository _repository; + + public MediaController(ILogger logger, IStorageService storageService) + { + _logger = logger; + _storageService = storageService; + } + + [HttpPost("upload")] + [RequestSizeLimit(100_000_000)]// ~100MB + public async Task Upload([FromForm] MediaUploadRequest request) + { + try + { + var url = await _storageService.SaveAsync(request.Data,request.FileName); + var mediaId = Guid.NewGuid(); + + _repository.AddAsync(new MediaAttachments() + { + Id = mediaId, + FilePath = url, + EncryptedKey = request.EncryptedKey, + MimeType = request.MimeType, + Type = request.Type, + }); + + return Ok(mediaId); + } + catch (Exception ex) + { + return StatusCode(500, ex); + } + } +} \ No newline at end of file diff --git a/Govor.API/Hubs/ChatsHub.cs b/Govor.API/Hubs/ChatsHub.cs index b959c3f..e0ffe2d 100644 --- a/Govor.API/Hubs/ChatsHub.cs +++ b/Govor.API/Hubs/ChatsHub.cs @@ -1,4 +1,5 @@ using System.Security.Claims; +using Govor.Contracts.Requests.SignalR; using Govor.Core.Models; using Govor.Core.Repositories.Users; using Govor.Data.Repositories.Exceptions; @@ -48,19 +49,19 @@ public class ChatsHub : Hub } - public async Task Send(string message, Guid toUserId) + public async Task Send(MessageRequest request) { // Валидация входных данных - if (string.IsNullOrWhiteSpace(message)) + if (string.IsNullOrWhiteSpace(request.EncryptedContent)) { _logger.LogWarning("Empty message received from user {UserId}", GetUserId()); - throw new ArgumentException("Message cannot be empty", nameof(message)); + throw new ArgumentException("Message cannot be empty", nameof(request.EncryptedContent)); } var senderId = GetUserId(); // Проверка существования получателя - try + /*try { await _usersRepository.FindByIdAsync(toUserId); } @@ -73,19 +74,19 @@ public class ChatsHub : Hub { _logger.LogWarning("Invalid recipient userId received from user {UserId}", GetUserId()); throw; - } + }*/ try { - _logger.LogInformation("Message sent from {SenderId} to {RecipientId}: {Message}", senderId, toUserId, message); + _logger.LogInformation("Message sent from {SenderId} to {RecipientId} at {UtcNow}", senderId, request.RecipientId, DateTime.UtcNow); // Отправка сообщения отправителю и получателю - await Clients.Group(toUserId.ToString()).SendAsync("Receive", message, senderId); - await Clients.Group(senderId.ToString()).SendAsync("Receive", message, senderId); + //await Clients.Group(request.RecipientId.ToString()).SendAsync("Receive", message, senderId); + // Clients.Group(senderId.ToString()).SendAsync("Receive", message, senderId); } catch (Exception ex) { - _logger.LogError(ex, "Error sending message from {SenderId} to {RecipientId}", senderId, toUserId); + //_logger.LogError(ex, "Error sending message from {SenderId} to {RecipientId}", senderId, toUserId); throw; } } diff --git a/Govor.Application/Interfaces/AdminsStuff/UsersService.cs b/Govor.Application/Interfaces/AdminsStuff/UsersService.cs index 10f41ec..56044cb 100644 --- a/Govor.Application/Interfaces/AdminsStuff/UsersService.cs +++ b/Govor.Application/Interfaces/AdminsStuff/UsersService.cs @@ -26,4 +26,11 @@ public class UsersService : IUsersAdministration return new List(); } } + + public async Task GetUserById(Guid userId) + { + var result = await _usersRepository.FindByIdAsync(userId); + + return result; + } } \ No newline at end of file diff --git a/Govor.Application/Interfaces/Authentication/IJwtService.cs b/Govor.Application/Interfaces/Authentication/IJwtService.cs index 96a0c15..7f0bf6b 100644 --- a/Govor.Application/Interfaces/Authentication/IJwtService.cs +++ b/Govor.Application/Interfaces/Authentication/IJwtService.cs @@ -4,5 +4,5 @@ namespace Govor.API.Services.Authentication.Interfaces; public interface IJwtService { - string GenerateJwtToken(User user); + Task GenerateJwtTokenAsync(User user); } \ No newline at end of file diff --git a/Govor.Application/Interfaces/IUsersAdministration.cs b/Govor.Application/Interfaces/IUsersAdministration.cs index f08836f..a6ccae5 100644 --- a/Govor.Application/Interfaces/IUsersAdministration.cs +++ b/Govor.Application/Interfaces/IUsersAdministration.cs @@ -5,4 +5,5 @@ namespace Govor.API.Services.AdminsStuff.Interfaces; public interface IUsersAdministration { Task> GetAllUsersAsync(); + Task GetUserById(Guid userId); } \ No newline at end of file diff --git a/Govor.Application/Services/AuthService.cs b/Govor.Application/Services/AuthService.cs index 8b2d0b1..e5682c2 100644 --- a/Govor.Application/Services/AuthService.cs +++ b/Govor.Application/Services/AuthService.cs @@ -57,7 +57,7 @@ public class AuthService : IAccountService SetRole(user, invitation); - return _jwtService.GenerateJwtToken(user); + return await _jwtService.GenerateJwtTokenAsync(user); } @@ -71,7 +71,7 @@ public class AuthService : IAccountService if (_passwordHasher.Verify(password, user.PasswordHash) == false) throw new LoginUserException(); - return _jwtService.GenerateJwtToken(user); + return await _jwtService.GenerateJwtTokenAsync(user); } private async void SetRole(User user, Invitation invitation) diff --git a/Govor.Application/Services/JwtService.cs b/Govor.Application/Services/JwtService.cs index bf0c37c..dcd8334 100644 --- a/Govor.Application/Services/JwtService.cs +++ b/Govor.Application/Services/JwtService.cs @@ -19,12 +19,12 @@ public class JwtService : IJwtService _invitesService = invitesService; } - public string GenerateJwtToken(User user) + public async Task GenerateJwtTokenAsync(User user) { var claims = new[] { new Claim("userId", user.Id.ToString()), - new Claim(ClaimTypes.Role, _invitesService.GetRoleAsync(user).Result, ClaimValueTypes.String) + new Claim(ClaimTypes.Role, await _invitesService.GetRoleAsync(user), ClaimValueTypes.String) }; var singing = new SigningCredentials( diff --git a/Govor.Contracts/Requests/MediaUploadRequest.cs b/Govor.Contracts/Requests/MediaUploadRequest.cs new file mode 100644 index 0000000..73f2c20 --- /dev/null +++ b/Govor.Contracts/Requests/MediaUploadRequest.cs @@ -0,0 +1,13 @@ +using System.ComponentModel.DataAnnotations; +using Govor.Core.Models; + +namespace Govor.Contracts.Requests; + +public class MediaUploadRequest +{ + public byte[] Data { get; set; } + public string FileName { get; set; } + public string EncryptedKey { get; set; } = string.Empty; + public MediaType Type { get; set; } + public string MimeType { get; set; } = string.Empty; +} \ No newline at end of file diff --git a/Govor.Contracts/Requests/SignalR/MediaReference.cs b/Govor.Contracts/Requests/SignalR/MediaReference.cs new file mode 100644 index 0000000..f5faef9 --- /dev/null +++ b/Govor.Contracts/Requests/SignalR/MediaReference.cs @@ -0,0 +1,11 @@ +using Govor.Core.Models; + +namespace Govor.Contracts.Requests.SignalR; + +public record MediaReference +{ + public Guid MediaId { get; init; } + public string EncryptedKey { get; init; } = string.Empty; + public MediaType Type { get; init; } + public string MimeType { get; init; } = string.Empty; +} \ No newline at end of file diff --git a/Govor.Contracts/Requests/SignalR/MessageRequest.cs b/Govor.Contracts/Requests/SignalR/MessageRequest.cs new file mode 100644 index 0000000..477b68c --- /dev/null +++ b/Govor.Contracts/Requests/SignalR/MessageRequest.cs @@ -0,0 +1,9 @@ +namespace Govor.Contracts.Requests.SignalR; + +public record MessageRequest +{ + public Guid RecipientId { get; init; } + public string EncryptedContent { get; init; } = string.Empty; + public Guid? ReplyToMessageId { get; set; } + public List MediaAttachments { get; set; } = new(); +} \ No newline at end of file diff --git a/Govor.Core/Models/MediaAttachments.cs b/Govor.Core/Models/MediaAttachments.cs index bc5b42c..43da672 100644 --- a/Govor.Core/Models/MediaAttachments.cs +++ b/Govor.Core/Models/MediaAttachments.cs @@ -4,11 +4,9 @@ public class MediaAttachments { public Guid Id { get; set; } public Guid MessageId { get; set; } - public MediaType Type { get; set; } public string FilePath { get; set; } = string.Empty; // local path in filesystem public string MimeType { get; set; } = string.Empty; - public string? EncryptedKey { get; set; } public Message Message { get; set; } = null!;