feat(api): в Works добавлена маска динамической генерации имени шаблона; добавлены Shortcodes; актализированы валидация, запросы,ответы; миграция БД - запрет приёма нулевых значений в маску
This commit is contained in:
@@ -3,6 +3,7 @@
|
|||||||
public class WorkRequest
|
public class WorkRequest
|
||||||
{
|
{
|
||||||
public required string Name { get; set; }
|
public required string Name { get; set; }
|
||||||
|
public required string TemplateNameMask { get; set; }
|
||||||
public string? TemplateSuffix { get;set; }
|
public string? TemplateSuffix { get;set; }
|
||||||
public int EsppId { get; set; }
|
public int EsppId { get; set; }
|
||||||
public Guid TnkId { get; set; }
|
public Guid TnkId { get; set; }
|
||||||
|
|||||||
@@ -6,6 +6,8 @@
|
|||||||
|
|
||||||
public required string Name { get; set; }
|
public required string Name { get; set; }
|
||||||
|
|
||||||
|
public required string TemplateNameMask { get; set; }
|
||||||
|
|
||||||
public string? TemplateSuffix { get; set; }
|
public string? TemplateSuffix { get; set; }
|
||||||
|
|
||||||
public int EsppId { get; set; }
|
public int EsppId { get; set; }
|
||||||
|
|||||||
@@ -137,6 +137,7 @@ namespace PARR.API.Controllers.V1
|
|||||||
{
|
{
|
||||||
Id = Guid.NewGuid(),
|
Id = Guid.NewGuid(),
|
||||||
Name = request.Name.Trim(),
|
Name = request.Name.Trim(),
|
||||||
|
TemplateNameMask = request.TemplateNameMask,
|
||||||
EsppId = request.EsppId,
|
EsppId = request.EsppId,
|
||||||
TnkId = request.TnkId,
|
TnkId = request.TnkId,
|
||||||
TemplateSuffix = request.TemplateSuffix
|
TemplateSuffix = request.TemplateSuffix
|
||||||
@@ -179,6 +180,7 @@ namespace PARR.API.Controllers.V1
|
|||||||
return BadRequest(new Response(false, new List<ErrorModel> { new ErrorModel { Message = $"Ошибка при изменении вида работ. Не найдена работа Id: {id}" } }));
|
return BadRequest(new Response(false, new List<ErrorModel> { new ErrorModel { Message = $"Ошибка при изменении вида работ. Не найдена работа Id: {id}" } }));
|
||||||
|
|
||||||
orig.Name = request.Name.Trim();
|
orig.Name = request.Name.Trim();
|
||||||
|
orig.TemplateNameMask = request.TemplateNameMask.Trim();
|
||||||
orig.EsppId = request.EsppId;
|
orig.EsppId = request.EsppId;
|
||||||
orig.TnkId = request.TnkId;
|
orig.TnkId = request.TnkId;
|
||||||
orig.DateModified = DateTimeOffset.UtcNow;
|
orig.DateModified = DateTimeOffset.UtcNow;
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
using FluentValidation;
|
using FluentValidation;
|
||||||
using PARR.API.Contracts.V1.Requests;
|
using PARR.API.Contracts.V1.Requests;
|
||||||
|
using PARR.BLL.Services.Interfaces;
|
||||||
|
using PARR.Constants.Shortcodes;
|
||||||
using PARR.DAL.Services.Interfaces;
|
using PARR.DAL.Services.Interfaces;
|
||||||
|
|
||||||
namespace PARR.API.Validators
|
namespace PARR.API.Validators
|
||||||
@@ -11,13 +13,27 @@ namespace PARR.API.Validators
|
|||||||
private bool? isValid = null;
|
private bool? isValid = null;
|
||||||
|
|
||||||
public WorkRequestValidator(
|
public WorkRequestValidator(
|
||||||
ITnkService tnkService
|
ITnkService tnkService,
|
||||||
|
ITemplateMaskValidator templateMaskValidator
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
this.tnkService = tnkService;
|
this.tnkService = tnkService;
|
||||||
|
|
||||||
RuleFor(t => t.Name).NotEmpty().NotNull();
|
RuleFor(t => t.Name).NotEmpty().NotNull();
|
||||||
|
|
||||||
|
RuleFor(t => t.TemplateNameMask)
|
||||||
|
.NotEmpty()
|
||||||
|
.NotNull();
|
||||||
|
|
||||||
|
RuleFor(t => t.TemplateNameMask)
|
||||||
|
.Must((entity, value, c) => templateMaskValidator
|
||||||
|
.IsValid(entity.TemplateNameMask))
|
||||||
|
.WithMessage($"Неверно указана маска имени шаблонов. Обязательными условиями являются" +
|
||||||
|
$" наличие кодового слова \"ПАРР\" и обязательное использование динамической составляющей" +
|
||||||
|
$" %ЭК%. Доступные значения динамических составляющих:" +
|
||||||
|
$" {string.Join(", ", Shortcodes.GetAll().Select(sc => sc.Name + " - " + sc.Description))}"
|
||||||
|
);
|
||||||
|
|
||||||
RuleFor(t => t.EsppId).NotEmpty().NotNull().WithMessage("EsppId не может быть пустым");
|
RuleFor(t => t.EsppId).NotEmpty().NotNull().WithMessage("EsppId не может быть пустым");
|
||||||
|
|
||||||
RuleFor(t => t.TnkId).NotEmpty().NotNull();
|
RuleFor(t => t.TnkId).NotEmpty().NotNull();
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ namespace PARR.BLL
|
|||||||
services.AddTransient<ITransformService, TransformService>();
|
services.AddTransient<ITransformService, TransformService>();
|
||||||
services.AddTransient<IIntervalService, IntervalService>();
|
services.AddTransient<IIntervalService, IntervalService>();
|
||||||
services.AddTransient<ICalendarService, CalendarService>();
|
services.AddTransient<ICalendarService, CalendarService>();
|
||||||
|
services.AddTransient<ITemplateMaskValidator, TemplateMaskValidator>();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
43
PARR.BLL/Services/Implementations/TemplateMaskValidator.cs
Normal file
43
PARR.BLL/Services/Implementations/TemplateMaskValidator.cs
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
using PARR.BLL.Services.Interfaces;
|
||||||
|
using PARR.Constants.Shortcodes;
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
|
|
||||||
|
namespace PARR.BLL.Services.Implementations
|
||||||
|
{
|
||||||
|
internal class TemplateMaskValidator : ITemplateMaskValidator
|
||||||
|
{
|
||||||
|
public bool IsValid(string mask)
|
||||||
|
{
|
||||||
|
if (!mask.Contains("ПАРР"))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
var shortcodePattern = "%[^%\\s]+%";
|
||||||
|
var shortcodesInMask = Regex.Matches(mask, shortcodePattern).ToList();
|
||||||
|
|
||||||
|
if (shortcodesInMask.Count() == 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
var validShortcodes = GetShortcodesNames();
|
||||||
|
|
||||||
|
foreach (var shortcode in shortcodesInMask)
|
||||||
|
{
|
||||||
|
if (!validShortcodes.Contains(shortcode.ToString().ToUpper()))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<string> GetShortcodesNames()
|
||||||
|
{
|
||||||
|
var result = new List<string>();
|
||||||
|
var shortcodes = Enum.GetValues(typeof(ShortcodeEnum)).Cast<ShortcodeEnum>();
|
||||||
|
foreach (var item in shortcodes)
|
||||||
|
{
|
||||||
|
result.Add(Shortcodes.GetShortcodeName(item).ToUpper());
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
13
PARR.BLL/Services/Interfaces/ITemplateMaskValidator.cs
Normal file
13
PARR.BLL/Services/Interfaces/ITemplateMaskValidator.cs
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace PARR.BLL.Services.Interfaces
|
||||||
|
{
|
||||||
|
public interface ITemplateMaskValidator
|
||||||
|
{
|
||||||
|
bool IsValid(string mask);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -3,7 +3,8 @@
|
|||||||
public enum ShortcodeEnum
|
public enum ShortcodeEnum
|
||||||
{
|
{
|
||||||
EK,
|
EK,
|
||||||
ZO
|
ZO,
|
||||||
|
Work
|
||||||
//!!!Не забыть добавить в справочник имен (ShortcodeName) строковое значение
|
//!!!Не забыть добавить в справочник имен (ShortcodeName) строковое значение
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,13 +1,12 @@
|
|||||||
using System.Data.Common;
|
namespace PARR.Constants.Shortcodes
|
||||||
|
|
||||||
namespace PARR.Constants.Shortcodes
|
|
||||||
{
|
{
|
||||||
public static class Shortcodes
|
public static class Shortcodes
|
||||||
{
|
{
|
||||||
private static readonly List<ShortcodeItem> ShortcodesList = new List<ShortcodeItem>()
|
private static readonly List<ShortcodeItem> ShortcodesList = new List<ShortcodeItem>()
|
||||||
{
|
{
|
||||||
new ShortcodeItem { ShortcodeEnum = ShortcodeEnum.EK, Name = "%ЭК%", Description = "Элемент конфигурации"},
|
new ShortcodeItem { ShortcodeEnum = ShortcodeEnum.EK, Name = "%ЭК%", Description = "Элемент конфигурации"},
|
||||||
new ShortcodeItem { ShortcodeEnum = ShortcodeEnum.ZO, Name = "%ЗО%", Description = "Зона ответственности"}
|
new ShortcodeItem { ShortcodeEnum = ShortcodeEnum.ZO, Name = "%ЗО%", Description = "Зона ответственности"},
|
||||||
|
new ShortcodeItem { ShortcodeEnum = ShortcodeEnum.Work, Name = "%РАБОТА%", Description = "Наименование работ"}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -16,5 +15,9 @@ namespace PARR.Constants.Shortcodes
|
|||||||
return ShortcodesList.First(s => s.ShortcodeEnum == shortcode).Name;
|
return ShortcodesList.First(s => s.ShortcodeEnum == shortcode).Name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static List<ShortcodeItem> GetAll()
|
||||||
|
{
|
||||||
|
return ShortcodesList;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
3247
PARR.DAL/Migrations/20250417063402_tblWorksClmnTemplateNameMaskIsNotNull.Designer.cs
generated
Normal file
3247
PARR.DAL/Migrations/20250417063402_tblWorksClmnTemplateNameMaskIsNotNull.Designer.cs
generated
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,36 @@
|
|||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace PARR.DAL.Migrations
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
public partial class tblWorksClmnTemplateNameMaskIsNotNull : Migration
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.AlterColumn<string>(
|
||||||
|
name: "TemplateNameMask",
|
||||||
|
table: "Works",
|
||||||
|
type: "text",
|
||||||
|
nullable: false,
|
||||||
|
defaultValue: "",
|
||||||
|
oldClrType: typeof(string),
|
||||||
|
oldType: "text",
|
||||||
|
oldNullable: true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.AlterColumn<string>(
|
||||||
|
name: "TemplateNameMask",
|
||||||
|
table: "Works",
|
||||||
|
type: "text",
|
||||||
|
nullable: true,
|
||||||
|
oldClrType: typeof(string),
|
||||||
|
oldType: "text");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2611,6 +2611,7 @@ namespace PARR.DAL.Migrations
|
|||||||
.HasColumnType("text");
|
.HasColumnType("text");
|
||||||
|
|
||||||
b.Property<string>("TemplateNameMask")
|
b.Property<string>("TemplateNameMask")
|
||||||
|
.IsRequired()
|
||||||
.HasColumnType("text");
|
.HasColumnType("text");
|
||||||
|
|
||||||
b.Property<string>("TemplateSuffix")
|
b.Property<string>("TemplateSuffix")
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ namespace PARR.DAL.Models
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Маска для динамического формирования имени шаблона
|
/// Маска для динамического формирования имени шаблона
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string? TemplateNameMask { get; set; }
|
public required string TemplateNameMask { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Короткое имя, для формирования имени шаблона
|
/// Короткое имя, для формирования имени шаблона
|
||||||
|
|||||||
@@ -100,7 +100,8 @@ namespace PARR.MockData.Services
|
|||||||
DateCreated = DateTimeOffset.UtcNow,
|
DateCreated = DateTimeOffset.UtcNow,
|
||||||
Name = "Прочее(работы)",
|
Name = "Прочее(работы)",
|
||||||
EsppId = 292917,
|
EsppId = 292917,
|
||||||
TnkId = tnk.Id
|
TnkId = tnk.Id,
|
||||||
|
TemplateNameMask= "%ЗО%-ЭИТИ-ПТК-ПАРР__%ЭК%__%РАБОТА%"
|
||||||
};
|
};
|
||||||
if (!await workService.CreateAsync(work) || !await workService.CommitAsync())
|
if (!await workService.CreateAsync(work) || !await workService.CommitAsync())
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user