diff --git a/.github/workflows/backend-build.yml b/.github/workflows/backend-build.yml new file mode 100644 index 0000000..7a00802 --- /dev/null +++ b/.github/workflows/backend-build.yml @@ -0,0 +1,29 @@ +name: Build Master Backend + +on: + push: + branches: + - main + paths: + - 'backend/**' + pull_request: + branches: + - main + paths: + - 'backend/**' + workflow_dispatch: + +defaults: + run: + working-directory: ./backend + +jobs: + build: + name: Build Master Backend + runs-on: ubuntu-latest + steps: + - name: Checkout Repository + uses: actions/checkout@v4 + + - name: Build Docker Image + run: docker build . -t francispion.azurecr.io/master_backend:${{ github.sha }} -f src/Logitar.Master/Dockerfile diff --git a/backend/.dockerignore b/backend/.dockerignore new file mode 100644 index 0000000..fe1152b --- /dev/null +++ b/backend/.dockerignore @@ -0,0 +1,30 @@ +**/.classpath +**/.dockerignore +**/.env +**/.git +**/.gitignore +**/.project +**/.settings +**/.toolstarget +**/.vs +**/.vscode +**/*.*proj.user +**/*.dbmdl +**/*.jfm +**/azds.yaml +**/bin +**/charts +**/docker-compose* +**/Dockerfile* +**/node_modules +**/npm-debug.log +**/obj +**/secrets.dev.yaml +**/values.dev.yaml +LICENSE +README.md +!**/.gitignore +!.git/HEAD +!.git/config +!.git/packed-refs +!.git/refs/heads/** \ No newline at end of file diff --git a/backend/.editorconfig b/backend/.editorconfig new file mode 100644 index 0000000..1b25fe4 --- /dev/null +++ b/backend/.editorconfig @@ -0,0 +1,136 @@ +############################### +# Core EditorConfig Options # +############################### +root = true +# All files +[*] +indent_style = space + +# XML project files +[*.{csproj,vbproj,vcxproj,vcxproj.filters,proj,projitems,shproj}] +indent_size = 2 + +# XML config files +[*.{props,targets,ruleset,config,nuspec,resx,vsixmanifest,vsct}] +indent_size = 2 + +# Code files +[*.{cs,csx,vb,vbx}] +indent_size = 2 +insert_final_newline = true +charset = utf-8-bom +############################### +# .NET Coding Conventions # +############################### +[*.{cs,vb}] +# Organize usings +dotnet_sort_system_directives_first = false +# this. preferences +dotnet_style_qualification_for_field = false:silent +dotnet_style_qualification_for_property = false:silent +dotnet_style_qualification_for_method = false:silent +dotnet_style_qualification_for_event = false:silent +# Language keywords vs BCL types preferences +dotnet_style_predefined_type_for_locals_parameters_members = true:silent +dotnet_style_predefined_type_for_member_access = true:silent +# Parentheses preferences +dotnet_style_parentheses_in_arithmetic_binary_operators = always_for_clarity:silent +dotnet_style_parentheses_in_relational_binary_operators = always_for_clarity:silent +dotnet_style_parentheses_in_other_binary_operators = always_for_clarity:silent +dotnet_style_parentheses_in_other_operators = never_if_unnecessary:silent +# Modifier preferences +dotnet_style_require_accessibility_modifiers = for_non_interface_members:silent +dotnet_style_readonly_field = true:suggestion +# Expression-level preferences +dotnet_style_object_initializer = true:suggestion +dotnet_style_collection_initializer = true:suggestion +dotnet_style_explicit_tuple_names = true:suggestion +dotnet_style_null_propagation = true:suggestion +dotnet_style_coalesce_expression = true:suggestion +dotnet_style_prefer_is_null_check_over_reference_equality_method = true:silent +dotnet_style_prefer_inferred_tuple_names = true:suggestion +dotnet_style_prefer_inferred_anonymous_type_member_names = true:suggestion +dotnet_style_prefer_auto_properties = true:silent +dotnet_style_prefer_conditional_expression_over_assignment = true:silent +dotnet_style_prefer_conditional_expression_over_return = true:silent +############################### +# Naming Conventions # +############################### +# Style Definitions +dotnet_naming_style.pascal_case_style.capitalization = pascal_case +# Use PascalCase for constant fields +dotnet_naming_rule.constant_fields_should_be_pascal_case.severity = suggestion +dotnet_naming_rule.constant_fields_should_be_pascal_case.symbols = constant_fields +dotnet_naming_rule.constant_fields_should_be_pascal_case.style = pascal_case_style +dotnet_naming_symbols.constant_fields.applicable_kinds = field +dotnet_naming_symbols.constant_fields.applicable_accessibilities = * +dotnet_naming_symbols.constant_fields.required_modifiers = const +############################### +# C# Coding Conventions # +############################### +[*.cs] +# var preferences +csharp_style_var_for_built_in_types = true:silent +csharp_style_var_when_type_is_apparent = true:silent +csharp_style_var_elsewhere = true:silent +# Expression-bodied members +csharp_style_expression_bodied_methods = false:silent +csharp_style_expression_bodied_constructors = false:silent +csharp_style_expression_bodied_operators = false:silent +csharp_style_expression_bodied_properties = true:silent +csharp_style_expression_bodied_indexers = true:silent +csharp_style_expression_bodied_accessors = true:silent +# Pattern matching preferences +csharp_style_pattern_matching_over_is_with_cast_check = true:suggestion +csharp_style_pattern_matching_over_as_with_null_check = true:suggestion +# Null-checking preferences +csharp_style_throw_expression = true:suggestion +csharp_style_conditional_delegate_call = true:suggestion +# Modifier preferences +csharp_preferred_modifier_order = public,private,protected,internal,static,extern,new,virtual,abstract,sealed,override,readonly,unsafe,volatile,async:suggestion +# Expression-level preferences +csharp_prefer_braces = true:silent +csharp_style_deconstructed_variable_declaration = true:suggestion +csharp_prefer_simple_default_expression = true:suggestion +csharp_style_pattern_local_over_anonymous_function = true:suggestion +csharp_style_inlined_variable_declaration = true:suggestion +# Use file scoped namespaces +csharp_style_namespace_declarations = file_scoped:error +############################### +# C# Formatting Rules # +############################### +# New line preferences +csharp_new_line_before_open_brace = all +csharp_new_line_before_else = true +csharp_new_line_before_catch = true +csharp_new_line_before_finally = true +csharp_new_line_before_members_in_object_initializers = true +csharp_new_line_before_members_in_anonymous_types = true +csharp_new_line_between_query_expression_clauses = true +# Indentation preferences +csharp_indent_case_contents = true +csharp_indent_switch_labels = true +csharp_indent_labels = flush_left +# Space preferences +csharp_space_after_cast = false +csharp_space_after_keywords_in_control_flow_statements = true +csharp_space_between_method_call_parameter_list_parentheses = false +csharp_space_between_method_declaration_parameter_list_parentheses = false +csharp_space_between_parentheses = false +csharp_space_before_colon_in_inheritance_clause = true +csharp_space_after_colon_in_inheritance_clause = true +csharp_space_around_binary_operators = before_and_after +csharp_space_between_method_declaration_empty_parameter_list_parentheses = false +csharp_space_between_method_call_name_and_opening_parenthesis = false +csharp_space_between_method_call_empty_parameter_list_parentheses = false +# Wrapping preferences +csharp_preserve_single_line_statements = true +csharp_preserve_single_line_blocks = true +[*.{cs,vb}] +dotnet_diagnostic.IDE0290.severity = none +############################### +# VB Coding Conventions # +############################### +[*.vb] +# Modifier preferences +visual_basic_preferred_modifier_order = Partial,Default,Private,Protected,Public,Friend,NotOverridable,Overridable,MustOverride,Overloads,Overrides,MustInherit,NotInheritable,Static,Shared,Shadows,ReadOnly,WriteOnly,Dim,Const,WithEvents,Widening,Narrowing,Custom,Async:suggestion \ No newline at end of file diff --git a/backend/.gitattributes b/backend/.gitattributes new file mode 100644 index 0000000..1ff0c42 --- /dev/null +++ b/backend/.gitattributes @@ -0,0 +1,63 @@ +############################################################################### +# Set default behavior to automatically normalize line endings. +############################################################################### +* text=auto + +############################################################################### +# Set default behavior for command prompt diff. +# +# This is need for earlier builds of msysgit that does not have it on by +# default for csharp files. +# Note: This is only used by command line +############################################################################### +#*.cs diff=csharp + +############################################################################### +# Set the merge driver for project and solution files +# +# Merging from the command prompt will add diff markers to the files if there +# are conflicts (Merging from VS is not affected by the settings below, in VS +# the diff markers are never inserted). Diff markers may cause the following +# file extensions to fail to load in VS. An alternative would be to treat +# these files as binary and thus will always conflict and require user +# intervention with every merge. To do so, just uncomment the entries below +############################################################################### +#*.sln merge=binary +#*.csproj merge=binary +#*.vbproj merge=binary +#*.vcxproj merge=binary +#*.vcproj merge=binary +#*.dbproj merge=binary +#*.fsproj merge=binary +#*.lsproj merge=binary +#*.wixproj merge=binary +#*.modelproj merge=binary +#*.sqlproj merge=binary +#*.wwaproj merge=binary + +############################################################################### +# behavior for image files +# +# image files are treated as binary by default. +############################################################################### +#*.jpg binary +#*.png binary +#*.gif binary + +############################################################################### +# diff behavior for common document formats +# +# Convert binary document formats to text before diffing them. This feature +# is only available from the command line. Turn it on by uncommenting the +# entries below. +############################################################################### +#*.doc diff=astextplain +#*.DOC diff=astextplain +#*.docx diff=astextplain +#*.DOCX diff=astextplain +#*.dot diff=astextplain +#*.DOT diff=astextplain +#*.pdf diff=astextplain +#*.PDF diff=astextplain +#*.rtf diff=astextplain +#*.RTF diff=astextplain diff --git a/backend/.gitignore b/backend/.gitignore new file mode 100644 index 0000000..ba22a70 --- /dev/null +++ b/backend/.gitignore @@ -0,0 +1,363 @@ +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. +## +## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore + +# User-specific files +*.rsuser +*.suo +*.user +*.userosscache +*.sln.docstates + +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs + +# Mono auto generated files +mono_crash.* + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +[Ww][Ii][Nn]32/ +[Aa][Rr][Mm]/ +[Aa][Rr][Mm]64/ +bld/ +[Bb]in/ +[Oo]bj/ +[Oo]ut/ +[Ll]og/ +[Ll]ogs/ + +# Visual Studio 2015/2017 cache/options directory +.vs/ +# Uncomment if you have tasks that create the project's static files in wwwroot +wwwroot/ + +# Visual Studio 2017 auto generated files +Generated\ Files/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +# NUnit +*.VisualState.xml +TestResult.xml +nunit-*.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +# Benchmark Results +BenchmarkDotNet.Artifacts/ + +# .NET Core +project.lock.json +project.fragment.lock.json +artifacts/ + +# ASP.NET Scaffolding +ScaffoldingReadMe.txt + +# StyleCop +StyleCopReport.xml + +# Files built by Visual Studio +*_i.c +*_p.c +*_h.h +*.ilk +*.meta +*.obj +*.iobj +*.pch +*.pdb +*.ipdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*_wpftmp.csproj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opendb +*.opensdf +*.sdf +*.cachefile +*.VC.db +*.VC.VC.opendb + +# Visual Studio profiler +*.psess +*.vsp +*.vspx +*.sap + +# Visual Studio Trace Files +*.e2e + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# AxoCover is a Code Coverage Tool +.axoCover/* +!.axoCover/settings.json + +# Coverlet is a free, cross platform Code Coverage Tool +coverage*.json +coverage*.xml +coverage*.info + +# Visual Studio code coverage results +*.coverage +*.coveragexml + +# NCrunch +_NCrunch_* +.*crunch*.local.xml +nCrunchTemp_* + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml +# Note: Comment the next line if you want to checkin your web deploy settings, +# but database connection strings (with potential passwords) will be unencrypted +*.pubxml +*.publishproj + +# Microsoft Azure Web App publish settings. Comment the next line if you want to +# checkin your Azure Web App publish settings, but sensitive information contained +# in these scripts will be unencrypted +PublishScripts/ + +# NuGet Packages +*.nupkg +# NuGet Symbol Packages +*.snupkg +# The packages folder can be ignored because of Package Restore +**/[Pp]ackages/* +# except build/, which is used as an MSBuild target. +!**/[Pp]ackages/build/ +# Uncomment if necessary however generally it will be regenerated when needed +#!**/[Pp]ackages/repositories.config +# NuGet v3's project.json files produces more ignorable files +*.nuget.props +*.nuget.targets + +# Microsoft Azure Build Output +csx/ +*.build.csdef + +# Microsoft Azure Emulator +ecf/ +rcf/ + +# Windows Store app package directories and files +AppPackages/ +BundleArtifacts/ +Package.StoreAssociation.xml +_pkginfo.txt +*.appx +*.appxbundle +*.appxupload + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!?*.[Cc]ache/ + +# Others +ClientBin/ +~$* +*~ +*.dbmdl +*.dbproj.schemaview +*.jfm +*.pfx +*.publishsettings +orleans.codegen.cs + +# Including strong name files can present a security risk +# (https://github.com/github/gitignore/pull/2483#issue-259490424) +#*.snk + +# Since there are multiple workflows, uncomment next line to ignore bower_components +# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) +#bower_components/ + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm +ServiceFabricBackup/ +*.rptproj.bak + +# SQL Server files +*.mdf +*.ldf +*.ndf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings +*.rptproj.rsuser +*- [Bb]ackup.rdl +*- [Bb]ackup ([0-9]).rdl +*- [Bb]ackup ([0-9][0-9]).rdl + +# Microsoft Fakes +FakesAssemblies/ + +# GhostDoc plugin setting file +*.GhostDoc.xml + +# Node.js Tools for Visual Studio +.ntvs_analysis.dat +node_modules/ + +# Visual Studio 6 build log +*.plg + +# Visual Studio 6 workspace options file +*.opt + +# Visual Studio 6 auto-generated workspace file (contains which files were open etc.) +*.vbw + +# Visual Studio LightSwitch build output +**/*.HTMLClient/GeneratedArtifacts +**/*.DesktopClient/GeneratedArtifacts +**/*.DesktopClient/ModelManifest.xml +**/*.Server/GeneratedArtifacts +**/*.Server/ModelManifest.xml +_Pvt_Extensions + +# Paket dependency manager +.paket/paket.exe +paket-files/ + +# FAKE - F# Make +.fake/ + +# CodeRush personal settings +.cr/personal + +# Python Tools for Visual Studio (PTVS) +__pycache__/ +*.pyc + +# Cake - Uncomment if you are using it +# tools/** +# !tools/packages.config + +# Tabs Studio +*.tss + +# Telerik's JustMock configuration file +*.jmconfig + +# BizTalk build output +*.btp.cs +*.btm.cs +*.odx.cs +*.xsd.cs + +# OpenCover UI analysis results +OpenCover/ + +# Azure Stream Analytics local run output +ASALocalRun/ + +# MSBuild Binary and Structured Log +*.binlog + +# NVidia Nsight GPU debugger configuration file +*.nvuser + +# MFractors (Xamarin productivity tool) working folder +.mfractor/ + +# Local History for Visual Studio +.localhistory/ + +# BeatPulse healthcheck temp database +healthchecksdb + +# Backup folder for Package Reference Convert tool in Visual Studio 2017 +MigrationBackup/ + +# Ionide (cross platform F# VS Code tools) working folder +.ionide/ + +# Fody - auto-generated XML schema +FodyWeavers.xsd \ No newline at end of file diff --git a/backend/.gitkeep b/backend/.gitkeep deleted file mode 100644 index e69de29..0000000 diff --git a/backend/Master.sln b/backend/Master.sln new file mode 100644 index 0000000..7864c11 --- /dev/null +++ b/backend/Master.sln @@ -0,0 +1,34 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.9.34728.123 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Logitar.Master", "src\Logitar.Master\Logitar.Master.csproj", "{386F3388-1EEC-4730-A492-85003937F502}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{2446C7B8-AEC8-47DC-A2CD-3A1D78F71548}" + ProjectSection(SolutionItems) = preProject + .dockerignore = .dockerignore + .editorconfig = .editorconfig + .gitattributes = .gitattributes + .gitignore = .gitignore + README.md = README.md + EndProjectSection +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {386F3388-1EEC-4730-A492-85003937F502}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {386F3388-1EEC-4730-A492-85003937F502}.Debug|Any CPU.Build.0 = Debug|Any CPU + {386F3388-1EEC-4730-A492-85003937F502}.Release|Any CPU.ActiveCfg = Release|Any CPU + {386F3388-1EEC-4730-A492-85003937F502}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {2EF5DF67-96A3-4877-949F-E046443F9E9A} + EndGlobalSection +EndGlobal diff --git a/backend/README.md b/backend/README.md new file mode 100644 index 0000000..02b76c7 --- /dev/null +++ b/backend/README.md @@ -0,0 +1,3 @@ +# Master Backend + +This is the backend of the Logitar project management suite. diff --git a/backend/src/Logitar.Master/Constants/Api.cs b/backend/src/Logitar.Master/Constants/Api.cs new file mode 100644 index 0000000..f33256c --- /dev/null +++ b/backend/src/Logitar.Master/Constants/Api.cs @@ -0,0 +1,7 @@ +namespace Logitar.Master.Constants; + +internal static class Api +{ + public const string Title = "Master API"; + public static readonly Version Version = new(1, 0, 0); +} diff --git a/backend/src/Logitar.Master/Controllers/IndexController.cs b/backend/src/Logitar.Master/Controllers/IndexController.cs new file mode 100644 index 0000000..1245a8d --- /dev/null +++ b/backend/src/Logitar.Master/Controllers/IndexController.cs @@ -0,0 +1,12 @@ +using Logitar.Master.Models.Index; +using Microsoft.AspNetCore.Mvc; + +namespace Logitar.Master.Controllers; + +[ApiController] +[Route("")] +public class IndexController : ControllerBase +{ + [HttpGet] + public ActionResult Get() => Ok(ApiVersion.Current); +} diff --git a/backend/src/Logitar.Master/Dockerfile b/backend/src/Logitar.Master/Dockerfile new file mode 100644 index 0000000..ecd43e9 --- /dev/null +++ b/backend/src/Logitar.Master/Dockerfile @@ -0,0 +1,25 @@ +#See https://aka.ms/customizecontainer to learn how to customize your debug container and how Visual Studio uses this Dockerfile to build your images for faster debugging. + +FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS base +USER app +WORKDIR /app +EXPOSE 8080 +EXPOSE 8081 + +FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build +ARG BUILD_CONFIGURATION=Release +WORKDIR /src +COPY ["src/Logitar.Master/Logitar.Master.csproj", "src/Logitar.Master/"] +RUN dotnet restore "./src/Logitar.Master/Logitar.Master.csproj" +COPY . . +WORKDIR "/src/src/Logitar.Master" +RUN dotnet build "./Logitar.Master.csproj" -c $BUILD_CONFIGURATION -o /app/build + +FROM build AS publish +ARG BUILD_CONFIGURATION=Release +RUN dotnet publish "./Logitar.Master.csproj" -c $BUILD_CONFIGURATION -o /app/publish /p:UseAppHost=false + +FROM base AS final +WORKDIR /app +COPY --from=publish /app/publish . +ENTRYPOINT ["dotnet", "Logitar.Master.dll"] \ No newline at end of file diff --git a/backend/src/Logitar.Master/Extensions/CorsExtensions.cs b/backend/src/Logitar.Master/Extensions/CorsExtensions.cs new file mode 100644 index 0000000..e2e25c6 --- /dev/null +++ b/backend/src/Logitar.Master/Extensions/CorsExtensions.cs @@ -0,0 +1,50 @@ +using Logitar.Master.Settings; + +namespace Logitar.Master.Extensions; + +internal static class CorsExtensions +{ + public static IServiceCollection AddCors(this IServiceCollection services, CorsSettings settings) + { + services.AddCors(options => options.AddDefaultPolicy(cors => + { + if (settings.AllowAnyOrigin) + { + cors.AllowAnyOrigin(); + } + else + { + cors.WithOrigins(settings.AllowedOrigins); + } + + if (settings.AllowAnyMethod) + { + cors.AllowAnyMethod(); + } + else + { + cors.WithMethods(settings.AllowedMethods); + } + + if (settings.AllowAnyHeader) + { + cors.AllowAnyHeader(); + } + else + { + cors.WithHeaders(settings.AllowedHeaders); + } + + if (settings.AllowCredentials) + { + cors.AllowCredentials(); + } + else + { + cors.DisallowCredentials(); + } + })); + + return services; + } +} diff --git a/backend/src/Logitar.Master/Extensions/OpenApiExtensions.cs b/backend/src/Logitar.Master/Extensions/OpenApiExtensions.cs new file mode 100644 index 0000000..2440a29 --- /dev/null +++ b/backend/src/Logitar.Master/Extensions/OpenApiExtensions.cs @@ -0,0 +1,128 @@ +using Logitar.Master.Constants; +using Microsoft.OpenApi.Models; + +namespace Logitar.Master.Extensions; + +internal static class OpenApiExtensions +{ + public static IServiceCollection AddOpenApi(this IServiceCollection services) + { + services.AddEndpointsApiExplorer(); + services.AddSwaggerGen(config => + { + //config.AddSecurity(); // TODO(fpion): OpenAPI Security + config.SwaggerDoc(name: $"v{Api.Version.Major}", new OpenApiInfo + { + Contact = new OpenApiContact + { + Email = "francispion@hotmail.com", + Name = "Logitar Team", + Url = new Uri("https://github.com/Logitar/Master", UriKind.Absolute) + }, + Description = "Project management suite.", + License = new OpenApiLicense + { + Name = "Use under MIT", + Url = new Uri("https://github.com/Logitar/Master/blob/main/LICENSE", UriKind.Absolute) + }, + Title = Api.Title, + Version = $"v{Api.Version}" + }); + }); + + return services; + } + + public static void UseOpenApi(this IApplicationBuilder builder) + { + builder.UseSwagger(); + builder.UseSwaggerUI(config => config.SwaggerEndpoint( + url: $"/swagger/v{Api.Version.Major}/swagger.json", + name: $"{Api.Title} v{Api.Version}" + )); + } + + //private static void AddSecurity(this SwaggerGenOptions options) + //{ + // options.AddSecurityDefinition(Schemes.ApiKey, new OpenApiSecurityScheme + // { + // Description = "Enter your API key in the input below:", + // In = ParameterLocation.Header, + // Name = Headers.ApiKey, + // Scheme = Schemes.ApiKey, + // Type = SecuritySchemeType.ApiKey + // }); + // options.AddSecurityRequirement(new OpenApiSecurityRequirement + // { + // { + // new OpenApiSecurityScheme + // { + // In = ParameterLocation.Header, + // Name = Headers.ApiKey, + // Reference = new OpenApiReference + // { + // Id = Schemes.ApiKey, + // Type = ReferenceType.SecurityScheme + // }, + // Scheme = Schemes.ApiKey, + // Type = SecuritySchemeType.ApiKey + // }, + // new List() + // } + // }); + + // options.AddSecurityDefinition(Schemes.Basic, new OpenApiSecurityScheme + // { + // Description = "Enter your credentials in the inputs below:", + // In = ParameterLocation.Header, + // Name = Headers.Authorization, + // Scheme = Schemes.Basic, + // Type = SecuritySchemeType.Http + // }); + // options.AddSecurityRequirement(new OpenApiSecurityRequirement + // { + // { + // new OpenApiSecurityScheme + // { + // In = ParameterLocation.Header, + // Name = Headers.Authorization, + // Reference = new OpenApiReference + // { + // Id = Schemes.Basic, + // Type = ReferenceType.SecurityScheme + // }, + // Scheme = Schemes.Basic, + // Type = SecuritySchemeType.Http + // }, + // new List() + // } + // }); + + // options.AddSecurityDefinition(Schemes.Bearer, new OpenApiSecurityScheme + // { + // Description = "Enter your access token in the input below:", + // In = ParameterLocation.Header, + // Name = Headers.Authorization, + // Scheme = Schemes.Bearer, + // Type = SecuritySchemeType.Http + // }); + // options.AddSecurityRequirement(new OpenApiSecurityRequirement + // { + // { + // new OpenApiSecurityScheme + // { + // In = ParameterLocation.Header, + // Name = Headers.Authorization, + // Reference = new OpenApiReference + // { + // Id = Schemes.Bearer, + // Type = ReferenceType.SecurityScheme + // }, + // Scheme = Schemes.Bearer, + // Type = SecuritySchemeType.Http + // }, + // new List() + // } + // }); + //} +} diff --git a/backend/src/Logitar.Master/Logitar.Master.csproj b/backend/src/Logitar.Master/Logitar.Master.csproj new file mode 100644 index 0000000..49520f5 --- /dev/null +++ b/backend/src/Logitar.Master/Logitar.Master.csproj @@ -0,0 +1,30 @@ + + + + net8.0 + enable + enable + da383c44-702f-4cec-bf5f-766b6fa41ed6 + Linux + ..\.. + + + + True + + + + True + + + + + + + + + + + + + diff --git a/backend/src/Logitar.Master/Models/Index/ApiVersion.cs b/backend/src/Logitar.Master/Models/Index/ApiVersion.cs new file mode 100644 index 0000000..15883f6 --- /dev/null +++ b/backend/src/Logitar.Master/Models/Index/ApiVersion.cs @@ -0,0 +1,25 @@ +using Logitar.Master.Constants; + +namespace Logitar.Master.Models.Index; + +public record ApiVersion +{ + public static ApiVersion Current => new(Api.Title, Api.Version); + + public string Title { get; set; } + public string Version { get; set; } + + public ApiVersion() : this(string.Empty, string.Empty) + { + } + + public ApiVersion(string title, Version version) : this(title, version.ToString()) + { + } + + public ApiVersion(string title, string version) + { + Title = title; + Version = version; + } +} diff --git a/backend/src/Logitar.Master/Program.cs b/backend/src/Logitar.Master/Program.cs new file mode 100644 index 0000000..b2b7cf0 --- /dev/null +++ b/backend/src/Logitar.Master/Program.cs @@ -0,0 +1,18 @@ +namespace Logitar.Master; + +internal class Program +{ + public static void Main(string[] args) + { + WebApplicationBuilder builder = WebApplication.CreateBuilder(args); + + Startup startup = new(builder.Configuration); + startup.ConfigureServices(builder.Services); + + WebApplication application = builder.Build(); + + startup.Configure(application); + + application.Run(); + } +} diff --git a/backend/src/Logitar.Master/Properties/launchSettings.json b/backend/src/Logitar.Master/Properties/launchSettings.json new file mode 100644 index 0000000..19f72e5 --- /dev/null +++ b/backend/src/Logitar.Master/Properties/launchSettings.json @@ -0,0 +1,52 @@ +{ + "profiles": { + "http": { + "commandName": "Project", + "launchBrowser": true, + "launchUrl": "swagger", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + }, + "dotnetRunMessages": true, + "applicationUrl": "http://localhost:5064" + }, + "https": { + "commandName": "Project", + "launchBrowser": true, + "launchUrl": "swagger", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + }, + "dotnetRunMessages": true, + "applicationUrl": "https://localhost:7235;http://localhost:5064" + }, + "IIS Express": { + "commandName": "IISExpress", + "launchBrowser": true, + "launchUrl": "swagger", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + }, + "Container (Dockerfile)": { + "commandName": "Docker", + "launchBrowser": true, + "launchUrl": "{Scheme}://{ServiceHost}:{ServicePort}/swagger", + "environmentVariables": { + "ASPNETCORE_HTTPS_PORTS": "8081", + "ASPNETCORE_HTTP_PORTS": "8080" + }, + "publishAllPorts": true, + "useSSL": true + } + }, + "$schema": "http://json.schemastore.org/launchsettings.json", + "iisSettings": { + "windowsAuthentication": false, + "anonymousAuthentication": true, + "iisExpress": { + "applicationUrl": "http://localhost:32521", + "sslPort": 44371 + } + } +} \ No newline at end of file diff --git a/backend/src/Logitar.Master/Settings/CorsSettings.cs b/backend/src/Logitar.Master/Settings/CorsSettings.cs new file mode 100644 index 0000000..da47875 --- /dev/null +++ b/backend/src/Logitar.Master/Settings/CorsSettings.cs @@ -0,0 +1,15 @@ +namespace Logitar.Master.Settings; + +internal record CorsSettings +{ + public bool AllowAnyOrigin { get; set; } + public string[] AllowedOrigins { get; set; } = []; + + public bool AllowAnyMethod { get; set; } + public string[] AllowedMethods { get; set; } = []; + + public bool AllowAnyHeader { get; set; } + public string[] AllowedHeaders { get; set; } = []; + + public bool AllowCredentials { get; set; } +} diff --git a/backend/src/Logitar.Master/Startup.cs b/backend/src/Logitar.Master/Startup.cs new file mode 100644 index 0000000..091e5a9 --- /dev/null +++ b/backend/src/Logitar.Master/Startup.cs @@ -0,0 +1,51 @@ +using Logitar.Master.Extensions; +using Logitar.Master.Settings; + +namespace Logitar.Master; + +internal class Startup : StartupBase +{ + private readonly IConfiguration _configuration; + private readonly bool _enableOpenApi; + + public Startup(IConfiguration configuration) + { + _configuration = configuration; + _enableOpenApi = configuration.GetValue("EnableOpenApi"); + } + + public override void ConfigureServices(IServiceCollection services) + { + services.AddControllers() + .AddJsonOptions(options => options.JsonSerializerOptions.Converters.Add(new JsonStringEnumConverter())); + + CorsSettings corsSettings = _configuration.GetSection("Cors").Get() ?? new(); + services.AddSingleton(corsSettings); + services.AddCors(corsSettings); + + services.AddApplicationInsightsTelemetry(); + IHealthChecksBuilder healthChecks = services.AddHealthChecks(); + + if (_enableOpenApi) + { + services.AddOpenApi(); + } + } + + public override void Configure(IApplicationBuilder builder) + { + if (_enableOpenApi) + { + builder.UseOpenApi(); + } + + builder.UseHttpsRedirection(); + builder.UseCors(); + + if (builder is WebApplication application) + { + application.MapControllers(); + application.MapHealthChecks("/health"); + } + } +} diff --git a/backend/src/Logitar.Master/appsettings.Development.json b/backend/src/Logitar.Master/appsettings.Development.json new file mode 100644 index 0000000..08425bd --- /dev/null +++ b/backend/src/Logitar.Master/appsettings.Development.json @@ -0,0 +1,9 @@ +{ + "EnableOpenApi": true, + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + } +} diff --git a/backend/src/Logitar.Master/appsettings.json b/backend/src/Logitar.Master/appsettings.json new file mode 100644 index 0000000..873deb1 --- /dev/null +++ b/backend/src/Logitar.Master/appsettings.json @@ -0,0 +1,18 @@ +{ + "AllowedHosts": "*", + "Cors": { + "AllowAnyOrigin": false, + "AllowedOrigins": [], + "AllowAnyMethod": false, + "AllowedMethods": [], + "AllowAnyHeader": false, + "AllowedHeaders": [], + "AllowCredentials": false + }, + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + } +} diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..b712857 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,14 @@ +version: '3.8' +name: logitar_master +services: + logitar_master_backend: + build: + context: ./backend + dockerfile: /src/Logitar.Master/Dockerfile + image: logitar_master_backend + container_name: Logitar.Master_backend + restart: unless-stopped + environment: + ASPNETCORE_Environment: Development + ports: + - 8091:8080