diff --git a/QS.Cloud.Client/Clients/DataBaseManagementCloudClient.cs b/QS.Cloud.Client/Clients/DataBaseManagementCloudClient.cs new file mode 100644 index 000000000..9579fd835 --- /dev/null +++ b/QS.Cloud.Client/Clients/DataBaseManagementCloudClient.cs @@ -0,0 +1,21 @@ +using Grpc.Core; +using QS.Cloud.Core; +using QS.Project.Versioning; +using System.Threading; + +namespace QS.Cloud.Client.Clients { + public class DataBaseManagementCloudClient : CloudClientByBasicAuth { + private IApplicationInfo applicationInfo { get; set; } + public DataBaseManagementCloudClient(IBasicAuthInfoProvider basicAuthInfoProvider) + : base(basicAuthInfoProvider, "core.cloud.qsolution.ru", 443) + { + this.applicationInfo = applicationInfo; + } + + public CreateDataBaseResponse CreateDataBase(string dbName, string dbTitle, IApplicationInfo applicationInfo) { + var client = new DataBaseManagement.DataBaseManagementClient(Channel); + var request = new CreateDataBaseRequest { Name = dbName, Title = dbTitle, ProductId = applicationInfo.ProductCode }; + return client.CreateDataBase(request, headers); + } + } +} diff --git a/QS.Cloud.Client/QSCloudProvider.cs b/QS.Cloud.Client/DataBase/QSCloudProvider.cs similarity index 76% rename from QS.Cloud.Client/QSCloudProvider.cs rename to QS.Cloud.Client/DataBase/QSCloudProvider.cs index c6e33dd8e..c8c2c9738 100644 --- a/QS.Cloud.Client/QSCloudProvider.cs +++ b/QS.Cloud.Client/DataBase/QSCloudProvider.cs @@ -8,35 +8,42 @@ using System.Linq; using System.Reflection; using System; +using System.Threading; +using QS.Cloud.Client.Clients; +using QS.DBScripts.Controllers; +using System.Threading.Tasks; +using Microsoft.Extensions.DependencyInjection; -namespace QS.Cloud.Client +namespace QS.Cloud.Client.DataBase { public class QSCloudProvider : IDbProvider { - public string ConnectionString { get => throw new NotImplementedException(); set => throw new NotImplementedException(); } - public bool IsConnected => throw new NotImplementedException(); + public int BaseId { get; private set; } + public BasicAuthInfoProvider AuthInfo { get; private set; } + + public bool IsConnected { get; private set; } public bool IsAdmin { get; protected set; } #region Параметры подключени public string Account { get; private set; } - #endregion public string UserName { get; private set; } - private CloudFeaturesClient featuresClient; + public bool CanCreateDatabase => dbClient.CanConnect; + private LoginManagementCloudClient loginClient; - private SessionManagementCloudClient sessionClient; - private UserManagementCloudClient userClient; + private DataBaseManagementCloudClient dbClient; public QSCloudProvider(IList parameters, string password = null) { Account = parameters.First(p => p.Name == "Account").Value; UserName = parameters.First(p => p.Name == "Login").Value; - BasicAuthInfoProvider authInfo = new BasicAuthInfoProvider($@"{Account}\{UserName}", password); + AuthInfo = new BasicAuthInfoProvider($@"{Account}\{UserName}", password); - loginClient = new LoginManagementCloudClient(authInfo); + loginClient = new LoginManagementCloudClient(AuthInfo); + dbClient = new DataBaseManagementCloudClient(AuthInfo); } public bool AddUser(string username, string password) @@ -49,9 +56,12 @@ public bool ChangePassword(string username, string oldPassword, string newPasswo throw new NotImplementedException(); } - public bool CreateDatabase(string databaseName) + public bool CreateDatabase(string databaseName, string title, IServiceProvider services) { - throw new NotImplementedException(); + IApplicationInfo applicationInfo = services.GetService(); + CreateDataBaseResponse response = dbClient.CreateDataBase(databaseName, title, applicationInfo); + BaseId = response.BaseId; + return true; } public void Dispose() diff --git a/QS.Cloud.Client/QsCloudConnectionTypeBase.cs b/QS.Cloud.Client/DataBase/QsCloudConnectionTypeBase.cs similarity index 57% rename from QS.Cloud.Client/QsCloudConnectionTypeBase.cs rename to QS.Cloud.Client/DataBase/QsCloudConnectionTypeBase.cs index 504c04fe5..bf0553cb2 100644 --- a/QS.Cloud.Client/QsCloudConnectionTypeBase.cs +++ b/QS.Cloud.Client/DataBase/QsCloudConnectionTypeBase.cs @@ -1,18 +1,23 @@ +using Microsoft.Extensions.DependencyInjection; using QS.DbManagement; +using QS.DBScripts; +using QS.DBScripts.Controllers; +using QS.DBScripts.Models; +using QS.Utilities.Extensions; using System.Collections.Generic; using System.Linq; using System.Reflection; -using QS.Utilities.Extensions; -namespace QS.Cloud.Client { +namespace QS.Cloud.Client.DataBase { public class QsCloudConnectionTypeBase : ConnectionTypeBase { + public QsCloudConnectionTypeBase() { Title = "QS: Облако"; ConnectionTypeName = "QSCloud"; - + Parameters.Add(new ConnectionParameter("Account","Организация")); Parameters.Add(new ConnectionParameter("Login","Пользователь")); - + IconBytes = Assembly.GetExecutingAssembly().GetResourceByteArray("QS.Cloud.Client.Icons.qscloud.ico"); } @@ -21,7 +26,21 @@ public override bool CanConnect(IEnumerable parameters parameters.Any(p => p.Name == "Login" && !string.IsNullOrEmpty(p.Value)); } - public override IDbProvider CreateProvider(IList parameters, string password = null) - => new QSCloudProvider(parameters, password); + public override IDbProvider CreateProvider(IList parameters, string password = null) { + return new QSCloudProvider(parameters, password); + } + + public override IDbCreatorModel CreatorFactory(CreatorFactoryArgs args) { + var provider = (QSCloudProvider)args.Provider; + var scripts = args.ServiceProvider.GetRequiredService(); + var creator = new QsCloudDbCreator( + provider.BaseId, + provider.AuthInfo, + scripts, + args.Progress, + args.Interaction, + args.CancellationToken); + return creator; + } } } diff --git a/QS.Cloud.Client/DataBase/QsCloudDbCreator.cs b/QS.Cloud.Client/DataBase/QsCloudDbCreator.cs new file mode 100644 index 000000000..7e189244f --- /dev/null +++ b/QS.Cloud.Client/DataBase/QsCloudDbCreator.cs @@ -0,0 +1,86 @@ +using QS.Cloud.Core; +using QS.DBScripts; +using QS.DBScripts.Controllers; +using QS.DBScripts.Models; +using QS.Dialog; +using System; +using System.Threading; +using System.Threading.Tasks; + +namespace QS.Cloud.Client.DataBase +{ + public class QsCloudDbCreator : IDbCreatorModel + { + static NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger(); + + private readonly int baseId; + + private readonly IProgressBarDisplayable progress; + private readonly IDbCreatorInteraction interaction; + private readonly IDbScriptsConfiguration configuration; + private readonly CancellationToken cancellationToken; + + private LoginManagementCloudClient loginClient; + + public QsCloudDbCreator( + int baseId, + BasicAuthInfoProvider AuthInfo, + IDbScriptsConfiguration configuration, + IProgressBarDisplayable progress, + IDbCreatorInteraction interaction, + CancellationToken cancellationToken) + { + this.baseId = baseId; + + loginClient = new LoginManagementCloudClient(AuthInfo); + + this.configuration = configuration ?? throw new ArgumentNullException(nameof(progress)); + this.progress = progress ?? throw new ArgumentNullException(nameof(progress)); + this.interaction = interaction ?? throw new ArgumentNullException(nameof(interaction)); + this.cancellationToken = cancellationToken; + } + + + public async Task RunCreationAsync(string dbName, string dbTitle) { + try { + StartSessionResponse session = loginClient.StartSession(baseId); + + if(!session.Success) { + await interaction.ReportErrorAsync("Ошибка в создании сесии", "Запрос в облако"); + throw new InvalidOperationException("Ошибка в создании сесии"); + } + else if(!session.IsAdmin) { + await interaction.ReportErrorAsync("Вы не имеете прав Администратора", "Запрос в облако"); + } + + var infoProvider = new SessionInfoProvider(sessionId: session.SessionId); + var sessionLife = new AliveCloudClient(infoProvider); + sessionLife.NewMessage += (mes) => { + progress.Update("Сессия: " + mes + " в статусе " + sessionLife.LastStatus.ToString()); + }; + sessionLife.KeepAlive(); + + var creator = new MySqlDbCreateModel(session.Db.Server, session.Db.Port, session.Db.Login, session.Db.Password, configuration, progress, interaction, cancellationToken); + creator.FillBaseGuid = false; + bool success = await creator.RunCreationAsync(session.Db.BaseName, dbTitle); + + sessionLife.Dispose(); + + return success; + } + catch(OperationCanceledException) { + logger.Info("Создание базы в облаке отменено пользователем."); + return false; + } + catch(Exception ex) { + logger.Error(ex, "Ошибка при создании базы в облаке."); + await interaction.ReportErrorAsync(ex.Message, null); + throw; + } + finally { + if(progress.IsStarted) + progress.Close(); + } + } + } +} diff --git a/QS.Cloud.Client/DataBase/QsCloudScriptsConfiguration.cs b/QS.Cloud.Client/DataBase/QsCloudScriptsConfiguration.cs new file mode 100644 index 000000000..20c1d0ac2 --- /dev/null +++ b/QS.Cloud.Client/DataBase/QsCloudScriptsConfiguration.cs @@ -0,0 +1,38 @@ +using QS.DBScripts; +using QS.DBScripts.Models; +using QS.Updater.DB; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Text; + +namespace QS.Cloud.Client.DataBase { + public class QsCloudScriptsConfiguration : IDbScriptsConfiguration { + private string ResourceName = "QS.Cloud.Client.Scripts.new_empty.sql"; + public bool HasCreationScript() { + return Assembly.GetAssembly(typeof(QsCloudScriptsConfiguration)) + .GetReferencedAssemblies().Select(x => x.FullName) + .Contains(ResourceName); + } + + public CreationScript MakeCreationScript() { + return new CreationScript( + Assembly.GetAssembly(typeof(QsCloudScriptsConfiguration)), + ResourceName, + new Version(1, 7) + ); + } + + public UpdateConfiguration MakeUpdateConfiguration() { + var configuration = new UpdateConfiguration(); + + configuration.AddUpdate( + new Version(1, 7), + new Version(1, 7, 1), + "QS.Cloud.Client.Scripts.1.7.sql"); + + return configuration; + } + } +} diff --git a/QS.Cloud.Client/Protos/DataBaseManagement.proto b/QS.Cloud.Client/Protos/DataBaseManagement.proto new file mode 100644 index 000000000..bb5c03f91 --- /dev/null +++ b/QS.Cloud.Client/Protos/DataBaseManagement.proto @@ -0,0 +1,19 @@ +syntax = "proto3"; + +package QS.Cloud.Core; + +service DataBaseManagement{ + // Создать пустую базу + rpc CreateDataBase (CreateDataBaseRequest) returns (CreateDataBaseResponse); +} + +message CreateDataBaseRequest{ + string name = 1; + string title = 2; + uint32 product_id = 3; +} + +message CreateDataBaseResponse{ + int32 base_id = 1; + string base_guid = 2; +} diff --git a/QS.Cloud.Client/QS.Cloud.Client.csproj b/QS.Cloud.Client/QS.Cloud.Client.csproj index ec2e96649..2ee482c3f 100644 --- a/QS.Cloud.Client/QS.Cloud.Client.csproj +++ b/QS.Cloud.Client/QS.Cloud.Client.csproj @@ -1,4 +1,4 @@ - + netstandard2.0 @@ -15,6 +15,11 @@ + + + + + @@ -22,11 +27,14 @@ + + + diff --git a/QS.Cloud.Client/Scripts/new_empty.sql b/QS.Cloud.Client/Scripts/new_empty.sql new file mode 100644 index 000000000..b25952e11 --- /dev/null +++ b/QS.Cloud.Client/Scripts/new_empty.sql @@ -0,0 +1,779 @@ +-- phpMyAdmin SQL Dump +-- version 5.0.4deb2~bpo10+1 +-- https://www.phpmyadmin.net/ +-- +-- Host: demeter.srv.qsolution.ru +-- Generation Time: Apr 30, 2026 at 01:52 PM +-- Server version: 10.3.39-MariaDB-0+deb10u2 +-- PHP Version: 7.3.31-1~deb10u7 + +SET SQL_MODE = "NO_AUTO_VALUE_ON_ZERO"; +START TRANSACTION; +SET time_zone = "+00:00"; + + +/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */; +/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */; +/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */; +/*!40101 SET NAMES utf8mb4 */; + +-- +-- Database: `QSService` +-- + +-- -------------------------------------------------------- + +-- +-- Table structure for table `accounts` +-- + +CREATE TABLE `accounts` ( + `id` int(10) UNSIGNED NOT NULL, + `login` varchar(20) NOT NULL, + `client_id` int(10) UNSIGNED DEFAULT NULL, + `customer` varchar(50) NOT NULL, + `email` varchar(50) DEFAULT NULL, + `paid_until` date DEFAULT NULL, + `notify_by_days` int(11) DEFAULT NULL COMMENT 'Уведомить за Н дней до окончания', + `bases_limit` int(10) UNSIGNED NOT NULL DEFAULT 1, + `users_limit` int(10) UNSIGNED NOT NULL DEFAULT 3, + `space_limit` int(10) UNSIGNED NOT NULL DEFAULT 500, + `deactivated` tinyint(1) NOT NULL DEFAULT 0 +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci; + +-- -------------------------------------------------------- + +-- +-- Table structure for table `api_tokens` +-- + +CREATE TABLE `api_tokens` ( + `id` int(10) UNSIGNED NOT NULL, + `base_id` int(10) UNSIGNED NOT NULL, + `token` char(36) NOT NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci; + +-- -------------------------------------------------------- + +-- +-- Table structure for table `bases` +-- + +CREATE TABLE `bases` ( + `id` int(10) UNSIGNED NOT NULL, + `account_id` int(10) UNSIGNED NOT NULL, + `server_id` int(10) UNSIGNED NOT NULL, + `base_title` varchar(64) DEFAULT NULL COMMENT 'Русское название базы для пользователя', + `base_name` varchar(45) NOT NULL, + `product_id` int(10) UNSIGNED NOT NULL, + `real_name` varchar(64) DEFAULT NULL, + `base_guid` char(36) DEFAULT NULL, + `wear_lk` tinyint(1) NOT NULL DEFAULT 0, + `number_of_lk_client` int(11) DEFAULT 0, + `claims_lk` tinyint(1) NOT NULL DEFAULT 0, + `postomats` tinyint(1) NOT NULL DEFAULT 0, + `catalog` tinyint(1) NOT NULL DEFAULT 0, + `comments` text DEFAULT NULL, + `ratings` tinyint(1) NOT NULL DEFAULT 0, + `appointment_lk` tinyint(1) NOT NULL DEFAULT 0 COMMENT 'включение предварительной записи', + `washing_lk` tinyint(1) NOT NULL DEFAULT 0 COMMENT 'Включение отображения стирки в мобильном кабинете', + `speccoin_lk` tinyint(1) NOT NULL DEFAULT 0 COMMENT 'Включение функциональности спецкойнов', + `size_editing_lk` tinyint(1) NOT NULL DEFAULT 1 COMMENT 'Редактирование размеров в мобилке', + `size_editing_days_before` int(10) UNSIGNED NOT NULL DEFAULT 0 COMMENT 'Запрет изменения размеров за указанное количество дней до выдачи.', + `postomat_email_notification` tinyint(1) NOT NULL DEFAULT 0 COMMENT 'Дублируют ли постоматы уведомления на Email.', + `stock_availability_enable` tinyint(1) NOT NULL DEFAULT 0, + `stock_availability_warehouse_id` int(10) UNSIGNED DEFAULT NULL COMMENT 'id склада по которому показывать наличие', + `choice_nomenclature_lk` tinyint(1) NOT NULL DEFAULT 0 COMMENT 'Выбор номенклатур сотрудником' +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci; + +-- -------------------------------------------------------- + +-- +-- Table structure for table `bases_scripts` +-- + +CREATE TABLE `bases_scripts` ( + `id` int(10) UNSIGNED NOT NULL, + `product_id` int(10) UNSIGNED NOT NULL, + `start_version` varchar(15) DEFAULT NULL, + `end_version` varchar(15) NOT NULL, + `script` mediumtext DEFAULT NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci; + +-- -------------------------------------------------------- + +-- +-- Table structure for table `base_access` +-- + +CREATE TABLE `base_access` ( + `id` int(10) UNSIGNED NOT NULL, + `user_id` int(10) UNSIGNED NOT NULL, + `base_id` int(10) UNSIGNED NOT NULL, + `admin` tinyint(1) NOT NULL DEFAULT 0, + `read_only` tinyint(1) NOT NULL DEFAULT 0, + `torpedo` tinyint(1) NOT NULL DEFAULT 0 COMMENT 'База доступна в панели инструментов' +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci; + +-- -------------------------------------------------------- + +-- +-- Table structure for table `base_parameters` +-- + +CREATE TABLE `base_parameters` ( + `name` varchar(20) NOT NULL, + `str_value` varchar(100) DEFAULT NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci; + + + +INSERT INTO `base_parameters` (`name`, `str_value`) VALUES +('ProductCode', '5'), +('product_name', 'ClientManager'), +('version', '1.7'); + +-- -------------------------------------------------------- + +-- +-- Table structure for table `bug_reports` +-- + +CREATE TABLE `bug_reports` ( + `id` int(10) UNSIGNED NOT NULL, + `created` datetime DEFAULT NULL, + `last_update` datetime DEFAULT NULL, + `product_id` int(10) UNSIGNED NOT NULL, + `edition` varchar(20) DEFAULT NULL, + `version` varchar(16) NOT NULL, + `fixed_in_version` varchar(16) DEFAULT NULL COMMENT 'Версия в которой баг пофикшен', + `message` varchar(2000) DEFAULT NULL, + `stack_trace` text DEFAULT NULL, + `description` text DEFAULT NULL, + `email` varchar(600) DEFAULT NULL, + `count` int(10) UNSIGNED DEFAULT 1, + `status` enum('New','InWork','NeedInfo','Rejected','Later','Known','Unreproducable','EndOfLife','Done') DEFAULT 'New', + `comments` text DEFAULT NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci; + +-- -------------------------------------------------------- + +-- +-- Table structure for table `bug_reports_messages` +-- + +CREATE TABLE `bug_reports_messages` ( + `id` int(10) UNSIGNED NOT NULL, + `created` datetime NOT NULL, + `bug_reports_id` int(10) UNSIGNED NOT NULL, + `email` varchar(254) DEFAULT NULL, + `user_name` varchar(60) DEFAULT NULL, + `messages` text DEFAULT NULL, + `db_name` varchar(60) DEFAULT NULL, + `report_type` enum('User','Automatic','Known') NOT NULL DEFAULT 'User', + `log_file` mediumtext DEFAULT NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci; + +-- -------------------------------------------------------- + +-- +-- Table structure for table `clients` +-- + +CREATE TABLE `clients` ( + `id` int(10) UNSIGNED NOT NULL, + `name` varchar(300) NOT NULL, + `email` varchar(45) DEFAULT NULL, + `email_notifications` varchar(200) DEFAULT NULL COMMENT 'Адреса для уведомлений', + `city` varchar(45) DEFAULT NULL, + `comments` text DEFAULT NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci; + +-- -------------------------------------------------------- + +-- +-- Table structure for table `cloud_users` +-- + +CREATE TABLE `cloud_users` ( + `id` int(10) UNSIGNED NOT NULL, + `login` varchar(20) NOT NULL, + `name` varchar(80) DEFAULT NULL, + `password` varchar(81) NOT NULL, + `disabled` tinyint(1) NOT NULL DEFAULT 0 COMMENT 'Пользователь отключен', + `is_account_admin` tinyint(1) NOT NULL DEFAULT 0 COMMENT 'Администратор учетной записи', + `post` varchar(200) DEFAULT NULL COMMENT 'Должность', + `phone` varchar(16) DEFAULT NULL COMMENT 'Телефон', + `email` varchar(60) DEFAULT NULL, + `account_id` int(10) UNSIGNED NOT NULL, + `multi_ip` tinyint(1) NOT NULL DEFAULT 0, + `client_id` int(10) UNSIGNED DEFAULT NULL, + `comment` text DEFAULT NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci; + +-- -------------------------------------------------------- + +-- +-- Table structure for table `products` +-- + +CREATE TABLE `products` ( + `id` int(10) UNSIGNED NOT NULL, + `name` varchar(45) NOT NULL, + `internal_name` varchar(45) NOT NULL, + `not_support_ver_regexp` varchar(45) DEFAULT NULL, + `telegram_notify` varchar(50) DEFAULT NULL COMMENT 'Отправлять уведомления о новых ошибках в чат' +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci; + +-- -------------------------------------------------------- + +-- +-- Table structure for table `product_editions` +-- + +CREATE TABLE `product_editions` ( + `id` int(10) UNSIGNED NOT NULL, + `product_id` int(10) UNSIGNED NOT NULL, + `code_number` int(10) UNSIGNED DEFAULT NULL COMMENT 'Номер редакции, внутри продукта', + `code_name` varchar(10) DEFAULT NULL COMMENT 'Кодовое имя редакции.', + `name` varchar(100) DEFAULT NULL COMMENT 'Название редакции отображаемое для пользователя.' +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci; + +-- -------------------------------------------------------- + +-- +-- Table structure for table `product_versions` +-- + +CREATE TABLE `product_versions` ( + `id` int(10) UNSIGNED NOT NULL, + `product_id` int(10) UNSIGNED NOT NULL, + `modification` varchar(25) DEFAULT NULL, + `channel` enum('Current','Stable') NOT NULL DEFAULT 'Current', + `disable` tinyint(1) NOT NULL DEFAULT 0, + `version_major` int(10) UNSIGNED NOT NULL DEFAULT 0, + `version_minor` int(10) UNSIGNED NOT NULL DEFAULT 0, + `version_build` int(10) UNSIGNED NOT NULL DEFAULT 0, + `version_revision` int(10) UNSIGNED NOT NULL DEFAULT 0, + `date` date NOT NULL, + `link_install` varchar(256) DEFAULT NULL, + `link_news` varchar(256) DEFAULT NULL, + `changes` text DEFAULT NULL, + `db_update` enum('None','Required','BreakingChange') NOT NULL DEFAULT 'None', + `comment` text DEFAULT NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci; + +-- -------------------------------------------------------- + +-- +-- Table structure for table `serial_numbers` +-- + +CREATE TABLE `serial_numbers` ( + `id` int(10) UNSIGNED NOT NULL, + `client_id` int(10) UNSIGNED NOT NULL, + `number` varchar(50) NOT NULL, + `recall` tinyint(1) NOT NULL DEFAULT 0, + `notify_by_days` int(11) DEFAULT NULL COMMENT 'Уведомить за Н дней до окончания', + `active_until` date DEFAULT NULL, + `serial_expiry_date` date DEFAULT NULL COMMENT 'Дата окончания действия серийного номера', + `instance` int(10) UNSIGNED NOT NULL DEFAULT 1, + `comment` text DEFAULT NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci; + +-- -------------------------------------------------------- + +-- +-- Table structure for table `servers` +-- + +CREATE TABLE `servers` ( + `id` int(10) UNSIGNED NOT NULL, + `server_address` varchar(60) NOT NULL, + `service_user` varchar(16) NOT NULL, + `service_password` varchar(81) NOT NULL, + `comment` text DEFAULT NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci; + +-- -------------------------------------------------------- + +-- +-- Table structure for table `sessions` +-- + +CREATE TABLE `sessions` ( + `id` int(10) UNSIGNED NOT NULL, + `session_id` varchar(36) NOT NULL, + `user_id` int(10) UNSIGNED DEFAULT NULL, + `account_id` int(10) UNSIGNED NOT NULL, + `base_id` int(10) UNSIGNED NOT NULL, + `start_time` datetime NOT NULL, + `end_time` datetime NOT NULL, + `is_closed` tinyint(1) NOT NULL DEFAULT 0, + `login` varchar(40) DEFAULT NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci; + +-- -------------------------------------------------------- + +-- +-- Table structure for table `telemetry_statistics` +-- + +CREATE TABLE `telemetry_statistics` ( + `id` int(10) UNSIGNED NOT NULL, + `last_update` datetime NOT NULL, + `ip_address` varchar(39) DEFAULT NULL, + `product` varchar(20) NOT NULL, + `edition` varchar(20) DEFAULT NULL, + `version` varchar(20) NOT NULL, + `os` varchar(100) DEFAULT NULL, + `net_framework` varchar(100) DEFAULT NULL, + `is_demo` tinyint(1) NOT NULL DEFAULT 0, + `app_edition` int(10) UNSIGNED DEFAULT NULL COMMENT 'Редакция программы', + `base_employees` int(10) UNSIGNED DEFAULT NULL COMMENT 'Количество сотрудников в базе', + `counter` mediumtext NOT NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci; + +-- -------------------------------------------------------- + +-- +-- Table structure for table `update_info` +-- + +CREATE TABLE `update_info` ( + `id` int(10) UNSIGNED NOT NULL, + `product` varchar(25) NOT NULL, + `edition` varchar(25) DEFAULT NULL, + `serial_number` varchar(45) DEFAULT NULL, + `start_version_major` int(10) UNSIGNED DEFAULT 0, + `start_version_minor` int(10) UNSIGNED DEFAULT 0, + `start_version_build` int(10) UNSIGNED DEFAULT 0, + `start_version_revision` int(10) UNSIGNED DEFAULT 0, + `new_version_major` int(10) UNSIGNED DEFAULT 0, + `new_version_minor` int(10) UNSIGNED DEFAULT 0, + `new_version_build` int(10) UNSIGNED DEFAULT 0, + `new_version_revision` int(10) UNSIGNED DEFAULT 0, + `link_install` varchar(256) NOT NULL, + `link_news` varchar(256) DEFAULT NULL, + `use_common` tinyint(1) DEFAULT 0, + `update_description` text DEFAULT NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci; + +-- -------------------------------------------------------- + +-- +-- Table structure for table `update_statistics` +-- + +CREATE TABLE `update_statistics` ( + `id` int(10) UNSIGNED NOT NULL, + `product_id` int(10) UNSIGNED DEFAULT NULL, + `edition` varchar(25) DEFAULT NULL, + `serial_number` varchar(45) DEFAULT NULL, + `client_version` varchar(16) NOT NULL, + `new_version` varchar(16) DEFAULT NULL, + `date` datetime NOT NULL DEFAULT utc_timestamp(), + `client_ip` varchar(15) DEFAULT NULL, + `channel` enum('Current','Stable') NOT NULL DEFAULT 'Current', + `status` enum('NoUpdates','NeedUpdate','Expired','Recalled','LicenceNotFound') DEFAULT NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci; + +-- -------------------------------------------------------- + +-- +-- Table structure for table `users` +-- + +CREATE TABLE `users` ( + `id` int(10) UNSIGNED NOT NULL, + `name` varchar(45) NOT NULL, + `login` varchar(45) NOT NULL, + `deactivated` tinyint(1) NOT NULL DEFAULT 0, + `email` varchar(60) DEFAULT NULL, + `description` text DEFAULT NULL, + `admin` tinyint(1) NOT NULL DEFAULT 0 +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci; + +-- +-- Indexes for dumped tables +-- + +-- +-- Indexes for table `accounts` +-- +ALTER TABLE `accounts` + ADD PRIMARY KEY (`id`), + ADD UNIQUE KEY `login_UNIQUE` (`login`), + ADD KEY `fk_accounts_1_idx` (`client_id`); + +-- +-- Indexes for table `api_tokens` +-- +ALTER TABLE `api_tokens` + ADD PRIMARY KEY (`id`), + ADD UNIQUE KEY `token_UNIQUE` (`token`), + ADD KEY `fk_api_tokens_1_idx` (`base_id`); + +-- +-- Indexes for table `bases` +-- +ALTER TABLE `bases` + ADD PRIMARY KEY (`id`), + ADD UNIQUE KEY `idx1_bases` (`base_name`,`account_id`), + ADD UNIQUE KEY `base_guid_UNIQUE` (`base_guid`), + ADD KEY `fk1_bases_idx` (`account_id`), + ADD KEY `fk2_bases_idx` (`server_id`), + ADD KEY `fk3_bases_idx` (`product_id`); + +-- +-- Indexes for table `bases_scripts` +-- +ALTER TABLE `bases_scripts` + ADD PRIMARY KEY (`id`), + ADD KEY `fk1_bases_scripts_idx` (`product_id`); + +-- +-- Indexes for table `base_access` +-- +ALTER TABLE `base_access` + ADD PRIMARY KEY (`id`), + ADD UNIQUE KEY `base_access_idx` (`user_id`,`base_id`), + ADD KEY `fk1_base_access_idx` (`user_id`), + ADD KEY `fk1_base_access_idx1` (`base_id`); + +-- +-- Indexes for table `base_parameters` +-- +ALTER TABLE `base_parameters` + ADD PRIMARY KEY (`name`); + +-- +-- Indexes for table `bug_reports` +-- +ALTER TABLE `bug_reports` + ADD PRIMARY KEY (`id`), + ADD KEY `fk_bug_reports_1_idx` (`product_id`), + ADD KEY `bug_reports_created` (`created`), + ADD KEY `bug_reports_last_update` (`last_update`), + ADD KEY `bug_reports_edition` (`edition`), + ADD KEY `bug_reports_version` (`version`), + ADD KEY `bug_reports_status` (`status`); + +-- +-- Indexes for table `bug_reports_messages` +-- +ALTER TABLE `bug_reports_messages` + ADD PRIMARY KEY (`id`), + ADD KEY `fk_bug_reports_messages_1_idx` (`bug_reports_id`); + +-- +-- Indexes for table `clients` +-- +ALTER TABLE `clients` + ADD PRIMARY KEY (`id`); + +-- +-- Indexes for table `cloud_users` +-- +ALTER TABLE `cloud_users` + ADD PRIMARY KEY (`id`), + ADD UNIQUE KEY `idx1_users` (`login`,`account_id`), + ADD KEY `fk1_users_idx` (`account_id`), + ADD KEY `fk_cloud_users_1_idx` (`client_id`); + +-- +-- Indexes for table `products` +-- +ALTER TABLE `products` + ADD PRIMARY KEY (`id`), + ADD UNIQUE KEY `internal_name_UNIQUE` (`internal_name`); + +-- +-- Indexes for table `product_editions` +-- +ALTER TABLE `product_editions` + ADD PRIMARY KEY (`id`), + ADD KEY `fk_product_id_idx` (`product_id`); + +-- +-- Indexes for table `product_versions` +-- +ALTER TABLE `product_versions` + ADD PRIMARY KEY (`id`), + ADD KEY `_idx` (`product_id`); + +-- +-- Indexes for table `serial_numbers` +-- +ALTER TABLE `serial_numbers` + ADD PRIMARY KEY (`id`), + ADD UNIQUE KEY `number_UNIQUE` (`number`), + ADD KEY `fk_serial_numbers_1_idx` (`client_id`); + +-- +-- Indexes for table `servers` +-- +ALTER TABLE `servers` + ADD PRIMARY KEY (`id`); + +-- +-- Indexes for table `sessions` +-- +ALTER TABLE `sessions` + ADD PRIMARY KEY (`id`), + ADD UNIQUE KEY `session_id_UNIQUE` (`session_id`), + ADD KEY `fk1_sessions_idx` (`account_id`), + ADD KEY `fk2_sessions_idx` (`user_id`), + ADD KEY `fk3_sessions_idx` (`base_id`), + ADD KEY `end_time_idx` (`end_time`), + ADD KEY `is_closed_idx` (`is_closed`); + +-- +-- Indexes for table `telemetry_statistics` +-- +ALTER TABLE `telemetry_statistics` + ADD PRIMARY KEY (`id`), + ADD KEY `index_telemetry_statistics_last_update` (`last_update`), + ADD KEY `index_telemetry_statistics_ip` (`ip_address`), + ADD KEY `index_telemetry_statistics_product` (`product`), + ADD KEY `index_telemetry_statistics_edition` (`edition`), + ADD KEY `index_telemetry_statistics_version` (`version`), + ADD KEY `inxex_telemetry_statistics_os` (`os`); + +-- +-- Indexes for table `update_info` +-- +ALTER TABLE `update_info` + ADD PRIMARY KEY (`id`); + +-- +-- Indexes for table `update_statistics` +-- +ALTER TABLE `update_statistics` + ADD PRIMARY KEY (`id`), + ADD UNIQUE KEY `id_UNIQUE` (`id`), + ADD KEY `fk_update_statistics_1_idx` (`product_id`), + ADD KEY `update_statistics_edition_idx` (`edition`), + ADD KEY `update_statistics_serial_idx` (`serial_number`), + ADD KEY `update_statistics_client_version_idx` (`client_version`), + ADD KEY `update_statistics_ip_idx` (`client_ip`), + ADD KEY `update_statistics_new_version_idx` (`new_version`), + ADD KEY `update_statistics_date_idx` (`date`), + ADD KEY `update_statistics_channel_idx` (`channel`); + +-- +-- Indexes for table `users` +-- +ALTER TABLE `users` + ADD PRIMARY KEY (`id`); + +-- +-- AUTO_INCREMENT for dumped tables +-- + +-- +-- AUTO_INCREMENT for table `accounts` +-- +ALTER TABLE `accounts` + MODIFY `id` int(10) UNSIGNED NOT NULL AUTO_INCREMENT; + +-- +-- AUTO_INCREMENT for table `api_tokens` +-- +ALTER TABLE `api_tokens` + MODIFY `id` int(10) UNSIGNED NOT NULL AUTO_INCREMENT; + +-- +-- AUTO_INCREMENT for table `bases` +-- +ALTER TABLE `bases` + MODIFY `id` int(10) UNSIGNED NOT NULL AUTO_INCREMENT; + +-- +-- AUTO_INCREMENT for table `bases_scripts` +-- +ALTER TABLE `bases_scripts` + MODIFY `id` int(10) UNSIGNED NOT NULL AUTO_INCREMENT; + +-- +-- AUTO_INCREMENT for table `base_access` +-- +ALTER TABLE `base_access` + MODIFY `id` int(10) UNSIGNED NOT NULL AUTO_INCREMENT; + +-- +-- AUTO_INCREMENT for table `bug_reports` +-- +ALTER TABLE `bug_reports` + MODIFY `id` int(10) UNSIGNED NOT NULL AUTO_INCREMENT; + +-- +-- AUTO_INCREMENT for table `bug_reports_messages` +-- +ALTER TABLE `bug_reports_messages` + MODIFY `id` int(10) UNSIGNED NOT NULL AUTO_INCREMENT; + +-- +-- AUTO_INCREMENT for table `clients` +-- +ALTER TABLE `clients` + MODIFY `id` int(10) UNSIGNED NOT NULL AUTO_INCREMENT; + +-- +-- AUTO_INCREMENT for table `cloud_users` +-- +ALTER TABLE `cloud_users` + MODIFY `id` int(10) UNSIGNED NOT NULL AUTO_INCREMENT; + +-- +-- AUTO_INCREMENT for table `products` +-- +ALTER TABLE `products` + MODIFY `id` int(10) UNSIGNED NOT NULL AUTO_INCREMENT; + +-- +-- AUTO_INCREMENT for table `product_editions` +-- +ALTER TABLE `product_editions` + MODIFY `id` int(10) UNSIGNED NOT NULL AUTO_INCREMENT; + +-- +-- AUTO_INCREMENT for table `product_versions` +-- +ALTER TABLE `product_versions` + MODIFY `id` int(10) UNSIGNED NOT NULL AUTO_INCREMENT; + +-- +-- AUTO_INCREMENT for table `serial_numbers` +-- +ALTER TABLE `serial_numbers` + MODIFY `id` int(10) UNSIGNED NOT NULL AUTO_INCREMENT; + +-- +-- AUTO_INCREMENT for table `servers` +-- +ALTER TABLE `servers` + MODIFY `id` int(10) UNSIGNED NOT NULL AUTO_INCREMENT; + +-- +-- AUTO_INCREMENT for table `sessions` +-- +ALTER TABLE `sessions` + MODIFY `id` int(10) UNSIGNED NOT NULL AUTO_INCREMENT; + +-- +-- AUTO_INCREMENT for table `telemetry_statistics` +-- +ALTER TABLE `telemetry_statistics` + MODIFY `id` int(10) UNSIGNED NOT NULL AUTO_INCREMENT; + +-- +-- AUTO_INCREMENT for table `update_info` +-- +ALTER TABLE `update_info` + MODIFY `id` int(10) UNSIGNED NOT NULL AUTO_INCREMENT; + +-- +-- AUTO_INCREMENT for table `update_statistics` +-- +ALTER TABLE `update_statistics` + MODIFY `id` int(10) UNSIGNED NOT NULL AUTO_INCREMENT; + +-- +-- AUTO_INCREMENT for table `users` +-- +ALTER TABLE `users` + MODIFY `id` int(10) UNSIGNED NOT NULL AUTO_INCREMENT; + +-- +-- Constraints for dumped tables +-- + +-- +-- Constraints for table `accounts` +-- +ALTER TABLE `accounts` + ADD CONSTRAINT `fk_accounts_1` FOREIGN KEY (`client_id`) REFERENCES `clients` (`id`) ON DELETE SET NULL ON UPDATE CASCADE; + +-- +-- Constraints for table `api_tokens` +-- +ALTER TABLE `api_tokens` + ADD CONSTRAINT `fk_api_tokens_1` FOREIGN KEY (`base_id`) REFERENCES `bases` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION; + +-- +-- Constraints for table `bases` +-- +ALTER TABLE `bases` + ADD CONSTRAINT `fk1_bases` FOREIGN KEY (`account_id`) REFERENCES `accounts` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION, + ADD CONSTRAINT `fk2_bases` FOREIGN KEY (`server_id`) REFERENCES `servers` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION, + ADD CONSTRAINT `fk3_bases` FOREIGN KEY (`product_id`) REFERENCES `products` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION; + +-- +-- Constraints for table `bases_scripts` +-- +ALTER TABLE `bases_scripts` + ADD CONSTRAINT `fk1_bases_scripts` FOREIGN KEY (`product_id`) REFERENCES `products` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION; + +-- +-- Constraints for table `base_access` +-- +ALTER TABLE `base_access` + ADD CONSTRAINT `fk1_base_access` FOREIGN KEY (`user_id`) REFERENCES `cloud_users` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION, + ADD CONSTRAINT `fk2_base_access` FOREIGN KEY (`base_id`) REFERENCES `bases` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION; + +-- +-- Constraints for table `bug_reports` +-- +ALTER TABLE `bug_reports` + ADD CONSTRAINT `fk_bug_reports_1` FOREIGN KEY (`product_id`) REFERENCES `products` (`id`) ON DELETE CASCADE ON UPDATE NO ACTION; + +-- +-- Constraints for table `bug_reports_messages` +-- +ALTER TABLE `bug_reports_messages` + ADD CONSTRAINT `fk_bug_reports_messages_1` FOREIGN KEY (`bug_reports_id`) REFERENCES `bug_reports` (`id`) ON DELETE CASCADE ON UPDATE CASCADE; + +-- +-- Constraints for table `cloud_users` +-- +ALTER TABLE `cloud_users` + ADD CONSTRAINT `fk1_users` FOREIGN KEY (`account_id`) REFERENCES `accounts` (`id`) ON DELETE CASCADE ON UPDATE NO ACTION, + ADD CONSTRAINT `fk_cloud_users_1` FOREIGN KEY (`client_id`) REFERENCES `clients` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION; + +-- +-- Constraints for table `product_editions` +-- +ALTER TABLE `product_editions` + ADD CONSTRAINT `fk_product_id` FOREIGN KEY (`product_id`) REFERENCES `products` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION; + +-- +-- Constraints for table `product_versions` +-- +ALTER TABLE `product_versions` + ADD CONSTRAINT `fk_product_versions_1` FOREIGN KEY (`product_id`) REFERENCES `products` (`id`) ON DELETE CASCADE ON UPDATE CASCADE; + +-- +-- Constraints for table `serial_numbers` +-- +ALTER TABLE `serial_numbers` + ADD CONSTRAINT `fk_serial_numbers_1` FOREIGN KEY (`client_id`) REFERENCES `clients` (`id`) ON DELETE CASCADE ON UPDATE CASCADE; + +-- +-- Constraints for table `sessions` +-- +ALTER TABLE `sessions` + ADD CONSTRAINT `fk1_sessions` FOREIGN KEY (`account_id`) REFERENCES `accounts` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION, + ADD CONSTRAINT `fk2_sessions` FOREIGN KEY (`user_id`) REFERENCES `cloud_users` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION, + ADD CONSTRAINT `fk3_sessions` FOREIGN KEY (`base_id`) REFERENCES `bases` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION; + +-- +-- Constraints for table `update_statistics` +-- +ALTER TABLE `update_statistics` + ADD CONSTRAINT `fk_update_statistics_1` FOREIGN KEY (`product_id`) REFERENCES `products` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION; +COMMIT; + +/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */; +/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */; +/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */; diff --git a/QS.DbManagement/ConnectionTypeBase.cs b/QS.DbManagement/ConnectionTypeBase.cs index 377ecad56..c3caca35c 100644 --- a/QS.DbManagement/ConnectionTypeBase.cs +++ b/QS.DbManagement/ConnectionTypeBase.cs @@ -1,5 +1,7 @@ using System; using System.Collections.Generic; +using QS.DBScripts.Controllers; +using QS.Dialog; namespace QS.DbManagement { @@ -10,9 +12,27 @@ public abstract class ConnectionTypeBase { public List Parameters { get; } = new List(); public byte[] IconBytes { get; protected set; } - + public abstract bool CanConnect(IEnumerable parameters); public abstract IDbProvider CreateProvider(IList parameters, string password = null); + + public abstract IDbCreatorModel CreatorFactory(CreatorFactoryArgs args); + + public IDbCreatorModel CreateCreator(CreatorFactoryArgs args) { + return CreatorFactory(args); + } + } + + /// + /// interaction — канал диалогов с пользователем + /// serviceProvider — для резолва дополнительных зависимостей + /// + public class CreatorFactoryArgs { + public IDbProvider Provider { get; set; } + public IProgressBarDisplayable Progress { get; set; } + public IDbCreatorInteraction Interaction { get; set; } + public System.Threading.CancellationToken CancellationToken { get; set; } + public IServiceProvider ServiceProvider { get; set; } } } diff --git a/QS.DbManagement/IDbProvider.cs b/QS.DbManagement/IDbProvider.cs index da6ea6964..c97d2f142 100644 --- a/QS.DbManagement/IDbProvider.cs +++ b/QS.DbManagement/IDbProvider.cs @@ -10,8 +10,8 @@ public interface IDbProvider : IDisposable string UserName { get; } bool ChangePassword(string username, string oldPassword, string newPassword); - - bool CreateDatabase(string databaseName); + + bool CreateDatabase(string databaseName, string title, IServiceProvider services = null); bool DropDatabase(string databaseName); @@ -26,5 +26,6 @@ public interface IDbProvider : IDisposable bool IsConnected { get; } bool IsAdmin { get; } + bool CanCreateDatabase { get; } } } diff --git a/QS.DbManagement/MariaDb/MariaDBProvider.cs b/QS.DbManagement/MariaDb/MariaDBProvider.cs index b0343a132..880714f9c 100644 --- a/QS.DbManagement/MariaDb/MariaDBProvider.cs +++ b/QS.DbManagement/MariaDb/MariaDBProvider.cs @@ -1,4 +1,5 @@ using Dapper; +using FluentNHibernate.Cfg.Db; using MySqlConnector; using QS.DbManagement.Responces; using QS.Project.Versioning; @@ -15,17 +16,23 @@ public class MariaDBProvider : IDbProvider { private static readonly string[] SystemDatabases = { "information_schema", "mysql", "performance_schema", "sys" }; readonly MySqlConnection connection; - readonly MySqlConnectionStringBuilder connectionStringBuilder; + + /// + /// Публичный - в типе родключения нужен доступ, реализацию он знает и так + /// + public MySqlConnectionStringBuilder ConnectionStringBuilder { get; } public bool IsConnected => connection.State == ConnectionState.Open; public bool IsAdmin { get; private set; } + public bool CanCreateDatabase { get; private set; } + /// - /// Есть ли у текущего пользователя право создавать базы данных. - /// Определяется в момент из SHOW GRANTS. + /// Переданный в тайтл созданой базы, + /// нужен потом при применения скрипта с наполнением базы /// - public bool CanCreateDatabase { get; private set; } + public string CreatedTitle { get; private set; } #region Параметры подключения public string Server { get; } @@ -51,15 +58,15 @@ public MariaDBProvider(IList parameters, string passwo } Server = serverValue; - connectionStringBuilder = new MySqlConnectionStringBuilder { + ConnectionStringBuilder = new MySqlConnectionStringBuilder { Server = host, UserID = UserName, Password = password, AllowUserVariables = true }; if(port != null) - connectionStringBuilder.Port = port.Value; - connection = new MySqlConnection(connectionStringBuilder.ConnectionString); + ConnectionStringBuilder.Port = port.Value; + connection = new MySqlConnection(ConnectionStringBuilder.ConnectionString); } #region IDbProvider @@ -142,11 +149,11 @@ public List GetUserDatabases(IApplicationInfo applicationInfo) { public LoginToDatabaseResponse LoginToDatabase(DbInfo dbInfo) { try { - connectionStringBuilder.Database = dbInfo.BaseName; + ConnectionStringBuilder.Database = dbInfo.BaseName; return new LoginToDatabaseResponse { Success = true, - ConnectionString = connectionStringBuilder.ConnectionString, + ConnectionString = ConnectionStringBuilder.ConnectionString, Login = UserName, Parameters = new Dictionary { { "BaseTitle", dbInfo.Title } @@ -171,7 +178,8 @@ public bool ChangePassword(string username, string oldPassword, string newPasswo return connection.Execute(sql) != 0; } - public bool CreateDatabase(string databaseName) { + public bool CreateDatabase(string databaseName, string title, IServiceProvider services = null) { + CreatedTitle = title; string sql = $"CREATE DATABASE IF NOT EXISTS `{databaseName}`"; return connection.Execute(sql) != 0; } diff --git a/QS.DbManagement/MariaDb/MariaDbConnectionTypeBase.cs b/QS.DbManagement/MariaDb/MariaDbConnectionTypeBase.cs index 960a29b4e..29b4805a3 100644 --- a/QS.DbManagement/MariaDb/MariaDbConnectionTypeBase.cs +++ b/QS.DbManagement/MariaDb/MariaDbConnectionTypeBase.cs @@ -1,7 +1,11 @@ +using Microsoft.Extensions.DependencyInjection; +using QS.DBScripts; +using QS.DBScripts.Controllers; +using QS.DBScripts.Models; +using QS.Utilities.Extensions; using System.Collections.Generic; using System.Linq; using System.Reflection; -using QS.Utilities.Extensions; namespace QS.DbManagement { @@ -20,6 +24,19 @@ public override bool CanConnect(IEnumerable parameters parameters.Any(p => p.Name == "Login" && !string.IsNullOrEmpty(p.Value)); } + public override IDbCreatorModel CreatorFactory(CreatorFactoryArgs args){ + var provider = (MariaDBProvider)args.Provider; + var scripts = args.ServiceProvider.GetRequiredService(); + var creator = new MySqlDbCreateModel( + provider.ConnectionStringBuilder.ConnectionString, + scripts, + args.Progress, + args.Interaction, + args.CancellationToken); + creator.FillBaseGuid = false; + return creator; + } + public override IDbProvider CreateProvider(IList parameters, string password = null) => new MariaDBProvider(parameters, password); } diff --git a/QS.DbManagement/ProviderResponces.cs b/QS.DbManagement/ProviderResponces.cs index d354ac0cd..b9e6dfa62 100644 --- a/QS.DbManagement/ProviderResponces.cs +++ b/QS.DbManagement/ProviderResponces.cs @@ -7,7 +7,8 @@ public class Response { public string ErrorMessage { get; set; } } - public class LoginToServerResponse : Response { + public class LoginToServerResponse : Response + { public bool CanCreateDatabase { get; set; } public bool IsAdmin { get; set; } public bool NeedToUpdateLauncher { get; set; } diff --git a/QS.DbManagement/QS.DbManagement.csproj b/QS.DbManagement/QS.DbManagement.csproj index 60196acee..f6c7779e5 100644 --- a/QS.DbManagement/QS.DbManagement.csproj +++ b/QS.DbManagement/QS.DbManagement.csproj @@ -26,6 +26,8 @@ + + diff --git a/QS.Launcher.Avalonia/DependencyInjection.cs b/QS.Launcher.Avalonia/DependencyInjection.cs index 6af20d57e..d5dce86ef 100644 --- a/QS.Launcher.Avalonia/DependencyInjection.cs +++ b/QS.Launcher.Avalonia/DependencyInjection.cs @@ -1,7 +1,9 @@ using Avalonia.Controls; using Microsoft.Extensions.DependencyInjection; +using QS.Launcher.Services; using QS.Launcher.Views; using QS.Launcher.Views.Pages; +using QS.Launcher.Views.Pages.DataBase; namespace QS.Launcher; public static partial class DependencyInjection { @@ -10,9 +12,8 @@ public static IServiceCollection AddPages(this IServiceCollection services) { .AddSingleton() .AddSingleton() .AddSingleton() - .AddSingleton() - .AddSingleton(); + .AddTransient() + .AddTransient() + .AddSingleton(); } - - } diff --git a/QS.Launcher.Avalonia/LauncherApp.axaml b/QS.Launcher.Avalonia/LauncherApp.axaml index e0f3cd31e..f1502c652 100644 --- a/QS.Launcher.Avalonia/LauncherApp.axaml +++ b/QS.Launcher.Avalonia/LauncherApp.axaml @@ -2,6 +2,10 @@ xmlns="https://github.com/avaloniaui" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:converters1="clr-namespace:QS.Project.Converters;assembly=QS.Project.Avalonia" + xmlns:vm="clr-namespace:QS.Launcher.ViewModels.PageViewModels;assembly=QS.Launcher" + xmlns:vmDb="clr-namespace:QS.Launcher.ViewModels.PageViewModels.DataBase;assembly=QS.Launcher" + xmlns:views="using:QS.Launcher.Views.Pages" + xmlns:viewsDb="using:QS.Launcher.Views.Pages.DataBase" x:CompileBindings="False" RequestedThemeVariant="Light"> diff --git a/QS.Launcher.Avalonia/QS.Launcher.Avalonia.csproj b/QS.Launcher.Avalonia/QS.Launcher.Avalonia.csproj index 0573db99d..e8a347a5a 100644 --- a/QS.Launcher.Avalonia/QS.Launcher.Avalonia.csproj +++ b/QS.Launcher.Avalonia/QS.Launcher.Avalonia.csproj @@ -53,9 +53,15 @@ LoginView.axaml - + DataBasesView.axaml + + CreateDataBaseSettingsView.axaml + + + CreateDataBaseProgressView.axaml + UserManagementView.axaml diff --git a/QS.Launcher.Avalonia/Services/AvaloniaUiThreadInvoker.cs b/QS.Launcher.Avalonia/Services/AvaloniaUiThreadInvoker.cs new file mode 100644 index 000000000..6ac1bc79e --- /dev/null +++ b/QS.Launcher.Avalonia/Services/AvaloniaUiThreadInvoker.cs @@ -0,0 +1,12 @@ +using System; +using Avalonia.Threading; +using QS.Launcher.Services; + +namespace QS.Launcher.Services { + public class AvaloniaUiThreadInvoker : IUiThreadInvoker { + public void Post(Action action) { + if(action == null) return; + Dispatcher.UIThread.Post(action); + } + } +} diff --git a/QS.Launcher.Avalonia/Views/MainWindow.axaml b/QS.Launcher.Avalonia/Views/MainWindow.axaml index b678546ae..761d4a59b 100644 --- a/QS.Launcher.Avalonia/Views/MainWindow.axaml +++ b/QS.Launcher.Avalonia/Views/MainWindow.axaml @@ -3,7 +3,6 @@ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" - xmlns:views="clr-namespace:QS.Launcher.Views" xmlns:vm="clr-namespace:QS.Launcher.ViewModels;assembly=QS.Launcher" Title="QS.Лаунчер" Width="450" @@ -17,7 +16,9 @@ mc:Ignorable="d"> - + diff --git a/QS.Launcher.Avalonia/Views/MainWindow.axaml.cs b/QS.Launcher.Avalonia/Views/MainWindow.axaml.cs index d17804705..d377b5ad7 100644 --- a/QS.Launcher.Avalonia/Views/MainWindow.axaml.cs +++ b/QS.Launcher.Avalonia/Views/MainWindow.axaml.cs @@ -2,6 +2,7 @@ using Avalonia.Media.Imaging; using QS.Launcher.ViewModels; using System.Collections.Generic; + namespace QS.Launcher.Views; public partial class MainWindow : Window { diff --git a/QS.Launcher.Avalonia/Views/Pages/DataBase/CreateDataBaseProgressView.axaml b/QS.Launcher.Avalonia/Views/Pages/DataBase/CreateDataBaseProgressView.axaml new file mode 100644 index 000000000..ee33ff10a --- /dev/null +++ b/QS.Launcher.Avalonia/Views/Pages/DataBase/CreateDataBaseProgressView.axaml @@ -0,0 +1,42 @@ + + +