diff --git a/Persistence.API/Controllers/ChangeLogController.cs b/Persistence.API/Controllers/ChangeLogController.cs index dd92e04..9ce80b0 100644 --- a/Persistence.API/Controllers/ChangeLogController.cs +++ b/Persistence.API/Controllers/ChangeLogController.cs @@ -1,6 +1,5 @@ using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; -using Persistence.Database.Model; using Persistence.Models; using Persistence.Repositories; @@ -20,8 +19,8 @@ public class ChangeLogController : ControllerBase, IChangeLogApi [HttpPost] public async Task> Add( - [FromRoute] Guid idDiscriminator, - ChangeLogDto dto, + Guid idDiscriminator, + [FromBody] DataWithWellDepthAndSectionDto dto, CancellationToken token) { var userId = User.GetUserId(); @@ -31,50 +30,88 @@ public class ChangeLogController : ControllerBase, IChangeLogApi } [HttpPost("range")] - public Task> AddRange(IEnumerable> dtos, CancellationToken token) + public async Task> AddRange( + Guid idDiscriminator, + [FromBody] IEnumerable dtos, CancellationToken token) { - throw new NotImplementedException(); + var userId = User.GetUserId(); + var result = await repository.InsertRange(userId, idDiscriminator, dtos, token); + + return Ok(result); } [HttpDelete] - public Task> Delete(int id, CancellationToken token) + public async Task> Delete(Guid id, CancellationToken token) { - throw new NotImplementedException(); + var userId = User.GetUserId(); + var result = await repository.MarkAsDeleted(userId, [id], token); + + return Ok(result); } [HttpDelete("range")] - public Task> DeleteRange(IEnumerable ids, CancellationToken token) + public async Task> DeleteRange(IEnumerable ids, CancellationToken token) { - throw new NotImplementedException(); + var userId = User.GetUserId(); + var result = await repository.MarkAsDeleted(userId, ids, token); + + return Ok(result); } [HttpGet] - public Task>>> GetChangeLogCurrent(CancellationToken token) + public async Task>> GetCurrent( + Guid idDiscriminator, + CancellationToken token) { - throw new NotImplementedException(); + var date = new DateTimeOffset(3000, 1, 1, 0, 0, 0, TimeSpan.Zero); + var result = await repository.GetByDate(idDiscriminator, date, token); + + return Ok(result); + } + + [HttpGet("moment")] + public async Task>> GetByDate( + Guid idDiscriminator, + DateTimeOffset moment, + CancellationToken token) + { + var result = await repository.GetByDate(idDiscriminator, moment, token); + + return Ok(result); } [HttpGet("history")] - public Task>> GetChangeLogForDate(DateTimeOffset historyMoment, CancellationToken token) + public async Task>> GetChangeLogForDate(Guid idDiscriminator, DateTimeOffset dateBegin, DateTimeOffset dateEnd, CancellationToken token) { - throw new NotImplementedException(); + var result = await repository.GetChangeLogForDate(idDiscriminator, dateBegin, dateEnd, token); + + return Ok(result); } - //[HttpGet("history")] - //public Task>>>> GetChangeLogForDate(DateTimeOffset historyMoment, CancellationToken token) - //{ - // throw new NotImplementedException(); - //} [HttpPut] - public Task> Update(IDictionary dto, CancellationToken token) + public async Task> Update( + Guid idDiscriminator, + DataWithWellDepthAndSectionDto dto, + CancellationToken token) { - throw new NotImplementedException(); + var userId = User.GetUserId(); + var result = await repository.UpdateRange(userId, idDiscriminator, [dto], token); + + return Ok(result); } [HttpPut("range")] - public Task> UpdateRange(IEnumerable> dtos, CancellationToken token) + public async Task> UpdateRange( + Guid idDiscriminator, + IEnumerable dtos, + CancellationToken token) { - throw new NotImplementedException(); + var userId = User.GetUserId(); + var result = await repository.UpdateRange(userId, idDiscriminator, dtos, token); + + return Ok(result); } + + } diff --git a/Persistence.API/DependencyInjection.cs b/Persistence.API/DependencyInjection.cs index cdfca4c..81713e4 100644 --- a/Persistence.API/DependencyInjection.cs +++ b/Persistence.API/DependencyInjection.cs @@ -59,7 +59,7 @@ public static class DependencyInjection private static void AddKeyCloakAuthentication(this IServiceCollection services, IConfiguration configuration) { - services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme) + services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme) .AddJwtBearer(options => { options.RequireHttpsMetadata = false; @@ -69,7 +69,7 @@ public static class DependencyInjection { ValidIssuer = configuration["Authentication:ValidIssuer"], }; - }); + }); } private static void AddDefaultAuthentication(this IServiceCollection services, IConfiguration configuration) diff --git a/Persistence.API/Persistence.API.csproj b/Persistence.API/Persistence.API.csproj index 2b8cb73..c14b509 100644 --- a/Persistence.API/Persistence.API.csproj +++ b/Persistence.API/Persistence.API.csproj @@ -8,7 +8,8 @@ - + + diff --git a/Persistence.API/Startup.cs b/Persistence.API/Startup.cs index e074845..57365fa 100644 --- a/Persistence.API/Startup.cs +++ b/Persistence.API/Startup.cs @@ -22,6 +22,7 @@ public class Startup services.AddSwagger(Configuration); services.AddInfrastructure(); services.AddPersistenceDbContext(Configuration); + services.AddAuthorization(); services.AddJWTAuthentication(Configuration); } @@ -38,6 +39,9 @@ public class Startup app.UseDeveloperExceptionPage(); } + + app.UseHttpsRedirection(); + app.UseAuthentication(); app.UseAuthorization(); diff --git a/Persistence.Repository/Repositories/ChangeLogRepository.cs b/Persistence.Repository/Repositories/ChangeLogRepository.cs index f659697..361a9df 100644 --- a/Persistence.Repository/Repositories/ChangeLogRepository.cs +++ b/Persistence.Repository/Repositories/ChangeLogRepository.cs @@ -14,24 +14,91 @@ public class ChangeLogRepository : IChangeLogRepository this.db = db; } - public Task Clear(int idUser, CancellationToken token) + public async Task Clear(Guid idUser, Guid idDiscriminator, CancellationToken token) { - throw new NotImplementedException(); + var updateTime = DateTimeOffset.UtcNow; + + var dbSet = db.Set(); + var query = dbSet + .Where(s => s.IdDiscriminator == idDiscriminator) + .Where(e => e.Obsolete == null); + + var entitiesToDelete = await query.ToArrayAsync(token); + + foreach (var entity in entitiesToDelete) + { + entity.Obsolete = updateTime; + entity.IdEditor = idUser; + } + + return await db.SaveChangesAsync(token); } - public Task ClearAndInsertRange(int idUser, IEnumerable> dtos, CancellationToken token) + public async Task ClearAndInsertRange(Guid idUser, Guid idDiscriminator, IEnumerable dtos, CancellationToken token) { - throw new NotImplementedException(); + var result = 0; + using var transaction = await db.Database.BeginTransactionAsync(token); + try + { + result += await Clear(idUser, idDiscriminator, token); + result += await InsertRange(idUser, idDiscriminator, dtos, token); + + await transaction.CommitAsync(token); + return result; + } + catch + { + await transaction.RollbackAsync(token); + throw; + } } - public Task> GetChangeLogForDate(DateTimeOffset? updateFrom, CancellationToken token) + public async Task> GetChangeLogForDate(Guid idDiscriminator, DateTimeOffset dateBegin, DateTimeOffset dateEnd, CancellationToken token) { - throw new NotImplementedException(); + var dbSet = db.Set(); + var query = dbSet.Where(s => s.IdDiscriminator == idDiscriminator); + + var min = dateBegin; + var max = dateEnd; + + var createdQuery = query.Where(e => e.Creation >= min && e.Creation <= max); + var editedQuery = query.Where(e => e.Obsolete != null && e.Obsolete >= min && e.Obsolete <= max); + + query = createdQuery.Union(editedQuery); + var entities = await query.ToListAsync(token); + + var dtos = entities.Select(e => new ChangeLogDto + { + Creation = e.Creation, + IdAuthor = e.IdAuthor, + IdEditor = e.IdEditor, + IdNext = e.IdNext, + Obsolete = e.Obsolete, + Value = new DataWithWellDepthAndSectionDto() + { + Value = e.Value, + IdSection = e.IdSection, + Id = e.Id, + DepthEnd = e.DepthEnd, + DepthStart = e.DepthStart + } + }); + + return dtos; } - public Task>> GetCurrent(DateTimeOffset moment, CancellationToken token) + public async Task> GetByDate(Guid idDiscriminator, DateTimeOffset momentUtc, CancellationToken token) { - throw new NotImplementedException(); + var dbSet = db.Set(); + var dbQuery = dbSet + .Where(s => s.IdDiscriminator == idDiscriminator) + .Where(e => e.Creation <= momentUtc) + .Where(e => e.Obsolete == null || e.Obsolete >= momentUtc); + + var entities = await dbQuery.ToArrayAsync(token); + var dtos = entities.Select(e => e.Adapt()); + + return dtos; } public Task> GetDatesChange(CancellationToken token) @@ -44,36 +111,54 @@ public class ChangeLogRepository : IChangeLogRepository throw new NotImplementedException(); } - public Task InsertRange(Guid idUser, Guid idDiscriminator, IEnumerable dtos, CancellationToken token) + public Task InsertRange(Guid idUser, Guid idDiscriminator, IEnumerable dtos, CancellationToken token) { - var entities = new List(); foreach (var dto in dtos) { - var entity = new ChangeLog() - { - IdAuthor = idUser, - IdDiscriminator = idDiscriminator, - IdEditor = idUser, - Value = dto.Value, - Creation = DateTimeOffset.UtcNow, - IdSection = dto.IdSection, - DepthStart = dto.DepthStart, - DepthEnd = dto.DepthEnd, - }; - entity.Id = idUser; - - entities.Add(entity); + var entity = CreateEntityFromDto(idUser, idDiscriminator, dto); + db.Set().Add(entity); } - db.Set().AddRange(entities); var result = db.SaveChangesAsync(token); return result; } - public Task MarkAsDeleted(int idUser, IEnumerable ids, CancellationToken token) + private ChangeLog CreateEntityFromDto(Guid idUser, Guid idDiscriminator, DataWithWellDepthAndSectionDto dto) { - throw new NotImplementedException(); + var entity = new ChangeLog() + { + Id = default, + Creation = DateTimeOffset.UtcNow, + IdAuthor = idUser, + IdDiscriminator = idDiscriminator, + IdEditor = idUser, + + Value = dto.Value, + IdSection = dto.IdSection, + DepthStart = dto.DepthStart, + DepthEnd = dto.DepthEnd, + }; + + return entity; + } + + public async Task MarkAsDeleted(Guid idUser, IEnumerable ids, CancellationToken token) + { + var result = 0; + var dbSet = db.Set(); + + var updatedEntity = dbSet + .Where(s => ids.Contains(s.Id)) + .FirstOrDefault(); + if (updatedEntity != null) + { + updatedEntity.Obsolete = DateTimeOffset.UtcNow; + + result = await db.SaveChangesAsync(token); + } + + return result; } public Task UpdateOrInsertRange(int idUser, IEnumerable> dtos, CancellationToken token) @@ -81,8 +166,29 @@ public class ChangeLogRepository : IChangeLogRepository throw new NotImplementedException(); } - public Task UpdateRange(int idUser, IEnumerable> dtos, CancellationToken token) + public async Task UpdateRange(Guid idUser, Guid idDiscriminator, IEnumerable dtos, CancellationToken token) { - throw new NotImplementedException(); + var dbSet = db.Set(); + + var updatedIds = dtos.Select(d => d.Id); + var updatedEntities = dbSet + .Where(s => updatedIds.Contains(s.Id)) + .ToDictionary(s => s.Id); + //todo + foreach (var dto in dtos) + { + var newEntity = CreateEntityFromDto(idUser, idDiscriminator, dto); + dbSet.Add(newEntity); + + var updatedEntity = updatedEntities.GetValueOrDefault(dto.Id)!; + updatedEntity.IdNext = newEntity.Id; + updatedEntity.Obsolete = DateTimeOffset.UtcNow; + updatedEntity.IdEditor = idUser; + + } + + var result = await db.SaveChangesAsync(token); + + return result; } } diff --git a/Persistence/API/IChangeLogApi.cs b/Persistence/API/IChangeLogApi.cs index 4752fb7..5419e2d 100644 --- a/Persistence/API/IChangeLogApi.cs +++ b/Persistence/API/IChangeLogApi.cs @@ -9,51 +9,67 @@ namespace Persistence.API; public interface IChangeLogApi { /// - /// Получение исторических данных на текущую дату + /// Получение данных на текущую дату /// + /// /// /// - Task>>> GetChangeLogCurrent(CancellationToken token); + Task>> GetCurrent(Guid idDiscriminator, CancellationToken token); /// - /// Получение исторических данных на определенную дату + /// Получение данных на определенную дату /// - /// + /// + /// /// /// - Task>> GetChangeLogForDate(DateTimeOffset historyMoment, CancellationToken token); + Task>> GetByDate(Guid idDiscriminator, DateTimeOffset moment, CancellationToken token); + + /// + /// Получение исторических данных за определенный период времени + /// + /// + /// + /// + /// + /// + Task>> GetChangeLogForDate(Guid idDiscriminator, DateTimeOffset dateBegin, DateTimeOffset dateEnd, CancellationToken token); /// /// Добавить одну запись /// + /// /// /// /// - Task> Add(Guid idDiscriminator, ChangeLogDto dto, CancellationToken token); + Task> Add(Guid idDiscriminator, DataWithWellDepthAndSectionDto dto, CancellationToken token); /// /// Добавить несколько записей /// + /// /// /// /// - Task> AddRange(IEnumerable> dtos, CancellationToken token); + Task> AddRange(Guid idDiscriminator, IEnumerable dtos, CancellationToken token); /// /// Обновить одну запись /// + /// /// /// /// - Task> Update(IDictionary dto, CancellationToken token); + Task> Update(Guid idDiscriminator, DataWithWellDepthAndSectionDto dto, CancellationToken token); /// /// Обновить несколько записей /// + /// /// /// /// - Task> UpdateRange(IEnumerable> dtos, CancellationToken token); + Task> UpdateRange(Guid idDiscriminator, IEnumerable dtos, CancellationToken token); /// /// Удалить одну запись @@ -61,7 +77,7 @@ public interface IChangeLogApi /// /// /// - Task> Delete(int id, CancellationToken token); + Task> Delete(Guid id, CancellationToken token); /// /// Удалить несколько записей @@ -69,5 +85,5 @@ public interface IChangeLogApi /// /// /// - Task> DeleteRange(IEnumerable ids, CancellationToken token); + Task> DeleteRange(IEnumerable ids, CancellationToken token); } diff --git a/Persistence/Models/ChangeLogDto.cs b/Persistence/Models/ChangeLogDto.cs index 14cbccc..aa8963f 100644 --- a/Persistence/Models/ChangeLogDto.cs +++ b/Persistence/Models/ChangeLogDto.cs @@ -10,11 +10,6 @@ public class ChangeLogDto } - /// - /// - /// - public Guid Id { get; set; } - /// /// Создатель записи /// @@ -40,23 +35,8 @@ public class ChangeLogDto /// public Guid? IdNext { get; set; } - /// - /// Глубина забоя на дату начала интервала - /// - public double DepthStart { get; set; } - - /// - /// Глубина забоя на дату окончания интервала - /// - public double DepthEnd { get; set; } - - /// - /// Ключ секции - /// - public Guid IdSection { get; set; } - /// /// Объект записи /// - public required IDictionary Value { get; set; } + public DataWithWellDepthAndSectionDto Value { get; set; } } diff --git a/Persistence/Models/DataWithWellDepthAndSectionDto.cs b/Persistence/Models/DataWithWellDepthAndSectionDto.cs new file mode 100644 index 0000000..b3747c2 --- /dev/null +++ b/Persistence/Models/DataWithWellDepthAndSectionDto.cs @@ -0,0 +1,43 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Persistence.Models; + +/// +/// Dto для хранения записей, содержащих начальную и конечную глубину забоя, а также секцию +/// +public class DataWithWellDepthAndSectionDto +{ + public DataWithWellDepthAndSectionDto() + { + + } + + /// + /// Ключ записи + /// + public Guid Id { get; set; } + + /// + /// Глубина забоя на дату начала интервала + /// + public double DepthStart { get; set; } + + /// + /// Глубина забоя на дату окончания интервала + /// + public double DepthEnd { get; set; } + + /// + /// Ключ секции + /// + public Guid IdSection { get; set; } + + /// + /// Объект записи + /// + public required IDictionary Value { get; set; } = default!; +} diff --git a/Persistence/Repositories/IChangeLogRepository.cs b/Persistence/Repositories/IChangeLogRepository.cs index 38b5dd2..ab4f4a9 100644 --- a/Persistence/Repositories/IChangeLogRepository.cs +++ b/Persistence/Repositories/IChangeLogRepository.cs @@ -16,16 +16,17 @@ public interface IChangeLogRepository //: ISyncRepository /// /// /// - Task InsertRange(Guid idUser, Guid idDiscriminator, IEnumerable dtos, CancellationToken token); + Task InsertRange(Guid idUser, Guid idDiscriminator, IEnumerable dtos, CancellationToken token); /// /// Редактирование записей /// /// пользователь, который редактирует + /// /// /// /// - Task UpdateRange(int idUser, IEnumerable> dtos, CancellationToken token); + Task UpdateRange(Guid idUser, Guid idDiscriminator, IEnumerable dtos, CancellationToken token); /// /// Добавляет Dto у которых id == 0, изменяет dto у которых id != 0 @@ -39,19 +40,20 @@ public interface IChangeLogRepository //: ISyncRepository /// /// Помечает записи как удаленные /// - /// пользователь, который чистит + /// /// /// - Task Clear(int idUser, CancellationToken token); + Task Clear(Guid idUser, Guid idDiscriminator, CancellationToken token); /// /// Очистить и добавить новые /// /// + /// /// /// /// - Task ClearAndInsertRange(int idUser, IEnumerable> dtos, CancellationToken token); + Task ClearAndInsertRange(Guid idUser, Guid idDiscriminator, IEnumerable dtos, CancellationToken token); /// /// Пометить записи как удаленные @@ -60,7 +62,7 @@ public interface IChangeLogRepository //: ISyncRepository /// /// /// - Task MarkAsDeleted(int idUser, IEnumerable ids, CancellationToken token); + Task MarkAsDeleted(Guid idUser, IEnumerable ids, CancellationToken token); /// /// Получение дат изменений записей @@ -71,18 +73,21 @@ public interface IChangeLogRepository //: ISyncRepository Task> GetDatesChange(CancellationToken token); /// - /// Получение измененных записей за определенную дату + /// Получение измененных записей за период времени /// - /// + /// + /// + /// /// /// - Task> GetChangeLogForDate(DateTimeOffset? updateFrom, CancellationToken token); + Task> GetChangeLogForDate(Guid idDiscriminator, DateTimeOffset dateBegin, DateTimeOffset dateEnd, CancellationToken token); /// - /// Получение текущих сейчас записей по параметрам + /// Получение актуальных записей на определенный момент времени /// - /// + /// + /// текущий момент времени /// /// - Task>> GetCurrent(DateTimeOffset moment, CancellationToken token); + Task> GetByDate(Guid idDiscriminator, DateTimeOffset moment, CancellationToken token); }