2024-05-29 03:46:16 +03:00
|
|
|
|
using Cronos;
|
2024-05-28 07:19:40 +03:00
|
|
|
|
using Microsoft.AspNetCore.Http;
|
|
|
|
|
using Microsoft.AspNetCore.Mvc;
|
2024-05-29 03:42:39 +03:00
|
|
|
|
using Microsoft.Data.Sqlite;
|
2024-05-29 03:35:52 +03:00
|
|
|
|
using Microsoft.Extensions.Caching.Memory;
|
2024-05-29 03:42:39 +03:00
|
|
|
|
using Mirea.Api.Dto.Requests;
|
|
|
|
|
using Mirea.Api.Dto.Requests.Configuration;
|
2024-05-28 07:19:40 +03:00
|
|
|
|
using Mirea.Api.Endpoint.Common.Attributes;
|
|
|
|
|
using Mirea.Api.Endpoint.Common.Exceptions;
|
|
|
|
|
using Mirea.Api.Endpoint.Common.Interfaces;
|
2024-05-29 03:35:52 +03:00
|
|
|
|
using Mirea.Api.Endpoint.Common.Services;
|
2024-05-28 07:19:40 +03:00
|
|
|
|
using Mirea.Api.Endpoint.Configuration.General;
|
2024-05-29 03:35:52 +03:00
|
|
|
|
using Mirea.Api.Endpoint.Configuration.General.Settings;
|
2024-05-29 03:42:39 +03:00
|
|
|
|
using MySqlConnector;
|
|
|
|
|
using Npgsql;
|
2024-05-29 03:43:08 +03:00
|
|
|
|
using StackExchange.Redis;
|
2024-05-29 03:37:04 +03:00
|
|
|
|
using System;
|
|
|
|
|
using System.Data;
|
2024-05-29 03:46:16 +03:00
|
|
|
|
using System.IO;
|
|
|
|
|
using System.Runtime.InteropServices;
|
|
|
|
|
using System.Security.Cryptography;
|
|
|
|
|
using System.Text.Json;
|
2024-05-28 07:19:40 +03:00
|
|
|
|
|
|
|
|
|
namespace Mirea.Api.Endpoint.Controllers.Configuration;
|
|
|
|
|
|
|
|
|
|
[ApiVersion("1.0")]
|
|
|
|
|
[ApiController]
|
|
|
|
|
[MaintenanceModeIgnore]
|
2024-05-29 03:35:52 +03:00
|
|
|
|
public class SetupController(ISetupToken setupToken, IMaintenanceModeNotConfigureService notConfigureService, IMemoryCache cache) : BaseController
|
2024-05-28 07:19:40 +03:00
|
|
|
|
{
|
2024-06-01 06:27:49 +03:00
|
|
|
|
private const string CacheGeneralKey = "config_general";
|
|
|
|
|
private const string CacheAdminKey = "config_admin";
|
|
|
|
|
|
2024-05-29 03:35:52 +03:00
|
|
|
|
private GeneralConfig GeneralConfig
|
|
|
|
|
{
|
|
|
|
|
get => cache.Get<GeneralConfig>(CacheGeneralKey) ?? new GeneralConfig();
|
|
|
|
|
set => cache.Set(CacheGeneralKey, value);
|
|
|
|
|
}
|
|
|
|
|
|
2024-05-28 07:19:40 +03:00
|
|
|
|
[HttpGet("GenerateToken")]
|
2024-05-29 03:30:26 +03:00
|
|
|
|
[Localhost]
|
2024-05-28 07:19:40 +03:00
|
|
|
|
public ActionResult<string> GenerateToken()
|
|
|
|
|
{
|
|
|
|
|
if (!notConfigureService.IsMaintenanceMode)
|
|
|
|
|
throw new ControllerArgumentException(
|
|
|
|
|
"The token cannot be generated because the server has been configured. " +
|
2024-05-28 07:20:21 +03:00
|
|
|
|
$"If you need to restart the configuration, then delete the \"{PathBuilder.Combine(GeneralConfig.FilePath)}\" file and restart the application.");
|
2024-05-28 07:19:40 +03:00
|
|
|
|
|
|
|
|
|
var token = new byte[32];
|
|
|
|
|
RandomNumberGenerator.Create().GetBytes(token);
|
|
|
|
|
setupToken.SetToken(token);
|
|
|
|
|
|
|
|
|
|
return Ok(Convert.ToBase64String(token));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[HttpGet("CheckToken")]
|
|
|
|
|
public ActionResult<bool> CheckToken([FromQuery] string token)
|
|
|
|
|
{
|
|
|
|
|
if (!setupToken.MatchToken(Convert.FromBase64String(token))) return Unauthorized("The token is not valid");
|
|
|
|
|
|
|
|
|
|
Response.Cookies.Append("AuthToken", token, new CookieOptions
|
|
|
|
|
{
|
|
|
|
|
HttpOnly = false,
|
|
|
|
|
Secure = false,
|
|
|
|
|
Path = "/"
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
return Ok(true);
|
|
|
|
|
}
|
|
|
|
|
|
2024-05-29 03:37:04 +03:00
|
|
|
|
private ActionResult<bool> SetDatabase<TConnection, TException>(string connectionString, DbSettings.DatabaseEnum databaseType)
|
|
|
|
|
where TConnection : class, IDbConnection, new()
|
|
|
|
|
where TException : Exception
|
|
|
|
|
{
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
using var connection = new TConnection();
|
|
|
|
|
connection.ConnectionString = connectionString;
|
|
|
|
|
connection.Open();
|
|
|
|
|
connection.Close();
|
|
|
|
|
|
|
|
|
|
var general = GeneralConfig;
|
|
|
|
|
general.DbSettings = new DbSettings
|
|
|
|
|
{
|
|
|
|
|
ConnectionStringSql = connectionString,
|
|
|
|
|
TypeDatabase = databaseType
|
|
|
|
|
};
|
|
|
|
|
GeneralConfig = general;
|
|
|
|
|
|
|
|
|
|
return Ok(true);
|
|
|
|
|
}
|
|
|
|
|
catch (TException ex)
|
|
|
|
|
{
|
|
|
|
|
throw new ControllerArgumentException($"Error when connecting: {ex.Message}");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-05-29 03:38:21 +03:00
|
|
|
|
[HttpPost("SetPsql")]
|
|
|
|
|
[TokenAuthentication]
|
|
|
|
|
[BadRequestResponse]
|
|
|
|
|
public ActionResult<bool> SetPsql([FromBody] DatabaseRequest request)
|
|
|
|
|
{
|
|
|
|
|
string connectionString = $"Host={request.Server}:{request.Port};Username={request.User};Database={request.Database}";
|
|
|
|
|
if (request.Password != null)
|
|
|
|
|
connectionString += $";Password={request.Password}";
|
|
|
|
|
if (request.Ssl)
|
|
|
|
|
connectionString += ";SSL Mode=Require;";
|
|
|
|
|
|
|
|
|
|
return SetDatabase<NpgsqlConnection, NpgsqlException>(connectionString, DbSettings.DatabaseEnum.PostgresSql);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[HttpPost("SetMysql")]
|
|
|
|
|
[TokenAuthentication]
|
|
|
|
|
[BadRequestResponse]
|
|
|
|
|
public ActionResult<bool> SetMysql([FromBody] DatabaseRequest request)
|
|
|
|
|
{
|
2024-06-01 06:28:13 +03:00
|
|
|
|
string connectionString = $"Server={request.Server}:{request.Port};Uid={request.User};Database={request.Database};";
|
2024-05-29 03:38:21 +03:00
|
|
|
|
if (request.Password != null)
|
2024-06-01 06:28:13 +03:00
|
|
|
|
connectionString += $"Pwd={request.Password};";
|
2024-05-29 03:38:21 +03:00
|
|
|
|
if (request.Ssl)
|
2024-06-01 06:28:13 +03:00
|
|
|
|
connectionString += "SslMode=Require;";
|
2024-05-29 03:38:21 +03:00
|
|
|
|
|
|
|
|
|
return SetDatabase<MySqlConnection, MySqlException>(connectionString, DbSettings.DatabaseEnum.Mysql);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[HttpPost("SetSqlite")]
|
|
|
|
|
[TokenAuthentication]
|
|
|
|
|
public ActionResult<bool> SetSqlite([FromQuery] string? path)
|
|
|
|
|
{
|
|
|
|
|
if (string.IsNullOrEmpty(path)) path = "database";
|
|
|
|
|
|
|
|
|
|
path = PathBuilder.Combine(path);
|
|
|
|
|
|
|
|
|
|
if (!Directory.Exists(path))
|
|
|
|
|
{
|
|
|
|
|
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
|
|
|
|
|
Directory.CreateDirectory(path);
|
|
|
|
|
else
|
|
|
|
|
Directory.CreateDirectory(path, UnixFileMode.UserRead | UnixFileMode.UserWrite);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
throw new ControllerArgumentException("Such a folder exists. Enter a different name");
|
|
|
|
|
|
|
|
|
|
string connectionString = $"Data Source={PathBuilder.Combine(path, "database.db3")}";
|
|
|
|
|
|
|
|
|
|
return SetDatabase<SqliteConnection, SqliteException>(connectionString, DbSettings.DatabaseEnum.Sqlite);
|
|
|
|
|
}
|
2024-05-29 03:43:08 +03:00
|
|
|
|
|
|
|
|
|
[HttpPost("SetRedis")]
|
|
|
|
|
[TokenAuthentication]
|
|
|
|
|
[BadRequestResponse]
|
|
|
|
|
public ActionResult<bool> SetRedis([FromBody] CacheRequest request)
|
|
|
|
|
{
|
|
|
|
|
string connectionString = $"{request.Server}:{request.Port},ssl=false";
|
|
|
|
|
if (request.Password != null)
|
|
|
|
|
connectionString += $",password={request.Password}";
|
|
|
|
|
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
var redis = ConnectionMultiplexer.Connect(connectionString);
|
|
|
|
|
redis.Close();
|
|
|
|
|
|
|
|
|
|
var general = GeneralConfig;
|
|
|
|
|
general.CacheSettings = new CacheSettings
|
|
|
|
|
{
|
|
|
|
|
ConnectionString = connectionString,
|
|
|
|
|
TypeDatabase = CacheSettings.CacheEnum.Redis
|
|
|
|
|
};
|
|
|
|
|
GeneralConfig = general;
|
|
|
|
|
|
|
|
|
|
return Ok(true);
|
|
|
|
|
}
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
{
|
|
|
|
|
throw new ControllerArgumentException("Error when connecting to Redis: " + ex.Message);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[HttpPost("SetMemcached")]
|
|
|
|
|
[TokenAuthentication]
|
|
|
|
|
[BadRequestResponse]
|
|
|
|
|
public ActionResult<bool> SetMemcached()
|
|
|
|
|
{
|
|
|
|
|
var general = GeneralConfig;
|
|
|
|
|
general.CacheSettings = new CacheSettings
|
|
|
|
|
{
|
|
|
|
|
ConnectionString = null,
|
|
|
|
|
TypeDatabase = CacheSettings.CacheEnum.Memcached
|
|
|
|
|
};
|
|
|
|
|
GeneralConfig = general;
|
|
|
|
|
|
|
|
|
|
return Ok(true);
|
|
|
|
|
}
|
2024-05-29 03:44:24 +03:00
|
|
|
|
|
2024-06-01 06:27:49 +03:00
|
|
|
|
[HttpPost("CreateAdmin")]
|
|
|
|
|
[TokenAuthentication]
|
|
|
|
|
[BadRequestResponse]
|
|
|
|
|
public ActionResult<string> CreateAdmin([FromBody] CreateUserRequest user)
|
|
|
|
|
{
|
|
|
|
|
// todo: change CreateUserRequest to Domain entity
|
|
|
|
|
cache.Set(CacheAdminKey, user);
|
|
|
|
|
return Ok(true);
|
|
|
|
|
}
|
|
|
|
|
|
2024-05-29 03:44:24 +03:00
|
|
|
|
[HttpPost("SetLogging")]
|
|
|
|
|
[TokenAuthentication]
|
|
|
|
|
[BadRequestResponse]
|
|
|
|
|
public ActionResult<bool> SetLogging([FromBody] LoggingRequest? request)
|
|
|
|
|
{
|
|
|
|
|
var settings = (request == null) switch
|
|
|
|
|
{
|
|
|
|
|
true => new LogSettings
|
|
|
|
|
{
|
|
|
|
|
EnableLogToFile = true,
|
|
|
|
|
LogFileName = "logging-",
|
|
|
|
|
LogFilePath = "logs"
|
|
|
|
|
},
|
|
|
|
|
false => new LogSettings
|
|
|
|
|
{
|
|
|
|
|
EnableLogToFile = request.EnableLogToFile,
|
|
|
|
|
LogFileName = request.LogFileName,
|
|
|
|
|
LogFilePath = request.LogFilePath
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
var general = GeneralConfig;
|
|
|
|
|
general.LogSettings = settings;
|
|
|
|
|
GeneralConfig = general;
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
2024-05-29 03:45:02 +03:00
|
|
|
|
|
|
|
|
|
[HttpPost("SetEmail")]
|
|
|
|
|
[TokenAuthentication]
|
|
|
|
|
[BadRequestResponse]
|
|
|
|
|
public ActionResult<bool> SetEmail([FromBody] EmailRequest? request)
|
|
|
|
|
{
|
|
|
|
|
var settings = (request == null) switch
|
|
|
|
|
{
|
|
|
|
|
true => new EmailSettings(),
|
|
|
|
|
false => new EmailSettings
|
|
|
|
|
{
|
|
|
|
|
Server = request.Server,
|
|
|
|
|
From = request.From,
|
|
|
|
|
Password = request.Password,
|
|
|
|
|
Port = request.Port,
|
|
|
|
|
Ssl = request.Ssl,
|
|
|
|
|
User = request.User
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
var general = GeneralConfig;
|
|
|
|
|
general.EmailSettings = settings;
|
|
|
|
|
GeneralConfig = general;
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
2024-05-29 03:46:16 +03:00
|
|
|
|
|
|
|
|
|
[HttpPost("SetSchedule")]
|
|
|
|
|
[TokenAuthentication]
|
|
|
|
|
[BadRequestResponse]
|
|
|
|
|
public ActionResult<bool> SetSchedule([FromBody] ScheduleConfigurationRequest request)
|
|
|
|
|
{
|
|
|
|
|
var general = GeneralConfig;
|
|
|
|
|
general.ScheduleSettings = new ScheduleSettings
|
|
|
|
|
{
|
|
|
|
|
// every 6 hours
|
|
|
|
|
CronUpdateSchedule = request.CronUpdateSchedule ?? "0 */6 * * *",
|
|
|
|
|
StartTerm = request.StartTerm,
|
|
|
|
|
PairPeriod = request.PairPeriod.ConvertFromDto()
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
if (!CronExpression.TryParse(general.ScheduleSettings.CronUpdateSchedule, CronFormat.Standard, out _))
|
|
|
|
|
throw new ControllerArgumentException("The Cron task could not be parsed. Check the format of the entered data.");
|
|
|
|
|
|
|
|
|
|
GeneralConfig = general;
|
|
|
|
|
|
|
|
|
|
return true;
|
2024-05-29 03:38:21 +03:00
|
|
|
|
}
|
|
|
|
|
|
2024-05-28 07:19:40 +03:00
|
|
|
|
|
|
|
|
|
}
|