Skip to content

Commit

Permalink
errors in shared Features
Browse files Browse the repository at this point in the history
  • Loading branch information
DavidEggenberger committed Jan 4, 2025
1 parent 2e88fcc commit babd7b3
Show file tree
Hide file tree
Showing 24 changed files with 230 additions and 210 deletions.
4 changes: 2 additions & 2 deletions Source/Modules/LandingPages/Server/LandingPagesLayout.razor
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@
@inherits LayoutComponentBase
@inject IModalService modalService

<div class="h-screen w-screen">
<div class="h-screen w-screen text-primary-500">
<nav class="ml-auto mr-auto flex h-[65px] w-full max-w-[1400px] flex-row content-start items-end justify-between p-5 pb-0">
<div>
<a id="start" href="/">
<h1 class="text-primary-900 text-4xl">SaaS template<span class="text-[46px]"></span></h1>
<h1 class="text-4xl text-primary-900">SaaS template<span class="text-[46px]"></span></h1>
</a>
</div>
<div class="flex flex-row gap-x-3">
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using Shared.Features.EFCore;
using Shared.Features.Messaging.Commands;
using Shared.Features.Server;
using Shared.Kernel.BuildingBlocks.Auth;
using Shared.Kernel.DomainKernel;
using System.Threading;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ public CreateTenantWithAdminCommandHandler(IServiceProvider serviceProvider) : b

