Mam aplikację, która umożliwia użytkownikom łączenie się grupy. Przynależności są definiowane przez rekordy tabeli GroupMemberships
zawierającą klucze obce GroupId
i UserId
składające się jednocześnie na composite key. Przy dodawaniu użytkownika do grupy trzeba wykonać zapytania do tabeli GroupMemberships
, aby sprawdzić, czy dodawany użytkownik już nie jest członkiem tej grupy, do tabeli Users
aby sprawdzić, czy użytkownik istnieje, to tabeli Groups
, aby sprawdzić, czy grupa istnieje i czy dodający użytkownik jest jej adminem, i w końcu do GroupMemberships
. Tylko że to są aż cztery zapytania do tak prostej czynności. Zastanawiam się, czy nie zostawić jedynie walidacji tego, czy użytkownik jest adminem. Pozostałe przypadki, przed którymi próbuję się chronić, są mało prawdopodobne i nie powodują luk bezpieczeństwa, bo przecież SQL nie pozwoli na zapis i serwer zwróci Internal Server Error
. Co sądzicie?
public async Task<Result> Handle(AddMemberToGroupCommand command, CancellationToken cancellationToken)
{
var groupMembershipTask = dbContext.GroupMemberships.AnyAsync(
gm => gm.GroupId == command.GroupId && gm.UserId == command.UserId, cancellationToken);
var userTask = dbContext.Users.AnyAsync(u => u.Id == command.UserId, cancellationToken);
var groupTask = dbContext.Groups.FindAsync(command.GroupId);
var isUserMember = await groupMembershipTask;
var isUserExisting = await userTask;
var group = await groupTask;
if (isUserMember)
{
return new Result(ErrorName.NotValid, "Użytkownik jest już członkiem tej grupy.");
}
if (!isUserExisting)
{
return new Result(ErrorName.NotValid, "Użytkownik o podanym id nie istnieje.");
}
if (group == null)
{
return new Result(ErrorName.NotValid, "Grupa o podanym id nie istnieje.");
}
if (group.CreatedById != authContext.GetCurrentUserId())
{
return new Result(ErrorName.NotAuthorized, "Nie możesz dodawać członków do nieswojej grupy.");
}
var membership = new GroupMembership
{
GroupId = command.GroupId,
UserId = command.UserId
};
dbContext.GroupMemberships.Add(membership);
await dbContext.SaveChangesAsync(cancellationToken);
return Result.SuccessfulResult;
}