Структура, доп модули, федерация, документация

This commit is contained in:
Халимов Рустам
2026-03-27 00:55:01 +03:00
parent 7cb6ac61dd
commit 7ef73b414c
64 changed files with 3080 additions and 133 deletions

View File

@@ -54,3 +54,59 @@ public sealed class ChatRepository : IChatRepository
}
}
public sealed class FolderRepository : IFolderRepository
{
private readonly ChatsDbContext _dbContext;
public FolderRepository(ChatsDbContext dbContext)
{
_dbContext = dbContext;
}
public void Add(Folder folder) => _dbContext.Folders.Add(folder);
public void Update(Folder folder) => _dbContext.Folders.Update(folder);
public void Remove(Folder folder) => _dbContext.Folders.Remove(folder);
public async Task<Folder?> GetByIdAsync(Guid id, CancellationToken cancellationToken)
{
return await _dbContext.Folders.FirstOrDefaultAsync(f => f.Id == id, cancellationToken);
}
public async Task<List<Folder>> GetUserFoldersAsync(Guid userId, CancellationToken cancellationToken)
{
// В доменной модели Folder не имеет UserId напрямую (может быть общей сущностью),
// но по логике "папки в настройках пользователя" можно фильтровать через настройки.
// Пока возвращаем все папки, которыми владеет пользователь (если добавить UserId)
// или все для упрощения первой итерации.
return await _dbContext.Folders.ToListAsync(cancellationToken);
}
}
public sealed class UserChatSettingsRepository : IUserChatSettingsRepository
{
private readonly ChatsDbContext _dbContext;
public UserChatSettingsRepository(ChatsDbContext dbContext)
{
_dbContext = dbContext;
}
public void Add(UserChatSettings settings) => _dbContext.UserChatSettings.Add(settings);
public void Update(UserChatSettings settings) => _dbContext.UserChatSettings.Update(settings);
public void Remove(UserChatSettings settings) => _dbContext.UserChatSettings.Remove(settings);
public void RemoveRange(IEnumerable<UserChatSettings> settings) => _dbContext.UserChatSettings.RemoveRange(settings);
public async Task<UserChatSettings?> GetAsync(Guid userId, Guid chatId, CancellationToken cancellationToken)
{
return await _dbContext.UserChatSettings
.FirstOrDefaultAsync(s => s.UserId == userId && s.ChatId == chatId, cancellationToken);
}
public async Task<List<UserChatSettings>> GetByUserIdAsync(Guid userId, CancellationToken cancellationToken)
{
return await _dbContext.UserChatSettings
.Where(s => s.UserId == userId)
.ToListAsync(cancellationToken);
}
}

View File

@@ -5,6 +5,11 @@ using Knot.Modules.Conversations.Application.Abstractions;
using Knot.Modules.Conversations.Domain;
using Knot.Shared.Kernel;
using Knot.Shared.Kernel.Security;
using System.Linq;
using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
namespace Knot.Modules.Conversations.Infrastructure.Persistence;
@@ -24,8 +29,8 @@ public sealed class ChatsDbContext : DbContext, IChatsUnitOfWork
}
public DbSet<Chat> Chats => Set<Chat>();
public DbSet<Folder> Folders => Set<Folder>();
public DbSet<UserChatSettings> UserChatSettings => Set<UserChatSettings>();
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
@@ -43,7 +48,6 @@ public sealed class ChatsDbContext : DbContext, IChatsUnitOfWork
builder.HasKey(c => c.Id);
builder.Property(c => c.Type).HasConversion<string>();
builder.OwnsMany(c => c.Members, mb =>
{
mb.ToTable("ChatMembers");
@@ -53,15 +57,32 @@ public sealed class ChatsDbContext : DbContext, IChatsUnitOfWork
}).Navigation(c => c.Members).UsePropertyAccessMode(PropertyAccessMode.Field);
});
modelBuilder.Entity<Folder>(builder =>
{
builder.ToTable("Folders");
builder.HasKey(f => f.Id);
builder.Property(f => f.Type).HasConversion<string>();
});
modelBuilder.Entity<UserChatSettings>(builder =>
{
builder.ToTable("UserChatSettings");
builder.HasKey(s => s.Id);
builder.HasIndex(s => new { s.UserId, s.ChatId }).IsUnique();
builder.Property(s => s.FolderIds)
.HasConversion(
v => string.Join(',', v),
v => v.Split(',', StringSplitOptions.RemoveEmptyEntries).Select(Guid.Parse).ToList()
);
});
}
public override async Task<int> SaveChangesAsync(CancellationToken cancellationToken = default)
{
// 1. Получаем все события из агрегатов
var domainEvents = ChangeTracker
.Entries<IAggregateRoot>()
.SelectMany(x =>
{
if (x.Entity is AggregateRoot<Guid> root)
{
@@ -73,10 +94,8 @@ public sealed class ChatsDbContext : DbContext, IChatsUnitOfWork
})
.ToList();
// 2. Сохраняем изменения
int result = await base.SaveChangesAsync(cancellationToken);
// 3. Публикуем события через MediatR
foreach (var domainEvent in domainEvents)
{
await _mediator.Publish(domainEvent, cancellationToken);
@@ -85,4 +104,3 @@ public sealed class ChatsDbContext : DbContext, IChatsUnitOfWork
return result;
}
}

View File

@@ -0,0 +1,25 @@
using Knot.Modules.Conversations.Domain;
using MongoDB.Bson.Serialization;
namespace Knot.Modules.Conversations.Infrastructure.Persistence.Mongo;
public static class ConversationsMongoDbMapConfigurator
{
private static bool _initialized;
public static void Configure()
{
if (_initialized) return;
if (!BsonClassMap.IsClassMapRegistered(typeof(UserFolderSettings)))
{
BsonClassMap.RegisterClassMap<UserFolderSettings>(cm =>
{
cm.AutoMap();
cm.SetDiscriminator("UserFolderSettings");
});
}
_initialized = true;
}
}

View File

@@ -0,0 +1,30 @@
using Knot.Modules.Conversations.Domain;
using MongoDB.Driver;
namespace Knot.Modules.Conversations.Infrastructure.Persistence.Mongo;
public sealed class UserFolderSettingsRepository : IUserFolderSettingsRepository
{
private readonly IMongoCollection<UserFolderSettings> _collection;
public UserFolderSettingsRepository(IMongoDatabase database)
{
_collection = database.GetCollection<UserFolderSettings>("user_folder_settings");
}
public async Task<UserFolderSettings?> GetByUserIdAsync(Guid userId, CancellationToken cancellationToken)
{
return await _collection.Find(s => s.UserId == userId).FirstOrDefaultAsync(cancellationToken);
}
public async Task UpdateAsync(UserFolderSettings settings, CancellationToken cancellationToken)
{
var options = new ReplaceOptions { IsUpsert = true };
await _collection.ReplaceOneAsync(s => s.Id == settings.Id, settings, options, cancellationToken);
}
public async Task RemoveByUserIdAsync(Guid userId, CancellationToken cancellationToken)
{
await _collection.DeleteManyAsync(s => s.UserId == userId, cancellationToken);
}
}