merge dev to 8879776

This commit is contained in:
ngfrolov 2023-02-17 09:33:00 +05:00
commit b8caa7451d
Signed by: ng.frolov
GPG Key ID: E99907A0357B29A7
6 changed files with 179 additions and 91 deletions

View File

@ -361,6 +361,6 @@ namespace AsbCloudDb.Model
{ {
var sql = $"REFRESH MATERIALIZED VIEW {materializedViewName};"; var sql = $"REFRESH MATERIALIZED VIEW {materializedViewName};";
return Database.ExecuteSqlRawAsync(sql, token); return Database.ExecuteSqlRawAsync(sql, token);
} }
} }
} }

View File

@ -67,9 +67,7 @@ namespace AsbCloudDb.Model
Task<int> RefreshMaterializedViewAsync<TEntity>(CancellationToken token) where TEntity : class; Task<int> RefreshMaterializedViewAsync<TEntity>(CancellationToken token) where TEntity : class;
int SaveChanges(); int SaveChanges();
int SaveChanges(bool acceptAllChangesOnSuccess); int SaveChanges(bool acceptAllChangesOnSuccess);
Task<int> SaveChangesAsync(CancellationToken cancellationToken); Task<int> SaveChangesAsync(CancellationToken cancellationToken);
DbSet<TEntity> Set<TEntity>(string name) where TEntity : class; DbSet<TEntity> Set<TEntity>() where TEntity : class;
DbSet<TEntity> Set<TEntity>() where TEntity : class;
} }
} }

View File

