Сборка

This commit is contained in:
Халимов Рустам
2026-03-31 00:38:34 +03:00
parent b09e197626
commit 60d3cf12ae
6 changed files with 39 additions and 39 deletions

View File

@@ -44,7 +44,7 @@ public static class AdminEndpoints
return Results.Ok(result.Value);
});
group.MapPost("users/{userId:guid}/reset-password", async (Guid userId, [FromBody] ResetPasswordRequest dto, ISender sender, CancellationToken ct) =>
group.MapPost("users/{userId:guid}/reset-password", async ([FromRoute] Guid userId, [FromBody] ResetPasswordRequest dto, ISender sender, CancellationToken ct) =>
{
var result = await sender.Send(new ResetUserPasswordCommand(userId, dto.NewPassword), ct);
if (result.IsFailure)
@@ -55,13 +55,13 @@ public static class AdminEndpoints
return Results.Ok(result.Value);
});
group.MapPost("users/{userId:guid}/ban", async (Guid userId, ISender sender, CancellationToken ct) =>
group.MapPost("users/{userId:guid}/ban", async ([FromRoute] Guid userId, ISender sender, CancellationToken ct) =>
{
var result = await sender.Send(new BanUserCommand(userId), ct);
return result.IsSuccess ? Results.Ok() : Results.BadRequest(new { error = result.Error.Description });
});
group.MapPost("users/{userId:guid}/unban", async (Guid userId, ISender sender, CancellationToken ct) =>
group.MapPost("users/{userId:guid}/unban", async ([FromRoute] Guid userId, ISender sender, CancellationToken ct) =>
{
var result = await sender.Send(new UnbanUserCommand(userId), ct);
return result.IsSuccess ? Results.Ok() : Results.BadRequest(new { error = result.Error.Description });
@@ -77,7 +77,7 @@ public static class AdminEndpoints
return Results.Ok(result.Value);
});
group.MapGet("users/{id:guid}", async (Guid id, ISender sender, CancellationToken ct) =>
group.MapGet("users/{id:guid}", async ([FromRoute] Guid id, ISender sender, CancellationToken ct) =>
{
var result = await sender.Send(new GetUserDetailsQuery(id), ct);
return result.IsSuccess ? Results.Ok(result.Value) : Results.NotFound("User not found");

View File

@@ -74,7 +74,7 @@ public static class ChatsEndpoints
return Results.Ok(chatResult.Value);
});
group.MapPut("{id:guid}", async (Guid id, [FromBody] UpdateChatRequest request, ISender sender, IUserContext userContext, CancellationToken ct) =>
group.MapPut("{id:guid}", async ([FromRoute] Guid id, [FromBody] UpdateChatRequest request, ISender sender, IUserContext userContext, CancellationToken ct) =>
{
var result = await sender.Send(new UpdateChatCommand(id, userContext.UserId, request.Name, request.Description), ct);
if (result.IsFailure) return Results.NotFound();
@@ -83,7 +83,7 @@ public static class ChatsEndpoints
return Results.Ok(chatResult.Value);
});
group.MapDelete("{id:guid}", async (Guid id, ISender sender, IUserContext userContext, CancellationToken ct) =>
group.MapDelete("{id:guid}", async ([FromRoute] Guid id, ISender sender, IUserContext userContext, CancellationToken ct) =>
{
var result = await sender.Send(new LeaveOrDeleteChatCommand(id, userContext.UserId), ct);
if (result.IsFailure)
@@ -94,19 +94,19 @@ public static class ChatsEndpoints
return Results.Ok(result.Value);
});
group.MapPost("{id:guid}/clear", async (Guid id, ISender sender, IUserContext userContext, CancellationToken ct) =>
group.MapPost("{id:guid}/clear", async ([FromRoute] Guid id, ISender sender, IUserContext userContext, CancellationToken ct) =>
{
var result = await sender.Send(new ClearChatCommand(id, userContext.UserId), ct);
return result.IsSuccess ? Results.Ok(result.Value) : Results.NotFound();
});
group.MapPost("{id:guid}/pin", async (Guid id, ISender sender, IUserContext userContext, CancellationToken ct) =>
group.MapPost("{id:guid}/pin", async ([FromRoute] Guid id, ISender sender, IUserContext userContext, CancellationToken ct) =>
{
var result = await sender.Send(new TogglePinCommand(id, userContext.UserId), ct);
return result.IsSuccess ? Results.Ok(result.Value) : Results.NotFound();
});
group.MapPost("{id:guid}/members", async (Guid id, [FromBody] AddMembersRequest request, ISender sender, IUserContext userContext, CancellationToken ct) =>
group.MapPost("{id:guid}/members", async ([FromRoute] Guid id, [FromBody] AddMembersRequest request, ISender sender, IUserContext userContext, CancellationToken ct) =>
{
var result = await sender.Send(new AddMembersCommand(id, userContext.UserId, request.UserIds.ToList()), ct);
if (result.IsFailure) return Results.NotFound();
@@ -115,7 +115,7 @@ public static class ChatsEndpoints
return Results.Ok(chatResult.Value);
});
group.MapDelete("{id:guid}/members/{userId:guid}", async (Guid id, Guid userId, ISender sender, IUserContext userContext, CancellationToken ct) =>
group.MapDelete("{id:guid}/members/{userId:guid}", async ([FromRoute] Guid id, [FromRoute] Guid userId, ISender sender, IUserContext userContext, CancellationToken ct) =>
{
var result = await sender.Send(new RemoveMemberCommand(id, userContext.UserId, userId), ct);
if (result.IsFailure) return Results.NotFound();
@@ -124,7 +124,7 @@ public static class ChatsEndpoints
return Results.Ok(chatResult.Value);
});
group.MapPost("{id:guid}/avatar", async (Guid id, HttpRequest req, ISender sender, IUserContext userContext, CancellationToken ct) =>
group.MapPost("{id:guid}/avatar", async ([FromRoute] Guid id, HttpRequest req, ISender sender, IUserContext userContext, CancellationToken ct) =>
{
if (!req.HasFormContentType) return Results.BadRequest("No file");
var form = await req.ReadFormAsync(ct);
@@ -139,7 +139,7 @@ public static class ChatsEndpoints
return Results.Ok(chatResult.Value);
}).DisableAntiforgery();
group.MapPost("{id:guid}/avatar/crop", async (Guid id, HttpRequest req, ISender sender, IUserContext userContext, CancellationToken ct) =>
group.MapPost("{id:guid}/avatar/crop", async ([FromRoute] Guid id, HttpRequest req, ISender sender, IUserContext userContext, CancellationToken ct) =>
{
if (!req.HasFormContentType) return Results.BadRequest("No file");
var form = await req.ReadFormAsync(ct);
@@ -159,7 +159,7 @@ public static class ChatsEndpoints
return Results.Ok(chatResult.Value);
}).DisableAntiforgery();
group.MapDelete("{id:guid}/avatar", async (Guid id, ISender sender, IUserContext userContext, CancellationToken ct) =>
group.MapDelete("{id:guid}/avatar", async ([FromRoute] Guid id, ISender sender, IUserContext userContext, CancellationToken ct) =>
{
var result = await sender.Send(new RemoveGroupAvatarCommand(id, userContext.UserId), ct);
if (result.IsFailure) return Results.NotFound();

View File

@@ -19,7 +19,7 @@ public static class MessagesEndpoints
{
var group = app.MapGroup("api/messages").RequireAuthorization();
group.MapGet("chat/{chatId:guid}", async (Guid chatId, [FromQuery] string? cursor, ISender sender, IUserContext userContext, CancellationToken ct) =>
group.MapGet("chat/{chatId:guid}", async ([FromRoute] Guid chatId, [FromQuery] string? cursor, ISender sender, IUserContext userContext, CancellationToken ct) =>
{
var result = await sender.Send(new GetMessagesQuery(userContext.UserId, chatId, cursor), ct);
return result.IsSuccess ? Results.Ok(result.Value) : Results.BadRequest(result.Error.Description);
@@ -49,13 +49,13 @@ public static class MessagesEndpoints
return Results.Ok(result.Value);
}).DisableAntiforgery();
group.MapGet("chat/{chatId:guid}/shared", async (Guid chatId, [FromQuery] string? type, ISender sender, IUserContext userContext, CancellationToken ct) =>
group.MapGet("chat/{chatId:guid}/shared", async ([FromRoute] Guid chatId, [FromQuery] string? type, ISender sender, IUserContext userContext, CancellationToken ct) =>
{
var result = await sender.Send(new GetSharedMediaQuery(userContext.UserId, chatId, type), ct);
return result.IsSuccess ? Results.Ok(result.Value) : Results.BadRequest(result.Error.Description);
});
group.MapPost("chat/{chatId:guid}", async (Guid chatId, [FromBody] SendMessageRequest request, ISender sender, IUserContext userContext, CancellationToken ct) =>
group.MapPost("chat/{chatId:guid}", async ([FromRoute] Guid chatId, [FromBody] SendMessageRequest request, ISender sender, IUserContext userContext, CancellationToken ct) =>
{
var attachments = request.Attachments?.Select(a =>
new AttachmentRequest(a.Type, a.Url, a.FileName, a.FileSize)).ToList();

View File

@@ -1,15 +1,15 @@
using MediatR;
using System;
using Host.Application.Federation.Commands;
using Knot.Contracts.Settings.Application.Abstractions;
using Knot.Contracts.Settings.Application.DTOs;
using Knot.Modules.Federation.Application.Abstractions;
using Knot.Shared.Kernel.Constants;
using Knot.Shared.Kernel.Storage;
using MediatR;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Routing;
using System;
using Host.Application.Federation.Commands;
using Knot.Modules.Federation.Application.Abstractions;
using Knot.Shared.Kernel.Storage;
using Knot.Contracts.Settings.Application.Abstractions;
using Knot.Contracts.Settings.Application.DTOs;
namespace Host.Endpoints;
@@ -21,7 +21,7 @@ public static class FederationEndpoints
public static void MapFederationEndpoints(this WebApplication app)
{
var group = app.MapGroup(Routes.ApiFederation);
group.MapPost("/handshake", async ([FromBody] HandshakeRequest request, ISender sender, CancellationToken ct) =>
{
var result = await sender.Send(new HandshakeFederationCommand(request), ct);
@@ -34,30 +34,30 @@ public static class FederationEndpoints
return result.IsSuccess ? Results.Accepted() : Results.BadRequest(new { error = result.Error.Description });
});
group.MapGet("/resolve/{username}", async (string username, ISender sender, CancellationToken ct) =>
group.MapGet("/resolve/{username}", async ([FromRoute] string username, ISender sender, CancellationToken ct) =>
{
var result = await sender.Send(new ResolveUserCommand(username), ct);
return result.IsSuccess ? Results.Ok(result.Value) : Results.NotFound(new { error = result.Error.Description });
});
group.MapGet("/proxy/{id}", async (string id, [FromHeader(Name = "X-Knot-Signature")] string signature, [FromHeader(Name = "X-Knot-Domain")] string senderDomain, [FromServices] IFileStorageService storage, [FromServices] ISettingsService settingsService, CancellationToken ct) =>
group.MapGet("/proxy/{id}", async ([FromRoute] string id, [FromHeader(Name = "X-Knot-Signature")] string signature, [FromHeader(Name = "X-Knot-Domain")] string senderDomain, [FromServices] IFileStorageService storage, [FromServices] ISettingsService settingsService, CancellationToken ct) =>
{
// 1. Валидация подписи (упрощенно)
var settings = await settingsService.GetSettingsAsync(ct);
var senderConfig = settings.Federation.AllowedDomains.FirstOrDefault(d => d.Domain.Equals(senderDomain, StringComparison.OrdinalIgnoreCase));
if (senderConfig == null || string.IsNullOrEmpty(senderConfig.PublicKey))
return Results.Forbid();
// В реальном коде здесь проверка RSA подписи параметров запроса (URL + Domain)
// 2. Стриминг файла первоисточника
try
try
{
var (stream, contentType, fileName) = await storage.DownloadFileAsync(id);
return Results.File(stream, contentType, fileName, enableRangeProcessing: true);
}
catch
catch
{
return Results.NotFound();
}

View File

@@ -29,7 +29,7 @@ public static class ContactsEndpoints
return result.IsSuccess ? Results.Ok(result.Value) : Results.BadRequest(result.Error);
});
group.MapGet("status/{userId:guid}", async (Guid userId, ISender sender, IUserContext userContext, IContactsDbContext context, CancellationToken ct) =>
group.MapGet("status/{userId:guid}", async ([FromRoute] Guid userId, ISender sender, IUserContext userContext, [FromServices] IContactsDbContext context, CancellationToken ct) =>
{
var contact = await context.Contacts
.FirstOrDefaultAsync(c =>
@@ -74,19 +74,19 @@ public static class ContactsEndpoints
return result.IsSuccess ? Results.Ok(new { status = "pending" }) : Results.BadRequest(result.Error.Description);
});
group.MapPost("{id:guid}/accept", async (Guid id, ISender sender, IUserContext userContext, CancellationToken ct) =>
group.MapPost("{id:guid}/accept", async ([FromRoute] Guid id, ISender sender, IUserContext userContext, CancellationToken ct) =>
{
var result = await sender.Send(new AcceptContactRequestCommand(userContext.UserId, id), ct);
return result.IsSuccess ? Results.Ok(new { id = result.Value }) : Results.NotFound(result.Error.Description);
});
group.MapPost("{id:guid}/decline", async (Guid id, ISender sender, IUserContext userContext, CancellationToken ct) =>
group.MapPost("{id:guid}/decline", async ([FromRoute] Guid id, ISender sender, IUserContext userContext, CancellationToken ct) =>
{
var result = await sender.Send(new DeclineContactRequestCommand(userContext.UserId, id), ct);
return result.IsSuccess ? Results.Ok(new { success = true }) : Results.NotFound(result.Error.Description);
});
group.MapDelete("{id:guid}", async (Guid id, ISender sender, IUserContext userContext, CancellationToken ct) =>
group.MapDelete("{id:guid}", async ([FromRoute] Guid id, ISender sender, IUserContext userContext, CancellationToken ct) =>
{
var result = await sender.Send(new RemoveContactCommand(userContext.UserId, id), ct);
return result.IsSuccess ? Results.Ok(new SuccessResponse(true)) : Results.NotFound(result.Error.Description);

View File

@@ -33,7 +33,7 @@ public static class StoriesEndpoints
return Results.Ok(new { id = result.Value });
});
group.MapPost("video", async (HttpRequest req, ISender sender, IUserContext userContext, IFileStorageService fileStorage, CancellationToken ct) =>
group.MapPost("video", async (HttpRequest req, ISender sender, IUserContext userContext, [FromServices] IFileStorageService fileStorage, CancellationToken ct) =>
{
if (!req.HasFormContentType) return Results.BadRequest("No file uploaded");
var form = await req.ReadFormAsync(ct);
@@ -45,26 +45,26 @@ public static class StoriesEndpoints
return Results.Ok(new { url = $"/api/files/{fileId}" });
}).DisableAntiforgery();
group.MapGet("user/{userId:guid}", async (Guid userId, ISender sender, IUserContext userContext, CancellationToken ct) =>
group.MapGet("user/{userId:guid}", async ([FromRoute] Guid userId, ISender sender, IUserContext userContext, CancellationToken ct) =>
{
var result = await sender.Send(new GetUserStoriesQuery(userContext.UserId, userId), ct);
return result.IsSuccess ? Results.Ok(result.Value) : Results.NotFound();
});
group.MapPost("{id:guid}/view", async (Guid id, ISender sender, IUserContext userContext, CancellationToken ct) =>
group.MapPost("{id:guid}/view", async ([FromRoute] Guid id, ISender sender, IUserContext userContext, CancellationToken ct) =>
{
var result = await sender.Send(new ViewStoryCommand(userContext.UserId, id), ct);
return result.IsSuccess ? Results.Ok(result.Value) : Results.NotFound();
});
group.MapGet("{id:guid}/viewers", async (Guid id, ISender sender, IUserContext userContext, CancellationToken ct) =>
group.MapGet("{id:guid}/viewers", async ([FromRoute] Guid id, ISender sender, IUserContext userContext, CancellationToken ct) =>
{
var result = await sender.Send(new GetStoryViewersQuery(userContext.UserId, id), ct);
if (result.IsFailure) return result.Error.Code == "Unauthorized" ? Results.Forbid() : Results.NotFound();
return Results.Ok(result.Value);
});
group.MapDelete("{id:guid}", async (Guid id, ISender sender, IUserContext userContext, CancellationToken ct) =>
group.MapDelete("{id:guid}", async ([FromRoute] Guid id, ISender sender, IUserContext userContext, CancellationToken ct) =>
{
var result = await sender.Send(new DeleteStoryCommand(userContext.UserId, id), ct);
if (result.IsFailure) return result.Error.Code == "Unauthorized" ? Results.Forbid() : Results.NotFound();