diff --git a/AsbCloud.sln b/AsbCloud.sln
new file mode 100644
index 00000000..3539f040
--- /dev/null
+++ b/AsbCloud.sln
@@ -0,0 +1,49 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.30907.101
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AsbCloudWebApi", "AsbCloudWebApi\AsbCloudWebApi.csproj", "{A2768702-47CB-4127-941C-E339D5EFCFFE}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AsbCloudApp", "AsbCloudApp\AsbCloudApp.csproj", "{B2A1546F-CBD8-4B1C-88EE-EADBBD5A06CB}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AsbCloudInfrastructure", "AsbCloudInfrastructure\AsbCloudInfrastructure.csproj", "{67DBFC52-BAE4-4903-827A-AD0288C292B6}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ConsoleApp1", "ConsoleApp1\ConsoleApp1.csproj", "{D04A84E7-5F08-4042-8FB5-476EE49E9D22}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AsbCloudDb", "AsbCloudDb\AsbCloudDb.csproj", "{40FBD29B-724B-4496-B5D9-1A5D14102456}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Release|Any CPU = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {A2768702-47CB-4127-941C-E339D5EFCFFE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {A2768702-47CB-4127-941C-E339D5EFCFFE}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {A2768702-47CB-4127-941C-E339D5EFCFFE}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {A2768702-47CB-4127-941C-E339D5EFCFFE}.Release|Any CPU.Build.0 = Release|Any CPU
+ {B2A1546F-CBD8-4B1C-88EE-EADBBD5A06CB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {B2A1546F-CBD8-4B1C-88EE-EADBBD5A06CB}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {B2A1546F-CBD8-4B1C-88EE-EADBBD5A06CB}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {B2A1546F-CBD8-4B1C-88EE-EADBBD5A06CB}.Release|Any CPU.Build.0 = Release|Any CPU
+ {67DBFC52-BAE4-4903-827A-AD0288C292B6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {67DBFC52-BAE4-4903-827A-AD0288C292B6}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {67DBFC52-BAE4-4903-827A-AD0288C292B6}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {67DBFC52-BAE4-4903-827A-AD0288C292B6}.Release|Any CPU.Build.0 = Release|Any CPU
+ {D04A84E7-5F08-4042-8FB5-476EE49E9D22}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {D04A84E7-5F08-4042-8FB5-476EE49E9D22}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {D04A84E7-5F08-4042-8FB5-476EE49E9D22}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {D04A84E7-5F08-4042-8FB5-476EE49E9D22}.Release|Any CPU.Build.0 = Release|Any CPU
+ {40FBD29B-724B-4496-B5D9-1A5D14102456}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {40FBD29B-724B-4496-B5D9-1A5D14102456}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {40FBD29B-724B-4496-B5D9-1A5D14102456}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {40FBD29B-724B-4496-B5D9-1A5D14102456}.Release|Any CPU.Build.0 = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ SolutionGuid = {E446878D-6B1B-4279-A3F0-1974362B9921}
+ EndGlobalSection
+EndGlobal
diff --git a/AsbCloudApp/AsbCloudApp.csproj b/AsbCloudApp/AsbCloudApp.csproj
new file mode 100644
index 00000000..8e347065
--- /dev/null
+++ b/AsbCloudApp/AsbCloudApp.csproj
@@ -0,0 +1,15 @@
+
+
+
+ netcoreapp3.1
+
+
+
+
+
+
+
+
+
+
+
diff --git a/AsbCloudApp/Data/AuthDto.cs b/AsbCloudApp/Data/AuthDto.cs
new file mode 100644
index 00000000..648a876c
--- /dev/null
+++ b/AsbCloudApp/Data/AuthDto.cs
@@ -0,0 +1,8 @@
+namespace AsbCloudApp.Data
+{
+ public class AuthDto
+ {
+ public string Login { get; set; }
+ public string Password { get; set; }
+ }
+}
diff --git a/AsbCloudApp/Data/DataSaubBaseDto.cs b/AsbCloudApp/Data/DataSaubBaseDto.cs
new file mode 100644
index 00000000..1dd57728
--- /dev/null
+++ b/AsbCloudApp/Data/DataSaubBaseDto.cs
@@ -0,0 +1,59 @@
+using System;
+
+namespace AsbCloudApp.Data
+{
+ public class DataSaubBaseDto
+ {
+ public DateTime Date { get; set; }
+
+ public int? Mode { get; set; }
+
+ public double? WellDepth { get; set; }
+
+ public double? BitDepth { get; set; }
+
+ public double? BlockHeight { get; set; }
+
+ public double? BlockSpeed { get; set; }
+
+ public double? BlockSpeedSp { get; set; }
+
+ public double? Pressure { get; set; }
+
+ public double? PressureIdle { get; set; }
+
+ public double? PressureSp { get; set; }
+
+ public double? PressureDeltaLimitMax { get; set; }
+
+ public double? AxialLoad { get; set; }
+
+ public double? AxialLoadSp { get; set; }
+
+ public double? AxialLoadLimitMax { get; set; }
+
+ public double? HookWeight { get; set; }
+
+ public double? HookWeightIdle { get; set; }
+
+ public double? HookWeightLimitMin { get; set; }
+
+ public double? HookWeightLimitMax { get; set; }
+
+ public double? RotorTorque { get; set; }
+
+ public double? RotorTorqueIdle { get; set; }
+
+ public double? RotorTorqueSp { get; set; }
+
+ public double? RotorTorqueLimitMax { get; set; }
+
+ public double? RotorSpeed { get; set; }
+
+ public double? Flow { get; set; }
+
+ public double? FlowIdle { get; set; }
+
+ public double? FlowDeltaLimitMax { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/AsbCloudApp/Data/UserBaseDto.cs b/AsbCloudApp/Data/UserBaseDto.cs
new file mode 100644
index 00000000..15f28ef7
--- /dev/null
+++ b/AsbCloudApp/Data/UserBaseDto.cs
@@ -0,0 +1,19 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace AsbCloudApp.Data
+{
+ public class UserBaseDto
+ {
+ public string Login { get; set; }
+
+ public int? Level { get; set; }
+
+ public string Name { get; set; }
+
+ public string Surname { get; set; }
+
+ public string Patronymic { get; set; }
+ }
+}
diff --git a/AsbCloudApp/Data/UserDto.cs b/AsbCloudApp/Data/UserDto.cs
new file mode 100644
index 00000000..3a439090
--- /dev/null
+++ b/AsbCloudApp/Data/UserDto.cs
@@ -0,0 +1,13 @@
+namespace AsbCloudApp.Data
+{
+ public class UserDto: UserBaseDto
+ {
+ public int Id { get; set; }
+
+ public int? IdCustomer { get; set; }
+
+ public int? IdRole { get; set; }
+
+ public string Password { get; set; }
+ }
+}
diff --git a/AsbCloudApp/Data/UserTokenDto.cs b/AsbCloudApp/Data/UserTokenDto.cs
new file mode 100644
index 00000000..167923ec
--- /dev/null
+++ b/AsbCloudApp/Data/UserTokenDto.cs
@@ -0,0 +1,14 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace AsbCloudApp.Data
+{
+ public class UserTokenDto: UserBaseDto
+ {
+ public int Id { get; set; }
+ public string CustomerName { get; set; }
+ public string RoleName { get; set; }
+ public string Token { get; set; }
+ }
+}
diff --git a/AsbCloudApp/Data/WellDto.cs b/AsbCloudApp/Data/WellDto.cs
new file mode 100644
index 00000000..21f8903d
--- /dev/null
+++ b/AsbCloudApp/Data/WellDto.cs
@@ -0,0 +1,11 @@
+namespace AsbCloudApp.Data
+{
+ public class WellDto
+ {
+ public int Id { get; set; }
+ public string Caption { get; set; }
+ public string Cluster { get; set; }
+ public string Deposit { get; set; }
+ public object LastData { get; set; }//DataSaubBaseDto
+ }
+}
diff --git a/AsbCloudApp/Services/IAuthService.cs b/AsbCloudApp/Services/IAuthService.cs
new file mode 100644
index 00000000..ab7c9e54
--- /dev/null
+++ b/AsbCloudApp/Services/IAuthService.cs
@@ -0,0 +1,15 @@
+using AsbCloudApp.Data;
+using System.Security.Claims;
+
+namespace AsbCloudApp.Services
+{
+ public interface IAuthService
+ {
+ int ChangePassword(int idUser, string newPassword);
+ int ChangePassword(string userLogin, string newPassword);
+ UserTokenDto Login(string login, string password);
+
+ string Refresh(ClaimsPrincipal user);
+ int Register(UserDto userDto);
+ }
+}
\ No newline at end of file
diff --git a/AsbCloudApp/Services/IDepositService.cs b/AsbCloudApp/Services/IDepositService.cs
new file mode 100644
index 00000000..d3050d7d
--- /dev/null
+++ b/AsbCloudApp/Services/IDepositService.cs
@@ -0,0 +1,6 @@
+namespace AsbCloudApp.Services
+{
+ public interface IDepositService
+ {
+ }
+}
diff --git a/AsbCloudApp/Services/IWellService.cs b/AsbCloudApp/Services/IWellService.cs
new file mode 100644
index 00000000..4f32a92c
--- /dev/null
+++ b/AsbCloudApp/Services/IWellService.cs
@@ -0,0 +1,10 @@
+using AsbCloudApp.Data;
+using System.Collections.Generic;
+
+namespace AsbCloudApp.Services
+{
+ public interface IWellService
+ {
+ IEnumerable GetWellsByCustomer(int idCustomer);
+ }
+}
diff --git a/AsbCloudDb/AsbCloudDb.csproj b/AsbCloudDb/AsbCloudDb.csproj
new file mode 100644
index 00000000..0b99e0d1
--- /dev/null
+++ b/AsbCloudDb/AsbCloudDb.csproj
@@ -0,0 +1,15 @@
+
+
+
+ netcoreapp3.1
+
+
+
+
+ all
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+
+
+
+
+
diff --git a/AsbCloudDb/Model/AsbCloudDbContext.cs b/AsbCloudDb/Model/AsbCloudDbContext.cs
new file mode 100644
index 00000000..1d189089
--- /dev/null
+++ b/AsbCloudDb/Model/AsbCloudDbContext.cs
@@ -0,0 +1,160 @@
+using Microsoft.EntityFrameworkCore;
+using System.Collections.Generic;
+using System.Linq;
+
+#nullable disable
+
+namespace AsbCloudDb.Model
+{
+ //Scaffold-DbContext "Host=localhost;Database=postgres;Username=postgres;Password=q;Persist Security Info=True" Npgsql.EntityFrameworkCore.PostgreSQL -OutputDir Model -DataAnnotations
+ public partial class AsbCloudDbContext : DbContext, IAsbCloudDbContext
+ {
+ private readonly string connectionString;
+ public virtual DbSet Clusters { get; set; }
+ public virtual DbSet Customers { get; set; }
+ public virtual DbSet DataSaubBases { get; set; }
+ public virtual DbSet Deposits { get; set; }
+ public virtual DbSet Events { get; set; }
+ public virtual DbSet Messages { get; set; }
+ public virtual DbSet Telemetries { get; set; }
+ public virtual DbSet TelemetryUsers { get; set; }
+ public virtual DbSet Users { get; set; }
+ public virtual DbSet UserRoles { get; set; }
+ public virtual DbSet Wells { get; set; }
+
+ //public AsbCloudDbContext(string connectionString = "Host=localhost;Database=postgres;Username=postgres;Password=q;Persist Security Info=True")
+ //{
+ // this.connectionString = connectionString;
+ // Database.EnsureCreated();
+ //}
+
+ public AsbCloudDbContext(DbContextOptions options)
+ : base(options)
+ {
+ Database.EnsureCreated();
+ }
+
+ protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
+ {
+ if (!optionsBuilder.IsConfigured)
+ {
+ optionsBuilder.UseNpgsql(connectionString);
+ }
+ }
+
+ protected override void OnModelCreating(ModelBuilder modelBuilder)
+ {
+ modelBuilder.HasPostgresExtension("adminpack")
+ .HasAnnotation("Relational:Collation", "Russian_Russia.1251");
+
+ modelBuilder.Entity(entity =>
+ {
+ entity.HasOne(d => d.Deposit)
+ .WithMany(p => p.Clusters)
+ .HasForeignKey(d => d.IdDeposit)
+ .HasConstraintName("t_cluster_t_deposit_id_fk");
+ });
+
+ modelBuilder.Entity(entity =>
+ {
+ entity.HasOne(d => d.Telemetry)
+ .WithMany(p => p.DataSaubBases)
+ .HasForeignKey(d => d.IdTelemetry)
+ .OnDelete(DeleteBehavior.ClientSetNull)
+ .HasConstraintName("t_data_saub_base_t_telemetry_id_fk");
+ });
+
+ modelBuilder.Entity(entity =>
+ {
+ entity.HasOne(d => d.Telemetry)
+ .WithMany(p => p.Messages)
+ .HasForeignKey(d => d.IdTelemetry)
+ .HasConstraintName("t_messages_t_telemetry_id_fk");
+ });
+
+ modelBuilder.Entity(entity =>
+ {
+ entity.HasOne(d => d.Telemetry)
+ .WithMany()
+ .HasForeignKey(d => d.IdTelemetry)
+ .OnDelete(DeleteBehavior.ClientSetNull)
+ .HasConstraintName("t_telemetry_user_t_telemetry_id_fk");
+ });
+
+ modelBuilder.Entity(entity =>
+ {
+ entity.HasData(new List{
+ new UserRole{ Id = 1, Caption = "Администратор", },
+ }); ;
+ });
+
+ modelBuilder.Entity(entity =>
+ {
+ entity.HasData(new List{
+ new Customer{ Id = 1, Caption = "\"ООО\" АСБ", },
+ }); ;
+ });
+
+ modelBuilder.Entity(entity =>
+ {
+ entity.HasOne(d => d.Customer)
+ .WithMany(p => p.Users)
+ .HasForeignKey(d => d.IdCustomer)
+ .HasConstraintName("t_user_t_customer_id_fk");
+
+ entity.HasIndex(d => d.Login)
+ .IsUnique();
+
+ entity.HasData(new List{
+ new User{
+ Id = 1,
+ IdCustomer = 1,
+ IdRole = 1,
+ Level = int.MaxValue,
+ Login = "dev",
+ PasswordHash = "Vlcj|4fa529103dde7ff72cfe76185f344d4aa87931f8e1b2044e8a7739947c3d18923464eaad93843e4f809c5e126d013072", // dev
+ Name = "Разработчик",
+ },
+ });
+ });
+
+ modelBuilder.Entity(entity =>
+ {
+ entity.HasOne(d => d.Cluster)
+ .WithMany(p => p.Wells)
+ .HasForeignKey(d => d.IdCluster)
+ .HasConstraintName("t_well_t_cluster_id_fk");
+
+ entity.HasOne(d => d.Customer)
+ .WithMany(p => p.Wells)
+ .HasForeignKey(d => d.IdCustomer)
+ .HasConstraintName("t_well_t_customer_id_fk");
+
+ entity.HasOne(d => d.Telemetry)
+ .WithOne(p => p.Well)
+ .HasForeignKey(d => d.IdTelemetry)
+ .HasConstraintName("t_well_t_telemetry_id_fk");
+ });
+
+ OnModelCreatingPartial(modelBuilder);
+ }
+
+ partial void OnModelCreatingPartial(ModelBuilder modelBuilder);
+
+ public IQueryable GetWellsByCustomer(int idCustomer)
+ {
+ return from well in Wells
+ .Include(w => w.Customer)
+ .Include(w => w.Cluster)
+ .ThenInclude(c => c.Deposit)
+ where well.IdCustomer == idCustomer
+ select well;
+ }
+
+ public IQueryable GetUsersByLogin(string login)
+ => Users
+ .Include(e => e.Role)
+ .Include(e => e.Customer)
+ .Where(e => e.Login == login);
+ }
+}
diff --git a/AsbCloudDb/Model/Cluster.cs b/AsbCloudDb/Model/Cluster.cs
new file mode 100644
index 00000000..8b01bd3b
--- /dev/null
+++ b/AsbCloudDb/Model/Cluster.cs
@@ -0,0 +1,33 @@
+using Microsoft.EntityFrameworkCore;
+using System.Collections.Generic;
+using System.ComponentModel.DataAnnotations;
+using System.ComponentModel.DataAnnotations.Schema;
+
+#nullable disable
+
+namespace AsbCloudDb.Model
+{
+ [Table("t_cluster"), Comment("Кусты")]
+ public partial class Cluster
+ {
+ public Cluster()
+ {
+ Wells = new HashSet();
+ }
+
+ [Key]
+ [Column("id")]
+ public int Id { get; set; }
+ [Column("caption"), Comment("Название")]
+ [StringLength(255)]
+ public string Caption { get; set; }
+ [Column("id_deposit")]
+ public int? IdDeposit { get; set; }
+
+ [ForeignKey(nameof(IdDeposit))]
+ [InverseProperty(nameof(Model.Deposit.Clusters))]
+ public virtual Deposit Deposit { get; set; }
+ [InverseProperty(nameof(Well.Cluster))]
+ public virtual ICollection Wells { get; set; }
+ }
+}
diff --git a/AsbCloudDb/Model/Customer.cs b/AsbCloudDb/Model/Customer.cs
new file mode 100644
index 00000000..47da6a50
--- /dev/null
+++ b/AsbCloudDb/Model/Customer.cs
@@ -0,0 +1,30 @@
+using System.Collections.Generic;
+using System.ComponentModel.DataAnnotations;
+using System.ComponentModel.DataAnnotations.Schema;
+
+#nullable disable
+
+namespace AsbCloudDb.Model
+{
+ [Table("t_customer")]
+ public partial class Customer
+ {
+ public Customer()
+ {
+ Users = new HashSet();
+ Wells = new HashSet();
+ }
+
+ [Key]
+ [Column("id")]
+ public int Id { get; set; }
+ [Column("caption")]
+ [StringLength(255)]
+ public string Caption { get; set; }
+
+ [InverseProperty(nameof(User.Customer))]
+ public virtual ICollection Users { get; set; }
+ [InverseProperty(nameof(Well.Customer))]
+ public virtual ICollection Wells { get; set; }
+ }
+}
diff --git a/AsbCloudDb/Model/DataSaubBase.cs b/AsbCloudDb/Model/DataSaubBase.cs
new file mode 100644
index 00000000..96fb7ede
--- /dev/null
+++ b/AsbCloudDb/Model/DataSaubBase.cs
@@ -0,0 +1,75 @@
+using Microsoft.EntityFrameworkCore;
+using System;
+using System.ComponentModel.DataAnnotations;
+using System.ComponentModel.DataAnnotations.Schema;
+
+#nullable disable
+
+namespace AsbCloudDb.Model
+{
+ [Table("t_data_saub_base"), Comment("набор основных данных по SAUB")]
+ public partial class DataSaubBase
+ {
+ [Key]
+ [Column("id")]
+ public int Id { get; set; }
+ [Column("id_telemetry")]
+ public int IdTelemetry { get; set; }
+ [Column("date", TypeName = "timestamp with time zone"), Comment("'2021-10-19 18:23:54+05'")]
+ public DateTime Date { get; set; }
+ [Column("mode"), Comment("Режим САУБ")]
+ public int? Mode { get; set; }
+ [Column("well_depth"), Comment("Глубина забоя")]
+ public double? WellDepth { get; set; }
+ [Column("bit_depth"), Comment("Положение инструмента")]
+ public double? BitDepth { get; set; }
+ [Column("block_height"), Comment("Высота талевого блока")]
+ public double? BlockHeight { get; set; }
+ [Column("block_speed"), Comment("Скорость талевого блока")]
+ public double? BlockSpeed { get; set; }
+ [Column("block_speed_sp"), Comment("Скорости талевого блока. Задание")]
+ public double? BlockSpeedSp { get; set; }
+ [Column("pressure"), Comment("Давление")]
+ public double? Pressure { get; set; }
+ [Column("pressure_idle"), Comment("Давление. Холостой ход")]
+ public double? PressureIdle { get; set; }
+ [Column("pressure_sp"), Comment("Давление. Задание")]
+ public double? PressureSp { get; set; }
+ [Column("pressure_delta_limit_max"), Comment("Давление дифф. Аварийное макс.")]
+ public double? PressureDeltaLimitMax { get; set; }
+ [Column("axial_load"), Comment("Осевая нагрузка")]
+ public double? AxialLoad { get; set; }
+ [Column("axial_load_sp"), Comment("Осевая нагрузка. Задание")]
+ public double? AxialLoadSp { get; set; }
+ [Column("axial_load_limit_max"), Comment("Осевая нагрузка. Аварийная макс.")]
+ public double? AxialLoadLimitMax { get; set; }
+ [Column("hook_weight"), Comment("Вес на крюке")]
+ public double? HookWeight { get; set; }
+ [Column("hook_weight_idle"), Comment("Вес на крюке. Холостой ход")]
+ public double? HookWeightIdle { get; set; }
+ [Column("hook_weight_limit_min"), Comment("Вес на крюке. Посадка")]
+ public double? HookWeightLimitMin { get; set; }
+ [Column("hook_weight_limit_max"), Comment("Вес на крюке. Затяжка")]
+ public double? HookWeightLimitMax { get; set; }
+ [Column("rotor_torque"), Comment("Момент на роторе")]
+ public double? RotorTorque { get; set; }
+ [Column("rotor_torque_idle"), Comment("Момент на роторе. Холостой ход")]
+ public double? RotorTorqueIdle { get; set; }
+ [Column("rotor_torque_sp"), Comment("Момент на роторе. Задание")]
+ public double? RotorTorqueSp { get; set; }
+ [Column("rotor_torque_limit_max"), Comment("Момент на роторе. Аварийный макс.")]
+ public double? RotorTorqueLimitMax { get; set; }
+ [Column("rotor_speed"), Comment("Обороты ротора")]
+ public double? RotorSpeed { get; set; }
+ [Column("flow"), Comment("Расход")]
+ public double? Flow { get; set; }
+ [Column("flow_idle"), Comment("Расход. Холостой ход")]
+ public double? FlowIdle { get; set; }
+ [Column("flow_delta_limit_max"), Comment("Расход. Аварийный макс.")]
+ public double? FlowDeltaLimitMax { get; set; }
+
+ [ForeignKey(nameof(IdTelemetry))]
+ [InverseProperty(nameof(Model.Telemetry.DataSaubBases))]
+ public virtual Telemetry Telemetry { get; set; }
+ }
+}
diff --git a/AsbCloudDb/Model/Deposit.cs b/AsbCloudDb/Model/Deposit.cs
new file mode 100644
index 00000000..a835186d
--- /dev/null
+++ b/AsbCloudDb/Model/Deposit.cs
@@ -0,0 +1,28 @@
+using Microsoft.EntityFrameworkCore;
+using System.Collections.Generic;
+using System.ComponentModel.DataAnnotations;
+using System.ComponentModel.DataAnnotations.Schema;
+
+#nullable disable
+
+namespace AsbCloudDb.Model
+{
+ [Table("t_deposit"), Comment("Месторождение")]
+ public partial class Deposit
+ {
+ public Deposit()
+ {
+ Clusters = new HashSet();
+ }
+
+ [Key]
+ [Column("id")]
+ public int Id { get; set; }
+ [Column("caption")]
+ [StringLength(255)]
+ public string Caption { get; set; }
+
+ [InverseProperty(nameof(Cluster.Deposit))]
+ public virtual ICollection Clusters { get; set; }
+ }
+}
diff --git a/AsbCloudDb/Model/Event.cs b/AsbCloudDb/Model/Event.cs
new file mode 100644
index 00000000..85fcc17d
--- /dev/null
+++ b/AsbCloudDb/Model/Event.cs
@@ -0,0 +1,25 @@
+using Microsoft.EntityFrameworkCore;
+using System;
+using System.ComponentModel.DataAnnotations;
+using System.ComponentModel.DataAnnotations.Schema;
+
+#nullable disable
+
+namespace AsbCloudDb.Model
+{
+ [Keyless]
+ [Table("t_event"), Comment("Справочник событий. События формируют сообщения. Разделено по версиям посылок от телеметрии.")]
+ [Index(nameof(IdEvent), nameof(Version), Name = "t_event_pk", IsUnique = true)]
+ public partial class Event
+ {
+ [Column("id_event")]
+ public int? IdEvent { get; set; }
+ [Column("version"), Comment("Версия ПО отправляющей телеметрии.")]
+ [StringLength(64)]
+ public string Version { get; set; }
+ [Column("id_category")]
+ public int? IdCategory { get; set; }
+ [Column("message_template")]
+ public string MessageTemplate { get; set; }
+ }
+}
diff --git a/AsbCloudDb/Model/IAsbCloudDbContext.cs b/AsbCloudDb/Model/IAsbCloudDbContext.cs
new file mode 100644
index 00000000..f2d1954c
--- /dev/null
+++ b/AsbCloudDb/Model/IAsbCloudDbContext.cs
@@ -0,0 +1,29 @@
+using Microsoft.EntityFrameworkCore;
+using System.Linq;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace AsbCloudDb.Model
+{
+ public interface IAsbCloudDbContext
+ {
+ DbSet Clusters { get; set; }
+ DbSet Customers { get; set; }
+ DbSet DataSaubBases { get; set; }
+ DbSet Deposits { get; set; }
+ DbSet Events { get; set; }
+ DbSet Messages { get; set; }
+ DbSet Telemetries { get; set; }
+ DbSet TelemetryUsers { get; set; }
+ DbSet Users { get; set; }
+ DbSet Wells { get; set; }
+ DbSet UserRoles { get; set; }
+
+ int SaveChanges();
+ int SaveChanges(bool acceptAllChangesOnSuccess);
+ Task SaveChangesAsync(CancellationToken cancellationToken);
+
+ IQueryable GetWellsByCustomer(int idCustomer);
+ IQueryable GetUsersByLogin(string login);
+ }
+}
\ No newline at end of file
diff --git a/AsbCloudDb/Model/Message.cs b/AsbCloudDb/Model/Message.cs
new file mode 100644
index 00000000..32f2a8d5
--- /dev/null
+++ b/AsbCloudDb/Model/Message.cs
@@ -0,0 +1,43 @@
+using Microsoft.EntityFrameworkCore;
+using System;
+using System.ComponentModel.DataAnnotations;
+using System.ComponentModel.DataAnnotations.Schema;
+
+#nullable disable
+
+namespace AsbCloudDb.Model
+{
+ [Table("t_message"), Comment("Сообщения на буровых")]
+ public partial class Message
+ {
+ [Key]
+ [Column("id")]
+ public int Id { get; set; }
+ [Column("id_telemetry")]
+ public int? IdTelemetry { get; set; }
+ [Column("id_event")]
+ public int IdEvent { get; set; }
+ [Column("id_telemetry_user"), Comment("Пользователь панели отправляющей телеметрию. не пользователь облака.")]
+ public int? IdTelemetryUser { get; set; }
+ [Column("date", TypeName = "timestamp with time zone")]
+ public DateTime Date { get; set; }
+ [Column("state"), Comment("1 - сработало событие. 0 - событие пропало.")]
+ public int? State { get; set; }
+ [Column("arg0"), Comment("Аргумент №0 для вставки в шаблон сообщения")]
+ [StringLength(255)]
+ public string Arg0 { get; set; }
+ [Column("arg1")]
+ [StringLength(255)]
+ public string Arg1 { get; set; }
+ [Column("arg3")]
+ [StringLength(255)]
+ public string Arg3 { get; set; }
+ [Column("arg4")]
+ [StringLength(255)]
+ public string Arg4 { get; set; }
+
+ [ForeignKey(nameof(IdTelemetry))]
+ [InverseProperty(nameof(Model.Telemetry.Messages))]
+ public virtual Telemetry Telemetry { get; set; }
+ }
+}
diff --git a/AsbCloudDb/Model/Telemetry.cs b/AsbCloudDb/Model/Telemetry.cs
new file mode 100644
index 00000000..b8cd9c05
--- /dev/null
+++ b/AsbCloudDb/Model/Telemetry.cs
@@ -0,0 +1,51 @@
+using Microsoft.EntityFrameworkCore;
+using System;
+using System.Collections.Generic;
+using System.ComponentModel.DataAnnotations;
+using System.ComponentModel.DataAnnotations.Schema;
+
+#nullable disable
+
+namespace AsbCloudDb.Model
+{
+ [Table("t_telemetry"), Comment("таблица привязки телеметрии от комплектов к конкретной скважине.")]
+ [Index(nameof(RemoteUid), Name = "t_telemetry_remote_uid_index")]
+ [Index(nameof(Version), Name = "t_telemetry_version_index")]
+ public partial class Telemetry
+ {
+ public Telemetry()
+ {
+ DataSaubBases = new HashSet();
+ Messages = new HashSet();
+ }
+
+ [Key]
+ [Column("id")]
+ public int Id { get; set; }
+
+ [Column("remote_uid"), Comment("Идентификатор передающего устройства. Может посторяться в списке, так как комплекты оборудования переезжают от скв. к скв.")]
+ public string RemoteUid { get; set; }
+
+ [Column("info", TypeName = "json"), Comment("Информация с панели о скважине")]
+ public string Info { get; set; }
+
+ [Column("data", TypeName = "json"), Comment("последние пришедшие данные со скважины в сыром виде")]
+ public string Data { get; set; }
+
+ [Column("last_data_saub", TypeName = "json"), Comment("последние пришедшие данные со скважины в виде json класса DataSaubBase")]
+ public string LastDataSaub { get; set; }
+
+ [Column("version"), Comment("Версия ПО панели отправляющей телеметрию")]
+ [StringLength(64)]
+ public string Version { get; set; }
+
+ [InverseProperty(nameof(Model.Well.Telemetry))]
+ public virtual Well Well { get; set; }
+
+ [InverseProperty(nameof(DataSaubBase.Telemetry))]
+ public virtual ICollection DataSaubBases { get; set; }
+
+ [InverseProperty(nameof(Message.Telemetry))]
+ public virtual ICollection Messages { get; set; }
+ }
+}
diff --git a/AsbCloudDb/Model/TelemetryUser.cs b/AsbCloudDb/Model/TelemetryUser.cs
new file mode 100644
index 00000000..4d6d8dd7
--- /dev/null
+++ b/AsbCloudDb/Model/TelemetryUser.cs
@@ -0,0 +1,34 @@
+using Microsoft.EntityFrameworkCore;
+using System;
+using System.ComponentModel.DataAnnotations;
+using System.ComponentModel.DataAnnotations.Schema;
+
+#nullable disable
+
+namespace AsbCloudDb.Model
+{
+ [Keyless]
+ [Table("t_telemetry_user"), Comment("Пользователи панели САУБ. Для сообщений.")]
+ [Index(nameof(IdUser), nameof(IdTelemetry), Name = "t_telemetry_user_pk", IsUnique = true)]
+ public partial class TelemetryUser
+ {
+ [Column("id_user")]
+ public int IdUser { get; set; }
+ [Column("id_telemetry")]
+ public int IdTelemetry { get; set; }
+ [Column("name")]
+ [StringLength(255)]
+ public string Name { get; set; }
+ [Column("surname")]
+ [StringLength(255)]
+ public string Surname { get; set; }
+ [Column("patronymic")]
+ [StringLength(255)]
+ public string Patronymic { get; set; }
+ [Column("level")]
+ public int? Level { get; set; }
+
+ [ForeignKey(nameof(IdTelemetry))]
+ public virtual Telemetry Telemetry { get; set; }
+ }
+}
diff --git a/AsbCloudDb/Model/User.cs b/AsbCloudDb/Model/User.cs
new file mode 100644
index 00000000..2163c9ab
--- /dev/null
+++ b/AsbCloudDb/Model/User.cs
@@ -0,0 +1,57 @@
+using Microsoft.EntityFrameworkCore;
+using System.ComponentModel.DataAnnotations;
+using System.ComponentModel.DataAnnotations.Schema;
+
+#nullable disable
+
+namespace AsbCloudDb.Model
+{
+ [Table("t_user"), Comment("Пользователи облака")]
+ public partial class User
+ {
+ [Key]
+ [Column("id")]
+ public int Id { get; set; }
+
+ [Column("id_customer")]
+ public int? IdCustomer { get; set; }
+
+ [Column("id_role")]
+ public int? IdRole { get; set; }
+
+
+ [Column("login")]
+ [StringLength(255)]
+ public string Login { get; set; }
+
+ [Column("password_hash"), Comment("соленый хэш пароля.\nпервые 5 символов - соль")]
+ [StringLength(255)]
+ public string PasswordHash { get; set; }
+
+ [Column("state"), Comment("состояние:\n100 - удален")]
+ public short? State { get; set; }
+
+ [Column("level")]
+ public int? Level { get; set; }
+
+ [Column("name")]
+ [StringLength(255)]
+ public string Name { get; set; }
+
+ [Column("surname")]
+ [StringLength(255)]
+ public string Surname { get; set; }
+
+ [Column("patronymic")]
+ [StringLength(255)]
+ public string Patronymic { get; set; }
+
+ [ForeignKey(nameof(IdCustomer))]
+ [InverseProperty(nameof(Model.Customer.Users))]
+ public virtual Customer Customer { get; set; }
+
+ [ForeignKey(nameof(IdRole))]
+ [InverseProperty(nameof(Model.UserRole.Users))]
+ public virtual UserRole Role { get; set; }
+ }
+}
diff --git a/AsbCloudDb/Model/UserRole.cs b/AsbCloudDb/Model/UserRole.cs
new file mode 100644
index 00000000..aeac0645
--- /dev/null
+++ b/AsbCloudDb/Model/UserRole.cs
@@ -0,0 +1,28 @@
+using Microsoft.EntityFrameworkCore;
+using System.Collections.Generic;
+using System.ComponentModel.DataAnnotations;
+using System.ComponentModel.DataAnnotations.Schema;
+
+
+namespace AsbCloudDb.Model
+{
+ [Table("t_user_role"), Comment("Роли пользователей в системе")]
+ public class UserRole
+ {
+ public UserRole()
+ {
+ Users = new HashSet();
+ }
+
+ [Key]
+ [Column("id")]
+ public int Id { get; set; }
+
+ [Column("caption"), Comment("Название")]
+ [StringLength(255)]
+ public string Caption { get; set; }
+
+ [InverseProperty(nameof(User.Role))]
+ public virtual ICollection Users { get; set; }
+ }
+}
diff --git a/AsbCloudDb/Model/Well.cs b/AsbCloudDb/Model/Well.cs
new file mode 100644
index 00000000..92983965
--- /dev/null
+++ b/AsbCloudDb/Model/Well.cs
@@ -0,0 +1,41 @@
+using Microsoft.EntityFrameworkCore;
+using System.ComponentModel.DataAnnotations;
+using System.ComponentModel.DataAnnotations.Schema;
+
+#nullable disable
+
+namespace AsbCloudDb.Model
+{
+ [Table("t_well"), Comment("скважины")]
+ public partial class Well
+ {
+ [Key]
+ [Column("id")]
+ public int Id { get; set; }
+
+ [Column("caption")]
+ [StringLength(255)]
+ public string Caption { get; set; }
+
+ [Column("id_cluster")]
+ public int? IdCluster { get; set; }
+
+ [Column("id_customer")]
+ public int? IdCustomer { get; set; }
+
+ [Column("id_telemetry")]
+ public int? IdTelemetry { get; set; }
+
+ [ForeignKey(nameof(IdCluster))]
+ [InverseProperty(nameof(Model.Cluster.Wells))]
+ public virtual Cluster Cluster { get; set; }
+
+ [ForeignKey(nameof(IdCustomer))]
+ [InverseProperty(nameof(Model.Customer.Wells))]
+ public virtual Customer Customer { get; set; }
+
+ [ForeignKey(nameof(IdTelemetry))]
+ [InverseProperty(nameof(Model.Telemetry.Well))]
+ public virtual Telemetry Telemetry { get; set; }
+ }
+}
diff --git a/AsbCloudInfrastructure/AsbCloudInfrastructure.csproj b/AsbCloudInfrastructure/AsbCloudInfrastructure.csproj
new file mode 100644
index 00000000..1b7857a3
--- /dev/null
+++ b/AsbCloudInfrastructure/AsbCloudInfrastructure.csproj
@@ -0,0 +1,19 @@
+
+
+
+ netcoreapp3.1
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/AsbCloudInfrastructure/DependencyInjection.cs b/AsbCloudInfrastructure/DependencyInjection.cs
new file mode 100644
index 00000000..dc2e37ac
--- /dev/null
+++ b/AsbCloudInfrastructure/DependencyInjection.cs
@@ -0,0 +1,36 @@
+using AsbCloudApp.Data;
+using AsbCloudApp.Services;
+using AsbCloudDb.Model;
+using AsbCloudInfrastructure.Services;
+using AutoMapper;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.Extensions.Configuration;
+using Microsoft.Extensions.DependencyInjection;
+
+namespace AsbCloudInfrastructure
+{
+ public static class DependencyInjection
+ {
+ public static IServiceCollection AddInfrastructure(this IServiceCollection services, IConfiguration configuration)
+ {
+ services.AddDbContext(options =>
+ options.UseNpgsql(configuration.GetConnectionString("DefaultConnection")));
+
+ services.AddScoped(provider => provider.GetService());
+
+ services.AddSingleton(new MapperConfiguration(AutoMapperConfig));
+
+ services.AddTransient();
+ services.AddTransient();
+
+ return services;
+ }
+
+
+
+ private static void AutoMapperConfig(IMapperConfigurationExpression cfg)
+ {
+ cfg.CreateMap();
+ }
+ }
+}
diff --git a/AsbCloudInfrastructure/Services/AuthService.cs b/AsbCloudInfrastructure/Services/AuthService.cs
new file mode 100644
index 00000000..6bcd9739
--- /dev/null
+++ b/AsbCloudInfrastructure/Services/AuthService.cs
@@ -0,0 +1,201 @@
+using AsbCloudApp.Data;
+using AsbCloudApp.Services;
+using AsbCloudDb.Model;
+using Microsoft.IdentityModel.Tokens;
+using System;
+using System.Collections.Generic;
+using System.IdentityModel.Tokens.Jwt;
+using System.Linq;
+using System.Security.Claims;
+using System.Security.Cryptography;
+using System.Text;
+
+namespace AsbCloudInfrastructure.Services
+{
+ public class AuthService : IAuthService
+ {
+ private readonly IAsbCloudDbContext db;
+
+ public const string issuer = "a";
+ public const string audience = "a";
+ public static readonly SymmetricSecurityKey securityKey = new SymmetricSecurityKey(Encoding.ASCII.GetBytes("супер секретный ключ для шифрования"));
+ public const string algorithms = SecurityAlgorithms.HmacSha256;
+
+ private static readonly TimeSpan expiresTimespan = TimeSpan.FromDays(365.25);
+ private static readonly Encoding encoding = Encoding.UTF8;
+ private const int PasswordSaltLength = 5;
+ private const string claimNameIdCustomer = "IdCustomer";
+ private readonly HashAlgorithm hashAlgoritm;
+ private readonly Random rnd;
+
+ public AuthService(IAsbCloudDbContext db)
+ {
+ this.db = db;
+ hashAlgoritm = SHA384.Create();
+ rnd = new Random((int)(DateTime.Now.Ticks % 2147480161));
+ }
+
+ public UserTokenDto Login(string login, string password)
+ {
+ var identity = GetClaimsUser(login, password);
+ if (identity == default)
+ return null;
+
+ return new UserTokenDto
+ {
+ Id = identity.User.Id,
+ Name = identity.User.Name,
+ CustomerName = identity.User.Customer.Caption,
+ Level = identity.User.Level,
+ Login = identity.User.Login,
+ Patronymic = identity.User.Patronymic,
+ RoleName = identity.User.Role.Caption,
+ Surname = identity.User.Surname,
+ Token = MakeToken(identity.Identity.Claims),
+ };
+ }
+
+ public string Refresh(ClaimsPrincipal user)
+ {
+ return MakeToken(user.Claims);
+ }
+
+ public int Register(UserDto userDto)
+ {
+ if (userDto.Login.Length < 3)
+ return -1;
+
+ if (userDto.Password.Length < 3)
+ return -2;
+
+ //if (db.Customers.FirstOrDefault(c=>c.Id == userDto.IdCustomer) is null)
+ // return -3;
+
+ //if (db.UserRoles.FirstOrDefault(c => c.Id == userDto.IdRole) is null)
+ // return -4;
+
+ //if (db.Users.FirstOrDefault(c => c.Login == userDto.Login) != null)
+ // return -5;
+
+ var salt = GenerateSalt();
+
+ var user = new User
+ {
+ IdCustomer = userDto.IdCustomer,
+ IdRole = userDto.IdRole,
+ Name = userDto.Name,
+ Surname = userDto.Surname,
+ Patronymic = userDto.Patronymic,
+ Level = userDto.Level,
+ Login = userDto.Login,
+ PasswordHash = salt + ComputeHash(salt, userDto.Password)
+ };
+
+ db.Users.Add(user);
+ try
+ {
+ db.SaveChanges();
+ }
+ catch //(Exception ex)
+ {
+ return -6;
+ }
+
+ return 0;
+ }
+
+ public int ChangePassword(string userLogin, string newPassword)
+ {
+ var user = db.Users.FirstOrDefault(u => u.Login == userLogin);
+ if (user == null)
+ return -1;
+
+ var salt = GenerateSalt();
+ user.PasswordHash = salt + ComputeHash(salt, newPassword);
+ db.SaveChanges();
+ return 0;
+ }
+
+ public int ChangePassword(int idUser, string newPassword)
+ {
+ var user = db.Users.FirstOrDefault(u => u.Id == idUser);
+ if (user == null)
+ return -1;
+
+ var salt = GenerateSalt();
+ user.PasswordHash = salt + ComputeHash(salt, newPassword);
+ db.SaveChanges();
+ return 0;
+ }
+
+ private string MakeToken(IEnumerable claims)
+ {
+ var now = DateTime.Now;
+
+ var jwt = new JwtSecurityToken(
+ issuer: issuer,
+ audience: audience,
+ notBefore: now,
+ claims: claims,
+ expires: now.Add(expiresTimespan),
+ signingCredentials: new SigningCredentials(securityKey, algorithms));
+
+ return new JwtSecurityTokenHandler().WriteToken(jwt);
+ }
+
+ private (ClaimsIdentity Identity, User User) GetClaimsUser(string login, string password)
+ {
+ var user = db
+ .GetUsersByLogin(login)
+ .FirstOrDefault();
+
+ if (user is null)
+ return default;
+
+ if (!CheckPassword(user.PasswordHash, password))
+ return default;
+
+ var claims = new List
+ {
+ new Claim(ClaimsIdentity.DefaultNameClaimType, user.Login),
+ new Claim(ClaimsIdentity.DefaultRoleClaimType, user.Role?.Caption??"GUEST"),
+ new Claim(claimNameIdCustomer, user.IdCustomer.ToString()),
+ };
+ var claimsIdentity = new ClaimsIdentity(claims, "Token", ClaimsIdentity.DefaultNameClaimType, ClaimsIdentity.DefaultRoleClaimType);
+ return (claimsIdentity, user);
+ }
+
+ private bool CheckPassword(string passwordHash, string password)
+ {
+ if (passwordHash.Length == 0 && password.Length == 0)
+ return true;
+
+ if (passwordHash.Length < PasswordSaltLength)
+ return false;
+
+ var salt = passwordHash[0..PasswordSaltLength];
+ var hashDb = passwordHash[PasswordSaltLength..];
+
+ return hashDb == ComputeHash(salt, password);
+ }
+
+ private string ComputeHash(string salt, string password)
+ {
+ var hashBytes = hashAlgoritm.ComputeHash(encoding.GetBytes(salt + password));
+ var hashString = BitConverter.ToString(hashBytes)
+ .Replace("-", "")
+ .ToLower();
+ return hashString;
+ }
+
+ public string GenerateSalt()
+ {
+ const string saltChars = "sHwiaX7kZT1QRp0cPILGUuK2Sz=9q8lmejDNfoYCE3B_WtgyVv6M5OxAJ4Frbhnd";
+ string salt = "";
+ for (int i = 0; i < PasswordSaltLength - 1; i++)
+ salt += saltChars[rnd.Next(0, saltChars.Length)];
+ salt += "|";
+ return salt;
+ }
+ }
+}
diff --git a/AsbCloudInfrastructure/Services/DepositService.cs b/AsbCloudInfrastructure/Services/DepositService.cs
new file mode 100644
index 00000000..95e9ef38
--- /dev/null
+++ b/AsbCloudInfrastructure/Services/DepositService.cs
@@ -0,0 +1,19 @@
+using AsbCloudApp.Services;
+using AsbCloudDb.Model;
+using AutoMapper;
+
+namespace AsbCloudInfrastructure.Services
+{
+ public class DepositService : IDepositService
+ {
+ private readonly IAsbCloudDbContext db;
+ private readonly MapperConfiguration mapperConfiguration;
+
+ public DepositService(IAsbCloudDbContext db, MapperConfiguration mapperConfiguration)
+ {
+ this.db = db;
+ this.mapperConfiguration = mapperConfiguration;
+ }
+
+ }
+}
diff --git a/AsbCloudInfrastructure/Services/WellService.cs b/AsbCloudInfrastructure/Services/WellService.cs
new file mode 100644
index 00000000..4867e58d
--- /dev/null
+++ b/AsbCloudInfrastructure/Services/WellService.cs
@@ -0,0 +1,48 @@
+using AsbCloudApp.Data;
+using AsbCloudApp.Services;
+using AsbCloudDb.Model;
+using AutoMapper;
+using System.Collections.Generic;
+using System.Linq;
+
+namespace AsbCloudInfrastructure.Services
+{
+ public class WellService : IWellService
+ {
+ private readonly IAsbCloudDbContext db;
+ private readonly MapperConfiguration mapperConfiguration;
+
+ public WellService(IAsbCloudDbContext db, MapperConfiguration mapperConfiguration)
+ {
+ this.db = db;
+ this.mapperConfiguration = mapperConfiguration;
+ }
+
+ public IEnumerable GetWellsByCustomer(int idCustomer)
+ {
+ var wells = db.GetWellsByCustomer(idCustomer).ToList();
+ return wells.Select(w => From(w));
+ }
+
+ private WellDto From(Well well)
+ {
+ var wellDto = new WellDto
+ {
+ Id = well.Id,
+ Caption = well.Caption,
+ Cluster = well.Cluster.Caption,
+ Deposit = well.Cluster.Deposit.Caption,
+ };
+
+ var dataJson = well.Telemetry?.LastDataSaub;
+
+ if (string.IsNullOrEmpty(dataJson))
+ return wellDto;
+
+ var data = System.Text.Json.JsonSerializer.Deserialize(dataJson);
+ wellDto.LastData = mapperConfiguration.CreateMapper().Map(data);
+
+ return wellDto;
+ }
+ }
+}
diff --git a/AsbCloudInfrastructure/TinyMapper.cs b/AsbCloudInfrastructure/TinyMapper.cs
new file mode 100644
index 00000000..be15bd9c
--- /dev/null
+++ b/AsbCloudInfrastructure/TinyMapper.cs
@@ -0,0 +1,24 @@
+using System.Reflection;
+
+namespace AsbCloudApp
+{
+ public class TinyMapper
+ where Tout: new()
+ {
+ private ConstructorInfo[] ctors;
+
+ public TinyMapper()
+ {
+ ctors = typeof(Tin).GetConstructors();
+ typeof(Tin).GetProperties();
+ }
+
+ //public Tout Map(Tin original, params object?[]? ctorParameters)
+ //{
+ // var result = new Tout();
+ // var convertion
+ // return result;
+ //}
+
+ }
+}
diff --git a/AsbCloudWebApi/.config/dotnet-tools.json b/AsbCloudWebApi/.config/dotnet-tools.json
new file mode 100644
index 00000000..4500a961
--- /dev/null
+++ b/AsbCloudWebApi/.config/dotnet-tools.json
@@ -0,0 +1,12 @@
+{
+ "version": 1,
+ "isRoot": true,
+ "tools": {
+ "dotnet-ef": {
+ "version": "5.0.4",
+ "commands": [
+ "dotnet-ef"
+ ]
+ }
+ }
+}
\ No newline at end of file
diff --git a/AsbCloudWebApi/AsbCloudWebApi.csproj b/AsbCloudWebApi/AsbCloudWebApi.csproj
new file mode 100644
index 00000000..da3b1513
--- /dev/null
+++ b/AsbCloudWebApi/AsbCloudWebApi.csproj
@@ -0,0 +1,32 @@
+
+
+
+ net5.0
+ true
+ $(NoWarn);1591
+ 80899ceb-210f-4f19-ac56-aa90a5d666d4
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ PreserveNewest
+
+
+
+
+
diff --git a/AsbCloudWebApi/AsbCloudWebApi.service b/AsbCloudWebApi/AsbCloudWebApi.service
new file mode 100644
index 00000000..4c5f5ac4
--- /dev/null
+++ b/AsbCloudWebApi/AsbCloudWebApi.service
@@ -0,0 +1,18 @@
+[Unit]
+Description=ASB Vision Rest Service [.net core]
+Requires=config
+# After=discovery
+[Service]
+User=root
+# The configuration file application.properties should be here:
+# change this to your workspace
+WorkingDirectory=/home/soltex/cloud2/rest
+#path to executable.
+#executable is a bash script which calls jar file
+ExecStart=/home/soltex/cloud2/rest/AsbCloudWebApi
+SuccessExitStatus=0
+TimeoutStopSec=20
+Restart=on-failure
+RestartSec=5
+[Install]
+WantedBy=multi-user.target
diff --git a/AsbCloudWebApi/Controllers/AuthController.cs b/AsbCloudWebApi/Controllers/AuthController.cs
new file mode 100644
index 00000000..db8f7d77
--- /dev/null
+++ b/AsbCloudWebApi/Controllers/AuthController.cs
@@ -0,0 +1,51 @@
+using AsbCloudApp.Data;
+using AsbCloudApp.Services;
+using Microsoft.AspNetCore.Authorization;
+using Microsoft.AspNetCore.Mvc;
+using Swashbuckle.AspNetCore.Annotations;
+
+namespace AsbCloudWebApi.Controllers
+{
+ [Route("/auth")]
+ [ApiController]
+ public class AuthController : ControllerBase
+ {
+ private readonly IAuthService authService;
+
+ public AuthController(IAuthService authService)
+ {
+ this.authService = authService;
+ }
+
+ ///
+ /// Аутентификация пользователя
+ ///
+ ///
+ /// новый токен
+ /// логин и пароль не подходят
+ [AllowAnonymous]
+ [HttpPost("login")]
+ [SwaggerOperation(OperationId = "logiin")]
+ [ProducesResponseType(typeof(UserTokenDto), (int)System.Net.HttpStatusCode.OK)]
+ public IActionResult Login([FromBody] AuthDto auth)
+ {
+ var userToken = authService.Login(auth.Login, auth.Password);
+ if (userToken is null)
+ BadRequest();//"wrong login or password"
+
+ return Ok(userToken);
+ }
+
+ ///
+ /// Продление срока действия токена
+ ///
+ /// новый токен
+ [Authorize]
+ [HttpGet("refresh")]
+ public IActionResult Refresh()
+ {
+ var newToken = authService.Refresh(User);
+ return Ok(newToken);
+ }
+ }
+}
diff --git a/AsbCloudWebApi/Controllers/WellController.cs b/AsbCloudWebApi/Controllers/WellController.cs
new file mode 100644
index 00000000..ec1c3dee
--- /dev/null
+++ b/AsbCloudWebApi/Controllers/WellController.cs
@@ -0,0 +1,54 @@
+using AsbCloudApp.Data;
+using AsbCloudApp.Services;
+using Microsoft.AspNetCore.Authorization;
+using Microsoft.AspNetCore.Mvc;
+using System.Collections.Generic;
+
+namespace AsbCloudWebApi.Controllers
+{
+ [Route("api/[controller]")]
+ [ApiController]
+ [Authorize]
+ public class WellController : ControllerBase
+ {
+ private readonly IWellService wellService;
+
+ public WellController(IWellService wellService)
+ {
+ this.wellService = wellService;
+ }
+
+ [HttpGet]
+ [ProducesResponseType(typeof(IEnumerable), (int)System.Net.HttpStatusCode.OK)]
+ public IActionResult Get()
+ {
+ var claimIdCustomer = User.FindFirst("IdCustomer");
+
+ if (claimIdCustomer is null)
+ return NoContent();
+
+ var idCustomer = int.Parse(claimIdCustomer.Value);
+
+ var wells = wellService.GetWellsByCustomer(idCustomer);
+
+ return Ok(wells);
+ }
+
+ //[Route("{id}")]
+ //[HttpGet]
+ //[ProducesResponseType(typeof(IEnumerable), (int)System.Net.HttpStatusCode.OK)]
+ //public IActionResult GetByCustomer(int id)
+ //{
+ // var claimIdCustomer = User.FindFirst("IdCustomer");
+
+ // if (claimIdCustomer is null)
+ // return NoContent();
+
+ // var idCustomer = int.Parse(claimIdCustomer.Value);
+
+ // var wells = wellService.GetWellsByCustomer(idCustomer);
+
+ // return Ok(wells);
+ //}
+ }
+}
diff --git a/AsbCloudWebApi/DependencyInjection.cs b/AsbCloudWebApi/DependencyInjection.cs
new file mode 100644
index 00000000..65efd95f
--- /dev/null
+++ b/AsbCloudWebApi/DependencyInjection.cs
@@ -0,0 +1,82 @@
+using AsbCloudInfrastructure.Services;
+using Microsoft.AspNetCore.Authentication.JwtBearer;
+using Microsoft.AspNetCore.Mvc.ApiExplorer;
+using Microsoft.Extensions.Configuration;
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.IdentityModel.Tokens;
+using Microsoft.OpenApi.Models;
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Reflection;
+
+namespace AsbCloudWebApi
+{
+ public static class DependencyInjection
+ {
+ public static void AddSwagger(this IServiceCollection services, IConfiguration configuration = null)
+ {
+ services.AddSwaggerGen(c =>
+ {
+ //c.CustomOperationIds(e => $"{e.ActionDescriptor.RouteValues["controller"]}_{e.HttpMethod}");
+ //c.CustomOperationIds(e => $"{e.HttpMethod}_{e.ActionDescriptor.Ac");
+ c.CustomOperationIds(e=> {
+ return $"{e.ActionDescriptor.RouteValues["action"]}";
+ });
+
+ c.SwaggerDoc("v1", new OpenApiInfo { Title = "Charging station", Version = "v1" });
+ c.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme
+ {
+ Description = @"JWT Authorization header using the Bearer scheme. Enter 'Bearer' [space] and then your token in the text input below. Example: 'Bearer 12345abcdef'",
+ Name = "Authorization",
+ In = ParameterLocation.Header,
+ Type = SecuritySchemeType.ApiKey,
+ Scheme = "Bearer"
+ });
+
+ c.AddSecurityRequirement(new OpenApiSecurityRequirement()
+ {
+ {
+ new OpenApiSecurityScheme
+ {
+ Reference = new OpenApiReference
+ {
+ Type = ReferenceType.SecurityScheme,
+ Id = "Bearer"
+ },
+ Scheme = "oauth2",
+ Name = "Bearer",
+ In = ParameterLocation.Header,
+
+ },
+ new List()
+ }
+ });
+
+ var xmlFile = $"{Assembly.GetExecutingAssembly().GetName().Name}.xml";
+ var xmlPath = Path.Combine(AppContext.BaseDirectory, xmlFile);
+ c.IncludeXmlComments(xmlPath);
+
+ });
+ }
+
+ public static void AddJWTAuthentication(this IServiceCollection services, IConfiguration configuration = null)
+ {
+ services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
+ .AddJwtBearer(options =>
+ {
+ options.RequireHttpsMetadata = false;
+ options.TokenValidationParameters = new TokenValidationParameters
+ {
+ ValidateIssuer = true,
+ ValidIssuer = AuthService.issuer,
+ ValidateAudience = true,
+ ValidAudience = AuthService.audience,
+ ValidateLifetime = true,
+ IssuerSigningKey = AuthService.securityKey,
+ ValidateIssuerSigningKey = true,
+ };
+ });
+ }
+ }
+}
diff --git a/AsbCloudWebApi/Program.cs b/AsbCloudWebApi/Program.cs
new file mode 100644
index 00000000..d4106a2e
--- /dev/null
+++ b/AsbCloudWebApi/Program.cs
@@ -0,0 +1,20 @@
+using Microsoft.AspNetCore.Hosting;
+using Microsoft.Extensions.Hosting;
+
+namespace AsbCloudWebApi
+{
+ public class Program
+ {
+ public static void Main(string[] args)
+ {
+ CreateHostBuilder(args).Build().Run();
+ }
+
+ public static IHostBuilder CreateHostBuilder(string[] args) =>
+ Host.CreateDefaultBuilder(args)
+ .ConfigureWebHostDefaults(webBuilder =>
+ {
+ webBuilder.UseStartup();
+ });
+ }
+}
diff --git a/AsbCloudWebApi/Properties/launchSettings.json b/AsbCloudWebApi/Properties/launchSettings.json
new file mode 100644
index 00000000..5b3d3393
--- /dev/null
+++ b/AsbCloudWebApi/Properties/launchSettings.json
@@ -0,0 +1,30 @@
+{
+ "iisSettings": {
+ "windowsAuthentication": false,
+ "anonymousAuthentication": true,
+ "iisExpress": {
+ "applicationUrl": "http://localhost:52123",
+ "sslPort": 44327
+ }
+ },
+ "$schema": "http://json.schemastore.org/launchsettings.json",
+ "profiles": {
+ "IIS Express": {
+ "commandName": "IISExpress",
+ "launchBrowser": true,
+ "launchUrl": "swagger",
+ "environmentVariables": {
+ "ASPNETCORE_ENVIRONMENT": "Development"
+ }
+ },
+ "AsbCloudWebApi": {
+ "commandName": "Project",
+ "launchBrowser": true,
+ "launchUrl": "swagger/index.html",
+ "environmentVariables": {
+ "ASPNETCORE_ENVIRONMENT": "Development"
+ },
+ "applicationUrl": "https://localhost:5001;http://localhost:5000"
+ }
+ }
+}
\ No newline at end of file
diff --git a/AsbCloudWebApi/Startup.cs b/AsbCloudWebApi/Startup.cs
new file mode 100644
index 00000000..81b404de
--- /dev/null
+++ b/AsbCloudWebApi/Startup.cs
@@ -0,0 +1,55 @@
+using AsbCloudInfrastructure;
+using Microsoft.AspNetCore.Builder;
+using Microsoft.AspNetCore.Hosting;
+using Microsoft.Extensions.Configuration;
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Hosting;
+
+namespace AsbCloudWebApi
+{
+ public class Startup
+ {
+ public Startup(IConfiguration configuration)
+ {
+ Configuration = configuration;
+ }
+
+ public IConfiguration Configuration { get; }
+
+ public void ConfigureServices(IServiceCollection services)
+ {
+ services.AddControllers();
+
+ services.AddSwagger(Configuration);
+
+ services.AddInfrastructure(Configuration);
+
+ services.AddJWTAuthentication(Configuration);
+ }
+
+ public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
+ {
+ app.UseSwagger();
+ app.UseSwaggerUI(c =>
+ {
+ c.SwaggerEndpoint("/swagger/v1/swagger.json", "Charging station V1");
+ });
+
+ if (env.IsDevelopment())
+ {
+ app.UseDeveloperExceptionPage();
+ }
+
+ //app.UseHttpsRedirection();
+ app.UseStaticFiles();
+ app.UseRouting();
+ app.UseAuthentication();
+ app.UseAuthorization();
+
+ app.UseEndpoints(endpoints =>
+ {
+ endpoints.MapControllers();
+ });
+ }
+ }
+}
diff --git a/AsbCloudWebApi/appsettings.Development.json b/AsbCloudWebApi/appsettings.Development.json
new file mode 100644
index 00000000..8983e0fc
--- /dev/null
+++ b/AsbCloudWebApi/appsettings.Development.json
@@ -0,0 +1,9 @@
+{
+ "Logging": {
+ "LogLevel": {
+ "Default": "Information",
+ "Microsoft": "Warning",
+ "Microsoft.Hosting.Lifetime": "Information"
+ }
+ }
+}
diff --git a/AsbCloudWebApi/appsettings.json b/AsbCloudWebApi/appsettings.json
new file mode 100644
index 00000000..2ddea643
--- /dev/null
+++ b/AsbCloudWebApi/appsettings.json
@@ -0,0 +1,14 @@
+{
+ "Logging": {
+ "LogLevel": {
+ "Default": "Information",
+ "Microsoft": "Warning",
+ "Microsoft.Hosting.Lifetime": "Information"
+ }
+ },
+ "ConnectionStrings": {
+ "DefaultConnection": "Host=localhost;Database=postgres;Username=postgres;Password=q;Persist Security Info=True"
+ },
+ "AllowedHosts": "*",
+ "Urls": "https://localhost:5001;http://localhost:5000" //http://0.0.0.0:5000;
+}
diff --git a/AsbCloudWebApi/wwwroot/index.html b/AsbCloudWebApi/wwwroot/index.html
new file mode 100644
index 00000000..f6b6ceeb
--- /dev/null
+++ b/AsbCloudWebApi/wwwroot/index.html
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+ RAMAMBA!
+
+
\ No newline at end of file
diff --git a/ConsoleApp1/ConsoleApp1.csproj b/ConsoleApp1/ConsoleApp1.csproj
new file mode 100644
index 00000000..fbf72ce7
--- /dev/null
+++ b/ConsoleApp1/ConsoleApp1.csproj
@@ -0,0 +1,19 @@
+
+
+
+ Exe
+ net5.0
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/ConsoleApp1/Program.cs b/ConsoleApp1/Program.cs
new file mode 100644
index 00000000..c2e73314
--- /dev/null
+++ b/ConsoleApp1/Program.cs
@@ -0,0 +1,18 @@
+using AsbCloudDb.Model;
+using AutoMapper;
+using BenchmarkDotNet.Attributes;
+using BenchmarkDotNet.Running;
+using Microsoft.EntityFrameworkCore;
+using System;
+using System.Reflection;
+
+namespace ConsoleApp1
+{
+ class Program
+ {
+ static void Main(string[] args)
+ {
+ Console.WriteLine("Done");
+ }
+ }
+}
diff --git a/CreateCloud2Scheme.sql b/CreateCloud2Scheme.sql
new file mode 100644
index 00000000..25e453d1
--- /dev/null
+++ b/CreateCloud2Scheme.sql
@@ -0,0 +1,269 @@
+create table t_deposit
+(
+ id serial not null
+ constraint t_deposit_pk
+ primary key,
+ caption varchar(255)
+);
+
+comment on table t_deposit is 'Месторождение';
+
+alter table t_deposit
+ owner to postgres;
+
+create table t_cluster
+(
+ id serial not null
+ constraint t_cluster_pk
+ primary key,
+ caption varchar(255),
+ id_deposit integer
+ constraint t_cluster_t_deposit_id_fk
+ references t_deposit
+);
+
+comment on table t_cluster is 'Кусты';
+
+alter table t_cluster
+ owner to postgres;
+
+create table t_customer
+(
+ id serial not null
+ constraint t_customer_pk
+ primary key,
+ caption varchar(255)
+);
+
+alter table t_customer
+ owner to postgres;
+
+create table t_well
+(
+ id serial not null
+ constraint t_well_pk
+ primary key,
+ caption varchar(255),
+ id_cluster integer
+ constraint t_well_t_cluster_id_fk
+ references t_cluster,
+ id_customer integer
+ constraint t_well_t_customer_id_fk
+ references t_customer
+);
+
+comment on table t_well is 'скважины';
+
+alter table t_well
+ owner to postgres;
+
+create table t_telemetry
+(
+ id serial not null
+ constraint t_telemetry_pk
+ primary key,
+ remote_uid text,
+ info json,
+ data json,
+ id_well integer
+ constraint t_telemetry_t_well_id_fk
+ references t_well,
+ version varchar(64)
+);
+
+comment on table t_telemetry is 'таблица привязки телеметрии от комплектов к конкретной скважине.';
+
+comment on column t_telemetry.remote_uid is 'Идентификатор передающего устройства. Может посторяться в списке, так как комплекты оборудования переезжают от скв. к скв.';
+
+comment on column t_telemetry.info is 'Информация с панели о скважине';
+
+comment on column t_telemetry.data is 'последние пришедшие данные со скважины в сыром виде';
+
+comment on column t_telemetry.version is 'Версия ПО в комплекте';
+
+alter table t_telemetry
+ owner to postgres;
+
+create index t_telemetry_remote_uid_index
+ on t_telemetry (remote_uid);
+
+create index t_telemetry_version_index
+ on t_telemetry (version);
+
+create table t_data_saub_base
+(
+ id serial not null
+ constraint t_data_saub_base_pk
+ primary key,
+ id_telemetry integer not null
+ constraint t_data_saub_base_t_telemetry_id_fk
+ references t_telemetry,
+ date timestamp with time zone,
+ mode integer,
+ well_depth double precision,
+ bit_depth double precision,
+ block_height double precision,
+ block_speed double precision,
+ block_speed_sp double precision,
+ pressure double precision,
+ pressure_idle double precision,
+ pressure_sp double precision,
+ pressure_delta_limit_max double precision,
+ axial_load double precision,
+ axial_load_sp double precision,
+ axial_load_limit_max double precision,
+ hook_weight double precision,
+ hook_weight_idle double precision,
+ hook_weight_limit_min double precision,
+ hook_weight_limit_max double precision,
+ rotor_torque double precision,
+ rotor_torque_idle double precision,
+ rotor_torque_sp double precision,
+ rotor_torque_limit_max double precision,
+ rotor_speed double precision,
+ flow double precision,
+ flow_idle double precision,
+ flow_delta_limit_max double precision
+);
+
+comment on table t_data_saub_base is 'набор основных данных по SAUB';
+
+comment on column t_data_saub_base.date is '''2021-10-19 18:23:54+05''';
+
+comment on column t_data_saub_base.mode is 'Режим САУБ';
+
+comment on column t_data_saub_base.well_depth is 'Глубина забоя';
+
+comment on column t_data_saub_base.bit_depth is 'Положение инструмента';
+
+comment on column t_data_saub_base.block_height is 'Высота талевого блока';
+
+comment on column t_data_saub_base.block_speed is 'Скорость талевого блока';
+
+comment on column t_data_saub_base.block_speed_sp is 'Скорости талевого блока. Задание';
+
+comment on column t_data_saub_base.pressure is 'Давление';
+
+comment on column t_data_saub_base.pressure_idle is 'Давление. Холостой ход';
+
+comment on column t_data_saub_base.pressure_sp is 'Давление. Задание';
+
+comment on column t_data_saub_base.pressure_delta_limit_max is 'Давление дифф. Аварийное макс.';
+
+comment on column t_data_saub_base.axial_load is 'Осевая нагрузка';
+
+comment on column t_data_saub_base.axial_load_sp is 'Осевая нагрузка. Задание';
+
+comment on column t_data_saub_base.axial_load_limit_max is 'Осевая нагрузка. Аварийная макс.';
+
+comment on column t_data_saub_base.hook_weight is 'Вес на крюке';
+
+comment on column t_data_saub_base.hook_weight_idle is 'Вес на крюке. Холостой ход';
+
+comment on column t_data_saub_base.hook_weight_limit_min is 'Вес на крюке. Посадка';
+
+comment on column t_data_saub_base.hook_weight_limit_max is 'Вес на крюке. Затяжка';
+
+comment on column t_data_saub_base.rotor_torque is 'Момент на роторе';
+
+comment on column t_data_saub_base.rotor_torque_idle is 'Момент на роторе. Холостой ход';
+
+comment on column t_data_saub_base.rotor_torque_sp is 'Момент на роторе. Задание';
+
+comment on column t_data_saub_base.rotor_torque_limit_max is 'Момент на роторе. Аварийный макс.';
+
+comment on column t_data_saub_base.rotor_speed is 'Обороты ротора';
+
+comment on column t_data_saub_base.flow is 'Расход';
+
+comment on column t_data_saub_base.flow_idle is 'Расход. Холостой ход';
+
+comment on column t_data_saub_base.flow_delta_limit_max is 'Расход. Аварийный макс.';
+
+alter table t_data_saub_base
+ owner to postgres;
+
+create table t_user
+(
+ id serial not null
+ constraint t_user_pk
+ primary key,
+ id_customer integer
+ constraint t_user_t_customer_id_fk
+ references t_customer,
+ login varchar(255),
+ password_hash varchar(255),
+ state smallint,
+ level integer,
+ name varchar(255),
+ surname varchar(255),
+ patronymic varchar(255)
+);
+
+comment on table t_user is 'Пользователи облака';
+
+comment on column t_user.password_hash is 'соленый хэш пароля.
+первые 5 символов - соль';
+
+comment on column t_user.state is 'состояние:
+100 - удален';
+
+alter table t_user
+ owner to postgres;
+
+create table t_message
+(
+ id serial not null
+ constraint t_messages_pk
+ primary key,
+ id_telemetry integer
+ constraint t_messages_t_telemetry_id_fk
+ references t_telemetry,
+ id_event integer not null,
+ id_user integer,
+ date timestamp with time zone not null,
+ state integer,
+ arg0 varchar(255),
+ arg1 varchar(255),
+ arg3 varchar(255),
+ arg4 varchar(255)
+);
+
+alter table t_message
+ owner to postgres;
+
+create table t_event
+(
+ id_event integer,
+ version varchar(64),
+ id_category integer,
+ message_template text,
+ constraint t_event_pk
+ unique (id_event, version)
+);
+
+comment on table t_event is 'Справочник сообщений. Разделение по версиям посылок телеметрии.';
+
+alter table t_event
+ owner to postgres;
+
+create table t_telemetry_user
+(
+ id_user integer not null,
+ id_telemetry integer not null
+ constraint t_telemetry_user_t_telemetry_id_fk
+ references t_telemetry,
+ name varchar(255),
+ surname varchar(255),
+ patronymic varchar(255),
+ level integer,
+ constraint t_telemetry_user_pk
+ unique (id_user, id_telemetry)
+);
+
+comment on table t_telemetry_user is 'Пользователи панели САУБ. Для сообщений.';
+
+alter table t_telemetry_user
+ owner to postgres;
+
+