Правки
This commit is contained in:
@@ -0,0 +1,35 @@
|
|||||||
|
using System;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Knot.Modules.Relations.Application.Abstractions;
|
||||||
|
using Knot.Modules.Relations.Domain;
|
||||||
|
using Knot.Shared.Kernel;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
|
||||||
|
namespace Knot.Modules.Relations.Application.Contacts;
|
||||||
|
|
||||||
|
public record DeclineContactRequestCommand(Guid UserId, Guid RequestId) : ICommand<bool>;
|
||||||
|
|
||||||
|
internal sealed class DeclineContactRequestCommandHandler : ICommandHandler<DeclineContactRequestCommand, bool>
|
||||||
|
{
|
||||||
|
private readonly IContactsDbContext _context;
|
||||||
|
|
||||||
|
public DeclineContactRequestCommandHandler(IContactsDbContext context)
|
||||||
|
{
|
||||||
|
_context = context;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<Result<bool>> Handle(DeclineContactRequestCommand request, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
var contact = await _context.Contacts.FirstOrDefaultAsync(c => c.Id == request.RequestId, cancellationToken);
|
||||||
|
if (contact == null || contact.ContactId != request.UserId)
|
||||||
|
{
|
||||||
|
return Result.Failure<bool>(new Error("Contacts.NotFound", "Contact request not found."));
|
||||||
|
}
|
||||||
|
|
||||||
|
contact.Decline();
|
||||||
|
await _context.SaveChangesAsync(cancellationToken);
|
||||||
|
|
||||||
|
return Result.Success(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,12 +1,14 @@
|
|||||||
using Carter;
|
using Carter;
|
||||||
using Knot.Shared.Kernel;
|
using Knot.Contracts.Relations.Domain;
|
||||||
using Knot.Shared.Infrastructure;
|
|
||||||
using Knot.Modules.Relations.Application.Contacts;
|
using Knot.Modules.Relations.Application.Contacts;
|
||||||
|
using Knot.Shared.Infrastructure;
|
||||||
|
using Knot.Shared.Kernel;
|
||||||
using MediatR;
|
using MediatR;
|
||||||
using Microsoft.AspNetCore.Builder;
|
using Microsoft.AspNetCore.Builder;
|
||||||
using Microsoft.AspNetCore.Http;
|
using Microsoft.AspNetCore.Http;
|
||||||
using Microsoft.AspNetCore.Routing;
|
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using Microsoft.AspNetCore.Routing;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
|
||||||
namespace Knot.Modules.Relations.Presentation.Endpoints;
|
namespace Knot.Modules.Relations.Presentation.Endpoints;
|
||||||
|
|
||||||
@@ -22,6 +24,51 @@ public sealed class ContactsEndpoints : ICarterModule
|
|||||||
return result.IsSuccess ? Results.Ok(result.Value) : Results.BadRequest(result.Error);
|
return result.IsSuccess ? Results.Ok(result.Value) : Results.BadRequest(result.Error);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
group.MapGet("requests", async (ISender sender, IUserContext userContext, CancellationToken ct) =>
|
||||||
|
{
|
||||||
|
var result = await sender.Send(new GetIncomingRequestsQuery(userContext.UserId), ct);
|
||||||
|
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) =>
|
||||||
|
{
|
||||||
|
var contact = await context.Contacts
|
||||||
|
.FirstOrDefaultAsync(c =>
|
||||||
|
(c.UserId == userContext.UserId && c.ContactId == userId) ||
|
||||||
|
(c.UserId == userId && c.ContactId == userContext.UserId), ct);
|
||||||
|
|
||||||
|
if (contact == null)
|
||||||
|
{
|
||||||
|
return Results.Ok(new { status = "none", friendshipId = (string?)null });
|
||||||
|
}
|
||||||
|
|
||||||
|
string status;
|
||||||
|
string? friendshipId = contact.Id.ToString();
|
||||||
|
|
||||||
|
if (contact.UserId == userContext.UserId && contact.Status == ContactStatus.Pending)
|
||||||
|
{
|
||||||
|
status = "outgoing";
|
||||||
|
}
|
||||||
|
else if (contact.Status == ContactStatus.Pending)
|
||||||
|
{
|
||||||
|
status = "pending";
|
||||||
|
}
|
||||||
|
else if (contact.Status == ContactStatus.Accepted)
|
||||||
|
{
|
||||||
|
status = "accepted";
|
||||||
|
}
|
||||||
|
else if (contact.Status == ContactStatus.Declined)
|
||||||
|
{
|
||||||
|
status = "declined";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
status = "none";
|
||||||
|
}
|
||||||
|
|
||||||
|
return Results.Ok(new { status, friendshipId });
|
||||||
|
});
|
||||||
|
|
||||||
group.MapPost("request", async ([FromBody] SendContactRequest request, ISender sender, IUserContext userContext, CancellationToken ct) =>
|
group.MapPost("request", async ([FromBody] SendContactRequest request, ISender sender, IUserContext userContext, CancellationToken ct) =>
|
||||||
{
|
{
|
||||||
var result = await sender.Send(new SendContactRequestCommand(userContext.UserId, request.ContactId), ct);
|
var result = await sender.Send(new SendContactRequestCommand(userContext.UserId, request.ContactId), ct);
|
||||||
@@ -34,6 +81,12 @@ public sealed class ContactsEndpoints : ICarterModule
|
|||||||
return result.IsSuccess ? Results.Ok(new { id = result.Value }) : Results.NotFound(result.Error.Description);
|
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) =>
|
||||||
|
{
|
||||||
|
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 (Guid id, ISender sender, IUserContext userContext, CancellationToken ct) =>
|
||||||
{
|
{
|
||||||
var result = await sender.Send(new RemoveContactCommand(userContext.UserId, id), ct);
|
var result = await sender.Send(new RemoveContactCommand(userContext.UserId, id), ct);
|
||||||
|
|||||||
+33
-1
@@ -1 +1,33 @@
|
|||||||
// file removed
|
using System;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Knot.Modules.Stories.Application.Abstractions;
|
||||||
|
using Knot.Shared.Kernel;
|
||||||
|
|
||||||
|
namespace Knot.Modules.Stories.Application.Stories.Commands.AddStoryReaction;
|
||||||
|
|
||||||
|
public record AddStoryReactionCommand(Guid UserId, Guid StoryId, string Emoji) : ICommand<bool>;
|
||||||
|
|
||||||
|
internal sealed class AddStoryReactionCommandHandler : ICommandHandler<AddStoryReactionCommand, bool>
|
||||||
|
{
|
||||||
|
private readonly IStoryRepository _storyRepository;
|
||||||
|
|
||||||
|
public AddStoryReactionCommandHandler(IStoryRepository storyRepository)
|
||||||
|
{
|
||||||
|
_storyRepository = storyRepository;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<Result<bool>> Handle(AddStoryReactionCommand request, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
var story = await _storyRepository.GetByIdAsync(request.StoryId, cancellationToken);
|
||||||
|
if (story == null)
|
||||||
|
{
|
||||||
|
return Result.Failure<bool>(new Error("Stories.NotFound", "Story not found."));
|
||||||
|
}
|
||||||
|
|
||||||
|
story.AddReaction(request.UserId, request.Emoji);
|
||||||
|
await _storyRepository.UpdateAsync(story, cancellationToken);
|
||||||
|
|
||||||
|
return Result.Success(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
+33
-1
@@ -1 +1,33 @@
|
|||||||
// file removed
|
using System;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Knot.Modules.Stories.Application.Abstractions;
|
||||||
|
using Knot.Shared.Kernel;
|
||||||
|
|
||||||
|
namespace Knot.Modules.Stories.Application.Stories.Commands.AddStoryReply;
|
||||||
|
|
||||||
|
public record AddStoryReplyCommand(Guid UserId, Guid StoryId, string Content) : ICommand<bool>;
|
||||||
|
|
||||||
|
internal sealed class AddStoryReplyCommandHandler : ICommandHandler<AddStoryReplyCommand, bool>
|
||||||
|
{
|
||||||
|
private readonly IStoryRepository _storyRepository;
|
||||||
|
|
||||||
|
public AddStoryReplyCommandHandler(IStoryRepository storyRepository)
|
||||||
|
{
|
||||||
|
_storyRepository = storyRepository;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<Result<bool>> Handle(AddStoryReplyCommand request, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
var story = await _storyRepository.GetByIdAsync(request.StoryId, cancellationToken);
|
||||||
|
if (story == null)
|
||||||
|
{
|
||||||
|
return Result.Failure<bool>(new Error("Stories.NotFound", "Story not found."));
|
||||||
|
}
|
||||||
|
|
||||||
|
story.AddReply(request.UserId, request.Content);
|
||||||
|
await _storyRepository.UpdateAsync(story, cancellationToken);
|
||||||
|
|
||||||
|
return Result.Success(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
+33
-1
@@ -1 +1,33 @@
|
|||||||
// file removed
|
using System;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Knot.Modules.Stories.Application.Abstractions;
|
||||||
|
using Knot.Shared.Kernel;
|
||||||
|
|
||||||
|
namespace Knot.Modules.Stories.Application.Stories.Commands.RemoveStoryReaction;
|
||||||
|
|
||||||
|
public record RemoveStoryReactionCommand(Guid UserId, Guid StoryId, string Emoji) : ICommand<bool>;
|
||||||
|
|
||||||
|
internal sealed class RemoveStoryReactionCommandHandler : ICommandHandler<RemoveStoryReactionCommand, bool>
|
||||||
|
{
|
||||||
|
private readonly IStoryRepository _storyRepository;
|
||||||
|
|
||||||
|
public RemoveStoryReactionCommandHandler(IStoryRepository storyRepository)
|
||||||
|
{
|
||||||
|
_storyRepository = storyRepository;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<Result<bool>> Handle(RemoveStoryReactionCommand request, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
var story = await _storyRepository.GetByIdAsync(request.StoryId, cancellationToken);
|
||||||
|
if (story == null)
|
||||||
|
{
|
||||||
|
return Result.Failure<bool>(new Error("Stories.NotFound", "Story not found."));
|
||||||
|
}
|
||||||
|
|
||||||
|
story.RemoveReaction(request.UserId, request.Emoji);
|
||||||
|
await _storyRepository.UpdateAsync(story, cancellationToken);
|
||||||
|
|
||||||
|
return Result.Success(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -0,0 +1,11 @@
|
|||||||
|
namespace Knot.Modules.Stories.Application.Stories.DTOs;
|
||||||
|
|
||||||
|
public record StoryReplyDto(
|
||||||
|
Guid Id,
|
||||||
|
Guid UserId,
|
||||||
|
string Username,
|
||||||
|
string DisplayName,
|
||||||
|
string? Avatar,
|
||||||
|
string Content,
|
||||||
|
DateTime CreatedAt
|
||||||
|
);
|
||||||
+42
-1
@@ -1 +1,42 @@
|
|||||||
// file removed
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Knot.Modules.Stories.Application.Abstractions;
|
||||||
|
using Knot.Modules.Stories.Application.Stories.DTOs;
|
||||||
|
using Knot.Shared.Kernel;
|
||||||
|
|
||||||
|
namespace Knot.Modules.Stories.Application.Stories.Queries.GetStoryReplies;
|
||||||
|
|
||||||
|
public record GetStoryRepliesQuery(Guid UserId, Guid StoryId) : IQuery<List<StoryReplyDto>>;
|
||||||
|
|
||||||
|
internal sealed class GetStoryRepliesQueryHandler : IQueryHandler<GetStoryRepliesQuery, List<StoryReplyDto>>
|
||||||
|
{
|
||||||
|
private readonly IStoryRepository _storyRepository;
|
||||||
|
|
||||||
|
public GetStoryRepliesQueryHandler(IStoryRepository storyRepository)
|
||||||
|
{
|
||||||
|
_storyRepository = storyRepository;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<Result<List<StoryReplyDto>>> Handle(GetStoryRepliesQuery request, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
var story = await _storyRepository.GetByIdAsync(request.StoryId, cancellationToken);
|
||||||
|
if (story == null)
|
||||||
|
{
|
||||||
|
return Result.Failure<List<StoryReplyDto>>(new Error("Stories.NotFound", "Story not found."));
|
||||||
|
}
|
||||||
|
|
||||||
|
var replies = story.Replies.ConvertAll(r => new StoryReplyDto(
|
||||||
|
r.Id,
|
||||||
|
r.UserId,
|
||||||
|
r.Username,
|
||||||
|
r.DisplayName,
|
||||||
|
r.Avatar,
|
||||||
|
r.Content,
|
||||||
|
r.CreatedAt
|
||||||
|
));
|
||||||
|
|
||||||
|
return Result.Success(replies);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,7 +1,25 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
using Knot.Shared.Kernel;
|
using Knot.Shared.Kernel;
|
||||||
|
|
||||||
namespace Knot.Modules.Stories.Domain;
|
namespace Knot.Modules.Stories.Domain;
|
||||||
|
|
||||||
|
public class StoryReaction
|
||||||
|
{
|
||||||
|
public Guid UserId { get; set; }
|
||||||
|
public string Emoji { get; set; } = string.Empty;
|
||||||
|
}
|
||||||
|
|
||||||
|
public class StoryReply
|
||||||
|
{
|
||||||
|
public Guid Id { get; set; }
|
||||||
|
public Guid UserId { get; set; }
|
||||||
|
public string Username { get; set; } = string.Empty;
|
||||||
|
public string DisplayName { get; set; } = string.Empty;
|
||||||
|
public string? Avatar { get; set; }
|
||||||
|
public string Content { get; set; } = string.Empty;
|
||||||
|
public DateTime CreatedAt { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
public class Story : Entity<Guid>
|
public class Story : Entity<Guid>
|
||||||
{
|
{
|
||||||
public Guid UserId { get; private set; }
|
public Guid UserId { get; private set; }
|
||||||
@@ -11,6 +29,8 @@ public class Story : Entity<Guid>
|
|||||||
public string? BgColor { get; private set; }
|
public string? BgColor { get; private set; }
|
||||||
public DateTime CreatedAt { get; private set; }
|
public DateTime CreatedAt { get; private set; }
|
||||||
public int ViewsCount { get; private set; }
|
public int ViewsCount { get; private set; }
|
||||||
|
public List<StoryReaction> Reactions { get; private set; } = new();
|
||||||
|
public List<StoryReply> Replies { get; private set; } = new();
|
||||||
|
|
||||||
protected Story() : base(Guid.NewGuid()) { }
|
protected Story() : base(Guid.NewGuid()) { }
|
||||||
|
|
||||||
@@ -33,4 +53,33 @@ public class Story : Entity<Guid>
|
|||||||
{
|
{
|
||||||
ViewsCount++;
|
ViewsCount++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void AddReaction(Guid userId, string emoji)
|
||||||
|
{
|
||||||
|
var existing = Reactions.FirstOrDefault(r => r.UserId == userId && r.Emoji == emoji);
|
||||||
|
if (existing == null)
|
||||||
|
{
|
||||||
|
Reactions.Add(new StoryReaction { UserId = userId, Emoji = emoji });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void RemoveReaction(Guid userId, string emoji)
|
||||||
|
{
|
||||||
|
var reaction = Reactions.FirstOrDefault(r => r.UserId == userId && r.Emoji == emoji);
|
||||||
|
if (reaction != null)
|
||||||
|
{
|
||||||
|
Reactions.Remove(reaction);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void AddReply(Guid userId, string content)
|
||||||
|
{
|
||||||
|
Replies.Add(new StoryReply
|
||||||
|
{
|
||||||
|
Id = Guid.NewGuid(),
|
||||||
|
UserId = userId,
|
||||||
|
Content = content,
|
||||||
|
CreatedAt = DateTime.UtcNow
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,17 +1,23 @@
|
|||||||
using Carter;
|
using Carter;
|
||||||
using Knot.Modules.Stories.Application.DTOs;
|
using Knot.Modules.Stories.Application.DTOs;
|
||||||
|
using Knot.Modules.Stories.Application.Stories.Commands.AddStoryReaction;
|
||||||
|
using Knot.Modules.Stories.Application.Stories.Commands.AddStoryReply;
|
||||||
|
using Knot.Modules.Stories.Application.Stories.Commands.CreateStory;
|
||||||
|
using Knot.Modules.Stories.Application.Stories.Commands.DeleteStory;
|
||||||
|
using Knot.Modules.Stories.Application.Stories.Commands.RemoveStoryReaction;
|
||||||
|
using Knot.Modules.Stories.Application.Stories.Commands.ViewStory;
|
||||||
|
using Knot.Modules.Stories.Application.Stories.Queries.GetStories;
|
||||||
|
using Knot.Modules.Stories.Application.Stories.Queries.GetStoryReplies;
|
||||||
|
using Knot.Modules.Stories.Application.Stories.Queries.GetStoryViewers;
|
||||||
|
using Knot.Modules.Stories.Application.Stories.Queries.GetUserStories;
|
||||||
|
using Knot.Modules.Stories.Domain;
|
||||||
using Knot.Shared.Kernel;
|
using Knot.Shared.Kernel;
|
||||||
|
using Knot.Shared.Kernel.Storage;
|
||||||
using MediatR;
|
using MediatR;
|
||||||
using Microsoft.AspNetCore.Builder;
|
using Microsoft.AspNetCore.Builder;
|
||||||
using Microsoft.AspNetCore.Http;
|
using Microsoft.AspNetCore.Http;
|
||||||
using Microsoft.AspNetCore.Routing;
|
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using Knot.Modules.Stories.Application.Stories.Queries.GetStories;
|
using Microsoft.AspNetCore.Routing;
|
||||||
using Knot.Modules.Stories.Application.Stories.Commands.CreateStory;
|
|
||||||
using Knot.Modules.Stories.Application.Stories.Queries.GetUserStories;
|
|
||||||
using Knot.Modules.Stories.Application.Stories.Commands.ViewStory;
|
|
||||||
using Knot.Modules.Stories.Application.Stories.Queries.GetStoryViewers;
|
|
||||||
using Knot.Modules.Stories.Application.Stories.Commands.DeleteStory;
|
|
||||||
|
|
||||||
namespace Knot.Modules.Stories.Presentation.Endpoints;
|
namespace Knot.Modules.Stories.Presentation.Endpoints;
|
||||||
|
|
||||||
@@ -33,6 +39,18 @@ public sealed class StoriesEndpoints : ICarterModule
|
|||||||
return Results.Ok(new { id = result.Value });
|
return Results.Ok(new { id = result.Value });
|
||||||
});
|
});
|
||||||
|
|
||||||
|
group.MapPost("video", async (HttpRequest req, ISender sender, IUserContext userContext, IFileStorageService fileStorage, CancellationToken ct) =>
|
||||||
|
{
|
||||||
|
if (!req.HasFormContentType) return Results.BadRequest("No file uploaded");
|
||||||
|
var form = await req.ReadFormAsync(ct);
|
||||||
|
var file = form.Files.FirstOrDefault();
|
||||||
|
if (file == null || file.Length == 0) return Results.BadRequest("No file uploaded");
|
||||||
|
|
||||||
|
using var stream = file.OpenReadStream();
|
||||||
|
var fileId = await fileStorage.UploadFileAsync(stream, file.FileName, file.ContentType);
|
||||||
|
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 (Guid userId, ISender sender, IUserContext userContext, CancellationToken ct) =>
|
||||||
{
|
{
|
||||||
var result = await sender.Send(new GetUserStoriesQuery(userContext.UserId, userId), ct);
|
var result = await sender.Send(new GetUserStoriesQuery(userContext.UserId, userId), ct);
|
||||||
@@ -58,6 +76,30 @@ public sealed class StoriesEndpoints : ICarterModule
|
|||||||
if (result.IsFailure) return result.Error.Code == "Unauthorized" ? Results.Forbid() : Results.NotFound();
|
if (result.IsFailure) return result.Error.Code == "Unauthorized" ? Results.Forbid() : Results.NotFound();
|
||||||
return Results.Ok(result.Value);
|
return Results.Ok(result.Value);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
group.MapPost("{id:guid}/reaction", async (Guid id, [FromBody] AddStoryReactionRequest request, ISender sender, IUserContext userContext, CancellationToken ct) =>
|
||||||
|
{
|
||||||
|
var result = await sender.Send(new AddStoryReactionCommand(userContext.UserId, id, request.Emoji), ct);
|
||||||
|
return result.IsSuccess ? Results.Ok(new { message = "Reaction added" }) : Results.NotFound();
|
||||||
|
});
|
||||||
|
|
||||||
|
group.MapDelete("{id:guid}/reaction", async (Guid id, [FromBody] RemoveStoryReactionRequest request, ISender sender, IUserContext userContext, CancellationToken ct) =>
|
||||||
|
{
|
||||||
|
var result = await sender.Send(new RemoveStoryReactionCommand(userContext.UserId, id, request.Emoji), ct);
|
||||||
|
return result.IsSuccess ? Results.Ok(new { message = "Reaction removed" }) : Results.NotFound();
|
||||||
|
});
|
||||||
|
|
||||||
|
group.MapPost("{id:guid}/reply", async (Guid id, [FromBody] AddStoryReplyRequest request, ISender sender, IUserContext userContext, CancellationToken ct) =>
|
||||||
|
{
|
||||||
|
var result = await sender.Send(new AddStoryReplyCommand(userContext.UserId, id, request.Content), ct);
|
||||||
|
return result.IsSuccess ? Results.Ok(new { message = "Reply added" }) : Results.NotFound();
|
||||||
|
});
|
||||||
|
|
||||||
|
group.MapGet("{id:guid}/replies", async (Guid id, ISender sender, IUserContext userContext, CancellationToken ct) =>
|
||||||
|
{
|
||||||
|
var result = await sender.Send(new GetStoryRepliesQuery(userContext.UserId, id), ct);
|
||||||
|
return result.IsSuccess ? Results.Ok(result.Value) : Results.NotFound();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,37 +3,33 @@ import type { FriendshipStatus, FriendRequest, FriendWithId } from '../../../cor
|
|||||||
|
|
||||||
export class FriendApi {
|
export class FriendApi {
|
||||||
static async getFriends() {
|
static async getFriends() {
|
||||||
return httpClient.request<FriendWithId[]>('/friends');
|
return httpClient.request<FriendWithId[]>('/contacts');
|
||||||
}
|
}
|
||||||
|
|
||||||
static async getFriendRequests() {
|
static async getFriendRequests() {
|
||||||
return httpClient.request<FriendRequest[]>('/friends/requests');
|
return httpClient.request<FriendRequest[]>('/contacts/requests');
|
||||||
}
|
|
||||||
|
|
||||||
static async getOutgoingRequests() {
|
|
||||||
return httpClient.request<FriendRequest[]>('/friends/outgoing');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static async getFriendshipStatus(userId: string) {
|
static async getFriendshipStatus(userId: string) {
|
||||||
return httpClient.request<FriendshipStatus>(`/friends/status/${userId}`);
|
return httpClient.request<FriendshipStatus>(`/contacts/status/${userId}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
static async sendFriendRequest(friendId: string) {
|
static async sendFriendRequest(friendId: string) {
|
||||||
return httpClient.request<{ status: string }>('/friends/request', {
|
return httpClient.request<{ status: string }>('/contacts/request', {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
body: JSON.stringify({ friendId }),
|
body: JSON.stringify({ contactId: friendId }),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
static async acceptFriendRequest(friendshipId: string) {
|
static async acceptFriendRequest(friendshipId: string) {
|
||||||
return httpClient.request<{ id: string }>(`/friends/${friendshipId}/accept`, { method: 'POST' });
|
return httpClient.request<{ id: string }>(`/contacts/${friendshipId}/accept`, { method: 'POST' });
|
||||||
}
|
}
|
||||||
|
|
||||||
static async declineFriendRequest(friendshipId: string) {
|
static async declineFriendRequest(friendshipId: string) {
|
||||||
return httpClient.request<{ success: boolean }>(`/friends/${friendshipId}/decline`, { method: 'POST' });
|
return httpClient.request<{ success: boolean }>(`/contacts/${friendshipId}/decline`, { method: 'POST' });
|
||||||
}
|
}
|
||||||
|
|
||||||
static async removeFriend(friendshipId: string) {
|
static async removeFriend(friendshipId: string) {
|
||||||
return httpClient.request<{ success: boolean }>(`/friends/${friendshipId}`, { method: 'DELETE' });
|
return httpClient.request<{ success: boolean }>(`/contacts/${friendshipId}`, { method: 'DELETE' });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user