@ -1,9 +1,7 @@
using AsbCloudApp.Data; using AsbCloudApp.Data;
using AsbCloudApp.Exceptions; using AsbCloudApp.Exceptions;
using AsbCloudApp.Repositories; using AsbCloudApp.Repositories;
using AsbCloudDb;
using AsbCloudDb.Model; using AsbCloudDb.Model;
using AsbCloudInfrastructure.EfCache;
using Mapster; using Mapster;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using System; using System;
@ -11,6 +9,7 @@ using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.Extensions.Caching.Memory;
namespace AsbCloudInfrastructure.Repository namespace AsbCloudInfrastructure.Repository
{ {
@ -29,10 +28,12 @@ namespace AsbCloudInfrastructure.Repository
dst => dst.Files, dst => dst.Files,
dst => dst.RelationUsersUserRoles) dst => dst.RelationUsersUserRoles)
.Config; .Config;
private readonly IMemoryCache memoryCache;
public UserRepository(IAsbCloudDbContext dbContext, IUserRoleRepository userRoleRepository) { public UserRepository(IAsbCloudDbContext dbContext, IUserRoleRepository userRoleRepository, IMemoryCache memoryCache)
{
this.dbContext = dbContext; this.dbContext = dbContext;
this.userRoleRepository = userRoleRepository; this.userRoleRepository = userRoleRepository;
this.memoryCache = memoryCache;
} }
public async Task<int> InsertAsync(UserExtendedDto dto, CancellationToken token) public async Task<int> InsertAsync(UserExtendedDto dto, CancellationToken token)
@ -58,31 +59,36 @@ namespace AsbCloudInfrastructure.Repository
public async Task<IEnumerable<UserExtendedDto>> GetAllAsync(CancellationToken token) public async Task<IEnumerable<UserExtendedDto>> GetAllAsync(CancellationToken token)
{ {
var dtos = (await GetCacheUserAsync(token)).ToList(); var users = await GetCacheUserAsync(token);
if (dtos is null) if (users is null)
return Enumerable.Empty<UserExtendedDto>(); return Enumerable.Empty<UserExtendedDto>();
var dtos = new List<UserExtendedDto>();
for (var i = 0; i < dtos.Count; i++) foreach(var user in users)
dtos[i].RoleNames = GetRolesNamesByIdUser(dtos[i].Id); {
var dto = Convert(user);
dto.RoleNames = GetRolesNamesByIdUser(user.Id);
dtos.Add(dto);
};
return dtos; return dtos;
} }
public UserExtendedDto? GetOrDefault(int id) public UserExtendedDto? GetOrDefault(int id)
{ {
var dto = GetCacheUser().FirstOrDefault(u => u.Id == id); var user = GetCacheUser().FirstOrDefault(u => u.Id == id);
if (dto is null) if (user is null)
return null; return null;
var entity = Convert(dto); var dto = Convert(user);
dto.RoleNames = GetRolesNamesByIdUser(dto.Id); dto.RoleNames = GetRolesNamesByIdUser(dto.Id);
return dto; return dto;
} }
public async Task<UserExtendedDto?> GetOrDefaultAsync(int id, CancellationToken token) public async Task<UserExtendedDto?> GetOrDefaultAsync(int id, CancellationToken token)
{ {
var dto = (await GetCacheUserAsync(token)).FirstOrDefault(u => u.Id == id); var user = (await GetCacheUserAsync(token)).FirstOrDefault(u => u.Id == id);
if (dto is null) if (user is null)
return null; return null;
var dto = Convert(user);
dto.RoleNames = GetRolesNamesByIdUser(dto.Id); dto.RoleNames = GetRolesNamesByIdUser(dto.Id);
return dto; return dto;
} }
@ -90,11 +96,13 @@ namespace AsbCloudInfrastructure.Repository
public async Task<int> UpdateAsync(UserExtendedDto dto, CancellationToken token) public async Task<int> UpdateAsync(UserExtendedDto dto, CancellationToken token)
{ {
if (dto.Id <= 1) if (dto.Id <= 1)
throw new ArgumentInvalidException($"Invalid id {dto.Id}. You can't edit this user.", nameof(dto)); throw new ArgumentInvalidException
($"Invalid id {dto.Id}. You can't edit this user.", nameof(dto));
var oldUser = (await GetCacheUserAsync(token)).FirstOrDefault(u => u.Id == dto.Id); var oldUser = (await GetCacheUserAsync(token)).FirstOrDefault(u => u.Id == dto.Id);
if (oldUser is null) if (oldUser is null)
return 0; throw new ArgumentInvalidException
($"Invalid id {dto.Id}. You can't edit this user.", nameof(dto));
if (oldUser.Login != dto.Login) if (oldUser.Login != dto.Login)
await AssertLoginIsBusyAsync(dto.Login, token); await AssertLoginIsBusyAsync(dto.Login, token);
@ -102,25 +110,43 @@ namespace AsbCloudInfrastructure.Repository
var userRoles = await userRoleRepository.GetByNamesAsync(dto.RoleNames, token).ConfigureAwait(false); var userRoles = await userRoleRepository.GetByNamesAsync(dto.RoleNames, token).ConfigureAwait(false);
await UpdateRolesCacheForUserAsync(dto.Id, userRoles, token); await UpdateRolesCacheForUserAsync(dto.Id, userRoles, token);
var entity = Convert(dto); var entity = dbContext.Users.FirstOrDefault(u => u.Id == dto.Id);
if (entity is null)
var result = dbContext.Users.Upsert(entity); throw new ArgumentInvalidException
($"Invalid id {dto.Id}. You can't edit this user.", nameof(dto));
entity.Id = dto.Id;
entity.Login = dto.Login;
entity.Name = dto.Name;
entity.Email = dto.Email;
entity.Phone = dto.Phone;
entity.Surname = dto.Surname;
entity.Patronymic = dto.Patronymic;
entity.Position = dto.Position;
entity.IdCompany = dto.IdCompany;
entity.IdState = dto.IdState;
await dbContext.SaveChangesAsync(token); await dbContext.SaveChangesAsync(token);
DropCacheUsers(); DropCacheUsers();
return result.Entity.Id; return entity.Id;
} }
public async Task<int> DeleteAsync(int id, CancellationToken token) public async Task<int> DeleteAsync(int id, CancellationToken token)
{ {
var dto = (await GetCacheUserAsync(token)).FirstOrDefault(u => u.Id == id); var user = (await GetCacheUserAsync(token)).FirstOrDefault(u => u.Id == id);
if (dto is null) if (user is null)
return 0; throw new ArgumentInvalidException
($"Invalid id {id}. You can't edit this user.", nameof(id));
var entity = Convert(dto); var query = dbContext
var result = dbContext.Users.Remove(entity); .Users
await dbContext.SaveChangesAsync(token); .Where(u => u.Id == id);
DropCacheUsers(); if (query.Any())
return result.Entity.Id; {
var result = dbContext.Users.Remove(query.First());
await dbContext.SaveChangesAsync(token);
DropCacheUsers();
return result.Entity.Id;
}
throw new ArgumentInvalidException
($"Invalid id {id}. You can't edit this user.", nameof(id));
} }
public IEnumerable<UserRoleDto> GetRolesByIdUser(int idUser, int nestedLevel = 0) public IEnumerable<UserRoleDto> GetRolesByIdUser(int idUser, int nestedLevel = 0)
@ -156,9 +182,14 @@ namespace AsbCloudInfrastructure.Repository
} }
private IEnumerable<string> GetRolesNamesByIdUser(int idUser) private IEnumerable<string> GetRolesNamesByIdUser(int idUser)
=> GetRolesByIdUser(idUser, 7) {
.Select(r => r.Caption) var userRoles = GetRolesByIdUser(idUser, 7)
.Distinct(); .Select(r => r.Caption)
.Distinct();
if (userRoles.Any())
return userRoles;
return Enumerable.Empty<string>();
}
private async Task AssertLoginIsBusyAsync(string login, CancellationToken token) private async Task AssertLoginIsBusyAsync(string login, CancellationToken token)
{ {
@ -167,63 +198,87 @@ namespace AsbCloudInfrastructure.Repository
if (existingUserDto is not null) if (existingUserDto is not null)
throw new ArgumentInvalidException($"Login {login} is busy by {existingUserDto.MakeDisplayName()}, id{existingUserDto.Id}", nameof(login)); throw new ArgumentInvalidException($"Login {login} is busy by {existingUserDto.MakeDisplayName()}, id{existingUserDto.Id}", nameof(login));
}
private IEnumerable<RelationUserUserRole> GetCachRelationUserUserRoleCacheTag()
{
var cache = memoryCache.GetOrCreate(relationUserUserRoleCacheTag, cacheEntry =>
{
cacheEntry.AbsoluteExpirationRelativeToNow = cacheObsolence;
cacheEntry.SlidingExpiration = cacheObsolence;
var query = dbContext.RelationUserUserRoles
.Include(r => r.UserRole)
.Include(r => r.User);
var entities = query.ToArray();
return entities;
});
return cache!;
}
private void DropCacheRelationUserUserRoleCacheTag()
{
memoryCache.Remove(relationUserUserRoleCacheTag);
} }
private Task<IEnumerable<UserExtendedDto>> GetCacheUserAsync(CancellationToken token) private async Task UpdateRolesCacheForUserAsync(int idUser, IEnumerable<UserRoleDto> roleDtos, CancellationToken token)
=> dbContext.Users
.Include(r => r.Company)
.Include(r => r.RelationUsersUserRoles)
.FromCacheAsync(userCacheTag, cacheObsolence, Convert, token);
private IEnumerable<UserExtendedDto> GetCacheUser()
=> dbContext.Users
.Include(r => r.Company)
.Include(r => r.RelationUsersUserRoles)
.FromCache(userCacheTag, cacheObsolence, Convert);
private void DropCacheUsers()
=> dbContext.Users.DropCache(userCacheTag);
private Task<IEnumerable<RelationUserUserRole>> GetCacheRelationUserUserRoleAsync(CancellationToken token)
=> dbContext.RelationUserUserRoles
.Include(r => r.UserRole)
.Include(r => r.User)
.FromCacheAsync(relationUserUserRoleCacheTag, cacheObsolence, token);
private IEnumerable<RelationUserUserRole> GetCachRelationUserUserRoleCacheTag()
=> dbContext.RelationUserUserRoles
.Include(r => r.UserRole)
.Include(r => r.User)
.FromCache(relationUserUserRoleCacheTag, cacheObsolence);
private void DropCacheRelationUserUserRoleCacheTag()
=> dbContext.RelationUserUserRoles.DropCache(relationUserUserRoleCacheTag);
private async Task UpdateRolesCacheForUserAsync(int idUser, IEnumerable<UserRoleDto> newRoles, CancellationToken token)
{ {
var relations = (await GetCacheRelationUserUserRoleAsync(token)).Where(r => r.IdUser == idUser); var relations = dbContext.RelationUserUserRoles.Where(r => r.IdUser == idUser);
dbContext.RelationUserUserRoles.RemoveRange(relations); dbContext.RelationUserUserRoles.RemoveRange(relations);
var entityRoles = roleDtos.Select(role => new RelationUserUserRole
if (newRoles?.Any() == true) {
await dbContext.RelationUserUserRoles.AddRangeAsync(newRoles.Select(role => new RelationUserUserRole IdUser = idUser,
{ IdUserRole = role.Id
IdUser = idUser, });
IdUserRole = role.Id dbContext.RelationUserUserRoles.AddRange(entityRoles);
}), token).ConfigureAwait(false);
await dbContext.SaveChangesAsync(token); await dbContext.SaveChangesAsync(token);
DropCacheRelationUserUserRoleCacheTag(); DropCacheRelationUserUserRoleCacheTag();
} }
protected virtual User Convert(UserExtendedDto dto) private void DropCacheUsers()
=> memoryCache.Remove(userCacheTag);
private IEnumerable<User> GetCacheUser()
{
var cache = memoryCache.GetOrCreate(userCacheTag, cacheEntry =>
{
cacheEntry.AbsoluteExpirationRelativeToNow = cacheObsolence;
cacheEntry.SlidingExpiration = cacheObsolence;
var query = dbContext.Users
.Include(r => r.Company)
.Include(r => r.RelationUsersUserRoles);
var entities = query.ToArray();
return entities;
});
return cache!;
}
private Task<IEnumerable<User>> GetCacheUserAsync(CancellationToken token)
{
var cache = memoryCache.GetOrCreateAsync(userCacheTag, async (cacheEntry) =>
{
cacheEntry.AbsoluteExpirationRelativeToNow = cacheObsolence;
cacheEntry.SlidingExpiration = cacheObsolence;
var query = dbContext.Users
.Include(r => r.Company)
.Include(r => r.RelationUsersUserRoles);
var entities = await query.ToArrayAsync(token);
return entities.AsEnumerable();
});
return cache!;
}
protected User Convert(UserExtendedDto dto)
{ {
var entity = dto.Adapt<User>(userTypeAdapterConfig); var entity = dto.Adapt<User>(userTypeAdapterConfig);
if (string.IsNullOrEmpty(entity.PasswordHash)) if (string.IsNullOrEmpty(entity.PasswordHash))
entity.PasswordHash = dbContext.Users.FirstOrDefault(u => u.Id == dto.Id)?.PasswordHash; entity.PasswordHash = dbContext.Users.FirstOrDefault(u => u.Id == dto.Id)?.PasswordHash;
return entity; return entity;
} }
protected virtual UserExtendedDto Convert(User entity) protected virtual UserExtendedDto Convert(User entity)
{ {
var dto = entity.Adapt<UserExtendedDto>(); var dto = entity.Adapt<UserExtendedDto>();
return dto; return dto;
} }
} }
#nullable disable #nullable disable
} }

