Use cacheTable for roles and permissions

This commit is contained in:
Фролов 2021-12-03 15:03:33 +05:00
parent 00dd39b587
commit 539905e8e0
14 changed files with 250 additions and 201 deletions

View File

@ -8,13 +8,12 @@ namespace AsbCloudApp.Services
where Tdto : Data.IId where Tdto : Data.IId
{ {
List<string> Incledes { get; } List<string> Incledes { get; }
Task<int> DeleteAsync(int id, CancellationToken token = default);
Task<int> DeleteAsync(IEnumerable<int> ids, CancellationToken token = default);
Task<IEnumerable<Tdto>> GetAllAsync(CancellationToken token = default);
Task<Tdto> GetAsync(int id, CancellationToken token = default);
Task<Data.PaginationContainer<Tdto>> GetPageAsync(int skip = 0, int take = 32, CancellationToken token = default);
Task<int> InsertAsync(Tdto newItem, CancellationToken token = default); Task<int> InsertAsync(Tdto newItem, CancellationToken token = default);
Task<int> InsertRangeAsync(IEnumerable<Tdto> newItems, CancellationToken token = default); Task<int> InsertRangeAsync(IEnumerable<Tdto> newItems, CancellationToken token = default);
Task<IEnumerable<Tdto>> GetAllAsync(CancellationToken token = default);
Task<Tdto> GetAsync(int id, CancellationToken token = default);
Task<int> UpdateAsync(int id, Tdto item, CancellationToken token = default); Task<int> UpdateAsync(int id, Tdto item, CancellationToken token = default);
Task<int> DeleteAsync(int id, CancellationToken token = default);
Task<int> DeleteAsync(IEnumerable<int> ids, CancellationToken token = default);
} }
} }

View File

@ -0,0 +1,10 @@
using System.Threading;
using System.Threading.Tasks;
namespace AsbCloudApp.Services
{
public interface IPaginationService<Tdto>
{
Task<Data.PaginationContainer<Tdto>> GetPageAsync(int skip = 0, int take = 32, CancellationToken token = default);
}
}

View File

@ -11,6 +11,6 @@ namespace AsbCloudApp.Services
Task<int> InsertRangeAsync(IEnumerable<PermissionDto> dtos, CancellationToken token); Task<int> InsertRangeAsync(IEnumerable<PermissionDto> dtos, CancellationToken token);
Task<int> UpdateAsync(PermissionDto dto, CancellationToken token); Task<int> UpdateAsync(PermissionDto dto, CancellationToken token);
Task<int> DeleteAsync(int idUserRole, int idPermission, CancellationToken token); Task<int> DeleteAsync(int idUserRole, int idPermission, CancellationToken token);
Task<int> DeleteAllByRoleAsync(int idUserRole, CancellationToken token);
} }
} }

View File

@ -0,0 +1,8 @@
using AsbCloudApp.Data;
namespace AsbCloudApp.Services
{
public interface IUserRoleService: ICrudService<UserRoleDto>
{
}
}

View File

@ -1,8 +1,5 @@
using AsbCloudApp.Data; using AsbCloudApp.Data;
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;

View File

