diff --git a/AsbCloudApp/Data/ParserResultDto.cs b/AsbCloudApp/Data/ParserResultDto.cs
new file mode 100644
index 00000000..5b6eca8d
--- /dev/null
+++ b/AsbCloudApp/Data/ParserResultDto.cs
@@ -0,0 +1,12 @@
+using System.Collections.Generic;
+
+namespace AsbCloudApp.Data;
+
+///
+/// Результат парсинга файла
+///
+///
+public class ParserResultDto : ValidationResultDto>>
+ where TDto : class, IId
+{
+}
\ No newline at end of file
diff --git a/AsbCloudApp/Data/Trajectory/TrajectoryGeoDto.cs b/AsbCloudApp/Data/Trajectory/TrajectoryGeoDto.cs
index 47563011..e47a66e8 100644
--- a/AsbCloudApp/Data/Trajectory/TrajectoryGeoDto.cs
+++ b/AsbCloudApp/Data/Trajectory/TrajectoryGeoDto.cs
@@ -5,7 +5,7 @@ namespace AsbCloudApp.Data.Trajectory
///
/// Базовая географическая траектория
///
- public abstract class TrajectoryGeoDto
+ public abstract class TrajectoryGeoDto : IId
{
///
/// ИД строки с координатами
diff --git a/AsbCloudApp/Requests/ParserOptions/IParserOptionsRequest.cs b/AsbCloudApp/Requests/ParserOptions/IParserOptionsRequest.cs
new file mode 100644
index 00000000..b3b12f51
--- /dev/null
+++ b/AsbCloudApp/Requests/ParserOptions/IParserOptionsRequest.cs
@@ -0,0 +1,19 @@
+namespace AsbCloudApp.Requests.ParserOptions;
+
+///
+/// Параметры парсинга
+///
+public interface IParserOptionsRequest
+{
+ private static DummyOptions empty => new();
+
+ private class DummyOptions : IParserOptionsRequest
+ {
+ }
+
+ ///
+ /// Получение пустого объекта опций
+ ///
+ ///
+ public static IParserOptionsRequest Empty() => empty;
+}
\ No newline at end of file
diff --git a/AsbCloudApp/Services/IParserService.cs b/AsbCloudApp/Services/IParserService.cs
new file mode 100644
index 00000000..2cfd8eb7
--- /dev/null
+++ b/AsbCloudApp/Services/IParserService.cs
@@ -0,0 +1,38 @@
+using System.IO;
+using System.Threading;
+using System.Threading.Tasks;
+using AsbCloudApp.Data;
+using AsbCloudApp.Requests.ParserOptions;
+
+namespace AsbCloudApp.Services;
+
+///
+/// Сервис парсинга
+///
+///
+///
+public interface IParserService : IParserService
+ where TDto : class, IId
+ where TOptions : IParserOptionsRequest
+{
+ ///
+ /// Распарсить файл
+ ///
+ ///
+ ///
+ ///
+ ParserResultDto Parse(Stream file, TOptions options);
+
+ ///
+ /// Получение шаблона для заполнения
+ ///
+ ///
+ Stream GetTemplateFile();
+}
+
+///
+/// Сервис парсинга(интерфейс маркер)
+///
+public interface IParserService
+{
+}
\ No newline at end of file
diff --git a/AsbCloudInfrastructure/AssemblyExtensions.cs b/AsbCloudInfrastructure/AssemblyExtensions.cs
index 9594261b..03cf7325 100644
--- a/AsbCloudInfrastructure/AssemblyExtensions.cs
+++ b/AsbCloudInfrastructure/AssemblyExtensions.cs
@@ -1,30 +1,50 @@
using System;
-using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
-using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace AsbCloudInfrastructure
{
- public static class AssemblyExtensions
- {
- public static async Task GetTemplateCopyStreamAsync(this Assembly assembly, string templateName, CancellationToken cancellationToken)
- {
- var resourceName = assembly
- .GetManifestResourceNames()
- .FirstOrDefault(n => n.EndsWith(templateName))!;
+ public static class AssemblyExtensions
+ {
+ public static Stream GetTemplateCopyStream(this Assembly assembly, string templateName)
+ {
+ var resourceName = assembly
+ .GetManifestResourceNames()
+ .FirstOrDefault(n => n.EndsWith(templateName));
- using var stream = Assembly.GetExecutingAssembly()
- .GetManifestResourceStream(resourceName)!;
+ if (string.IsNullOrWhiteSpace(resourceName))
+ throw new ArgumentNullException(nameof(resourceName));
- var memoryStream = new MemoryStream();
- await stream.CopyToAsync(memoryStream, cancellationToken);
- memoryStream.Position = 0;
+ using var stream = Assembly.GetExecutingAssembly()
+ .GetManifestResourceStream(resourceName);
- return memoryStream;
- }
- }
-}
+ var memoryStream = new MemoryStream();
+ stream?.CopyTo(memoryStream);
+ memoryStream.Position = 0;
+
+ return memoryStream;
+ }
+
+ [Obsolete]
+ public static async Task GetTemplateCopyStreamAsync(this Assembly assembly,
+ string templateName,
+ CancellationToken cancellationToken)
+ {
+ var resourceName = assembly
+ .GetManifestResourceNames()
+ .FirstOrDefault(n => n.EndsWith(templateName))!;
+
+ using var stream = Assembly.GetExecutingAssembly()
+ .GetManifestResourceStream(resourceName)!;
+
+ var memoryStream = new MemoryStream();
+ await stream.CopyToAsync(memoryStream, cancellationToken);
+ memoryStream.Position = 0;
+
+ return memoryStream;
+ }
+ }
+}
\ No newline at end of file
diff --git a/AsbCloudInfrastructure/DependencyInjection.cs b/AsbCloudInfrastructure/DependencyInjection.cs
index 913fdfe4..28a051ab 100644
--- a/AsbCloudInfrastructure/DependencyInjection.cs
+++ b/AsbCloudInfrastructure/DependencyInjection.cs
@@ -30,7 +30,6 @@ using AsbCloudInfrastructure.Services.SAUB;
using AsbCloudInfrastructure.Services.Subsystems;
using AsbCloudInfrastructure.Services.Trajectory;
using AsbCloudInfrastructure.Services.Trajectory.Export;
-using AsbCloudInfrastructure.Services.Trajectory.Import;
using AsbCloudInfrastructure.Services.WellOperationImport;
using AsbCloudInfrastructure.Services.WellOperationImport.FileParser;
using AsbCloudInfrastructure.Services.WellOperationService;
@@ -46,6 +45,7 @@ using AsbCloudDb.Model.WellSections;
using AsbCloudInfrastructure.Services.ProcessMaps;
using AsbCloudApp.Data.ProcessMapPlan;
using AsbCloudApp.Requests;
+using AsbCloudInfrastructure.Services.Trajectory.Parser;
namespace AsbCloudInfrastructure
{
@@ -328,6 +328,8 @@ namespace AsbCloudInfrastructure
services.AddTransient, ProcessMapPlanService>();
services.AddTransient();
+
+ services.AddSingleton();
return services;
}
diff --git a/AsbCloudInfrastructure/ParserServiceBase.cs b/AsbCloudInfrastructure/ParserServiceBase.cs
new file mode 100644
index 00000000..d98404e7
--- /dev/null
+++ b/AsbCloudInfrastructure/ParserServiceBase.cs
@@ -0,0 +1,72 @@
+using System;
+using System.Collections.Generic;
+using System.ComponentModel.DataAnnotations;
+using System.IO;
+using System.Linq;
+using AsbCloudApp.Data;
+using AsbCloudApp.Requests.ParserOptions;
+using AsbCloudApp.Services;
+using ClosedXML.Excel;
+
+namespace AsbCloudInfrastructure;
+
+public abstract class ParserServiceBase : IParserService
+ where TDto : class, IId
+ where TOptions : IParserOptionsRequest
+{
+ protected readonly IServiceProvider serviceProvider;
+
+ protected ParserServiceBase(IServiceProvider serviceProvider)
+ {
+ this.serviceProvider = serviceProvider;
+ }
+
+ public abstract ParserResultDto Parse(Stream file, TOptions options);
+ public abstract Stream GetTemplateFile();
+
+ protected virtual ParserResultDto ParseExcelSheet(IXLWorksheet sheet,
+ Func> parseRow,
+ int columnCount,
+ int headerRowsCount = 0)
+ {
+ if (sheet.RangeUsed().RangeAddress.LastAddress.ColumnNumber < columnCount)
+ throw new FileFormatException($"Лист {sheet.Name} содержит меньшее количество столбцов.");
+
+ var count = sheet.RowsUsed().Count() - headerRowsCount;
+
+ if (count > 1024)
+ throw new FileFormatException($"Лист {sheet.Name} содержит слишком большое количество строк.");
+
+ if (count <= 0)
+ return new ParserResultDto();
+
+ var dtos = new List>(count);
+ var warnings = new List();
+
+ for (var i = 0; i < count; i++)
+ {
+ var row = sheet.Row(1 + i + headerRowsCount);
+
+ try
+ {
+ var dto = parseRow.Invoke(row);
+ dtos.Add(dto);
+ }
+ catch (FileFormatException ex)
+ {
+ var warning = new ValidationResult(ex.Message);
+ warnings.Add(warning);
+ }
+ }
+
+ var parserResult = new ParserResultDto
+ {
+ Item = dtos
+ };
+
+ if (warnings.Any())
+ parserResult.Warnings = warnings;
+
+ return parserResult;
+ }
+}
\ No newline at end of file
diff --git a/AsbCloudInfrastructure/Services/ParserServiceFactory.cs b/AsbCloudInfrastructure/Services/ParserServiceFactory.cs
new file mode 100644
index 00000000..5b852a8e
--- /dev/null
+++ b/AsbCloudInfrastructure/Services/ParserServiceFactory.cs
@@ -0,0 +1,36 @@
+using System;
+using System.Collections.Generic;
+using AsbCloudApp.Data;
+using AsbCloudApp.Requests.ParserOptions;
+using AsbCloudApp.Services;
+using AsbCloudInfrastructure.Services.Trajectory.Parser;
+
+namespace AsbCloudInfrastructure.Services;
+
+public class ParserServiceFactory
+{
+ public const int IdTrajectoryFactManualParserService = 1;
+ public const int IdTrajectoryPlanParserService = 2;
+
+ private readonly IDictionary> parsers;
+
+ public ParserServiceFactory(IServiceProvider serviceProvider)
+ {
+ parsers = new Dictionary>
+ {
+ { IdTrajectoryPlanParserService, () => new TrajectoryPlanParserService(serviceProvider) },
+ { IdTrajectoryFactManualParserService, () => new TrajectoryFactManualParserService(serviceProvider) }
+ };
+ }
+
+ public IParserService Create(int idParserService)
+ where TDto : class, IId
+ where TOptions : IParserOptionsRequest
+ {
+ if (!parsers.TryGetValue(idParserService, out var parserService))
+ throw new ArgumentNullException(nameof(idParserService), "Не правильный идентификатор парсера");
+
+ return parserService.Invoke() as IParserService
+ ?? throw new ArgumentNullException(nameof(idParserService), "Ошибка приведения типа");
+ }
+}
\ No newline at end of file
diff --git a/AsbCloudInfrastructure/Services/SAUB/TelemetryDataCache.cs b/AsbCloudInfrastructure/Services/SAUB/TelemetryDataCache.cs
index ec92c00f..74643429 100644
--- a/AsbCloudInfrastructure/Services/SAUB/TelemetryDataCache.cs
+++ b/AsbCloudInfrastructure/Services/SAUB/TelemetryDataCache.cs
@@ -299,7 +299,7 @@ namespace AsbCloudInfrastructure.Services.SAUB
if (request.LeDate.HasValue)
{
var leDate = request.LeDate.Value.ToRemoteDateTime(cacheItem.TimezoneHours);
- data = data.Where(d => d.DateTime >= request.LeDate);
+ data = data.Where(d => d.DateTime <= request.LeDate);
}
if (request.Divider > 1)
diff --git a/AsbCloudInfrastructure/Services/Trajectory/Import/TrajectoryFactManualParserService.cs b/AsbCloudInfrastructure/Services/Trajectory/Import/TrajectoryFactManualParserService.cs
deleted file mode 100644
index be08e12e..00000000
--- a/AsbCloudInfrastructure/Services/Trajectory/Import/TrajectoryFactManualParserService.cs
+++ /dev/null
@@ -1,30 +0,0 @@
-using AsbCloudApp.Data.Trajectory;
-using ClosedXML.Excel;
-
-namespace AsbCloudInfrastructure.Services.Trajectory.Import
-{
-
- public class TrajectoryFactManualParserService : TrajectoryParserService
- {
- public override string templateFileName { get; } = "TrajectoryFactManualTemplate.xlsx";
- public override string usingTemplateFile { get; } = "AsbCloudInfrastructure.Services.Trajectory.Templates";
- public override string sheetName { get; } = "Фактическая траектория";
- public override int headerRowsCount { get; } = 2;
-
- protected override TrajectoryGeoFactDto ParseRow(IXLRow row)
- {
- var trajectoryRow = new TrajectoryGeoFactDto
- {
- WellboreDepth = row.Cell(1).GetCellValue(),
- ZenithAngle = row.Cell(2).GetCellValue(),
- AzimuthGeo = row.Cell(3).GetCellValue(),
- AzimuthMagnetic = row.Cell(4).GetCellValue(),
- VerticalDepth = row.Cell(5).GetCellValue(),
- Comment = row.Cell(6).GetCellValue()
- };
- //TODO: Добавить валидацию модели IValidatableObject
- return trajectoryRow;
- }
- }
-}
-
diff --git a/AsbCloudInfrastructure/Services/Trajectory/Import/TrajectoryParserService.cs b/AsbCloudInfrastructure/Services/Trajectory/Import/TrajectoryParserService.cs
deleted file mode 100644
index c67bc409..00000000
--- a/AsbCloudInfrastructure/Services/Trajectory/Import/TrajectoryParserService.cs
+++ /dev/null
@@ -1,78 +0,0 @@
-using AsbCloudApp.Data.Trajectory;
-using ClosedXML.Excel;
-using System.Collections.Generic;
-using System.IO;
-using System.Linq;
-
-namespace AsbCloudInfrastructure.Services.Trajectory.Import
-{
- public abstract class TrajectoryParserService
- where T : TrajectoryGeoDto
- {
- public abstract string templateFileName { get; }
- public abstract string usingTemplateFile { get; }
- public abstract string sheetName { get; }
- public abstract int headerRowsCount { get; }
-
- protected abstract T ParseRow(IXLRow row);
-
- public IEnumerable Import(Stream stream)
- {
- using var workbook = new XLWorkbook(stream, XLEventTracking.Disabled);
- var trajectoryRows = ParseFileStream(stream);
-
- return trajectoryRows;
- }
-
-
- private IEnumerable ParseFileStream(Stream stream)
- {
- using var workbook = new XLWorkbook(stream, XLEventTracking.Disabled);
- return ParseWorkbook(workbook);
- }
-
- private IEnumerable ParseWorkbook(IXLWorkbook workbook)
- {
- var sheetTrajectory = workbook.Worksheets.FirstOrDefault(ws => ws.Name == sheetName);
- if (sheetTrajectory is null)
- throw new FileFormatException($"Книга excel не содержит листа {sheetName}.");
- var trajectoryRows = ParseSheet(sheetTrajectory);
- return trajectoryRows;
- }
-
- private IEnumerable ParseSheet(IXLWorksheet sheet)
- {
- if (sheet.RangeUsed().RangeAddress.LastAddress.ColumnNumber < 6)
- throw new FileFormatException($"Лист {sheet.Name} содержит меньшее количество столбцов.");
-
- var count = sheet.RowsUsed().Count() - headerRowsCount;
-
- if (count > 1024)
- throw new FileFormatException($"Лист {sheet.Name} содержит слишком большое количество строк.");
-
- if (count <= 0)
- throw new FileFormatException($"Лист {sheet.Name} некорректного формата либо пустой");
-
- var trajectoryRows = new List(count);
- var parseErrors = new List();
- for (int i = 0; i < count; i++)
- {
- var row = sheet.Row(1 + i + headerRowsCount);
- try
- {
- var trajectoryRow = ParseRow(row);
- trajectoryRows.Add(trajectoryRow);
- }
- catch (FileFormatException ex)
- {
- parseErrors.Add(ex.Message);
- }
- }
-
- if (parseErrors.Any())
- throw new FileFormatException(string.Join("\r\n", parseErrors));
-
- return trajectoryRows;
- }
- }
-}
diff --git a/AsbCloudInfrastructure/Services/Trajectory/Import/TrajectoryPlanParserService.cs b/AsbCloudInfrastructure/Services/Trajectory/Import/TrajectoryPlanParserService.cs
deleted file mode 100644
index 00f3f197..00000000
--- a/AsbCloudInfrastructure/Services/Trajectory/Import/TrajectoryPlanParserService.cs
+++ /dev/null
@@ -1,33 +0,0 @@
-using AsbCloudApp.Data.Trajectory;
-using ClosedXML.Excel;
-
-namespace AsbCloudInfrastructure.Services.Trajectory.Import
-{
-
- public class TrajectoryPlanParserService : TrajectoryParserService
- {
- public override string templateFileName { get; } = "TrajectoryPlanTemplate.xlsx";
- public override string usingTemplateFile { get; } = "AsbCloudInfrastructure.Services.Trajectory.Templates";
- public override string sheetName { get; } = "Плановая траектория";
- public override int headerRowsCount { get; } = 2;
-
- protected override TrajectoryGeoPlanDto ParseRow(IXLRow row)
- {
- var trajectoryRow = new TrajectoryGeoPlanDto
- {
- WellboreDepth = row.Cell(1).GetCellValue(),
- ZenithAngle = row.Cell(2).GetCellValue(),
- AzimuthGeo = row.Cell(3).GetCellValue(),
- AzimuthMagnetic = row.Cell(4).GetCellValue(),
- VerticalDepth = row.Cell(5).GetCellValue(),
- Radius = row.Cell(6).GetCellValue(),
- Comment = row.Cell(7).GetCellValue()
- };
-
- //TODO: Добавить валидацию модели IValidatableObject
- return trajectoryRow;
- }
- }
-
-}
-
diff --git a/AsbCloudInfrastructure/Services/Trajectory/Parser/TrajectoryFactManualParserService.cs b/AsbCloudInfrastructure/Services/Trajectory/Parser/TrajectoryFactManualParserService.cs
new file mode 100644
index 00000000..6e4034a5
--- /dev/null
+++ b/AsbCloudInfrastructure/Services/Trajectory/Parser/TrajectoryFactManualParserService.cs
@@ -0,0 +1,39 @@
+using System;
+using AsbCloudApp.Data;
+using AsbCloudApp.Data.Trajectory;
+using ClosedXML.Excel;
+
+namespace AsbCloudInfrastructure.Services.Trajectory.Parser;
+
+public class TrajectoryFactManualParserService : TrajectoryParserService
+{
+ protected override string SheetName => "Фактическая траектория";
+ protected override string TemplateFileName => "TrajectoryFactManualTemplate.xlsx";
+
+ public TrajectoryFactManualParserService(IServiceProvider serviceProvider)
+ : base(serviceProvider)
+ {
+ }
+
+ protected override ValidationResultDto ParseRow(IXLRow row)
+ {
+ var trajectoryRow = new TrajectoryGeoFactDto
+ {
+ WellboreDepth = row.Cell(1).GetCellValue(),
+ ZenithAngle = row.Cell(2).GetCellValue(),
+ AzimuthGeo = row.Cell(3).GetCellValue(),
+ AzimuthMagnetic = row.Cell(4).GetCellValue(),
+ VerticalDepth = row.Cell(5).GetCellValue(),
+ Comment = row.Cell(6).GetCellValue()
+ };
+
+ //TODO: Добавить валидацию модели
+
+ var validationResult = new ValidationResultDto
+ {
+ Item = trajectoryRow
+ };
+
+ return validationResult;
+ }
+}
\ No newline at end of file
diff --git a/AsbCloudInfrastructure/Services/Trajectory/Parser/TrajectoryParserService.cs b/AsbCloudInfrastructure/Services/Trajectory/Parser/TrajectoryParserService.cs
new file mode 100644
index 00000000..d0afe513
--- /dev/null
+++ b/AsbCloudInfrastructure/Services/Trajectory/Parser/TrajectoryParserService.cs
@@ -0,0 +1,44 @@
+using System;
+using AsbCloudApp.Data.Trajectory;
+using ClosedXML.Excel;
+using System.IO;
+using System.Linq;
+using System.Reflection;
+using AsbCloudApp.Data;
+using AsbCloudApp.Requests.ParserOptions;
+
+namespace AsbCloudInfrastructure.Services.Trajectory.Parser;
+
+public abstract class TrajectoryParserService : ParserServiceBase
+ where T : TrajectoryGeoDto
+{
+ private const int HeaderRowsCount = 2;
+ private const int ColumnCount = 6;
+
+ protected TrajectoryParserService(IServiceProvider serviceProvider)
+ : base(serviceProvider)
+ {
+ }
+
+ protected abstract string SheetName { get; }
+
+ protected abstract string TemplateFileName { get; }
+
+ protected abstract ValidationResultDto ParseRow(IXLRow row);
+
+ public override Stream GetTemplateFile() =>
+ Assembly.GetExecutingAssembly().GetTemplateCopyStream(TemplateFileName)
+ ?? throw new ArgumentNullException($"Файл '{TemplateFileName}' не найден");
+
+ public override ParserResultDto Parse(Stream file, IParserOptionsRequest options)
+ {
+ using var workbook = new XLWorkbook(file, XLEventTracking.Disabled);
+
+ var sheet = workbook.Worksheets.FirstOrDefault(ws =>
+ ws.Name.ToLower().Trim() == SheetName.ToLower().Trim())
+ ?? throw new FileFormatException($"Книга excel не содержит листа {SheetName}.");
+
+ var trajectoryRows = ParseExcelSheet(sheet, ParseRow, ColumnCount, HeaderRowsCount);
+ return trajectoryRows;
+ }
+}
\ No newline at end of file
diff --git a/AsbCloudInfrastructure/Services/Trajectory/Parser/TrajectoryPlanParserService.cs b/AsbCloudInfrastructure/Services/Trajectory/Parser/TrajectoryPlanParserService.cs
new file mode 100644
index 00000000..fbf5a537
--- /dev/null
+++ b/AsbCloudInfrastructure/Services/Trajectory/Parser/TrajectoryPlanParserService.cs
@@ -0,0 +1,40 @@
+using System;
+using AsbCloudApp.Data;
+using AsbCloudApp.Data.Trajectory;
+using ClosedXML.Excel;
+
+namespace AsbCloudInfrastructure.Services.Trajectory.Parser;
+
+public class TrajectoryPlanParserService : TrajectoryParserService
+{
+ protected override string SheetName => "Плановая траектория";
+ protected override string TemplateFileName => "TrajectoryPlanTemplate.xlsx";
+
+ public TrajectoryPlanParserService(IServiceProvider serviceProvider)
+ : base(serviceProvider)
+ {
+ }
+
+ protected override ValidationResultDto ParseRow(IXLRow row)
+ {
+ var trajectoryRow = new TrajectoryGeoPlanDto
+ {
+ WellboreDepth = row.Cell(1).GetCellValue(),
+ ZenithAngle = row.Cell(2).GetCellValue(),
+ AzimuthGeo = row.Cell(3).GetCellValue(),
+ AzimuthMagnetic = row.Cell(4).GetCellValue(),
+ VerticalDepth = row.Cell(5).GetCellValue(),
+ Radius = row.Cell(6).GetCellValue(),
+ Comment = row.Cell(7).GetCellValue()
+ };
+
+ //TODO: Добавить валидацию модели
+
+ var validationResult = new ValidationResultDto
+ {
+ Item = trajectoryRow
+ };
+
+ return validationResult;
+ }
+}
\ No newline at end of file
diff --git a/AsbCloudInfrastructure/XLExtentions.cs b/AsbCloudInfrastructure/XLExtentions.cs
index 3a583bf9..e633a875 100644
--- a/AsbCloudInfrastructure/XLExtentions.cs
+++ b/AsbCloudInfrastructure/XLExtentions.cs
@@ -2,96 +2,11 @@
using System;
using System.Globalization;
using System.IO;
-using AsbCloudInfrastructure.Services.DailyReport;
namespace AsbCloudInfrastructure;
internal static class XLExtentions
{
- internal static IXLRange _SetValue(this IXLRange range, object value)
- {
- var mergedRange = range.Merge();
- mergedRange.FirstCell()._SetValue(value);
- var colWidth = mergedRange.FirstCell().WorksheetColumn().Width;
- var maxCharsToWrap = colWidth / (0.1d * mergedRange.FirstCell().Style.Font.FontSize);
- if (value is string valueString && valueString.Length > maxCharsToWrap)
- {
- var row = mergedRange.FirstCell().WorksheetRow();
- var baseHeight = row.Height;
- row.Height = 0.5d * baseHeight * Math.Ceiling(1d + valueString.Length / maxCharsToWrap);
- }
-
- mergedRange.Style.SetAllBorders()
- .Alignment.SetWrapText(true);
- return mergedRange;
- }
-
- internal static IXLCell _SetValue(this IXLCell cell, object value)
- {
- switch (value)
- {
- case DateTime dateTime:
- cell._SetValue(dateTime);
- break;
- case IFormattable formattable:
- cell._SetValue(formattable);
- break;
- case string valueString:
- cell._SetValue(valueString);
- break;
- default:
- cell.Value = value;
- break;
- }
-
- return cell;
- }
-
- internal static IXLCell _SetValue(this IXLCell cell, string value, bool adaptRowHeight = false)
- {
- cell.Value = value;
- cell.Style
- .SetAllBorders()
- .Alignment.WrapText = true;
-
- cell.Value = value;
- if (adaptRowHeight)
- {
- var colWidth = cell.WorksheetColumn().Width;
- var maxCharsToWrap = colWidth / (0.1d * cell.Style.Font.FontSize);
- if (value.Length > maxCharsToWrap)
- {
- var row = cell.WorksheetRow();
- var baseHeight = row.Height;
- row.Height = 0.5d * baseHeight * Math.Ceiling(1d + value.Length / maxCharsToWrap);
- }
- }
-
- return cell;
- }
-
- internal static IXLCell _ValueNoBorder(this IXLCell cell, string value, bool adaptRowHeight = false)
- {
- cell.Value = value;
- cell.Style.Alignment.WrapText = true;
-
- cell.Value = value;
- if (adaptRowHeight)
- {
- var colWidth = cell.WorksheetColumn().Width;
- var maxCharsToWrap = colWidth / (0.1d * cell.Style.Font.FontSize);
- if (value.Length > maxCharsToWrap)
- {
- var row = cell.WorksheetRow();
- var baseHeight = row.Height;
- row.Height = 0.5d * baseHeight * Math.Ceiling(1d + value.Length / maxCharsToWrap);
- }
- }
-
- return cell;
- }
-
-
internal static IXLCell _SetValue(this IXLCell cell, DateTime value, string dateFormat = "DD.MM.YYYY HH:MM:SS", bool setAllBorders = true)
{
cell.Value = value;
@@ -111,21 +26,6 @@ internal static class XLExtentions
return cell;
}
- internal static IXLCell _SetValue(this IXLCell cell, IFormattable value, string format = "0.00")
- {
- cell.Value = value;
- cell.Style
- .SetAllBorders()
- .Alignment.WrapText = true;
-
- cell.Value = value;
-
- cell.DataType = XLDataType.Number;
- cell.Style.NumberFormat.Format = "0.00";
-
- return cell;
- }
-
public static IXLCell SetVal(this IXLCell cell, double? value, string format = "0.00")
{
cell.Value = (value is not null && double.IsFinite(value.Value)) ? value : null;
@@ -161,7 +61,7 @@ internal static class XLExtentions
return cell;
}
- internal static IXLStyle SetAllBorders(this IXLStyle style, XLBorderStyleValues borderStyle = XLBorderStyleValues.Thin)
+ private static IXLStyle SetAllBorders(this IXLStyle style, XLBorderStyleValues borderStyle = XLBorderStyleValues.Thin)
{
style.Border.RightBorder = borderStyle;
style.Border.LeftBorder = borderStyle;
@@ -172,20 +72,6 @@ internal static class XLExtentions
return style;
}
- internal static IXLStyle SetBaseFont(this IXLStyle style)
- {
- style.Font.FontName = "Calibri";
- style.Font.FontSize = 10;
- return style;
- }
-
- internal static IXLStyle SetH1(this IXLStyle style)
- {
- style.Font.FontName = "Calibri";
- style.Font.FontSize = 14;
- return style;
- }
-
internal static T? GetCellValue(this IXLCell cell)
{
try
@@ -204,7 +90,7 @@ internal static class XLExtentions
catch
{
throw new FileFormatException(
- $"Лист '{cell.Worksheet.Name}'. Ячейка: ({cell.Address.RowNumber},{cell.Address.ColumnNumber}) содержит некорректное значение");
+ $"Лист '{cell.Worksheet.Name}'. {cell.Address.RowNumber} строка содержит некорректное значение в {cell.Address.ColumnNumber} столбце");
}
}
}
\ No newline at end of file
diff --git a/AsbCloudWebApi.Tests/Services/Trajectory/TrajectoryImportTest.cs b/AsbCloudWebApi.Tests/Services/Trajectory/TrajectoryImportTest.cs
deleted file mode 100644
index e6763582..00000000
--- a/AsbCloudWebApi.Tests/Services/Trajectory/TrajectoryImportTest.cs
+++ /dev/null
@@ -1,48 +0,0 @@
-using AsbCloudInfrastructure.Services.Trajectory.Import;
-using System.Linq;
-using Xunit;
-
-namespace AsbCloudWebApi.Tests.Services.Trajectory
-{
- public class TrajectoryImportTest
- {
- private readonly TrajectoryPlanParserService trajectoryPlanImportService;
- private readonly TrajectoryFactManualParserService trajectoryFactManualImportService;
-
- private string usingTemplateFile = "AsbCloudWebApi.Tests.Services.Trajectory.Templates";
-
- public TrajectoryImportTest()
- {
- trajectoryPlanImportService = new TrajectoryPlanParserService();
- trajectoryFactManualImportService = new TrajectoryFactManualParserService();
- }
-
- [Fact]
- public void Import_trajectory_plan()
- {
- var stream = System.Reflection.Assembly.GetExecutingAssembly()
- .GetManifestResourceStream($"{usingTemplateFile}.TrajectoryPlanTemplate.xlsx");
-
- if (stream is null)
- Assert.Fail("Файла для импорта не существует");
-
- var trajectoryRows = trajectoryPlanImportService.Import(stream);
-
- Assert.Equal(3, trajectoryRows.Count());
- }
-
- [Fact]
- public void Import_trajectory_fact_manual()
- {
- var stream = System.Reflection.Assembly.GetExecutingAssembly()
- .GetManifestResourceStream($"{usingTemplateFile}.TrajectoryFactManualTemplate.xlsx");
-
- if (stream is null)
- Assert.Fail("Файла для импорта не существует");
-
- var trajectoryRows = trajectoryFactManualImportService.Import(stream);
-
- Assert.Equal(4, trajectoryRows.Count());
- }
- }
-}
diff --git a/AsbCloudWebApi.Tests/Services/Trajectory/TrajectoryParserTest.cs b/AsbCloudWebApi.Tests/Services/Trajectory/TrajectoryParserTest.cs
new file mode 100644
index 00000000..1fddd56d
--- /dev/null
+++ b/AsbCloudWebApi.Tests/Services/Trajectory/TrajectoryParserTest.cs
@@ -0,0 +1,63 @@
+using System;
+using System.Linq;
+using AsbCloudApp.Data.Trajectory;
+using AsbCloudApp.Requests.ParserOptions;
+using AsbCloudInfrastructure.Services;
+using Microsoft.Extensions.DependencyInjection;
+using NSubstitute;
+using Xunit;
+
+namespace AsbCloudWebApi.Tests.Services.Trajectory;
+
+public class TrajectoryParserTest
+{
+ private const string UsingTemplateFile = "AsbCloudWebApi.Tests.Services.Trajectory.Templates";
+
+ private readonly IServiceProvider serviceProviderMock = Substitute.For();
+ private readonly IServiceScope serviceScopeMock = Substitute.For();
+ private readonly IServiceScopeFactory serviceScopeFactoryMock = Substitute.For();
+
+ private readonly ParserServiceFactory parserServiceFactory;
+
+ public TrajectoryParserTest()
+ {
+ serviceScopeFactoryMock.CreateScope().Returns(serviceScopeMock);
+ ((ISupportRequiredService)serviceProviderMock).GetRequiredService(typeof(IServiceScopeFactory)).Returns(serviceScopeFactoryMock);
+
+ parserServiceFactory = new ParserServiceFactory(serviceProviderMock);
+ }
+
+ [Fact]
+ public void Parse_trajectory_plan()
+ {
+ var stream = System.Reflection.Assembly.GetExecutingAssembly()
+ .GetManifestResourceStream($"{UsingTemplateFile}.TrajectoryPlanTemplate.xlsx");
+
+ if (stream is null)
+ Assert.Fail("Файла для импорта не существует");
+
+ var parserService = parserServiceFactory.Create(
+ ParserServiceFactory.IdTrajectoryPlanParserService);
+
+ var trajectoryRows = parserService.Parse(stream, IParserOptionsRequest.Empty());
+
+ Assert.Equal(3, trajectoryRows.Item.Count());
+ }
+
+ [Fact]
+ public void Parse_trajectory_fact_manual()
+ {
+ var stream = System.Reflection.Assembly.GetExecutingAssembly()
+ .GetManifestResourceStream($"{UsingTemplateFile}.TrajectoryFactManualTemplate.xlsx");
+
+ if (stream is null)
+ Assert.Fail("Файла для импорта не существует");
+
+ var parserService = parserServiceFactory.Create(
+ ParserServiceFactory.IdTrajectoryFactManualParserService);
+
+ var trajectoryRows = parserService.Parse(stream, IParserOptionsRequest.Empty());
+
+ Assert.Equal(4, trajectoryRows.Item.Count());
+ }
+}
\ No newline at end of file
diff --git a/AsbCloudWebApi/Controllers/Interfaces/IControllerWithParser.cs b/AsbCloudWebApi/Controllers/Interfaces/IControllerWithParser.cs
new file mode 100644
index 00000000..d11ac201
--- /dev/null
+++ b/AsbCloudWebApi/Controllers/Interfaces/IControllerWithParser.cs
@@ -0,0 +1,13 @@
+using System.IO;
+using AsbCloudApp.Data;
+using Microsoft.AspNetCore.Mvc;
+
+namespace AsbCloudWebApi.Controllers.Interfaces;
+
+public interface IControllerWithParser
+ where TDto : class, IId
+{
+ ActionResult> Parse(Stream file, TOptions options);
+
+ IActionResult GetTemplate();
+}
\ No newline at end of file
diff --git a/AsbCloudWebApi/Controllers/Trajectory/TrajectoryEditableController.cs b/AsbCloudWebApi/Controllers/Trajectory/TrajectoryEditableController.cs
index 10ed41f3..7a04e7fc 100644
--- a/AsbCloudWebApi/Controllers/Trajectory/TrajectoryEditableController.cs
+++ b/AsbCloudWebApi/Controllers/Trajectory/TrajectoryEditableController.cs
@@ -2,7 +2,6 @@
using AsbCloudApp.Repositories;
using AsbCloudApp.Services;
using AsbCloudInfrastructure.Services.Trajectory.Export;
-using AsbCloudInfrastructure.Services.Trajectory.Import;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
@@ -10,6 +9,10 @@ using System.Collections.Generic;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
+using AsbCloudApp.Data;
+using AsbCloudApp.Requests.ParserOptions;
+using AsbCloudInfrastructure.Services;
+using AsbCloudWebApi.Controllers.Interfaces;
namespace AsbCloudWebApi.Controllers.Trajectory
{
@@ -19,28 +22,41 @@ namespace AsbCloudWebApi.Controllers.Trajectory
///
[ApiController]
[Authorize]
- public abstract class TrajectoryEditableController : TrajectoryController
+ public abstract class TrajectoryEditableController : TrajectoryController,
+ IControllerWithParser
where TDto : TrajectoryGeoDto
- {
- private readonly TrajectoryParserService trajectoryImportService;
- private readonly TrajectoryExportService trajectoryExportService;
- private readonly ITrajectoryEditableRepository trajectoryRepository;
+ {
+ private readonly IParserService parserService;
+ private readonly ITrajectoryEditableRepository trajectoryRepository;
- public TrajectoryEditableController(IWellService wellService,
- TrajectoryParserService trajectoryImportService,
- TrajectoryExportService trajectoryExportService,
- ITrajectoryEditableRepository trajectoryRepository)
+ protected TrajectoryEditableController(IWellService wellService,
+ ParserServiceFactory parserServiceFactory,
+ TrajectoryExportService trajectoryExportService,
+ ITrajectoryEditableRepository trajectoryRepository,
+ int idParserService)
: base(
wellService,
trajectoryExportService,
trajectoryRepository)
{
- this.trajectoryImportService = trajectoryImportService;
- this.trajectoryExportService = trajectoryExportService;
- this.trajectoryRepository = trajectoryRepository;
-
- }
+ parserService = parserServiceFactory.Create(idParserService);
+ this.trajectoryRepository = trajectoryRepository;
+ }
+ ActionResult> IControllerWithParser.Parse(Stream file,
+ IParserOptionsRequest options)
+ {
+ try
+ {
+ var parserResult = parserService.Parse(file, options);
+ return Ok(parserResult);
+ }
+ catch (FileFormatException ex)
+ {
+ return this.ValidationBadRequest("files", ex.Message);
+ }
+ }
+
///
/// Возвращает excel шаблон для заполнения строк траектории
///
@@ -51,110 +67,96 @@ namespace AsbCloudWebApi.Controllers.Trajectory
[ProducesResponseType(StatusCodes.Status204NoContent)]
public IActionResult GetTemplate()
{
- var stream = trajectoryExportService.GetTemplateFile();
+ var stream = parserService.GetTemplateFile();
return File(stream, "application/octet-stream", fileName);
}
- ///
- /// Импортирует координаты из excel (xlsx) файла
- ///
- /// id скважины
- /// Коллекция из одного файла xlsx
- /// Удалить операции перед импортом, если фал валидный
- /// Токен отмены задачи
- /// количество успешно записанных строк в БД
- [HttpPost("import/{deleteBeforeImport}")]
- [ProducesResponseType(typeof(int), (int)System.Net.HttpStatusCode.OK)]
- [ProducesResponseType(typeof(ValidationProblemDetails), (int)System.Net.HttpStatusCode.BadRequest)]
- public async Task ImportAsync(int idWell,
- [FromForm] IFormFileCollection files,
- bool deleteBeforeImport,
- CancellationToken token)
- {
- int? idUser = User.GetUserId();
- if (!idUser.HasValue)
- return Forbid();
- if (!await CanUserAccessToWellAsync(idWell,
- token).ConfigureAwait(false))
- return Forbid();
- if (files.Count < 1)
- return this.ValidationBadRequest(nameof(files), "нет файла");
- var file = files[0];
- if (Path.GetExtension(file.FileName).ToLower() != ".xlsx")
- return this.ValidationBadRequest(nameof(files), "Требуется xlsx файл.");
- using Stream stream = file.OpenReadStream();
+ ///
+ /// Импортирует координаты из excel (xlsx) файла
+ ///
+ /// id скважины
+ /// Коллекция из одного файла xlsx
+ /// Токен отмены задачи
+ /// количество успешно записанных строк в БД
+ [HttpPost("parse")]
+ [ProducesResponseType((int)System.Net.HttpStatusCode.OK)]
+ [ProducesResponseType(typeof(ValidationProblemDetails), (int)System.Net.HttpStatusCode.BadRequest)]
+ public async Task>> Parse(int idWell,
+ [FromForm] IFormFileCollection files,
+ CancellationToken token)
+ {
+ var idUser = User.GetUserId();
- try
- {
- var trajectoryRows = trajectoryImportService.Import(stream);
- foreach (var row in trajectoryRows)
- {
- row.IdWell = idWell;
- row.IdUser = idUser.Value;
- }
+ if (!idUser.HasValue)
+ return Forbid();
- if (deleteBeforeImport)
- await trajectoryRepository.DeleteByIdWellAsync(idWell, token);
+ if (!await CanUserAccessToWellAsync(idWell, token))
+ return Forbid();
- var rowsCount = await trajectoryRepository.AddRangeAsync(trajectoryRows, token);
+ return this.ParseExcelFile(files, IParserOptionsRequest.Empty());
+ }
+
+ ///
+ /// Добавление
+ ///
+ ///
+ ///
+ ///
+ ///
+ [HttpPost]
+ [ProducesResponseType(typeof(int), (int)System.Net.HttpStatusCode.OK)]
+ public async Task InsertRangeAsync(int idWell, [FromBody] IEnumerable dtos, CancellationToken token)
+ {
+ if (!await CanUserAccessToWellAsync(idWell, token))
+ return Forbid();
+
+ var idUser = User.GetUserId();
+
+ if (!idUser.HasValue)
+ return Forbid();
+
+ foreach (var dto in dtos)
+ {
+ dto.IdUser = idUser.Value;
+ dto.IdWell = idWell;
+ }
- return Ok(rowsCount);
- }
- catch (FileFormatException ex)
- {
- return this.ValidationBadRequest(nameof(files), ex.Message);
- }
- }
+ var result = await trajectoryRepository.AddRangeAsync(dtos, token);
+ return Ok(result);
+ }
+ ///
+ /// Удалить все по скважине и добавить новые
+ ///
+ ///
+ ///
+ ///
+ ///
+ [HttpPost("replace")]
+ [ProducesResponseType(typeof(int), (int)System.Net.HttpStatusCode.OK)]
+ public async Task ClearAndInsertRangeAsync(int idWell, [FromBody] IEnumerable dtos, CancellationToken token)
+ {
+ //TODO: это вся радость требует рефакторинга.
+ //Удаление с добавлением новых записей должно происходить в рамках одной транзакции, да и вообще должно быть реализовано на уровне репозиторий.
+ //Рефакторинг будет когда доберёмся до журнала изменений для траекторий.
+ if (!await CanUserAccessToWellAsync(idWell, token))
+ return Forbid();
+
+ var idUser = User.GetUserId();
+
+ if (!idUser.HasValue)
+ return Forbid();
+
+ foreach (var dto in dtos)
+ {
+ dto.IdUser = idUser.Value;
+ dto.IdWell = idWell;
+ }
- ///
- /// Добавить одну новую строчку координат для плановой траектории
- ///
- ///
- ///
- ///
- /// количество успешно записанных строк в БД
- [HttpPost]
- [ProducesResponseType(typeof(int), (int)System.Net.HttpStatusCode.OK)]
- public async Task AddAsync(int idWell, [FromBody] TDto row,
- CancellationToken token)
- {
- if (!await CanUserAccessToWellAsync(idWell, token).ConfigureAwait(false))
- return Forbid();
- var idUser = User.GetUserId();
- if (!idUser.HasValue)
- return Forbid();
- row.IdUser = idUser.Value;
- row.IdWell = idWell;
- var result = await trajectoryRepository.AddAsync(row, token);
- return Ok(result);
- }
-
- ///
- /// Добавить массив строчек координат для плановой траектории
- ///
- ///
- ///
- ///
- /// количество успешно записанных строк в БД
- [HttpPost("range")]
- [ProducesResponseType(typeof(int), (int)System.Net.HttpStatusCode.OK)]
- public async Task AddRangeAsync(int idWell, [FromBody] IEnumerable rows,
- CancellationToken token)
- {
- if (!await CanUserAccessToWellAsync(idWell, token).ConfigureAwait(false))
- return Forbid();
- int? idUser = User.GetUserId();
- if (!idUser.HasValue)
- return Forbid();
- foreach (var item in rows)
- {
- item.IdUser = idUser.Value;
- item.IdWell = idWell;
- }
- var result = await trajectoryRepository.AddRangeAsync(rows, token);
- return Ok(result);
- }
+ await trajectoryRepository.DeleteByIdWellAsync(idWell, token);
+ var result = await trajectoryRepository.AddRangeAsync(dtos, token);
+ return Ok(result);
+ }
///
/// Изменить выбранную строку с координатами
@@ -201,4 +203,4 @@ namespace AsbCloudWebApi.Controllers.Trajectory
return Ok(result);
}
}
-}
+}
\ No newline at end of file
diff --git a/AsbCloudWebApi/Controllers/Trajectory/TrajectoryFactManualController.cs b/AsbCloudWebApi/Controllers/Trajectory/TrajectoryFactManualController.cs
index e3020342..97b84b07 100644
--- a/AsbCloudWebApi/Controllers/Trajectory/TrajectoryFactManualController.cs
+++ b/AsbCloudWebApi/Controllers/Trajectory/TrajectoryFactManualController.cs
@@ -1,8 +1,8 @@
using AsbCloudApp.Data.Trajectory;
using AsbCloudApp.Repositories;
using AsbCloudApp.Services;
+using AsbCloudInfrastructure.Services;
using AsbCloudInfrastructure.Services.Trajectory.Export;
-using AsbCloudInfrastructure.Services.Trajectory.Import;
using Microsoft.AspNetCore.Mvc;
namespace AsbCloudWebApi.Controllers.Trajectory;
@@ -14,15 +14,17 @@ namespace AsbCloudWebApi.Controllers.Trajectory;
[Route("api/well/{idWell}/[controller]")]
public class TrajectoryFactManualController : TrajectoryEditableController
{
- protected override string fileName => "ЕЦП_шаблон_файла_фактическая_траектория.xlsx";
- public TrajectoryFactManualController(IWellService wellService,
- TrajectoryFactManualParserService factTrajectoryImportService,
- TrajectoryFactManualExportService factTrajectoryExportService,
- ITrajectoryEditableRepository trajectoryFactRepository)
- : base(
- wellService,
- factTrajectoryImportService,
- factTrajectoryExportService,
- trajectoryFactRepository)
- { }
+ protected override string fileName => "ЕЦП_шаблон_файла_фактическая_траектория.xlsx";
+
+ public TrajectoryFactManualController(IWellService wellService,
+ TrajectoryFactManualExportService trajectoryExportService,
+ ParserServiceFactory parserServiceFactory,
+ ITrajectoryEditableRepository trajectoryRepository)
+ : base(wellService,
+ parserServiceFactory,
+ trajectoryExportService,
+ trajectoryRepository,
+ ParserServiceFactory.IdTrajectoryFactManualParserService)
+ {
+ }
}
\ No newline at end of file
diff --git a/AsbCloudWebApi/Controllers/Trajectory/TrajectoryPlanController.cs b/AsbCloudWebApi/Controllers/Trajectory/TrajectoryPlanController.cs
index 122352ad..cf3f648d 100644
--- a/AsbCloudWebApi/Controllers/Trajectory/TrajectoryPlanController.cs
+++ b/AsbCloudWebApi/Controllers/Trajectory/TrajectoryPlanController.cs
@@ -2,58 +2,58 @@
using AsbCloudApp.Repositories;
using AsbCloudApp.Services;
using AsbCloudInfrastructure.Services.Trajectory;
-using AsbCloudInfrastructure.Services.Trajectory.Import;
using AsbCloudInfrastructure.Services.Trajectory.Export;
using Microsoft.AspNetCore.Mvc;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
+using AsbCloudInfrastructure.Services;
namespace AsbCloudWebApi.Controllers.Trajectory
{
+ ///
+ /// Плановая траектория (загрузка и хранение)
+ ///
+ [Route("api/well/{idWell}/[controller]")]
+ [ApiController]
+ public class TrajectoryPlanController : TrajectoryEditableController
+ {
+ private readonly TrajectoryService trajectoryVisualizationService;
- ///
- /// Плановая траектория (загрузка и хранение)
- ///
- [Route("api/well/{idWell}/[controller]")]
- [ApiController]
- public class TrajectoryPlanController : TrajectoryEditableController
- {
- private readonly TrajectoryService trajectoryVisualizationService;
+ protected override string fileName => "ЕЦП_шаблон_файла_плановая_траектория.xlsx";
- protected override string fileName => "ЕЦП_шаблон_файла_плановая_траектория.xlsx";
+ public TrajectoryPlanController(IWellService wellService,
+ TrajectoryPlanExportService trajectoryExportService,
+ ParserServiceFactory parserServiceFactory,
+ ITrajectoryEditableRepository trajectoryRepository,
+ TrajectoryService trajectoryVisualizationService)
+ : base(wellService,
+ parserServiceFactory,
+ trajectoryExportService,
+ trajectoryRepository,
+ ParserServiceFactory.IdTrajectoryPlanParserService)
+ {
+ this.trajectoryVisualizationService = trajectoryVisualizationService;
+ }
- public TrajectoryPlanController(IWellService wellService,
- TrajectoryPlanParserService trajectoryPlanImportService,
- TrajectoryPlanExportService trajectoryPlanExportService,
- ITrajectoryEditableRepository trajectoryPlanRepository,
- TrajectoryService trajectoryVisualizationService)
- : base(
- wellService,
- trajectoryPlanImportService,
- trajectoryPlanExportService,
- trajectoryPlanRepository)
- {
- this.trajectoryVisualizationService = trajectoryVisualizationService;
- }
+ ///
+ /// Получение координат для визуализации траектории (плановой и фактической)
+ ///
+ ///
+ ///
+ ///
+ [HttpGet("trajectoryCartesianPlanFact")]
+ [ProducesResponseType(
+ typeof(TrajectoryPlanFactDto, IEnumerable>),
+ (int)System.Net.HttpStatusCode.OK)]
+ public async Task GetTrajectoryCartesianPlanFactAsync(int idWell, CancellationToken token)
+ {
+ if (!await CanUserAccessToWellAsync(idWell,
+ token).ConfigureAwait(false))
+ return Forbid();
- ///
- /// Получение координат для визуализации траектории (плановой и фактической)
- ///
- ///
- ///
- ///
- [HttpGet("trajectoryCartesianPlanFact")]
- [ProducesResponseType(typeof(TrajectoryPlanFactDto, IEnumerable>), (int)System.Net.HttpStatusCode.OK)]
- public async Task GetTrajectoryCartesianPlanFactAsync(int idWell, CancellationToken token)
- {
- if (!await CanUserAccessToWellAsync(idWell,
- token).ConfigureAwait(false))
- return Forbid();
-
- var result = await trajectoryVisualizationService.GetTrajectoryCartesianAsync(idWell, token);
- return Ok(result);
- }
- }
-
-}
+ var result = await trajectoryVisualizationService.GetTrajectoryCartesianAsync(idWell, token);
+ return Ok(result);
+ }
+ }
+}
\ No newline at end of file
diff --git a/AsbCloudWebApi/Extensions.cs b/AsbCloudWebApi/Extensions.cs
new file mode 100644
index 00000000..489d6149
--- /dev/null
+++ b/AsbCloudWebApi/Extensions.cs
@@ -0,0 +1,125 @@
+using AsbCloudApp.Data.User;
+using AsbCloudWebApi.Converters;
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.IO;
+using System.ComponentModel.DataAnnotations;
+using System.Linq;
+using System.Security.Claims;
+using AsbCloudApp.Data;
+using AsbCloudApp.Requests.ParserOptions;
+using AsbCloudWebApi.Controllers.Interfaces;
+using Microsoft.AspNetCore.Http;
+
+namespace Microsoft.AspNetCore.Mvc;
+
+public static class Extensions
+{
+ public static int? GetCompanyId(this ClaimsPrincipal user)
+ {
+ var claimIdCompany = user.FindFirst(nameof(UserDto.IdCompany));
+ if (claimIdCompany is null)
+ return null;
+
+ return int.TryParse(claimIdCompany.Value, out int uid)
+ ? uid
+ : null;
+ }
+
+ public static int? GetUserId(this ClaimsPrincipal user)
+ {
+ var userId = user.FindFirst(nameof(UserDto.Id));
+ if (userId is null)
+ return null;
+
+ return int.TryParse(userId.Value, out int uid)
+ ? uid
+ : null;
+ }
+
+ ///
+ ///
+ /// Returns BadRequest with ValidationProblemDetails as body
+ ///
+ ///
+ /// Используйте этот метод только если валидацию нельзя сделать через
+ /// атрибуты валидации или IValidatableObject модели.
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ public static BadRequestObjectResult ValidationBadRequest(this ControllerBase controller, string paramName, string error)
+ {
+ return MakeBadRequestObjectResult(paramName, error);
+ }
+
+ private static BadRequestObjectResult MakeBadRequestObjectResult(string paramName, string error)
+ {
+ var errors = new Dictionary {
+ { paramName, new[]{ error } }
+ };
+ var problem = new ValidationProblemDetails(errors);
+ var badRequestObject = new BadRequestObjectResult(problem);
+ return badRequestObject;
+ }
+
+ ///
+ ///
+ /// Returns BadRequest with ValidationProblemDetails as body
+ ///
+ ///
+ /// Используйте этот метод только если валидацию нельзя сделать через
+ /// атрибуты валидации или IValidatableObject модели.
+ ///
+ ///
+ ///
+ ///
+ ///
+ public static BadRequestObjectResult ValidationBadRequest(this ControllerBase controller, IEnumerable validationResults)
+ {
+ var errors = validationResults
+ .SelectMany(e => e.MemberNames.Select(name => new { name, e.ErrorMessage }))
+ .GroupBy(e => e.name)
+ .ToDictionary(e => e.Key, e => e.Select(el => el.ErrorMessage ?? string.Empty).ToArray());
+
+ var problem = new ValidationProblemDetails(errors);
+ return controller.BadRequest(problem);
+ }
+
+ public static MvcOptions UseDateOnlyTimeOnlyStringConverters(this MvcOptions options)
+ {
+ TypeDescriptor.AddAttributes(typeof(DateOnly), new TypeConverterAttribute(typeof(DateOnlyTypeConverter)));
+ return options;
+ }
+
+ ///
+ /// Вызов парсера со стандартной валидацией входного файла
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ public static ActionResult> ParseExcelFile(
+ this IControllerWithParser controller,
+ IFormFileCollection files,
+ TOptions options)
+ where TDto : class, IId
+ where TOptions : class, IParserOptionsRequest
+ {
+ if (files.Count < 1)
+ return MakeBadRequestObjectResult(nameof(files), "Нет файла");
+
+ var file = files[0];
+ if (Path.GetExtension(file.FileName).ToLower() != ".xlsx")
+ return MakeBadRequestObjectResult(nameof(files), "Требуется .xlsx файл.");
+
+ var stream = file.OpenReadStream();
+
+ return controller.Parse(stream, options);
+ }
+}
\ No newline at end of file
diff --git a/AsbCloudWebApi/Extentions.cs b/AsbCloudWebApi/Extentions.cs
deleted file mode 100644
index 7299fae5..00000000
--- a/AsbCloudWebApi/Extentions.cs
+++ /dev/null
@@ -1,89 +0,0 @@
-using AsbCloudApp.Data.User;
-using AsbCloudWebApi.Converters;
-using System;
-using System.Collections.Generic;
-using System.ComponentModel;
-using System.ComponentModel.DataAnnotations;
-using System.Linq;
-using System.Security.Claims;
-
-namespace Microsoft.AspNetCore.Mvc
-{
- public static class Extentions
- {
- public static int? GetCompanyId(this ClaimsPrincipal user)
- {
- var claimIdCompany = user.FindFirst(nameof(UserDto.IdCompany));
- if (claimIdCompany is null)
- return null;
-
- return int.TryParse(claimIdCompany.Value, out int uid)
- ? uid
- : null;
- }
-
- public static int? GetUserId(this ClaimsPrincipal user)
- {
- var userId = user.FindFirst(nameof(UserDto.Id));
- if (userId is null)
- return null;
-
- return int.TryParse(userId.Value, out int uid)
- ? uid
- : null;
- }
-
- ///
- ///
- /// Returns BadRequest with ValidationProblemDetails as body
- ///
- ///
- /// Используйте этот метод только если валидацию нельзя сделать через
- /// атрибуты валидации или IValidatableObject модели.
- ///
- ///
- ///
- ///
- ///
- ///
- public static BadRequestObjectResult ValidationBadRequest(this ControllerBase controller, string paramName, string error)
- {
- var errors = new Dictionary {
- { paramName, new[]{ error } }
- };
- var problem = new ValidationProblemDetails(errors);
- return controller.BadRequest(problem);
- }
-
- ///
- ///
- /// Returns BadRequest with ValidationProblemDetails as body
- ///
- ///
- /// Используйте этот метод только если валидацию нельзя сделать через
- /// атрибуты валидации или IValidatableObject модели.
- ///
- ///
- ///
- ///
- ///
- public static BadRequestObjectResult ValidationBadRequest(this ControllerBase controller, IEnumerable validationResults)
- {
- var errors = validationResults
- .SelectMany(e => e.MemberNames.Select(name => new { name, e.ErrorMessage }))
- .GroupBy(e => e.name)
- .ToDictionary(e => e.Key, e => e.Select(el => el.ErrorMessage ?? string.Empty).ToArray());
-
- var problem = new ValidationProblemDetails(errors);
- return controller.BadRequest(problem);
- }
-
- public static MvcOptions UseDateOnlyTimeOnlyStringConverters(this MvcOptions options)
- {
- TypeDescriptor.AddAttributes(typeof(DateOnly), new TypeConverterAttribute(typeof(DateOnlyTypeConverter)));
- return options;
- }
-
- }
-}
-