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; + +