Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions server/Directory.Packages.props
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,12 @@
<PackageVersion Include="EntityFrameworkCore.Exceptions.Common" Version="10.0.0" />
<PackageVersion Include="Hangfire" Version="1.8.23" />
<PackageVersion Include="Jdenticon-net" Version="3.1.2" />
<PackageVersion Include="MediatR" Version="14.1.0" />
<PackageVersion Include="Microsoft.AspNetCore.DataProtection.EntityFrameworkCore" Version="10.0.7" />
<PackageVersion Include="Microsoft.AspNetCore.OpenApi" Version="10.0.7" />
<PackageVersion Include="Microsoft.AspNetCore.OutputCaching.StackExchangeRedis" Version="10.0.7" />
<PackageVersion Include="Microsoft.AspNetCore.SignalR.StackExchangeRedis" Version="10.0.7" />
<PackageVersion Include="Microsoft.EntityFrameworkCore.Tools" Version="10.0.7" />
<PackageVersion Include="Microsoft.Extensions.Caching.StackExchangeRedis" Version="10.0.7" />
<PackageVersion Include="Microsoft.Extensions.Http.Resilience" Version="10.5.0" />
<PackageVersion Include="Microsoft.Extensions.ServiceDiscovery" Version="10.5.0" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,6 @@ public interface IAppDbContext
DbSet<Tag> Tags { get; }

DbSet<Card> Cards { get; }

DbSet<CardComment> CardComments { get; }
Task<int> SaveChangesAsync(CancellationToken cancellationToken = default);
}
2 changes: 1 addition & 1 deletion server/src/Application/Boards/Create/CreateBoardCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,5 @@ public sealed record CreateBoardMemberRequest(int UserId, MemberRole Role);

public sealed record CreateBoardCommand(
string Title,
string Description,
string? Description,
IReadOnlyList<CreateBoardMemberRequest>? Members = null) : ICommand<int>;
2 changes: 1 addition & 1 deletion server/src/Application/Boards/Get/GetBoardsResponse.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ public sealed record UserDto(int Id, string UserName)
public sealed record BoardDto(
int Id,
string Title,
string Description,
string? Description,
MemberRole YourRole,
DateTimeOffset CreatedAt,
UserDto CreatedBy,
Expand Down
11 changes: 10 additions & 1 deletion server/src/Application/Boards/GetById/GetBoardByIdHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,16 @@ public async Task<Result<GetBoardByIdResponse>> Handle(GetBoardByIdQuery query,
c.CreatedAt,
UserDto.From(c.CreatedBy),
c.UpdatedAt,
UserDto.From(c.UpdatedBy)))
UserDto.From(c.UpdatedBy),
c.Comments
.OrderBy(comm => comm.CreatedAt)
.Select(comm => new CardCommentDto(
comm.Id,
comm.UserId,
comm.User.UserName ?? "Unknown",
comm.Content,
comm.CreatedAt))
.ToList()))
.ToList()))
.ToList()))
.ToList()))
Expand Down
14 changes: 11 additions & 3 deletions server/src/Application/Boards/GetById/GetBoardByIdResponse.cs
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
using System.Diagnostics.CodeAnalysis;
using Snapflow.Application.Cards.AddComment;
using static Snapflow.Application.Boards.GetById.GetBoardByIdResponse;

namespace Snapflow.Application.Boards.GetById;

