From 8bcb8127bf8fc2dd24377fd2f9740e048424eb0a Mon Sep 17 00:00:00 2001 From: cswimr Date: Wed, 29 Jan 2025 18:09:21 +0000 Subject: [PATCH] feat: add src closes #6 --- Data/MyhmContext.cs | 15 ++++ Models/MyhmConfiguration.cs | 17 ++++ Program.cs | 120 ++++++++++++++++++++++++++++ Properties/launchSettings.json | 23 ++++++ README.md | 1 - Util/RandomStringGenerator.cs | 26 ++++++ Util/SwaggerTheme/CustomStyle.cs | 12 +++ Util/SwaggerTheme/modern.custom.css | 117 +++++++++++++++++++++++++++ appsettings.Development.json | 12 +++ appsettings.json | 27 +++++++ myhm-commission.csproj | 20 +++++ myhm-commission.sln | 22 +++++ 12 files changed, 411 insertions(+), 1 deletion(-) create mode 100644 Data/MyhmContext.cs create mode 100644 Models/MyhmConfiguration.cs create mode 100644 Program.cs create mode 100644 Properties/launchSettings.json create mode 100644 Util/RandomStringGenerator.cs create mode 100644 Util/SwaggerTheme/CustomStyle.cs create mode 100644 Util/SwaggerTheme/modern.custom.css create mode 100644 appsettings.Development.json create mode 100644 appsettings.json create mode 100644 myhm-commission.csproj create mode 100644 myhm-commission.sln diff --git a/Data/MyhmContext.cs b/Data/MyhmContext.cs new file mode 100644 index 0000000..fd8061d --- /dev/null +++ b/Data/MyhmContext.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.EntityFrameworkCore; +using Myhm.Models; + +namespace Myhm.Data +{ + public class MyhmContext(DbContextOptions options) : DbContext(options) + { + + //public DbSet Ban { get; set; } = default!; + } +} diff --git a/Models/MyhmConfiguration.cs b/Models/MyhmConfiguration.cs new file mode 100644 index 0000000..fecf389 --- /dev/null +++ b/Models/MyhmConfiguration.cs @@ -0,0 +1,17 @@ +namespace Myhm.Models +{ + public class MyhmConfiguration + { + public required string GlobalToken { get; init; } + public required string DatabaseConnectionString { get; init; } + public required DatabaseTypes DatabaseType { get; init; } + public bool UseSentry { get; init; } = true; + public bool UseSwagger { get; init; } = true; + public bool LogRequests { get; init; } = true; + } + + public enum DatabaseTypes + { + PostgresSQL, + } +} diff --git a/Program.cs b/Program.cs new file mode 100644 index 0000000..5c19331 --- /dev/null +++ b/Program.cs @@ -0,0 +1,120 @@ +using System.Reflection; +using Microsoft.EntityFrameworkCore; +using Microsoft.OpenApi.Models; +using Myhm.Data; +using Myhm.Models; +using Myhm.Util.SwaggerTheme; + +var builder = WebApplication.CreateBuilder(args); + +// Configuration +var config = builder.Configuration.GetSection("Configuration").Get(); +builder.Services.Configure(builder.Configuration.GetSection("Configuration")); + +if (config?.GlobalToken == "CHANGE-ME") +{ + throw new InvalidOperationException( + "Global token is not a valid value, please set the `CONFIGURATION__GLOBALTOKEN` environment variable to a random value. `openssl rand -hex 64` is a good way to generate a random value." + ); +} + +// Initialize Database +builder.Services.AddDbContextFactory(options => + options.UseNpgsql(builder.Configuration.GetConnectionString("MyhmContext")) +); + +// Sentry +if (config?.UseSentry == true) +{ + builder.WebHost.UseSentry(); +} + +// Add services to the container. +builder.Services.AddHttpLogging(o => { }); +builder.Services.AddEndpointsApiExplorer(); +builder.Services.AddSwaggerGen(opts => +{ + opts.SwaggerDoc( + "v1", + new OpenApiInfo + { + Title = "Myhm API", + Version = "v1", + Description = "", + } + ); + opts.AddSecurityDefinition( + "Bearer", + new OpenApiSecurityScheme + { + Description = + "JWT Authorization header using the Bearer scheme. Example: \"Authorization: Bearer {token}\"", + Name = "Authorization", + In = ParameterLocation.Header, + Type = SecuritySchemeType.ApiKey, + Scheme = "Bearer", + } + ); + opts.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"; + opts.IncludeXmlComments(Path.Combine(AppContext.BaseDirectory, xmlFile)); +}); + +var app = builder.Build(); + +var assembly = Assembly.GetExecutingAssembly(); +foreach (var resource in assembly.GetManifestResourceNames()) +{ + app.Logger.LogDebug("Resource: {Resource}", resource); +} + +if (config?.UseSwagger == true) +{ + app.UseSwagger(); + app.UseSwaggerUI(CustomStyle.CustomModern); +} + +if (config?.LogRequests == true) +{ + app.UseHttpLogging(); +} + +// Configure the HTTP request pipeline. +if (!app.Environment.IsDevelopment()) +{ + app.UseExceptionHandler("/Error", createScopeForErrors: true); + // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts. + app.UseHsts(); +} + +app.UseHttpsRedirection(); + +app.UseAntiforgery(); + +// if (app.Environment.IsDevelopment()) +// { +// app.Logger.LogInformation( +// "Development mode detected, printing configuration: {Configuration}", +// config?.ToJson() +// ); +// } + +app.Run(); diff --git a/Properties/launchSettings.json b/Properties/launchSettings.json new file mode 100644 index 0000000..e746d1b --- /dev/null +++ b/Properties/launchSettings.json @@ -0,0 +1,23 @@ +{ + "$schema": "https://json.schemastore.org/launchsettings.json", + "profiles": { + "http": { + "commandName": "Project", + "dotnetRunMessages": true, + "launchBrowser": false, + "applicationUrl": "http://localhost:5054", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + }, + "https": { + "commandName": "Project", + "dotnetRunMessages": true, + "launchBrowser": false, + "applicationUrl": "https://localhost:7076;http://localhost:5054", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + } + } +} diff --git a/README.md b/README.md index 712b086..9f368c1 100644 --- a/README.md +++ b/README.md @@ -1,2 +1 @@ # myhm-commission - diff --git a/Util/RandomStringGenerator.cs b/Util/RandomStringGenerator.cs new file mode 100644 index 0000000..77e646f --- /dev/null +++ b/Util/RandomStringGenerator.cs @@ -0,0 +1,26 @@ +using System.Security.Cryptography; +using System.Text; + +namespace Myhm.Util; + +public class RandomStringGenerator +{ + private static readonly char[] chars = + "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%^&*+?".ToCharArray(); + + public static string GenerateRandomString(int length) + { + var stringBuilder = new StringBuilder(); + using (var rng = RandomNumberGenerator.Create()) + { + byte[] buffer = new byte[1]; + for (int i = 0; i < length; i++) + { + rng.GetBytes(buffer); + var randomIndex = buffer[0] % chars.Length; + stringBuilder.Append(chars[randomIndex]); + } + } + return stringBuilder.ToString(); + } +} diff --git a/Util/SwaggerTheme/CustomStyle.cs b/Util/SwaggerTheme/CustomStyle.cs new file mode 100644 index 0000000..110037d --- /dev/null +++ b/Util/SwaggerTheme/CustomStyle.cs @@ -0,0 +1,12 @@ +using System; +using AspNetCore.Swagger.Themes; + +namespace Myhm.Util.SwaggerTheme; + +public class CustomStyle : ModernStyle +{ + protected CustomStyle(string fileName) + : base(fileName) { } + + public static CustomStyle CustomModern => new("modern.custom.css"); +} diff --git a/Util/SwaggerTheme/modern.custom.css b/Util/SwaggerTheme/modern.custom.css new file mode 100644 index 0000000..ad22abb --- /dev/null +++ b/Util/SwaggerTheme/modern.custom.css @@ -0,0 +1,117 @@ +:root { + /* Light mode (Catppuccin Latte) */ + --catppuccin-pink: #ea76cb; + --catppuccin-mauve: #8839ef; + --catppuccin-red: #d20f39; + --catppuccin-maroon: #e64553; + --catppuccin-peach: #fe640b; + --catppuccin-yellow: #df8e1d; + --catppuccin-green: #40a02b; + --catppuccin-teal: #179299; + --catppuccin-sky: #04a5e5; + --catppuccin-sapphire: #209fb5; + --catppuccin-blue: #1e66f5; + --catppuccin-lavender: #7287fd; + --catppuccin-text: #4c4f69; + --catppuccin-subtext1: #5c5f77; + --catppuccin-subtext0: #6c6f85; + --catppuccin-overlay2: #7c7f93; + --catppuccin-overlay1: #8c8fa1; + --catppuccin-overlay0: #9ca0b0; + --catppuccin-surface2: #acb0be; + --catppuccin-surface1: #bcc0cc; + --catppuccin-surface0: #ccd0da; + --catppuccin-base: #eff1f5; + --catppuccin-mantle: #e6e9ef; + --catppuccin-crust: #dce0e8; + + --link: var(--catppuccin-blue); + --link-hover: var(--catppuccin-sapphire); + --accent: var(--catppuccin-green); + --error: var(--catppuccin-red); + + /* Body */ + --body-background-color: var(--catppuccin-base); + --swagger-main-color: var(--catppuccin-text); + --scrollbar-thumb-color: var(--catppuccin-surface1); + --scrollbar-thumb-hover-color: var(--catppuccin-surface0); + + /* Loading */ + --loading-container-border-color: var(--accent); + + /* Errors Container */ + --errors-wrapper-background-color: var(--catppuccin-surface0); + --errors-wrapper-border-color: var(--error); + --errors-wrapper-errors-color: var(--error); + + /* Topbar */ + --topbar-background-color: var(--catppuccin-surface0); + --topbar-pinned-background-color: var(--catppuccin-surface0); + --topbar-border-color: var(--accent); + --topbar-select-label-color: var(--catppuccin-text); + --topbar-select-border-color: var(--accent); + + /* Infobox */ + --swagger-info-link: var(--link); + --swagger-info-link-hover: var(--link-hover); + --api-version-background-color: var(--catppuccin-surface2); + --api-version-stamp-background-color: var(--accent); + --api-version-color: var(--catppuccin-base); + + /* Authorization */ + --btn-authorize-background-color: var(--catppuccin-surface0); + --btn-authorize-border-color: var(--catppuccin-green); + --btn-authorize-font-color: var(--catppuccin-green); + --btn-authorize-svg-fill-color: var(--catppuccin-green); + --auth-container-background-color: var(--catppuccin-surface0); + --auth-container-errors-color: var(--catppuccin-red); + --auth-wrapper-background-color: var(--catppuccin-mantle); + --auth-wrapper-border-color: var(--accent); + + /* Form Elements */ + --select-border-color: var(--accent); + --input-background-color: var(--catppuccin-surface0); + --input-border-color: var(--accent); + --input-invalid-border-color: var(--error); + --input-disabled-background-color: var(--catppuccin-crust); + --input-disabled-border-color: var(--catppuccin-surface1); + + /* Dialog */ + --dialog-background-color: var(--catppuccin-mantle); + --dialog-border-color: var(--accent); +} + +.swagger-ui .topbar .download-url-wrapper input[type="text"], .swagger-ui .topbar .download-url-wrapper .select-label select { + background-color: var(--catppuccin-surface0); + color: var(--catppuccin-text); +} + +@media (prefers-color-scheme: dark) { + :root { + /* Dark mode (Catppuccin Mocha) */ + --catppuccin-pink: #f5c2e7; + --catppuccin-mauve: #cba6f7; + --catppuccin-red: #f38ba8; + --catppuccin-maroon: #eba0ac; + --catppuccin-peach: #fab387; + --catppuccin-yellow: #f9e2af; + --catppuccin-green: #a6e3a1; + --catppuccin-teal: #94e2d5; + --catppuccin-sky: #89dceb; + --catppuccin-sapphire: #74c7ec; + --catppuccin-blue: #89b4fa; + --catppuccin-lavender: #b4befe; + --catppuccin-text: #cdd6f4; + --catppuccin-subtext1: #bac2de; + --catppuccin-subtext0: #a6adc8; + --catppuccin-overlay2: #9399b2; + --catppuccin-overlay1: #7f849c; + --catppuccin-overlay0: #6c7086; + --catppuccin-surface2: #585b70; + --catppuccin-surface1: #45475a; + --catppuccin-surface0: #313244; + --catppuccin-base: #1e1e2e; + --catppuccin-mantle: #181825; + --catppuccin-crust: #11111b; + } +} diff --git a/appsettings.Development.json b/appsettings.Development.json new file mode 100644 index 0000000..257a057 --- /dev/null +++ b/appsettings.Development.json @@ -0,0 +1,12 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Trace" + } + }, + "Configuration": { + // DO NOT USE THIS AUTHTOKEN IN PRODUCTION!!! + "AuthToken": "hi", + "UseSentry": false + } +} diff --git a/appsettings.json b/appsettings.json new file mode 100644 index 0000000..3e51e5a --- /dev/null +++ b/appsettings.json @@ -0,0 +1,27 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning", + "Microsoft.AspNetCore.HttpLogging.HttpLoggingMiddleware": "Information" + } + }, + "AllowedHosts": "*", + "Configuration": { + "AuthToken": "CHANGE-ME", + "UseSwagger": true, + "LogRequests": true, + "UseSentry": true + }, + "Sentry": { + "Dsn": "https://64a43934d4e6b76fce9b2307e1787188@sentry.csw.im/8", + "SendDefaultPii": true, + "MaxRequestBodySize": "Always", + "MinimumBreadcrumbLevel": "Debug", + "MinimumEventLevel": "Warning", + "AttachStackTrace": true, + "Debug": true, + "DiagnosticLevel": "Error", + "TracesSampleRate": 1.0 + } +} diff --git a/myhm-commission.csproj b/myhm-commission.csproj new file mode 100644 index 0000000..9b51b7b --- /dev/null +++ b/myhm-commission.csproj @@ -0,0 +1,20 @@ + + + + net9.0 + enable + enable + Myhm + + + + + + + + + + + + + diff --git a/myhm-commission.sln b/myhm-commission.sln new file mode 100644 index 0000000..9c56277 --- /dev/null +++ b/myhm-commission.sln @@ -0,0 +1,22 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.0.31903.59 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "myhm-commission", "myhm-commission.csproj", "{D39B0551-B762-4BD9-81DC-FF49FB7F8439}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {D39B0551-B762-4BD9-81DC-FF49FB7F8439}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D39B0551-B762-4BD9-81DC-FF49FB7F8439}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D39B0551-B762-4BD9-81DC-FF49FB7F8439}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D39B0551-B762-4BD9-81DC-FF49FB7F8439}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection +EndGlobal