View File

@ -13,9 +13,9 @@ namespace AsbCloudInfrastructure.Services.ProcessMap
public class ProcessMapReportService : IProcessMapReportService public class ProcessMapReportService : IProcessMapReportService
{ {
const int firstColumn = 2; const int firstColumn = 2;
const int lastColumn = 27; const int lastColumn = 61;
const int headerRowsCount = 3; const int headerRowsCount = 8;
private readonly IProcessMapService processMapService; private readonly IProcessMapService processMapService;
@ -68,7 +68,9 @@ namespace AsbCloudInfrastructure.Services.ProcessMap
sheet.Range(row, firstColumn, row, lastColumn) sheet.Range(row, firstColumn, row, lastColumn)
.Merge() .Merge()
.FirstCell() .FirstCell()
.SetVal(sectionName); .SetVal(sectionName)
.Style
.Fill.SetBackgroundColor(XLColor.LightGray);
row++; row++;
@ -82,14 +84,17 @@ namespace AsbCloudInfrastructure.Services.ProcessMap
private static int FillIntervalData(IXLWorksheet sheet, ProcessMapReportDto interval, int row) private static int FillIntervalData(IXLWorksheet sheet, ProcessMapReportDto interval, int row)
{ {
const int columnDepth = firstColumn; const int columnDepth = firstColumn + 1;
const int columnDate = firstColumn + 1; const int columnDate = firstColumn + 2;
const int columnRopTime = firstColumn + 2; const int columnRopTime = firstColumn + 3;
const int columnMode = firstColumn + 3; const int columnMode = firstColumn + 4;
int rowRotor = row; int rowRotor = row;
int rowSlide = row + 1; int rowSlide = row + 1;
sheet.Range(rowRotor, firstColumn, rowSlide, firstColumn)
.Merge();
sheet.Range(rowRotor, columnDepth, rowSlide, columnDepth) sheet.Range(rowRotor, columnDepth, rowSlide, columnDepth)
.Merge().FirstCell() .Merge().FirstCell()
.SetVal(interval.DepthStart, "0.0"); .SetVal(interval.DepthStart, "0.0");
@ -103,7 +108,7 @@ namespace AsbCloudInfrastructure.Services.ProcessMap
.SetVal(interval.MechDrillingHours); .SetVal(interval.MechDrillingHours);
row = FillIntervalModeData(sheet, "Ротор", interval.Rotor, columnMode, row); row = FillIntervalModeData(sheet, "Ротор", interval.Rotor, columnMode, row);
row = FillIntervalModeData(sheet, "Слайд", interval.Rotor, columnMode, row); row = FillIntervalModeData(sheet, "Слайд", interval.Slide, columnMode, row);
return row; return row;
} }
@ -115,8 +120,9 @@ namespace AsbCloudInfrastructure.Services.ProcessMap
int columnLoad = columnPressure + 5; int columnLoad = columnPressure + 5;
int columnTorque = columnLoad + 5; int columnTorque = columnLoad + 5;
int columnSpeed = columnTorque + 5; int columnSpeed = columnTorque + 5;
int columnUsage = columnSpeed + 4; int columnUsagePlan = columnSpeed + 5;
int columnRop = columnUsage + 1; int columnUsageFact = columnUsagePlan + 1;
int columnRop = columnUsageFact + 12;
sheet.Cell(row, column) sheet.Cell(row, column)
.SetVal(modeName); .SetVal(modeName);
@ -129,7 +135,10 @@ namespace AsbCloudInfrastructure.Services.ProcessMap
FillIntervalModeDataParam(sheet, modeData.TopDriveTorque, columnTorque, row); FillIntervalModeDataParam(sheet, modeData.TopDriveTorque, columnTorque, row);
FillIntervalModeDataSpeed(sheet, modeData.SpeedLimit, columnSpeed, row); FillIntervalModeDataSpeed(sheet, modeData.SpeedLimit, columnSpeed, row);
sheet.Cell(row, columnUsage) sheet.Cell(row, columnUsagePlan)
.SetVal(100);
sheet.Cell(row, columnUsageFact)
.SetVal(modeData.Usage); .SetVal(modeData.Usage);
sheet.Cell(row, columnRop) sheet.Cell(row, columnRop)
@ -167,7 +176,8 @@ namespace AsbCloudInfrastructure.Services.ProcessMap
const int columnOffsetSpPlan = 0; const int columnOffsetSpPlan = 0;
const int columnOffsetSpFact = 1; const int columnOffsetSpFact = 1;
const int columnOffsetFact = 2; const int columnOffsetFact = 2;
const int columnOffsetPercent = 3; const int columnOffsetLimit = 3;
const int columnOffsetPercent = 4;
sheet.Cell(row, column + columnOffsetSpPlan) sheet.Cell(row, column + columnOffsetSpPlan)
.SetVal(dataParam.SetpointPlan); .SetVal(dataParam.SetpointPlan);
@ -178,6 +188,9 @@ namespace AsbCloudInfrastructure.Services.ProcessMap
sheet.Cell(row, column + columnOffsetFact) sheet.Cell(row, column + columnOffsetFact)
.SetVal(dataParam.Fact); .SetVal(dataParam.Fact);
sheet.Cell(row, column + columnOffsetLimit)
.SetVal(dataParam.Limit);
sheet.Cell(row, column + columnOffsetPercent) sheet.Cell(row, column + columnOffsetPercent)
.SetVal(dataParam.PercDrillingSetpoint); .SetVal(dataParam.PercDrillingSetpoint);
} }

