forked from ddrilling/AsbCloudServer
Merge branch 'dev' into feature/initial_screen
This commit is contained in:
commit
d1540ceb17
33
AsbCloudApp/Data/Manuals/ManualDirectoryDto.cs
Normal file
33
AsbCloudApp/Data/Manuals/ManualDirectoryDto.cs
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
|
namespace AsbCloudApp.Data.Manuals;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Директория для хранения инструкций
|
||||||
|
/// </summary>
|
||||||
|
public class ManualDirectoryDto : IId
|
||||||
|
{
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public int Id { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Название
|
||||||
|
/// </summary>
|
||||||
|
public string Name { get; set; } = null!;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Id родительской директории
|
||||||
|
/// </summary>
|
||||||
|
public int? IdParent { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Вложенные директории
|
||||||
|
/// </summary>
|
||||||
|
public IEnumerable<ManualDirectoryDto> Children { get; set; } = Enumerable.Empty<ManualDirectoryDto>();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Хранимые инструкции
|
||||||
|
/// </summary>
|
||||||
|
public IEnumerable<ManualDto> Manuals { get; set; } = Enumerable.Empty<ManualDto>();
|
||||||
|
}
|
37
AsbCloudApp/Data/Manuals/ManualDto.cs
Normal file
37
AsbCloudApp/Data/Manuals/ManualDto.cs
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace AsbCloudApp.Data.Manuals;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Инструкция
|
||||||
|
/// </summary>
|
||||||
|
public class ManualDto : IId
|
||||||
|
{
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public int Id { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Название
|
||||||
|
/// </summary>
|
||||||
|
public string Name { get; set; } = null!;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Дата загрузки
|
||||||
|
/// </summary>
|
||||||
|
public DateTime DateDownload { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Id автора
|
||||||
|
/// </summary>
|
||||||
|
public int IdAuthor { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Id директории
|
||||||
|
/// </summary>
|
||||||
|
public int IdDirectory { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Id категории файла
|
||||||
|
/// </summary>
|
||||||
|
public int IdCategory { get; set; }
|
||||||
|
}
|
@ -47,6 +47,13 @@ namespace AsbCloudApp.Repositories
|
|||||||
/// <param name="fileName"></param>
|
/// <param name="fileName"></param>
|
||||||
void DeleteFile(string fileName);
|
void DeleteFile(string fileName);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Удаление директории
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="path"></param>
|
||||||
|
/// <param name="isRecursive"></param>
|
||||||
|
void DeleteDirectory(string path, bool isRecursive);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Удаление всех файлов с диска о которых нет информации в базе
|
/// Удаление всех файлов с диска о которых нет информации в базе
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
37
AsbCloudApp/Repositories/IManualDirectoryRepository.cs
Normal file
37
AsbCloudApp/Repositories/IManualDirectoryRepository.cs
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using AsbCloudApp.Data.Manuals;
|
||||||
|
using AsbCloudApp.Services;
|
||||||
|
|
||||||
|
namespace AsbCloudApp.Repositories;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Репозиторий для работы с директориямиы хранящими инструкциями
|
||||||
|
/// </summary>
|
||||||
|
public interface IManualDirectoryRepository : ICrudRepository<ManualDirectoryDto>
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Получение дерева директорий
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="cancellationToken"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
Task<IEnumerable<ManualDirectoryDto>> GetTreeAsync(CancellationToken cancellationToken);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Получение одной директории по параметрам
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="name"></param>
|
||||||
|
/// <param name="idParent"></param>
|
||||||
|
/// <param name="cancellationToken"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
Task<ManualDirectoryDto?> GetOrDefaultAsync(string name, int? idParent, CancellationToken cancellationToken);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Проверка директории на существование
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="id"></param>
|
||||||
|
/// <param name="cancellationToken"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
Task<bool> IsExistsAsync(int id, CancellationToken cancellationToken);
|
||||||
|
}
|
64
AsbCloudApp/Services/IManualCatalogService.cs
Normal file
64
AsbCloudApp/Services/IManualCatalogService.cs
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
using System.IO;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace AsbCloudApp.Services;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Сервис для работы c каталогом инструкций
|
||||||
|
/// </summary>
|
||||||
|
public interface IManualCatalogService
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Сохранение файла
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="idDirectory"></param>
|
||||||
|
/// <param name="idAuthor"></param>
|
||||||
|
/// <param name="name"></param>
|
||||||
|
/// <param name="stream"></param>
|
||||||
|
/// <param name="cancellationToken"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
Task<int> SaveFileAsync(int idDirectory, int idAuthor, string name, Stream stream, CancellationToken cancellationToken);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Добавление директории
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="name"></param>
|
||||||
|
/// <param name="idParent"></param>
|
||||||
|
/// <param name="cancellationToken"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
Task<int> AddDirectoryAsync(string name, int? idParent, CancellationToken cancellationToken);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Обновление директории
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="id"></param>
|
||||||
|
/// <param name="name"></param>
|
||||||
|
/// <param name="cancellationToken"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
Task UpdateDirectoryAsync(int id, string name, CancellationToken cancellationToken);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Удаление директории
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="id"></param>
|
||||||
|
/// <param name="cancellationToken"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
Task<int> DeleteDirectoryAsync(int id, CancellationToken cancellationToken);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Удаление файла
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="id"></param>
|
||||||
|
/// <param name="cancellationToken"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
Task<int> DeleteFileAsync(int id, CancellationToken cancellationToken);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Получение файла
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="id"></param>
|
||||||
|
/// <param name="cancellationToken"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
Task<(Stream stream, string fileName)?> GetFileAsync(int id, CancellationToken cancellationToken);
|
||||||
|
}
|
8539
AsbCloudDb/Migrations/20230907070954_Add_Manuals.Designer.cs
generated
Normal file
8539
AsbCloudDb/Migrations/20230907070954_Add_Manuals.Designer.cs
generated
Normal file
File diff suppressed because it is too large
Load Diff
148
AsbCloudDb/Migrations/20230907070954_Add_Manuals.cs
Normal file
148
AsbCloudDb/Migrations/20230907070954_Add_Manuals.cs
Normal file
@ -0,0 +1,148 @@
|
|||||||
|
using System;
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace AsbCloudDb.Migrations
|
||||||
|
{
|
||||||
|
public partial class Add_Manuals : Migration
|
||||||
|
{
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "t_manual_directory",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
id = table.Column<int>(type: "integer", nullable: false)
|
||||||
|
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
|
||||||
|
name = table.Column<string>(type: "text", nullable: false, comment: "Название"),
|
||||||
|
id_parent = table.Column<int>(type: "integer", nullable: true, comment: "Id родительской директории")
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_t_manual_directory", x => x.id);
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "FK_t_manual_directory_t_manual_directory_id_parent",
|
||||||
|
column: x => x.id_parent,
|
||||||
|
principalTable: "t_manual_directory",
|
||||||
|
principalColumn: "id",
|
||||||
|
onDelete: ReferentialAction.Cascade);
|
||||||
|
},
|
||||||
|
comment: "Директория для инструкций");
|
||||||
|
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "t_manual",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
id = table.Column<int>(type: "integer", nullable: false)
|
||||||
|
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
|
||||||
|
name = table.Column<string>(type: "text", nullable: false, comment: "Название"),
|
||||||
|
date_download = table.Column<DateTime>(type: "timestamp with time zone", nullable: false, comment: "Дата загрузки"),
|
||||||
|
id_directory = table.Column<int>(type: "integer", nullable: false, comment: "Id директории"),
|
||||||
|
id_category = table.Column<int>(type: "integer", nullable: false, comment: "Id категории файла"),
|
||||||
|
id_author = table.Column<int>(type: "integer", nullable: false, comment: "Id автора")
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_t_manual", x => x.id);
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "FK_t_manual_t_file_category_id_category",
|
||||||
|
column: x => x.id_category,
|
||||||
|
principalTable: "t_file_category",
|
||||||
|
principalColumn: "id",
|
||||||
|
onDelete: ReferentialAction.Cascade);
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "FK_t_manual_t_manual_directory_id_directory",
|
||||||
|
column: x => x.id_directory,
|
||||||
|
principalTable: "t_manual_directory",
|
||||||
|
principalColumn: "id",
|
||||||
|
onDelete: ReferentialAction.Cascade);
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "FK_t_manual_t_user_id_author",
|
||||||
|
column: x => x.id_author,
|
||||||
|
principalTable: "t_user",
|
||||||
|
principalColumn: "id",
|
||||||
|
onDelete: ReferentialAction.Cascade);
|
||||||
|
},
|
||||||
|
comment: "Инструкции");
|
||||||
|
|
||||||
|
migrationBuilder.InsertData(
|
||||||
|
table: "t_file_category",
|
||||||
|
columns: new[] { "id", "name", "short_name" },
|
||||||
|
values: new object[] { 30000, "Инструкции", null });
|
||||||
|
|
||||||
|
migrationBuilder.InsertData(
|
||||||
|
table: "t_permission",
|
||||||
|
columns: new[] { "id", "description", "name" },
|
||||||
|
values: new object[,]
|
||||||
|
{
|
||||||
|
{ 523, "Разрешить редактирование инструкций", "Manual.edit" },
|
||||||
|
{ 524, "Разрешить получение инструкций", "Manual.get" }
|
||||||
|
});
|
||||||
|
|
||||||
|
migrationBuilder.InsertData(
|
||||||
|
table: "t_relation_user_role_permission",
|
||||||
|
columns: new[] { "id_permission", "id_user_role" },
|
||||||
|
values: new object[,]
|
||||||
|
{
|
||||||
|
{ 523, 1 },
|
||||||
|
{ 524, 1 }
|
||||||
|
});
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_t_manual_id_author",
|
||||||
|
table: "t_manual",
|
||||||
|
column: "id_author");
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_t_manual_id_category",
|
||||||
|
table: "t_manual",
|
||||||
|
column: "id_category");
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_t_manual_id_directory",
|
||||||
|
table: "t_manual",
|
||||||
|
column: "id_directory");
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_t_manual_directory_id_parent",
|
||||||
|
table: "t_manual_directory",
|
||||||
|
column: "id_parent");
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "t_manual");
|
||||||
|
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "t_manual_directory");
|
||||||
|
|
||||||
|
migrationBuilder.DeleteData(
|
||||||
|
table: "t_file_category",
|
||||||
|
keyColumn: "id",
|
||||||
|
keyValue: 30000);
|
||||||
|
|
||||||
|
migrationBuilder.DeleteData(
|
||||||
|
table: "t_relation_user_role_permission",
|
||||||
|
keyColumns: new[] { "id_permission", "id_user_role" },
|
||||||
|
keyValues: new object[] { 523, 1 });
|
||||||
|
|
||||||
|
migrationBuilder.DeleteData(
|
||||||
|
table: "t_relation_user_role_permission",
|
||||||
|
keyColumns: new[] { "id_permission", "id_user_role" },
|
||||||
|
keyValues: new object[] { 524, 1 });
|
||||||
|
|
||||||
|
migrationBuilder.DeleteData(
|
||||||
|
table: "t_permission",
|
||||||
|
keyColumn: "id",
|
||||||
|
keyValue: 523);
|
||||||
|
|
||||||
|
migrationBuilder.DeleteData(
|
||||||
|
table: "t_permission",
|
||||||
|
keyColumn: "id",
|
||||||
|
keyValue: 524);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -785,6 +785,11 @@ namespace AsbCloudDb.Migrations
|
|||||||
{
|
{
|
||||||
Id = 20000,
|
Id = 20000,
|
||||||
Name = "Справки по страницам"
|
Name = "Справки по страницам"
|
||||||
|
},
|
||||||
|
new
|
||||||
|
{
|
||||||
|
Id = 30000,
|
||||||
|
Name = "Инструкции"
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -1066,6 +1071,83 @@ namespace AsbCloudDb.Migrations
|
|||||||
b.HasComment("Ограничения по параметрам телеметрии");
|
b.HasComment("Ограничения по параметрам телеметрии");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("AsbCloudDb.Model.Manuals.Manual", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("integer")
|
||||||
|
.HasColumnName("id");
|
||||||
|
|
||||||
|
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
|
||||||
|
|
||||||
|
b.Property<DateTime>("DateDownload")
|
||||||
|
.HasColumnType("timestamp with time zone")
|
||||||
|
.HasColumnName("date_download")
|
||||||
|
.HasComment("Дата загрузки");
|
||||||
|
|
||||||
|
b.Property<int>("IdAuthor")
|
||||||
|
.HasColumnType("integer")
|
||||||
|
.HasColumnName("id_author")
|
||||||
|
.HasComment("Id автора");
|
||||||
|
|
||||||
|
b.Property<int>("IdCategory")
|
||||||
|
.HasColumnType("integer")
|
||||||
|
.HasColumnName("id_category")
|
||||||
|
.HasComment("Id категории файла");
|
||||||
|
|
||||||
|
b.Property<int>("IdDirectory")
|
||||||
|
.HasColumnType("integer")
|
||||||
|
.HasColumnName("id_directory")
|
||||||
|
.HasComment("Id директории");
|
||||||
|
|
||||||
|
b.Property<string>("Name")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("text")
|
||||||
|
.HasColumnName("name")
|
||||||
|
.HasComment("Название");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("IdAuthor");
|
||||||
|
|
||||||
|
b.HasIndex("IdCategory");
|
||||||
|
|
||||||
|
b.HasIndex("IdDirectory");
|
||||||
|
|
||||||
|
b.ToTable("t_manual");
|
||||||
|
|
||||||
|
b.HasComment("Инструкции");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("AsbCloudDb.Model.Manuals.ManualDirectory", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("integer")
|
||||||
|
.HasColumnName("id");
|
||||||
|
|
||||||
|
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
|
||||||
|
|
||||||
|
b.Property<int?>("IdParent")
|
||||||
|
.HasColumnType("integer")
|
||||||
|
.HasColumnName("id_parent")
|
||||||
|
.HasComment("Id родительской директории");
|
||||||
|
|
||||||
|
b.Property<string>("Name")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("text")
|
||||||
|
.HasColumnName("name")
|
||||||
|
.HasComment("Название");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("IdParent");
|
||||||
|
|
||||||
|
b.ToTable("t_manual_directory");
|
||||||
|
|
||||||
|
b.HasComment("Директория для инструкций");
|
||||||
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("AsbCloudDb.Model.Measure", b =>
|
modelBuilder.Entity("AsbCloudDb.Model.Measure", b =>
|
||||||
{
|
{
|
||||||
b.Property<int>("Id")
|
b.Property<int>("Id")
|
||||||
@ -2165,6 +2247,18 @@ namespace AsbCloudDb.Migrations
|
|||||||
Name = "UserSettings.delete"
|
Name = "UserSettings.delete"
|
||||||
},
|
},
|
||||||
new
|
new
|
||||||
|
{
|
||||||
|
Id = 523,
|
||||||
|
Description = "Разрешить редактирование инструкций",
|
||||||
|
Name = "Manual.edit"
|
||||||
|
},
|
||||||
|
new
|
||||||
|
{
|
||||||
|
Id = 524,
|
||||||
|
Description = "Разрешить получение инструкций",
|
||||||
|
Name = "Manual.get"
|
||||||
|
},
|
||||||
|
new
|
||||||
{
|
{
|
||||||
Id = 525,
|
Id = 525,
|
||||||
Description = "Разрешение на редактирование РТК у завершенной скважины",
|
Description = "Разрешение на редактирование РТК у завершенной скважины",
|
||||||
@ -3719,6 +3813,16 @@ namespace AsbCloudDb.Migrations
|
|||||||
IdPermission = 522
|
IdPermission = 522
|
||||||
},
|
},
|
||||||
new
|
new
|
||||||
|
{
|
||||||
|
IdUserRole = 1,
|
||||||
|
IdPermission = 523
|
||||||
|
},
|
||||||
|
new
|
||||||
|
{
|
||||||
|
IdUserRole = 1,
|
||||||
|
IdPermission = 524
|
||||||
|
},
|
||||||
|
new
|
||||||
{
|
{
|
||||||
IdUserRole = 1,
|
IdUserRole = 1,
|
||||||
IdPermission = 525
|
IdPermission = 525
|
||||||
@ -7659,6 +7763,43 @@ namespace AsbCloudDb.Migrations
|
|||||||
b.Navigation("Telemetry");
|
b.Navigation("Telemetry");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("AsbCloudDb.Model.Manuals.Manual", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("AsbCloudDb.Model.User", "Author")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("IdAuthor")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.HasOne("AsbCloudDb.Model.FileCategory", "Category")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("IdCategory")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.HasOne("AsbCloudDb.Model.Manuals.ManualDirectory", "Directory")
|
||||||
|
.WithMany("Manuals")
|
||||||
|
.HasForeignKey("IdDirectory")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("Author");
|
||||||
|
|
||||||
|
b.Navigation("Category");
|
||||||
|
|
||||||
|
b.Navigation("Directory");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("AsbCloudDb.Model.Manuals.ManualDirectory", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("AsbCloudDb.Model.Manuals.ManualDirectory", "Parent")
|
||||||
|
.WithMany("Children")
|
||||||
|
.HasForeignKey("IdParent")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade);
|
||||||
|
|
||||||
|
b.Navigation("Parent");
|
||||||
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("AsbCloudDb.Model.Measure", b =>
|
modelBuilder.Entity("AsbCloudDb.Model.Measure", b =>
|
||||||
{
|
{
|
||||||
b.HasOne("AsbCloudDb.Model.MeasureCategory", "Category")
|
b.HasOne("AsbCloudDb.Model.MeasureCategory", "Category")
|
||||||
@ -8284,6 +8425,13 @@ namespace AsbCloudDb.Migrations
|
|||||||
b.Navigation("FileMarks");
|
b.Navigation("FileMarks");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("AsbCloudDb.Model.Manuals.ManualDirectory", b =>
|
||||||
|
{
|
||||||
|
b.Navigation("Children");
|
||||||
|
|
||||||
|
b.Navigation("Manuals");
|
||||||
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("AsbCloudDb.Model.MeasureCategory", b =>
|
modelBuilder.Entity("AsbCloudDb.Model.MeasureCategory", b =>
|
||||||
{
|
{
|
||||||
b.Navigation("Measures");
|
b.Navigation("Measures");
|
||||||
|
@ -3,6 +3,7 @@ using AsbCloudDb.Model.Subsystems;
|
|||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using AsbCloudDb.Model.Manuals;
|
||||||
|
|
||||||
namespace AsbCloudDb.Model
|
namespace AsbCloudDb.Model
|
||||||
{
|
{
|
||||||
@ -77,6 +78,9 @@ namespace AsbCloudDb.Model
|
|||||||
public DbSet<HelpPage> HelpPages => Set<HelpPage>();
|
public DbSet<HelpPage> HelpPages => Set<HelpPage>();
|
||||||
public DbSet<Notification> Notifications => Set<Notification>();
|
public DbSet<Notification> Notifications => Set<Notification>();
|
||||||
public DbSet<NotificationCategory> NotificationCategories => Set<NotificationCategory>();
|
public DbSet<NotificationCategory> NotificationCategories => Set<NotificationCategory>();
|
||||||
|
public DbSet<Manual> Manuals => Set<Manual>();
|
||||||
|
public DbSet<ManualDirectory> ManualDirectories => Set<ManualDirectory>();
|
||||||
|
|
||||||
|
|
||||||
public AsbCloudDbContext() : base()
|
public AsbCloudDbContext() : base()
|
||||||
{
|
{
|
||||||
@ -388,6 +392,18 @@ namespace AsbCloudDb.Model
|
|||||||
entity.HasKey(x => new { x.IdWell, x.IdUser });
|
entity.HasKey(x => new { x.IdWell, x.IdUser });
|
||||||
});
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity<ManualDirectory>()
|
||||||
|
.HasOne(mf => mf.Parent)
|
||||||
|
.WithMany(mf => mf.Children)
|
||||||
|
.HasForeignKey(mf => mf.IdParent)
|
||||||
|
.OnDelete(DeleteBehavior.Cascade);
|
||||||
|
|
||||||
|
modelBuilder.Entity<Manual>()
|
||||||
|
.HasOne(m => m.Directory)
|
||||||
|
.WithMany(f => f.Manuals)
|
||||||
|
.HasForeignKey(m => m.IdDirectory)
|
||||||
|
.OnDelete(DeleteBehavior.Cascade);
|
||||||
|
|
||||||
DefaultData.DefaultContextData.Fill(modelBuilder);
|
DefaultData.DefaultContextData.Fill(modelBuilder);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -73,7 +73,9 @@
|
|||||||
new () {Id = 10042, Name = "Паспорт скважины (заполняется геологами)"},
|
new () {Id = 10042, Name = "Паспорт скважины (заполняется геологами)"},
|
||||||
new () {Id = 10043, Name = "Фактические данные бурения (вставляются в паспорт скважины)"},
|
new () {Id = 10043, Name = "Фактические данные бурения (вставляются в паспорт скважины)"},
|
||||||
|
|
||||||
new () {Id = 20000, Name = "Справки по страницам"}
|
new () {Id = 20000, Name = "Справки по страницам"},
|
||||||
|
|
||||||
|
new() { Id = 30000, Name = "Инструкции"},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -156,6 +156,9 @@
|
|||||||
new() { Id = 521, Name = "HelpPage.edit", Description = "Разрешить создание справок по страницам"},
|
new() { Id = 521, Name = "HelpPage.edit", Description = "Разрешить создание справок по страницам"},
|
||||||
|
|
||||||
new() { Id = 522, Name = "UserSettings.delete", Description = "Разрешить удаление всех настроек пользователя"},
|
new() { Id = 522, Name = "UserSettings.delete", Description = "Разрешить удаление всех настроек пользователя"},
|
||||||
|
|
||||||
|
new() { Id = 523, Name = "Manual.edit", Description = "Разрешить редактирование инструкций" },
|
||||||
|
new() { Id = 524, Name = "Manual.get", Description = "Разрешить получение инструкций"},
|
||||||
|
|
||||||
new (){ Id = 525, Name = "ProcessMap.editCompletedWell", Description = "Разрешение на редактирование РТК у завершенной скважины"},
|
new (){ Id = 525, Name = "ProcessMap.editCompletedWell", Description = "Разрешение на редактирование РТК у завершенной скважины"},
|
||||||
new (){ Id = 526, Name = "WellOperation.editCompletedWell", Description = "Разрешение на редактирование операций у завершенной скважины"}
|
new (){ Id = 526, Name = "WellOperation.editCompletedWell", Description = "Разрешение на редактирование операций у завершенной скважины"}
|
||||||
|
@ -7,6 +7,7 @@ using Microsoft.EntityFrameworkCore.Infrastructure;
|
|||||||
using System;
|
using System;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using AsbCloudDb.Model.Manuals;
|
||||||
|
|
||||||
namespace AsbCloudDb.Model
|
namespace AsbCloudDb.Model
|
||||||
{
|
{
|
||||||
@ -70,6 +71,8 @@ namespace AsbCloudDb.Model
|
|||||||
DbSet<HelpPage> HelpPages { get; }
|
DbSet<HelpPage> HelpPages { get; }
|
||||||
DbSet<Notification> Notifications { get; }
|
DbSet<Notification> Notifications { get; }
|
||||||
DbSet<NotificationCategory> NotificationCategories { get; }
|
DbSet<NotificationCategory> NotificationCategories { get; }
|
||||||
|
DbSet<Manual> Manuals { get; }
|
||||||
|
DbSet<ManualDirectory> ManualDirectories { get; }
|
||||||
DatabaseFacade Database { get; }
|
DatabaseFacade Database { get; }
|
||||||
|
|
||||||
Task<int> RefreshMaterializedViewAsync(string mwName, CancellationToken token);
|
Task<int> RefreshMaterializedViewAsync(string mwName, CancellationToken token);
|
||||||
|
38
AsbCloudDb/Model/Manuals/Manual.cs
Normal file
38
AsbCloudDb/Model/Manuals/Manual.cs
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
using System;
|
||||||
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
using System.ComponentModel.DataAnnotations.Schema;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
|
||||||
|
namespace AsbCloudDb.Model.Manuals;
|
||||||
|
|
||||||
|
[Table("t_manual"), Comment("Инструкции")]
|
||||||
|
public class Manual : IId
|
||||||
|
{
|
||||||
|
[Key]
|
||||||
|
[Column("id")]
|
||||||
|
public int Id { get; set; }
|
||||||
|
|
||||||
|
[Column("name"), Comment("Название")]
|
||||||
|
public string Name { get; set; } = null!;
|
||||||
|
|
||||||
|
[Column("date_download"), Comment("Дата загрузки")]
|
||||||
|
public DateTime DateDownload { get; set; }
|
||||||
|
|
||||||
|
[Column("id_directory"), Comment("Id директории")]
|
||||||
|
public int IdDirectory { get; set; }
|
||||||
|
|
||||||
|
[Column("id_category"), Comment("Id категории файла")]
|
||||||
|
public int IdCategory { get; set; }
|
||||||
|
|
||||||
|
[Column("id_author"), Comment("Id автора")]
|
||||||
|
public int IdAuthor { get; set; }
|
||||||
|
|
||||||
|
[ForeignKey(nameof(IdDirectory))]
|
||||||
|
public virtual ManualDirectory Directory { get; set; } = null!;
|
||||||
|
|
||||||
|
[ForeignKey(nameof(IdCategory))]
|
||||||
|
public virtual FileCategory Category { get; set; } = null!;
|
||||||
|
|
||||||
|
[ForeignKey(nameof(IdAuthor))]
|
||||||
|
public virtual User Author { get; set; } = null!;
|
||||||
|
}
|
27
AsbCloudDb/Model/Manuals/ManualDirectory.cs
Normal file
27
AsbCloudDb/Model/Manuals/ManualDirectory.cs
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
using System.ComponentModel.DataAnnotations.Schema;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
|
||||||
|
namespace AsbCloudDb.Model.Manuals;
|
||||||
|
|
||||||
|
[Table("t_manual_directory"), Comment("Директория для инструкций")]
|
||||||
|
public class ManualDirectory : IId
|
||||||
|
{
|
||||||
|
[Key]
|
||||||
|
[Column("id")]
|
||||||
|
public int Id { get; set; }
|
||||||
|
|
||||||
|
[Column("name"), Comment("Название")]
|
||||||
|
public string Name { get; set; } = null!;
|
||||||
|
|
||||||
|
[Column("id_parent"), Comment("Id родительской директории")]
|
||||||
|
public int? IdParent { get; set; }
|
||||||
|
|
||||||
|
[ForeignKey(nameof(IdParent))]
|
||||||
|
public virtual ManualDirectory? Parent { get; set; }
|
||||||
|
|
||||||
|
public virtual ICollection<ManualDirectory>? Children { get; set; }
|
||||||
|
|
||||||
|
public virtual ICollection<Manual>? Manuals { get; set; }
|
||||||
|
}
|
@ -23,8 +23,10 @@ using Microsoft.Extensions.Caching.Memory;
|
|||||||
using Microsoft.Extensions.Configuration;
|
using Microsoft.Extensions.Configuration;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using System;
|
using System;
|
||||||
|
using AsbCloudApp.Data.Manuals;
|
||||||
using AsbCloudApp.Services.AutoGeneratedDailyReports;
|
using AsbCloudApp.Services.AutoGeneratedDailyReports;
|
||||||
using AsbCloudApp.Services.Notifications;
|
using AsbCloudApp.Services.Notifications;
|
||||||
|
using AsbCloudDb.Model.Manuals;
|
||||||
using AsbCloudInfrastructure.Services.AutoGeneratedDailyReports;
|
using AsbCloudInfrastructure.Services.AutoGeneratedDailyReports;
|
||||||
|
|
||||||
namespace AsbCloudInfrastructure
|
namespace AsbCloudInfrastructure
|
||||||
@ -221,6 +223,10 @@ namespace AsbCloudInfrastructure
|
|||||||
|
|
||||||
services.AddTransient<IAutoGeneratedDailyReportService, AutoGeneratedDailyReportService>();
|
services.AddTransient<IAutoGeneratedDailyReportService, AutoGeneratedDailyReportService>();
|
||||||
services.AddTransient<IAutoGeneratedDailyReportMakerService, AutoGeneratedDailyReportMakerService>();
|
services.AddTransient<IAutoGeneratedDailyReportMakerService, AutoGeneratedDailyReportMakerService>();
|
||||||
|
|
||||||
|
services.AddTransient<IManualDirectoryRepository, ManualDirectoryRepository>();
|
||||||
|
services.AddTransient<IManualCatalogService, ManualCatalogService>();
|
||||||
|
services.AddTransient<ICrudRepository<ManualDto>, CrudRepositoryBase<ManualDto, Manual>>();
|
||||||
|
|
||||||
services.AddTransient<IWellboreService, WellboreService>();
|
services.AddTransient<IWellboreService, WellboreService>();
|
||||||
|
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
using AsbCloudApp.Data;
|
using System;
|
||||||
|
using AsbCloudApp.Data;
|
||||||
using AsbCloudApp.Repositories;
|
using AsbCloudApp.Repositories;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
@ -33,6 +34,23 @@ public class FileStorageRepository : IFileStorageRepository
|
|||||||
DeleteFile(fileName);
|
DeleteFile(fileName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void DeleteDirectory(string path, bool isRecursive)
|
||||||
|
{
|
||||||
|
if (!Directory.Exists(path))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!isRecursive)
|
||||||
|
{
|
||||||
|
var files = Directory.GetFiles(path);
|
||||||
|
var directories = Directory.GetDirectories(path);
|
||||||
|
|
||||||
|
if (files.Length != 0 || directories.Length != 0)
|
||||||
|
throw new InvalidOperationException("Директория не пуста и не может быть удалена");
|
||||||
|
}
|
||||||
|
|
||||||
|
Directory.Delete(path, isRecursive);
|
||||||
|
}
|
||||||
|
|
||||||
public void DeleteFile(string fileName)
|
public void DeleteFile(string fileName)
|
||||||
{
|
{
|
||||||
|
@ -0,0 +1,62 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using AsbCloudApp.Data.Manuals;
|
||||||
|
using AsbCloudApp.Repositories;
|
||||||
|
using AsbCloudDb.Model;
|
||||||
|
using AsbCloudDb.Model.Manuals;
|
||||||
|
using Mapster;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
|
||||||
|
namespace AsbCloudInfrastructure.Repository;
|
||||||
|
|
||||||
|
public class ManualDirectoryRepository : CrudRepositoryBase<ManualDirectoryDto, ManualDirectory>, IManualDirectoryRepository
|
||||||
|
{
|
||||||
|
public ManualDirectoryRepository(IAsbCloudDbContext context) : base(context)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<IEnumerable<ManualDirectoryDto>> GetTreeAsync(CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
var directories = await dbContext.ManualDirectories
|
||||||
|
.Include(m => m.Manuals)
|
||||||
|
.Include(m => m.Parent)
|
||||||
|
.AsNoTracking()
|
||||||
|
.ToArrayAsync(cancellationToken);
|
||||||
|
|
||||||
|
return BuildTree(directories).Select(x => x.Adapt<ManualDirectoryDto>());
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<ManualDirectoryDto?> GetOrDefaultAsync(string name, int? idParent, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
var entity = await dbContext.ManualDirectories
|
||||||
|
.AsNoTracking()
|
||||||
|
.FirstOrDefaultAsync(m => m.Name == name &&
|
||||||
|
m.IdParent == idParent, cancellationToken);
|
||||||
|
|
||||||
|
if (entity is null)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
return Convert(entity);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<bool> IsExistsAsync(int id, CancellationToken cancellationToken) =>
|
||||||
|
dbContext.ManualDirectories.AnyAsync(d => d.Id == id, cancellationToken);
|
||||||
|
|
||||||
|
private static IEnumerable<ManualDirectory> BuildTree(IEnumerable<ManualDirectory> directories)
|
||||||
|
{
|
||||||
|
var directoryDict = directories.ToDictionary(f => f.Id);
|
||||||
|
|
||||||
|
foreach (var directory in directories)
|
||||||
|
{
|
||||||
|
if (directory.IdParent.HasValue && directoryDict.TryGetValue(directory.IdParent.Value, out var parent))
|
||||||
|
{
|
||||||
|
parent.Children ??= new List<ManualDirectory>();
|
||||||
|
parent.Children.Add(directory);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return directories.Where(f => f.IdParent == null);
|
||||||
|
}
|
||||||
|
}
|
180
AsbCloudInfrastructure/Services/ManualCatalogService.cs
Normal file
180
AsbCloudInfrastructure/Services/ManualCatalogService.cs
Normal file
@ -0,0 +1,180 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using AsbCloudApp.Data.Manuals;
|
||||||
|
using AsbCloudApp.Exceptions;
|
||||||
|
using AsbCloudApp.Repositories;
|
||||||
|
using AsbCloudApp.Services;
|
||||||
|
using Microsoft.Extensions.Configuration;
|
||||||
|
|
||||||
|
namespace AsbCloudInfrastructure.Services;
|
||||||
|
|
||||||
|
public class ManualCatalogService : IManualCatalogService
|
||||||
|
{
|
||||||
|
private const int IdFileCategory = 30000;
|
||||||
|
|
||||||
|
private readonly IEnumerable<string> validExtensions = new[]
|
||||||
|
{
|
||||||
|
".pdf",
|
||||||
|
".mp4"
|
||||||
|
};
|
||||||
|
|
||||||
|
private readonly string directoryFiles;
|
||||||
|
private readonly IFileStorageRepository fileStorageRepository;
|
||||||
|
private readonly IManualDirectoryRepository manualDirectoryRepository;
|
||||||
|
private readonly ICrudRepository<ManualDto> manualRepository;
|
||||||
|
|
||||||
|
public ManualCatalogService(IFileStorageRepository fileStorageRepository,
|
||||||
|
IManualDirectoryRepository manualDirectoryRepository,
|
||||||
|
ICrudRepository<ManualDto> manualRepository,
|
||||||
|
IConfiguration configuration)
|
||||||
|
{
|
||||||
|
this.fileStorageRepository = fileStorageRepository;
|
||||||
|
this.manualDirectoryRepository = manualDirectoryRepository;
|
||||||
|
this.manualRepository = manualRepository;
|
||||||
|
directoryFiles = configuration.GetValue<string>("DirectoryManualFiles");
|
||||||
|
|
||||||
|
if (string.IsNullOrWhiteSpace(directoryFiles))
|
||||||
|
directoryFiles = "manuals";
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<int> SaveFileAsync(int idDirectory, int idAuthor, string name, Stream stream, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
var extension = Path.GetExtension(name);
|
||||||
|
|
||||||
|
if (!validExtensions.Contains(extension))
|
||||||
|
throw new ArgumentInvalidException(
|
||||||
|
$"Невозможно загрузить файл с расширением '{extension}'. Допустимые форматы файлов: {string.Join(", ", validExtensions)}",
|
||||||
|
extension);
|
||||||
|
|
||||||
|
var path = await BuildFilePathAsync(idDirectory, name, cancellationToken);
|
||||||
|
|
||||||
|
await fileStorageRepository.SaveFileAsync(path, stream, cancellationToken);
|
||||||
|
|
||||||
|
var manual = new ManualDto
|
||||||
|
{
|
||||||
|
Name = name,
|
||||||
|
DateDownload = DateTime.UtcNow,
|
||||||
|
IdDirectory = idDirectory,
|
||||||
|
IdCategory = IdFileCategory,
|
||||||
|
IdAuthor = idAuthor
|
||||||
|
};
|
||||||
|
|
||||||
|
return await manualRepository.InsertAsync(manual, cancellationToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<int> AddDirectoryAsync(string name, int? idParent, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
if (idParent.HasValue && !await manualDirectoryRepository.IsExistsAsync(idParent.Value, cancellationToken))
|
||||||
|
throw new ArgumentInvalidException("Родительской директории не существует", nameof(idParent));
|
||||||
|
|
||||||
|
var directory = new ManualDirectoryDto
|
||||||
|
{
|
||||||
|
Name = name,
|
||||||
|
IdParent = idParent,
|
||||||
|
};
|
||||||
|
|
||||||
|
if (await IsExistDirectoryAsync(directory, cancellationToken))
|
||||||
|
throw new ArgumentInvalidException("Директория с таким названием уже существует", name);
|
||||||
|
|
||||||
|
return await manualDirectoryRepository.InsertAsync(directory, cancellationToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task UpdateDirectoryAsync(int id, string name, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
var directory = await manualDirectoryRepository.GetOrDefaultAsync(id, cancellationToken)
|
||||||
|
?? throw new ArgumentInvalidException($"Директории с Id: {id} не существует", nameof(id));
|
||||||
|
|
||||||
|
directory.Name = name;
|
||||||
|
|
||||||
|
if (await IsExistDirectoryAsync(directory, cancellationToken))
|
||||||
|
throw new ArgumentInvalidException("Директория с таким названием уже существует", name);
|
||||||
|
|
||||||
|
await manualDirectoryRepository.UpdateAsync(directory, cancellationToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<int> DeleteDirectoryAsync(int id, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
var directory = await manualDirectoryRepository.GetOrDefaultAsync(id, cancellationToken);
|
||||||
|
|
||||||
|
if (directory is null)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
var path = fileStorageRepository.MakeFilePath(directoryFiles, IdFileCategory.ToString(),
|
||||||
|
await BuildDirectoryPathAsync(id, cancellationToken));
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
fileStorageRepository.DeleteDirectory(path, true);
|
||||||
|
}
|
||||||
|
catch (InvalidOperationException ex)
|
||||||
|
{
|
||||||
|
throw new ArgumentInvalidException(ex.Message, nameof(id));
|
||||||
|
}
|
||||||
|
|
||||||
|
return await manualDirectoryRepository.DeleteAsync(directory.Id, cancellationToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<int> DeleteFileAsync(int id, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
var manual = await manualRepository.GetOrDefaultAsync(id, cancellationToken);
|
||||||
|
|
||||||
|
if (manual is null)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
var filePath = await BuildFilePathAsync(manual.IdDirectory, manual.Name, cancellationToken);
|
||||||
|
|
||||||
|
fileStorageRepository.DeleteFile(filePath);
|
||||||
|
|
||||||
|
return await manualRepository.DeleteAsync(manual.Id, cancellationToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<(Stream stream, string fileName)?> GetFileAsync(int id, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
var manual = await manualRepository.GetOrDefaultAsync(id, cancellationToken);
|
||||||
|
|
||||||
|
if (manual is null)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
var path = await BuildFilePathAsync(manual.IdDirectory, manual.Name, cancellationToken);
|
||||||
|
var fileStream = new FileStream(path, FileMode.Open);
|
||||||
|
return (fileStream, manual.Name);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task<bool> IsExistDirectoryAsync(ManualDirectoryDto directory, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
var existingDirectory = await manualDirectoryRepository.GetOrDefaultAsync(directory.Name, directory.IdParent,
|
||||||
|
cancellationToken);
|
||||||
|
|
||||||
|
return existingDirectory is not null && directory.Id != existingDirectory.Id;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task<string> BuildDirectoryPathAsync(int idDirectory, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
var directiories = await manualDirectoryRepository.GetAllAsync(cancellationToken);
|
||||||
|
|
||||||
|
var directory = directiories.FirstOrDefault(d => d.Id == idDirectory)
|
||||||
|
?? throw new ArgumentInvalidException($"Директории с Id: {idDirectory} не существует", nameof(idDirectory));
|
||||||
|
|
||||||
|
var pathSegments = new List<int> { directory.Id };
|
||||||
|
|
||||||
|
while (directory.IdParent.HasValue)
|
||||||
|
{
|
||||||
|
directory = directiories.FirstOrDefault(d => d.Id == directory.IdParent.Value);
|
||||||
|
|
||||||
|
pathSegments.Insert(0, directory.Id);
|
||||||
|
}
|
||||||
|
|
||||||
|
return string.Join("/", pathSegments);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task<string> BuildFilePathAsync(int idDirectory, string name, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
var directoryPath = await BuildDirectoryPathAsync(idDirectory, cancellationToken);
|
||||||
|
|
||||||
|
return fileStorageRepository.MakeFilePath(directoryFiles, IdFileCategory.ToString(), Path.Combine(directoryPath, name));
|
||||||
|
}
|
||||||
|
}
|
105
AsbCloudWebApi/Controllers/ManualController.cs
Normal file
105
AsbCloudWebApi/Controllers/ManualController.cs
Normal file
@ -0,0 +1,105 @@
|
|||||||
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using AsbCloudApp.Exceptions;
|
||||||
|
using AsbCloudApp.Repositories;
|
||||||
|
using AsbCloudApp.Services;
|
||||||
|
using Microsoft.AspNetCore.Authorization;
|
||||||
|
using Microsoft.AspNetCore.Http;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
|
||||||
|
namespace AsbCloudWebApi.Controllers;
|
||||||
|
|
||||||
|
[ApiController]
|
||||||
|
[Route("api/[controller]")]
|
||||||
|
[Authorize]
|
||||||
|
public class ManualController : ControllerBase
|
||||||
|
{
|
||||||
|
private readonly IManualCatalogService manualCatalogService;
|
||||||
|
private readonly IUserRepository userRepository;
|
||||||
|
|
||||||
|
public ManualController(IManualCatalogService manualCatalogService,
|
||||||
|
IUserRepository userRepository)
|
||||||
|
{
|
||||||
|
this.manualCatalogService = manualCatalogService;
|
||||||
|
this.userRepository = userRepository;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Сохранение файла
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="idDirectory">Id директории</param>
|
||||||
|
/// <param name="file">Загружаемый файл</param>
|
||||||
|
/// <param name="cancellationToken"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
[HttpPost]
|
||||||
|
[Permission]
|
||||||
|
[ProducesResponseType(typeof(int), StatusCodes.Status200OK)]
|
||||||
|
[ProducesResponseType(StatusCodes.Status400BadRequest)]
|
||||||
|
[ProducesResponseType(StatusCodes.Status403Forbidden)]
|
||||||
|
public async Task<IActionResult> SaveFileAsync(int idDirectory,
|
||||||
|
[Required] IFormFile file,
|
||||||
|
CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
var idUser = User.GetUserId();
|
||||||
|
|
||||||
|
if(!idUser.HasValue)
|
||||||
|
throw new ForbidException("Не удается вас опознать");
|
||||||
|
|
||||||
|
AssertUserHasAccessToManual("Manual.edit");
|
||||||
|
|
||||||
|
using var fileStream = file.OpenReadStream();
|
||||||
|
|
||||||
|
var id = await manualCatalogService.SaveFileAsync(idDirectory, idUser.Value, file.FileName, fileStream, cancellationToken);
|
||||||
|
|
||||||
|
return Ok(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Получение файла
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="id">Id инструкции</param>
|
||||||
|
/// <param name="cancellationToken"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
[HttpGet("{id:int}")]
|
||||||
|
[Permission]
|
||||||
|
[ProducesResponseType(typeof(PhysicalFileResult), StatusCodes.Status200OK, "application/octet-stream")]
|
||||||
|
[ProducesResponseType(StatusCodes.Status204NoContent)]
|
||||||
|
[ProducesResponseType(StatusCodes.Status403Forbidden)]
|
||||||
|
public async Task<IActionResult> GetFileAsync(int id, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
AssertUserHasAccessToManual("Manual.get");
|
||||||
|
|
||||||
|
var file = await manualCatalogService.GetFileAsync(id, cancellationToken);
|
||||||
|
|
||||||
|
if (!file.HasValue)
|
||||||
|
return NoContent();
|
||||||
|
|
||||||
|
return File(file.Value.stream, "application/octet-stream", file.Value.fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Удаление файла
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="id">Id инструкции</param>
|
||||||
|
/// <param name="cancellationToken"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
[HttpDelete]
|
||||||
|
[Permission]
|
||||||
|
[ProducesResponseType(typeof(int), StatusCodes.Status200OK)]
|
||||||
|
[ProducesResponseType(StatusCodes.Status403Forbidden)]
|
||||||
|
public async Task<IActionResult> DeleteFileAsync(int id, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
AssertUserHasAccessToManual("Manual.edit");
|
||||||
|
|
||||||
|
return Ok(await manualCatalogService.DeleteFileAsync(id, cancellationToken));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void AssertUserHasAccessToManual(string permissionName)
|
||||||
|
{
|
||||||
|
var idUser = User.GetUserId();
|
||||||
|
|
||||||
|
if (!idUser.HasValue || !userRepository.HasPermission(idUser.Value, permissionName))
|
||||||
|
throw new ForbidException("У вас недостаточно прав");
|
||||||
|
}
|
||||||
|
}
|
110
AsbCloudWebApi/Controllers/ManualDirectoryController.cs
Normal file
110
AsbCloudWebApi/Controllers/ManualDirectoryController.cs
Normal file
@ -0,0 +1,110 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using AsbCloudApp.Data.Manuals;
|
||||||
|
using AsbCloudApp.Exceptions;
|
||||||
|
using AsbCloudApp.Repositories;
|
||||||
|
using AsbCloudApp.Services;
|
||||||
|
using Microsoft.AspNetCore.Authorization;
|
||||||
|
using Microsoft.AspNetCore.Http;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
namespace AsbCloudWebApi.Controllers;
|
||||||
|
|
||||||
|
[ApiController]
|
||||||
|
[Route("api/[controller]")]
|
||||||
|
[Authorize]
|
||||||
|
public class ManualDirectoryController : ControllerBase
|
||||||
|
{
|
||||||
|
private readonly IManualDirectoryRepository manualDirectoryRepository;
|
||||||
|
private readonly IManualCatalogService manualCatalogService;
|
||||||
|
private readonly IUserRepository userRepository;
|
||||||
|
|
||||||
|
public ManualDirectoryController(IManualDirectoryRepository manualDirectoryRepository,
|
||||||
|
IManualCatalogService manualCatalogService,
|
||||||
|
IUserRepository userRepository)
|
||||||
|
{
|
||||||
|
this.manualDirectoryRepository = manualDirectoryRepository;
|
||||||
|
this.manualCatalogService = manualCatalogService;
|
||||||
|
this.userRepository = userRepository;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Создание директории
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="name">Название</param>
|
||||||
|
/// <param name="idParent">Необязательный параметр. Id родительской директории</param>
|
||||||
|
/// <param name="cancellationToken"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
[HttpPost]
|
||||||
|
[Permission]
|
||||||
|
[ProducesResponseType(typeof(int), StatusCodes.Status200OK)]
|
||||||
|
[ProducesResponseType(StatusCodes.Status400BadRequest)]
|
||||||
|
[ProducesResponseType(StatusCodes.Status403Forbidden)]
|
||||||
|
public async Task<IActionResult> AddDirectoryAsync(string name, int? idParent, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
AssertUserHasAccessToManualDirectory("Manual.edit");
|
||||||
|
|
||||||
|
return Ok(await manualCatalogService.AddDirectoryAsync(name, idParent, cancellationToken));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Обновление директории
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="id"></param>
|
||||||
|
/// <param name="name">Новое название директории</param>
|
||||||
|
/// <param name="cancellationToken"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
[HttpPut]
|
||||||
|
[Permission]
|
||||||
|
[ProducesResponseType(StatusCodes.Status400BadRequest)]
|
||||||
|
[ProducesResponseType(StatusCodes.Status403Forbidden)]
|
||||||
|
public async Task<IActionResult> UpdateDirectoryAsync(int id, string name, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
AssertUserHasAccessToManualDirectory("Manual.edit");
|
||||||
|
|
||||||
|
await manualCatalogService.UpdateDirectoryAsync(id, name, cancellationToken);
|
||||||
|
|
||||||
|
return Ok();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Удаление директории
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="id">Идентификатор директории</param>
|
||||||
|
/// <param name="cancellationToken"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
[HttpDelete]
|
||||||
|
[Permission]
|
||||||
|
[ProducesResponseType(typeof(int), StatusCodes.Status200OK)]
|
||||||
|
[ProducesResponseType(StatusCodes.Status403Forbidden)]
|
||||||
|
public async Task<IActionResult> DeleteDirectoryAsync(int id, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
AssertUserHasAccessToManualDirectory("Manual.edit");
|
||||||
|
|
||||||
|
return Ok(await manualCatalogService.DeleteDirectoryAsync(id, cancellationToken));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Получение дерева категорий
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="cancellationToken"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
[HttpGet]
|
||||||
|
[Permission]
|
||||||
|
[ProducesResponseType(typeof(IEnumerable<ManualDirectoryDto>), StatusCodes.Status200OK)]
|
||||||
|
[ProducesResponseType(StatusCodes.Status403Forbidden)]
|
||||||
|
public async Task<IActionResult> GetAsync(CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
AssertUserHasAccessToManualDirectory("Manual.get");
|
||||||
|
|
||||||
|
return Ok(await manualDirectoryRepository.GetTreeAsync(cancellationToken));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void AssertUserHasAccessToManualDirectory(string permissionName)
|
||||||
|
{
|
||||||
|
var idUser = User.GetUserId();
|
||||||
|
|
||||||
|
if (!idUser.HasValue || !userRepository.HasPermission(idUser.Value, permissionName))
|
||||||
|
throw new ForbidException("У вас недостаточно прав");
|
||||||
|
}
|
||||||
|
}
|
@ -27,6 +27,7 @@
|
|||||||
"supportMail": "support@digitaldrilling.ru"
|
"supportMail": "support@digitaldrilling.ru"
|
||||||
},
|
},
|
||||||
"DirectoryNameHelpPageFiles": "helpPages",
|
"DirectoryNameHelpPageFiles": "helpPages",
|
||||||
|
"DirectoryManualFiles": "manuals",
|
||||||
"Urls": "http://0.0.0.0:5000" //;https://0.0.0.0:5001" //,
|
"Urls": "http://0.0.0.0:5000" //;https://0.0.0.0:5001" //,
|
||||||
// See https man: https://docs.microsoft.com/en-us/aspnet/core/fundamentals/servers/kestrel/endpoints?view=aspnetcore-6.0
|
// See https man: https://docs.microsoft.com/en-us/aspnet/core/fundamentals/servers/kestrel/endpoints?view=aspnetcore-6.0
|
||||||
//"Kestrel": {
|
//"Kestrel": {
|
||||||
|
Loading…
Reference in New Issue
Block a user