Изображения в услугах, поиске, возможность открыть карточку услуги
This commit is contained in:
@@ -36,13 +36,16 @@ public record CreateOfferCommand : IRequest<Result<Guid>>
|
||||
/// </summary>
|
||||
public JsonDocument? Attributes { get; init; }
|
||||
|
||||
public CreateOfferCommand(Guid categoryId, string title, string description, Price price, JsonDocument? attributes)
|
||||
public List<string>? Images { get; init; }
|
||||
|
||||
public CreateOfferCommand(Guid categoryId, string title, string description, Price price, JsonDocument? attributes, List<string>? images)
|
||||
{
|
||||
CategoryId = categoryId;
|
||||
Title = title;
|
||||
Description = description;
|
||||
Price = price;
|
||||
Attributes = attributes;
|
||||
Images = images;
|
||||
}
|
||||
|
||||
public CreateOfferCommand() { }
|
||||
@@ -70,7 +73,8 @@ public class CreateOfferCommandHandler : IRequestHandler<CreateOfferCommand, Res
|
||||
request.Title,
|
||||
request.Description,
|
||||
request.Price,
|
||||
request.Attributes
|
||||
request.Attributes,
|
||||
request.Images
|
||||
);
|
||||
|
||||
await _repository.AddAsync(offer, cancellationToken);
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
using MediatR;
|
||||
using Nashel.BuildingBlocks.Application.Abstractions;
|
||||
using Nashel.Modules.Catalog.Domain.Repositories;
|
||||
|
||||
namespace Nashel.Modules.Catalog.Application.Commands;
|
||||
|
||||
public record DeleteOfferCommand(Guid OfferId) : IRequest<bool>;
|
||||
|
||||
public class DeleteOfferCommandHandler : IRequestHandler<DeleteOfferCommand, bool>
|
||||
{
|
||||
private readonly IOfferRepository _repository;
|
||||
private readonly ICurrentUserService _currentUser;
|
||||
|
||||
public DeleteOfferCommandHandler(IOfferRepository repository, ICurrentUserService currentUser)
|
||||
{
|
||||
_repository = repository;
|
||||
_currentUser = currentUser;
|
||||
}
|
||||
|
||||
public async Task<bool> Handle(DeleteOfferCommand request, CancellationToken cancellationToken)
|
||||
{
|
||||
var offer = await _repository.GetByIdAsync(request.OfferId, cancellationToken);
|
||||
if (offer == null) throw new Exception("Offer not found");
|
||||
|
||||
if (offer.PerformerId != _currentUser.UserId)
|
||||
throw new UnauthorizedAccessException("Not your offer");
|
||||
|
||||
offer.Delete();
|
||||
await _repository.UpdateAsync(offer, cancellationToken);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
using MediatR;
|
||||
using Nashel.BuildingBlocks.Application.Abstractions;
|
||||
using Nashel.Modules.Catalog.Domain.Repositories;
|
||||
|
||||
namespace Nashel.Modules.Catalog.Application.Commands;
|
||||
|
||||
public record ToggleOfferStatusCommand(Guid OfferId) : IRequest<bool>;
|
||||
|
||||
public class ToggleOfferStatusCommandHandler : IRequestHandler<ToggleOfferStatusCommand, bool>
|
||||
{
|
||||
private readonly IOfferRepository _repository;
|
||||
private readonly ICurrentUserService _currentUser;
|
||||
|
||||
public ToggleOfferStatusCommandHandler(IOfferRepository repository, ICurrentUserService currentUser)
|
||||
{
|
||||
_repository = repository;
|
||||
_currentUser = currentUser;
|
||||
}
|
||||
|
||||
public async Task<bool> Handle(ToggleOfferStatusCommand request, CancellationToken cancellationToken)
|
||||
{
|
||||
var offer = await _repository.GetByIdAsync(request.OfferId, cancellationToken);
|
||||
if (offer == null) throw new Exception("Offer not found");
|
||||
|
||||
if (offer.PerformerId != _currentUser.UserId)
|
||||
throw new UnauthorizedAccessException("Not your offer");
|
||||
|
||||
offer.ToggleActive();
|
||||
await _repository.UpdateAsync(offer, cancellationToken);
|
||||
return offer.IsActive;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
using System.Text.Json;
|
||||
using MediatR;
|
||||
using Nashel.BuildingBlocks.Application.Abstractions;
|
||||
using Nashel.Modules.Catalog.Domain.Aggregates;
|
||||
using Nashel.Modules.Catalog.Domain.Repositories;
|
||||
using Nashel.Modules.Catalog.Domain.ValueObjects;
|
||||
|
||||
namespace Nashel.Modules.Catalog.Application.Commands;
|
||||
|
||||
public record UpdateOfferCommand(
|
||||
Guid OfferId,
|
||||
string Title,
|
||||
string Description,
|
||||
decimal PriceAmount,
|
||||
int PriceType, // 0-Fixed, 1-Hourly, 2-Negotiable
|
||||
Dictionary<string, string>? Attributes,
|
||||
List<string>? Images) : IRequest<bool>;
|
||||
|
||||
public class UpdateOfferCommandHandler : IRequestHandler<UpdateOfferCommand, bool>
|
||||
{
|
||||
private readonly IOfferRepository _repository;
|
||||
private readonly ICurrentUserService _currentUser;
|
||||
|
||||
public UpdateOfferCommandHandler(IOfferRepository repository, ICurrentUserService currentUser)
|
||||
{
|
||||
_repository = repository;
|
||||
_currentUser = currentUser;
|
||||
}
|
||||
|
||||
public async Task<bool> Handle(UpdateOfferCommand request, CancellationToken cancellationToken)
|
||||
{
|
||||
var offer = await _repository.GetByIdAsync(request.OfferId, cancellationToken);
|
||||
if (offer == null) throw new Exception("Offer not found");
|
||||
|
||||
if (offer.PerformerId != _currentUser.UserId)
|
||||
throw new UnauthorizedAccessException("Not your offer");
|
||||
|
||||
var price = new Price(request.PriceAmount, (Nashel.Modules.Catalog.Domain.Enums.OfferType)request.PriceType);
|
||||
var jsonAttrs = request.Attributes != null && request.Attributes.Count > 0
|
||||
? JsonDocument.Parse(JsonSerializer.Serialize(request.Attributes))
|
||||
: null;
|
||||
|
||||
offer.Update(request.Title, request.Description, price, jsonAttrs, request.Images);
|
||||
|
||||
await _repository.UpdateAsync(offer, cancellationToken);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
using MediatR;
|
||||
using Nashel.BuildingBlocks.Application.Abstractions;
|
||||
|
||||
namespace Nashel.Modules.Catalog.Application.Commands;
|
||||
|
||||
public record UploadOfferImageCommand(byte[] Content, string FileName) : IRequest<string>;
|
||||
|
||||
public class UploadOfferImageCommandHandler : IRequestHandler<UploadOfferImageCommand, string>
|
||||
{
|
||||
private const long MaxFileSize = 5 * 1024 * 1024; // 5MB
|
||||
private static readonly string[] AllowedExtensions = { ".jpg", ".jpeg", ".png", ".webp" };
|
||||
|
||||
private readonly ICurrentUserService _currentUserService;
|
||||
|
||||
public UploadOfferImageCommandHandler(ICurrentUserService currentUserService)
|
||||
{
|
||||
_currentUserService = currentUserService;
|
||||
}
|
||||
|
||||
public Task<string> Handle(UploadOfferImageCommand request, CancellationToken cancellationToken)
|
||||
{
|
||||
var userId = _currentUserService.UserId;
|
||||
if (userId == null) throw new UnauthorizedAccessException();
|
||||
|
||||
if (request.Content.Length > MaxFileSize)
|
||||
throw new InvalidOperationException("Размер файла не должен превышать 5 МБ");
|
||||
|
||||
var extension = Path.GetExtension(request.FileName).ToLowerInvariant();
|
||||
if (Array.IndexOf(AllowedExtensions, extension) == -1)
|
||||
throw new InvalidOperationException("Допустимые форматы: JPG, PNG, WEBP");
|
||||
|
||||
var base64String = Convert.ToBase64String(request.Content);
|
||||
|
||||
var mimeType = extension switch
|
||||
{
|
||||
".png" => "image/png",
|
||||
".webp" => "image/webp",
|
||||
_ => "image/jpeg"
|
||||
};
|
||||
|
||||
return Task.FromResult($"data:{mimeType};base64,{base64String}");
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user