public sealed record GetBoardByIdResponse(
int Id,
string Title,
string Description,
string? Description,
IReadOnlyList<SwimlaneDto> Swimlanes)
{
public sealed record UserDto(int Id, string UserName)
Expand Down Expand Up @@ -34,10 +35,17 @@ public sealed record ListDto(
public sealed record CardDto(
int Id,
string Title,
string Description,
string? Description,
string Rank,
DateTimeOffset CreatedAt,
UserDto CreatedBy,
DateTimeOffset? UpdatedAt,
UserDto? UpdatedBy);
UserDto? UpdatedBy,
List<CardCommentDto> Comments);
public sealed record CardCommentDto(
int Id,
int UserId,
string UserName,
string Content,
DateTimeOffset CreatedAt);
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ namespace Snapflow.Application.Boards.GetDetails;
public sealed record GetBoardDetailsResponse(
int Id,
string Title,
string Description,
string? Description,
IReadOnlyList<GetBoardDetailsMemberResponse> Members);

public sealed record GetBoardDetailsMemberResponse(
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
using Snapflow.Application.Abstractions.Messaging;
using Snapflow.Application.Boards.GetById;

namespace Snapflow.Application.Cards.AddComment;

public sealed record AddCardCommentCommand(int CardId, int UserId, string Content)
: ICommand<GetBoardByIdResponse.CardCommentDto>;
46 changes: 46 additions & 0 deletions server/src/Application/Cards/AppComment/AddCardCommentHandler.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
using Microsoft.EntityFrameworkCore;
using Snapflow.Application.Abstractions.Messaging;
using Snapflow.Application.Abstractions.Persistence;
using Snapflow.Application.Boards.GetById;
using Snapflow.Common;
using Snapflow.Domain.Cards;

namespace Snapflow.Application.Cards.AddComment;

internal sealed class AddCardCommentCommandHandler(
IAppDbContext context) : ICommandHandler<AddCardCommentCommand, GetBoardByIdResponse.CardCommentDto> // <--- ZMIANA 1: Zwracamy DTO zamiast int
{
public async Task<Result<GetBoardByIdResponse.CardCommentDto>> Handle(AddCardCommentCommand request, CancellationToken cancellationToken = default)
{
var card = await context.Cards
.FirstOrDefaultAsync(c => c.Id == request.CardId && !c.IsDeleted, cancellationToken);

if (card is null)
{
return Result.Failure<GetBoardByIdResponse.CardCommentDto>(CardErrors.NotFound(request.CardId));
}

var user = await context.Users
.FirstOrDefaultAsync(u => u.Id == request.UserId, cancellationToken);

if (user is null)
{
return Result.Failure<GetBoardByIdResponse.CardCommentDto>(new Error("User.NotFound", "User not found", ErrorType.NotFound));
}
Comment thread
danielprokopowicz marked this conversation as resolved.

var comment = CardComment.Create(request.CardId, request.UserId, request.Content);

context.CardComments.Add(comment);
await context.SaveChangesAsync(cancellationToken);

var dto = new GetBoardByIdResponse.CardCommentDto(
comment.Id,
user.Id,
user.UserName ?? "Unknown",
comment.Content,
comment.CreatedAt
);

return dto;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,6 @@ public sealed record CardDto(
int SwimlaneId,
int BoardId,
string Title,
string Description,
string? Description,
string Rank);
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ public sealed record GetCardByIdResponse(
int SwimlaneId,
int BoardId,
string Title,
string Description,
string? Description,
string Rank,
DateTimeOffset CreatedAt,
UserDto CreatedBy,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,6 @@ public sealed record CardDto(
int SwimlaneId,
int BoardId,
string Title,
string Description,
string? Description,
string Rank);
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,6 @@ public sealed record CardDto(
int SwimlaneId,
int BoardId,
string Title,
string Description,
string? Description,
string Rank);
}
2 changes: 1 addition & 1 deletion server/src/Application/Cards/Update/UpdateCardCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@

namespace Snapflow.Application.Cards.Update;

public sealed record UpdateCardCommand(int Id, string Title, string Description) : ICommand<UpdateCardResponse>;
public sealed record UpdateCardCommand(int Id, string Title, string? Description) : ICommand<UpdateCardResponse>;
6 changes: 3 additions & 3 deletions server/src/Domain/Boards/Board.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ public class Board : Entity<int, Board>
public Board() { }

public string Title { get; private set; } = null!;
public string Description { get; private set; } = "";
public string? Description { get; private set; } = "";

Comment thread
danielprokopowicz marked this conversation as resolved.
public DateTimeOffset CreatedAt { get; private set; }
public int CreatedById { get; private set; }
Expand All @@ -34,7 +34,7 @@ public Board() { }
public virtual ICollection<Card> Cards { get; private set; } = [];
public virtual ICollection<Tag> Tags { get; private set; } = [];

public static Board Create(string title, string description, int createdById, DateTimeOffset createdAt, string? connectionId = null)
public static Board Create(string title, string? description, int createdById, DateTimeOffset createdAt, string? connectionId = null)
{
var board = new Board
{
Expand All @@ -51,7 +51,7 @@ public static Board Create(string title, string description, int createdById, Da
return board;
}

public void Update(string title, string description, int updatedById, DateTimeOffset updatedAt, string? connectionId = null)
public void Update(string title, string? description, int updatedById, DateTimeOffset updatedAt, string? connectionId = null)
{
Title = title;
Description = description;
Expand Down
2 changes: 1 addition & 1 deletion server/src/Domain/Boards/BoardEvents.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ public sealed record BoardCreatedDomainEvent(
public sealed record BoardUpdatedDomainEvent(
int Id,
string Title,
string Description,
string? Description,
string? ConnectionId) : IDomainEvent;

public sealed record BoardDeletedDomainEvent(
Expand Down
15 changes: 10 additions & 5 deletions server/src/Domain/Cards/Card.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,8 @@ public Card() { }
public virtual List List { get; private set; } = null!;

public string Title { get; private set; } = null!;
public string Description { get; private set; } = "";
public string? Description { get; private set; } = "";
public string Rank { get; set; } = null!;

public DateTimeOffset CreatedAt { get; private set; }
public int CreatedById { get; private set; }
public virtual IUser CreatedBy { get; private set; } = null!;
Expand All @@ -38,8 +37,10 @@ public Card() { }
public bool DeletedByCascade { get; private set; }

public virtual ICollection<Tag> Tags { get; private set; } = [];

public static Card Create(int boardId, int swimlaneId, int listId, string title, string description, string rank, int createdById, DateTimeOffset createdAt, string? connectionId = null)

private readonly List<CardComment> _comments = [];
public virtual IReadOnlyCollection<CardComment> Comments => _comments.AsReadOnly();
public static Card Create(int boardId, int swimlaneId, int listId, string title, string? description, string rank, int createdById, DateTimeOffset createdAt, string? connectionId = null)
{
var card = new Card
{
Expand All @@ -58,7 +59,7 @@ public static Card Create(int boardId, int swimlaneId, int listId, string title,
return card;
}

public void Update(string title, string description, int updatedById, DateTimeOffset updatedAt, string? connectionId = null)
public void Update(string title, string? description, int updatedById, DateTimeOffset updatedAt, string? connectionId = null)
{
Title = title;
Description = description;
Expand Down Expand Up @@ -88,4 +89,8 @@ public void SoftDelete(int deletedById, DateTimeOffset deletedAt, string? connec

Raise(c => new CardDeletedDomainEvent(Id, BoardId, connectionId));
}
public void AddComment(int userId, string content)
{
_comments.Add(CardComment.Create(Id, userId, content));
}
}
24 changes: 24 additions & 0 deletions server/src/Domain/Cards/CardComment.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
using Snapflow.Domain.Users;
using Snapflow.Common;

namespace Snapflow.Domain.Cards;

public class CardComment : Entity<int, CardComment>
{
public int CardId { get; private set; }
public int UserId { get; private set; }
public string Content { get; private set; } = null!;
public DateTimeOffset CreatedAt { get; private set; }
public virtual IUser User { get; private set; } = null!;

public static CardComment Create(int cardId, int userId, string content)
{
return new CardComment
{
CardId = cardId,
UserId = userId,
Content = content,
CreatedAt = DateTimeOffset.UtcNow
};
}
}
4 changes: 2 additions & 2 deletions server/src/Domain/Cards/CardEvents.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,15 @@ public sealed record CardCreatedDomainEvent(
int SwimlaneId,
int ListId,
string Title,
string Description,
string? Description,
string Rank,
string? ConnectionId) : IDomainEvent;

public sealed record CardUpdatedDomainEvent(
int Id,
int BoardId,
string Title,
string Description,
string? Description,
string? ConnectionId) : IDomainEvent;

public sealed record CardMovedDomainEvent(
Expand Down
4 changes: 4 additions & 0 deletions server/src/Infrastructure/Infrastructure.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@
<PackageReference Include="MailKit" />
<PackageReference Include="Microsoft.AspNetCore.DataProtection.EntityFrameworkCore" />
<PackageReference Include="Microsoft.AspNetCore.Identity" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.Extensions.Caching.StackExchangeRedis" />
<PackageReference Include="Microsoft.Extensions.Http.Resilience" />
<PackageReference Include="Microsoft.Extensions.Identity.Core" />
Expand Down
12 changes: 11 additions & 1 deletion server/src/Infrastructure/Persistence/AppDbContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
using Microsoft.EntityFrameworkCore.Metadata;
using Snapflow.Domain.Roles;


namespace Snapflow.Infrastructure.Persistence;

public sealed class AppDbContext(
Expand All @@ -28,7 +29,7 @@ public sealed class AppDbContext(
public DbSet<Member> Members { get; private set; }
public DbSet<Tag> Tags { get; private set; }
public DbSet<Card> Cards { get; private set; }

public DbSet<CardComment> CardComments => Set<CardComment>();
public DbSet<DataProtectionKey> DataProtectionKeys { get; private set; }

protected override void OnModelCreating(ModelBuilder builder)
Expand All @@ -44,5 +45,14 @@ protected override void OnModelCreating(ModelBuilder builder)
{
builder.Entity(entityType.ClrType).Ignore(nameof(IEntity.DomainEvents));
}
builder.Entity<CardComment>(entity =>
{
entity.HasOne(x => (AppUser)x.User)
.WithMany()
.HasForeignKey(x => x.UserId)
.OnDelete(DeleteBehavior.NoAction);

entity.ToTable("card_comments");
});
Comment thread
danielprokopowicz marked this conversation as resolved.
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -37,5 +37,8 @@ public void Configure(EntityTypeBuilder<Card> builder)

builder.HasIndex(c => c.ListId)
.HasFilter("is_deleted = false");
builder.Property(card => card.Description)
.HasMaxLength(2000)
.IsRequired(false);
}
}
Loading