diff --git a/.gitignore b/.gitignore
index 1eedd164e..cadc2946b 100644
--- a/.gitignore
+++ b/.gitignore
@@ -271,3 +271,6 @@ paket-files/
# Environment Specific app settings
appsettings.*.json
secrets.config
+
+# Logs
+Gordon360/Logs/*
\ No newline at end of file
diff --git a/Gordon360/Documentation/Gordon360.xml b/Gordon360/Documentation/Gordon360.xml
index 7f3a77b1f..b8b60c986 100644
--- a/Gordon360/Documentation/Gordon360.xml
+++ b/Gordon360/Documentation/Gordon360.xml
@@ -148,28 +148,6 @@
-
-
- Get all admins
-
-
- A list of all admins
-
-
- Server makes call to the database and returns all admins
-
-
-
- Create a new admin to be added to database
- The admin item containing all required and relevant information
-
- Posts a new admin to the server to be added into the database
-
-
- Delete an existing admin
- The username of the user to demote
- Calls the server to make a call and remove the given admin from the database
-
Return a list majors.
@@ -1476,7 +1454,7 @@
Activity Info and ACtivity may be talked about interchangeably.
-
+
Service Class that facilitates data transactions between the ActivitiesController and the ACT_INFO database model.
ACT_INFO is basically a copy of the ACT_CLUB_DEF domain model in TmsEPrd but with extra fields that we want to store (activity image, blurb etc...)
@@ -1573,50 +1551,6 @@
The activity code
activity private or not
-
-
- Service class to facilitate interacting with the Admin table.
-
-
-
-
- Service class to facilitate interacting with the Admin table.
-
-
-
-
- Fetches all the administrators from the database
-
- Returns a list of administrators. If no administrators were found, an empty list is returned.
-
-
-
- Fetches a specific admin from the database
-
- Returns a list of administrators. If no administrators were found, an empty list is returned.
-
-
-
- Adds a new Administrator record to storage. Since we can't establish foreign key constraints and relationships on the database side,
- we do it here by using the validateAdmin() method.
-
- The admin to be added
- The newly added Admin object
-
-
-
- Delete the admin whose id is specified by the parameter.
-
- The username of the admin to demote
- The admin that was just deleted
-
-
-
- Helper method to Validate an admin
-
- The admin to validate
- True if the admin is valid. Throws ResourceNotFoundException if not. Exception is cauth in an Exception Filter
-
Service class that facilitates data (specifically, site content) passing between the ContentManagementController and the database model.
diff --git a/Gordon360/Gordon360.csproj b/Gordon360/Gordon360.csproj
index 24fe5cae9..58f85ebe4 100644
--- a/Gordon360/Gordon360.csproj
+++ b/Gordon360/Gordon360.csproj
@@ -63,6 +63,11 @@
+
+
+
+
+
@@ -71,6 +76,9 @@
+
+
+
OnBuildSuccess
diff --git a/Gordon360/Program.cs b/Gordon360/Program.cs
index 85672b73d..5b5510ad8 100644
--- a/Gordon360/Program.cs
+++ b/Gordon360/Program.cs
@@ -12,109 +12,137 @@
using Microsoft.Extensions.FileProviders;
using Microsoft.Identity.Web;
using Microsoft.OpenApi.Models;
+using Serilog;
+using Serilog.Formatting.Compact;
using System;
using System.Collections.Generic;
using System.IO;
-using RecIM = Gordon360.Services.RecIM;
-var builder = WebApplication.CreateBuilder(args);
+const string CorsPolicy = "360UI";
-var azureConfig = builder.Configuration.GetSection("AzureAd").Get();
+Log.Logger = new LoggerConfiguration().WriteTo.Console().CreateBootstrapLogger();
-// Add services to the container.
-builder.Services.AddMicrosoftIdentityWebApiAuthentication(builder.Configuration, "AzureAd");
-
-builder.Services.AddControllers(options =>
+try
{
- options.OutputFormatters.RemoveType(); // Return strings as application/json instead of text/plain
- options.OutputFormatters.RemoveType(); // Return null as 200 Ok null instead of 204 No Content
-}).AddNewtonsoftJson(options => options.UseMemberCasing());
+ var builder = WebApplication.CreateBuilder(args);
-// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
-builder.Services.AddEndpointsApiExplorer();
-builder.Services.AddSwaggerGen(c =>
-{
- c.AddSecurityDefinition("oauth2", new OpenApiSecurityScheme
+ builder.Services.AddSerilog((services, lc) => lc
+ .ReadFrom.Configuration(builder.Configuration)
+ .ReadFrom.Services(services)
+ .Enrich.FromLogContext()
+ .WriteTo.Console()
+ .WriteTo.File(new CompactJsonFormatter(), "./Logs/info.json", rollingInterval: RollingInterval.Day, retainedFileCountLimit: 14, rollOnFileSizeLimit: true)
+ .WriteTo.File(new CompactJsonFormatter(), "./Logs/error.json", restrictedToMinimumLevel: Serilog.Events.LogEventLevel.Error, rollingInterval: RollingInterval.Day));
+
+ builder.Services.AddMicrosoftIdentityWebApiAuthentication(builder.Configuration, "AzureAd");
+
+ builder.Services.AddControllers(options =>
+ {
+ options.OutputFormatters.RemoveType(); // Return strings as application/json instead of text/plain
+ options.OutputFormatters.RemoveType(); // Return null as 200 Ok null instead of 204 No Content
+ }).AddNewtonsoftJson(options => options.UseMemberCasing());
+
+ builder.Services.AddEndpointsApiExplorer();
+
+ var azureConfig = builder.Configuration.GetSection("AzureAd").Get();
+
+ builder.Services.AddSwaggerGen(c =>
{
- Type = SecuritySchemeType.OAuth2,
- Flows = new OpenApiOAuthFlows()
+ c.AddSecurityDefinition("oauth2", new OpenApiSecurityScheme
{
- AuthorizationCode = new OpenApiOAuthFlow()
+ Type = SecuritySchemeType.OAuth2,
+ Flows = new OpenApiOAuthFlows()
{
- AuthorizationUrl = new Uri($"https://login.microsoftonline.com/{azureConfig.TenantId}/oauth2/v2.0/authorize"),
- TokenUrl = new Uri($"https://login.microsoftonline.com/{azureConfig.TenantId}/oauth2/v2.0/token"),
- Scopes = new Dictionary {
+ AuthorizationCode = new OpenApiOAuthFlow()
+ {
+ AuthorizationUrl = new Uri($"https://login.microsoftonline.com/{azureConfig.TenantId}/oauth2/v2.0/authorize"),
+ TokenUrl = new Uri($"https://login.microsoftonline.com/{azureConfig.TenantId}/oauth2/v2.0/token"),
+ Scopes = new Dictionary {
{
$"{azureConfig.Audience}/access_as_user",
"Access 360 as you."
}
}
+ }
}
- }
+ });
+ c.AddSecurityRequirement(new OpenApiSecurityRequirement() {
+ {
+ new OpenApiSecurityScheme {
+ Reference = new OpenApiReference {
+ Type = ReferenceType.SecurityScheme,
+ Id = "oauth2"
+ },
+ Scheme = "oauth2",
+ Name = "oauth2",
+ In = ParameterLocation.Header
+ },
+ new List()
+ }
+ });
});
- c.AddSecurityRequirement(new OpenApiSecurityRequirement() {
+
+ builder.Services.AddCors(p => p.AddPolicy(name: CorsPolicy, corsBuilder =>
{
- new OpenApiSecurityScheme {
- Reference = new OpenApiReference {
- Type = ReferenceType.SecurityScheme,
- Id = "oauth2"
- },
- Scheme = "oauth2",
- Name = "oauth2",
- In = ParameterLocation.Header
- },
- new List < string > ()
- }
-});
-}
-);
+ corsBuilder.WithOrigins(builder.Configuration.GetValue("AllowedOrigin")).AllowAnyMethod().AllowAnyHeader();
+ }));
-string corsPolicy = "360UI";
-builder.Services.AddCors(p => p.AddPolicy(name: corsPolicy, corsBuilder =>
-{
- corsBuilder.WithOrigins(builder.Configuration.GetValue("AllowedOrigin")).AllowAnyMethod().AllowAnyHeader();
-}));
+ builder.Services.AddDbContext(options =>
+ options.UseSqlServer(builder.Configuration.GetConnectionString("CCT"))
+ ).AddDbContext(options =>
+ options.UseSqlServer(builder.Configuration.GetConnectionString("MyGordon"))
+ ).AddDbContext(options =>
+ options.UseSqlServer(builder.Configuration.GetConnectionString("webSQL"))
+ );
-builder.Services.AddDbContext(options =>
- options.UseSqlServer(builder.Configuration.GetConnectionString("CCT"))
-).AddDbContext(options =>
- options.UseSqlServer(builder.Configuration.GetConnectionString("MyGordon"))
-).AddDbContext(options =>
- options.UseSqlServer(builder.Configuration.GetConnectionString("webSQL"))
-);
+ builder.Services.Add360Services();
+ builder.Services.AddHostedService();
+ builder.Services.AddScoped();
-builder.Services.Add360Services();
-builder.Services.AddHostedService();
-builder.Services.AddScoped();
+ builder.Services.AddMemoryCache();
-builder.Services.AddMemoryCache();
+ var app = builder.Build();
-var app = builder.Build();
+ // Configure the HTTP request pipeline.
-// Configure the HTTP request pipeline.
+ app.UseSwagger();
+ app.UseSwaggerUI(c =>
+ {
+ c.OAuthClientId(azureConfig.ClientId);
+ c.OAuthScopes($"{azureConfig.Audience}/access_as_user");
+ c.OAuthUsePkce();
+ });
-app.UseSwagger();
-app.UseSwaggerUI(c =>
-{
- c.OAuthClientId(azureConfig.ClientId);
- c.OAuthScopes($"{azureConfig.Audience}/access_as_user");
- c.OAuthUsePkce();
-});
+ app.UseSerilogRequestLogging();
-app.UseStaticFiles(new StaticFileOptions
-{
- FileProvider = new PhysicalFileProvider(
- Path.Combine(builder.Environment.ContentRootPath, "browseable")),
- RequestPath = "/browseable"
-});
+ app.UseStaticFiles(new StaticFileOptions
+ {
+ FileProvider = new PhysicalFileProvider(
+ Path.Combine(builder.Environment.ContentRootPath, "browseable")),
+ RequestPath = "/browseable"
+ });
-app.UseRouting();
+ app.UseRouting();
-app.UseAuthentication();
-app.UseAuthorization();
+ app.UseAuthentication();
+ app.UseAuthorization();
-app.UseCors(corsPolicy);
+ app.UseCors(CorsPolicy);
-app.MapControllers();
+ app.MapControllers();
+
+ app.Run();
+
+ // Only runs once the app shutsdown
+ return 0;
+}
+catch (Exception ex)
+{
+ Log.Fatal(ex, "An unhandled exception occurred during startup");
+ return 1;
+}
+finally
+{
+ Log.CloseAndFlush();
+}
-app.Run();
diff --git a/Gordon360/appsettings.json b/Gordon360/appsettings.json
index 9f0dbb20f..3fa7d86fb 100644
--- a/Gordon360/appsettings.json
+++ b/Gordon360/appsettings.json
@@ -1,6 +1,6 @@
{
"AllowedHosts": "localhost;360.gordon.edu",
- "AllowedOrigin": "",
+ "AllowedOrigin": "",
"AzureAd": {
"Instance": "",
"ClientId": "",
@@ -37,5 +37,16 @@
"Microsoft.Hosting.Lifetime": "Information"
}
},
+ "Serilog": {
+ "Using": [ "Serilog.Sinks.Console", "Serilog.Sinks.File" ],
+ "MinimumLevel": {
+ "Default": "Information",
+ "Override": {
+ "Microsoft.AspNetCore.Mvc": "Warning",
+ "Microsoft.AspNetCore.Routing": "Warning",
+ "Microsoft.AspNetCore.Hosting": "Warning"
+ }
+ }
+ },
"SmtpHost": "smtp.gordon.edu"
}
\ No newline at end of file