v1.2.11.3 deployed

This commit is contained in:
2024-04-24 17:16:49 +01:00
parent 05f166f3d1
commit e40876aeb2
38 changed files with 1222 additions and 168 deletions
+13
View File
@@ -0,0 +1,13 @@
{
"version": 1,
"isRoot": true,
"tools": {
"dotnet-ef": {
"version": "8.0.4",
"commands": [
"dotnet-ef"
],
"rollForward": false
}
}
}
@@ -0,0 +1,141 @@
using Microsoft.Identity.Client;
using Sarand.Net.Standard.Base.App;
using Sarand.Net.Standard.Base.Dbas;
using Sarand.Net.Standard.Base.Helpers;
using Sarand.Net.Standard.Base.IO;
using Sarand.Net.Standard.Base.Utils;
using Saxonite.Net.Core.Web.Base.App;
using Saxonite.Net.Core.Web.Base.Helpers;
using Saxonite.Net.Standard.Base.App;
using Saxonite.Net.Standard.Base.Consoles;
using Saxonite.Net.Standard.Base.Helpers;
using Saxonite.Web.Api.Consoles;
using System.Text.RegularExpressions;
using static Saxonite.Net.Core.Web.Base.App.SaxAppConfig;
namespace Saxonite.Web.Api.App
{
//=======================================================================
public class SaxApplication_Api : SaxApplication_Web
{
//-------------------------------------------------------------------
// Data members.
private Dictionary<String, SaxAppConfig> appConfigs = new Dictionary<string, SaxAppConfig>();
private Dictionary<String, SaxEmailConfig> emailConfigs = new Dictionary<string, SaxEmailConfig>();
// Session contexts.
private class SessionContextData_Api : SessionContextData_Web
{
public SessionContextData_Api(SaxSessionContext_Web sessionContext) : base(sessionContext) { }
}
private readonly Dictionary<int, SessionContextData_Api> sessionContexts = new Dictionary<int, SessionContextData_Api>();
//-------------------------------------------------------------------
// Construction.
public SaxApplication_Api()
{
InitialiseTemporaryLoggingFolder();
try
{
AppInstance = this;
ConsoleHelper_Api = new SaxConsoleHelper_Api(this);
// Logging configuration.
SaLogger.LogFilenamePrefix = "Sax-Web-Api";
SaLogger.IncludeHostInFileMessage = false;
SaLogger.IncludeUserInFileMessage = false;
LoadConfiguration();
}
catch (Exception exc)
{
SaLogger.Error(GetType().Name + ".CTR " + ExceptionUtil.GetErrorStateMessage(exc));
throw;
}
}
//-------------------------------------------------------------------
// Properties.
public static SaxApplication_Api? AppInstance { get; private set; }
public override SaxConsoleHelper ConsoleHelper { get { return ConsoleHelper_Api; } }
public SaxConsoleHelper_Api ConsoleHelper_Api { get; private set; }
// Database.
public override ISacsDatabase? GetDatabase(SaxSessionContext sessionContext, Sax.Database databaseType)
{
return sessionContexts.GetValue(sessionContext.Index, null)?.Databases.GetValue(databaseType, null);
}
// Configuration.
public override SaxAppConfig AppConfig { get { return appConfigs.Values.ToList().getConfigForApplication(); } }
public override SaxEmailConfig EmailConfig { get { return emailConfigs.Values.ToList().getConfigForSession(AppConfig); } }
public override String SessionCookieName { get { return Sax.Config.Api.Session.Cookie.Name; } }
// Startup messages - for debugging. See Admin.Views._Layout.
public List<String> Messages { get; } = new List<String>();
//-------------------------------------------------------------------
// Initialisation.
private void LoadConfiguration()
{
try
{
// Environment.
environmentName = Environments.Development;
if (SaxSystem.ComputerName.EqualsCI("Sarand601"))
environmentName = Environments.Production;
// Load server configuration.
var builder =
new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("appsettings.json", optional: true, reloadOnChange: false)
.AddJsonFile($"appsettings.{environmentName}.json", optional: true, reloadOnChange: false)
.AddJsonFile($"appsettings.machine.{SaxSystem.ComputerName}.json", optional: true, reloadOnChange: false)
.AddEnvironmentVariables();
Stream configStream = SaxResourceHelper.GetResourceStream("appsettings.json", "Config");
if (configStream != null) builder.AddJsonStream(configStream);
configStream = SaxResourceHelper.GetResourceStream($"appsettings.{environmentName}.json", "Config");
if (configStream != null) builder.AddJsonStream(configStream);
configStream = SaxResourceHelper.GetResourceStream($"appsettings.machine.{SaxSystem.ComputerName}.json", "Config");
if (configStream != null) builder.AddJsonStream(configStream);
SaxConfiguration = builder.Build();
// Application configuration.
appConfigs = SaxAppConfigHelper.ExtractAppConfigs(SaxConfiguration.GetSection("AppConfigs"));
emailConfigs = SaxEmailConfigHelper.ExtractEmailConfigs(SaxConfiguration.GetSection("EmailConfigs"));
LoggingRootFolder = AppConfig.Logging.RootFolder;
// Ensure root log folder ends with Api folder.
if (!StringUtil.IsBlank(LoggingRootFolder) && !Regex.IsMatch(LoggingRootFolder, "[\\\\/]Api$", RegexOptions.IgnoreCase))
LoggingRootFolder = StringUtil.CombineFilePath(LoggingRootFolder, "Api");
// Application instance.
if (AppConfig.Instance.EqualsCI("Dev")) instanceType = Sax.InstanceType.Dev;
else if (AppConfig.Instance.ContainsCI("Q")) instanceType = Sax.InstanceType.QC;
else if (AppConfig.Instance.ContainsCI("UAT")) instanceType = Sax.InstanceType.UAT;
else if (AppConfig.Instance.EqualsCI("PreProd")) instanceType = Sax.InstanceType.UAT;
// Initialise hard-coded logging path.
if (StringUtil.IsBlank(LoggingRootFolder))
{
if (SaxSystem.ComputerName.EqualsCI("WIN-BPCLM1QUOMT"))
LoggingRootFolder = @"D:\Saxonite\Logs\" + (Development ? "Dev" : "Test");
}
if (DirectoryUtil.DirectoryExists(LoggingRootFolder))
SaLogger.LogFolder = LoggingRootFolder;
LogApplicationStart(SysUtil.Fn);
// Session context - only one context available/necessary (for now).
SessionContextData_Api sessionContextData = new SessionContextData_Api(new SaxSessionContext_Web(100, Sax.Application.Api));
ConfigureDatabaseConnection(sessionContextData, Sax.Database.Core);
ConfigureDatabaseConnection(sessionContextData, Sax.Database.Support);
sessionContexts.Add(sessionContextData.SessionContext.Index, sessionContextData);
SessionContext = sessionContextData.SessionContext;
}
catch (Exception exc)
{
SaLogger.Warn(SysUtil.Fn + " " + ExceptionUtil.GetLogMessage(exc, "loading application configuration", 8));
}
}
//-------------------------------------------------------------------
}
//=======================================================================
}
@@ -0,0 +1,27 @@
using Sarand.Net.Standard.Base.App;
using Sarand.Net.Standard.Base.Utils;
using Saxonite.Net.Core.Web.Base.Consoles;
using Saxonite.Net.Standard.Base.App;
namespace Saxonite.Web.Api.Consoles
{
//=======================================================================
public class SaxActivityConsole_Api : SaxActivityConsole_Web
{
//-------------------------------------------------------------------
// Data members.
//-------------------------------------------------------------------
public SaxActivityConsole_Api(SaxSessionContext sessionContext) :
base(sessionContext)
{
SaLogger.Info(SysUtil.Fn + "");
}
//-------------------------------------------------------------------
// Utilities.
//-------------------------------------------------------------------
}
//=======================================================================
}
@@ -0,0 +1,84 @@
using Saxonite.Net.Core.Web.Base.Consoles;
using Saxonite.Net.Standard.Base.App;
using Saxonite.Net.Standard.Base.Consoles;
using Saxonite.Web.Api.App;
namespace Saxonite.Web.Api.Consoles
{
//=======================================================================
public class SaxConsoleHelper_Api : SaxConsoleHelper_Web
{
//-------------------------------------------------------------------
// Data members:
private readonly SaxApplication_Api app;
//-------------------------------------------------------------------
// Construction.
public SaxConsoleHelper_Api(SaxApplication_Api app)
{
this.app = app;
}
protected override void Dispose(bool disposing)
{
if (disposing)
{
// Clear process consoles.
foreach (SaxProcessConsole_Api processConsole in processConsoles.Values)
{
processConsole.Dispose();
}
processConsoles.Clear();
}
base.Dispose(disposing);
}
//-------------------------------------------------------------------
// Data cache console.
public override SaxDataCacheConsole GetDataCacheConsole(SaxSessionContext sessionContext)
{
String fn = GetType().Name + ".GetDataCacheConsole";
//throw new NotSupportedException(fn + " Data Cache Console not supported in Admin app.");
return null;
}
//-------------------------------------------------------------------
// Session data console.
public override SaxSessionDataConsole? GetSessionDataConsole(SaxSessionContext sessionContext)
{
// Method is called by Base Controller on ValidUserSession and must return null for Admin app.
return null;
}
//-------------------------------------------------------------------
// Process console.
private Dictionary<ushort, SaxProcessConsole_Api> processConsoles { get; } = new Dictionary<ushort, SaxProcessConsole_Api>();
public SaxProcessConsole GetProcessConsole(SaxSessionContext sessionContext)
{
if (sessionContext == null) throw new NotSupportedException(GetType().Name + ".GetProcessConsole Session Context must be specified");
SaxProcessConsole_Api processConsole = processConsoles.GetValueOrDefault(sessionContext.Index, null);
if (processConsole == null)
{
processConsole = processConsoles[sessionContext.Index] = new SaxProcessConsole_Api(sessionContext);
}
return processConsole;
}
//-------------------------------------------------------------------
// Activity console.
public override SaxActivityConsole CreateActivityConsole(SaxSessionContext sessionContext)
{
return new SaxActivityConsole_Api(sessionContext);
}
//-------------------------------------------------------------------
// Email console.
public override SaxEmailConsole CreateEmailConsole(SaxSessionContext sessionContext)
{
SaxEmailConsole emailConsole = new SaxEmailConsole_Web(app.EmailConfig);
return emailConsole;
}
//-------------------------------------------------------------------
}
//=======================================================================
}
@@ -0,0 +1,102 @@
using Sarand.Net.Standard.Base.Procs;
using Saxonite.Net.Standard.Base.App;
using Saxonite.Net.Standard.Base.Consoles;
using Saxonite.Web.Api.Procs;
namespace Saxonite.Web.Api.Consoles
{
//=======================================================================
public class SaxProcessConsole_Api : SaxProcessConsole
{
//-------------------------------------------------------------------
// Definitions.
public enum ProcessType
{
}
//-------------------------------------------------------------------
// Process cache - to sustain processes outside of request/response timescales.
internal class ProcessData
{
public ProcessData(SaxProcess_Api process)
{
this.Process = process;
}
public SaxProcess_Api Process { get; }
}
// Cache.
private Dictionary<ProcessType, ProcessData> processes { get; } = new Dictionary<ProcessType, ProcessData>();
//-------------------------------------------------------------------
// Data members.
private SaxInternals? internals = null;
//-------------------------------------------------------------------
// Construction.
public SaxProcessConsole_Api(SaxSessionContext sessionContext) : base(sessionContext)
{
}
protected async override void Dispose(bool disposing)
{
if (disposing)
{
// Clear processes.
foreach (ProcessData processData in processes.Values)
{
await processData.Process.StopProcessAsync();
processData.Process.Dispose();
}
}
base.Dispose(disposing);
}
//-------------------------------------------------------------------
// Processes.
//-------------------------------------------------------------------
public SaxProcess_Api GetProcess(ProcessType processType)
{
return processes.GetValueOrDefault(processType, null)?.Process;
}
public bool IsProcessing(ProcessType processType)
{
SaxProcess_Api process = GetProcess(processType);
if (process != null)
if (process.Processing) return true;
return false;
}
/// <summary>
/// Remove the process from the cache.
/// </summary>
/// <param name="processType"></param>
/// <returns></returns>
/// <exception cref="InProgressException"></exception>
public bool ClearProcess(ProcessType processType)
{
SaxProcess_Api process = GetProcess(processType);
if (process != null)
{
if (process.Processing)
throw new SaProcess_Base.InProgressException();
process.Dispose();
}
return processes.Remove(processType);
}
public void SetProcess(ProcessType processType, SaxProcess_Api process)
{
ClearProcess(processType);
processes.Add(processType, new ProcessData(process));
}
//-------------------------------------------------------------------
// Specific processes.
//-------------------------------------------------------------------
//-------------------------------------------------------------------
}
//=======================================================================
}
@@ -0,0 +1,39 @@
using Microsoft.AspNetCore.Mvc;
namespace Saxonite.Web.Api.Controllers
{
//=======================================================================
[ApiController]
//[Route("[controller]")]
public class SecurityController : SwapiControllerBase
{
//-------------------------------------------------------------------
// Construction.
public SecurityController()
{
}
//-------------------------------------------------------------------
// Start session.
public class RequestData_StartSession
{
public String userCode { get; set; } = "";
}
public class ResponseData_StartSession : ApiResponse_Data
{
}
[HttpPost]
[Route("[controller]/StartSession")]
public ResponseData_StartSession StartSession_Get(RequestData_StartSession requestData)
{
ResponseData_StartSession responseData = new ResponseData_StartSession();
responseData.SetMessage("Security",$"User: {requestData.userCode}.");
return responseData;
}
//-------------------------------------------------------------------
}
//=======================================================================
}
@@ -0,0 +1,140 @@
using Microsoft.AspNetCore.Mvc;
using Sacs.Web.Components;
using Sarand.Net.Standard.Base.App;
using Sarand.Net.Standard.Base.Core;
using Sarand.Net.Standard.Base.Utils;
namespace Saxonite.Web.Api.Controllers
{
//=======================================================================
public class SwapiControllerBase : ControllerBase
{
//-------------------------------------------------------------------
// Definitions.
//-------------------------------------------------------------------
// Response data.
// Null values are ignored by JSON serialisation.
// - See Saxonite.Net.Core.Web.Base.App.SaxStartup.ConfigureServices()
// - Ref. config.services.AddMvc(...).AddJsonOptions(options => { options.JsonSerializerOptions.IgnoreNullValues = true; });
//-------------------------------------------------------------------
// Base response data - for simple responses.
public class ApiResponse_Base
{
// Response status.
public bool? Success { get; set; } = null;
public bool? Error { get; set; } = null;
public bool? SessionExpired { get; protected set; } = null;
public ApiResponse_Base SetSessionExpired(String title, String text)
{
SessionExpired = true;
return SetMessage(title, text);
}
// Message - displays alert popup.
public class MessageData
{
public MessageData(String title, String text)
{
this.Title = title;
this.Text = text;
}
public String Title { get; }
public String Text { get; }
}
public MessageData? Message { get; private set; }
public ApiResponse_Base SetMessage(String title, String text)
{
if (!StringUtil.IsBlank(text))
Message = new MessageData(title, text);
return this;
}
}
//-------------------------------------------------------------------
public class ApiResponse_Data : ApiResponse_Base
{
//---------------------------------------------------------------
// Construction.
protected ApiResponse_Data()
{
}
//---------------------------------------------------------------
/// <summary>Item data - Common properties for data items.</summary>
public class ItemData_Base
{
// Common item properties.
public String? Id { get; set; }
public String? Notes { get; set; }
public String? StatusCode { get; set; }
public String? StatusDesc { get; set; }
// Flags for common status values.
// Return true or null so that property is not serialised when false.
public bool? Awaiting { get { return StatusCode.EqualsCI(SacsSystem.GetStatusCode(SaStatus.Awaiting)) ? true : (bool?)null; } }
public bool? Active { get { return StatusCode.EqualsCI(SacsSystem.GetStatusCode(SaStatus.Active)) ? true : (bool?)null; } }
public bool? Inactive { get { return StatusCode.EqualsCI(SacsSystem.GetStatusCode(SaStatus.Inactive)) ? true : (bool?)null; } }
public bool? Deleted { get { return StatusCode.EqualsCI(SacsSystem.GetStatusCode(SaStatus.Deleted)) ? true : (bool?)null; } }
/// <summary>Created on date - YYYYMMDD</summary>
public String? CreatedOn { get; set; }
/// <summary>Created on date - formatted per locale</summary>
public String? CreatedOnFmt { get; set; }
/// <summary>Updated on date - YYYYMMDD</summary>
public String? UpdatedOn { get; set; }
/// <summary>Updated on date - formatted per locale</summary>
public String? UpdatedOnFmt { get; set; }
}
/// <summary>Contact Method properties.</summary>
public class ContactMethodData
{
public String? Method { get; set; }
public String? MethodCaption { get; set; }
public String? Value { get; set; }
}
/// <summary>Address properties.</summary>
public class AddressData : ItemData_Base
{
public String? Line1 { get; set; }
public String? Line2 { get; set; }
public String? Line3 { get; set; }
public String? Town { get; set; }
public String? RegionIdProvince { get; set; }
public String? RegionNameProvince { get; set; }
public String? RegionIdCountry { get; set; }
public String? RegionNameCountry { get; set; }
public String? PostalCode { get; set; }
}
/// <summary>
/// Item data with label and value.
/// </summary>
public class ItemLabelValue
{
public String? Label { get; set; }
public String? Value { get; set; }
}
/// <summary>
/// Item data with just Id and name.
/// <para>- Id is String to allow for obfuscated values.</para>
/// </summary>
public class ItemIdName
{
public String? Id { get; set; }
public String? Name { get; set; }
}
/// <summary>Item code and desc values.</summary>
public class ItemCodeDesc
{
public String? Code { get; set; }
public String? Desc { get; set; }
}
}
//-------------------------------------------------------------------
// Construction.
protected SwapiControllerBase()
{
}
//-------------------------------------------------------------------
}
//=======================================================================
}
@@ -0,0 +1,39 @@
using Microsoft.AspNetCore.Mvc;
using Saxonite.Net.Standard.Base.App;
using static Sarand.Net.Standard.Base.Helpers.SacsHttpClientHelper;
namespace Saxonite.Web.Api.Controllers
{
//=======================================================================
[ApiController]
public class SystemController : SwapiControllerBase
{
//-------------------------------------------------------------------
// Construction.
public SystemController()
{
}
//-------------------------------------------------------------------
// Start session.
public class RequestData_Version
{
}
public class ResponseData_Version : ApiResponse_Data
{
public String? Version { get; set; }
}
[HttpPost]
[Route("[controller]/Version")]
public ResponseData_Version GetVersion_Post(RequestData_Version requestData)
{
ResponseData_Version responseData = new ResponseData_Version();
responseData.Version = Sax.Version.GetFullVersion();
return responseData;
}
//-------------------------------------------------------------------
}
//=======================================================================
}
@@ -0,0 +1,32 @@
using Sarand.Net.Standard.Proc.Excel;
using Saxonite.Net.Standard.Base.App;
using Saxonite.Net.Standard.Base.Procs;
namespace Saxonite.Web.Api.Procs
{
//=======================================================================
public abstract class SaxProcess_Api : SaxProcess_Base
{
//-------------------------------------------------------------------
// Definitions.
public new class Config : SaxProcess_Base.Config
{
protected Config(SaxSessionContext sessionContext) : base(sessionContext)
{ }
}
//-------------------------------------------------------------------
// Data members.
private Config config;
//-------------------------------------------------------------------
// Construction.
protected SaxProcess_Api(Config config) : base(config)
{
this.config = config;
}
//-------------------------------------------------------------------
}
//=======================================================================
}
+37
View File
@@ -0,0 +1,37 @@
using Saxonite.Web.Api.App;
using System.Text.Json.Serialization;
{
// Saxonite API application.
var application = new SaxApplication_Api();
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddControllers();
builder.Services.AddControllers().AddJsonOptions(options =>
{
options.JsonSerializerOptions.DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull;
});
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
var app = builder.Build();
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}
//app.UseHttpsRedirection();
app.UseAuthorization();
app.MapControllers();
app.Run();
}
@@ -0,0 +1,31 @@
{
"$schema": "https://json.schemastore.org/launchsettings.json",
"iisSettings": {
"windowsAuthentication": false,
"anonymousAuthentication": true,
"iisExpress": {
"applicationUrl": "http://localhost:52385",
"sslPort": 44304
}
},
"profiles": {
"SaxoniteWebApi": {
"commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": true,
"launchUrl": "swagger",
"applicationUrl": "https://localhost:7048;http://localhost:5193",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"IIS Express": {
"commandName": "IISExpress",
"launchBrowser": true,
"launchUrl": "swagger",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
}
}
}
+29
View File
@@ -0,0 +1,29 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<AssemblyName>Saxonite.Web</AssemblyName>
<RootNamespace>Saxonite.Web</RootNamespace>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.5.0" />
</ItemGroup>
<ItemGroup>
<Folder Include="Api\Base\" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\Common-VS\Workspace\SacsCoreWeb\SacsCoreWeb.csproj" />
<ProjectReference Include="..\..\..\Common-VS\Workspace\SacsStandardBase\SacsStandardBase.csproj" />
<ProjectReference Include="..\..\..\Common-VS\Workspace\SacsStandardDbas\SacsStandardDbas.csproj" />
<ProjectReference Include="..\..\..\Common-VS\Workspace\SacsStandardProc\SacsStandardProc.csproj" />
<ProjectReference Include="..\SaxoniteCoreWeb\SaxoniteCoreWeb.csproj" />
<ProjectReference Include="..\SaxoniteStandardBase\SaxoniteStandardBase.csproj" />
<ProjectReference Include="..\SaxoniteStandardDbas\SaxoniteStandardDbas.csproj" />
</ItemGroup>
</Project>
@@ -0,0 +1,8 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
}
}
+9
View File
@@ -0,0 +1,9 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "*"
}