View File

@ -22,13 +22,20 @@ namespace AsbCloudWebApi.Controllers
{ {
private readonly ITelemetryService telemetryService; private readonly ITelemetryService telemetryService;
private readonly IProcessMapReportService processMapReportService; private readonly IProcessMapReportService processMapReportService;
private readonly IProcessMapService processMapService;
public ProcessMapController(IWellService wellService, IProcessMapRepository repository, IProcessMapReportService processMapReportService, public ProcessMapController(
IWellService wellService,
IProcessMapRepository repository,
IProcessMapReportService processMapReportService,
IProcessMapService processMapService,
ITelemetryService telemetryService) ITelemetryService telemetryService)
: base(wellService, repository) : base(wellService, repository)
{ {
this.telemetryService = telemetryService; this.telemetryService = telemetryService;
this.processMapReportService = processMapReportService; this.processMapReportService = processMapReportService;
this.processMapService = processMapService;
} }
/// <summary> /// <summary>
@ -104,6 +111,21 @@ namespace AsbCloudWebApi.Controllers
return NoContent(); return NoContent();
} }
/// <summary>
/// Выгрузка режимной карты по бурению скважины
/// </summary>
/// <param name="wellId"></param>
/// <param name="token"></param>
/// <returns></returns>
[HttpGet]
[Route("getDrillProcessMap/{wellId}")]
[ProducesResponseType(typeof(IEnumerable<ProcessMapReportDto>), (int)System.Net.HttpStatusCode.OK)]
public async Task<IActionResult> GetDrillProcessMap(int wellId, CancellationToken token)
{
var data = await processMapService.GetProcessMapAsync(wellId, token);
return Ok(data);
}
/// <summary> /// <summary>
/// Добавить запись /// Добавить запись
/// </summary> /// </summary>