@ -42,41 +42,35 @@ namespace AsbCloudInfrastructure
services.AddTransient<IAuthService, AuthService>(); services.AddTransient<IAuthService, AuthService>();
services.AddTransient<IClusterService, ClusterService>(); services.AddTransient<IClusterService, ClusterService>();
services.AddTransient<IDrillFlowChartService, DrillFlowChartService>(); services.AddTransient<IDrillFlowChartService, DrillFlowChartService>();
services.AddTransient<IDrillParamsService, DrillParamsService>();
services.AddTransient<IDrillingProgramService, DrillingProgramService>(); services.AddTransient<IDrillingProgramService, DrillingProgramService>();
services.AddTransient<IDrillParamsService, DrillParamsService>();
services.AddTransient<IEventService, EventService>(); services.AddTransient<IEventService, EventService>();
services.AddTransient<IFileService, FileService>(); services.AddTransient<IFileService, FileService>();
services.AddTransient<IMeasureService, MeasureService>(); services.AddTransient<IMeasureService, MeasureService>();
services.AddTransient<IMessageService, MessageService>(); services.AddTransient<IMessageService, MessageService>();
services.AddTransient<IOperationsStatService, OperationsStatService>();
services.AddTransient<IPermissionService, PermissionService>(); services.AddTransient<IPermissionService, PermissionService>();
services.AddTransient<IReportService, ReportService>(); services.AddTransient<IReportService, ReportService>();
services.AddTransient<ISetpointsService, SetpointsService>();
services.AddTransient<ITelemetryAnalyticsService, TelemetryAnalyticsService>(); services.AddTransient<ITelemetryAnalyticsService, TelemetryAnalyticsService>();
services.AddTransient<ITelemetryService, TelemetryService>(); services.AddTransient<ITelemetryService, TelemetryService>();
services.AddTransient<ITelemetryUserService, TelemetryUserService>(); services.AddTransient<ITelemetryUserService, TelemetryUserService>();
services.AddTransient<ITimeZoneService, TimeZoneService>(); services.AddTransient<ITimeZoneService, TimeZoneService>();
services.AddTransient<IUserRoleService, UserRoleService>();
services.AddTransient<IWellService, WellService>();
services.AddTransient<IWellCompositeService, WellCompositeService>(); services.AddTransient<IWellCompositeService, WellCompositeService>();
services.AddTransient<IWellOperationImportService, WellOperationImportService>(); services.AddTransient<IWellOperationImportService, WellOperationImportService>();
services.AddTransient<IWellOperationService, WellOperationService>(); services.AddTransient<IWellOperationService, WellOperationService>();
services.AddTransient<IOperationsStatService, OperationsStatService>();
services.AddTransient<IWellOperationImportService, WellOperationImportService>();
services.AddTransient<IWellCompositeService, WellCompositeService>();
services.AddTransient<IMeasureService, MeasureService>();
services.AddTransient<IDrillingProgramService, DrillingProgramService>();
services.AddTransient<IDrillParamsService, DrillParamsService>();
services.AddTransient<IDrillFlowChartService, DrillFlowChartService>();
services.AddTransient<ITimeZoneService, TimeZoneService>();
services.AddTransient<ISetpointsService, SetpointsService>();
// admin crud services: // admin crud services:
services.AddTransient<ICrudService<ClusterDto>, CrudServiceBase<ClusterDto, Cluster>>();
services.AddTransient<ICrudService<CompanyDto>, CrudServiceBase<CompanyDto, Company>>();
services.AddTransient<ICrudService<DepositDto>, CrudServiceBase<DepositDto, Deposit>>();
services.AddTransient<ICrudService<DrillParamsDto>, DrillParamsService>();
services.AddTransient<ICrudService<PermissionInfoDto>, CrudServiceBase<PermissionInfoDto, PermissionInfo>>();
services.AddTransient<ICrudService<TelemetryDto>, CrudServiceBase<TelemetryDto, Telemetry>>();
services.AddTransient<ICrudService<UserDto>, CrudServiceBase<UserDto, User>>();
services.AddTransient<ICrudService<UserRoleDto>, UserRoleService>();
services.AddTransient<ICrudService<WellDto>, CrudServiceBase<WellDto, Well>>(); services.AddTransient<ICrudService<WellDto>, CrudServiceBase<WellDto, Well>>();
services.AddTransient<ICrudService<UserDto>, CrudServiceBase<UserDto, User>>();
services.AddTransient<ICrudService<TelemetryDto>, CrudServiceBase<TelemetryDto, Telemetry>>();
services.AddTransient<ICrudService<PermissionInfoDto>, CrudServiceBase<PermissionInfoDto, PermissionInfo>>();
services.AddTransient<ICrudService<DrillParamsDto>, DrillParamsService>();
services.AddTransient<ICrudService<DepositDto>, CrudServiceBase<DepositDto, Deposit>>();
services.AddTransient<ICrudService<CompanyDto>, CrudServiceBase<CompanyDto, Company>>();
services.AddTransient<ICrudService<ClusterDto>, CrudServiceBase<ClusterDto, Cluster>>();
// TelemetryData services // TelemetryData services
services.AddTransient<ITelemetryDataService<TelemetryDataSaubDto>, TelemetryDataSaubService>(); services.AddTransient<ITelemetryDataService<TelemetryDataSaubDto>, TelemetryDataSaubService>();

View File

