Compare commits

..

7 Commits

14 changed files with 210 additions and 99 deletions

19
.env Normal file
View File

@ -0,0 +1,19 @@
# The .env configuration file
# Please DO NOT share this file, it contains confidential data.
# All variables are specified according to this rule:
# DESCRIPTION - information about what the variable is responsible for
# TYPE - the type of the variable (string, boolean, etc.)
# Any additional information
# SOME_ENV_CODE=data - default data. If specified, then the variable is optional
# General
# The path to save the data.
# string
# (optional)
# Saving logs (if the full path is not specified),
# databases (if Sqlite) and other data that should be saved in a place other than the place where the program is launched.
# REQUIRED if the application is inside the container
# If you want to change this value, you need to change the values in Settings.json and move the file itself to the desired location.
PATH_TO_SAVE=

View File

@ -10,22 +10,20 @@ EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Elements of the solution", "Elements of the solution", "{3E087889-A4A0-4A55-A07D-7D149A5BC928}" Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Elements of the solution", "Elements of the solution", "{3E087889-A4A0-4A55-A07D-7D149A5BC928}"
ProjectSection(SolutionItems) = preProject ProjectSection(SolutionItems) = preProject
.dockerignore = .dockerignore .dockerignore = .dockerignore
.env = .env
.gitattributes = .gitattributes .gitattributes = .gitattributes
.gitignore = .gitignore .gitignore = .gitignore
Dockerfile = Dockerfile Dockerfile = Dockerfile
LICENSE.txt = LICENSE.txt LICENSE.txt = LICENSE.txt
README.md = README.md README.md = README.md
.gitea\workflows\test.yaml = .gitea\workflows\test.yaml
EndProjectSection EndProjectSection
EndProject EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Application", "Application\Application.csproj", "{E7F0A4D4-B032-4BB9-9526-1AF688F341A4}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Application", "Application\Application.csproj", "{E7F0A4D4-B032-4BB9-9526-1AF688F341A4}"
ProjectSection(ProjectDependencies) = postProject
{C27FB5CD-6A70-4FB2-847A-847B34806902} = {C27FB5CD-6A70-4FB2-847A-847B34806902}
EndProjectSection
EndProject EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Persistence", "Persistence\Persistence.csproj", "{4C1E558F-633F-438E-AC3A-61CDDED917C5}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Persistence", "Persistence\Persistence.csproj", "{4C1E558F-633F-438E-AC3A-61CDDED917C5}"
ProjectSection(ProjectDependencies) = postProject EndProject
{E7F0A4D4-B032-4BB9-9526-1AF688F341A4} = {E7F0A4D4-B032-4BB9-9526-1AF688F341A4} Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ApiDto", "ApiDto\ApiDto.csproj", "{0335FA36-E137-453F-853B-916674C168FE}"
EndProjectSection
EndProject EndProject
Global Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution
@ -49,6 +47,10 @@ Global
{4C1E558F-633F-438E-AC3A-61CDDED917C5}.Debug|Any CPU.Build.0 = Debug|Any CPU {4C1E558F-633F-438E-AC3A-61CDDED917C5}.Debug|Any CPU.Build.0 = Debug|Any CPU
{4C1E558F-633F-438E-AC3A-61CDDED917C5}.Release|Any CPU.ActiveCfg = Release|Any CPU {4C1E558F-633F-438E-AC3A-61CDDED917C5}.Release|Any CPU.ActiveCfg = Release|Any CPU
{4C1E558F-633F-438E-AC3A-61CDDED917C5}.Release|Any CPU.Build.0 = Release|Any CPU {4C1E558F-633F-438E-AC3A-61CDDED917C5}.Release|Any CPU.Build.0 = Release|Any CPU
{0335FA36-E137-453F-853B-916674C168FE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{0335FA36-E137-453F-853B-916674C168FE}.Debug|Any CPU.Build.0 = Debug|Any CPU
{0335FA36-E137-453F-853B-916674C168FE}.Release|Any CPU.ActiveCfg = Release|Any CPU
{0335FA36-E137-453F-853B-916674C168FE}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection EndGlobalSection
GlobalSection(SolutionProperties) = preSolution GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE HideSolutionNode = FALSE

View File

@ -0,0 +1,11 @@
using System;
using System.IO;
using System.Linq;
namespace Mirea.Api.Endpoint.Common.Services;
public static class PathBuilder
{
public static string PathToSave => Environment.GetEnvironmentVariable("PATH_TO_SAVE") ?? Directory.GetCurrentDirectory();
public static string Combine(params string[] paths) => Path.Combine([.. paths.Prepend(PathToSave)]);
}

View File

@ -0,0 +1,8 @@
using System;
namespace Mirea.Api.Endpoint.Configuration.General.Attributes;
[AttributeUsage(AttributeTargets.Class, Inherited = false)]
public class RequiredSettingsAttribute : Attribute;
// todo: only with IIsConfigured. If possible add Roslyn Analyzer later

View File

@ -0,0 +1,14 @@
using Mirea.Api.Endpoint.Configuration.General.Settings;
namespace Mirea.Api.Endpoint.Configuration.General;
public class GeneralConfig
{
public const string FilePath = "Settings.json";
public DbSettings? DbSettings { get; set; }
public CacheSettings? CacheSettings { get; set; }
public ScheduleSettings? ScheduleSettings { get; set; }
public EmailSettings? EmailSettings { get; set; }
public LogSettings? LogSettings { get; set; }
}

View File

@ -0,0 +1,23 @@
using Mirea.Api.Endpoint.Configuration.General.Attributes;
using Mirea.Api.Endpoint.Configuration.General.Interfaces;
namespace Mirea.Api.Endpoint.Configuration.General.Settings;
[RequiredSettings]
public class CacheSettings : IIsConfigured
{
public enum CacheEnum
{
Memcached,
Redis
}
public CacheEnum TypeDatabase { get; set; }
public string? ConnectionString { get; set; }
public bool IsConfigured()
{
return TypeDatabase == CacheEnum.Memcached ||
!string.IsNullOrEmpty(ConnectionString);
}
}

View File

@ -0,0 +1,22 @@
using Mirea.Api.Endpoint.Configuration.General.Attributes;
using Mirea.Api.Endpoint.Configuration.General.Interfaces;
namespace Mirea.Api.Endpoint.Configuration.General.Settings;
[RequiredSettings]
public class DbSettings : IIsConfigured
{
public enum DatabaseEnum
{
Mysql,
Sqlite,
PostgresSql
}
public DatabaseEnum TypeDatabase { get; set; }
public required string ConnectionStringSql { get; set; }
public bool IsConfigured()
{
return !string.IsNullOrEmpty(ConnectionStringSql);
}
}

View File

@ -0,0 +1,23 @@
using Mirea.Api.Endpoint.Configuration.General.Interfaces;
namespace Mirea.Api.Endpoint.Configuration.General.Settings;
public class EmailSettings : IIsConfigured
{
public string? Server { get; set; }
public string? User { get; set; }
public string? Password { get; set; }
public string? From { get; set; }
public int? Port { get; set; }
public bool? Ssl { get; set; }
public bool IsConfigured()
{
return !string.IsNullOrEmpty(Server) &&
!string.IsNullOrEmpty(User) &&
!string.IsNullOrEmpty(Password) &&
!string.IsNullOrEmpty(From) &&
Port.HasValue &&
Ssl.HasValue;
}
}

View File

@ -0,0 +1,19 @@
using Mirea.Api.Endpoint.Configuration.General.Attributes;
using Mirea.Api.Endpoint.Configuration.General.Interfaces;
namespace Mirea.Api.Endpoint.Configuration.General.Settings;
[RequiredSettings]
public class LogSettings : IIsConfigured
{
public bool EnableLogToFile { get; set; }
public string? LogFilePath { get; set; }
public string? LogFileName { get; set; }
public bool IsConfigured()
{
return !EnableLogToFile ||
!string.IsNullOrEmpty(LogFilePath) &&
!string.IsNullOrEmpty(LogFileName);
}
}

View File

@ -0,0 +1,45 @@
using Mirea.Api.Endpoint.Configuration.General.Attributes;
using Mirea.Api.Endpoint.Configuration.General.Interfaces;
using System;
using System.Collections.Generic;
using System.Linq;
namespace Mirea.Api.Endpoint.Configuration.General.Settings;
[RequiredSettings]
public class ScheduleSettings : IIsConfigured
{
public struct PairPeriodTime
{
public TimeOnly Start { get; set; }
public TimeOnly End { get; set; }
public PairPeriodTime(TimeOnly t1, TimeOnly t2)
{
if (t1 > t2)
{
Start = t2;
End = t1;
}
else
{
Start = t1;
End = t2;
}
}
public PairPeriodTime(Dto.Common.PairPeriodTime time) : this(time.Start, time.End) { }
}
public required string CronUpdateSchedule { get; set; }
public DateOnly StartTerm { get; set; }
public required IDictionary<int, PairPeriodTime> PairPeriod { get; set; }
public bool IsConfigured()
{
return !string.IsNullOrEmpty(CronUpdateSchedule) &&
StartTerm != default &&
PairPeriod.Count != 0 &&
PairPeriod.Any();
}
}

View File

@ -8,6 +8,7 @@ using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Options; using Microsoft.Extensions.Options;
using Mirea.Api.DataAccess.Application; using Mirea.Api.DataAccess.Application;
using Mirea.Api.DataAccess.Persistence; using Mirea.Api.DataAccess.Persistence;
using Mirea.Api.Endpoint.Common.Services;
using Mirea.Api.Endpoint.Configuration; using Mirea.Api.Endpoint.Configuration;
using Mirea.Api.Endpoint.Properties; using Mirea.Api.Endpoint.Properties;
using Mirea.Api.Endpoint.Configuration.Swagger; using Mirea.Api.Endpoint.Configuration.Swagger;
@ -42,10 +43,11 @@ public class Program
var builder = WebApplication.CreateBuilder(args); var builder = WebApplication.CreateBuilder(args);
builder.Configuration.AddConfiguration(ConfigureEnvironment()); builder.Configuration.AddConfiguration(ConfigureEnvironment());
builder.Configuration.AddJsonFile(Settings.FilePath, optional: true, reloadOnChange: true); builder.Configuration.AddJsonFile(PathBuilder.Combine(GeneralConfig.FilePath), optional: true, reloadOnChange: true);
builder.Services.Configure<GeneralConfig>(builder.Configuration);
builder.Services.AddApplication(); builder.Services.AddApplication();
builder.Services.AddPersistence(builder.Configuration); builder.Services.AddPersistence(builder.Configuration.Get<GeneralConfig>()?.DbSettings?.ConnectionStringSql ?? string.Empty);
builder.Services.AddControllers(); builder.Services.AddControllers();
builder.Services.AddCors(options => builder.Services.AddCors(options =>

View File

@ -1,36 +0,0 @@
using Mirea.Api.DataAccess.Persistence.Properties;
namespace Mirea.Api.Endpoint.Properties;
public class EmailSettings
{
public string? Server { get; set; }
public string? User { get; set; }
public string? Password { get; set; }
public string? From { get; set; }
public int? Port { get; set; }
public bool? Ssl { get; set; }
}
public class LogSettings
{
public bool EnableLogToFile { get; set; }
public string? LogFilePath { get; set; }
public string? LogFileName { get; set; }
}
public class ScheduleSettings
{
// Every 6 hours
public string CronUpdateSchedule { get; set; } = "0 0 0/6 * * *";
}
public class Settings
{
public const string FilePath = "Settings.json";
public EmailSettings? EmailSettings { get; set; }
public LogSettings? LogSettings { get; set; }
public DbSettings? DbSettings { get; set; }
public ScheduleSettings? ScheduleSettings { get; set; }
}

View File

@ -1,54 +1,26 @@
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Mirea.Api.DataAccess.Application.Interfaces.DbContexts.Schedule; using Mirea.Api.DataAccess.Application.Interfaces.DbContexts.Schedule;
using Mirea.Api.DataAccess.Persistence.Contexts.Schedule; using Mirea.Api.DataAccess.Persistence.Contexts.Schedule;
using Mirea.Api.DataAccess.Persistence.Properties;
using System;
using System.Collections.Generic;
namespace Mirea.Api.DataAccess.Persistence; namespace Mirea.Api.DataAccess.Persistence;
public static class DependencyInjection public static class DependencyInjection
{ {
public static IServiceCollection AddPersistence(this IServiceCollection services, IConfiguration configuration) public static IServiceCollection AddPersistence(this IServiceCollection services, string connection)
{ {
var settings = configuration.GetSection(nameof(DbSettings)).Get<DbSettings>(); services.AddDbContext<CampusDbContext>(DbConfig);
var connection = settings?.ConnectionStringSql; services.AddDbContext<DisciplineDbContext>(DbConfig);
services.AddDbContext<FacultyDbContext>(DbConfig);
services.AddDbContext<GroupDbContext>(DbConfig);
services.AddDbContext<LectureHallDbContext>(DbConfig);
services.AddDbContext<LessonAssociationDbContext>(DbConfig);
services.AddDbContext<ProfessorDbContext>(DbConfig);
services.AddDbContext<LessonDbContext>(DbConfig);
services.AddDbContext<TypeOfOccupationDbContext>(DbConfig);
services.AddDbContext<SpecificWeekDbContext>(DbConfig);
Dictionary<DatabaseEnum, Action<DbContextOptionsBuilder>> dbConfigurations = new() services.AddDbContext<UberDbContext>(DbConfig);
{
{
DatabaseEnum.Mysql,
options => options.UseMySql(connection, ServerVersion.AutoDetect(connection))
},
{
DatabaseEnum.Sqlite,
options => options.UseSqlite(connection)
},
{
DatabaseEnum.PostgresSql,
options => options.UseNpgsql(connection)
}
};
if (dbConfigurations.TryGetValue((DatabaseEnum)settings?.TypeDatabase!, out var dbConfig))
{
services.AddDbContext<CampusDbContext>(dbConfig);
services.AddDbContext<DisciplineDbContext>(dbConfig);
services.AddDbContext<FacultyDbContext>(dbConfig);
services.AddDbContext<GroupDbContext>(dbConfig);
services.AddDbContext<LectureHallDbContext>(dbConfig);
services.AddDbContext<LessonAssociationDbContext>(dbConfig);
services.AddDbContext<ProfessorDbContext>(dbConfig);
services.AddDbContext<LessonDbContext>(dbConfig);
services.AddDbContext<TypeOfOccupationDbContext>(dbConfig);
services.AddDbContext<SpecificWeekDbContext>(dbConfig);
services.AddDbContext<UberDbContext>(dbConfig);
}
else
throw new NotSupportedException("Unsupported database type");
services.AddScoped<ICampusDbContext>(provider => provider.GetService<CampusDbContext>()!); services.AddScoped<ICampusDbContext>(provider => provider.GetService<CampusDbContext>()!);
services.AddScoped<IDisciplineDbContext>(provider => provider.GetService<DisciplineDbContext>()!); services.AddScoped<IDisciplineDbContext>(provider => provider.GetService<DisciplineDbContext>()!);
@ -62,5 +34,7 @@ public static class DependencyInjection
services.AddScoped<ISpecificWeekDbContext>(provider => provider.GetService<SpecificWeekDbContext>()!); services.AddScoped<ISpecificWeekDbContext>(provider => provider.GetService<SpecificWeekDbContext>()!);
return services; return services;
void DbConfig(DbContextOptionsBuilder options) => options.UseSqlite(connection);
} }
} }

View File

@ -1,15 +0,0 @@
namespace Mirea.Api.DataAccess.Persistence.Properties;
public enum DatabaseEnum
{
Mysql,
Sqlite,
PostgresSql
}
public class DbSettings
{
public bool IsDoneConfiguration { get; set; }
public DatabaseEnum TypeDatabase { get; set; }
public required string ConnectionStringSql { get; set; }
public DatabaseEnum? MigrateTo { get; set; }
}