Refactored organisation entities and endpoints #129
@@ -19,6 +19,7 @@ public sealed class CreateOrganisationEndpoint : IEndpoint
|
|||||||
await service.CreateOrganisationAsync(request, context.GetUserId(), cancellationToken) switch
|
await service.CreateOrganisationAsync(request, context.GetUserId(), cancellationToken) switch
|
||||||
{
|
{
|
||||||
{ IsSuccess: true } => Results.Ok(),
|
{ IsSuccess: true } => Results.Ok(),
|
||||||
|
var r when r.HasError<ValidationError>() => Results.BadRequest(r.Errors.ToProblems()),
|
||||||
var r when r.HasError<CreateError>() => Results.BadRequest(r.Errors.ToProblems()),
|
var r when r.HasError<CreateError>() => Results.BadRequest(r.Errors.ToProblems()),
|
||||||
var r => Results.InternalServerError(r.Errors.ToProblems())
|
var r => Results.InternalServerError(r.Errors.ToProblems())
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ public sealed class GetTenantEndpoint : IEndpoint
|
|||||||
var r when r.HasError<NotFoundError>() => Results.NotFound(r.Errors.ToProblems()),
|
var r when r.HasError<NotFoundError>() => Results.NotFound(r.Errors.ToProblems()),
|
||||||
var r => Results.InternalServerError(r.Errors.ToProblems())
|
var r => Results.InternalServerError(r.Errors.ToProblems())
|
||||||
})
|
})
|
||||||
.WithDescription("Gets system tenants")
|
.WithDescription("Gets a single tenant")
|
||||||
.RequireAuthorization(Constants.MainScope)
|
.RequireAuthorization(Constants.MainScope)
|
||||||
.WithName(typeof(GetTenantsEndpoint).ToEndpointName())
|
.WithName(typeof(GetTenantsEndpoint).ToEndpointName())
|
||||||
.MapToApiVersion(new ApiVersion(1))
|
.MapToApiVersion(new ApiVersion(1))
|
||||||
|
|||||||
@@ -0,0 +1,36 @@
|
|||||||
|
using PostFundManagement.Application.Abstractions.Services;
|
||||||
|
using PostFundManagement.Application.Extensions;
|
||||||
|
using PostFundManagement.Domain.Abstractions;
|
||||||
|
using PostFundManagement.Domain.Entities;
|
||||||
|
using PostFundManagement.Domain.Errors;
|
||||||
|
using PostFundManagement.Domain.Extensions;
|
||||||
|
using PostFundManagement.Domain.Security;
|
||||||
|
using StackExchange.Redis;
|
||||||
|
using Problems = Microsoft.AspNetCore.Mvc.ProblemDetails;
|
||||||
|
|
||||||
|
namespace PostFundManagement.Api.Endpoints.Governance;
|
||||||
|
|
||||||
|
[ApiVersionTarget(1)]
|
||||||
|
public sealed class GetTenantOrganisationsEndpoint : IEndpoint
|
||||||
|
{
|
||||||
|
public void Map(IEndpointRouteBuilder builder)
|
||||||
|
{
|
||||||
|
builder.MapGet("api/governance/tenants/{tenantIdHash}/organisations", async (IGovernanceService service, string tenantIdHash,
|
||||||
|
CancellationToken cancellationToken = default) =>
|
||||||
|
await service.GetTenantOrganisationsAsync(tenantIdHash, cancellationToken) switch
|
||||||
|
{
|
||||||
|
{ IsSuccess: true, Value: var tenantOrganisations } => Results.Ok(tenantOrganisations),
|
||||||
|
var r when r.HasError<IdDecodeError>() => Results.Forbid(),
|
||||||
|
var r => Results.InternalServerError(r.Errors.ToProblems())
|
||||||
|
})
|
||||||
|
.WithDescription("Gets organisations created and managed by one tenant")
|
||||||
|
.RequireAuthorization(Constants.MainScope)
|
||||||
|
.WithName(typeof(GetTenantOrganisationsEndpoint).ToEndpointName("Retrieval"))
|
||||||
|
.MapToApiVersion(new ApiVersion(1))
|
||||||
|
.Produces<TenantOrganisation[]>(StatusCodes.Status200OK)
|
||||||
|
.Produces(StatusCodes.Status403Forbidden)
|
||||||
|
.Produces(StatusCodes.Status401Unauthorized)
|
||||||
|
.Produces<Problems>(StatusCodes.Status500InternalServerError)
|
||||||
|
.WithTags(EndpointTags.Governance);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -91,7 +91,7 @@ public interface IGovernanceService
|
|||||||
Task<Result> UpdateTenantOrganisationAsync(string tenantOrganisationIdHash, ActivityStatus status, Guid userId, CancellationToken cancellationToken = default);
|
Task<Result> UpdateTenantOrganisationAsync(string tenantOrganisationIdHash, ActivityStatus status, Guid userId, CancellationToken cancellationToken = default);
|
||||||
|
|
||||||
[Log]
|
[Log]
|
||||||
Task<Result<TenantOrganisation[]>> GetTenantOrganisationsAsync(CancellationToken cancellationToken = default);
|
Task<Result<TenantOrganisation[]>> GetTenantOrganisationsAsync(string tenantIdHash, CancellationToken cancellationToken = default);
|
||||||
|
|
||||||
[Log]
|
[Log]
|
||||||
Task<Result<TenantOrganisation>> GetTenantOrganisationAsync(string tenantOrganisationIdHash, CancellationToken cancellationToken = default);
|
Task<Result<TenantOrganisation>> GetTenantOrganisationAsync(string tenantOrganisationIdHash, CancellationToken cancellationToken = default);
|
||||||
|
|||||||
@@ -266,19 +266,19 @@ public sealed class GovernanceCacheService(GovernanceService service, IDistribut
|
|||||||
return Result.Ok(cached.FromJson<TenantOrganisation>());
|
return Result.Ok(cached.FromJson<TenantOrganisation>());
|
||||||
}));
|
}));
|
||||||
|
|
||||||
public async Task<Result<TenantOrganisation[]>> GetTenantOrganisationsAsync(CancellationToken cancellationToken = default) =>
|
public async Task<Result<TenantOrganisation[]>> GetTenantOrganisationsAsync(string tenantIdHash, CancellationToken cancellationToken = default) =>
|
||||||
await Result.Try((Func<Task<Result<TenantOrganisation[]>>>)(async () =>
|
await Result.Try((Func<Task<Result<TenantOrganisation[]>>>)(async () =>
|
||||||
{
|
{
|
||||||
if (!await featureManager.IsEnabledAsync(ServiceCachingFeature))
|
if (!await featureManager.IsEnabledAsync(ServiceCachingFeature))
|
||||||
return await service.GetTenantOrganisationsAsync(cancellationToken);
|
return await service.GetTenantOrganisationsAsync(tenantIdHash, cancellationToken);
|
||||||
|
|
||||||
var cacheKey = HashService.ToMd5Hash($"gettenantorganisations").Value;
|
var cacheKey = HashService.ToMd5Hash($"gettenantorganisations-{tenantIdHash}").Value;
|
||||||
|
|
||||||
var cached = await cache.GetStringAsync(cacheKey, cancellationToken);
|
var cached = await cache.GetStringAsync(cacheKey, cancellationToken);
|
||||||
|
|
||||||
if (string.IsNullOrWhiteSpace(cached))
|
if (string.IsNullOrWhiteSpace(cached))
|
||||||
{
|
{
|
||||||
var result = await service.GetTenantOrganisationsAsync(cancellationToken);
|
var result = await service.GetTenantOrganisationsAsync(tenantIdHash, cancellationToken);
|
||||||
|
|
||||||
if (result.IsFailed) return result;
|
if (result.IsFailed) return result;
|
||||||
|
|
||||||
|
|||||||
@@ -138,8 +138,14 @@ public sealed class GovernanceService(IDbContextFactory<ApplicationDbContext> co
|
|||||||
|
|
||||||
var registrationNo = request.RegistrationNo.Clean();
|
var registrationNo = request.RegistrationNo.Clean();
|
||||||
|
|
||||||
|
if(!await context.Users.AnyAsync(u => u.Id == request.OrganisationUser, cancellationToken))
|
||||||
|
return Result.Fail(NotFoundError.Create("Organisation user not found"));
|
||||||
|
|
||||||
|
if(!await context.TenantUsers.AnyAsync(u => u.UserId == request.OrganisationUser && u.TenantId == tenantContext.TenantId, cancellationToken))
|
||||||
|
return Result.Fail(ValidationError.Create("Organisation user does not belong to the current tenant"));
|
||||||
|
|
||||||
if (await context.Organisations.AnyAsync(o => o.RegistrationNo == registrationNo, cancellationToken))
|
if (await context.Organisations.AnyAsync(o => o.RegistrationNo == registrationNo, cancellationToken))
|
||||||
return Result.Fail(CreateError.Create("Organisation with the same registration number already exists"));
|
return Result.Fail(ValidationError.Create("Organisation with the same registration number already exists"));
|
||||||
|
|
||||||
var organisation = context.Organisations.Add(new Domain.Entities.Organisation
|
var organisation = context.Organisations.Add(new Domain.Entities.Organisation
|
||||||
{
|
{
|
||||||
@@ -149,9 +155,17 @@ public sealed class GovernanceService(IDbContextFactory<ApplicationDbContext> co
|
|||||||
Type = request.Type,
|
Type = request.Type,
|
||||||
Status = ActivityStatus.Active,
|
Status = ActivityStatus.Active,
|
||||||
CreatedBy = userId,
|
CreatedBy = userId,
|
||||||
CreatedAt = DateTime.UtcNow
|
CreatedAt = DateTime.UtcNow,
|
||||||
|
UserId = request.OrganisationUser
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if(!string.IsNullOrWhiteSpace(request.IdNumber))
|
||||||
|
{
|
||||||
|
var linkedUser = await context.Users.FirstOrDefaultAsync(u => u.Id == request.OrganisationUser, cancellationToken);
|
||||||
|
|
||||||
|
linkedUser!.IdNumber = request.IdNumber.Clean();
|
||||||
|
}
|
||||||
|
|
||||||
await context.SaveChangesAsync(cancellationToken);
|
await context.SaveChangesAsync(cancellationToken);
|
||||||
|
|
||||||
var mapResult = await CreateTenantOrganisationAsync(hashService.HashEncodeLongId(organisation.Entity.Id).Value,
|
var mapResult = await CreateTenantOrganisationAsync(hashService.HashEncodeLongId(organisation.Entity.Id).Value,
|
||||||
@@ -165,6 +179,12 @@ public sealed class GovernanceService(IDbContextFactory<ApplicationDbContext> co
|
|||||||
{
|
{
|
||||||
await using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
|
await using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
|
||||||
|
|
||||||
|
if (!await context.Users.AnyAsync(u => u.Id == request.OrganisationUser, cancellationToken))
|
||||||
|
return Result.Fail(ValidationError.Create("Organisation user not found"));
|
||||||
|
|
||||||
|
if (!await context.TenantUsers.AnyAsync(u => u.UserId == request.OrganisationUser && u.TenantId == tenantContext.TenantId, cancellationToken))
|
||||||
|
return Result.Fail(ValidationError.Create("Organisation user does not belong to the current tenant"));
|
||||||
|
|
||||||
var changedTotal = await context.Organisations
|
var changedTotal = await context.Organisations
|
||||||
.Where(f => f.Id == request.OrganisationId)
|
.Where(f => f.Id == request.OrganisationId)
|
||||||
.ExecuteUpdateAsync(f => f
|
.ExecuteUpdateAsync(f => f
|
||||||
@@ -181,7 +201,16 @@ public sealed class GovernanceService(IDbContextFactory<ApplicationDbContext> co
|
|||||||
|
|
||||||
var updateResult = await UpdateTenantOrganisationAsync(hashService.HashEncodeLongId(tenantOrganisation.Id).Value, request.Status, userId, cancellationToken);
|
var updateResult = await UpdateTenantOrganisationAsync(hashService.HashEncodeLongId(tenantOrganisation.Id).Value, request.Status, userId, cancellationToken);
|
||||||
|
|
||||||
return Result.OkIf(changedTotal > 0 && updateResult.IsSuccess, UpdateError.Create("Failed to update organisation"));
|
if (!string.IsNullOrWhiteSpace(request.IdNumber))
|
||||||
|
{
|
||||||
|
var linkedUser = await context.Users.FirstOrDefaultAsync(u => u.Id == request.OrganisationUser, cancellationToken);
|
||||||
|
|
||||||
|
linkedUser!.IdNumber = request.IdNumber.Clean();
|
||||||
|
}
|
||||||
|
|
||||||
|
var userUpdated = await context.SaveChangesAsync(cancellationToken) > 0;
|
||||||
|
|
||||||
|
return Result.OkIf(changedTotal > 0 && updateResult.IsSuccess && userUpdated, UpdateError.Create("Failed to update organisation"));
|
||||||
}));
|
}));
|
||||||
|
|
||||||
public async Task<Result> CreatePortfolioAsync(CreatePortfolioRequest request, Guid userId, CancellationToken cancellationToken = default) =>
|
public async Task<Result> CreatePortfolioAsync(CreatePortfolioRequest request, Guid userId, CancellationToken cancellationToken = default) =>
|
||||||
@@ -403,15 +432,21 @@ public sealed class GovernanceService(IDbContextFactory<ApplicationDbContext> co
|
|||||||
return Result.OkIf(changedTotal > 0, UpdateError.Create("Failed to update tenant organisation map"));
|
return Result.OkIf(changedTotal > 0, UpdateError.Create("Failed to update tenant organisation map"));
|
||||||
}));
|
}));
|
||||||
|
|
||||||
public async Task<Result<TenantOrganisation[]>> GetTenantOrganisationsAsync(CancellationToken cancellationToken = default) =>
|
public async Task<Result<TenantOrganisation[]>> GetTenantOrganisationsAsync(string tenantIdHash, CancellationToken cancellationToken = default) =>
|
||||||
await Result.Try((Func<Task<Result<TenantOrganisation[]>>>)(async () =>
|
await Result.Try((Func<Task<Result<TenantOrganisation[]>>>)(async () =>
|
||||||
{
|
{
|
||||||
|
var decodeResult = hashService.DecodeLongIdHash(tenantIdHash);
|
||||||
|
|
||||||
|
if (decodeResult.IsFailed)
|
||||||
|
return Result.Fail(IdDecodeError.Create()
|
||||||
|
.CausedBy(decodeResult.Errors));
|
||||||
|
|
||||||
await using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
|
await using var context = await contextFactory.CreateDbContextAsync(cancellationToken);
|
||||||
|
|
||||||
var tenantOrganisations = await context.TenantOrganisations.AsNoTracking()
|
var tenantOrganisations = await context.TenantOrganisations.AsNoTracking()
|
||||||
.Include(i => i.Organisation)
|
.Include(i => i.Organisation)
|
||||||
.Include(i => i.Tenant)
|
.Include(i => i.Tenant)
|
||||||
.Where(f => f.TenantId == tenantContext.TenantId)
|
.Where(f => f.TenantId == decodeResult.Value)
|
||||||
.ToListAsync();
|
.ToListAsync();
|
||||||
|
|
||||||
return Result.Ok(tenantOrganisations?.Select(i => i.Map()).ToArray() ?? []);
|
return Result.Ok(tenantOrganisations?.Select(i => i.Map()).ToArray() ?? []);
|
||||||
|
|||||||
@@ -38,12 +38,16 @@ public sealed record UpdateOrganisationRequest([Required] long OrganisationId,
|
|||||||
[Required][MaxLength(LabelLength)] string Name,
|
[Required][MaxLength(LabelLength)] string Name,
|
||||||
[Required][MaxLength(LabelLength)] string RegistrationNo,
|
[Required][MaxLength(LabelLength)] string RegistrationNo,
|
||||||
[Required][EmailAddress][MaxLength(LabelLength)] string Email,
|
[Required][EmailAddress][MaxLength(LabelLength)] string Email,
|
||||||
|
[Required][EmailAddress][MaxLength(LabelLength)] string IdNumber,
|
||||||
|
[Required] Guid OrganisationUser,
|
||||||
[Required] OrganisationType Type,
|
[Required] OrganisationType Type,
|
||||||
[Required] ActivityStatus Status);
|
[Required] ActivityStatus Status);
|
||||||
|
|
||||||
public sealed record CreateOrganisationRequest([Required][MaxLength(LabelLength)] string Name,
|
public sealed record CreateOrganisationRequest([Required][MaxLength(LabelLength)] string Name,
|
||||||
[Required][MaxLength(LabelLength)] string RegistrationNo,
|
[Required][MaxLength(LabelLength)] string RegistrationNo,
|
||||||
[Required][EmailAddress][MaxLength(LabelLength)] string Email,
|
[Required][EmailAddress][MaxLength(LabelLength)] string Email,
|
||||||
|
[Required][EmailAddress][MaxLength(LabelLength)] string IdNumber,
|
||||||
|
[Required] Guid OrganisationUser,
|
||||||
[Required] OrganisationType Type = OrganisationType.PrivateLimitedCompany);
|
[Required] OrganisationType Type = OrganisationType.PrivateLimitedCompany);
|
||||||
|
|
||||||
public sealed record Dashboard([Required] decimal PortfolioValue,
|
public sealed record Dashboard([Required] decimal PortfolioValue,
|
||||||
|
|||||||
@@ -5,6 +5,8 @@ namespace PostFundManagement.Domain.Entities;
|
|||||||
[EntityTypeConfiguration<OrganisationConfiguration, Organisation>]
|
[EntityTypeConfiguration<OrganisationConfiguration, Organisation>]
|
||||||
public class Organisation : Models.Organisation
|
public class Organisation : Models.Organisation
|
||||||
{
|
{
|
||||||
|
public virtual User? User { get; set; }
|
||||||
|
|
||||||
public virtual User? Creator { get; set; }
|
public virtual User? Creator { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -16,6 +18,7 @@ public sealed class OrganisationConfiguration : IEntityTypeConfiguration<Organis
|
|||||||
|
|
||||||
builder.HasKey(pk => pk.Id);
|
builder.HasKey(pk => pk.Id);
|
||||||
builder.Property(f => f.CreatedBy).IsRequired();
|
builder.Property(f => f.CreatedBy).IsRequired();
|
||||||
|
builder.Property(f => f.UserId).IsRequired(false);
|
||||||
builder.Property(f => f.CreatedAt).IsRequired().HasDefaultValueSql("now()");
|
builder.Property(f => f.CreatedAt).IsRequired().HasDefaultValueSql("now()");
|
||||||
builder.Property(f => f.RegistrationNo).IsRequired().HasMaxLength(LabelLength);
|
builder.Property(f => f.RegistrationNo).IsRequired().HasMaxLength(LabelLength);
|
||||||
builder.Property(f => f.Name).IsRequired().HasMaxLength(LabelLength);
|
builder.Property(f => f.Name).IsRequired().HasMaxLength(LabelLength);
|
||||||
@@ -25,6 +28,12 @@ public sealed class OrganisationConfiguration : IEntityTypeConfiguration<Organis
|
|||||||
builder.Property(f => f.Status).IsRequired().HasConversion<int>().HasDefaultValueSql("1")
|
builder.Property(f => f.Status).IsRequired().HasConversion<int>().HasDefaultValueSql("1")
|
||||||
.HasSentinel(ActivityStatus.Active);
|
.HasSentinel(ActivityStatus.Active);
|
||||||
|
|
||||||
|
builder.HasOne(f => f.User)
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey(fk => fk.UserId)
|
||||||
|
.IsRequired(false)
|
||||||
|
.OnDelete(DeleteBehavior.NoAction);
|
||||||
|
|
||||||
builder.HasOne(f => f.Creator)
|
builder.HasOne(f => f.Creator)
|
||||||
.WithMany()
|
.WithMany()
|
||||||
.HasForeignKey(fk => fk.CreatedBy)
|
.HasForeignKey(fk => fk.CreatedBy)
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ public sealed class UserConfiguration : IEntityTypeConfiguration<User>
|
|||||||
builder.HasKey(pk => pk.Id);
|
builder.HasKey(pk => pk.Id);
|
||||||
builder.Property(f => f.Email).IsRequired().HasMaxLength(LabelLength);
|
builder.Property(f => f.Email).IsRequired().HasMaxLength(LabelLength);
|
||||||
builder.Property(f => f.Role).IsRequired(false).HasMaxLength(LabelLength);
|
builder.Property(f => f.Role).IsRequired(false).HasMaxLength(LabelLength);
|
||||||
|
builder.Property(f => f.IdNumber).IsRequired(false).HasMaxLength(LabelLength);
|
||||||
builder.Property(f => f.Status).IsRequired().HasConversion<int>().HasDefaultValueSql("2")
|
builder.Property(f => f.Status).IsRequired().HasConversion<int>().HasDefaultValueSql("2")
|
||||||
.HasSentinel(ActivityStatus.Inactive);
|
.HasSentinel(ActivityStatus.Inactive);
|
||||||
builder.Property(f => f.LastLoginAt).IsRequired(false);
|
builder.Property(f => f.LastLoginAt).IsRequired(false);
|
||||||
|
|||||||
@@ -270,7 +270,8 @@ public static class Mappers
|
|||||||
Name = entity.Name,
|
Name = entity.Name,
|
||||||
RegistrationNo = entity.RegistrationNo,
|
RegistrationNo = entity.RegistrationNo,
|
||||||
Status = entity.Status,
|
Status = entity.Status,
|
||||||
Type = entity.Type
|
Type = entity.Type,
|
||||||
|
UserId = entity.UserId
|
||||||
};
|
};
|
||||||
|
|
||||||
public static Outcome Map(this Entities.Outcome entity) => new()
|
public static Outcome Map(this Entities.Outcome entity) => new()
|
||||||
@@ -392,6 +393,7 @@ public static class Mappers
|
|||||||
Email = entity.Email,
|
Email = entity.Email,
|
||||||
LastLoginAt = entity.LastLoginAt,
|
LastLoginAt = entity.LastLoginAt,
|
||||||
Status = entity.Status,
|
Status = entity.Status,
|
||||||
Role = entity.Role
|
Role = entity.Role,
|
||||||
|
IdNumber = entity.IdNumber
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -14,6 +14,8 @@ public class Organisation
|
|||||||
|
|
||||||
public string? Email { get; set; }
|
public string? Email { get; set; }
|
||||||
|
|
||||||
|
public Guid? UserId { get; set; }
|
||||||
|
|
||||||
public OrganisationType Type { get; set; }
|
public OrganisationType Type { get; set; }
|
||||||
|
|
||||||
public ActivityStatus Status { get; set; }
|
public ActivityStatus Status { get; set; }
|
||||||
|
|||||||
@@ -10,5 +10,7 @@ public class User
|
|||||||
|
|
||||||
public string? Role { get; set; }
|
public string? Role { get; set; }
|
||||||
|
|
||||||
|
public string? IdNumber { get; set; }
|
||||||
|
|
||||||
public ActivityStatus Status { get; set; }
|
public ActivityStatus Status { get; set; }
|
||||||
}
|
}
|
||||||
@@ -6,7 +6,7 @@ namespace PostFundManagement.Infrastructure.Database;
|
|||||||
public sealed class ApplicationDbContext(DbContextOptions<ApplicationDbContext> options,
|
public sealed class ApplicationDbContext(DbContextOptions<ApplicationDbContext> options,
|
||||||
ITenantContextService tenantService) : DbContext(options)
|
ITenantContextService tenantService) : DbContext(options)
|
||||||
{
|
{
|
||||||
private bool BypassFilter => tenantService.IsAdmin || tenantService.ByPassTenantQueryFilter;
|
private bool BypassFilter => tenantService.ByPassTenantQueryFilter;
|
||||||
private long CurrentTenantId => tenantService.TenantId;
|
private long CurrentTenantId => tenantService.TenantId;
|
||||||
|
|
||||||
public DbSet<TenantUser> TenantUsers => Set<TenantUser>();
|
public DbSet<TenantUser> TenantUsers => Set<TenantUser>();
|
||||||
@@ -84,14 +84,14 @@ public sealed class ApplicationDbContext(DbContextOptions<ApplicationDbContext>
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
modelBuilder.Entity<Organisation>().HasQueryFilter(o => BypassFilter == false &&
|
modelBuilder.Entity<Organisation>().HasQueryFilter(o => BypassFilter ||
|
||||||
Set<TenantOrganisation>().Any(to => to.TenantId == CurrentTenantId && to.OrganisationId == o.Id));
|
Set<TenantOrganisation>().Any(to => to.TenantId == CurrentTenantId && to.OrganisationId == o.Id));
|
||||||
|
|
||||||
modelBuilder.Entity<TenantOrganisation>()
|
modelBuilder.Entity<TenantOrganisation>()
|
||||||
.HasQueryFilter(to => BypassFilter == false && to.TenantId == CurrentTenantId);
|
.HasQueryFilter(to => BypassFilter || to.TenantId == CurrentTenantId);
|
||||||
|
|
||||||
modelBuilder.Entity<TenantUser>()
|
modelBuilder.Entity<TenantUser>()
|
||||||
.HasQueryFilter(to => BypassFilter == false && to.TenantId == CurrentTenantId);
|
.HasQueryFilter(to => BypassFilter || to.TenantId == CurrentTenantId);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override Task<int> SaveChangesAsync(CancellationToken cancellationToken = default)
|
public override Task<int> SaveChangesAsync(CancellationToken cancellationToken = default)
|
||||||
|
|||||||
+2473
File diff suppressed because it is too large
Load Diff
+60
@@ -0,0 +1,60 @@
|
|||||||
|
using System;
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace PostFundManagement.Infrastructure.Database.Migrations
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
public partial class AddedUserIdAndIdNumberTenantOrgAndUserObjects : Migration
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.AddColumn<string>(
|
||||||
|
name: "IdNumber",
|
||||||
|
table: "Users",
|
||||||
|
type: "character varying(256)",
|
||||||
|
maxLength: 256,
|
||||||
|
nullable: true);
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<Guid>(
|
||||||
|
name: "UserId",
|
||||||
|
table: "Organisations",
|
||||||
|
type: "uuid",
|
||||||
|
nullable: true);
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_Organisations_UserId",
|
||||||
|
table: "Organisations",
|
||||||
|
column: "UserId");
|
||||||
|
|
||||||
|
migrationBuilder.AddForeignKey(
|
||||||
|
name: "FK_Organisations_Users_UserId",
|
||||||
|
table: "Organisations",
|
||||||
|
column: "UserId",
|
||||||
|
principalTable: "Users",
|
||||||
|
principalColumn: "Id");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DropForeignKey(
|
||||||
|
name: "FK_Organisations_Users_UserId",
|
||||||
|
table: "Organisations");
|
||||||
|
|
||||||
|
migrationBuilder.DropIndex(
|
||||||
|
name: "IX_Organisations_UserId",
|
||||||
|
table: "Organisations");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "IdNumber",
|
||||||
|
table: "Users");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "UserId",
|
||||||
|
table: "Organisations");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+16
@@ -1017,10 +1017,15 @@ namespace PostFundManagement.Infrastructure.Database.Migrations
|
|||||||
.HasColumnType("integer")
|
.HasColumnType("integer")
|
||||||
.HasDefaultValueSql("5");
|
.HasDefaultValueSql("5");
|
||||||
|
|
||||||
|
b.Property<Guid?>("UserId")
|
||||||
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
b.HasKey("Id");
|
b.HasKey("Id");
|
||||||
|
|
||||||
b.HasIndex("CreatedBy");
|
b.HasIndex("CreatedBy");
|
||||||
|
|
||||||
|
b.HasIndex("UserId");
|
||||||
|
|
||||||
b.ToTable("Organisations", (string)null);
|
b.ToTable("Organisations", (string)null);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -1530,6 +1535,10 @@ namespace PostFundManagement.Infrastructure.Database.Migrations
|
|||||||
.HasMaxLength(256)
|
.HasMaxLength(256)
|
||||||
.HasColumnType("character varying(256)");
|
.HasColumnType("character varying(256)");
|
||||||
|
|
||||||
|
b.Property<string>("IdNumber")
|
||||||
|
.HasMaxLength(256)
|
||||||
|
.HasColumnType("character varying(256)");
|
||||||
|
|
||||||
b.Property<DateTime?>("LastLoginAt")
|
b.Property<DateTime?>("LastLoginAt")
|
||||||
.HasColumnType("timestamp with time zone");
|
.HasColumnType("timestamp with time zone");
|
||||||
|
|
||||||
@@ -2124,7 +2133,14 @@ namespace PostFundManagement.Infrastructure.Database.Migrations
|
|||||||
.OnDelete(DeleteBehavior.NoAction)
|
.OnDelete(DeleteBehavior.NoAction)
|
||||||
.IsRequired();
|
.IsRequired();
|
||||||
|
|
||||||
|
b.HasOne("PostFundManagement.Domain.Entities.User", "User")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("UserId")
|
||||||
|
.OnDelete(DeleteBehavior.NoAction);
|
||||||
|
|
||||||
b.Navigation("Creator");
|
b.Navigation("Creator");
|
||||||
|
|
||||||
|
b.Navigation("User");
|
||||||
});
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("PostFundManagement.Domain.Entities.Outcome", b =>
|
modelBuilder.Entity("PostFundManagement.Domain.Entities.Outcome", b =>
|
||||||
|
|||||||
@@ -19,6 +19,9 @@ public sealed class TenantContextService : ITenantContextService
|
|||||||
var user = httpContextAccessor.HttpContext?.User;
|
var user = httpContextAccessor.HttpContext?.User;
|
||||||
|
|
||||||
IsAdmin = user?.IsInRole("Admin") == true || user?.HasClaim("role", "Admin") == true;
|
IsAdmin = user?.IsInRole("Admin") == true || user?.HasClaim("role", "Admin") == true;
|
||||||
|
ByPassTenantQueryFilter = user?.IsInRole("Partner") == true || user?.HasClaim("role", "Partner") == true;
|
||||||
|
|
||||||
|
ByPassTenantQueryFilter = ByPassTenantQueryFilter || IsAdmin;
|
||||||
|
|
||||||
HasTenantFilter = !IsAdmin;
|
HasTenantFilter = !IsAdmin;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user