@ -65,15 +65,17 @@ namespace AsbCloudInfrastructure.Services.Cache
/// It may be needed to avoid multiple operations like Refresh(). /// It may be needed to avoid multiple operations like Refresh().
/// </summary> /// </summary>
/// <param name="action">(wasFree) => {...}</param> /// <param name="action">(wasFree) => {...}</param>
/// <returns>false - semaphore.Wait returned by timeout</returns> /// <returns>default if semaphoreTimeout. Or result of func(..)</returns>
private static bool Sync(Action<bool> action) private static T Sync<T>(Func<bool, T> func)
{ {
var wasFree = semaphore.CurrentCount > 0; var wasFree = semaphore.CurrentCount > 0;
if (!semaphore.Wait(semaphoreTimeout)) T result = default;
return false; if (func is null || !semaphore.Wait(semaphoreTimeout))
return result;
try try
{ {
action?.Invoke(wasFree); result = func.Invoke(wasFree);
} }
catch (Exception ex) catch (Exception ex)
{ {
@ -85,7 +87,7 @@ namespace AsbCloudInfrastructure.Services.Cache
{ {
semaphore.Release(); semaphore.Release();
} }
return true; return result;
} }
/// <summary> /// <summary>
@ -94,15 +96,18 @@ namespace AsbCloudInfrastructure.Services.Cache
/// It may be needed to avoid multiple operations like Refresh(). /// It may be needed to avoid multiple operations like Refresh().
/// </summary> /// </summary>
/// <param name="action">(wasFree) => {...}</param> /// <param name="action">(wasFree) => {...}</param>
/// <returns>false - semaphore.Wait returned by timeout</returns> /// <returns>default if semaphoreTimeout. Or result of func(..)</returns>
private static async Task<bool> SyncAsync(Func<bool, CancellationToken, Task> task, CancellationToken token = default) private static async Task<T> SyncAsync<T>(Func<bool, CancellationToken, Task<T>> funcAsync, CancellationToken token = default)
{ {
var wasFree = semaphore.CurrentCount > 0; var wasFree = semaphore.CurrentCount > 0;
if (!await semaphore.WaitAsync(semaphoreTimeout, token).ConfigureAwait(false)) T result = default;
return false;
if (funcAsync is null || !await semaphore.WaitAsync(semaphoreTimeout, token).ConfigureAwait(false))
return result;
try try
{ {
await task?.Invoke(wasFree, token); result = await funcAsync.Invoke(wasFree, token);
} }
catch (Exception ex) catch (Exception ex)
{ {
@ -114,10 +119,10 @@ namespace AsbCloudInfrastructure.Services.Cache
{ {
semaphore.Release(); semaphore.Release();
} }
return true; return result;
} }
private void InternalRefresh(bool force) private int InternalRefresh(bool force)
{ {
if (force || data.LastResreshDate + minPeriodRefresh < DateTime.Now) if (force || data.LastResreshDate + minPeriodRefresh < DateTime.Now)
{ {
@ -128,9 +133,10 @@ namespace AsbCloudInfrastructure.Services.Cache
cached.AddRange(entities); cached.AddRange(entities);
data.LastResreshDate = DateTime.Now; data.LastResreshDate = DateTime.Now;
} }
return cached.Count;
} }
private async Task InternalRefreshAsync(bool force, CancellationToken token = default) private async Task<int> InternalRefreshAsync(bool force, CancellationToken token = default)
{ {
if (force || data.LastResreshDate + minPeriodRefresh < DateTime.Now) if (force || data.LastResreshDate + minPeriodRefresh < DateTime.Now)
{ {
@ -142,24 +148,18 @@ namespace AsbCloudInfrastructure.Services.Cache
cached.AddRange(entities); cached.AddRange(entities);
data.LastResreshDate = DateTime.Now; data.LastResreshDate = DateTime.Now;
} }
return cached.Count;
} }
public int Refresh(bool force) public int Refresh(bool force)
{ => Sync((wasFree) => wasFree ? InternalRefresh(force) : 0);
Sync((wasFree) => {
if (wasFree)
InternalRefresh(force);
});
return cached.Count;
}
public async Task<int> RefreshAsync(bool force, CancellationToken token = default) public Task<int> RefreshAsync(bool force, CancellationToken token = default)
{ {
await SyncAsync(async (wasFree, token) => { return SyncAsync(async (wasFree, token) =>
if (wasFree) {
await InternalRefreshAsync(force, token).ConfigureAwait(false); return wasFree ? await InternalRefreshAsync(force, token).ConfigureAwait(false) : 0;
}, token).ConfigureAwait(false); }, token);
return cached.Count;
} }
public bool Contains(Func<TEntity, bool> predicate) public bool Contains(Func<TEntity, bool> predicate)
@ -169,25 +169,22 @@ namespace AsbCloudInfrastructure.Services.Cache
=> await FirstOrDefaultAsync(predicate, token) != default; => await FirstOrDefaultAsync(predicate, token) != default;
public TEntity GetOrCreate(Func<TEntity, bool> predicate, Func<TEntity> makeNew) public TEntity GetOrCreate(Func<TEntity, bool> predicate, Func<TEntity> makeNew)
=> Sync(wasFree =>
{ {
TEntity result = default; var result = cached.FirstOrDefault(predicate);
Sync(wasFree => {
result = cached.FirstOrDefault(predicate);
if (result != default) if (result != default)
return; return result;
InternalRefresh(true); InternalRefresh(true);
result = cached.FirstOrDefault(predicate); result = cached.FirstOrDefault(predicate);
if (result != default) if (result != default)
return; return result;
var entry = dbSet.Add(makeNew()); var entry = dbSet.Add(makeNew());
context.SaveChanges(); context.SaveChanges();
InternalRefresh(true); InternalRefresh(true);
result = entry.Entity; return entry.Entity;
}); });
return result;
}
public TEntity FirstOrDefault() public TEntity FirstOrDefault()
{ {
@ -263,11 +260,11 @@ namespace AsbCloudInfrastructure.Services.Cache
return result; return result;
} }
public void Upsert(TEntity entity) public int Upsert(TEntity entity)
{ {
if (entity == default) if (entity == default)
return; return 0;
Sync((wasFree) => return Sync((wasFree) =>
{ {
if (dbSet.Contains(entity)) if (dbSet.Contains(entity))
dbSet.Update(entity); dbSet.Update(entity);
@ -276,26 +273,29 @@ namespace AsbCloudInfrastructure.Services.Cache
var affected = context.SaveChanges(); var affected = context.SaveChanges();
if (affected > 0) if (affected > 0)
InternalRefresh(true); InternalRefresh(true);
return affected;
}); });
} }
public Task UpsertAsync(TEntity entity, CancellationToken token = default) public Task<int> UpsertAsync(TEntity entity, CancellationToken token = default)
=> SyncAsync(async (wasFree, token) => { => SyncAsync(async (wasFree, token) =>
{
if (dbSet.Contains(entity)) if (dbSet.Contains(entity))
dbSet.Update(entity); dbSet.Update(entity);
else else
dbSet.Add(entity); dbSet.Add(entity);
var affected = await context.SaveChangesAsync(token).ConfigureAwait(false); var affected = await context.SaveChangesAsync(token).ConfigureAwait(false);
if(affected > 0) if (affected > 0)
await InternalRefreshAsync(true, token).ConfigureAwait(false); await InternalRefreshAsync(true, token).ConfigureAwait(false);
return affected;
}, token); }, token);
public void Upsert(IEnumerable<TEntity> entities) public int Upsert(IEnumerable<TEntity> entities)
{ {
if (!entities.Any()) if (!entities.Any())
return; return 0;
Sync((wasFree) => return Sync((wasFree) =>
{ {
foreach (var entity in entities) foreach (var entity in entities)
{ {
@ -307,15 +307,17 @@ namespace AsbCloudInfrastructure.Services.Cache
var affected = context.SaveChanges(); var affected = context.SaveChanges();
if (affected > 0) if (affected > 0)
InternalRefresh(true); InternalRefresh(true);
return affected;
}); });
} }
public async Task UpsertAsync(IEnumerable<TEntity> entities, CancellationToken token = default) public Task<int> UpsertAsync(IEnumerable<TEntity> entities, CancellationToken token = default)
{ {
if (!entities.Any()) if (!entities.Any())
return; return Task.FromResult(0);
await SyncAsync(async (wasFree, token) => { return SyncAsync(async (wasFree, token) =>
{
var upsertedEntries = new List<TEntity>(entities.Count()); var upsertedEntries = new List<TEntity>(entities.Count());
foreach (var entity in entities) foreach (var entity in entities)
{ {
@ -327,76 +329,76 @@ namespace AsbCloudInfrastructure.Services.Cache
var affected = await context.SaveChangesAsync(token).ConfigureAwait(false); var affected = await context.SaveChangesAsync(token).ConfigureAwait(false);
if (affected > 0) if (affected > 0)
await InternalRefreshAsync(true, token).ConfigureAwait(false); await InternalRefreshAsync(true, token).ConfigureAwait(false);
return affected;
}, token); }, token);
} }
public void Remove(Func<TEntity, bool> predicate) public int Remove(Func<TEntity, bool> predicate)
=> Sync(_ => => Sync(_ =>
{ {
dbSet.RemoveRange(dbSet.Where(predicate)); dbSet.RemoveRange(dbSet.Where(predicate));
var affected = context.SaveChanges(); var affected = context.SaveChanges();
if (affected > 0) if (affected > 0)
InternalRefresh(true); InternalRefresh(true);
return affected;
}); });
public Task RemoveAsync(Func<TEntity, bool> predicate, CancellationToken token = default) public Task<int> RemoveAsync(Func<TEntity, bool> predicate, CancellationToken token = default)
=> SyncAsync(async (wasFree, token) => { => SyncAsync(async (wasFree, token) =>
{
dbSet.RemoveRange(dbSet.Where(predicate)); dbSet.RemoveRange(dbSet.Where(predicate));
var affected = await context.SaveChangesAsync(token).ConfigureAwait(false); var affected = await context.SaveChangesAsync(token).ConfigureAwait(false);
if (affected > 0) if (affected > 0)
await InternalRefreshAsync(true, token).ConfigureAwait(false); await InternalRefreshAsync(true, token).ConfigureAwait(false);
return affected;
}, token); }, token);
public TEntity Insert(TEntity entity) public TEntity Insert(TEntity entity)
{ {
TEntity result = default; return Sync(_ =>
Sync(_ =>
{ {
var entry = dbSet.Add(entity); var entry = dbSet.Add(entity);
var affected = context.SaveChanges(); var affected = context.SaveChanges();
if (affected > 0) if (affected > 0)
InternalRefresh(true); InternalRefresh(true);
result = entry.Entity; return entry.Entity;
}); });
return result;
} }
public async Task<TEntity> InsertAsync(TEntity entity, CancellationToken token = default) public Task<TEntity> InsertAsync(TEntity entity, CancellationToken token = default)
{ {
TEntity result = default; return SyncAsync(async (wasFree, token) =>
await SyncAsync(async (wasFree, token) =>
{ {
var entry = dbSet.Add(entity); var entry = dbSet.Add(entity);
var affected = await context.SaveChangesAsync(token).ConfigureAwait(false); var affected = await context.SaveChangesAsync(token).ConfigureAwait(false);
if (affected > 0) if (affected > 0)
await InternalRefreshAsync(true, token).ConfigureAwait(false); await InternalRefreshAsync(true, token).ConfigureAwait(false);
result = entry.Entity; return entry.Entity;
}, token); }, token);
return result;
} }
public int Insert(IEnumerable<TEntity> newEntities) public int Insert(IEnumerable<TEntity> newEntities)
{ {
int result = 0; return Sync(_ =>
Sync(_ => { {
dbSet.AddRange(newEntities); dbSet.AddRange(newEntities);
result = context.SaveChanges(); var affected = context.SaveChanges();
if (result > 0) if (affected > 0)
InternalRefresh(true); InternalRefresh(true);
return affected;
}); });
return result;
} }
public async Task<int> InsertAsync(IEnumerable<TEntity> newEntities, CancellationToken token = default) public Task<int> InsertAsync(IEnumerable<TEntity> newEntities, CancellationToken token = default)
{
return SyncAsync(async (wasFree, token) =>
{ {
int result = 0;
await SyncAsync(async (wasFree, token) => {
dbSet.AddRange(newEntities); dbSet.AddRange(newEntities);
result = await context.SaveChangesAsync(token).ConfigureAwait(false); var affected = await context.SaveChangesAsync(token).ConfigureAwait(false);
if (result > 0) if (affected > 0)
await InternalRefreshAsync(true, token).ConfigureAwait(false); await InternalRefreshAsync(true, token).ConfigureAwait(false);
return affected;
}, token); }, token);
return result;
} }
public IEnumerator<TEntity> GetEnumerator() => Where().GetEnumerator(); public IEnumerator<TEntity> GetEnumerator() => Where().GetEnumerator();

View File

@ -102,11 +102,15 @@ namespace AsbCloudInfrastructure.Services
return context.SaveChangesAsync(token); return context.SaveChangesAsync(token);
} }
public virtual Task<int> UpdateAsync(int id, TDto item, CancellationToken token = default) public virtual async Task<int> UpdateAsync(int id, TDto item, CancellationToken token = default)
{ {
var existingEntity = await dbSet.AsNoTracking().FirstOrDefaultAsync(e => e.Id == id).ConfigureAwait(false);
if (existingEntity is null)
return 0;
var entity = Convert(item); var entity = Convert(item);
entity.Id = id;
dbSet.Update(entity); dbSet.Update(entity);
return context.SaveChangesAsync(token); return await context.SaveChangesAsync(token);
} }
public virtual Task<int> DeleteAsync(int id, CancellationToken token = default) public virtual Task<int> DeleteAsync(int id, CancellationToken token = default)

View File

@ -1,8 +1,9 @@
using AsbCloudApp.Data; using AsbCloudApp.Data;
using AsbCloudApp.Services; using AsbCloudApp.Services;
using AsbCloudDb.Model; using AsbCloudDb.Model;
using AsbCloudInfrastructure.Services.Cache;
using Mapster; using Mapster;
using Microsoft.EntityFrameworkCore; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Threading; using System.Threading;
@ -12,18 +13,19 @@ namespace AsbCloudInfrastructure.Services
{ {
public class PermissionService : IPermissionService, IConverter<PermissionDto, Permission> public class PermissionService : IPermissionService, IConverter<PermissionDto, Permission>
{ {
private readonly IAsbCloudDbContext db; private readonly CacheTable<Permission> cachePermission;
public PermissionService(IAsbCloudDbContext db) public PermissionService(IAsbCloudDbContext db, CacheDb cacheDb)
{ {
this.db = db; cachePermission = cacheDb.GetCachedTable<Permission>(
(AsbCloudDbContext)db,
new string[] { nameof(Permission.PermissionInfo) });
} }
public async Task<IEnumerable<PermissionDto>> GetByIdRoleAsync(int idRole, CancellationToken token) public async Task<IEnumerable<PermissionDto>> GetByIdRoleAsync(int idRole, CancellationToken token)
{ {
var entities = await db.Permissions var entities = await cachePermission
.Where(p => p.IdUserRole == idRole) .WhereAsync(p => p.IdUserRole == idRole, token)
.ToListAsync(token)
.ConfigureAwait(false); .ConfigureAwait(false);
var dto = entities.Select(Convert); var dto = entities.Select(Convert);
return dto; return dto;
@ -32,26 +34,36 @@ namespace AsbCloudInfrastructure.Services
public Task<int> InsertRangeAsync(IEnumerable<PermissionDto> dtos, CancellationToken token) public Task<int> InsertRangeAsync(IEnumerable<PermissionDto> dtos, CancellationToken token)
{ {
var entities = dtos.Select(Convert); var entities = dtos.Select(Convert);
db.Permissions.AddRange(entities); return cachePermission.InsertAsync(entities, token);
return db.SaveChangesAsync(token);
} }
public Task<int> UpdateAsync(PermissionDto dto, CancellationToken token) public async Task<int> UpdateAsync(PermissionDto dto, CancellationToken token)
{ {
var entity = Convert(dto); var entity = Convert(dto);
db.Permissions.Update(entity); await cachePermission.UpsertAsync(entity, token)
return db.SaveChangesAsync(token); .ConfigureAwait(false);
return 1;
} }
public Task<int> DeleteAsync(int idUserRole, int idPermission, CancellationToken token) public Task<int> DeleteAsync(int idUserRole, int idPermission, CancellationToken token)
{ {
var entities = db.Permissions.AsNoTracking() bool predicate(Permission p) => p.IdUserRole == idUserRole && p.IdPermission == idPermission;
.Where(e => e.IdUserRole == idUserRole && e.IdPermission == idPermission) return DeleteAsync(predicate, token);
.ToList(); }
if (!entities.Any())
return Task.FromResult(0); public Task<int> DeleteAllByRoleAsync(int idUserRole, CancellationToken token)
db.Permissions.RemoveRange(entities); {
return db.SaveChangesAsync(token); bool predicate(Permission p) => p.IdUserRole == idUserRole;
return DeleteAsync(predicate, token);
}
private async Task<int> DeleteAsync(Func<Permission, bool> predicate, CancellationToken token)
{
var count = (await cachePermission.WhereAsync(predicate, token).ConfigureAwait(false)).Count();
if (count > 0)
await cachePermission.RemoveAsync(predicate, token)
.ConfigureAwait(false);
return count;
} }
public Permission Convert(PermissionDto src) public Permission Convert(PermissionDto src)

View File

@ -11,66 +11,97 @@ using AsbCloudApp.Services;
namespace AsbCloudInfrastructure.Services namespace AsbCloudInfrastructure.Services
{ {
public class UserRoleService : CrudServiceBase<UserRoleDto, UserRole> public class UserRoleService : IUserRoleService
{ {
private readonly CacheTable<UserRole> cacheUserRoles; private readonly CacheTable<UserRole> cacheUserRoles;
private readonly IPermissionService permissionService; private readonly IPermissionService permissionService;
public UserRoleService(IAsbCloudDbContext context, CacheDb cacheDb, IPermissionService permissionService) : base(context) public List<string> Incledes { get; } = new();
public UserRoleService(IAsbCloudDbContext context, CacheDb cacheDb, IPermissionService permissionService)
{ {
cacheUserRoles = cacheDb.GetCachedTable<UserRole>((AsbCloudDbContext)context); cacheUserRoles = cacheDb.GetCachedTable<UserRole>((AsbCloudDbContext)context, new string[] { nameof(UserRole.Permissions) });
this.permissionService = permissionService; this.permissionService = permissionService;
} }
public override async Task<PaginationContainer<UserRoleDto>> GetPageAsync(int skip = 0, public async Task<IEnumerable<UserRoleDto>> GetAllAsync(CancellationToken token = default)
int take = 32, CancellationToken token = default)
{ {
var rolesDtos = await base.GetPageAsync(skip, take, token); var entities = await cacheUserRoles.WhereAsync(token)
return rolesDtos; .ConfigureAwait(false);
var dtos = entities.Adapt<UserRoleDto>();
return dtos;
} }
public override async Task<UserRoleDto> GetAsync(int id, CancellationToken token = default) public async Task<UserRoleDto> GetAsync(int id, CancellationToken token = default)
{ {
var roleDto = await base.GetAsync(id,token); var entity = await cacheUserRoles.FirstOrDefaultAsync(r=>r.Id == id, token)
.ConfigureAwait(false);
return roleDto; var dto = entity?.Adapt<UserRoleDto>();
return dto;
} }
public override async Task<int> InsertAsync(UserRoleDto dto, CancellationToken token = default) public async Task<int> InsertAsync(UserRoleDto dto, CancellationToken token = default)
{ {
var id = await base.InsertAsync(dto, token).ConfigureAwait(false); var entity = dto.Adapt<UserRole>();
if (dto.Permissions is not null && dto.Permissions.Any()) var updatedEntity = await cacheUserRoles.InsertAsync(entity, token).ConfigureAwait(false);
if (dto.Permissions?.Any() == true)
{
foreach (var permission in dto.Permissions)
permission.IdUserRole = updatedEntity.Id;
await permissionService.InsertRangeAsync(dto.Permissions, token).ConfigureAwait(false);
await cacheUserRoles.RefreshAsync(true, token)
.ConfigureAwait(false);
}
return updatedEntity?.Id ?? 0;
}
public async Task<int> InsertRangeAsync(IEnumerable<UserRoleDto> dtos, CancellationToken token = default)
{
var entities = dtos.Adapt<UserRole>();
return await cacheUserRoles.InsertAsync(entities, token).ConfigureAwait(false);
}
public async Task<int> UpdateAsync(int id, UserRoleDto dto, CancellationToken token = default)
{
var entity = dto.Adapt<UserRole>();
entity.Id = id;
await cacheUserRoles.UpsertAsync(entity, token)
.ConfigureAwait(false);
if(dto.Permissions is not null)
{
await permissionService.DeleteAllByRoleAsync(id, token)
.ConfigureAwait(false);
if (dto.Permissions.Any())
{ {
foreach (var permission in dto.Permissions) foreach (var permission in dto.Permissions)
permission.IdUserRole = id; permission.IdUserRole = id;
await permissionService.InsertRangeAsync(dto.Permissions, token).ConfigureAwait(false);
await permissionService.InsertRangeAsync(dto.Permissions, token)
.ConfigureAwait(false);
} }
await cacheUserRoles.RefreshAsync(true, token)
.ConfigureAwait(false);
}
return id; return id;
} }
public override async Task<int> UpdateAsync(int id, UserRoleDto item, CancellationToken token = default)
{
foreach (var p in item.Permissions)
p.IdUserRole = item.Id;
var result = await base.UpdateAsync(id, item, token);
return result;
}
private IEnumerable<Permission> GetNestedPermissions(UserRole role, int counter = 10) private IEnumerable<Permission> GetNestedPermissions(UserRole role, int counter = 10)
{ {
List<Permission> permissions = role.Permissions.ToList(); List<Permission> permissions = role.Permissions.ToList();
if (role.IdParent is not null) if (role.IdParent is not null)
{ {
if(counter == 0) if (counter == 0)
{ {
Trace.WriteLine($"User role with id: {role.Id} has more than 10 nested childs"); Trace.WriteLine($"User role with id: {role.Id} has more than 10 nested childs");
return permissions; return permissions;
} }
var parentRole = cacheUserRoles.FirstOrDefault(r => r.Id == role.IdParent); var parentRole = cacheUserRoles.FirstOrDefault(r => r.Id == role.IdParent);
if(parentRole is null) if (parentRole is null)
return permissions; return permissions;
var parentPermissions = GetNestedPermissions(parentRole, counter--); var parentPermissions = GetNestedPermissions(parentRole, counter--);
@ -98,5 +129,11 @@ namespace AsbCloudInfrastructure.Services
} }
} }
} }
public Task<int> DeleteAsync(int id, CancellationToken token = default)
=> cacheUserRoles.RemoveAsync(r => r.Id == id, token);
public Task<int> DeleteAsync(IEnumerable<int> ids, CancellationToken token = default)
=> cacheUserRoles.RemoveAsync(r => ids.Contains(r.Id), token);
} }
} }

View File

@ -71,7 +71,7 @@ namespace AsbCloudWebApi.Controllers
/// <param name="idUserRole"> id роли для удаления разрешения </param> /// <param name="idUserRole"> id роли для удаления разрешения </param>
/// <param name="token"> Токен отмены задачи </param> /// <param name="token"> Токен отмены задачи </param>
/// <returns></returns> /// <returns></returns>
[HttpDelete("{idPermission}/{idRole}")] [HttpDelete("{idPermission}/{idUserRole}")]
[ProducesResponseType(typeof(int), (int)System.Net.HttpStatusCode.OK)] [ProducesResponseType(typeof(int), (int)System.Net.HttpStatusCode.OK)]
public async Task<IActionResult> DeleteAsync(int idUserRole, int idPermission, public async Task<IActionResult> DeleteAsync(int idUserRole, int idPermission,
CancellationToken token = default) CancellationToken token = default)

View File

@ -13,6 +13,5 @@ namespace AsbCloudWebApi.Controllers
public AdminPermissionInfoController(ICrudService<PermissionInfoDto> permissionInfoService) public AdminPermissionInfoController(ICrudService<PermissionInfoDto> permissionInfoService)
:base(permissionInfoService) :base(permissionInfoService)
{} {}
} }
} }

View File

@ -10,8 +10,9 @@ namespace AsbCloudWebApi.Controllers
[Authorize] [Authorize]
public class AdminUserRoleController : CrudController<UserRoleDto, ICrudService<UserRoleDto>> public class AdminUserRoleController : CrudController<UserRoleDto, ICrudService<UserRoleDto>>
{ {
public AdminUserRoleController(ICrudService<UserRoleDto> service) public AdminUserRoleController(IUserRoleService service)
: base(service) :base(service)
{ } {
}
} }
} }

View File

@ -30,24 +30,6 @@ namespace AsbCloudWebApi.Controllers
this.service = service; this.service = service;
} }
/// <summary>
/// Получить страницу с записями в PaginationContainer
/// </summary>
/// <param name="skip">пропустить skip записей</param>
/// <param name="take">получить take записей</param>
/// <param name="token">CancellationToken</param>
/// <returns>страница с записями в PaginationContainer</returns>
[HttpGet()]
public virtual async Task<ActionResult<PaginationContainer<T>>> GetPage(int skip = 0, int take = 32,
CancellationToken token = default)
{
if (!Roles.Any(role => User.IsInRole(role)))
return Forbid();
var result = await service.GetPageAsync(skip, take, token).ConfigureAwait(false);
return Ok(result);
}
/// <summary> /// <summary>
/// Получить все записи /// Получить все записи
/// </summary> /// </summary>
@ -111,6 +93,8 @@ namespace AsbCloudWebApi.Controllers
return Forbid(); return Forbid();
var result = await service.UpdateAsync(id, value, token).ConfigureAwait(false); var result = await service.UpdateAsync(id, value, token).ConfigureAwait(false);
if (result == 0)
return BadRequest($"id:{id} does not exist in the db");
return Ok(result); return Ok(result);
} }
@ -131,4 +115,6 @@ namespace AsbCloudWebApi.Controllers
return Ok(result); return Ok(result);
} }
} }
} }