0
0
mirror of https://github.com/alex289/CleanArchitecture.git synced 2025-06-30 10:33:43 +00:00

Add tenant entity

This commit is contained in:
alex289 2023-08-27 19:09:23 +02:00
parent 65d15d383b
commit b0d96d8b4d
No known key found for this signature in database
GPG Key ID: 573F77CD2D87F863
26 changed files with 133 additions and 77 deletions

View File

@ -25,6 +25,7 @@ public sealed class GetAllUsersTestFixture : QueryHandlerBaseFixture
{
var user = new User(
ExistingUserId,
Guid.NewGuid(),
"max@mustermann.com",
"Max",
"Mustermann",
@ -40,6 +41,7 @@ public sealed class GetAllUsersTestFixture : QueryHandlerBaseFixture
{
var user = new User(
ExistingUserId,
Guid.NewGuid(),
"max@mustermann.com",
"Max",
"Mustermann",

View File

@ -26,6 +26,7 @@ public sealed class GetUserByIdTestFixture : QueryHandlerBaseFixture
{
var user = new User(
ExistingUserId,
Guid.NewGuid(),
"max@mustermann.com",
"Max",
"Mustermann",
@ -41,6 +42,7 @@ public sealed class GetUserByIdTestFixture : QueryHandlerBaseFixture
{
var user = new User(
ExistingUserId,
Guid.NewGuid(),
"max@mustermann.com",
"Max",
"Mustermann",

View File

@ -46,6 +46,7 @@ public sealed class UserService : IUserService
await _bus.SendCommandAsync(new CreateUserCommand(
userId,
user.TenantId,
user.Email,
user.FirstName,
user.LastName,

View File

@ -27,6 +27,7 @@ public sealed class ChangePasswordCommandTestFixture : CommandHandlerFixtureBase
public Entities.User SetupUser()
{
var user = new Entities.User(
Guid.NewGuid(),
Guid.NewGuid(),
"max@mustermann.com",
"Max",

View File

@ -16,6 +16,7 @@ public sealed class CreateUserCommandHandlerTests
_fixture.SetupUser();
var command = new CreateUserCommand(
Guid.NewGuid(),
Guid.NewGuid(),
"test@email.com",
"Test",
@ -37,6 +38,7 @@ public sealed class CreateUserCommandHandlerTests
var command = new CreateUserCommand(
user.Id,
Guid.NewGuid(),
"test@email.com",
"Test",
"Email",

View File

@ -25,6 +25,7 @@ public sealed class CreateUserCommandTestFixture : CommandHandlerFixtureBase
public Entities.User SetupUser()
{
var user = new Entities.User(
Guid.NewGuid(),
Guid.NewGuid(),
"max@mustermann.com",
"Max",

View File

@ -178,6 +178,7 @@ public sealed class CreateUserCommandValidationTests :
private static CreateUserCommand CreateTestCommand(
Guid? userId = null,
Guid? tenantId = null,
string? email = null,
string? firstName = null,
string? lastName = null,
@ -185,6 +186,7 @@ public sealed class CreateUserCommandValidationTests :
{
return new(
userId ?? Guid.NewGuid(),
tenantId ?? Guid.NewGuid(),
email ?? "test@email.com",
firstName ?? "test",
lastName ?? "email",

View File

@ -26,6 +26,7 @@ public sealed class DeleteUserCommandTestFixture : CommandHandlerFixtureBase
public Entities.User SetupUser()
{
var user = new Entities.User(
Guid.NewGuid(),
Guid.NewGuid(),
"max@mustermann.com",
"Max",

View File

@ -37,6 +37,7 @@ public sealed class LoginUserCommandTestFixture : CommandHandlerFixtureBase
public Entities.User SetupUser()
{
var user = new Entities.User(
Guid.NewGuid(),
Guid.NewGuid(),
"max@mustermann.com",
"Max",

View File

@ -71,6 +71,7 @@ public sealed class UpdateUserCommandHandlerTests
_fixture.UserRepository
.GetByEmailAsync(command.Email)
.Returns(new Entities.User(
Guid.NewGuid(),
Guid.NewGuid(),
command.Email,
"Some",

View File

@ -26,6 +26,7 @@ public sealed class UpdateUserCommandTestFixture : CommandHandlerFixtureBase
public Entities.User SetupUser()
{
var user = new Entities.User(
Guid.NewGuid(),
Guid.NewGuid(),
"max@mustermann.com",
"Max",

View File

@ -8,12 +8,14 @@ public sealed class CreateUserCommand : CommandBase
public CreateUserCommand(
Guid userId,
Guid tenantId,
string email,
string firstName,
string lastName,
string password) : base(userId)
{
UserId = userId;
TenantId = tenantId;
Email = email;
FirstName = firstName;
LastName = lastName;
@ -21,6 +23,7 @@ public sealed class CreateUserCommand : CommandBase
}
public Guid UserId { get; }
public Guid TenantId { get; }
public string Email { get; }
public string FirstName { get; }
public string LastName { get; }

View File

@ -61,6 +61,7 @@ public sealed class CreateUserCommandHandler : CommandHandlerBase,
var user = new User(
request.UserId,
request.TenantId,
request.Email,
request.FirstName,
request.LastName,

View File

@ -1,3 +1,4 @@
using CleanArchitecture.Domain.Constants;
using CleanArchitecture.Domain.Errors;
using CleanArchitecture.Domain.Extensions.Validation;
using FluentValidation;
@ -29,7 +30,7 @@ public sealed class CreateUserCommandValidation : AbstractValidator<CreateUserCo
.EmailAddress()
.WithErrorCode(DomainErrorCodes.UserInvalidEmail)
.WithMessage("Email is not a valid email address")
.MaximumLength(320)
.MaximumLength(MaxLengths.User.Email)
.WithErrorCode(DomainErrorCodes.UserEmailExceedsMaxLength)
.WithMessage("Email may not be longer than 320 characters");
}
@ -40,7 +41,7 @@ public sealed class CreateUserCommandValidation : AbstractValidator<CreateUserCo
.NotEmpty()
.WithErrorCode(DomainErrorCodes.UserEmptyFirstName)
.WithMessage("FirstName may not be empty")
.MaximumLength(100)
.MaximumLength(MaxLengths.User.FirstName)
.WithErrorCode(DomainErrorCodes.UserFirstNameExceedsMaxLength)
.WithMessage("FirstName may not be longer than 100 characters");
}
@ -51,7 +52,7 @@ public sealed class CreateUserCommandValidation : AbstractValidator<CreateUserCo
.NotEmpty()
.WithErrorCode(DomainErrorCodes.UserEmptyLastName)
.WithMessage("LastName may not be empty")
.MaximumLength(100)
.MaximumLength(MaxLengths.User.LastName)
.WithErrorCode(DomainErrorCodes.UserLastNameExceedsMaxLength)
.WithMessage("LastName may not be longer than 100 characters");
}

View File

@ -1,4 +1,5 @@
using CleanArchitecture.Domain.Errors;
using CleanArchitecture.Domain.Constants;
using CleanArchitecture.Domain.Errors;
using CleanArchitecture.Domain.Extensions.Validation;
using FluentValidation;
@ -18,7 +19,7 @@ public sealed class LoginUserCommandValidation : AbstractValidator<LoginUserComm
.EmailAddress()
.WithErrorCode(DomainErrorCodes.UserInvalidEmail)
.WithMessage("Email is not a valid email address")
.MaximumLength(320)
.MaximumLength(MaxLengths.User.Email)
.WithErrorCode(DomainErrorCodes.UserEmailExceedsMaxLength)
.WithMessage("Email may not be longer than 320 characters");
}

View File

@ -1,3 +1,4 @@
using CleanArchitecture.Domain.Constants;
using CleanArchitecture.Domain.Errors;
using FluentValidation;
@ -28,7 +29,7 @@ public sealed class UpdateUserCommandValidation : AbstractValidator<UpdateUserCo
.EmailAddress()
.WithErrorCode(DomainErrorCodes.UserInvalidEmail)
.WithMessage("Email is not a valid email address")
.MaximumLength(320)
.MaximumLength(MaxLengths.User.Email)
.WithErrorCode(DomainErrorCodes.UserEmailExceedsMaxLength)
.WithMessage("Email may not be longer than 320 characters");
}
@ -39,7 +40,7 @@ public sealed class UpdateUserCommandValidation : AbstractValidator<UpdateUserCo
.NotEmpty()
.WithErrorCode(DomainErrorCodes.UserEmptyFirstName)
.WithMessage("FirstName may not be empty")
.MaximumLength(100)
.MaximumLength(MaxLengths.User.FirstName)
.WithErrorCode(DomainErrorCodes.UserFirstNameExceedsMaxLength)
.WithMessage("FirstName may not be longer than 100 characters");
}
@ -50,7 +51,7 @@ public sealed class UpdateUserCommandValidation : AbstractValidator<UpdateUserCo
.NotEmpty()
.WithErrorCode(DomainErrorCodes.UserEmptyLastName)
.WithMessage("LastName may not be empty")
.MaximumLength(100)
.MaximumLength(MaxLengths.User.LastName)
.WithErrorCode(DomainErrorCodes.UserLastNameExceedsMaxLength)
.WithMessage("LastName may not be longer than 100 characters");
}

View File

@ -0,0 +1,12 @@
using System;
namespace CleanArchitecture.Domain.Constants;
public static class Ids
{
public static class Seed
{
public static readonly Guid UserId = new("7e3892c0-9374-49fa-a3fd-53db637a40ae");
public static readonly Guid TenantId = new("b542bf25-134c-47a2-a0df-84ed14d03c4a");
}
}

View File

@ -0,0 +1,17 @@
namespace CleanArchitecture.Domain.Constants;
public sealed class MaxLengths
{
public static class User
{
public const int Email = 320;
public const int FirstName = 100;
public const int LastName = 100;
public const int Password = 128;
}
public static class Tenant
{
public const int Name = 255;
}
}

View File

@ -0,0 +1,18 @@
using System;
using System.Collections.Generic;
namespace CleanArchitecture.Domain.Entities;
public class Tenant : Entity
{
public string Name { get; private set; }
public ICollection<User> Users { get; private set; } = new HashSet<User>();
public Tenant(
Guid id,
string name) : base(id)
{
Name = name;
}
}

View File

@ -6,21 +6,6 @@ namespace CleanArchitecture.Domain.Entities;
public class User : Entity
{
public User(
Guid id,
string email,
string firstName,
string lastName,
string password,
UserRole role) : base(id)
{
Email = email;
FirstName = firstName;
LastName = lastName;
Password = password;
Role = role;
}
public string Email { get; private set; }
public string FirstName { get; private set; }
public string LastName { get; private set; }
@ -29,71 +14,43 @@ public class User : Entity
public string FullName => $"{FirstName}, {LastName}";
[MemberNotNull(nameof(Email))]
public Guid TenantId { get; private set; }
public Tenant Tenant { get; private set; } = null!;
public User(
Guid id,
Guid tenantId,
string email,
string firstName,
string lastName,
string password,
UserRole role) : base(id)
{
Email = email;
TenantId = tenantId;
FirstName = firstName;
LastName = lastName;
Password = password;
Role = role;
}
public void SetEmail(string email)
{
if (email == null)
{
throw new ArgumentNullException(nameof(email));
}
if (email.Length > 320)
{
throw new ArgumentException(
"Email may not be longer than 320 characters.");
}
Email = email;
}
[MemberNotNull(nameof(FirstName))]
public void SetFirstName(string firstName)
{
if (firstName == null)
{
throw new ArgumentNullException(nameof(firstName));
}
if (firstName.Length > 100)
{
throw new ArgumentException(
"First name may not be longer than 100 characters");
}
FirstName = firstName;
}
[MemberNotNull(nameof(LastName))]
public void SetLastName(string lastName)
{
if (lastName == null)
{
throw new ArgumentNullException(nameof(lastName));
}
if (lastName.Length > 100)
{
throw new ArgumentException(
"Last name may not be longer than 100 characters");
}
LastName = lastName;
}
[MemberNotNull(nameof(Password))]
public void SetPassword(string password)
{
if (password == null)
{
throw new ArgumentNullException(nameof(password));
}
if (password.Length > 100)
{
throw new ArgumentException(
"Password may not be longer than 100 characters");
}
Password = password;
}

View File

@ -0,0 +1,21 @@
using CleanArchitecture.Domain.Constants;
using CleanArchitecture.Domain.Entities;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
namespace CleanArchitecture.Infrastructure.Configurations;
public sealed class TenantConfiguration : IEntityTypeConfiguration<Tenant>
{
public void Configure(EntityTypeBuilder<Tenant> builder)
{
builder
.Property(user => user.Name)
.IsRequired()
.HasMaxLength(MaxLengths.Tenant.Name);
builder.HasData(new Tenant(
Ids.Seed.TenantId,
"Admin Tenant"));
}
}

View File

@ -1,4 +1,5 @@
using System;
using CleanArchitecture.Domain.Constants;
using CleanArchitecture.Domain.Entities;
using CleanArchitecture.Domain.Enums;
using Microsoft.EntityFrameworkCore;
@ -13,25 +14,26 @@ public sealed class UserConfiguration : IEntityTypeConfiguration<User>
builder
.Property(user => user.Email)
.IsRequired()
.HasMaxLength(320);
.HasMaxLength(MaxLengths.User.Email);
builder
.Property(user => user.FirstName)
.IsRequired()
.HasMaxLength(100);
.HasMaxLength(MaxLengths.User.FirstName);
builder
.Property(user => user.LastName)
.IsRequired()
.HasMaxLength(100);
.HasMaxLength(MaxLengths.User.LastName);
builder
.Property(user => user.Password)
.IsRequired()
.HasMaxLength(128);
.HasMaxLength(MaxLengths.User.Password);
builder.HasData(new User(
Guid.NewGuid(),
Ids.Seed.UserId,
Ids.Seed.TenantId,
"admin@email.com",
"Admin",
"User",

View File

@ -11,9 +11,11 @@ public class ApplicationDbContext : DbContext
}
public DbSet<User> Users { get; set; } = null!;
public DbSet<Tenant> Tenants { get; set; } = null!;
protected override void OnModelCreating(ModelBuilder builder)
{
builder.ApplyConfiguration(new UserConfiguration());
builder.ApplyConfiguration(new TenantConfiguration());
}
}

View File

@ -32,7 +32,8 @@ public sealed class UserControllerTests : IClassFixture<UserTestFixture>
_fixture.CreatedUserEmail,
"Test",
"Email",
_fixture.CreatedUserPassword);
_fixture.CreatedUserPassword,
Guid.NewGuid());
var response = await _fixture.ServerClient.PostAsJsonAsync("/api/v1/user", user);

View File

@ -33,6 +33,7 @@ public sealed class GetUsersByIdsTestFixture : TestFixtureBase
{
return new User(
CreatedUserId,
Guid.NewGuid(),
"user@user.de",
"User First Name",
"User Last Name",

View File

@ -16,6 +16,7 @@ public sealed class UserTestsFixture
ExistingUsers = new List<User>
{
new(
Guid.NewGuid(),
Guid.NewGuid(),
"test@test.de",
"Test First Name",
@ -23,6 +24,7 @@ public sealed class UserTestsFixture
"Test Password",
UserRole.User),
new(
Guid.NewGuid(),
Guid.NewGuid(),
"email@Email.de",
"Email First Name",
@ -30,6 +32,7 @@ public sealed class UserTestsFixture
"Email Password",
UserRole.Admin),
new(
Guid.NewGuid(),
Guid.NewGuid(),
"user@user.de",
"User First Name",