public async Task<TenantDTO> HandleAsync(CreateTenantWithAdmin createTenant, CancellationToken cancellationToken)
{
var tenant = Tenant.CreateTenantWithAdmin(createTenant.Name, Guid.Empty);
var tenant = Tenant.CreateTenant(createTenant.Name, Guid.Empty);

module.TenantIdentityDbContext.Tenants.Add(tenant);
await module.TenantIdentityDbContext.SaveChangesAsync(cancellationToken);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
using Microsoft.EntityFrameworkCore;
using System.Threading;
using Shared.Features.Server;
using Shared.Kernel.Errors;
using Modules.TenantIdentity.Features.DomainFeatures.Tenants.Domain;
using Shared.Features.Messaging.Commands;
using Shared.Features.Errors;

namespace Modules.TenantIdentity.Features.DomainFeatures.Tenants.Application.Commands
{
Expand All @@ -21,11 +21,9 @@ public async Task HandleAsync(DeleteTenant command, CancellationToken cancellati
var tenant = await module.TenantIdentityDbContext.Tenants.SingleAsync(t => t.Id == command.TenantId);
if (tenant == null)
{
throw Errors.NotFound(nameof(Tenant), command.TenantId);
throw Error.NotFound(nameof(Tenant), command.TenantId);
}

tenant.ThrowIfUserCantDeleteTenant();

module.TenantIdentityDbContext.Entry(tenant.Id).State = EntityState.Deleted;
await module.TenantIdentityDbContext.SaveChangesAsync();
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using Shared.Features.Messaging.Commands;
using Shared.Features.Server;
using Shared.Kernel.BuildingBlocks.Auth;
using Shared.Kernel.DomainKernel;
using System.Threading;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
namespace Modules.TenantIdentity.Features.DomainFeatures.Tenants.Domain.Exceptions
using Microsoft.AspNetCore.Http;
using Shared.Features.Errors.Exceptions;

namespace Modules.TenantIdentity.Features.DomainFeatures.Tenants.Domain.Exceptions
{
public class MemberNotFoundException : Exception
public class MemberNotFoundException : DomainException
{
public MemberNotFoundException() : base("Member not found", StatusCodes.Status404NotFound)
{
}
}
}
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
using Shared.Features.Domain.Exceptions;
using Microsoft.AspNetCore.Http;
using Shared.Features.Errors.Exceptions;

namespace Modules.TenantIdentity.Features.DomainFeatures.Tenants.Domain.Exceptions
{
public class TabsAlreadyClosedException : DomainException
{
public TabsAlreadyClosedException(string message) : base(message)
public TabsAlreadyClosedException(string message) : base(message, StatusCodes.Status500InternalServerError)
{
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
namespace Modules.TenantIdentity.Features.DomainFeatures.Tenants.Domain.Exceptions
{
public class UserIsAlreadyMemberException : Exception
public class UserAlreadyMemberException : Exception
{
}
}
Original file line number Diff line number Diff line change
@@ -1,31 +1,27 @@
using Microsoft.EntityFrameworkCore;
using Microsoft.AspNetCore.Http;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
using Modules.TenantIdentity.Features.DomainFeatures.Tenants.Domain.Exceptions;
using Modules.TenantIdentity.Public.DTOs.Tenant;
using Shared.Features.Domain;
using Shared.Features.Domain.Exceptions;
using Shared.Features.Errors;
using Shared.Kernel.DomainKernel;
using Shared.Kernel.Errors;

namespace Modules.TenantIdentity.Features.DomainFeatures.Tenants.Domain
{
public class Tenant : Entity
{
private Tenant() { }

public string Name { get; private set; }
public SubscriptionPlanType SubscriptionPlanType { get; private set; }
public IReadOnlyCollection<TenantMembership> Memberships => memberships.AsReadOnly();
private List<TenantMembership> memberships = new List<TenantMembership>();
public IReadOnlyCollection<TenantInvitation> Invitations => invitations.AsReadOnly();
private List<TenantInvitation> invitations = new List<TenantInvitation>();
public SubscriptionPlanType SubscriptionPlan { get; private set; }
public List<TenantMembership> Memberships { get; private set; }
public List<TenantInvitation> Invitations { get; private set; }

public static Tenant CreateTenantWithAdmin(string tenantName, Guid adminUserId)
public static Tenant CreateTenant(string tenantName, Guid adminUserId)
{
return new Tenant
{
Name = tenantName,
memberships = new List<TenantMembership>
Memberships = new List<TenantMembership>
{
new TenantMembership(adminUserId, TenantRole.Admin)
}
Expand All @@ -37,51 +33,57 @@ public void AddUser(Guid userId, TenantRole role)
ThrowIfCallerIsNotInRole(TenantRole.Admin);

TenantMembership tenantMembership;
if ((tenantMembership = memberships.SingleOrDefault(m => m.UserId == userId)) is not null)
if ((tenantMembership = Memberships.SingleOrDefault(m => m.UserId == userId)) is not null)
{
throw new DomainException("");
throw Error.DomainException("User is already a member of the tenant", StatusCodes.Status409Conflict);
}
else
{
memberships.Add(new TenantMembership(userId, role));
Memberships.Add(new TenantMembership(userId, role));
}
}

public void ChangeRoleOfTenantMember(Guid userId, TenantRole newRole)
{
ThrowIfCallerIsNotInRole(TenantRole.Admin);

if (CheckIfMember(userId) is false)
if (CheckIfUserIsMember(userId) is false)
{
throw new MemberNotFoundException();
}

TenantMembership tenantMembership = memberships.Single(m => m.UserId == userId);
TenantMembership tenantMembership = Memberships.Single(m => m.UserId == userId);
tenantMembership.UpdateRole(newRole);
}

public void RemoveUser(Guid userId)
{
ThrowIfCallerIsNotInRole(TenantRole.Admin);

if (CheckIfMember(userId) is false)
if (CheckIfUserIsMember(userId) is false)
{
throw new MemberNotFoundException();
}

memberships.Remove(memberships.Single(m => m.UserId == userId));
var membership = Memberships.Single(m => m.UserId == userId);
if (membership.Role == TenantRole.Admin && Memberships.Count(m => m.Role == TenantRole.Admin) == 1)
{
throw Error.DomainException("Cant remove only admin from tenant", StatusCodes.Status409Conflict);
}

Memberships.Remove(Memberships.Single(m => m.UserId == userId));
}

public void InviteUserToRole(string email, TenantRole role)
{
ThrowIfCallerIsNotInRole(TenantRole.Admin);

if (invitations.Any(invitation => invitation.Email == email))
if (Invitations.Any(invitation => invitation.Email == email))
{
throw new DomainException("");
throw Error.DomainException("User is already invited", StatusCodes.Status409Conflict);
}

invitations.Add(TenantInvitation.Create(this, email, role));
Invitations.Add(TenantInvitation.Create(this, email, role));
}

public void DeleteTenantMembership(Guid membershipId)
Expand All @@ -91,26 +93,22 @@ public void DeleteTenantMembership(Guid membershipId)
var tenantMembership = Memberships.SingleOrDefault(t => t.Id == membershipId);
if (tenantMembership == null)
{
throw Errors.NotFound(nameof(TenantMembership), membershipId);
throw Error.NotFound(nameof(TenantMembership), membershipId);
}

memberships.Remove(tenantMembership);
Memberships.Remove(tenantMembership);
}

public bool CheckIfMember(Guid userId)
public bool CheckIfUserIsMember(Guid userId)
{
return memberships.Any(membership => membership.UserId == userId);
return Memberships.Any(membership => membership.UserId == userId);
}

public void UpdateSubscriptionPlan(SubscriptionPlanType subscriptionPlanType)
{
SubscriptionPlanType = subscriptionPlanType;
SubscriptionPlan = subscriptionPlanType;
}

public void ThrowIfUserCantDeleteTenant()
{
ThrowIfCallerIsNotInRole(TenantRole.Admin);
}

public TenantDTO ToDTO() => new TenantDTO();
public TenantExtendedDTO ToDetailDTO() => new TenantExtendedDTO();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ public async Task<IEnumerable<Claim>> HandleAsync(GetClaimsForExecutingUser quer

claims.AddRange(new List<Claim>
{
new Claim(ClaimConstants.TenantPlanClaimType, tenant.SubscriptionPlanType.ToString()),
new Claim(ClaimConstants.TenantPlanClaimType, tenant.SubscriptionPlan.ToString()),
new Claim(ClaimConstants.TenantNameClaimType, tenant.Name),
new Claim(ClaimConstants.TenantIdClaimType, tenant.Id.ToString()),
new Claim(ClaimConstants.UserRoleInTenantClaimType, tenantMembership.Role.ToString()),
Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,14 @@
using Microsoft.EntityFrameworkCore;
using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
using Microsoft.AspNetCore.Identity;
using Shared.Features.Domain.Exceptions;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Shared.Features.EFCore.Configuration;
using Modules.TenantIdentity.Features.DomainFeatures.Users;
using Shared.Features.EFCore;
using Shared.Kernel.BuildingBlocks;
using Modules.TenantIdentity.Features.DomainFeatures.Tenants.Domain;
using Shared.Kernel.Errors;
using Shared.Features.Errors;

namespace Modules.TenantIdentity.Features.Infrastructure.EFCore
{
Expand Down Expand Up @@ -79,7 +78,7 @@ public async Task<ApplicationUser> GetUserByIdAsync(Guid userId)
var user = await Users.FirstOrDefaultAsync(t => t.Id == userId);
if (user == null)
{
throw Errors.NotFound(nameof(ApplicationUser), userId);
throw Error.NotFound(nameof(ApplicationUser), userId);
}
return user;
}
Expand All @@ -89,7 +88,7 @@ public async Task<Tenant> GetTenantByIdAsync(Guid tenantId)
var tenant = await Tenants.FirstOrDefaultAsync(t => t.TenantId == tenantId);
if (tenant == null)
{
throw Errors.NotFound(nameof(Tenant), tenantId);
throw Error.NotFound(nameof(Tenant), tenantId);
}
return tenant;
}
Expand All @@ -102,7 +101,7 @@ public async Task<Tenant> GetTenantExtendedByIdAsync(Guid tenantId)
.FirstOrDefaultAsync(t => t.TenantId == tenantId);
if (tenant == null)
{
throw Errors.NotFound(nameof(Tenant), tenantId);
throw Error.NotFound(nameof(Tenant), tenantId);
}

return tenant;
Expand Down
4 changes: 3 additions & 1 deletion Source/Shared/Features/Domain/Entity.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
using System.ComponentModel.DataAnnotations.Schema;
using Shared.Kernel.BuildingBlocks.Auth.Exceptions;
using Shared.Kernel.DomainKernel;
using Shared.Kernel.BuildingBlocks.Auth;
using Shared.Features.Errors;

namespace Shared.Features.Domain
{
Expand All @@ -28,7 +30,7 @@ public void ThrowIfCallerIsNotInRole(TenantRole role)
{
if (ExecutionContext.TenantRole != role)
{
throw new UnauthorizedException();
throw Error.UnAuthorized;
}
}
}
Expand Down
10 changes: 0 additions & 10 deletions Source/Shared/Features/Domain/Exceptions/DomainException.cs

This file was deleted.

10 changes: 5 additions & 5 deletions Source/Shared/Features/EFCore/DbSetExtensions.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Query;
using Shared.Features.Domain;
using Shared.Kernel.Errors;
using Shared.Features.Errors;

namespace Shared.Features.EFCore
{
Expand All @@ -12,11 +12,11 @@ public static async Task<TEntity> GetEntityAsync<TEntity>(this DbSet<TEntity> db
var entity = await dbSet.FirstOrDefaultAsync(t => t.Id == entityId);
if (entity == null)
{
throw Errors.NotFound(typeof(TEntity).Name, entityId);
throw Error.NotFound(typeof(TEntity).Name, entityId);
}
if (entity.TenantId != owningTenantId)
{
throw Errors.UnAuthorized;
throw Error.UnAuthorized;
}

return entity;
Expand All @@ -27,11 +27,11 @@ public static async Task<TEntity> GetEntityAsync<TEntity, TSecond>(this IIncluda
var entity = await dbSet.FirstOrDefaultAsync(t => t.Id == entityId);
if (entity == null)
{
throw Errors.NotFound(typeof(TEntity).Name, entityId);
throw Error.NotFound(typeof(TEntity).Name, entityId);
}
if (entity.TenantId != tenantId)
{
throw Errors.UnAuthorized;
throw Error.UnAuthorized;
}

return entity;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
using Shared.Kernel.Errors.Exceptions;
using Shared.Features.Errors.Exceptions;

namespace Shared.Kernel.Errors
namespace Shared.Features.Errors
{
public static class Errors
public static class Error
{
public static NotFoundException NotFound(string entityName, Guid id) => new NotFoundException(entityName, id);
public static NotFoundException NotFound(string entityName, string id) => new NotFoundException(entityName, id);
public static DomainException DomainException(string message, int statusCode) => new DomainException(message, statusCode);
public static UnAuthorizedException UnAuthorized = new UnAuthorizedException();
}
}
12 changes: 12 additions & 0 deletions Source/Shared/Features/Errors/Exceptions/DomainException.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
namespace Shared.Features.Errors.Exceptions
{
public class DomainException : Exception
{
public int StatusCode { get; private set; }

public DomainException(string message, int statusCode) : base(message)
{
StatusCode = statusCode;
}
}
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
namespace Shared.Features.Domain.Exceptions
using Microsoft.AspNetCore.Http;

namespace Shared.Features.Errors.Exceptions
{
public class InvalidEntityDeleteException : DomainException
{
public InvalidEntityDeleteException(string message) : base(message)
public InvalidEntityDeleteException(string message) : base(message, StatusCodes.Status409Conflict)
{

}
Expand Down
Loading

0 comments on commit babd7b3

Please sign in to comment.