Restructure Saxonite workspace and upgrade to .NET 10
This commit is contained in:
@@ -0,0 +1,238 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 17
|
||||
VisualStudioVersion = 17.7.34202.233
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SaxoniteCoreWebAdmin", "SaxoniteCoreWebAdmin\SaxoniteCoreWebAdmin.csproj", "{F646283D-F7C2-42DD-AB1E-E741455664BD}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SaxoniteStandardDbas", "SaxoniteStandardDbas\SaxoniteStandardDbas.csproj", "{DA383586-69E3-40EB-A20D-AC1AD24E336C}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SaxoniteStandardBase", "SaxoniteStandardBase\SaxoniteStandardBase.csproj", "{38FBE932-C1D0-4A28-9172-1466347FD62B}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SacsStandardBase", "..\..\..\Common-VS\Workspace\SacsStandardBase\SacsStandardBase.csproj", "{9C5309DA-3205-4423-BE13-923EE61370A6}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SacsStandardDbas", "..\..\..\Common-VS\Workspace\SacsStandardDbas\SacsStandardDbas.csproj", "{E211FE36-108E-4D07-BD30-799A156DDDBB}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SaxoniteStandardMob", "SaxoniteStandardMob\SaxoniteStandardMob.csproj", "{89CFDAA1-15C9-45CF-8FBF-88E36E0E32CF}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SaxoniteCoreWeb", "SaxoniteCoreWeb\SaxoniteCoreWeb.csproj", "{CFF91B48-04B7-4075-A5B2-FF3FC0B22BC1}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SaxoniteCoreWebOnline", "SaxoniteCoreWebOnline\SaxoniteCoreWebOnline.csproj", "{C1A3E949-B5EA-4A77-9411-5D8B350056D6}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SacsCoreWeb", "..\..\..\Common-VS\Workspace\SacsCoreWeb\SacsCoreWeb.csproj", "{BBEEBD5B-7D00-4024-9626-D8B2FBF248A4}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SaxoniteUnitTestsAdmin", "SaxoniteUnitTestsAdmin\SaxoniteUnitTestsAdmin.csproj", "{CA680625-E334-4F76-881B-1327A2F9FE86}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution files", "Solution files", "{BD66A338-2D41-4B64-86B0-670F4F42A489}"
|
||||
ProjectSection(SolutionItems) = preProject
|
||||
ReadMe.md = ReadMe.md
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SaxoniteUnitTestsOnline", "SaxoniteUnitTestsOnline\SaxoniteUnitTestsOnline.csproj", "{303BA8E9-1B95-41AD-9F51-32037A22C908}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SacsStandardProc", "..\..\..\Common-VS\Workspace\SacsStandardProc\SacsStandardProc.csproj", "{E012B3D3-CF4D-4C2E-ABC6-9E3A3DAE03C5}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SaxoniteWebApi", "SaxoniteWebApi\SaxoniteWebApi.csproj", "{3E1C2BE2-46C8-4D1D-A1C2-806BB1AD8A7E}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SacsBusinessBase", "..\..\..\Common-VS\Workspace\SacsBusinessBase\SacsBusinessBase.csproj", "{3D3F98C7-F165-45E1-A2B2-773CB0296962}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SaxoniteUnitTestsShared", "SaxoniteUnitTestsShared\SaxoniteUnitTestsShared.csproj", "{EF62BB9D-8FBC-4B83-BC59-CD123A27BB8E}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Debug|x64 = Debug|x64
|
||||
Debug|x86 = Debug|x86
|
||||
Release|Any CPU = Release|Any CPU
|
||||
Release|x64 = Release|x64
|
||||
Release|x86 = Release|x86
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{F646283D-F7C2-42DD-AB1E-E741455664BD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{F646283D-F7C2-42DD-AB1E-E741455664BD}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{F646283D-F7C2-42DD-AB1E-E741455664BD}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{F646283D-F7C2-42DD-AB1E-E741455664BD}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{F646283D-F7C2-42DD-AB1E-E741455664BD}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{F646283D-F7C2-42DD-AB1E-E741455664BD}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{F646283D-F7C2-42DD-AB1E-E741455664BD}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{F646283D-F7C2-42DD-AB1E-E741455664BD}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{F646283D-F7C2-42DD-AB1E-E741455664BD}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{F646283D-F7C2-42DD-AB1E-E741455664BD}.Release|x64.Build.0 = Release|Any CPU
|
||||
{F646283D-F7C2-42DD-AB1E-E741455664BD}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{F646283D-F7C2-42DD-AB1E-E741455664BD}.Release|x86.Build.0 = Release|Any CPU
|
||||
{DA383586-69E3-40EB-A20D-AC1AD24E336C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{DA383586-69E3-40EB-A20D-AC1AD24E336C}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{DA383586-69E3-40EB-A20D-AC1AD24E336C}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{DA383586-69E3-40EB-A20D-AC1AD24E336C}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{DA383586-69E3-40EB-A20D-AC1AD24E336C}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{DA383586-69E3-40EB-A20D-AC1AD24E336C}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{DA383586-69E3-40EB-A20D-AC1AD24E336C}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{DA383586-69E3-40EB-A20D-AC1AD24E336C}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{DA383586-69E3-40EB-A20D-AC1AD24E336C}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{DA383586-69E3-40EB-A20D-AC1AD24E336C}.Release|x64.Build.0 = Release|Any CPU
|
||||
{DA383586-69E3-40EB-A20D-AC1AD24E336C}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{DA383586-69E3-40EB-A20D-AC1AD24E336C}.Release|x86.Build.0 = Release|Any CPU
|
||||
{38FBE932-C1D0-4A28-9172-1466347FD62B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{38FBE932-C1D0-4A28-9172-1466347FD62B}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{38FBE932-C1D0-4A28-9172-1466347FD62B}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{38FBE932-C1D0-4A28-9172-1466347FD62B}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{38FBE932-C1D0-4A28-9172-1466347FD62B}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{38FBE932-C1D0-4A28-9172-1466347FD62B}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{38FBE932-C1D0-4A28-9172-1466347FD62B}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{38FBE932-C1D0-4A28-9172-1466347FD62B}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{38FBE932-C1D0-4A28-9172-1466347FD62B}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{38FBE932-C1D0-4A28-9172-1466347FD62B}.Release|x64.Build.0 = Release|Any CPU
|
||||
{38FBE932-C1D0-4A28-9172-1466347FD62B}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{38FBE932-C1D0-4A28-9172-1466347FD62B}.Release|x86.Build.0 = Release|Any CPU
|
||||
{9C5309DA-3205-4423-BE13-923EE61370A6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{9C5309DA-3205-4423-BE13-923EE61370A6}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{9C5309DA-3205-4423-BE13-923EE61370A6}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{9C5309DA-3205-4423-BE13-923EE61370A6}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{9C5309DA-3205-4423-BE13-923EE61370A6}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{9C5309DA-3205-4423-BE13-923EE61370A6}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{9C5309DA-3205-4423-BE13-923EE61370A6}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{9C5309DA-3205-4423-BE13-923EE61370A6}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{9C5309DA-3205-4423-BE13-923EE61370A6}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{9C5309DA-3205-4423-BE13-923EE61370A6}.Release|x64.Build.0 = Release|Any CPU
|
||||
{9C5309DA-3205-4423-BE13-923EE61370A6}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{9C5309DA-3205-4423-BE13-923EE61370A6}.Release|x86.Build.0 = Release|Any CPU
|
||||
{E211FE36-108E-4D07-BD30-799A156DDDBB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{E211FE36-108E-4D07-BD30-799A156DDDBB}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{E211FE36-108E-4D07-BD30-799A156DDDBB}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{E211FE36-108E-4D07-BD30-799A156DDDBB}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{E211FE36-108E-4D07-BD30-799A156DDDBB}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{E211FE36-108E-4D07-BD30-799A156DDDBB}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{E211FE36-108E-4D07-BD30-799A156DDDBB}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{E211FE36-108E-4D07-BD30-799A156DDDBB}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{E211FE36-108E-4D07-BD30-799A156DDDBB}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{E211FE36-108E-4D07-BD30-799A156DDDBB}.Release|x64.Build.0 = Release|Any CPU
|
||||
{E211FE36-108E-4D07-BD30-799A156DDDBB}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{E211FE36-108E-4D07-BD30-799A156DDDBB}.Release|x86.Build.0 = Release|Any CPU
|
||||
{89CFDAA1-15C9-45CF-8FBF-88E36E0E32CF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{89CFDAA1-15C9-45CF-8FBF-88E36E0E32CF}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{89CFDAA1-15C9-45CF-8FBF-88E36E0E32CF}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{89CFDAA1-15C9-45CF-8FBF-88E36E0E32CF}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{89CFDAA1-15C9-45CF-8FBF-88E36E0E32CF}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{89CFDAA1-15C9-45CF-8FBF-88E36E0E32CF}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{89CFDAA1-15C9-45CF-8FBF-88E36E0E32CF}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{89CFDAA1-15C9-45CF-8FBF-88E36E0E32CF}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{89CFDAA1-15C9-45CF-8FBF-88E36E0E32CF}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{89CFDAA1-15C9-45CF-8FBF-88E36E0E32CF}.Release|x64.Build.0 = Release|Any CPU
|
||||
{89CFDAA1-15C9-45CF-8FBF-88E36E0E32CF}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{89CFDAA1-15C9-45CF-8FBF-88E36E0E32CF}.Release|x86.Build.0 = Release|Any CPU
|
||||
{CFF91B48-04B7-4075-A5B2-FF3FC0B22BC1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{CFF91B48-04B7-4075-A5B2-FF3FC0B22BC1}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{CFF91B48-04B7-4075-A5B2-FF3FC0B22BC1}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{CFF91B48-04B7-4075-A5B2-FF3FC0B22BC1}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{CFF91B48-04B7-4075-A5B2-FF3FC0B22BC1}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{CFF91B48-04B7-4075-A5B2-FF3FC0B22BC1}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{CFF91B48-04B7-4075-A5B2-FF3FC0B22BC1}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{CFF91B48-04B7-4075-A5B2-FF3FC0B22BC1}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{CFF91B48-04B7-4075-A5B2-FF3FC0B22BC1}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{CFF91B48-04B7-4075-A5B2-FF3FC0B22BC1}.Release|x64.Build.0 = Release|Any CPU
|
||||
{CFF91B48-04B7-4075-A5B2-FF3FC0B22BC1}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{CFF91B48-04B7-4075-A5B2-FF3FC0B22BC1}.Release|x86.Build.0 = Release|Any CPU
|
||||
{C1A3E949-B5EA-4A77-9411-5D8B350056D6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{C1A3E949-B5EA-4A77-9411-5D8B350056D6}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{C1A3E949-B5EA-4A77-9411-5D8B350056D6}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{C1A3E949-B5EA-4A77-9411-5D8B350056D6}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{C1A3E949-B5EA-4A77-9411-5D8B350056D6}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{C1A3E949-B5EA-4A77-9411-5D8B350056D6}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{C1A3E949-B5EA-4A77-9411-5D8B350056D6}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{C1A3E949-B5EA-4A77-9411-5D8B350056D6}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{C1A3E949-B5EA-4A77-9411-5D8B350056D6}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{C1A3E949-B5EA-4A77-9411-5D8B350056D6}.Release|x64.Build.0 = Release|Any CPU
|
||||
{C1A3E949-B5EA-4A77-9411-5D8B350056D6}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{C1A3E949-B5EA-4A77-9411-5D8B350056D6}.Release|x86.Build.0 = Release|Any CPU
|
||||
{BBEEBD5B-7D00-4024-9626-D8B2FBF248A4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{BBEEBD5B-7D00-4024-9626-D8B2FBF248A4}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{BBEEBD5B-7D00-4024-9626-D8B2FBF248A4}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{BBEEBD5B-7D00-4024-9626-D8B2FBF248A4}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{BBEEBD5B-7D00-4024-9626-D8B2FBF248A4}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{BBEEBD5B-7D00-4024-9626-D8B2FBF248A4}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{BBEEBD5B-7D00-4024-9626-D8B2FBF248A4}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{BBEEBD5B-7D00-4024-9626-D8B2FBF248A4}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{BBEEBD5B-7D00-4024-9626-D8B2FBF248A4}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{BBEEBD5B-7D00-4024-9626-D8B2FBF248A4}.Release|x64.Build.0 = Release|Any CPU
|
||||
{BBEEBD5B-7D00-4024-9626-D8B2FBF248A4}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{BBEEBD5B-7D00-4024-9626-D8B2FBF248A4}.Release|x86.Build.0 = Release|Any CPU
|
||||
{CA680625-E334-4F76-881B-1327A2F9FE86}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{CA680625-E334-4F76-881B-1327A2F9FE86}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{CA680625-E334-4F76-881B-1327A2F9FE86}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{CA680625-E334-4F76-881B-1327A2F9FE86}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{CA680625-E334-4F76-881B-1327A2F9FE86}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{CA680625-E334-4F76-881B-1327A2F9FE86}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{CA680625-E334-4F76-881B-1327A2F9FE86}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{CA680625-E334-4F76-881B-1327A2F9FE86}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{CA680625-E334-4F76-881B-1327A2F9FE86}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{CA680625-E334-4F76-881B-1327A2F9FE86}.Release|x64.Build.0 = Release|Any CPU
|
||||
{CA680625-E334-4F76-881B-1327A2F9FE86}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{CA680625-E334-4F76-881B-1327A2F9FE86}.Release|x86.Build.0 = Release|Any CPU
|
||||
{303BA8E9-1B95-41AD-9F51-32037A22C908}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{303BA8E9-1B95-41AD-9F51-32037A22C908}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{303BA8E9-1B95-41AD-9F51-32037A22C908}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{303BA8E9-1B95-41AD-9F51-32037A22C908}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{303BA8E9-1B95-41AD-9F51-32037A22C908}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{303BA8E9-1B95-41AD-9F51-32037A22C908}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{303BA8E9-1B95-41AD-9F51-32037A22C908}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{303BA8E9-1B95-41AD-9F51-32037A22C908}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{303BA8E9-1B95-41AD-9F51-32037A22C908}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{303BA8E9-1B95-41AD-9F51-32037A22C908}.Release|x64.Build.0 = Release|Any CPU
|
||||
{303BA8E9-1B95-41AD-9F51-32037A22C908}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{303BA8E9-1B95-41AD-9F51-32037A22C908}.Release|x86.Build.0 = Release|Any CPU
|
||||
{E012B3D3-CF4D-4C2E-ABC6-9E3A3DAE03C5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{E012B3D3-CF4D-4C2E-ABC6-9E3A3DAE03C5}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{E012B3D3-CF4D-4C2E-ABC6-9E3A3DAE03C5}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{E012B3D3-CF4D-4C2E-ABC6-9E3A3DAE03C5}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{E012B3D3-CF4D-4C2E-ABC6-9E3A3DAE03C5}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{E012B3D3-CF4D-4C2E-ABC6-9E3A3DAE03C5}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{E012B3D3-CF4D-4C2E-ABC6-9E3A3DAE03C5}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{E012B3D3-CF4D-4C2E-ABC6-9E3A3DAE03C5}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{E012B3D3-CF4D-4C2E-ABC6-9E3A3DAE03C5}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{E012B3D3-CF4D-4C2E-ABC6-9E3A3DAE03C5}.Release|x64.Build.0 = Release|Any CPU
|
||||
{E012B3D3-CF4D-4C2E-ABC6-9E3A3DAE03C5}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{E012B3D3-CF4D-4C2E-ABC6-9E3A3DAE03C5}.Release|x86.Build.0 = Release|Any CPU
|
||||
{3E1C2BE2-46C8-4D1D-A1C2-806BB1AD8A7E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{3E1C2BE2-46C8-4D1D-A1C2-806BB1AD8A7E}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{3E1C2BE2-46C8-4D1D-A1C2-806BB1AD8A7E}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{3E1C2BE2-46C8-4D1D-A1C2-806BB1AD8A7E}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{3E1C2BE2-46C8-4D1D-A1C2-806BB1AD8A7E}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{3E1C2BE2-46C8-4D1D-A1C2-806BB1AD8A7E}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{3E1C2BE2-46C8-4D1D-A1C2-806BB1AD8A7E}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{3E1C2BE2-46C8-4D1D-A1C2-806BB1AD8A7E}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{3E1C2BE2-46C8-4D1D-A1C2-806BB1AD8A7E}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{3E1C2BE2-46C8-4D1D-A1C2-806BB1AD8A7E}.Release|x64.Build.0 = Release|Any CPU
|
||||
{3E1C2BE2-46C8-4D1D-A1C2-806BB1AD8A7E}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{3E1C2BE2-46C8-4D1D-A1C2-806BB1AD8A7E}.Release|x86.Build.0 = Release|Any CPU
|
||||
{3D3F98C7-F165-45E1-A2B2-773CB0296962}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{3D3F98C7-F165-45E1-A2B2-773CB0296962}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{3D3F98C7-F165-45E1-A2B2-773CB0296962}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{3D3F98C7-F165-45E1-A2B2-773CB0296962}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{3D3F98C7-F165-45E1-A2B2-773CB0296962}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{3D3F98C7-F165-45E1-A2B2-773CB0296962}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{3D3F98C7-F165-45E1-A2B2-773CB0296962}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{3D3F98C7-F165-45E1-A2B2-773CB0296962}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{3D3F98C7-F165-45E1-A2B2-773CB0296962}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{3D3F98C7-F165-45E1-A2B2-773CB0296962}.Release|x64.Build.0 = Release|Any CPU
|
||||
{3D3F98C7-F165-45E1-A2B2-773CB0296962}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{3D3F98C7-F165-45E1-A2B2-773CB0296962}.Release|x86.Build.0 = Release|Any CPU
|
||||
{EF62BB9D-8FBC-4B83-BC59-CD123A27BB8E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{EF62BB9D-8FBC-4B83-BC59-CD123A27BB8E}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{EF62BB9D-8FBC-4B83-BC59-CD123A27BB8E}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{EF62BB9D-8FBC-4B83-BC59-CD123A27BB8E}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{EF62BB9D-8FBC-4B83-BC59-CD123A27BB8E}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{EF62BB9D-8FBC-4B83-BC59-CD123A27BB8E}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{EF62BB9D-8FBC-4B83-BC59-CD123A27BB8E}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{EF62BB9D-8FBC-4B83-BC59-CD123A27BB8E}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{EF62BB9D-8FBC-4B83-BC59-CD123A27BB8E}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{EF62BB9D-8FBC-4B83-BC59-CD123A27BB8E}.Release|x64.Build.0 = Release|Any CPU
|
||||
{EF62BB9D-8FBC-4B83-BC59-CD123A27BB8E}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{EF62BB9D-8FBC-4B83-BC59-CD123A27BB8E}.Release|x86.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {0DFC2321-53B9-493B-83D3-2ACD1C47C732}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
@@ -0,0 +1,259 @@
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Sarand.Net.Standard.Base.App;
|
||||
using Sarand.Net.Standard.Base.Core;
|
||||
using Sarand.Net.Standard.Base.Utils;
|
||||
using Saxonite.Net.Standard.Base.App;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace Saxonite.Net.Core.Web.Base.App
|
||||
{
|
||||
//=======================================================================
|
||||
public class SaxAppConfig
|
||||
{
|
||||
//---------------------------------------------------------------
|
||||
// Data members.
|
||||
private readonly List<String> environments = new List<string>();
|
||||
|
||||
//---------------------------------------------------------------
|
||||
// Construction.
|
||||
public SaxAppConfig(String context, ConfigurationSection configSection, SaxAppConfig defaultConfig)
|
||||
{
|
||||
Context = context;
|
||||
PopulateDefaults(defaultConfig);
|
||||
PopulateConfig(configSection);
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------
|
||||
// Properties.
|
||||
public String Context { get; }
|
||||
public List<String> Environments { get { return new List<String>(environments); } }
|
||||
public String Instance { get; set; } = "";
|
||||
// URLs.
|
||||
public class URLConfig
|
||||
{
|
||||
public class OnlineConfig
|
||||
{
|
||||
public String Root { get; set; }
|
||||
}
|
||||
public OnlineConfig Online { get; } = new OnlineConfig();
|
||||
}
|
||||
public URLConfig URL { get; } = new URLConfig();
|
||||
// Security.
|
||||
public class SecurityConfig
|
||||
{
|
||||
public class PasswordConfig
|
||||
{
|
||||
public int MinLength { get; set; }
|
||||
}
|
||||
public PasswordConfig Password { get; } = new PasswordConfig();
|
||||
public class SignUpConfig
|
||||
{
|
||||
public class ActivationConfig
|
||||
{
|
||||
public int EmailLinkExpiresMins = Sax.Config.Security.Activation.EmailLinkExpiresMins_Default;
|
||||
}
|
||||
public ActivationConfig Activation { get; } = new ActivationConfig();
|
||||
}
|
||||
public SignUpConfig SignUp { get; } = new SignUpConfig();
|
||||
public class SignInConfig
|
||||
{
|
||||
public class PasswordRequestConfig
|
||||
{
|
||||
public int EmailLinkExpiresMins = Sax.Config.Security.Activation.EmailLinkExpiresMins_Default;
|
||||
}
|
||||
public PasswordRequestConfig PasswordRequest { get; } = new PasswordRequestConfig();
|
||||
public class KeepLoggedInConfig
|
||||
{
|
||||
public bool Allowed { get; set; } = Sax.Config.Security.SignIn.KeepLoggedIn.Allowed_Default;
|
||||
public int CookieExpiresDays { get; set; } = Sax.Config.Security.SignIn.KeepLoggedIn.CookieExpiresDays_Default;
|
||||
}
|
||||
public KeepLoggedInConfig KeepLoggedIn { get; } = new KeepLoggedInConfig();
|
||||
}
|
||||
public SignInConfig SignIn { get; } = new SignInConfig();
|
||||
}
|
||||
public SecurityConfig Security { get; } = new SecurityConfig();
|
||||
// Email.
|
||||
public class EmailConfig
|
||||
{
|
||||
public class SpecificEmailConfig
|
||||
{
|
||||
public List<String> AddressesTo { get; } = new List<string>();
|
||||
public List<String> AddressesCc { get; } = new List<string>();
|
||||
public List<String> AddressesBcc { get; } = new List<string>();
|
||||
}
|
||||
public SpecificEmailConfig ContactUs { get; } = new SpecificEmailConfig();
|
||||
public SpecificEmailConfig Signup_Activate { get; } = new SpecificEmailConfig();
|
||||
public SpecificEmailConfig Signup_Welcome { get; } = new SpecificEmailConfig();
|
||||
public String Context { get; internal set; }
|
||||
}
|
||||
public EmailConfig Email { get; } = new EmailConfig();
|
||||
// Databases.
|
||||
public class DatabaseConfig
|
||||
{
|
||||
public String Location { get; internal set; }
|
||||
public String User { get; internal set; }
|
||||
public String Password { get; internal set; }
|
||||
}
|
||||
public class DatabasesConfig
|
||||
{
|
||||
public Dictionary<Sax.Database, DatabaseConfig> Databases { get; } = new Dictionary<Sax.Database, DatabaseConfig>();
|
||||
public DatabaseConfig Core { get { return Databases.GetValue(Sax.Database.Core, new DatabaseConfig()); } }
|
||||
public DatabaseConfig Reference { get { return Databases.GetValue(Sax.Database.Reference, new DatabaseConfig()); } }
|
||||
public DatabaseConfig Support { get { return Databases.GetValue(Sax.Database.Support, new DatabaseConfig()); } }
|
||||
}
|
||||
public DatabasesConfig Databases { get; } = new DatabasesConfig();
|
||||
// Documents.
|
||||
public class DocumentsConfig
|
||||
{
|
||||
public String RootFolder { get; internal set; }
|
||||
}
|
||||
public DocumentsConfig Documents { get; } = new DocumentsConfig();
|
||||
// Logging.
|
||||
public class LoggingConfig
|
||||
{
|
||||
public String RootFolder { get; internal set; }
|
||||
}
|
||||
public LoggingConfig Logging { get; } = new LoggingConfig();
|
||||
|
||||
//---------------------------------------------------------------
|
||||
private void PopulateDefaults(SaxAppConfig defaultConfig)
|
||||
{
|
||||
if (defaultConfig == null) return;
|
||||
Security.Password.MinLength = defaultConfig.Security.Password.MinLength;
|
||||
Security.SignIn.KeepLoggedIn.Allowed = defaultConfig.Security.SignIn.KeepLoggedIn.Allowed;
|
||||
Security.SignIn.KeepLoggedIn.CookieExpiresDays = defaultConfig.Security.SignIn.KeepLoggedIn.CookieExpiresDays;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------
|
||||
private void PopulateConfig(ConfigurationSection configSection)
|
||||
{
|
||||
if (configSection != null)
|
||||
{
|
||||
// Environments.
|
||||
foreach (ConfigurationSection environment in configSection.GetSection("Environments").GetChildren())
|
||||
environments.Add(StringUtil.TrimAll(environment.Value));
|
||||
Instance = StringUtil.OnEmpty(configSection["Instance"], Instance);
|
||||
|
||||
// URLs.
|
||||
IConfigurationSection urls = configSection.GetSection("URLs");
|
||||
if (urls.Exists())
|
||||
{
|
||||
IConfigurationSection onlineUrls = urls.GetSection("Online");
|
||||
if (onlineUrls.Exists())
|
||||
{
|
||||
URL.Online.Root = onlineUrls["Root"];
|
||||
}
|
||||
}
|
||||
|
||||
// Security.
|
||||
IConfigurationSection security = configSection.GetSection("Security");
|
||||
if (security.Exists())
|
||||
{
|
||||
// Security - Password.
|
||||
IConfigurationSection securityPassword = security.GetSection("Password");
|
||||
if (securityPassword.Exists())
|
||||
{
|
||||
Security.Password.MinLength = StringUtil.ToInt(securityPassword["MinLength"], Security.Password.MinLength);
|
||||
}
|
||||
// Security - Sign-Up.
|
||||
IConfigurationSection securitySignUp = security.GetSection("SignUp");
|
||||
if (securitySignUp.Exists())
|
||||
{
|
||||
}
|
||||
// Security - Sign-In.
|
||||
IConfigurationSection securitySignIn = security.GetSection("SignIn");
|
||||
if (securitySignIn.Exists())
|
||||
{
|
||||
IConfigurationSection keepLoggedIn = securitySignIn.GetSection("SignIn");
|
||||
if (keepLoggedIn.Exists())
|
||||
{
|
||||
Security.SignIn.KeepLoggedIn.Allowed = StringUtil.ToBool(StringUtil.OnEmpty(keepLoggedIn["Allowed"], Security.SignIn.KeepLoggedIn.Allowed.ToString()));
|
||||
Security.SignIn.KeepLoggedIn.CookieExpiresDays = StringUtil.ToInt(keepLoggedIn["CookieExpiresDays"], Security.SignIn.KeepLoggedIn.CookieExpiresDays);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Email.
|
||||
IConfigurationSection email = configSection.GetSection("Email");
|
||||
if (email.Exists())
|
||||
{
|
||||
Email.Context = email["Context"];
|
||||
PopulateEmailConfig(Email.ContactUs, email.GetSection("ContactUs"));
|
||||
PopulateEmailConfig(Email.Signup_Activate, email.GetSection("Signup").GetSection("Activate"));
|
||||
PopulateEmailConfig(Email.Signup_Welcome, email.GetSection("Signup").GetSection("Welcome"));
|
||||
}
|
||||
|
||||
// Documents.
|
||||
IConfigurationSection documents = configSection.GetSection("Documents");
|
||||
if (documents.Exists())
|
||||
{
|
||||
Documents.RootFolder = StringUtil.OnEmpty(documents["RootFolder"], Documents.RootFolder);
|
||||
}
|
||||
|
||||
// Logging.
|
||||
IConfigurationSection logging = configSection.GetSection("Logging");
|
||||
if (logging.Exists())
|
||||
{
|
||||
Logging.RootFolder = StringUtil.OnEmpty(logging["RootFolder"], Logging.RootFolder);
|
||||
}
|
||||
|
||||
// Database.
|
||||
ExtractDatabasesConfig(Databases, configSection.GetSection("Databases"));
|
||||
|
||||
// Variants.
|
||||
foreach (ConfigurationSection variantSection in configSection.GetSection("Variants").GetChildren())
|
||||
{
|
||||
// Variants override selected values but must match the application root folder to identify a specific instance.
|
||||
String applicationRootPath = variantSection["ApplicationRootFolder"];
|
||||
if (StringUtil.IsEmpty(applicationRootPath)) continue;
|
||||
if (!SaxSystem.ApplicationFolder.EqualsCI(applicationRootPath)) continue;
|
||||
PopulateConfig(variantSection);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------
|
||||
private void PopulateEmailConfig(EmailConfig.SpecificEmailConfig config, IConfigurationSection emailSection)
|
||||
{
|
||||
if (!emailSection.Exists()) return;
|
||||
foreach (var addressTo in emailSection.GetSection("AddressesTo").GetChildren())
|
||||
config.AddressesTo.Add(StringUtil.TrimAll(addressTo.Value));
|
||||
foreach (var addressCc in emailSection.GetSection("AddressesCc").GetChildren())
|
||||
config.AddressesCc.Add(StringUtil.TrimAll(addressCc.Value));
|
||||
foreach (var addressBcc in emailSection.GetSection("AddressesBcc").GetChildren())
|
||||
config.AddressesBcc.Add(StringUtil.TrimAll(addressBcc.Value));
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------
|
||||
private void ExtractDatabasesConfig(DatabasesConfig databases, IConfigurationSection databasesSection)
|
||||
{
|
||||
if (!databasesSection.Exists()) return;
|
||||
// 'Database' section contains a separate named configuration for each database: 'Core', 'Support' etc.
|
||||
foreach (var databaseSection in databasesSection.GetChildren())
|
||||
ExtractDatabaseConfig(databases, databaseSection);
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------
|
||||
private void ExtractDatabaseConfig(DatabasesConfig databases, IConfigurationSection databaseSection)
|
||||
{
|
||||
if (!databaseSection.Exists()) return;
|
||||
Sax.Database databaseType = EnumUtil.ParseEnum<Sax.Database>(databaseSection.Key);
|
||||
if (databaseType <= 0)
|
||||
{
|
||||
SaLogger.Warn($"{SysUtil.Fn} Unrecognised database: {databaseSection.Key}");
|
||||
return;
|
||||
}
|
||||
// Extract database configuration.
|
||||
DatabaseConfig database = new DatabaseConfig();
|
||||
database.Location = StringUtil.OnEmpty(databaseSection["Location"], database.Location);
|
||||
database.User = StringUtil.OnEmpty(databaseSection["User"], database.User);
|
||||
database.Password = StringUtil.OnEmpty(databaseSection["Password"], database.Password);
|
||||
databases.Databases.Add(databaseType, database);
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------
|
||||
}
|
||||
//=======================================================================
|
||||
}
|
||||
@@ -0,0 +1,191 @@
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using Sarand.Net.Standard.Base.App;
|
||||
using Sarand.Net.Standard.Base.Core;
|
||||
using Sarand.Net.Standard.Base.Dbas;
|
||||
using Sarand.Net.Standard.Base.Email;
|
||||
using Sarand.Net.Standard.Base.IO;
|
||||
using Sarand.Net.Standard.Base.Utils;
|
||||
using Sarand.Net.Standard.Dbas.Base;
|
||||
using Sarand.Net.Standard.Dbas.Data;
|
||||
using Saxonite.Net.Core.Web.Base.Consoles;
|
||||
using Saxonite.Net.Standard.Base.App;
|
||||
using Saxonite.Net.Standard.Base.Consoles;
|
||||
using Saxonite.Net.Standard.Base.Helpers;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace Saxonite.Net.Core.Web.Base.App
|
||||
{
|
||||
//=======================================================================
|
||||
public abstract class SaxApplication_Web : SaxApplication_Base
|
||||
{
|
||||
//-------------------------------------------------------------------
|
||||
// Data members.
|
||||
protected Sax.InstanceType instanceType;
|
||||
protected String environmentName = "";
|
||||
// Session context.
|
||||
protected class SessionContextData_Web
|
||||
{
|
||||
public SessionContextData_Web(SaxSessionContext_Web sessionContext)
|
||||
{
|
||||
SessionContext = sessionContext;
|
||||
}
|
||||
public SaxSessionContext_Web SessionContext { get; }
|
||||
public Dictionary<Sax.Database, ISacsDatabase> Databases { get; } = new Dictionary<Sax.Database, ISacsDatabase>();
|
||||
public ISacsDatabase CoreDatabase { get { return Databases.GetValue(Sax.Database.Core, null); } }
|
||||
public ISacsDatabase ReferenceDatabase { get { return Databases.GetValue(Sax.Database.Reference, null); } }
|
||||
public ISacsDatabase SupportDatabase { get { return Databases.GetValue(Sax.Database.Support, null); } }
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Protected construction.
|
||||
protected SaxApplication_Web(Sax.Application applicationType)
|
||||
{
|
||||
WebApp = this;
|
||||
System_Web = new SaxSystem_Web();
|
||||
ApplicationType = applicationType;
|
||||
}
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
WebApp = null;
|
||||
System_Web = null;
|
||||
}
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Globals.
|
||||
public static SaxApplication_Web WebApp { get; private set; }
|
||||
public Sax.Application ApplicationType { get; }
|
||||
public override SaxSystem System { get { return System_Web; } }
|
||||
public SaxSystem_Web System_Web { get; private set; }
|
||||
// Application instance.
|
||||
public override Sax.InstanceType InstanceType { get { return instanceType; } }
|
||||
public override String EnvironmentName { get { return environmentName; } }
|
||||
public bool Development { get; protected set; }
|
||||
public String LoggingRootFolder { get; protected set; } = "";
|
||||
// Application components.
|
||||
public abstract String SessionCookieName { get; }
|
||||
public virtual SaxSessionContext SessionContext { get; protected set; }
|
||||
public abstract SaxAppConfig AppConfig { get; }
|
||||
public SaxConsoleHelper_Web ConsoleHelper_Web { get; protected set; }
|
||||
public override IDatabaseInfo CreateDbInfo(SaxSessionContext sessionContext, Sax.Database databaseType) { return new DbDataItem.DatabaseInfo(GetDatabase(sessionContext, databaseType)); }
|
||||
// Configuration.
|
||||
public IConfiguration Configuration { get; protected set; }
|
||||
public IConfiguration SaxConfiguration { get; private set; }
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
protected void InitEnvironment(IWebHostEnvironment env, String logFilenamePrefix)
|
||||
{
|
||||
Development = env.IsDevelopment();
|
||||
environmentName = env.EnvironmentName;
|
||||
SaxConfiguration = LoadApplicationConfiguration();
|
||||
|
||||
// Configure logging.
|
||||
SaLogger.LogFilenamePrefix = logFilenamePrefix;
|
||||
SaLogger.IncludeHostInFileMessage = false;
|
||||
SaLogger.IncludeUserInFileMessage = false;
|
||||
|
||||
//Messages.Add($"Host: {SaxSystem.ComputerName}");
|
||||
//Messages.Add($"Config file: appsettings.machine.{SaxSystem.ComputerName}.json");
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Application configuration.
|
||||
private IConfiguration LoadApplicationConfiguration()
|
||||
{
|
||||
// Load configuration resource files.
|
||||
// Later files override values from previous.
|
||||
var builder =
|
||||
new ConfigurationBuilder()
|
||||
.SetBasePath(Directory.GetCurrentDirectory())
|
||||
.AddEnvironmentVariables();
|
||||
|
||||
// Saxonite Web configuration - shared by all applications.
|
||||
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);
|
||||
|
||||
// Application specific configuration.
|
||||
builder
|
||||
.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);
|
||||
|
||||
return builder.Build();
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Database configuration.
|
||||
protected void ConfigureDatabaseConnection(SessionContextData_Web sessionContextData, Sax.Database databaseInstance)
|
||||
{
|
||||
// Configure database connection.
|
||||
SaxAppConfig.DatabaseConfig databaseConfig = AppConfig.Databases.Databases.GetValue(databaseInstance, new SaxAppConfig.DatabaseConfig());
|
||||
SacsDatabaseConsole.OdbcConfig config = new SacsDatabaseConsole.OdbcConfig();
|
||||
config.Location = databaseConfig.Location;
|
||||
config.User = databaseConfig.User;
|
||||
config.Password = databaseConfig.Password;
|
||||
SacsDatabase database = SacsDatabaseConsole.OpenOdbcDatabase(config);
|
||||
if (database.HasErrorState())
|
||||
SaLogger.Warn(SysUtil.Fn + " " + databaseInstance.ToString() + " Database initialisation error: " + database.ErrorStateMessage);
|
||||
sessionContextData.Databases.Add(databaseInstance, database);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Logging.
|
||||
protected void LogApplicationStart(String fn)
|
||||
{
|
||||
// Log application start.
|
||||
List<StringPair> applicationParams = new List<StringPair>();
|
||||
applicationParams.Add("Host", SaxSystem.ComputerName);
|
||||
applicationParams.Add("Version", Sax.Version.GetFullVersion());
|
||||
applicationParams.Add("Instance", InstanceType.ToString() + (!StringUtil.IsEmpty(AppConfig.Instance) ? " [" + AppConfig.Instance + "]" : ""));
|
||||
applicationParams.Add("Configuration", SaxSystem.DebugMode ? "Debug" : "Release");
|
||||
applicationParams.Add("Environment", EnvironmentName);
|
||||
if (!StringUtil.IsBlank(AppConfig.Databases.Core.Location))
|
||||
applicationParams.Add("Database - Core", AppConfig.Databases.Core.Location);
|
||||
if (!StringUtil.IsBlank(AppConfig.Databases.Reference.Location))
|
||||
applicationParams.Add("Database - Reference", AppConfig.Databases.Reference.Location);
|
||||
if (!StringUtil.IsBlank(AppConfig.Databases.Support.Location))
|
||||
applicationParams.Add("Database - Support", AppConfig.Databases.Support.Location);
|
||||
applicationParams.Add("Application root", SaxSystem.ApplicationFolder);
|
||||
if (!StringUtil.IsEmpty(AppConfig.Documents.RootFolder))
|
||||
applicationParams.Add("Documents root", AppConfig.Documents.RootFolder);
|
||||
applicationParams.Add("Email context", AppConfig.Email.Context + (!StringUtil.IsEmpty(EmailConfig.SMTP.Server) ? " [" + EmailConfig.SMTP.Server + "]" : ""));
|
||||
SaLogger.Info(fn + " Application start." + applicationParams.Select(item => StringUtil.PadRight(item.Item1 + ":", 23, ' ') + " " + item.Item2).Concat("", "\n\t"), true);
|
||||
if (StringUtil.IsEmpty(EmailConfig.SMTP.Server) || StringUtil.IsEmpty(EmailConfig.Message.AddressFrom))
|
||||
SaLogger.Warn(fn + " Incomplete email configuration.", true);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
protected void InitialiseTemporaryLoggingFolder()
|
||||
{
|
||||
// Default logging folder - in case of startup failure.
|
||||
try
|
||||
{
|
||||
foreach (String folder in new String[] { @"D:\Sarand\Projects\User\AHoward\VS2017\Saxonite\Logs" })
|
||||
{
|
||||
if (DirectoryUtil.DirectoryExists(folder))
|
||||
{
|
||||
SaLogger.LogFolder = folder;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception) { }
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
}
|
||||
//=======================================================================
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
using Saxonite.Net.Standard.Base.Consoles;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace Saxonite.Net.Core.Web.Base.App
|
||||
{
|
||||
//=======================================================================
|
||||
public static class SaxGlobals_Web
|
||||
{
|
||||
//-------------------------------------------------------------------
|
||||
// System.
|
||||
public static SaxSystem_Web System { get { return SaxGlobals_Web.System as SaxSystem_Web; } }
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Application.
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
}
|
||||
//=======================================================================
|
||||
}
|
||||
@@ -0,0 +1,368 @@
|
||||
using Microsoft.AspNetCore.Html;
|
||||
using Microsoft.AspNetCore.Mvc.Localization;
|
||||
using Microsoft.Extensions.Localization;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Sarand.Net.Standard.Base.App;
|
||||
using Sarand.Net.Standard.Base.Bus;
|
||||
using Sarand.Net.Standard.Base.Core;
|
||||
using Sarand.Net.Standard.Base.Utils;
|
||||
using Saxonite.Net.Standard.Base.App;
|
||||
using Saxonite.Net.Standard.Base.Bus;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Resources;
|
||||
using System.Web;
|
||||
|
||||
namespace Saxonite.Net.Core.Web.Base.App
|
||||
{
|
||||
//=======================================================================
|
||||
public abstract class SaxLocaliser
|
||||
{
|
||||
//-------------------------------------------------------------------
|
||||
// Data members.
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
/// <summary>
|
||||
/// Localisers are supplied by derived object.
|
||||
/// </summary>
|
||||
protected SaxLocaliser()
|
||||
{
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Properties.
|
||||
public abstract IStringLocalizer MainProperties { get; }
|
||||
public virtual List<IStringLocalizer> AlternativeProperties { get; } = new List<IStringLocalizer>();
|
||||
private HashSet<String> MissingKeysLogged { get; } = new HashSet<String>(StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Generic phrase translation.
|
||||
//-------------------------------------------------------------------
|
||||
/// <summary>Retrieve localised text.</summary>
|
||||
public LocalizedString GetText(string key)
|
||||
{
|
||||
return GetText(key, null);
|
||||
}
|
||||
/// <summary>Retrieve localised text.</summary>
|
||||
public LocalizedString GetText(string key, bool logMissingKey = true)
|
||||
{
|
||||
return GetText(key, null, logMissingKey);
|
||||
}
|
||||
/// <summary>Retrieve localised text.</summary>
|
||||
public LocalizedString GetText(string key, object param)
|
||||
{
|
||||
return GetText(key, new object[] { param });
|
||||
}
|
||||
/// <summary>Retrieve localised text.</summary>
|
||||
public LocalizedString GetText(string key, object param1, object param2)
|
||||
{
|
||||
return GetText(key, new object[] { param1, param2 });
|
||||
}
|
||||
/// <summary>Retrieve localised text.</summary>
|
||||
public LocalizedString GetText(string key, object[] parameters, bool logMissingKey = true)
|
||||
{
|
||||
LocalizedString text = parameters == null || parameters.IsEmpty() ? MainProperties.GetString(key) : MainProperties.GetString(key, parameters);
|
||||
if (text.ResourceNotFound)
|
||||
{
|
||||
// Look up key in alternative property files.
|
||||
foreach (IStringLocalizer properties in AlternativeProperties ?? new List<IStringLocalizer>())
|
||||
{
|
||||
text = parameters == null || parameters.IsEmpty() ? properties.GetString(key) : properties.GetString(key, parameters);
|
||||
if (!text.ResourceNotFound)
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (text.ResourceNotFound && logMissingKey && !MissingKeysLogged.Contains(key))
|
||||
{
|
||||
MissingKeysLogged.Add(key);
|
||||
SaLogger.Debug($"{SysUtil.Fn} Key not found: {key}");
|
||||
}
|
||||
return text;
|
||||
}
|
||||
|
||||
// Square bracket indexing.
|
||||
public LocalizedString this[String key]
|
||||
{
|
||||
get { return GetText(key); }
|
||||
}
|
||||
public LocalizedString this[String key, object param]
|
||||
{
|
||||
get { return GetText(key, param); }
|
||||
}
|
||||
public LocalizedString this[String key, object param1, object param2]
|
||||
{
|
||||
get { return GetText(key, param1, param2); }
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
/// <summary>
|
||||
/// Localised HTML text.
|
||||
/// <para>Line delimiters changed to '<br/>'.</para>
|
||||
/// </summary>
|
||||
public HtmlString GetHtmlText(string key, String param1 = "", String param2 = "")
|
||||
{
|
||||
return GetHtmlText(key, new Object[] { param1, param2 });
|
||||
}
|
||||
/// <summary>
|
||||
/// Localised HTML text.
|
||||
/// <para>Line delimiters changed to '<br/>'.</para>
|
||||
/// </summary>
|
||||
public HtmlString GetHtmlText(string key, object[] parameters)
|
||||
{
|
||||
LocalizedString localisedText = GetText(key, parameters);
|
||||
String value = localisedText.Value;
|
||||
// Replace all line delimiters.
|
||||
value = value.Replace("\r\n", "\n").Replace("\n", "<br/>").Replace("\r", "<br/>");
|
||||
return new HtmlString(value);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
/// <summary>
|
||||
/// Localised javascript string.
|
||||
/// <para>All quotes are escaped.</para>
|
||||
/// </summary>
|
||||
public LocalizedString GetJavascriptText(string key, String param1 = "", String param2 = "")
|
||||
{
|
||||
LocalizedString localisedText = GetText(key, param1, param2);
|
||||
return new LocalizedString(localisedText, EscapeJavascriptText(localisedText.Value), localisedText.ResourceNotFound);
|
||||
}
|
||||
public String EscapeJavascriptText(string value)
|
||||
{
|
||||
// Escape all quotes.
|
||||
value = value.Replace("'", "\\'").Replace("\"", "\\\"");
|
||||
return value;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Numeric and datetime formatting
|
||||
//-------------------------------------------------------------------
|
||||
public static String DateFormat_Default { get; } = "d-MMM-yyyy";
|
||||
public static String DateWithWeekdayFormat_Default { get; } = "ddd d-MMM-yyyy";
|
||||
public String FormatDate(DateTime? value, Boolean includeWeekday = true)
|
||||
{
|
||||
String dateFormat = includeWeekday ? DateWithWeekdayFormat_Default : DateFormat_Default;
|
||||
return DateUtil.Format(value, dateFormat);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Specific phrase translation.
|
||||
//-------------------------------------------------------------------
|
||||
private class CodesCache
|
||||
{
|
||||
private Dictionary<Sax.CodeType, List<TypeCodeDesc>> codeTypeCache { get; } = new Dictionary<Sax.CodeType, List<TypeCodeDesc>>();
|
||||
public List<TypeCodeDesc> GetCodesOfType(Sax.CodeType codeType)
|
||||
{
|
||||
List<TypeCodeDesc> codes = null;
|
||||
lock (codeTypeCache)
|
||||
{
|
||||
codes = codeTypeCache.GetValue(codeType, null);
|
||||
if (codes == null)
|
||||
{
|
||||
codes = SaxSystem.GetCodesOfType(codeType);
|
||||
codeTypeCache.Add(codeType, codes);
|
||||
}
|
||||
}
|
||||
return codes;
|
||||
}
|
||||
}
|
||||
private CodesCache codesCache = new CodesCache();
|
||||
|
||||
// Status.
|
||||
public String GetStatusCaption(SaStatus status)
|
||||
{
|
||||
// ToDo Status description localisation.
|
||||
return SacsSystem.GetStatusDesc(status);
|
||||
}
|
||||
|
||||
// Generic code type.
|
||||
private String GetCodeTypeCaption<T>(Sax.CodeType codeType, T type) where T : struct, IConvertible
|
||||
{
|
||||
if (!(type is Enum))
|
||||
throw new ArgumentException($"{SysUtil.Fn} Type parameter must be an enumerated type. Type supplied: {type.GetType().Name}");
|
||||
return GetCodeTypeCaption(codeType, (int)(type as IConvertible), type.ToString());
|
||||
}
|
||||
private String GetCodeTypeCaption(Sax.CodeType codeType, int type, String typeName)
|
||||
{
|
||||
if (type < 1) return "";
|
||||
List<TypeCodeDesc> codes = this.codesCache.GetCodesOfType(codeType);
|
||||
TypeCodeDesc code = codes.GetEntryForType(type);
|
||||
if (code != null)
|
||||
{
|
||||
// Code Type localisation.
|
||||
String codeTypeKey = "codeType." + codeType.ToString() + "." + typeName;
|
||||
String typeDesc = GetText(codeTypeKey, false);
|
||||
if (typeDesc.EqualsCI(codeTypeKey))
|
||||
typeDesc = "";
|
||||
return StringUtil.OnEmpty(typeDesc, code.Desc);
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
// Yes/No.
|
||||
public String GetYesNoCaption(Sax.YesNo yesNo)
|
||||
{
|
||||
return GetCodeTypeCaption(Sax.CodeType.YesNo, yesNo);
|
||||
}
|
||||
|
||||
// Data item type.
|
||||
public String GetItemDataTypeCaption(Sax.DataItemType itemType)
|
||||
{
|
||||
return GetCodeTypeCaption(Sax.CodeType.DataItemType, itemType);
|
||||
}
|
||||
|
||||
// Gender.
|
||||
public String GetGenderCaption(Sax.Gender gender)
|
||||
{
|
||||
return GetCodeTypeCaption(Sax.CodeType.Gender, gender);
|
||||
}
|
||||
|
||||
// Sport Grouping.
|
||||
public String GetSportGroupingCaption(Sax.SportGrouping sportGrouping)
|
||||
{
|
||||
return GetCodeTypeCaption(Sax.CodeType.SportGrouping, sportGrouping);
|
||||
}
|
||||
|
||||
// Sport Speciality label.
|
||||
public String GetSportSpecialityLabelCaption(Sax.SportSpecialityLabel sportSpecialityLabel)
|
||||
{
|
||||
return GetCodeTypeCaption(Sax.CodeType.SportSpecialityLabel, sportSpecialityLabel);
|
||||
}
|
||||
|
||||
// Sport Contact Type.
|
||||
public String GetSportContactTypeCaption(Sax.SportContactType sportContactType)
|
||||
{
|
||||
return GetCodeTypeCaption(Sax.CodeType.SportContactType, sportContactType);
|
||||
}
|
||||
|
||||
// Sport Participating.
|
||||
public String GetSportParticipatingCaption(Sax.SportParticipating participating)
|
||||
{
|
||||
return GetCodeTypeCaption(Sax.CodeType.SportParticipating, participating);
|
||||
}
|
||||
|
||||
// Sport Preparing.
|
||||
public String GetSportPreparingCaption(Sax.SportPreparing preparing)
|
||||
{
|
||||
return GetCodeTypeCaption(Sax.CodeType.SportPreparing, preparing);
|
||||
}
|
||||
|
||||
// Sport Officiating.
|
||||
public String GetSportOfficiatingCaption(Sax.SportOfficiating officiating)
|
||||
{
|
||||
return GetCodeTypeCaption(Sax.CodeType.SportOfficiating, officiating);
|
||||
}
|
||||
|
||||
// Region type.
|
||||
public String GetRegionTypeCaption(Sax.RegionType regionType)
|
||||
{
|
||||
return GetCodeTypeCaption(Sax.CodeType.RegionType, regionType);
|
||||
}
|
||||
|
||||
// Eligibility type.
|
||||
public String GetEligibilityTypeCaption(Sax.EligibilityType regionType)
|
||||
{
|
||||
return GetCodeTypeCaption(Sax.CodeType.EligibilityType, regionType);
|
||||
}
|
||||
|
||||
// User role.
|
||||
public String GetUserRoleCaption(Sax.UserRole userRole)
|
||||
{
|
||||
return GetCodeTypeCaption(Sax.CodeType.UserRole, userRole);
|
||||
}
|
||||
|
||||
// Organisation type.
|
||||
public String GetOrganisationTypeCaption(Sax.OrganisationType organisationType)
|
||||
{
|
||||
return GetCodeTypeCaption(Sax.CodeType.OrganisationType, organisationType);
|
||||
}
|
||||
|
||||
// Organisation category.
|
||||
public String GetOrganisationCategoryCaption(Sax.OrganisationCategory organisationCategory)
|
||||
{
|
||||
return GetCodeTypeCaption(Sax.CodeType.OrganisationCategory, organisationCategory);
|
||||
}
|
||||
|
||||
// Organisation role.
|
||||
public String GetOrganisationRoleCaption(Sax.OrganisationRole organisationRole)
|
||||
{
|
||||
return GetCodeTypeCaption(Sax.CodeType.OrganisationRole, organisationRole);
|
||||
}
|
||||
|
||||
// Association types.
|
||||
public String GetAssociationTypeCaption(Sax.AssociationType addressType)
|
||||
{
|
||||
return GetCodeTypeCaption(Sax.CodeType.AssociationType, addressType);
|
||||
}
|
||||
|
||||
// Address types.
|
||||
public String GetAddressTypeCaption(Sax.AddressType addressType)
|
||||
{
|
||||
return GetCodeTypeCaption(Sax.CodeType.AddressType, addressType);
|
||||
}
|
||||
|
||||
// Contact Method.
|
||||
public String GetContactMethodCaption(Sax.ContactMethod contactMethod)
|
||||
{
|
||||
return GetCodeTypeCaption(Sax.CodeType.ContactMethod, contactMethod);
|
||||
}
|
||||
|
||||
// Event type.
|
||||
public String GetEventTypeCaption(Sax.EventType eventType)
|
||||
{
|
||||
return GetCodeTypeCaption(Sax.CodeType.EventType, eventType);
|
||||
}
|
||||
|
||||
// Opportunity type.
|
||||
public String GetOpportunityTypeCaption(Sax.OpportunityType opportunityType)
|
||||
{
|
||||
return GetCodeTypeCaption(Sax.CodeType.OpportunityType, opportunityType);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Support.
|
||||
|
||||
// User Report Type.
|
||||
public String GetUserReportTypeCaption(Sax.UserReportType reportType)
|
||||
{
|
||||
return GetCodeTypeCaption(Sax.CodeType.UserReportType, reportType);
|
||||
}
|
||||
|
||||
// Support Item Process Type.
|
||||
public String GetSupportItemProcessTypeCaption(Sax.SupportItemProcessType processType)
|
||||
{
|
||||
return GetCodeTypeCaption(Sax.CodeType.SupportItemProcessType, processType);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Region.
|
||||
public String GetRegionName(SaxRegion.Data region)
|
||||
{
|
||||
if (region == null) return "";
|
||||
// ToDo Region name localisation.
|
||||
return region.Name;
|
||||
}
|
||||
public String GetRegionName(SysId regionId, String regionName)
|
||||
{
|
||||
// ToDo Region name localisation.
|
||||
return regionName;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Sport.
|
||||
public String GetSportName(SaxSport.Data sport)
|
||||
{
|
||||
if (sport == null) return "";
|
||||
// ToDo Sport name localisation.
|
||||
return sport.Name;
|
||||
}
|
||||
public String GetSportName(SysId sportId, String sportName)
|
||||
{
|
||||
// ToDo Sport name localisation.
|
||||
return sportName;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
}
|
||||
//=======================================================================
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
using Saxonite.Net.Standard.Base.App;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Saxonite.Net.Core.Web.Base.App
|
||||
{
|
||||
//=======================================================================
|
||||
public class SaxSessionContext_Web : SaxSessionContext
|
||||
{
|
||||
//-------------------------------------------------------------------
|
||||
/// <summary>Blank construction - used for deserilisation of session data.</summary>
|
||||
protected SaxSessionContext_Web () : base() { }
|
||||
public SaxSessionContext_Web (ushort sesionContextIndex, Sax.Application application) :
|
||||
base(sesionContextIndex, application)
|
||||
{
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
}
|
||||
//=======================================================================
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
using Saxonite.Net.Standard.Base.App;
|
||||
using Saxonite.Net.Standard.Base.Bus;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace Saxonite.Net.Core.Web.Base.App
|
||||
{
|
||||
//=======================================================================
|
||||
public abstract class SaxSessionData_Web : SaxSessionData
|
||||
{
|
||||
//-------------------------------------------------------------------
|
||||
// Private construction - for JSON deserialisation.
|
||||
protected SaxSessionData_Web(long sessionIdx, int itemIdx, SaxSessionContext sessionContext) :
|
||||
base(sessionIdx, itemIdx, sessionContext)
|
||||
{
|
||||
}
|
||||
// Protected construction.
|
||||
protected SaxSessionData_Web(SaxSessionContext sessionContext, SaxUserAccount userAccount, List<SaxUserRole> userRoles) :
|
||||
base(sessionContext, userAccount, userRoles)
|
||||
{
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
}
|
||||
//=======================================================================
|
||||
}
|
||||
@@ -0,0 +1,219 @@
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Localization;
|
||||
using Microsoft.AspNetCore.Mvc.Razor;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Microsoft.Net.Http.Headers;
|
||||
using Sarand.Net.Standard.Base.App;
|
||||
using Sarand.Net.Standard.Base.Core;
|
||||
using Saxonite.Net.Core.Web.Base.Middleware;
|
||||
using Saxonite.Net.Standard.Base.App;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Net.Http;
|
||||
using System.Text;
|
||||
|
||||
namespace Saxonite.Net.Core.Web.Base.App
|
||||
{
|
||||
//=======================================================================
|
||||
public class SaxStartup
|
||||
{
|
||||
//-------------------------------------------------------------------
|
||||
// Data members.
|
||||
// Localisation.
|
||||
private static RequestCulture defaultRequestCulture = new RequestCulture("en-GB", "en-GB");
|
||||
private static List<CultureInfo> supportedCultures = new List<CultureInfo>
|
||||
{
|
||||
new CultureInfo("en-GB"),
|
||||
new CultureInfo("en-US"),
|
||||
new CultureInfo("en"),
|
||||
new CultureInfo("fr-FR"),
|
||||
new CultureInfo("fr"),
|
||||
};
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Protected construction.
|
||||
protected SaxStartup(IConfiguration configuration)
|
||||
{
|
||||
Configuration = configuration;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Properties.
|
||||
public IConfiguration Configuration { get; }
|
||||
public static RequestCulture DefaultRequestCulture { get { return defaultRequestCulture; } }
|
||||
public static List<CultureInfo> SupportedCultures { get { return new List<CultureInfo>(supportedCultures); } }
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// This method gets called by the runtime. Use this method to add services to the container.
|
||||
protected class ConfigureServicesConfig
|
||||
{
|
||||
public IServiceCollection services;
|
||||
public String sessionCookieName;
|
||||
public bool sessionCookieHttpOnly;
|
||||
public TimeSpan sessionIdleTimeout;
|
||||
}
|
||||
protected void ConfigureServices(ConfigureServicesConfig config)
|
||||
{
|
||||
// Authentication service.
|
||||
// Required to handle 'Forbidden' responses etc.
|
||||
config.services
|
||||
.AddAuthentication(options =>
|
||||
{
|
||||
options.DefaultAuthenticateScheme = "forbidScheme";
|
||||
options.DefaultForbidScheme = "forbidScheme";
|
||||
options.AddScheme<SaxAuthenticationHandler>("forbidScheme", "Handle Forbidden");
|
||||
});
|
||||
|
||||
// Added to support memory caching of sessions.
|
||||
config.services.AddMemoryCache();
|
||||
//config.services.AddDistributedMemoryCache(); - for multiple web servers.
|
||||
// Online web application cookie definition.
|
||||
config.services.AddSession
|
||||
(options =>
|
||||
{
|
||||
options.Cookie.Name = config.sessionCookieName;
|
||||
options.Cookie.HttpOnly = config.sessionCookieHttpOnly;
|
||||
options.IdleTimeout = config.sessionIdleTimeout;
|
||||
// Override cookie policy for session cookie. Ref. config.app.UseCookiePolicy()
|
||||
options.Cookie.IsEssential = true;
|
||||
}
|
||||
);
|
||||
|
||||
// Localisation properties folder.
|
||||
String resourcesPath = "Localisation";
|
||||
config.services.AddLocalization(opts => { opts.ResourcesPath = resourcesPath; });
|
||||
|
||||
// Modify pages during debug.
|
||||
#if DEBUG
|
||||
if (SaxSystem.DebugMode)
|
||||
{
|
||||
// If the following line throws an error such as:
|
||||
// 'imvcbuilder' does not contain a definition for 'addrazorruntimecompilation'
|
||||
// Revert the NuGet Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation package
|
||||
// to a previous version and then reinstal the latest version.
|
||||
config.services.AddRazorPages().AddRazorRuntimeCompilation();
|
||||
//config.services.AddControllersWithViews().AddRazorRuntimeCompilation();
|
||||
}
|
||||
#endif
|
||||
|
||||
config.services.AddMvc
|
||||
(options =>
|
||||
{
|
||||
// Model binding - intercepting form values being bound to models.
|
||||
options.ModelBinderProviders.Insert(0, new SaxModelBinderProvider());
|
||||
// Blank form values to be populated to model as empty strings rather than null values.
|
||||
options.ModelMetadataDetailsProviders.Add(new SaxMetadataProvider());
|
||||
}
|
||||
)
|
||||
// View and data annotation localisations.
|
||||
.AddViewLocalization(
|
||||
LanguageViewLocationExpanderFormat.Suffix,
|
||||
opts => { opts.ResourcesPath = resourcesPath; })
|
||||
.AddDataAnnotationsLocalization()
|
||||
// Ignore null values during object serialiation.
|
||||
.AddJsonOptions(options => { options.JsonSerializerOptions.DefaultIgnoreCondition = System.Text.Json.Serialization.JsonIgnoreCondition.WhenWritingNull; });
|
||||
|
||||
// Configure localisation middleware.
|
||||
config.services.Configure<RequestLocalizationOptions>
|
||||
(opts =>
|
||||
{
|
||||
// Default culture to use for requests.
|
||||
opts.DefaultRequestCulture = DefaultRequestCulture;
|
||||
// Cultures supported by the application. Formatting numbers, dates, etc.
|
||||
opts.SupportedCultures = SupportedCultures;
|
||||
// UI cultures supported by the application. UI strings that have been localized.
|
||||
opts.SupportedUICultures = SupportedCultures;
|
||||
}
|
||||
);
|
||||
|
||||
// Allows access to the HttpContext inside a service.
|
||||
config.services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
|
||||
protected class ConfigureConfig
|
||||
{
|
||||
public IApplicationBuilder app;
|
||||
public IHostApplicationLifetime hostApplicationLifetime;
|
||||
public IWebHostEnvironment env;
|
||||
}
|
||||
protected void Configure(ConfigureConfig config)
|
||||
{
|
||||
if (config.env.IsDevelopment())
|
||||
{
|
||||
config.app.UseDeveloperExceptionPage();
|
||||
}
|
||||
else
|
||||
{
|
||||
config.app.UseExceptionHandler("/Home/Error");
|
||||
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
|
||||
config.app.UseHsts();
|
||||
}
|
||||
|
||||
config.app.UseHttpsRedirection();
|
||||
config.app.UseStaticFiles();
|
||||
config.app.UseCookiePolicy();
|
||||
config.app.UseSession();
|
||||
config.app.UseRouting();
|
||||
//config.app.UseAuthorization();
|
||||
config.app.UseAntiforgeryTokens();
|
||||
|
||||
// Localisation.
|
||||
IOptions<RequestLocalizationOptions> localizationOptions = config.app.ApplicationServices.GetService<IOptions<RequestLocalizationOptions>>();
|
||||
config.app.UseRequestLocalization(localizationOptions.Value);
|
||||
|
||||
config.app.UseEndpoints(endpoints =>
|
||||
{
|
||||
endpoints.MapControllerRoute(
|
||||
name: "default",
|
||||
pattern: "{controller=Home}/{action=Index}/{id?}");
|
||||
});
|
||||
|
||||
// Application events.
|
||||
// NB The shutdown events only fire if he application stops 'gracefully'.
|
||||
config.hostApplicationLifetime.ApplicationStarted.Register(OnApplicationStarted);
|
||||
config.hostApplicationLifetime.ApplicationStopping.Register(OnApplicationStopping);
|
||||
config.hostApplicationLifetime.ApplicationStopped.Register(OnApplicationStopped);
|
||||
|
||||
config.app.Use(async (context, next) =>
|
||||
{
|
||||
if (context.Request.Method.Equals(HttpMethod.Get.Method))
|
||||
{
|
||||
context.Response.GetTypedHeaders().CacheControl = new CacheControlHeaderValue()
|
||||
{
|
||||
Public = true,
|
||||
MaxAge = TimeSpan.FromSeconds(10)
|
||||
};
|
||||
//context.Response.Headers[HeaderNames.Vary] = new string[] { "Accept-Encoding" };
|
||||
}
|
||||
await next();
|
||||
});
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Application events.
|
||||
private readonly static String ApplicationEventLogPrefix = "### ";
|
||||
private void OnApplicationStarted()
|
||||
{
|
||||
SaLogger.Info(ApplicationEventLogPrefix + "Application started");
|
||||
}
|
||||
private void OnApplicationStopping()
|
||||
{
|
||||
SaLogger.Info(ApplicationEventLogPrefix + "Application stopping");
|
||||
}
|
||||
private void OnApplicationStopped()
|
||||
{
|
||||
SaLogger.Info(ApplicationEventLogPrefix + "Application stopped");
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
}
|
||||
//=======================================================================
|
||||
}
|
||||
@@ -0,0 +1,135 @@
|
||||
using Sarand.Net.Standard.Base.Core;
|
||||
using Saxonite.Net.Standard.Dbas.App;
|
||||
using Saxonite.Net.Standard.Base.App;
|
||||
using Saxonite.Net.Standard.Base.Mgr;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using Sarand.Net.Standard.Base.App;
|
||||
using Sarand.Net.Standard.Base.Utils;
|
||||
|
||||
namespace Saxonite.Net.Core.Web.Base.App
|
||||
{
|
||||
//=======================================================================
|
||||
public class SaxSystem_Web : SaxSystem_Dbas
|
||||
{
|
||||
//-------------------------------------------------------------------
|
||||
// Data members.
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
/// <summary>Static initialisation.</summary>
|
||||
static SaxSystem_Web()
|
||||
{
|
||||
InitComputerName();
|
||||
InitUserName();
|
||||
InitApplicationPath();
|
||||
InitApplicationFolder();
|
||||
InitAssemblyBuildAt();
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Construction.
|
||||
public SaxSystem_Web() : base()
|
||||
{
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
/// <summary>
|
||||
/// Computer name
|
||||
/// <para>Windows: System.Environment.MachineName</para>
|
||||
/// <para>Web: HttpContext.Current.Server.MachineName</para>
|
||||
/// <para>FQDN: System.Net.Dns.GetHostName()</para>
|
||||
/// </summary>
|
||||
public static void InitComputerName()
|
||||
{
|
||||
try
|
||||
{
|
||||
ComputerName = System.Environment.MachineName;
|
||||
}
|
||||
catch (Exception exc)
|
||||
{
|
||||
SaLogger.Warn("SaxSystem.InitComputerName Failed to initialise computer name from environment. " + ExceptionUtil.GetErrorStateMessage(exc));
|
||||
}
|
||||
try
|
||||
{
|
||||
if (StringUtil.IsEmpty(ComputerName))
|
||||
ComputerName = Environment.GetEnvironmentVariable("COMPUTERNAME") ?? Environment.GetEnvironmentVariable("HOSTNAME");
|
||||
}
|
||||
catch (Exception exc)
|
||||
{
|
||||
SaLogger.Warn("SaxSystem.InitComputerName Failed to initialise computer name from environment variable. " + ExceptionUtil.GetErrorStateMessage(exc));
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
/// <summary>To be populated by application<para>Windows: Environment.UserName</para></summary>
|
||||
private static void InitUserName()
|
||||
{
|
||||
try
|
||||
{
|
||||
UserName = Environment.UserName;
|
||||
}
|
||||
catch (Exception exc)
|
||||
{
|
||||
SaLogger.Warn("SaxSystem.InitUserName Failed to initialise user name. " + ExceptionUtil.GetErrorStateMessage(exc));
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
/// <summary>
|
||||
/// Application Path.
|
||||
/// <para>Windows: System.Reflection.Assembly.GetEntryAssembly().Location;</para>
|
||||
/// </summary>
|
||||
private static void InitApplicationPath()
|
||||
{
|
||||
try
|
||||
{
|
||||
ApplicationPath = Assembly.GetEntryAssembly().Location;
|
||||
}
|
||||
catch (Exception exc)
|
||||
{
|
||||
SaLogger.Warn("SaxSystem.InitApplicationPath Failed to initialise application path. " + ExceptionUtil.GetErrorStateMessage(exc));
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
/// <summary>
|
||||
/// Application folder.
|
||||
/// <para>Windows: System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetEntryAssembly().Location);</para>
|
||||
/// </summary>
|
||||
private static void InitApplicationFolder()
|
||||
{
|
||||
try
|
||||
{
|
||||
ApplicationFolder = Path.GetDirectoryName(Assembly.GetEntryAssembly().Location);
|
||||
}
|
||||
catch (Exception exc)
|
||||
{
|
||||
SaLogger.Warn("SaxSystem.InitApplicationFolder Failed to initialise application folder. " + ExceptionUtil.GetErrorStateMessage(exc));
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
/// <summary>
|
||||
/// DateTime when the executing assembly was built.
|
||||
/// </summary>
|
||||
private static void InitAssemblyBuildAt()
|
||||
{
|
||||
try
|
||||
{
|
||||
// Assembly build date.
|
||||
Assembly assembly = Assembly.GetExecutingAssembly();
|
||||
AssemblyBuildAt = File.GetLastWriteTime(assembly.Location);
|
||||
}
|
||||
catch (Exception exc)
|
||||
{
|
||||
SaLogger.Warn("SaxSystem.InitAssemblyBuildAt Failed to initialise assembly build date. " + ExceptionUtil.GetErrorStateMessage(exc));
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
}
|
||||
//=======================================================================
|
||||
}
|
||||
@@ -0,0 +1,607 @@
|
||||
using Sarand.Net.Standard.Base.App;
|
||||
using Sarand.Net.Standard.Base.Bus;
|
||||
using Sarand.Net.Standard.Base.Core;
|
||||
using Sarand.Net.Standard.Base.Dbas;
|
||||
using Sarand.Net.Standard.Base.Utils;
|
||||
using Sarand.Net.Standard.Dbas.Data;
|
||||
using Saxonite.Base.App;
|
||||
using Saxonite.Net.Standard.Base.App;
|
||||
using Saxonite.Net.Standard.Base.Bus;
|
||||
using Saxonite.Net.Standard.Base.Consoles;
|
||||
using Saxonite.Net.Standard.Dbas.Mgr;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Saxonite.Net.Core.Web.Base.Consoles
|
||||
{
|
||||
//=======================================================================
|
||||
public abstract class SaxActivityConsole_Web : SaxActivityConsole
|
||||
{
|
||||
//-------------------------------------------------------------------
|
||||
// Data members.
|
||||
private readonly String alias_ActivityIndex = SaxActivityMgr_Dbas.aliasActivityIndex;
|
||||
private readonly String alias_ActivityIndex_UserActivity = SaxActivityMgr_Dbas.aliasActivityIndex_UserActivity;
|
||||
protected class IndexStatsData
|
||||
{
|
||||
public int EntriesInserted { get; set; }
|
||||
public int EntriesUpdated { get; set; }
|
||||
public int EntriesDeleted { get; set; }
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Protected construction.
|
||||
protected SaxActivityConsole_Web(SaxSessionContext sessionContext) :
|
||||
base(sessionContext)
|
||||
{
|
||||
}
|
||||
//-------------------------------------------------------------------
|
||||
// Query Activity Index Entries for User Context.
|
||||
//-------------------------------------------------------------------
|
||||
private class ActivityData_Web : IndexResults.ActivityData
|
||||
{
|
||||
public ActivityData_Web(ItemId itemId, DateTime effectiveOn) : base(itemId, effectiveOn) { }
|
||||
public void SetOrganisation(SysId organisationId, String organisation, bool hasLogo) { OrganisationId = organisationId; Organisation = organisation; OrganisationHasLogo = hasLogo; }
|
||||
public void SetAuthor(SysId userAccountId, String author) { UserAccountIdAuthor = userAccountId; Author = author; }
|
||||
public void SetDetails(String caption, String blurb) { Caption = caption; Blurb = blurb; }
|
||||
public void SetSport(SysId sportId, String sportName) { SportId = sportId; SportName = sportName; }
|
||||
public void SetRegion(SysId regionId, String regionName) { RegionId = regionId; RegionName = regionName; }
|
||||
// User Activity.
|
||||
public void SetLastListedAt(DateTime lastListedAt) { LastListedAt = lastListedAt; }
|
||||
public void SetLastViewedAt(DateTime lastViewedAt) { LastViewedAt = lastViewedAt; }
|
||||
public void SetReaction(Sax.ActivityReaction reaction) { Reaction = reaction; }
|
||||
public void SetLastReactedAt(DateTime lastReactedAt) { LastReactedAt = lastReactedAt; }
|
||||
public static int CompareActivityIndices(ActivityData_Web item1, ActivityData_Web item2)
|
||||
{
|
||||
int effectiveCompare = item1.EffectiveOn.CompareTo(item2.EffectiveOn);
|
||||
if (effectiveCompare != 0) return effectiveCompare * -1;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
public override IndexResults QueryIndex(IndexContext context)
|
||||
{
|
||||
String fn = GetType().Name + ".QueryIndex";
|
||||
ClearErrorState();
|
||||
IndexResults results = new IndexResults();
|
||||
if (!context.IsValid()) return results;
|
||||
|
||||
// Columns to query.
|
||||
ColumnDfn colItemType = Internals.ActivityMgr.GetActivityIndexColumnDfn(SaxActivityIndex.Column.ItemType);
|
||||
ColumnDfn colItemId = Internals.ActivityMgr.GetActivityIndexColumnDfn(SaxActivityIndex.Column.ItemId);
|
||||
// NB Would like to include the Organisation namd and logo count but this involves joing to Organisation and item image
|
||||
// which will make the following query significantly more complex.
|
||||
ColumnDfn colOrganisationId = Internals.ActivityMgr.GetActivityIndexColumnDfn(SaxActivityIndex.Column.OrganisationIdOwner);
|
||||
ColumnDfn colOrganisationName = Internals.ActivityMgr.GetActivityIndexColumnDfn(SaxActivityIndex.Column.OrganisationOwner_Name);
|
||||
ColumnDfn colOrganisationLogoCount = Internals.ActivityMgr.GetActivityIndexColumnDfn(SaxActivityIndex.Column.OrganisationOwner_LogoCount);
|
||||
String colDataNameEffectiveOn = "EffectiveOn";
|
||||
|
||||
// Query the Activity Index.
|
||||
// NB An item may have multiple index entries but these wil only differe by Sport and/or Region.
|
||||
// User, Organisation Effective & Expiry dates wil be the same for all entries for an item.
|
||||
ISacsDatabase db = SaxGlobals.App.GetDatabase(SessionContext, Sax.Database.Core);
|
||||
DbQuery query = new DbQuery(db.DbmsType);
|
||||
query.Tables.Add(SaxDbDfn_Core.GetTableName(SaxDbDfn_Core.TableIdx.ActivityIndex, false), alias_ActivityIndex);
|
||||
query.Columns.Add(SaxDbDfn_Core.GetColumnNameQual(SaxDbDfn_Core.ColumnIdx.ActivityIndex_ItemType, alias_ActivityIndex), colItemType.DataName);
|
||||
query.Columns.Add(SaxDbDfn_Core.GetColumnNameQual(SaxDbDfn_Core.ColumnIdx.ActivityIndex_ItemId, alias_ActivityIndex), colItemId.DataName);
|
||||
query.Columns.Add("Max(" + SaxDbDfn_Core.GetColumnNameQual(SaxDbDfn_Core.ColumnIdx.ActivityIndex_EffectiveOn, alias_ActivityIndex) + ")", colDataNameEffectiveOn);
|
||||
query.GroupBy.Add(SaxDbDfn_Core.GetColumnNameQual(SaxDbDfn_Core.ColumnIdx.ActivityIndex_ItemType, alias_ActivityIndex));
|
||||
query.GroupBy.Add(SaxDbDfn_Core.GetColumnNameQual(SaxDbDfn_Core.ColumnIdx.ActivityIndex_ItemId, alias_ActivityIndex));
|
||||
query.OrderBy.Add("Max(" + SaxDbDfn_Core.GetColumnNameQual(SaxDbDfn_Core.ColumnIdx.ActivityIndex_EffectiveOn, alias_ActivityIndex) + ") DESC");
|
||||
|
||||
// Filter.
|
||||
SaxActivityIndex.Params prmActivityIndex = new SaxActivityIndex.Params();
|
||||
prmActivityIndex.UserAccountIdsOwnerIncluded.AddRange(context.UserAccountIdsOwner);
|
||||
prmActivityIndex.OrganisationIdsOwnerIncluded.AddRange(context.OrganisationIdsOwner);
|
||||
prmActivityIndex.SportRegionIdsIncluded.AddRange(context.SportRegionIdsIncluded);
|
||||
prmActivityIndex.EffectiveFrom = context.EffectiveFrom;
|
||||
prmActivityIndex.EffectiveTo = context.EffectiveTo;
|
||||
prmActivityIndex.NotExpiredOn = context.NotExpiredOn;
|
||||
prmActivityIndex.Alias_ActivityIndex = alias_ActivityIndex;
|
||||
prmActivityIndex.ResultsPaging.PageNo = 1;
|
||||
prmActivityIndex.ResultsPaging.PageLength = 100;
|
||||
query.Filters.AddRange(Internals.ActivityMgr.GetActivityIndexQueryFilter(prmActivityIndex));
|
||||
|
||||
// First pass, note the activity Item and effective date.
|
||||
List<ActivityData_Web> activityDataList = new List<ActivityData_Web>();
|
||||
using (DbResultSet dbResultSet = DbResultSet_DataReader.ExecuteQuery(db, query.BuildQuery(context.Paging)))
|
||||
{
|
||||
while (dbResultSet != null && dbResultSet.NextRecord())
|
||||
{
|
||||
NamedValue.Map values = dbResultSet.GetRecordValues();
|
||||
Sax.DataItemType itemType = (Sax.DataItemType)values.GetLong(colItemType.DataName);
|
||||
ItemId itemId = new ItemId((short)itemType, new SysId(values.GetLong(colItemId.DataName)));
|
||||
DateTime effectiveOn = values.GetDate(colDataNameEffectiveOn);
|
||||
ActivityData_Web activityData = new ActivityData_Web(itemId, effectiveOn);
|
||||
activityDataList.Add(activityData);
|
||||
SaLogger.Info(fn + " Activity found - " + itemType.ToString() + ":" + SysId.ToString(itemId.Id) + ". Effective: " + DateUtil.Format(effectiveOn, "d-MMM-yyyy"));
|
||||
}
|
||||
}
|
||||
|
||||
// Sort the activity list.
|
||||
activityDataList.Sort(ActivityData_Web.CompareActivityIndices);
|
||||
|
||||
// Populate activity details.
|
||||
PopulateActivityDetails(context, activityDataList);
|
||||
|
||||
// ToDo Remove activities with blank caption.
|
||||
|
||||
results.Items.AddRange(activityDataList);
|
||||
return results;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Populate Activity Details.
|
||||
//-------------------------------------------------------------------
|
||||
private void PopulateActivityDetails(IndexContext context, List<ActivityData_Web> activities)
|
||||
{
|
||||
PopulateUserActivityDetails(context, activities);
|
||||
PopulateArticleDetails(context, activities);
|
||||
PopulateOrganisationEventDetails(context, activities);
|
||||
PopulateOrganisationOpportunityDetails(context, activities);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
private void PopulateUserActivityDetails(IndexContext context, List<ActivityData_Web> activities)
|
||||
{
|
||||
// Validate parameters.
|
||||
if (!SysId.IsValid(context.UserAccountId)) return;
|
||||
|
||||
// Extract article Ids.
|
||||
List<ItemId> activityItemIds = activities.Select(item => new ItemId(item.ItemId.Type, item.ItemId.Id)).ToList();
|
||||
if (activityItemIds.IsEmpty()) return;
|
||||
|
||||
// User Activity columns - limit to essential information.
|
||||
ColumnDfn colItemType = Internals.ActivityMgr.GetUserActivityColumnDfn(SaxUserActivity.Column.ItemType);
|
||||
ColumnDfn colItemId = Internals.ActivityMgr.GetUserActivityColumnDfn(SaxUserActivity.Column.ItemId);
|
||||
ColumnDfn colUserAccountId = Internals.ActivityMgr.GetUserActivityColumnDfn(SaxUserActivity.Column.UserAccountId);
|
||||
ColumnDfn colLastListedAt = Internals.ActivityMgr.GetUserActivityColumnDfn(SaxUserActivity.Column.LastListedAt);
|
||||
ColumnDfn colLastViewedAt = Internals.ActivityMgr.GetUserActivityColumnDfn(SaxUserActivity.Column.LastViewedAt);
|
||||
ColumnDfn colReaction = Internals.ActivityMgr.GetUserActivityColumnDfn(SaxUserActivity.Column.Reaction);
|
||||
ColumnDfn colLastReactedAt = Internals.ActivityMgr.GetUserActivityColumnDfn(SaxUserActivity.Column.LastReactedAt);
|
||||
List<ColumnDfn> columns = new List<ColumnDfn>() { colItemType, colItemId, colUserAccountId, colLastListedAt, colLastViewedAt, colReaction, colLastReactedAt };
|
||||
|
||||
// User Activity filter.
|
||||
SaxUserActivity.Params prmUserActivity = new SaxUserActivity.Params();
|
||||
prmUserActivity.UserAccountIdsIncluded.Add(context.UserAccountId);
|
||||
prmUserActivity.ItemIdsIncluded.AddRange(activityItemIds);
|
||||
prmUserActivity.StatusCat = SaxUserActivity.StatusCat.ActiveOnly;
|
||||
|
||||
using (DbResultSet dbResultSet = Internals.ActivityMgr.ExecuteUserActivityQuery(columns, prmUserActivity))
|
||||
{
|
||||
while (dbResultSet != null && dbResultSet.NextRecord())
|
||||
{
|
||||
NamedValue.Map values = dbResultSet.GetRecordValues();
|
||||
ItemId activityItemId = new ItemId((short)values.GetLong(colItemType.DataName), new SysId(values.GetLong(colItemId.DataName)));
|
||||
DateTime lastListedAt = values.GetDateTime(colLastListedAt.DataName);
|
||||
DateTime lastViewedAt = values.GetDateTime(colLastViewedAt.DataName);
|
||||
Sax.ActivityReaction reaction = (Sax.ActivityReaction)values.GetLong(colReaction.DataName);
|
||||
DateTime lastReactedAt = values.GetDateTime(colLastReactedAt.DataName);
|
||||
|
||||
// Populate to corresponding activities.
|
||||
foreach (ActivityData_Web activity in activities.FindAll(item => item.ItemId.Equals(activityItemId)))
|
||||
{
|
||||
activity.SetLastListedAt(lastListedAt);
|
||||
activity.SetLastViewedAt(lastViewedAt);
|
||||
activity.SetReaction(reaction);
|
||||
activity.SetLastReactedAt(lastReactedAt);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Article details.
|
||||
private void PopulateArticleDetails(IndexContext context, List<ActivityData_Web> activities)
|
||||
{
|
||||
// Extract article Ids.
|
||||
List<SysId> articleIds = activities.FindAll(item => item.ItemId.Type == (int)Sax.DataItemType.Article).Select(ItemId => ItemId.ItemId.Id).ToList();
|
||||
if (articleIds.IsEmpty()) return;
|
||||
|
||||
// Article columns - limit to essential information.
|
||||
ColumnDfn colId = Internals.ActivityMgr.GetArticleColumnDfn(SaxArticle.Column.Id);
|
||||
ColumnDfn colOrganisationId = Internals.ActivityMgr.GetArticleColumnDfn(SaxArticle.Column.OrganisationId);
|
||||
ColumnDfn colOrganisation = Internals.ActivityMgr.GetArticleColumnDfn(SaxArticle.Column.Organisation_Name);
|
||||
ColumnDfn colOrganisationLogoCount = Internals.ActivityMgr.GetArticleColumnDfn(SaxArticle.Column.Organisation_LogoCount);
|
||||
ColumnDfn colAuthorId = Internals.ActivityMgr.GetArticleColumnDfn(SaxArticle.Column.UserAccountIdAuthor);
|
||||
ColumnDfn colAuthor = Internals.ActivityMgr.GetArticleColumnDfn(SaxArticle.Column.Author_DisplayName);
|
||||
ColumnDfn colHeadline = Internals.ActivityMgr.GetArticleColumnDfn(SaxArticle.Column.Headline);
|
||||
ColumnDfn colSummary = Internals.ActivityMgr.GetArticleColumnDfn(SaxArticle.Column.Summary);
|
||||
ColumnDfn colItemImageIdThumbnail = Internals.ActivityMgr.GetArticleColumnDfn(SaxArticle.Column.ItemImageIdThumbnail);
|
||||
ColumnDfn colSportId = Internals.ActivityMgr.GetArticleColumnDfn(SaxArticle.Column.SportIdPrimary);
|
||||
ColumnDfn colSportName = Internals.ActivityMgr.GetArticleColumnDfn(SaxArticle.Column.Sport_Name);
|
||||
ColumnDfn colRegionId = Internals.ActivityMgr.GetArticleColumnDfn(SaxArticle.Column.RegionIdPrimary);
|
||||
ColumnDfn colRegionName = Internals.ActivityMgr.GetArticleColumnDfn(SaxArticle.Column.Region_Name);
|
||||
List<ColumnDfn> columns = new List<ColumnDfn>()
|
||||
{
|
||||
colId, colOrganisationId, colOrganisation, colOrganisationLogoCount, colAuthor, colAuthorId,
|
||||
colHeadline, colSummary, colItemImageIdThumbnail, colSportId, colSportName, colRegionId, colRegionName
|
||||
};
|
||||
|
||||
// Article filter.
|
||||
SaxArticle.Params prmArticle = new SaxArticle.Params();
|
||||
prmArticle.IdsIncluded.AddRange(articleIds);
|
||||
prmArticle.StatusCat = SaxArticle.StatusCat.ActiveOnly;
|
||||
|
||||
using (DbResultSet dbResultSet = Internals.ActivityMgr.ExecuteArticleQuery(columns, prmArticle))
|
||||
{
|
||||
while (dbResultSet != null && dbResultSet.NextRecord())
|
||||
{
|
||||
NamedValue.Map values = dbResultSet.GetRecordValues();
|
||||
ItemId itemId = new ItemId((short)Sax.DataItemType.Article, new SysId(values.GetLong(colId.DataName)));
|
||||
SysId organisationId = new SysId(values.GetLong(colOrganisationId.DataName));
|
||||
String organisation = values.GetString(colOrganisation.DataName);
|
||||
long organisationLogoCount = values.GetLong(colOrganisationLogoCount.DataName);
|
||||
SysId authorId = new SysId(values.GetLong(colAuthorId.DataName));
|
||||
String author = Internals.ActivityMgr.GetArticleDataValue(colAuthor, values).ToString();
|
||||
String headline = values.GetString(colHeadline.DataName);
|
||||
String summary = values.GetString(colSummary.DataName);
|
||||
SysId itemImageIdThumbnail = new SysId(values.GetLong(colItemImageIdThumbnail.DataName));
|
||||
SysId sportId = new SysId(values.GetLong(colSportId.DataName));
|
||||
String sportName = values.GetString(colSportName.DataName);
|
||||
SysId regionId = new SysId(values.GetLong(colRegionId.DataName));
|
||||
String regionName = values.GetString(colRegionName.DataName);
|
||||
|
||||
// Populate to corresponding activities.
|
||||
foreach (ActivityData_Web activity in activities.FindAll(item => item.ItemId.Equals(itemId)))
|
||||
{
|
||||
activity.SetOrganisation(organisationId, organisation, organisationLogoCount > 0);
|
||||
activity.SetAuthor(authorId, author);
|
||||
activity.SetDetails(headline, summary);
|
||||
activity.ItemImageIdThumbnail = itemImageIdThumbnail;
|
||||
activity.SetSport(sportId, sportName);
|
||||
activity.SetRegion(regionId, regionName);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Organisation Event details.
|
||||
private void PopulateOrganisationEventDetails(IndexContext context, List<ActivityData_Web> activities)
|
||||
{
|
||||
// Extract organisationEvent Ids.
|
||||
List<SysId> organisationEventIds = activities.FindAll(item => item.ItemId.Type == (int)Sax.DataItemType.OrganisationEvent).Select(ItemId => ItemId.ItemId.Id).ToList();
|
||||
if (organisationEventIds.IsEmpty()) return;
|
||||
|
||||
// Event columns - limit to essential information.
|
||||
ColumnDfn colId = Internals.ActivityMgr.GetOrganisationEventColumnDfn(SaxOrganisationEvent.Column.Id);
|
||||
ColumnDfn colOrganisationId = Internals.ActivityMgr.GetOrganisationEventColumnDfn(SaxOrganisationEvent.Column.OrganisationId);
|
||||
ColumnDfn colOrganisation = Internals.ActivityMgr.GetOrganisationEventColumnDfn(SaxOrganisationEvent.Column.Organisation_Name);
|
||||
ColumnDfn colOrganisationLogoCount = Internals.ActivityMgr.GetOrganisationEventColumnDfn(SaxOrganisationEvent.Column.Organisation_LogoCount);
|
||||
ColumnDfn colEventAt = Internals.ActivityMgr.GetOrganisationEventColumnDfn(SaxOrganisationEvent.Column.EventAt_DateTime);
|
||||
ColumnDfn colSummary = Internals.ActivityMgr.GetOrganisationEventColumnDfn(SaxOrganisationEvent.Column.Summary);
|
||||
ColumnDfn colDetails = Internals.ActivityMgr.GetOrganisationEventColumnDfn(SaxOrganisationEvent.Column.Details);
|
||||
ColumnDfn colSportId = Internals.ActivityMgr.GetOrganisationEventColumnDfn(SaxOrganisationEvent.Column.SportIdPrimary);
|
||||
ColumnDfn colSportName = Internals.ActivityMgr.GetOrganisationEventColumnDfn(SaxOrganisationEvent.Column.Sport_Name);
|
||||
ColumnDfn colRegionId = Internals.ActivityMgr.GetOrganisationEventColumnDfn(SaxOrganisationEvent.Column.RegionIdCountry);
|
||||
ColumnDfn colRegionName = Internals.ActivityMgr.GetOrganisationEventColumnDfn(SaxOrganisationEvent.Column.Region_Name);
|
||||
List<ColumnDfn> columns = new List<ColumnDfn>()
|
||||
{
|
||||
colId, colOrganisationId, colOrganisation, colOrganisationLogoCount,
|
||||
colEventAt, colSummary, colDetails, colSportId, colSportName, colRegionId, colRegionName
|
||||
};
|
||||
|
||||
// Event filter.
|
||||
SaxOrganisationEvent.Params prmEvent = new SaxOrganisationEvent.Params();
|
||||
prmEvent.IdsIncluded.AddRange(organisationEventIds);
|
||||
prmEvent.StatusCat = SaxOrganisationEvent.StatusCat.ActiveOnly;
|
||||
|
||||
using (DbResultSet dbResultSet = Internals.ActivityMgr.ExecuteOrganisationEventQuery(columns, prmEvent))
|
||||
{
|
||||
while (dbResultSet != null && dbResultSet.NextRecord())
|
||||
{
|
||||
NamedValue.Map values = dbResultSet.GetRecordValues();
|
||||
ItemId itemId = new ItemId((short)Sax.DataItemType.OrganisationEvent, new SysId(values.GetLong(colId.DataName)));
|
||||
SysId organisationId = new SysId(values.GetLong(colOrganisationId.DataName));
|
||||
String organisation = values.GetString(colOrganisation.DataName);
|
||||
long organisationLogoCount = values.GetLong(colOrganisationLogoCount.DataName);
|
||||
DateTime eventAt = values.GetDateTime(colEventAt.DataName);
|
||||
String eventAtDisplay = DateUtil.Format(eventAt, "d-MMM-yy");
|
||||
if (eventAt.Hour > 0 || eventAt.Minute > 0)
|
||||
eventAtDisplay += DateUtil.Format(values.GetDateTime(colEventAt.DataName), " HH:mm");
|
||||
String eventSummary = values.GetString(colSummary.DataName);
|
||||
String eventDetails = values.GetString(colDetails.DataName);
|
||||
SysId sportId = new SysId(values.GetLong(colSportId.DataName));
|
||||
String sportName = values.GetString(colSportName.DataName);
|
||||
SysId regionId = new SysId(values.GetLong(colRegionId.DataName));
|
||||
String regionName = values.GetString(colRegionName.DataName);
|
||||
|
||||
// Populate to corresponding activities.
|
||||
foreach (ActivityData_Web activity in activities.FindAll(item => item.ItemId.Equals(itemId)))
|
||||
{
|
||||
activity.SetOrganisation(organisationId, organisation, organisationLogoCount > 0);
|
||||
activity.SetDetails(eventAtDisplay, eventSummary);
|
||||
activity.SetSport(sportId, sportName);
|
||||
activity.SetRegion(regionId, regionName);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Organisation Opportunity details.
|
||||
private void PopulateOrganisationOpportunityDetails(IndexContext context, List<ActivityData_Web> activities)
|
||||
{
|
||||
// Extract opportunity Ids.
|
||||
List<SysId> opportunityIds = activities.FindAll(item => item.ItemId.Type == (int)Sax.DataItemType.OrganisationOpportunity).Select(ItemId => ItemId.ItemId.Id).ToList();
|
||||
if (opportunityIds.IsEmpty()) return;
|
||||
|
||||
// Opportunity columns - limit to essential information.
|
||||
ColumnDfn colId = Internals.ActivityMgr.GetOrganisationOpportunityColumnDfn(SaxOrganisationOpportunity.Column.Id);
|
||||
ColumnDfn colOrganisationId = Internals.ActivityMgr.GetOrganisationOpportunityColumnDfn(SaxOrganisationOpportunity.Column.OrganisationId);
|
||||
ColumnDfn colOrganisation = Internals.ActivityMgr.GetOrganisationOpportunityColumnDfn(SaxOrganisationOpportunity.Column.Organisation_Name);
|
||||
ColumnDfn colOrganisationLogoCount = Internals.ActivityMgr.GetOrganisationOpportunityColumnDfn(SaxOrganisationOpportunity.Column.Organisation_LogoCount);
|
||||
ColumnDfn colPosition = Internals.ActivityMgr.GetOrganisationOpportunityColumnDfn(SaxOrganisationOpportunity.Column.Position);
|
||||
ColumnDfn colOutline = Internals.ActivityMgr.GetOrganisationOpportunityColumnDfn(SaxOrganisationOpportunity.Column.Outline);
|
||||
ColumnDfn colSportId = Internals.ActivityMgr.GetOrganisationOpportunityColumnDfn(SaxOrganisationOpportunity.Column.SportIdPrimary);
|
||||
ColumnDfn colSportName = Internals.ActivityMgr.GetOrganisationOpportunityColumnDfn(SaxOrganisationOpportunity.Column.Sport_Name);
|
||||
ColumnDfn colRegionId = Internals.ActivityMgr.GetOrganisationOpportunityColumnDfn(SaxOrganisationOpportunity.Column.RegionIdPrimary);
|
||||
ColumnDfn colRegionName = Internals.ActivityMgr.GetOrganisationOpportunityColumnDfn(SaxOrganisationOpportunity.Column.Region_Name);
|
||||
List<ColumnDfn> columns = new List<ColumnDfn>()
|
||||
{
|
||||
colId, colOrganisationId, colOrganisation, colOrganisationLogoCount,
|
||||
colPosition, colOutline, colSportId, colSportName, colRegionId, colRegionName
|
||||
};
|
||||
|
||||
// Opportunity filter.
|
||||
SaxOrganisationOpportunity.Params prmOpportunity = new SaxOrganisationOpportunity.Params();
|
||||
prmOpportunity.IdsIncluded.AddRange(opportunityIds);
|
||||
prmOpportunity.StatusCat = SaxOrganisationOpportunity.StatusCat.ActiveOnly;
|
||||
|
||||
using (DbResultSet dbResultSet = Internals.ActivityMgr.ExecuteOrganisationOpportunityQuery(columns, prmOpportunity))
|
||||
{
|
||||
while (dbResultSet != null && dbResultSet.NextRecord())
|
||||
{
|
||||
NamedValue.Map values = dbResultSet.GetRecordValues();
|
||||
ItemId itemId = new ItemId((short)Sax.DataItemType.OrganisationOpportunity, new SysId(values.GetLong(colId.DataName)));
|
||||
SysId organisationId = new SysId(values.GetLong(colOrganisationId.DataName));
|
||||
String organisation = values.GetString(colOrganisation.DataName);
|
||||
long organisationLogoCount = values.GetLong(colOrganisationLogoCount.DataName);
|
||||
String position = values.GetString(colPosition.DataName);
|
||||
String outline = values.GetString(colOutline.DataName);
|
||||
SysId sportId = new SysId(values.GetLong(colSportId.DataName));
|
||||
String sportName = values.GetString(colSportName.DataName);
|
||||
SysId regionId = new SysId(values.GetLong(colRegionId.DataName));
|
||||
String regionName = values.GetString(colRegionName.DataName);
|
||||
|
||||
// Populate to corresponding activities.
|
||||
foreach (ActivityData_Web activity in activities.FindAll(item => item.ItemId.Equals(itemId)))
|
||||
{
|
||||
activity.SetOrganisation(organisationId, organisation, organisationLogoCount > 0);
|
||||
activity.SetDetails(position, outline);
|
||||
activity.SetSport(sportId, sportName);
|
||||
activity.SetRegion(regionId, regionName);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Store Activity Index.
|
||||
//-------------------------------------------------------------------
|
||||
protected override bool StoreActivityIndexData(IndexData indexData, DbUpdateInfo dbUpdateInfo)
|
||||
{
|
||||
// Store the Activity Index data for the specified item - Article, Event, Opportunity etc.
|
||||
// An item may have multiple index entries to describe the different
|
||||
// combination of sport and region that they apply to.
|
||||
// NB All entries for the same item must have the same values for:
|
||||
// - Owner User Account Id.
|
||||
// - Owner Organisation Id.
|
||||
// - Effective on date.
|
||||
// - Expires on date.
|
||||
String fn = GetType().Name + ".StoreActivityIndexData";
|
||||
ClearErrorState();
|
||||
|
||||
// Validate paramaters.
|
||||
if (!ItemId.IsValid(indexData.ItemId)) return false;
|
||||
if (!ValidActivityItemTypes.Contains((Sax.DataItemType)indexData.ItemId.Type))
|
||||
{
|
||||
SaLogger.Warn(fn + " Invalid item type specified for Activity Index: " + ((Sax.DataItemType)indexData.ItemId.Type).ToString());
|
||||
return SetErrorState("Invalid item type specified for Activity Index");
|
||||
}
|
||||
IndexStatsData stats = new IndexStatsData();
|
||||
|
||||
// Index entries required for activity.
|
||||
List<IndexEntryData> indexEntryDataList = GetEntriesForIndex(indexData);
|
||||
|
||||
// Retrieve existing index entries for the item.
|
||||
List<SaxActivityIndex> indexEntries = Internals.ActivityMgr.GetActivityIndexListForItem(indexData.ItemId);
|
||||
foreach (SaxActivityIndex indexEntry in indexEntries)
|
||||
{
|
||||
// Is the index entry still required.
|
||||
// Logic only compares the Ids (item, sport, region) and then updates the effective date if a match is found.
|
||||
// Based on the fact that and change in the effective date will impact all entries in the index for the item
|
||||
// and this approach minimises the number of updates required as Ids can't be changed in code (protected setters).
|
||||
IndexEntryData indexEntrydata = indexEntryDataList.Find(item => item.MatchesIds(indexEntry));
|
||||
if (indexEntrydata != null)
|
||||
{
|
||||
// Match found - update properties.
|
||||
indexEntry.UserAccountIdOwner = indexEntrydata.UserAccountIdOwner;
|
||||
indexEntry.OrganisationIdOwner = indexEntrydata.OrganisationIdOwner;
|
||||
indexEntry.EffectiveOn = indexEntrydata.EffectiveOn;
|
||||
indexEntry.ExpiresOn = indexEntrydata.ExpiresOn;
|
||||
if (indexEntry.Changed)
|
||||
{
|
||||
if (Internals.ActivityMgr.UpdateActivityIndex(indexEntry, dbUpdateInfo))
|
||||
stats.EntriesUpdated++;
|
||||
else SaLogger.Warn(fn + " Failed to update Activity Index - " + Internals.ActivityMgr.ErrorStateMessage);
|
||||
}
|
||||
|
||||
// Remove the entry from the 'required' list.
|
||||
// Entries remaining in this list will be created.
|
||||
indexEntryDataList.Remove(indexEntrydata);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Index entry no longer required.
|
||||
if (Internals.ActivityMgr.DeleteActivityIndex(indexEntry, dbUpdateInfo))
|
||||
stats.EntriesDeleted++;
|
||||
else SaLogger.Warn(fn + " Failed to delete Activity Index - " + Internals.ActivityMgr.ErrorStateMessage);
|
||||
}
|
||||
}
|
||||
// The remaining required Index entries will be created.
|
||||
foreach (IndexEntryData indexEntry in indexEntryDataList)
|
||||
{
|
||||
SaxActivityIndex itemIndexEntry = Internals.ActivityMgr.CreateActivityIndex(indexEntry.ItemId, indexEntry.SportId, indexEntry.RegionId);
|
||||
itemIndexEntry.UserAccountIdOwner = indexEntry.UserAccountIdOwner;
|
||||
itemIndexEntry.OrganisationIdOwner = indexEntry.OrganisationIdOwner;
|
||||
itemIndexEntry.EffectiveOn = indexEntry.EffectiveOn;
|
||||
itemIndexEntry.ExpiresOn = indexEntry.ExpiresOn;
|
||||
if (Internals.ActivityMgr.InsertActivityIndex(itemIndexEntry, dbUpdateInfo))
|
||||
stats.EntriesInserted++;
|
||||
else SaLogger.Warn(fn + " Failed to insert Activity Index - " + Internals.ActivityMgr.ErrorStateMessage);
|
||||
}
|
||||
|
||||
// Log statistics.
|
||||
List<String> statsLog = new List<string>();
|
||||
if (stats.EntriesInserted > 0) statsLog.Add("Inserted: " + stats.EntriesInserted);
|
||||
if (stats.EntriesUpdated > 0) statsLog.Add("Updated: " + stats.EntriesUpdated);
|
||||
if (stats.EntriesDeleted > 0) statsLog.Add("Deleted: " + stats.EntriesDeleted);
|
||||
SaLogger.Info(fn + " Activity Index stored for " + ((Sax.DataItemType)indexData.ItemId.Type).ToString() + ":" + indexData.ItemId.Id.ToLong() + "." + statsLog.Concat("", "", ". "));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
protected override bool ClearActivityIndex(ItemId itemId, DbUpdateInfo dbUpdateInfo)
|
||||
{
|
||||
String fn = GetType().Name + ".ClearActivityIndex";
|
||||
ClearErrorState();
|
||||
String tableName = SaxDbDfn_Core.GetTableName(SaxDbDfn_Core.TableIdx.ActivityIndex);
|
||||
String filter =
|
||||
SaxDbDfn_Core.GetColumnName(SaxDbDfn_Core.ColumnIdx.ActivityIndex_ItemType) + "=" + itemId.Type +
|
||||
" And " + SaxDbDfn_Core.GetColumnName(SaxDbDfn_Core.ColumnIdx.ActivityIndex_ItemId) + "=" + itemId.Id.ToLong();
|
||||
ISacsDatabase db = CoreDatabase;
|
||||
int recordsDeleted = db.ExecuteDelete(tableName, filter);
|
||||
if (recordsDeleted > 0)
|
||||
SaLogger.Info(fn + " Records deleted: " + recordsDeleted + ". Filter: " + filter, true);
|
||||
return true;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// User Activities
|
||||
//-------------------------------------------------------------------
|
||||
/// <summary>
|
||||
/// Record listing of activities by user - those populated to the application page.
|
||||
/// <para>- Activities not previously listed are added to the user's list.</para>
|
||||
/// <para>- Activities previously listed are updated in the user's list.</para>
|
||||
/// <para>- User Activities no longer listed are flagged as 'Not currently listed'.</para>
|
||||
/// </summary>
|
||||
public override bool RecordUserActivitiesListed(SysId userAccountId, List<ItemId> activityItemIds, DbUpdateInfo dbUpdateInfo)
|
||||
{
|
||||
String fn = GetType().Name + ".RecordUserActivitiesListed";
|
||||
if (!SysId.IsValid(userAccountId)) return SetErrorState("User Account must be specified");
|
||||
if (activityItemIds.IsEmpty()) return SetErrorState("Activity item ids must be specified");
|
||||
String sqlNow = "'" + DateUtil.FormatSqlDateTime(DateTime.Now) + "'";
|
||||
String sqlStatus = "'" + SacsSystem.GetStatusCode(SaxUserActivity.DefaultStatus) + "'";
|
||||
|
||||
// Merge query - insert missing user activities and update existing.
|
||||
List<String> query = new List<String>()
|
||||
{
|
||||
"Merge",
|
||||
"\tInto " + SaxDbDfn_Core.GetTableName(SaxDbDfn_Core.TableIdx.UserActivity) + " As UsrAct",
|
||||
// Virtual table defining Activity Item Ids currently listed.
|
||||
"\tUsing",
|
||||
"\t(",
|
||||
"\t\tSelect ItemType, ItemId From (Select 0 ItemType, 0 ItemId" + activityItemIds.Select(item => " Union Select " + item.Type.ToString() + ", " + item.Id.ToString()).ToList().Concat("", " ") + ") Dat Where Dat.ItemType>0 And Dat.ItemId>0",
|
||||
"\t) As Act",
|
||||
"\tOn UsrAct.UserAccountId="+userAccountId.ToString() + " And UsrAct.ItemType=Act.ItemType And UsrAct.ItemId=Act.ItemId",
|
||||
// Matched - Update the User Activity to indicate 'Currently listed' and update the last listed date/time.
|
||||
"\tWhen Matched Then",
|
||||
"\t\tUpdate Set CurrentlyListed=1, ListedAtLast=" + sqlNow + ", Status=" + sqlStatus + ", UpdateOn=" + sqlNow + ", UpdateBy=" + dbUpdateInfo.UserId.ToString() + ", UpdateHost='" + dbUpdateInfo.Host + "'",
|
||||
// Not Matched By Target - Insert the User Activity and indicate 'Currently listed' with first and last listed date/times.
|
||||
"\tWhen Not Matched Then",
|
||||
"\t\tInsert",
|
||||
"\t\t\t(UserAccountId, ItemType, ItemId, CurrentlyListed, ListedAtFirst, ListedAtLast, Reaction, UserActivityData, Notes, Flags, Status, CreateOn, CreateBy, CreateHost, UpdateOn, UpdateBy, UpdateHost)",
|
||||
"\t\t\tValues ("+userAccountId.ToString()+", Act.ItemType, Act.ItemId, 1, " + sqlNow + ", " + sqlNow + ", 0, '', '', 0, " + sqlStatus + ", " + sqlNow + ", " + dbUpdateInfo.UserId.ToString() + ", '" + dbUpdateInfo.Host + "', " + sqlNow + ", " + dbUpdateInfo.UserId.ToString() + ", '" + dbUpdateInfo.Host + "')",
|
||||
// Not Matched By Source - Update the User Activity to indicate 'Not currently listed'.
|
||||
"\tWhen Not Matched By Source And UsrAct.UserAccountId=" + userAccountId.ToString() + " And CurrentlyListed=1 Then",
|
||||
"\t\tUpdate Set CurrentlyListed=0, UpdateOn=" + sqlNow + ", UpdateBy=" + dbUpdateInfo.UserId.ToString() + ", UpdateHost='" + dbUpdateInfo.Host + "'",
|
||||
";"
|
||||
};
|
||||
String sql = query.Concat("\n");
|
||||
//SaLogger.Debug(fn + " Query:\n" + sql);
|
||||
ISacsDatabase db = CoreDatabase;
|
||||
int rows = db.ExecuteNonQuery(sql);
|
||||
if (db.HasErrorState())
|
||||
SaLogger.Debug(fn + " Database error: " + db.ErrorStateMessage);
|
||||
SaLogger.Debug(fn + " Rows modified: " + rows);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
public override bool RecordUserActivityViewed(SysId userAccountId, ItemId activityItemId, DbUpdateInfo dbUpdateInfo)
|
||||
{
|
||||
String fn = GetType().Name + ".RecordUserActivityViewed";
|
||||
if (!SysId.IsValid(userAccountId)) return SetErrorState("User Account must be specified");
|
||||
if (!ItemId.IsValid(activityItemId)) return SetErrorState("Activity item id must be specified");
|
||||
DateTime now = DateTime.Now;
|
||||
|
||||
SaxUserActivity userActivity = Internals.ActivityMgr.GetUserActivityForUserItem(userAccountId, activityItemId);
|
||||
if (userActivity != null)
|
||||
{
|
||||
// Update activity.
|
||||
userActivity.CurrentlyListed = true;
|
||||
if (!DateUtil.IsValid(userActivity.ViewedAtFirst))
|
||||
userActivity.ViewedAtFirst = now;
|
||||
userActivity.ViewedAtLast = now;
|
||||
userActivity.Status = SaxUserActivity.DefaultStatus;
|
||||
if (!Internals.ActivityMgr.UpdateUserActivity(userActivity, dbUpdateInfo))
|
||||
{
|
||||
SaLogger.Warn(fn + " Failed to update User Activity for viewing: " + Internals.ActivityMgr.ErrorStateMessage);
|
||||
return SetErrorState(Internals.ActivityMgr.ErrorStateMessage);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
SaLogger.Warn(fn + " User Activity not found. UserAccountId: " + userAccountId.ToString() + ". Item Type: " + (Sax.DataItemType)activityItemId.Type + ". ItemId: " + activityItemId.Id.ToString() + ".");
|
||||
return SetErrorState("User Activity not found");
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
public override bool RecordUserActivityReaction(SysId userAccountId, ItemId activityItemId, Sax.ActivityReaction activityReaction, DbUpdateInfo dbUpdateInfo)
|
||||
{
|
||||
String fn = GetType().Name + ".RecordUserActivityReaction";
|
||||
if (!SysId.IsValid(userAccountId)) return SetErrorState("User Account must be specified");
|
||||
if (!ItemId.IsValid(activityItemId)) return SetErrorState("Activity item id must be specified");
|
||||
DateTime now = DateTime.Now;
|
||||
|
||||
SaxUserActivity userActivity = Internals.ActivityMgr.GetUserActivityForUserItem(userAccountId, activityItemId);
|
||||
if (userActivity != null)
|
||||
{
|
||||
if (userActivity.Reaction != activityReaction)
|
||||
{
|
||||
// Update activity.
|
||||
userActivity.CurrentlyListed = true;
|
||||
if (!DateUtil.IsValid(userActivity.ViewedAtFirst))
|
||||
userActivity.ViewedAtFirst = now;
|
||||
userActivity.ViewedAtLast = now;
|
||||
userActivity.Reaction = activityReaction;
|
||||
if (!DateUtil.IsValid(userActivity.ReactedAtFirst))
|
||||
userActivity.ReactedAtFirst = now;
|
||||
userActivity.ReactedAtLast = now;
|
||||
userActivity.Status = SaxUserActivity.DefaultStatus;
|
||||
if (!Internals.ActivityMgr.UpdateUserActivity(userActivity, dbUpdateInfo))
|
||||
{
|
||||
SaLogger.Warn(fn + " Failed to update User Activity with reaction: " + Internals.ActivityMgr.ErrorStateMessage);
|
||||
return SetErrorState(Internals.ActivityMgr.ErrorStateMessage);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
SaLogger.Warn(fn + " User Activity not found. UserAccountId: " + userAccountId.ToString() + ". Item Type: " + (Sax.DataItemType)activityItemId.Type + ". ItemId: " + activityItemId.Id.ToString() + ".");
|
||||
return SetErrorState("User Activity not found");
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
}
|
||||
//=======================================================================
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
using Saxonite.Net.Standard.Base.Consoles;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace Saxonite.Net.Core.Web.Base.Consoles
|
||||
{
|
||||
//=======================================================================
|
||||
public abstract class SaxConsoleHelper_Web : SaxConsoleHelper
|
||||
{
|
||||
//-------------------------------------------------------------------
|
||||
// Protected construction.
|
||||
protected SaxConsoleHelper_Web()
|
||||
{
|
||||
}
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
}
|
||||
//=======================================================================
|
||||
}
|
||||
@@ -0,0 +1,291 @@
|
||||
using Microsoft.IdentityModel.Tokens;
|
||||
using Sarand.Net.Standard.Base.App;
|
||||
using Sarand.Net.Standard.Base.Bus;
|
||||
using Sarand.Net.Standard.Base.Utils;
|
||||
using Saxonite.Net.Standard.Base.App;
|
||||
using Saxonite.Net.Standard.Base.Bus;
|
||||
using Saxonite.Net.Standard.Base.Consoles;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace Saxonite.Net.Core.Web.Base.Consoles
|
||||
{
|
||||
//=======================================================================
|
||||
public abstract class SaxDataCacheConsole_Web : SaxDataCacheConsole
|
||||
{
|
||||
//-------------------------------------------------------------------
|
||||
// Data members.
|
||||
private class DataMembers
|
||||
{
|
||||
public SaxInternals internals;
|
||||
public Dictionary<Sax.DataItemType, Dictionary<SysId, String>> encryptedIdCache = new Dictionary<Sax.DataItemType, Dictionary<SysId, String>>();
|
||||
}
|
||||
private DataMembers data = new DataMembers();
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Protected construction.
|
||||
protected SaxDataCacheConsole_Web(SaxSessionContext sessionContext) :
|
||||
base(sessionContext)
|
||||
{
|
||||
data.internals = new SaxInternals(sessionContext, false);
|
||||
}
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
data.internals.Dispose();
|
||||
}
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Utilities.
|
||||
protected abstract void ForceRefresh();
|
||||
|
||||
public override void PopulateCachedDataToInternals(SaxInternals internals)
|
||||
{
|
||||
if (regionsData.regionDataMap == null) ForceRefresh();
|
||||
|
||||
// Regions.
|
||||
List<SaxRegion.Data> activeRegionDataList = new List<SaxRegion.Data>();
|
||||
lock (regionsData)
|
||||
activeRegionDataList.AddRange(regionsData.activeRegionDataList);
|
||||
internals.PopulateRegionCache(activeRegionDataList);
|
||||
|
||||
// Sports.
|
||||
List<SaxSport.Data> activeSportDataList = new List<SaxSport.Data>();
|
||||
lock (sportsData)
|
||||
activeSportDataList.AddRange(sportsData.activeSportDataList);
|
||||
internals.PopulateSportCache(activeSportDataList);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Encrypted Ids are stored in cache to ensure that they are consistent throughout a user's session
|
||||
/// by persisting them through the life of the cache (application restart).
|
||||
/// <para>Required as the encrypted values are compared in javascript.</para>
|
||||
/// <para>Candidate encrypted value supplied by calling routine as cache doesn't know how to encrypt - used if Id not previously encrypted.</para>
|
||||
/// </summary>
|
||||
public override String GetEncryptedId(Sax.DataItemType itemType, SysId id, String candidateValue)
|
||||
{
|
||||
// Invalid Id always has a blank encrypted value.
|
||||
if (!SysId.IsValid(id)) return "";
|
||||
|
||||
// Only Regions and Sports are supported.
|
||||
if (!(new List<Sax.DataItemType>() { Sax.DataItemType.Sport, Sax.DataItemType.Region }).Contains(itemType))
|
||||
return candidateValue;
|
||||
|
||||
lock (data.encryptedIdCache)
|
||||
{
|
||||
Dictionary<SysId, String> itemIds = data.encryptedIdCache.GetValue(itemType, null);
|
||||
if (itemIds == null)
|
||||
{
|
||||
// Add cache entry for this item type.
|
||||
itemIds = new Dictionary<SysId, string>();
|
||||
data.encryptedIdCache.Add(itemType, itemIds);
|
||||
}
|
||||
String encryptedId = itemIds.GetValue(id, null);
|
||||
if (encryptedId == null && !StringUtil.IsEmpty(candidateValue))
|
||||
{
|
||||
// Use the candidate value and store it.
|
||||
encryptedId = candidateValue;
|
||||
itemIds.Add(id, encryptedId);
|
||||
}
|
||||
return encryptedId;
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Regions.
|
||||
public bool RegionsSupported { get; protected set; } = false;
|
||||
private class RegionsData
|
||||
{
|
||||
public Dictionary<SysId, SaxRegion.Data> regionDataMap = null;
|
||||
public List<SaxRegion.Data> activeRegionDataList = null;
|
||||
}
|
||||
private readonly RegionsData regionsData = new RegionsData();
|
||||
public override List<SaxRegion.Data> GetAllRegions()
|
||||
{
|
||||
String fn = GetType().Name + ".ActiveRegions";
|
||||
if (!RegionsSupported) throw new NotSupportedException(fn + " Regions not supported.");
|
||||
List<SaxRegion.Data> activeRegions = new List<SaxRegion.Data>();
|
||||
if (regionsData.regionDataMap == null) ForceRefresh();
|
||||
lock (regionsData)
|
||||
{
|
||||
if (regionsData.regionDataMap == null) throw new NotSupportedException(fn + " Regions not populated.");
|
||||
activeRegions.AddRange(regionsData.regionDataMap.Values);
|
||||
}
|
||||
return activeRegions;
|
||||
}
|
||||
public override List<SaxRegion.Data> GetActiveRegions()
|
||||
{
|
||||
String fn = GetType().Name + ".ActiveRegions";
|
||||
if (!RegionsSupported) throw new NotSupportedException(fn + " Regions not supported.");
|
||||
List<SaxRegion.Data> activeRegions = new List<SaxRegion.Data>();
|
||||
if (regionsData.regionDataMap == null) ForceRefresh();
|
||||
lock (regionsData)
|
||||
{
|
||||
if (regionsData.regionDataMap == null) throw new NotSupportedException(fn + " Regions not populated.");
|
||||
activeRegions.AddRange(regionsData.activeRegionDataList);
|
||||
}
|
||||
return activeRegions;
|
||||
}
|
||||
protected void RefreshRegions()
|
||||
{
|
||||
String fn = GetType().Name + ".RefreshRegions";
|
||||
if (!RegionsSupported) throw new NotSupportedException(fn + " Regions not supported.");
|
||||
|
||||
try
|
||||
{
|
||||
DateTime startedAt = DateTime.Now;
|
||||
|
||||
// Refreshed lists will be populated in isolation and then used to instantaneously replace the cache lists.
|
||||
Dictionary<SysId, SaxRegion.Data> newRegionDataMap = new Dictionary<SysId, SaxRegion.Data>();
|
||||
List<SaxRegion.Data> newActiveRegionDataList = new List<SaxRegion.Data>();
|
||||
|
||||
// Query Regions to replace cache.
|
||||
SaxRegion.Params prmRegion = new SaxRegion.Params();
|
||||
prmRegion.StatusCat = SaxRegion.StatusCat.NotDeleted;
|
||||
foreach (SaxRegion region in data.internals.ReferenceMgr.GetRegionList(prmRegion))
|
||||
{
|
||||
// Only interested in retaining the Data objects.
|
||||
newRegionDataMap[region.Id] = region.GetData();
|
||||
region.Dispose();
|
||||
}
|
||||
|
||||
// Populate replacement list of active regions.
|
||||
foreach (SaxRegion.Data regionData in newRegionDataMap.GetValues())
|
||||
{
|
||||
if (IsRegionActive(newRegionDataMap, regionData))
|
||||
newActiveRegionDataList.Add(regionData.Clone());
|
||||
}
|
||||
|
||||
// Replace the list of Regions.
|
||||
lock (regionsData)
|
||||
{
|
||||
// Assign the refreshed regions and active regions.
|
||||
// NB The old regions don't need to be disposed as they are SaxRegion.Data objects.
|
||||
regionsData.regionDataMap = newRegionDataMap;
|
||||
regionsData.activeRegionDataList = newActiveRegionDataList;
|
||||
}
|
||||
SaLogger.Info(fn + " Regions found: " + regionsData.regionDataMap.Count + ". Elapsed: " + DateUtil.FormatNumberOfSeconds((DateTime.Now - startedAt).TotalSeconds));
|
||||
}
|
||||
catch (Exception exc)
|
||||
{
|
||||
SaLogger.Error(fn + ExceptionUtil.GetLogMessage(exc, "refreshing Regions cache"));
|
||||
}
|
||||
}
|
||||
private static bool IsRegionActive(Dictionary<SysId, SaxRegion.Data> regionDataMap, SaxRegion.Data regionData)
|
||||
{
|
||||
if (regionData == null) return false;
|
||||
if (!regionData.IsStatusActive) return false;
|
||||
if (SysId.IsValid(regionData.RegionIdParent))
|
||||
return IsRegionActive(regionDataMap, regionDataMap.GetValue(regionData.RegionIdParent, null));
|
||||
return true;
|
||||
}
|
||||
private SaxRegion GetRegion(SaxRegion.Data regionData)
|
||||
{
|
||||
if (regionData == null) return null;
|
||||
SaxRegion region = data.internals.ReferenceMgr.CreateRegion();
|
||||
region.SetData(regionData);
|
||||
return region;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Sports.
|
||||
public bool SportsSupported { get; protected set; } = false;
|
||||
private class SportsData
|
||||
{
|
||||
public Dictionary<SysId, SaxSport.Data> sportDataMap = null;
|
||||
public List<SaxSport.Data> activeSportDataList = null;
|
||||
}
|
||||
private readonly SportsData sportsData = new SportsData();
|
||||
public override List<SaxSport.Data> GetAllSports()
|
||||
{
|
||||
String fn = GetType().Name + ".GetAllSports";
|
||||
if (!SportsSupported) throw new NotSupportedException(fn + " Sports not supported.");
|
||||
List<SaxSport.Data> sports = new List<SaxSport.Data>();
|
||||
if (sportsData.sportDataMap == null) ForceRefresh();
|
||||
lock (sportsData)
|
||||
{
|
||||
if (sportsData.sportDataMap == null) throw new NotSupportedException(fn + " Sports not populated.");
|
||||
sports.AddRange(sportsData.sportDataMap.Values);
|
||||
}
|
||||
return sports;
|
||||
}
|
||||
public override List<SaxSport.Data> GetActiveSports()
|
||||
{
|
||||
String fn = GetType().Name + ".GetActiveSports";
|
||||
if (!SportsSupported) throw new NotSupportedException(fn + " Sports not supported.");
|
||||
List<SaxSport.Data> activeSports = new List<SaxSport.Data>();
|
||||
if (sportsData.sportDataMap == null) ForceRefresh();
|
||||
lock (sportsData)
|
||||
{
|
||||
if (sportsData.sportDataMap == null) throw new NotSupportedException(fn + " Sports not populated.");
|
||||
activeSports.AddRange(sportsData.activeSportDataList);
|
||||
}
|
||||
return activeSports;
|
||||
}
|
||||
protected void RefreshSports()
|
||||
{
|
||||
String fn = GetType().Name + ".RefreshSports";
|
||||
if (!SportsSupported) throw new NotSupportedException(fn + " Sports not supported.");
|
||||
|
||||
try
|
||||
{
|
||||
DateTime startedAt = DateTime.Now;
|
||||
|
||||
// Refreshed lists will be populated in isolation and then used to instantaneously replace the cache lists.
|
||||
Dictionary<SysId, SaxSport.Data> newSportDataMap = new Dictionary<SysId, SaxSport.Data>();
|
||||
List<SaxSport.Data> newActiveSportDataList = new List<SaxSport.Data>();
|
||||
|
||||
// Query Sports to replace cache.
|
||||
SaxSport.Params prmSport = new SaxSport.Params();
|
||||
prmSport.StatusCat = SaxSport.StatusCat.NotDeleted;
|
||||
foreach (SaxSport sport in data.internals.ReferenceMgr.GetSportList(prmSport))
|
||||
{
|
||||
// Only interested in retaining the Data objects.
|
||||
newSportDataMap[sport.Id] = sport.GetData();
|
||||
sport.Dispose();
|
||||
}
|
||||
|
||||
// Populate replacement list of active sports.
|
||||
foreach (SaxSport.Data sportData in newSportDataMap.GetValues())
|
||||
{
|
||||
if (IsSportActive(newSportDataMap, sportData))
|
||||
newActiveSportDataList.Add(sportData.Clone());
|
||||
}
|
||||
|
||||
// Replace the list of Sports.
|
||||
lock (sportsData)
|
||||
{
|
||||
// Assign the refreshed sports and active sports.
|
||||
// NB The old sports don't need to be disposed as they are SaxSport.Data objects.
|
||||
sportsData.sportDataMap = newSportDataMap;
|
||||
sportsData.activeSportDataList = newActiveSportDataList;
|
||||
}
|
||||
SaLogger.Info(fn + " Sports found: " + sportsData.sportDataMap.Count + ". Elapsed: " + DateUtil.FormatNumberOfSeconds((DateTime.Now - startedAt).TotalSeconds));
|
||||
}
|
||||
catch (Exception exc)
|
||||
{
|
||||
SaLogger.Error(fn + ExceptionUtil.GetLogMessage(exc, "refreshing Sports cache"));
|
||||
}
|
||||
}
|
||||
private static bool IsSportActive(Dictionary<SysId, SaxSport.Data> sportDataMap, SaxSport.Data sportData)
|
||||
{
|
||||
if (sportData == null) return false;
|
||||
if (!sportData.IsStatusActive) return false;
|
||||
return true;
|
||||
}
|
||||
private SaxSport GetSport(SaxSport.Data sportData)
|
||||
{
|
||||
if (sportData == null) return null;
|
||||
SaxSport sport = data.internals.ReferenceMgr.CreateSport();
|
||||
sport.SetData(sportData);
|
||||
return sport;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
}
|
||||
//=======================================================================
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
using Saxonite.Net.Standard.Base.Consoles;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace Saxonite.Net.Core.Web.Base.Consoles
|
||||
{
|
||||
//=======================================================================
|
||||
public class SaxEmailConsole_Web : SaxEmailConsole
|
||||
{
|
||||
//-------------------------------------------------------------------
|
||||
// Protected construction.
|
||||
public SaxEmailConsole_Web(SaxEmailConfig emailConfig) :
|
||||
base(emailConfig)
|
||||
{
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
}
|
||||
//=======================================================================
|
||||
}
|
||||
@@ -0,0 +1,98 @@
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using Sarand.Net.Standard.Base.App;
|
||||
using Sarand.Net.Standard.Base.Core;
|
||||
using Sarand.Net.Standard.Base.Tasks;
|
||||
using Sarand.Net.Standard.Base.Utils;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Saxonite.Net.Core.Web.Base.Consoles
|
||||
{
|
||||
//=======================================================================
|
||||
public abstract class SaxHostedServiceConsole_Web : SacsDisposable, IHostedService
|
||||
{
|
||||
//-------------------------------------------------------------------
|
||||
// Definitions.
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Data members.
|
||||
private Timer processTimer;
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Construction.
|
||||
protected SaxHostedServiceConsole_Web ()
|
||||
{
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Clean-up.
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
DisposeTimer();
|
||||
if (ProcessTaskData != null) ProcessTaskData.Dispose();
|
||||
ProcessTaskData = null;
|
||||
}
|
||||
|
||||
private void DisposeTimer()
|
||||
{
|
||||
if (processTimer != null) processTimer.Dispose();
|
||||
processTimer = null;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Properties.
|
||||
|
||||
// Task data - allows cancellation to be triggered for executing processes, eg. when application is stopping.
|
||||
protected SacsTaskData ProcessTaskData { get; private set; }
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
|
||||
/// <summary>
|
||||
/// Periodic processing to execute application processes as required.
|
||||
/// </summary>
|
||||
protected abstract void DoWork(object state);
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
|
||||
/// <summary>
|
||||
/// Triggered when the application host is ready to start the service.
|
||||
/// </summary>
|
||||
/// <param name="cancellationToken">Indicates that the start process has been aborted.</param>
|
||||
/// <returns></returns>
|
||||
public virtual Task StartAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
SaLogger.Info($"{SysUtil.Fn} Timed Background Service started.");
|
||||
|
||||
// Initialise the background task cancellation token.
|
||||
ProcessTaskData = new SacsTaskData();
|
||||
|
||||
// Initialise the scheduled task timer.
|
||||
processTimer = new Timer(DoWork, null, TimeSpan.Zero, TimeSpan.FromMinutes(1));
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Triggered when the application host is performing a graceful shutdown.
|
||||
/// </summary>
|
||||
/// <param name="cancellationToken">Indicates that the shutdown process should no longer be graceful.</param>
|
||||
/// <returns></returns>
|
||||
public virtual Task StopAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
SaLogger.Info($"{SysUtil.Fn} Timed Background Service stopped.");
|
||||
|
||||
// Signal cancellation to the background tasks.
|
||||
ProcessTaskData.TriggerCancellation();
|
||||
|
||||
// Stop the timer.
|
||||
processTimer?.Change(Timeout.Infinite, 0);
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
}
|
||||
//=======================================================================
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
using Saxonite.Net.Standard.Base.App;
|
||||
using Saxonite.Net.Standard.Base.Consoles;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Saxonite.Net.Core.Web.Base.Consoles
|
||||
{
|
||||
//=======================================================================
|
||||
public abstract class SaxSessionDataConsole_Web : SaxSessionDataConsole
|
||||
{
|
||||
//-------------------------------------------------------------------
|
||||
// Definitions.
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Data members.
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Construction.
|
||||
protected SaxSessionDataConsole_Web(SaxSessionContext sessionContext) :
|
||||
base(sessionContext)
|
||||
{
|
||||
}
|
||||
//-------------------------------------------------------------------
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
}
|
||||
//=======================================================================
|
||||
}
|
||||
@@ -0,0 +1,148 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Sacs.Web.Components;
|
||||
using Sarand.Net.Standard.Base.App;
|
||||
using Sarand.Net.Standard.Base.Bus;
|
||||
using Sarand.Net.Standard.Base.Core;
|
||||
using Sarand.Net.Standard.Base.Email;
|
||||
using Sarand.Net.Standard.Base.Utils;
|
||||
using Saxonite.Net.Core.Web.Base.App;
|
||||
using Saxonite.Net.Standard.Base.App;
|
||||
using Saxonite.Net.Standard.Base.Bus;
|
||||
using Saxonite.Net.Standard.Base.Consoles;
|
||||
using Saxonite.Net.Standard.Base.Mgr;
|
||||
using Saxonite.Net.Standard.Base.Mgr.Reference;
|
||||
using Saxonite.Net.Standard.Base.Mgr.Support;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Saxonite.Net.Core.Web.Base.Controllers
|
||||
{
|
||||
//=======================================================================
|
||||
public abstract class SaxController_Base : SaController
|
||||
{
|
||||
//-------------------------------------------------------------------
|
||||
// Data members.
|
||||
private SaxInternals internals;
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Protected construction.
|
||||
protected SaxController_Base(SaxLocaliser localiser)
|
||||
{
|
||||
Localiser = localiser;
|
||||
|
||||
// Initialise console (debug) logging listener.
|
||||
//if (Directory.Exists(App.LoggingRootFolder) && SaxSystem.DebugMode)
|
||||
// SaxConsoleListener.ConfigureDebugListener(App.LoggingRootFolder);
|
||||
if (DebugMode) SaLogger.Trace($"{GetType().Name}.CTR");
|
||||
}
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
}
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Properties.
|
||||
protected SaxApplication_Web App { get { return SaxApplication_Web.WebApp; } }
|
||||
public SaxAppConfig AppConfig { get { return App.AppConfig; } }
|
||||
public SaxSessionContext SessionContext { get { return App.SessionContext; } }
|
||||
public SaxLocaliser Localiser { get; }
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Globals.
|
||||
protected SaxConsoleHelper ConsoleHelper { get { return SaxGlobals.ConsoleHelper; } }
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Business components.
|
||||
public SaxInternals Internals { get { if (internals == null) internals = new SaxInternals(SessionContext); return internals; } }
|
||||
// Consoles.
|
||||
public SaxDataCacheConsole DataCacheConsole { get { return Internals.DataCacheConsole; } }
|
||||
public SaxSessionDataConsole SessionDataConsole { get { return Internals.SessionDataConsole; } }
|
||||
public SaxActivityConsole ActivityConsole { get { return Internals.ActivityConsole; } }
|
||||
// Managers.
|
||||
public SaxReferenceMgr ReferenceMgr { get { return Internals.ReferenceMgr; } }
|
||||
public SaxAccountMgr AccountMgr { get { return Internals.AccountMgr; } }
|
||||
public SaxActivityMgr ActivityMgr { get { return Internals.ActivityMgr; } }
|
||||
public SaxItemDataMgr ItemDataMgr { get { return Internals.ItemDataMgr; } }
|
||||
public SaxReferenceGolfMgr ReferenceGolfMgr { get { return Internals.ReferenceGolfMgr; } }
|
||||
public SaxSupportMgr SupportMgr { get { return Internals.SupportMgr; } }
|
||||
// System codes.
|
||||
public List<TypeCodeDesc> DataItemTypeCodes { get { return Internals.DataItemTypeCodes; } }
|
||||
public List<TypeCodeDesc> SportGroupingCodes { get { return Internals.SportGroupingCodes; } }
|
||||
public List<TypeCodeDesc> SportSpecialityLabelCodes { get { return Internals.SportSpecialityLabelCodes; } }
|
||||
public List<TypeCodeDesc> SportContactTypeCodes { get { return Internals.SportContactTypeCodes; } }
|
||||
public List<TypeCodeDesc> SportParticipatingCodes { get { return Internals.SportParticipatingCodes; } }
|
||||
public List<TypeCodeDesc> SportPreparingCodes { get { return Internals.SportPreparingCodes; } }
|
||||
public List<TypeCodeDesc> SportOfficiatingCodes { get { return Internals.SportOfficiatingCodes; } }
|
||||
public List<TypeCodeDesc> RegionTypeCodes { get { return Internals.RegionTypeCodes; } }
|
||||
public List<TypeCodeDesc> EligibilityTypeCodes { get { return Internals.EligibilityTypeCodes; } }
|
||||
public List<TypeCodeDesc> UserRoleCodes { get { return Internals.UserRoleCodes; } }
|
||||
public List<TypeCodeDesc> OrganisationTypeCodes { get { return Internals.OrganisationTypeCodes; } }
|
||||
public List<TypeCodeDesc> OrganisationCategoryCodes { get { return Internals.OrganisationCategoryCodes; } }
|
||||
public List<TypeCodeDesc> OrganisationRoleCodes { get { return Internals.OrganisationRoleCodes; } }
|
||||
public List<TypeCodeDesc> AssociationTypeCodes { get { return Internals.AssociationTypeCodes; } }
|
||||
public List<TypeCodeDesc> AddressTypeCodes { get { return Internals.AddressTypeCodes; } }
|
||||
public List<TypeCodeDesc> ContactMethodCodes { get { return Internals.ContactMethodCodes; } }
|
||||
public List<TypeCodeDesc> EventTypeCodes { get { return Internals.EventTypeCodes; } }
|
||||
public List<TypeCodeDesc> OpportunityTypeCodes { get { return Internals.OpportunityTypeCodes; } }
|
||||
public List<TypeCodeDesc> ActivityReactionCodes { get { return Internals.ActivityReactionCodes; } }
|
||||
// Support.
|
||||
public List<TypeCodeDesc> UserReportTypeCodes { get { return Internals.UserReportTypeCodes; } }
|
||||
public List<TypeCodeDesc> SupportItemProcessTypeCodes { get { return Internals.SupportItemProcessTypeCodes; } }
|
||||
// Email.
|
||||
public SaEmailConfig EmailConfig { get { return App.EmailConfig; } }
|
||||
public SaxEmailConsole EmailConsole { get { return Internals.EmailConsole; } }
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
[NonAction]
|
||||
/// <summary>
|
||||
/// Retrieve sport by matching the name and include groups as required.
|
||||
/// </summary>
|
||||
/// <param name="sportName"></param>
|
||||
/// <param name="includeGroups"></param>
|
||||
/// <returns>List of matching sports.</returns>
|
||||
public List<SaxSport.Data> GetSportsByName(String sportName, bool includeGroups = false)
|
||||
{
|
||||
List<SaxSport.Data> sportsData = new List<SaxSport.Data>();
|
||||
if (DataCacheConsole != null)
|
||||
{
|
||||
List<SaxSport.Data> allSports = DataCacheConsole.GetActiveSports();
|
||||
foreach (SaxSport.Data sport in allSports.Where(item => item.Name.EqualsCI(sportName)))
|
||||
{
|
||||
sportsData.Add(sport);
|
||||
if (!includeGroups) continue;
|
||||
foreach (SaxSport.Data sportParent in allSports.Where(item => item.Id.Equals(sport.SportIdParent)))
|
||||
sportsData.Add(sportParent);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Data cache is not available.
|
||||
// Query direct from the database (Admin).
|
||||
Dictionary<SysId, SaxSport> sports = new Dictionary<SysId, SaxSport>();
|
||||
|
||||
// Sport by name.
|
||||
SaxSport.Params prmSport = new SaxSport.Params();
|
||||
prmSport.NameFull = sportName;
|
||||
sports.AddRange(ReferenceMgr.GetSportList(prmSport).ToDictionary(item => item.Id));
|
||||
|
||||
if (includeGroups)
|
||||
{
|
||||
// Parent sports.
|
||||
prmSport = new SaxSport.Params();
|
||||
prmSport.IdsIncluded.AddIds(sports.Values.Where(item => SysId.IsValid(item.SportIdParent)).Select(item => item.SportIdParent));
|
||||
if (prmSport.IdsIncluded.Any())
|
||||
sports.AddRange(ReferenceMgr.GetSportList(prmSport).ToDictionary(item => item.Id));
|
||||
}
|
||||
sportsData = sports.Values.Select(item => item.GetData()).ToList();
|
||||
}
|
||||
return sportsData;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
}
|
||||
//=======================================================================
|
||||
}
|
||||
@@ -0,0 +1,222 @@
|
||||
using Microsoft.AspNetCore.Mvc.Filters;
|
||||
using Microsoft.Net.Http.Headers;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Serialization;
|
||||
using Sarand.Net.Standard.Base.App;
|
||||
using Sarand.Net.Standard.Base.Bus;
|
||||
using Sarand.Net.Standard.Base.Dbas;
|
||||
using Sarand.Net.Standard.Base.Helpers;
|
||||
using Sarand.Net.Standard.Base.Utils;
|
||||
using Saxonite.Net.Core.Web.Base.App;
|
||||
using Saxonite.Net.Core.Web.Base.Models;
|
||||
using Saxonite.Net.Standard.Base.App;
|
||||
using Saxonite.Net.Standard.Base.Consoles;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
|
||||
namespace Saxonite.Net.Core.Web.Base.Controllers
|
||||
{
|
||||
//=======================================================================
|
||||
public abstract class SaxController_Web : SaxController_Base
|
||||
{
|
||||
//-------------------------------------------------------------------
|
||||
// Data members.
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Protected construction.
|
||||
protected SaxController_Web(SaxLocaliser localiser) : base(localiser)
|
||||
{
|
||||
}
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
}
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Properties.
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Action execution events.
|
||||
//-------------------------------------------------------------------
|
||||
public override void OnActionExecuting(ActionExecutingContext filterContext)
|
||||
{
|
||||
//if (DebugMode) SaLogger.Debug($"{SysUtil.Fn}" + (ViewData.Model != null ? " Model: " + ViewData.Model : ""));
|
||||
|
||||
// Refreh model properties.
|
||||
SaxModel_Base baseModel = ViewData.Model as SaxModel_Base;
|
||||
RefreshModel(baseModel);
|
||||
|
||||
base.OnActionExecuting(filterContext);
|
||||
}
|
||||
public override void OnActionExecuted(ActionExecutedContext filterContext)
|
||||
{
|
||||
//if (DebugMode) SaLogger.Debug($"{SysUtil.Fn}" + (ViewData.Model != null ? " Model: " + ViewData.Model : ""));
|
||||
|
||||
// Refreh model properties.
|
||||
SaxModel_Base baseModel = ViewData.Model as SaxModel_Base;
|
||||
RefreshModel(baseModel);
|
||||
|
||||
// Store session data if present - as potentially modfied.
|
||||
if (SessionData != null)
|
||||
{
|
||||
// Most actions will store the session data in case it's been modified.
|
||||
// Some actions (eg. score password) don't need to.
|
||||
if (StoreSessionData)
|
||||
{
|
||||
String sessionDataJson = NewtonsoftJsonUtil.SerializeObject(SessionData);
|
||||
HttpContext.Session.Set(SessionStorage.SessionKey_SessionData, SessionStorage.sessionDataEncoding.GetBytes(sessionDataJson));
|
||||
}
|
||||
}
|
||||
else HttpContext.Session.Remove(SessionStorage.SessionKey_SessionData);
|
||||
|
||||
// Response headers.
|
||||
if (baseModel != null && baseModel.ProhibitCache)
|
||||
{
|
||||
if (Response.Headers.ContainsKey(HeaderNames.CacheControl))
|
||||
Response.Headers.Remove(HeaderNames.CacheControl);
|
||||
Response.Headers.Add(HeaderNames.CacheControl, "no-cache, no-store, must-revalidate");
|
||||
Response.Headers.Add(HeaderNames.Pragma, "no-cache");
|
||||
Response.Headers.Add(HeaderNames.Expires, "0");
|
||||
}
|
||||
|
||||
base.OnActionExecuted(filterContext);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Model.
|
||||
//-------------------------------------------------------------------
|
||||
protected void RefreshModel(SaxModel_Base model)
|
||||
{
|
||||
if (model == null) return;
|
||||
|
||||
// Session data.
|
||||
model.Controller = this;
|
||||
model.SessionData = SessionData;
|
||||
|
||||
// Redirect locations.
|
||||
model.RedirectLocation.Base = GetRedirectLocation(RedirectLocation.WebAppBase);
|
||||
model.RedirectLocation.Home = GetRedirectLocation(RedirectLocation.WebAppHome);
|
||||
model.RedirectLocation.Home_SessionExpired = GetRedirectLocation(RedirectLocation.WebAppHome_SessionExpired);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Online encryption parameters.
|
||||
//-------------------------------------------------------------------
|
||||
// Online Request Password encryption parameters are defined in
|
||||
// the base Controller so that they can be shared with the Admin application.
|
||||
protected static String Base64Key_RequestPassword_Online { get; } = SacsEncryptionHelper.EncodePlainKey("{~Saxonite@@Request^Password=}", SacsEncryptionHelper.KeyLength);
|
||||
protected const String Purpose_RequestPassword_Online = "Saxonite.Online.RequestPassword";
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Session.
|
||||
//-------------------------------------------------------------------
|
||||
private bool UserActiveRecorded { get; set; } = false;
|
||||
public bool ValidUserSession
|
||||
{
|
||||
get
|
||||
{
|
||||
if (SessionData == null || !SessionData.ValidUserSession) return false;
|
||||
SaxSessionDataConsole sessionDataConsole = SessionDataConsole;
|
||||
if (sessionDataConsole != null && !UserActiveRecorded)
|
||||
{
|
||||
// Record the user as active once per request.
|
||||
sessionDataConsole.RecordUserActive(SessionUserAccountId, CreatedAt);
|
||||
UserActiveRecorded = true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
public SysId SessionUserAccountId { get { return SessionData?.User?.UserAccountId ?? null; } }
|
||||
public DbUpdateInfo DbUpdateInfo { get { return SessionData?.DbUpdateInfo ?? new DbUpdateInfo(null, "", SaxSystem.ComputerName); } }
|
||||
// Referrer.
|
||||
public String Referer { get { return Request.Headers["Referer"].ToString(); } }
|
||||
public bool ValidReferer { get { return !StringUtil.IsEmpty(Referer); } }
|
||||
|
||||
/// <summary>Store session data, eg. to start a new user session on sign-in.</summary>
|
||||
protected bool SetSessionData(SaxSessionData sessionData)
|
||||
{
|
||||
if (sessionStorage.SessionData != null) return false;
|
||||
sessionStorage.SessionData = sessionData;
|
||||
return true;
|
||||
}
|
||||
protected void ClearSessionData()
|
||||
{
|
||||
if (HttpContext.Session.IsAvailable)
|
||||
HttpContext.Session.Clear();
|
||||
sessionStorage.SessionData = null;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Session storage.
|
||||
public class SessionStorage
|
||||
{
|
||||
public SaxSessionData SessionData { get; set; }
|
||||
public static String SessionKey_SessionData { get; } = "SaxSessionData";
|
||||
public static Encoding sessionDataEncoding { get; } = Encoding.UTF8;
|
||||
//JSON Serialisation.
|
||||
public class SaxSessionDataContractResolver : DefaultContractResolver
|
||||
{
|
||||
// To allow private properties to be deserialised.
|
||||
// NB Only applies to top level properties in the serialised object.
|
||||
protected override List<MemberInfo> GetSerializableMembers(Type objectType)
|
||||
{
|
||||
var flags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;
|
||||
MemberInfo[] fields = objectType.GetFields(flags);
|
||||
return fields
|
||||
.Concat(objectType.GetProperties(flags).Where(propInfo => propInfo.CanWrite))
|
||||
.ToList();
|
||||
}
|
||||
protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization)
|
||||
{
|
||||
return base.CreateProperties(type, MemberSerialization.Fields);
|
||||
}
|
||||
};
|
||||
public static JsonSerializerSettings JsonDeserialisationSettings = new JsonSerializerSettings
|
||||
{
|
||||
ContractResolver = new SaxSessionDataContractResolver(),
|
||||
// Force all deserialised objects to be replaced - to avoid proxy lists not populating.
|
||||
ObjectCreationHandling = ObjectCreationHandling.Replace
|
||||
};
|
||||
}
|
||||
private readonly SessionStorage sessionStorage = new SessionStorage();
|
||||
protected JsonSerializerSettings SaxSessionDataJsonSerializerSettings { get { return SessionStorage.JsonDeserialisationSettings; } }
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
public SaxSessionData SessionData
|
||||
{
|
||||
get
|
||||
{
|
||||
try
|
||||
{
|
||||
// Retrieve session data if not already in controller.
|
||||
if (sessionStorage.SessionData == null)
|
||||
{
|
||||
byte[] sessionDataBytes = null;
|
||||
HttpContext.Session.TryGetValue(SessionStorage.SessionKey_SessionData, out sessionDataBytes);
|
||||
if (sessionDataBytes != null)
|
||||
{
|
||||
String sessionDataJson = SessionStorage.sessionDataEncoding.GetString(sessionDataBytes);
|
||||
sessionStorage.SessionData = DeserializeSessionData(sessionDataJson);
|
||||
}
|
||||
}
|
||||
return sessionStorage.SessionData;
|
||||
}
|
||||
catch (Exception exc)
|
||||
{
|
||||
SaLogger.Warn($"{SysUtil.Fn} {exc.GetType().Name} - {exc.Message}{exc.GetStackEntries().Concat("", "\n\t")}");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
protected abstract SaxSessionData DeserializeSessionData(String sessionDataJson);
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
}
|
||||
//=======================================================================
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Sarand.Net.Standard.Base.Core;
|
||||
using Saxonite.Net.Standard.Base.App;
|
||||
using Saxonite.Net.Core.Web.Base.App;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using Sarand.Net.Standard.Base.Utils;
|
||||
|
||||
namespace Saxonite.Net.Core.Web.Base.Helpers
|
||||
{
|
||||
//=======================================================================
|
||||
public static class SaxAppConfigHelper
|
||||
{
|
||||
//-------------------------------------------------------------------
|
||||
public static Dictionary<String, SaxAppConfig> ExtractAppConfigs(IConfigurationSection appConfigsSection)
|
||||
{
|
||||
// NB The set of configurations will only allow one per context.
|
||||
// Only the last configuration found for each context will be stored (NB usually only one of each apart from 'Defaults').
|
||||
Dictionary<String, SaxAppConfig> appConfigs = new Dictionary<String, SaxAppConfig>();
|
||||
|
||||
// Start the list with a default 'Defaults' configuration - values set to application defaults (defined in Sax).
|
||||
// NB This can be overridden in each level of configuration.
|
||||
// Settings from the 'Defaults' configuration provide values where they are missing from other configurations.
|
||||
// NB Coverage may not be 100% - just where it's proven needed.
|
||||
SaxAppConfig defaultsAppConfig = new SaxAppConfig(Sax.Config.Context_Defaults, null, null);
|
||||
appConfigs.Add(defaultsAppConfig.Context, defaultsAppConfig);
|
||||
|
||||
// Load session configurations.
|
||||
foreach (ConfigurationSection appConfigSection in appConfigsSection.GetChildren())
|
||||
{
|
||||
if (StringUtil.IsEmpty(appConfigSection.Key)) continue;
|
||||
|
||||
// Extract the configuration, supplying current 'Defaults' to supply missing values, and add to the list.
|
||||
SaxAppConfig appConfig = new SaxAppConfig(appConfigSection.Key, appConfigSection, defaultsAppConfig);
|
||||
appConfigs.Remove(appConfigSection.Key);
|
||||
appConfigs.Add(appConfigSection.Key, appConfig);
|
||||
|
||||
// Replace the 'Defaults' configuration if this one matches the context.
|
||||
if (appConfig.Context.EqualsCI(Sax.Config.Context_Defaults))
|
||||
defaultsAppConfig = appConfig;
|
||||
}
|
||||
return appConfigs;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
}
|
||||
|
||||
//=======================================================================
|
||||
public static class AppConfigList
|
||||
{
|
||||
public static SaxAppConfig getConfigForApplication(this List<SaxAppConfig> appConfigs)
|
||||
{
|
||||
SaxAppConfig defaultsAppConfig = new SaxAppConfig("", null, null);
|
||||
SaxApplication_Base app = SaxGlobals.App;
|
||||
if (app != null)
|
||||
{
|
||||
foreach (SaxAppConfig appConfig in appConfigs)
|
||||
{
|
||||
if (appConfig.Environments.ContainsCI(app.EnvironmentName))
|
||||
return appConfig;
|
||||
if (appConfig.Context.EqualsCI(Sax.Config.Context_Defaults))
|
||||
defaultsAppConfig = appConfig;
|
||||
}
|
||||
}
|
||||
return defaultsAppConfig;
|
||||
}
|
||||
}
|
||||
|
||||
//=======================================================================
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Sarand.Net.Standard.Base.Core;
|
||||
using Sarand.Net.Standard.Base.Email;
|
||||
using Saxonite.Net.Standard.Base.App;
|
||||
using Saxonite.Net.Standard.Base.Bus;
|
||||
using Saxonite.Net.Core.Web.Base.App;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using Saxonite.Net.Standard.Base.Consoles;
|
||||
using Sarand.Net.Standard.Base.Utils;
|
||||
|
||||
namespace Saxonite.Net.Core.Web.Base.Helpers
|
||||
{
|
||||
//=======================================================================
|
||||
public static class SaxEmailConfigHelper
|
||||
{
|
||||
//-------------------------------------------------------------------
|
||||
/// <summary>Extract the email configurations from the application settings.</summary>
|
||||
public static Dictionary<String, SaxEmailConfig> ExtractEmailConfigs(IConfigurationSection emailConfigsSection)
|
||||
{
|
||||
Dictionary<String, SaxEmailConfig> emailConfigs = new Dictionary<String, SaxEmailConfig>();
|
||||
foreach (ConfigurationSection emailConfigSection in emailConfigsSection.GetChildren())
|
||||
{
|
||||
if (!StringUtil.IsEmpty(emailConfigSection.Key))
|
||||
emailConfigs.Add(emailConfigSection.Key, CreateEmailConfig(emailConfigSection.Key, emailConfigSection));
|
||||
}
|
||||
return emailConfigs;
|
||||
}
|
||||
private static SaxEmailConfig CreateEmailConfig(String context, ConfigurationSection emailConfigSection)
|
||||
{
|
||||
SaxEmailConfig emailConfig = new SaxEmailConfig(context);
|
||||
if (emailConfigSection != null)
|
||||
{
|
||||
IConfigurationSection message = emailConfigSection.GetSection("Message");
|
||||
emailConfig.Message.AddressFrom = message["AddressFrom"];
|
||||
foreach (var addressBcc in message.GetSection("AddressesBcc").GetChildren())
|
||||
emailConfig.Message.AddressesBcc.Add(StringUtil.TrimAll(addressBcc.Value));
|
||||
IConfigurationSection smtp = emailConfigSection.GetSection("SMTP");
|
||||
emailConfig.SMTP.Server = smtp["Server"];
|
||||
emailConfig.SMTP.ServerPort = StringUtil.ToInt(smtp["ServerPort"]);
|
||||
emailConfig.SMTP.UseSSL = StringUtil.ToBool(smtp["UseSSL"]);
|
||||
IConfigurationSection send = emailConfigSection.GetSection("Send");
|
||||
emailConfig.Send.Using = send["Using"];
|
||||
emailConfig.Send.UserName = send["UserName"];
|
||||
emailConfig.Send.Password = send["Password"];
|
||||
}
|
||||
return emailConfig;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Send email.
|
||||
public static bool SendEmail(SaEmailData emailData)
|
||||
{
|
||||
// ToDo return EmailConsole.SendEmail(emailData);
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
/// <summary>
|
||||
/// Replace dynamic tags in email message body.
|
||||
/// <para></para>
|
||||
/// </summary>
|
||||
public static void ReplaceDynamicEmailBodyTags(SaEmailData emailData, SaxSessionData sessionData, SaxUserAccount userAccount)
|
||||
{
|
||||
// Replace core tags, eg. main stylesheet.
|
||||
// ToDo. EmailConsole.ReplaceDynamicEmailTags(emailData);
|
||||
|
||||
// Replace tags known to the web application.
|
||||
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
}
|
||||
|
||||
//=======================================================================
|
||||
public static class EmailConfigList
|
||||
{
|
||||
public static SaxEmailConfig getConfigForSession(this List<SaxEmailConfig> emailConfigs, SaxAppConfig appConfig)
|
||||
{
|
||||
if (appConfig != null && !StringUtil.IsEmpty(appConfig.Email.Context))
|
||||
{
|
||||
foreach (SaxEmailConfig emailConfig in emailConfigs)
|
||||
{
|
||||
if (emailConfig.Context.EqualsCI(appConfig.Email.Context))
|
||||
return emailConfig;
|
||||
}
|
||||
}
|
||||
return new SaxEmailConfig("");
|
||||
}
|
||||
}
|
||||
|
||||
//=======================================================================
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
using Sarand.Net.Standard.Base.Helpers;
|
||||
using Sarand.Net.Standard.Base.Utils;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Saxonite.Net.Core.Web.Base.Helpers
|
||||
{
|
||||
//=======================================================================
|
||||
public static class SaxResourceHelper_Web
|
||||
{
|
||||
//-------------------------------------------------------------------
|
||||
// Definitions.
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Properties.
|
||||
public static Assembly MyAssembly { get; } = typeof(SaxResourceHelper_Web).GetTypeInfo().Assembly;
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Text resources.
|
||||
|
||||
/// <summary> Retrieve contents of text resource in this assembly by name.</summary>
|
||||
public static String GetResourceText(String resourceFilename, String partialPath = "")
|
||||
{
|
||||
if (!StringUtil.IsBlank(resourceFilename))
|
||||
{
|
||||
String resourceText = SacsResourceHelper.GetManifestResourceAsText(MyAssembly, partialPath, resourceFilename);
|
||||
if (!StringUtil.IsBlank(resourceText))
|
||||
return resourceText;
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Resource stream.
|
||||
|
||||
/// <summary>
|
||||
/// Retrieve stream to resource in this assembly.
|
||||
/// </summary>
|
||||
public static Stream GetResourceStream(String resourceFilename, String partialPath = "")
|
||||
{
|
||||
if (!StringUtil.IsBlank(resourceFilename))
|
||||
{
|
||||
return SacsResourceHelper.GetManifestResourceStream(MyAssembly, partialPath, resourceFilename);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
}
|
||||
//=======================================================================
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
using Microsoft.AspNetCore.Authentication;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Options;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Net;
|
||||
using System.Text;
|
||||
using System.Text.Encodings.Web;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Saxonite.Net.Core.Web.Base.Middleware
|
||||
{
|
||||
//=======================================================================
|
||||
// Authentication handler required to allow actions to issue Forbid() responses.
|
||||
// Ref. https://stackoverflow.com/questions/54578426/why-do-i-need-to-set-a-defaultforbidscheme/54587054#54587054
|
||||
//=======================================================================
|
||||
public class SaxAuthenticationHandler : AuthenticationHandler<AuthenticationSchemeOptions>
|
||||
{
|
||||
//-------------------------------------------------------------------
|
||||
// Data members.
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
public SaxAuthenticationHandler(IOptionsMonitor<AuthenticationSchemeOptions> options, ILoggerFactory logger, UrlEncoder encoder, ISystemClock clock) :
|
||||
base(options, logger, encoder, clock)
|
||||
{
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
protected override Task HandleForbiddenAsync(AuthenticationProperties properties)
|
||||
{
|
||||
Context.Response.StatusCode = (int)HttpStatusCode.Forbidden;
|
||||
return base.HandleForbiddenAsync(properties);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
protected override async Task<AuthenticateResult> HandleAuthenticateAsync()
|
||||
{
|
||||
// NoOp task to avoid compiler warning.
|
||||
await Task.CompletedTask;
|
||||
Context.Response.StatusCode = (int)HttpStatusCode.Unauthorized;
|
||||
return AuthenticateResult.NoResult();
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
}
|
||||
//=======================================================================
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
using Microsoft.AspNetCore.Mvc.ModelBinding.Metadata;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace Saxonite.Net.Core.Web.Base.Middleware
|
||||
{
|
||||
//=======================================================================
|
||||
/// <summary>
|
||||
/// Force blank form values to be populated to the model as empty strings rather than null values.
|
||||
/// </summary>
|
||||
public class SaxMetadataProvider : IMetadataDetailsProvider, IDisplayMetadataProvider
|
||||
{
|
||||
public void CreateDisplayMetadata(DisplayMetadataProviderContext context)
|
||||
{
|
||||
if (context.Key.MetadataKind == ModelMetadataKind.Property)
|
||||
{
|
||||
context.DisplayMetadata.ConvertEmptyStringToNull = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
//=======================================================================
|
||||
}
|
||||
@@ -0,0 +1,116 @@
|
||||
using Microsoft.AspNetCore.Mvc.ModelBinding;
|
||||
using Microsoft.AspNetCore.Mvc.ModelBinding.Binders;
|
||||
using Sarand.Net.Standard.Base.App;
|
||||
using Sarand.Net.Standard.Base.Core;
|
||||
using Sarand.Net.Standard.Base.Utils;
|
||||
using Saxonite.Net.Core.Web.Base.App;
|
||||
using Saxonite.Net.Standard.Base.App;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using static Saxonite.Net.Standard.Base.App.Sax.Config.Security;
|
||||
|
||||
// Ignore obsolete warning on ComplexTypeModelBinder.
|
||||
#pragma warning disable 0618
|
||||
|
||||
namespace Saxonite.Net.Core.Web.Base.Middleware
|
||||
{
|
||||
//=======================================================================
|
||||
/// <summary>
|
||||
/// Maps a browser request to a data object. Default class provides a base implementation of a model binder.
|
||||
/// <para>Overridden to trim whitespace from input values.</para>
|
||||
/// </summary>
|
||||
public class SaxModelBinder : ComplexTypeModelBinder
|
||||
{
|
||||
//-------------------------------------------------------------------
|
||||
// Construction.
|
||||
public SaxModelBinder(IDictionary<ModelMetadata, IModelBinder> propertyBinders, Microsoft.Extensions.Logging.ILoggerFactory loggerFactory) :
|
||||
base(propertyBinders, loggerFactory)
|
||||
{
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
/// <summary>
|
||||
/// Creates the model with one (or more) injected service parameters.
|
||||
/// </summary>
|
||||
protected override object CreateModel(ModelBindingContext bindingContext)
|
||||
{
|
||||
var services = bindingContext.HttpContext.RequestServices;
|
||||
var modelType = bindingContext.ModelType;
|
||||
var ctors = modelType.GetConstructors();
|
||||
foreach (var ctor in ctors)
|
||||
{
|
||||
var paramTypes = ctor.GetParameters().Select(p => p.ParameterType).ToList();
|
||||
var parameters = paramTypes.Select(p => services.GetService(p)).ToArray();
|
||||
if (parameters.All(p => p != null))
|
||||
{
|
||||
var model = ctor.Invoke(parameters);
|
||||
return model;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
/// <summary>
|
||||
/// Intercept String properties and trim whitespace.
|
||||
/// </summary>
|
||||
protected override void SetProperty(ModelBindingContext bindingContext, string modelName, ModelMetadata propertyMetadata, ModelBindingResult result)
|
||||
{
|
||||
//if (SaxSystem.DebugMode) Logger.Debug(fn + " Form property " + modelName + ": '" + result.Model.ToString() + ".");
|
||||
object originalValue = result.Model;
|
||||
// Anything that looks like a password will be left as is.
|
||||
bool password = modelName.ContainsCI("Password");
|
||||
// Exclude properties that retain leading/trailing whitespace.
|
||||
if (result.Model is string)
|
||||
{
|
||||
if (!password)
|
||||
{
|
||||
string value = result.Model as string;
|
||||
|
||||
// Trim leading and trailing whitespace.
|
||||
value = StringUtil.TrimAll(value);
|
||||
|
||||
// Check for multi-line.
|
||||
if (value.Contains('\n'))
|
||||
{
|
||||
// Simplify line delimiters.
|
||||
value = Regex.Replace(value, "\\r\\n", "\n");
|
||||
// Remove white space in front of newlines.
|
||||
value = Regex.Replace(value, "\\s+\\n", "\n");
|
||||
// Remove multiple newlines.
|
||||
value = Regex.Replace(value, "\\n+", "\n");
|
||||
}
|
||||
|
||||
// Email addresses must be lowercase to ensure match to encrypted data.
|
||||
if (modelName.EqualsCI("EmailAddress") || modelName.EqualsCI("AccountEmailAddress"))
|
||||
value = value.ToLower();
|
||||
|
||||
// Uppercase selected values.
|
||||
if (modelName.EqualsCI("Postcode") || modelName.EqualsCI("AccountPostcode") || modelName.EqualsCI("RegisteredAddressPostcode"))
|
||||
value = value.ToUpper();
|
||||
|
||||
// Assign resulting value.
|
||||
result = ModelBindingResult.Success(value);
|
||||
}
|
||||
}
|
||||
// Log property details.
|
||||
if (SaxSystem.DebugMode &&
|
||||
// Ignore blank values.
|
||||
result.Model != null && !StringUtil.IsBlank(result.Model.ToString()) &&
|
||||
// Ignore passwords.
|
||||
!password &&
|
||||
// Ignore items that correspond with objects in the model rather than values.
|
||||
!result.Model.ToString().Equals(result.Model.GetType().FullName) &&
|
||||
// Ignore form files.
|
||||
!result.Model.ToString().ContainsCI("Microsoft.AspNetCore.Http.IFormFile"))
|
||||
SaLogger.Debug(SysUtil.Fn + " Form property " + modelName + ": '" + result.Model.ToString() + "'." + (originalValue != null && !originalValue.Equals(result.Model) ? " Original value: '" + originalValue.ToString() + "'" : ""));
|
||||
base.SetProperty(bindingContext, modelName, propertyMetadata, result);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
}
|
||||
//=======================================================================
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
using Microsoft.AspNetCore.Mvc.ModelBinding;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace Saxonite.Net.Core.Web.Base.Middleware
|
||||
{
|
||||
//=======================================================================
|
||||
/// <summary>
|
||||
/// Maps a browser request to a data object. Default class provides a base implementation of a model binder.
|
||||
/// <para>Overridden to trim whitespace from input values.</para>
|
||||
/// </summary>
|
||||
public class SaxModelBinderProvider : IModelBinderProvider
|
||||
{
|
||||
//-------------------------------------------------------------------
|
||||
// Data members.
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Construction.
|
||||
public SaxModelBinderProvider()
|
||||
{
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
public IModelBinder GetBinder(ModelBinderProviderContext context)
|
||||
{
|
||||
if (context == null) throw new ArgumentNullException(nameof(context));
|
||||
|
||||
if (context.Metadata.IsComplexType && !context.Metadata.IsCollectionType)
|
||||
{
|
||||
var propertyBinders = context.Metadata.Properties.ToDictionary(property => property, context.CreateBinder);
|
||||
ILoggerFactory loggerFactory = (ILoggerFactory)context.Services.GetService(typeof(ILoggerFactory));
|
||||
return new SaxModelBinder(propertyBinders, loggerFactory);
|
||||
}
|
||||
|
||||
// Default - return null so that default binding provider is used.
|
||||
return null;
|
||||
}
|
||||
}
|
||||
//=======================================================================
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
using Microsoft.AspNetCore.Antiforgery;
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Sarand.Net.Standard.Base.App;
|
||||
using Sarand.Net.Standard.Base.Core;
|
||||
using Sarand.Net.Standard.Base.Utils;
|
||||
using Saxonite.Net.Standard.Base.App;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Saxonite.Net.Core.Web.Base.Middleware
|
||||
{
|
||||
//=======================================================================
|
||||
/// <summary>
|
||||
/// Extend IApplicationBuilder class to use the anit-forgery token validation middleware.
|
||||
/// </summary>
|
||||
public static class ApplicationBuilderExtensions
|
||||
{
|
||||
public static IApplicationBuilder UseAntiforgeryTokens(this IApplicationBuilder app)
|
||||
{
|
||||
return app.UseMiddleware<ValidateAntiForgeryTokenMiddleware>();
|
||||
}
|
||||
}
|
||||
|
||||
//=======================================================================
|
||||
/// <summary>
|
||||
/// Ensure relevant actions validate the anti-forgery token, eg. post requests.
|
||||
/// </summary>
|
||||
public class ValidateAntiForgeryTokenMiddleware
|
||||
{
|
||||
private readonly RequestDelegate _next;
|
||||
private readonly IAntiforgery _antiforgery;
|
||||
|
||||
public ValidateAntiForgeryTokenMiddleware(RequestDelegate next, IAntiforgery antiforgery)
|
||||
{
|
||||
_next = next;
|
||||
_antiforgery = antiforgery;
|
||||
}
|
||||
|
||||
public async Task Invoke(HttpContext context)
|
||||
{
|
||||
String fn = GetType().Name + ".Invoke";
|
||||
|
||||
// Log action.
|
||||
//String rawTarget = context.Features.Get<IHttpRequestFeature>().RawTarget;
|
||||
if (SaxSystem.DebugMode) SaLogger.Trace(fn + " Action: '" + Regex.Replace(context.Request.Path.ToString(), "^/", "") + "'. Method: " + context.Request.Method);
|
||||
|
||||
// Intercept POST requests and apply anti-forgery test.
|
||||
if (HttpMethods.IsPost(context.Request.Method))
|
||||
{
|
||||
await _antiforgery.ValidateRequestAsync(context);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
await _next(context);
|
||||
}
|
||||
catch (Exception exc)
|
||||
{
|
||||
SaLogger.Warn(fn + " " + ExceptionUtil.GetLogMessage(exc));
|
||||
throw;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//=======================================================================
|
||||
}
|
||||
@@ -0,0 +1,441 @@
|
||||
using Microsoft.AspNetCore.Html;
|
||||
using Microsoft.AspNetCore.Mvc.ModelBinding.Validation;
|
||||
using Microsoft.AspNetCore.Mvc.Rendering;
|
||||
using Sacs.Web.Components;
|
||||
using Sarand.Net.Standard.Base.App;
|
||||
using Sarand.Net.Standard.Base.Bus;
|
||||
using Sarand.Net.Standard.Base.Core;
|
||||
using Sarand.Net.Standard.Base.Dbas;
|
||||
using Sarand.Net.Standard.Base.Utils;
|
||||
using Saxonite.Base.App;
|
||||
using Saxonite.Net.Core.Web.Base.App;
|
||||
using Saxonite.Net.Core.Web.Base.Controllers;
|
||||
using Saxonite.Net.Standard.Base.App;
|
||||
using Saxonite.Net.Standard.Base.Bus;
|
||||
using Saxonite.Net.Standard.Base.Consoles;
|
||||
using Saxonite.Net.Standard.Base.Mgr;
|
||||
using Saxonite.Net.Standard.Base.Mgr.Reference;
|
||||
using Saxonite.Net.Standard.Base.Mgr.Support;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using static Saxonite.Net.Standard.Base.App.Sax;
|
||||
|
||||
namespace Saxonite.Net.Core.Web.Base.Models
|
||||
{
|
||||
//=======================================================================
|
||||
public class SaxModel_Base : SaModel
|
||||
{
|
||||
//-------------------------------------------------------------------
|
||||
// Data members.
|
||||
private SaxInternals internals;
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Protected construction.
|
||||
protected SaxModel_Base(SaxLocaliser localiser)
|
||||
{
|
||||
Localiser = localiser;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Application properties.
|
||||
private SaxApplication_Web App { get { return SaxApplication_Web.WebApp; } }
|
||||
protected SaxAppConfig AppConfig { get { return App.AppConfig; } }
|
||||
protected SaxSystem_Web System { get { return App.System_Web; } }
|
||||
public String SessionCookieName { get { return App.SessionCookieName; } }
|
||||
public SaxLocaliser Localiser { get; }
|
||||
public override String GetText(String textKey, String defaultText)
|
||||
{
|
||||
String text = Localiser[textKey];
|
||||
if (StringUtil.IsBlank(text) || text.EqualsCI(textKey))
|
||||
return defaultText;
|
||||
return text;
|
||||
}
|
||||
// Session properties.
|
||||
public SaxSessionData SessionData { get; set; }
|
||||
public SaxSessionContext SessionContext { get { return SessionData?.SessionContext ?? App.SessionContext; } }
|
||||
public DbUpdateInfo DbUpdateInfo { get { return SessionData?.DbUpdateInfo ?? new DbUpdateInfo(null, "", SaxSystem.ComputerName); } }
|
||||
// Request properties.
|
||||
public SaxController_Base Controller { get; set; }
|
||||
public CultureInfo SessionCulture { get { return Controller?.SessionCulture ?? CultureInfo.InvariantCulture; } }
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Page configuration.
|
||||
public String Version { get { return SaxSystem.DebugMode ? $"v{Sax.Version.GetFullVersion()}" : $"v{Sax.Version.GetAppVersion()}"; } }
|
||||
public String InstanceVersion { get { return (!StringUtil.IsEmpty(App.AppConfig.Instance) ? App.AppConfig.Instance + " " : "") + $"{Version}"; } }
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Business components.
|
||||
public SaxInternals Internals { get { if (internals == null) internals = new SaxInternals(SessionContext); return internals; } }
|
||||
// Consoles.
|
||||
protected SaxDataCacheConsole DataCacheConsole { get { return Internals.DataCacheConsole; } }
|
||||
protected SaxSessionDataConsole SessionDataConsole { get { return Internals.SessionDataConsole; } }
|
||||
protected SaxActivityConsole ActivityConsole { get { return Internals.ActivityConsole; } }
|
||||
// Managers.
|
||||
public SaxReferenceMgr ReferenceMgr { get { return Internals.ReferenceMgr; } }
|
||||
public SaxAccountMgr AccountMgr { get { return Internals.AccountMgr; } }
|
||||
public SaxActivityMgr ActivityMgr { get { return Internals.ActivityMgr; } }
|
||||
public SaxItemDataMgr ItemDataMgr { get { return Internals.ItemDataMgr; } }
|
||||
public SaxReferenceGolfMgr ReferenceGolfMgr { get { return Internals.ReferenceGolfMgr; } }
|
||||
public SaxSupportMgr SupportMgr { get { return Internals.SupportMgr; } }
|
||||
// System codes.
|
||||
public List<TypeCodeDesc> DataItemTypeCodes { get { return Internals.DataItemTypeCodes; } }
|
||||
public List<TypeCodeDesc> YesNoCodes { get { return Internals.YesNoCodes; } }
|
||||
public List<TypeCodeDesc> SportGroupingCodes { get { return Internals.SportGroupingCodes; } }
|
||||
public List<TypeCodeDesc> SportSpecialityLabelCodes { get { return Internals.SportSpecialityLabelCodes; } }
|
||||
public List<TypeCodeDesc> SportContactTypeCodes { get { return Internals.SportContactTypeCodes; } }
|
||||
public List<TypeCodeDesc> SportParticipatingCodes { get { return Internals.SportParticipatingCodes; } }
|
||||
public List<TypeCodeDesc> SportPreparingCodes { get { return Internals.SportPreparingCodes; } }
|
||||
public List<TypeCodeDesc> SportOfficiatingCodes { get { return Internals.SportOfficiatingCodes; } }
|
||||
public List<TypeCodeDesc> RegionTypeCodes { get { return Internals.RegionTypeCodes; } }
|
||||
public List<TypeCodeDesc> EligibilityTypeCodes { get { return Internals.EligibilityTypeCodes; } }
|
||||
public List<TypeCodeDesc> UserRoleCodes { get { return Internals.UserRoleCodes; } }
|
||||
public List<TypeCodeDesc> OrganisationTypeCodes { get { return Internals.OrganisationTypeCodes; } }
|
||||
public List<TypeCodeDesc> OrganisationCategoryCodes { get { return Internals.OrganisationCategoryCodes; } }
|
||||
public List<TypeCodeDesc> OrganisationRoleCodes { get { return Internals.OrganisationRoleCodes; } }
|
||||
public List<TypeCodeDesc> AssociationTypeCodes { get { return Internals.AssociationTypeCodes; } }
|
||||
public List<TypeCodeDesc> AddressTypeCodes { get { return Internals.AddressTypeCodes; } }
|
||||
public List<TypeCodeDesc> ContactMethodCodes { get { return Internals.ContactMethodCodes; } }
|
||||
public List<TypeCodeDesc> EventTypeCodes { get { return Internals.EventTypeCodes; } }
|
||||
public List<TypeCodeDesc> OpportunityTypeCodes { get { return Internals.OpportunityTypeCodes; } }
|
||||
public List<TypeCodeDesc> ActivityReactionCodes { get { return Internals.ActivityReactionCodes; } }
|
||||
// Support.
|
||||
public List<TypeCodeDesc> UserReportTypeCodes { get { return Internals.UserReportTypeCodes; } }
|
||||
public List<TypeCodeDesc> SupportItemProcessTypeCodes { get { return Internals.SupportItemProcessTypeCodes; } }
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Common data components.
|
||||
// User Accounts.
|
||||
public SaxUserAccount GetUserAccount(SysId userAccountId)
|
||||
{
|
||||
return Internals.GetUserAccount(userAccountId);
|
||||
}
|
||||
public String GetUserAccountDisplayName(SysId userAccountId)
|
||||
{
|
||||
return Internals.GetUserAccountDisplayName(userAccountId);
|
||||
}
|
||||
// Organisations.
|
||||
public SaxOrganisation GetOrganisation(SysId organisationId)
|
||||
{
|
||||
return Internals.GetOrganisation(organisationId);
|
||||
}
|
||||
public String GetOrganisationName(SysId organisationId)
|
||||
{
|
||||
return Internals.GetOrganisationName(organisationId);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Security.
|
||||
public bool ValidUserSession { get { return SessionData?.ValidUserSession ?? false; } }
|
||||
public bool AwaitingLogin { get { return !ValidUserSession; } }
|
||||
public bool KeepLoggedIn { get { return !AwaitingLogin && SessionData.User.KeepLoggedIn; } }
|
||||
/// <summary>Maximum length allowed for password entry: sign-up, change password etc.</summary>
|
||||
public int PasswordMaxLength { get; } = 32;
|
||||
|
||||
// Account actions.
|
||||
// NB The form proerty will never be used - account actions processed within page.
|
||||
public String AccountAction { get; set; }
|
||||
public IEnumerable<SelectListItem> GetAccountActions()
|
||||
{
|
||||
List<CodeDesc> items = new List<CodeDesc>();
|
||||
if (SessionData?.ValidUserSession ?? false)
|
||||
{
|
||||
items.Add("Profile", Localiser["label.view.profile"]);
|
||||
items.Add("ChangePassword", Localiser["label.change.password"]);
|
||||
items.Add("SignOut", Localiser["label.sign.out"]);
|
||||
}
|
||||
return new SelectList(items, "Code", "Desc");
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Link URLs.
|
||||
public class LinksData
|
||||
{
|
||||
public String Facebook { get; } = "https://www.facebook.com/sportierre/";
|
||||
public String LinkedIn { get; } = "https://www.linkedin.com/company/sportierre/about/";
|
||||
}
|
||||
public LinksData Links { get; } = new LinksData();
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Copyright notice.
|
||||
public HtmlString CopyrightNotice
|
||||
{
|
||||
get
|
||||
{
|
||||
int initialYear = 2020;
|
||||
int currentYear = DateTime.Today.Year;
|
||||
return Localiser.GetHtmlText("copyright.symbol.year.html", (initialYear != currentYear ? initialYear + "-" : "") + currentYear.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
/// <summary>
|
||||
/// Form control value max length.
|
||||
/// <para>In many cases the database columns allow plenty of extra space for the value, in case they need to be encrypted.</para>
|
||||
/// <para>Hence, several cases where the value entered in the control isn't allowed the full database length.</para>
|
||||
/// </summary>
|
||||
public int GetControlMaxLength(SaxDbDfn_Core.ColumnIdx column)
|
||||
{
|
||||
int maxLength = (int)SaxDbDfn_Core.GetColTextLen(column);
|
||||
switch (column)
|
||||
{
|
||||
case SaxDbDfn_Core.ColumnIdx.UserAccount_EmailAddress:
|
||||
return Math.Min(maxLength, 60);
|
||||
case SaxDbDfn_Core.ColumnIdx.UserAccount_FirstName:
|
||||
case SaxDbDfn_Core.ColumnIdx.UserAccount_LastName:
|
||||
return Math.Min(maxLength, 40);
|
||||
case SaxDbDfn_Core.ColumnIdx.UserAccount_About:
|
||||
return Math.Min(maxLength, 2000);
|
||||
case SaxDbDfn_Core.ColumnIdx.Organisation_Name:
|
||||
return Math.Min(maxLength, 80);
|
||||
case SaxDbDfn_Core.ColumnIdx.Organisation_About:
|
||||
case SaxDbDfn_Core.ColumnIdx.Organisation_Facilities:
|
||||
case SaxDbDfn_Core.ColumnIdx.Organisation_Notes:
|
||||
return Math.Min(maxLength, 2000);
|
||||
case SaxDbDfn_Core.ColumnIdx.UserAccount_PhoneMain:
|
||||
case SaxDbDfn_Core.ColumnIdx.UserAccount_PhoneMobile:
|
||||
return Math.Min(maxLength, 20);
|
||||
//case SaxDbDfn.ColumnIdx.UserAccount_Postcode:
|
||||
//case SaxDbDfn.ColumnIdx.ItemAddress_Postcode:
|
||||
// return Math.Min(maxLength, 16);
|
||||
case SaxDbDfn_Core.ColumnIdx.Article_Headline:
|
||||
return Math.Min(maxLength, 2000);
|
||||
case SaxDbDfn_Core.ColumnIdx.Article_Summary:
|
||||
return Math.Min(maxLength, 1000);
|
||||
}
|
||||
return maxLength;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Form control value max length - support database.
|
||||
/// <para>In many cases the database columns allow plenty of extra space for the value, in case they need to be encrypted.</para>
|
||||
/// <para>Hence, several cases where the value entered in the control isn't allowed the full database length.</para>
|
||||
/// </summary>
|
||||
public int GetControlMaxLength(SaxDbDfn_Support.ColumnIdx column)
|
||||
{
|
||||
int maxLength = (int)SaxDbDfn_Support.GetColTextLen(column);
|
||||
switch (column)
|
||||
{
|
||||
case SaxDbDfn_Support.ColumnIdx.UserReport_Title:
|
||||
break;
|
||||
}
|
||||
return maxLength;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Display data - Dates.
|
||||
public String FormatDateForDisplay(DateTime value)
|
||||
{
|
||||
return FormatDateForDisplay((DateTime?)value);
|
||||
}
|
||||
public String FormatDateForDisplay(DateTime? value)
|
||||
{
|
||||
return DateUtil.Format(value, "d-MMM-yy", SessionCulture);
|
||||
}
|
||||
public String FormatDateTimeForDisplay(DateTime value)
|
||||
{
|
||||
return FormatDateTimeForDisplay((DateTime?)value);
|
||||
}
|
||||
public String FormatDateTimeForDisplay(DateTime? value)
|
||||
{
|
||||
return StringUtil.TrimAll(DateUtil.Format(value, "d-MMM-yy HH:mm", SessionCulture));
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Form data - Dates.
|
||||
// Format may depend on locale, but as long as these methods are used consistently,
|
||||
// there should be consistent formatting, display and parsing of date values.
|
||||
public String CalendarDateFormat
|
||||
{
|
||||
get
|
||||
{
|
||||
// JQuery-UI DatePicker date format.
|
||||
// Format:
|
||||
// d Single digit day of month
|
||||
// dd Double digit day of month
|
||||
// D 3 letter day of week abbreviation.
|
||||
// DD Day of week.
|
||||
// m Single digit month.
|
||||
// mm Double digit month.
|
||||
// M 3 letter month abbreviation.
|
||||
// MM Month name.
|
||||
// yy 4 digit year.
|
||||
// Examples:
|
||||
// dd/mm/yy 07/04/2012
|
||||
// dd-M-yy 07-Apr-2012
|
||||
// d-M-yy 7-Apr-2012
|
||||
return "dd-M-yy";
|
||||
}
|
||||
}
|
||||
public String FormatDateForForm(DateTime? value)
|
||||
{
|
||||
return DateUtil.Format(value, "dd-MMM-yyyy", SessionCulture);
|
||||
}
|
||||
public DateTime ParseDateFromForm(String value)
|
||||
{
|
||||
DateTime date = DateUtil.ParseExact(value, "dd-MMM-yyyy", SessionCulture);
|
||||
if (!date.IsValid())
|
||||
date = DateUtil.ParseExact(value, "dd-MMM-yyyy", CultureInfo.CurrentUICulture);
|
||||
if (!date.IsValid())
|
||||
date = DateUtil.ParseExact(value, "dd-MMM-yyyy", CultureInfo.CurrentCulture);
|
||||
if (!date.IsValid())
|
||||
date = DateUtil.ParseExact(value, "dd-MMM-yyyy", CultureInfo.InvariantCulture);
|
||||
return date;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Form data.
|
||||
//-------------------------------------------------------------------
|
||||
// Common form values.
|
||||
public String FormAction { get; set; }
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
/// <summary>List of Yes/No options for dropdown.</summary>
|
||||
public IEnumerable<SelectListItem> YesNoOptionsForSelect
|
||||
{
|
||||
get
|
||||
{
|
||||
List<SelectListItem> values = new List<SelectListItem>();
|
||||
foreach (TypeCodeDesc yesNo in YesNoCodes)
|
||||
values.Add(new SelectListItem(Localiser.GetYesNoCaption((Sax.YesNo)yesNo.Type), yesNo.Code));
|
||||
return values;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>List of Sport Grouping for dropdown.</summary>
|
||||
public IEnumerable<SelectListItem> SportGroupingCodesForSelect
|
||||
{
|
||||
get
|
||||
{
|
||||
List<SelectListItem> values = new List<SelectListItem>();
|
||||
foreach (TypeCodeDesc sportGrouping in SportGroupingCodes)
|
||||
values.Add(new SelectListItem(Localiser.GetSportGroupingCaption((Sax.SportGrouping)sportGrouping.Type), sportGrouping.Code));
|
||||
return values;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>List of Sport Speciality Labels for dropdown.</summary>
|
||||
public IEnumerable<SelectListItem> SportSpecialityLabelCodesForSelect
|
||||
{
|
||||
get
|
||||
{
|
||||
List<SelectListItem> values = new List<SelectListItem>();
|
||||
values.Add(new SelectListItem("Default", ""));
|
||||
foreach (TypeCodeDesc sportSpecialityLabel in SportSpecialityLabelCodes)
|
||||
values.Add(new SelectListItem(Localiser.GetSportSpecialityLabelCaption((Sax.SportSpecialityLabel)sportSpecialityLabel.Type), sportSpecialityLabel.Code));
|
||||
return values;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>List of Sport Participating options for dropdown.</summary>
|
||||
public IEnumerable<SelectListItem> SportParticipatingCodesForSelect
|
||||
{
|
||||
get
|
||||
{
|
||||
List<SelectListItem> values = new List<SelectListItem>();
|
||||
foreach (TypeCodeDesc sportParticipating in SportParticipatingCodes)
|
||||
values.Add(new SelectListItem(Localiser.GetSportParticipatingCaption((Sax.SportParticipating)sportParticipating.Type), sportParticipating.Code));
|
||||
return values;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>List of Sport Preparing options for dropdown.</summary>
|
||||
public IEnumerable<SelectListItem> SportPreparingCodesForSelect
|
||||
{
|
||||
get
|
||||
{
|
||||
List<SelectListItem> values = new List<SelectListItem>();
|
||||
foreach (TypeCodeDesc sportPreparing in SportPreparingCodes)
|
||||
values.Add(new SelectListItem(Localiser.GetSportPreparingCaption((Sax.SportPreparing)sportPreparing.Type), sportPreparing.Code));
|
||||
return values;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>List of Sport Officiating options for dropdown.</summary>
|
||||
public IEnumerable<SelectListItem> SportOfficiatingCodesForSelect
|
||||
{
|
||||
get
|
||||
{
|
||||
List<SelectListItem> values = new List<SelectListItem>();
|
||||
foreach (TypeCodeDesc sportOfficiating in SportOfficiatingCodes)
|
||||
values.Add(new SelectListItem(Localiser.GetSportOfficiatingCaption((Sax.SportOfficiating)sportOfficiating.Type), sportOfficiating.Code));
|
||||
return values;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>List of Region Types for dropdown.</summary>
|
||||
public IEnumerable<SelectListItem> RegionTypesForSelect
|
||||
{
|
||||
get
|
||||
{
|
||||
List<SelectListItem> values = new List<SelectListItem>();
|
||||
foreach (TypeCodeDesc organisationType in RegionTypeCodes.FindAll(item => item.Type != (int)Sax.RegionType.Universe && item.Type != (int)Sax.RegionType.Galaxy))
|
||||
values.Add(new SelectListItem(Localiser.GetRegionTypeCaption((Sax.RegionType)organisationType.Type), organisationType.Code));
|
||||
return values;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>List of titles for dropdown.</summary>
|
||||
public IEnumerable<SelectListItem> TitlesForSelect
|
||||
{
|
||||
get { return new SelectList(SaxSystem.GetCodesOfType(Sax.CodeType.Title), "Code", "Desc"); }
|
||||
}
|
||||
|
||||
/// <summary>List of eligibility types for dropdown.</summary>
|
||||
public IEnumerable<SelectListItem> EligibilityTypesForSelect
|
||||
{
|
||||
get
|
||||
{
|
||||
List<SelectListItem> values = new List<SelectListItem>();
|
||||
foreach (TypeCodeDesc eligibilityType in Internals.EligibilityTypeCodes)
|
||||
values.Add(new SelectListItem(Localiser.GetEligibilityTypeCaption((Sax.EligibilityType)eligibilityType.Type), eligibilityType.Code));
|
||||
return values;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>List of Organisation Types for dropdown.</summary>
|
||||
public IEnumerable<SelectListItem> OrganisationTypesForSelect
|
||||
{
|
||||
get
|
||||
{
|
||||
List<SelectListItem> values = new List<SelectListItem>();
|
||||
foreach (TypeCodeDesc organisationType in OrganisationTypeCodes)
|
||||
values.Add(new SelectListItem(Localiser.GetOrganisationTypeCaption((Sax.OrganisationType)organisationType.Type), organisationType.Code));
|
||||
return values;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// List of Organisation Categories for dropdown.
|
||||
/// <para>NB Does not include 'Partner' or 'Other'.</para>
|
||||
/// </summary>
|
||||
public IEnumerable<SelectListItem> OrganisationCategoriesForSelect
|
||||
{
|
||||
get
|
||||
{
|
||||
List<SelectListItem> values = new List<SelectListItem>();
|
||||
foreach (TypeCodeDesc organisationCategory in OrganisationCategoryCodes.FindAll(item => item.Type != (int)Sax.OrganisationCategory.Partner && item.Type != (int)Sax.OrganisationCategory.Other))
|
||||
values.Add(new SelectListItem(Localiser.GetOrganisationCategoryCaption((Sax.OrganisationCategory)organisationCategory.Type), organisationCategory.Code));
|
||||
return values;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// List of Organisation Categories for Admin dropdown.
|
||||
/// <para>Includes complete set of categories.</para>
|
||||
/// </summary>
|
||||
public IEnumerable<SelectListItem> AdminOrganisationCategoriesForSelect
|
||||
{
|
||||
get
|
||||
{
|
||||
List<SelectListItem> values = new List<SelectListItem>();
|
||||
foreach (TypeCodeDesc organisationCategory in OrganisationCategoryCodes)
|
||||
values.Add(new SelectListItem(Localiser.GetOrganisationCategoryCaption((Sax.OrganisationCategory)organisationCategory.Type), organisationCategory.Code));
|
||||
return values;
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
}
|
||||
//=======================================================================
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Sarand.Net.Standard.Base.Core;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
|
||||
namespace Saxonite.Net.Core.Web.Base.Procs.Data
|
||||
{
|
||||
//=======================================================================
|
||||
/// <summary>
|
||||
/// Object to persist upload file after request has terminated, and the Form File has been disposed.
|
||||
/// <para>- Too allow async processes to access the file after request completed.</para>
|
||||
/// </summary>
|
||||
public class UploadFileData
|
||||
{
|
||||
//-------------------------------------------------------------------
|
||||
public UploadFileData(IFormFile dataFile)
|
||||
{
|
||||
ContentDisposition = dataFile.ContentDisposition;
|
||||
ContentType = dataFile.ContentType;
|
||||
FileName = dataFile.FileName;
|
||||
Length = dataFile.Length;
|
||||
Name = dataFile.Name;
|
||||
foreach (var header in dataFile.Headers)
|
||||
Headers.Add(header.Key, header.Value.ToString());
|
||||
// Load file data.
|
||||
using (MemoryStream stream = new MemoryStream())
|
||||
{
|
||||
dataFile.CopyTo(stream);
|
||||
FileData = stream.ToArray();
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Properties.
|
||||
|
||||
/// <summary>Gets the raw Content-Disposition header of the uploaded file.</summary>
|
||||
public String ContentDisposition { get; }
|
||||
|
||||
/// <summary>Gets the raw Content-Type header of the uploaded file.</summary>
|
||||
public String ContentType { get; }
|
||||
|
||||
/// <summary>Gets the file name from the Content-Disposition header.</summary>
|
||||
public String FileName { get; }
|
||||
|
||||
/// <summary>Gets the header dictionary of the uploaded file.</summary>
|
||||
public Dictionary<String, String> Headers { get; } = new Dictionary<String, String>();
|
||||
|
||||
/// <summary>Gets the file length in bytes.</summary>
|
||||
public long Length { get; }
|
||||
|
||||
/// <summary>Gets the form field name from the Content-Disposition header.</summary>
|
||||
public String Name { get; }
|
||||
|
||||
/// <summary>File data.</summary>
|
||||
public byte[] FileData { get; }
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
}
|
||||
//=======================================================================
|
||||
}
|
||||
+341
@@ -0,0 +1,341 @@
|
||||
using DocumentFormat.OpenXml.Drawing.Diagrams;
|
||||
using DocumentFormat.OpenXml.Office2016.Excel;
|
||||
using Sarand.Net.Standard.Base.App;
|
||||
using Sarand.Net.Standard.Base.Bus;
|
||||
using Sarand.Net.Standard.Base.Core;
|
||||
using Sarand.Net.Standard.Base.Dbas;
|
||||
using Sarand.Net.Standard.Base.Helpers;
|
||||
using Sarand.Net.Standard.Base.Tasks;
|
||||
using Sarand.Net.Standard.Base.Utils;
|
||||
using Saxonite.Net.Standard.Base.App;
|
||||
using Saxonite.Net.Standard.Base.Bus.Reference;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Saxonite.Net.Core.Web.Base.Procs
|
||||
{
|
||||
//=======================================================================
|
||||
partial class SaxGolfUsgaDataLookup
|
||||
{
|
||||
//-------------------------------------------------------------------
|
||||
private class ScheduledUsgaDataLookupControlData
|
||||
{
|
||||
public DateTime CountriesLastLookedUp { get; set; } = DateTime.Now;
|
||||
}
|
||||
private static ScheduledUsgaDataLookupControlData usgaDataLookupControl { get; } = new ScheduledUsgaDataLookupControlData();
|
||||
|
||||
/// <summary>
|
||||
/// Determine which USGA data population process to run.
|
||||
/// <para>- Method is invoked periodically (every 20 mins) by the Admin Hosted Service Console.</para>
|
||||
/// <para>- 1. Populate countries if not already done or not done for a while (eg. 24 hours).</para>
|
||||
/// <para>- 2. Populate provinces for a Country that has none or occasionally refresh one that has.</para>
|
||||
/// <para>- 3. Populate Courses for a Province that has none or occasionally refresh one that has.</para>
|
||||
/// <para>- 4. Populate Markers for a Course that has none or occasionally refresh one that has.</para>
|
||||
/// </summary>
|
||||
public static void ExecuteScheduledUsgaDataLookup(SaxSessionContext sessionContext, DbUpdateInfo dbUpdateInfo, SacsTaskData taskData)
|
||||
{
|
||||
SaLogger.Debug($"{SysUtil.Fn}");
|
||||
|
||||
using (DisposableCollection<IDisposable> disposableItems = new DisposableCollection<IDisposable>())
|
||||
{
|
||||
SaxInternals internals = new SaxInternals(sessionContext);
|
||||
disposableItems.Add(internals);
|
||||
|
||||
// Configure process.
|
||||
SaxGolfUsgaDataLookup.Config courseLookupConfig = new SaxGolfUsgaDataLookup.Config(sessionContext, dbUpdateInfo);
|
||||
SaxGolfUsgaDataLookup usgaDataLookup = new SaxGolfUsgaDataLookup(courseLookupConfig);
|
||||
|
||||
if (taskData.IsCancellationRequested) return;
|
||||
|
||||
// Determine which process to run.
|
||||
|
||||
//-----------------------------------------------------------
|
||||
// 1. Countries.
|
||||
{
|
||||
// Check USGA country population.
|
||||
List<SaxGolfUsgaCountry> usgaCountries = internals.ReferenceGolfMgr.GetUsgaCountryList(new SaxGolfUsgaCountry.Params());
|
||||
if (!usgaCountries.Any() || (DateTime.Now - usgaDataLookupControl.CountriesLastLookedUp).TotalHours > MathUtil.Constrain(Sax.Config.Admin.Processes.Scheduled.UsgaGolfDataLookup.HoursBetweenCountryLookup, 1, 24 * 7))
|
||||
{
|
||||
// No countries currently found or long enough since last lookup.
|
||||
// Lookup USGA countries.
|
||||
List<SaxGolfUsgaDataLookup.CountryData> countriesData = usgaDataLookup.LookupUsgaCountries();
|
||||
SaLogger.Info($"{SysUtil.Fn} USGA Countries populated: {countriesData.Count}.", true);
|
||||
usgaDataLookupControl.CountriesLastLookedUp = DateTime.Now;
|
||||
return;
|
||||
}
|
||||
if (taskData.IsCancellationRequested) return;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------
|
||||
// 2. Provinces.
|
||||
|
||||
// 2a. Population of active priority Country with no Provinces.
|
||||
{
|
||||
bool populatePriorityCountryNoProvinces = SacsRandomHelper.GetInt32(1, 5) == 1;
|
||||
if (populatePriorityCountryNoProvinces)
|
||||
{
|
||||
SaxGolfUsgaCountry.Params prmCountry = new SaxGolfUsgaCountry.Params();
|
||||
prmCountry.PriorityFlagState = SacsHierarchyItem.Params.FlagState.True;
|
||||
prmCountry.HasProvinces = SacsHierarchyItem.Params.BoolState.False;
|
||||
prmCountry.StatusCat = SaxGolfUsgaCountry.StatusCat.ActiveOnly;
|
||||
prmCountry.ResultsPaging.Set(1, 4);
|
||||
prmCountry.RandomOrder = true;
|
||||
List<SaxGolfUsgaCountry> countriesNoProvinces = internals.ReferenceGolfMgr.GetUsgaCountryList(prmCountry).Randomise();
|
||||
disposableItems.AddRange(countriesNoProvinces);
|
||||
if (countriesNoProvinces.Any())
|
||||
{
|
||||
SaxGolfUsgaCountry usgaCountry = countriesNoProvinces[0];
|
||||
List<SaxGolfUsgaDataLookup.ProvinceData> provincesData = usgaDataLookup.LookupUsgaProvincesForCountry(usgaCountry.CountryCode);
|
||||
SaLogger.Info($"{SysUtil.Fn} USGA Provinces populated for {usgaCountry.CountryCode} {usgaCountry.CountryName}" + (usgaCountry.Priority ? " [Priority]" : "") + $": {provincesData.Count}.", true);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 2b. Refresh active priority Country with Provinces.
|
||||
{
|
||||
bool refreshPriorityCountryWithProvinces = SacsRandomHelper.GetInt32(1, 25) == 1;
|
||||
if (refreshPriorityCountryWithProvinces)
|
||||
{
|
||||
SaxGolfUsgaCountry.Params prmCountry = new SaxGolfUsgaCountry.Params();
|
||||
prmCountry.PriorityFlagState = SacsHierarchyItem.Params.FlagState.True;
|
||||
prmCountry.HasProvinces = SacsHierarchyItem.Params.BoolState.True;
|
||||
prmCountry.StatusCat = SaxGolfUsgaCountry.StatusCat.ActiveOnly;
|
||||
prmCountry.ResultsPaging.Set(1, 4);
|
||||
prmCountry.RandomOrder = true;
|
||||
List<SaxGolfUsgaCountry> countriesWithProvinces = internals.ReferenceGolfMgr.GetUsgaCountryList(prmCountry).Randomise();
|
||||
disposableItems.AddRange(countriesWithProvinces);
|
||||
if (countriesWithProvinces.Any())
|
||||
{
|
||||
SaxGolfUsgaCountry usgaCountry = countriesWithProvinces[0];
|
||||
List<SaxGolfUsgaDataLookup.ProvinceData> provincesData = usgaDataLookup.LookupUsgaProvincesForCountry(usgaCountry.CountryCode);
|
||||
SaLogger.Info($"{SysUtil.Fn} USGA Provinces refreshed for {usgaCountry.CountryCode} {usgaCountry.CountryName}" + (usgaCountry.Priority ? " [Priority]" : "") + $": {provincesData.Count}.", true);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------
|
||||
// 3. Courses.
|
||||
|
||||
// 3a. Populate active priority Province with no Facilities (Courses).
|
||||
{
|
||||
bool populatePriorityProvinceNoFacilities = SacsRandomHelper.GetInt32(1, 4) == 1;
|
||||
if (populatePriorityProvinceNoFacilities)
|
||||
{
|
||||
// Active priority Provinces with no Facilities.
|
||||
SaxGolfUsgaProvince.Params prmProvince = new SaxGolfUsgaProvince.Params();
|
||||
prmProvince.PriorityFlagState = SacsHierarchyItem.Params.FlagState.True;
|
||||
prmProvince.HasFacilities = SacsHierarchyItem.Params.BoolState.False;
|
||||
prmProvince.StatusCat = SaxGolfUsgaProvince.StatusCat.ActiveOnly;
|
||||
prmProvince.ResultsPaging.Set(1, 4);
|
||||
prmProvince.RandomOrder = true;
|
||||
List<SaxGolfUsgaProvince> provincesNoFacilities = internals.ReferenceGolfMgr.GetUsgaProvinceList(prmProvince).Randomise();
|
||||
disposableItems.AddRange(provincesNoFacilities);
|
||||
if (provincesNoFacilities.Any())
|
||||
{
|
||||
// Province has no Facilities - populate courses.
|
||||
SaxGolfUsgaProvince usgaProvince = provincesNoFacilities[0];
|
||||
List<SaxGolfUsgaDataLookup.CourseData> coursesData = LookupUsgaCourses(internals, usgaDataLookup, usgaProvince, false);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 3b. Refresh active priority Province with Facilities (courses).
|
||||
{
|
||||
bool refreshProvinceWithFacilities = SacsRandomHelper.GetInt32(1, 21) == 1;
|
||||
if (refreshProvinceWithFacilities)
|
||||
{
|
||||
SaxGolfUsgaProvince.Params prmProvince = new SaxGolfUsgaProvince.Params();
|
||||
prmProvince.PriorityFlagState = SacsHierarchyItem.Params.FlagState.True;
|
||||
prmProvince.HasFacilities = SacsHierarchyItem.Params.BoolState.True;
|
||||
prmProvince.StatusCat = SaxGolfUsgaProvince.StatusCat.ActiveOnly;
|
||||
prmProvince.ResultsPaging.Set(1, 4);
|
||||
prmProvince.RandomOrder = true;
|
||||
List<SaxGolfUsgaProvince> provincesWithFacilities = internals.ReferenceGolfMgr.GetUsgaProvinceList(prmProvince).Randomise();
|
||||
disposableItems.AddRange(provincesWithFacilities);
|
||||
if (provincesWithFacilities.Any())
|
||||
{
|
||||
SaxGolfUsgaProvince usgaProvince = provincesWithFacilities[0];
|
||||
List<SaxGolfUsgaDataLookup.CourseData> coursesData = LookupUsgaCourses(internals, usgaDataLookup, usgaProvince, true);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------
|
||||
// 4. Markers.
|
||||
|
||||
// 4a. Populate active priority Course with no Markers.
|
||||
{
|
||||
bool populatePriorityCourseNoMarkers = SacsRandomHelper.GetInt32(1, 2) == 1;
|
||||
if (populatePriorityCourseNoMarkers)
|
||||
{
|
||||
SaxGolfUsgaCourse.Params prmCourse = new SaxGolfUsgaCourse.Params();
|
||||
prmCourse.PriorityFlagState = SacsHierarchyItem.Params.FlagState.True;
|
||||
prmCourse.HasMarkers = SacsHierarchyItem.Params.BoolState.False;
|
||||
prmCourse.StatusCat = SaxGolfUsgaCourse.StatusCat.ActiveOnly;
|
||||
prmCourse.ResultsPaging.Set(1, 4);
|
||||
prmCourse.RandomOrder = true;
|
||||
List<SaxGolfUsgaCourse> coursesNoMarkers = internals.ReferenceGolfMgr.GetUsgaCourseList(prmCourse).Randomise();
|
||||
disposableItems.AddRange(coursesNoMarkers);
|
||||
if (coursesNoMarkers.Any())
|
||||
{
|
||||
SaxGolfUsgaCourse usgaCourse = coursesNoMarkers[0];
|
||||
List<SaxGolfUsgaDataLookup.MarkerData> markersData = LookupUsgaMarkers(internals, usgaDataLookup, usgaCourse, false);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 4b. Refresh active priority Course with Markers.
|
||||
{
|
||||
bool refreshPriorityCourseWithMarkers = SacsRandomHelper.GetInt32(1, 17) == 1;
|
||||
if (refreshPriorityCourseWithMarkers)
|
||||
{
|
||||
// Active priority Course with no Markers.
|
||||
SaxGolfUsgaCourse.Params prmCourse = new SaxGolfUsgaCourse.Params();
|
||||
prmCourse.PriorityFlagState = SacsHierarchyItem.Params.FlagState.True;
|
||||
prmCourse.HasMarkers = SacsHierarchyItem.Params.BoolState.True;
|
||||
prmCourse.StatusCat = SaxGolfUsgaCourse.StatusCat.ActiveOnly;
|
||||
prmCourse.ResultsPaging.Set(1, 4);
|
||||
prmCourse.RandomOrder = true;
|
||||
List<SaxGolfUsgaCourse> coursesWithMarkers = internals.ReferenceGolfMgr.GetUsgaCourseList(prmCourse).Randomise();
|
||||
disposableItems.AddRange(coursesWithMarkers);
|
||||
if (coursesWithMarkers.Any())
|
||||
{
|
||||
// Refresh first Course with Markers.
|
||||
SaxGolfUsgaCourse usgaCourse = coursesWithMarkers[0];
|
||||
List<SaxGolfUsgaDataLookup.MarkerData> markersData = LookupUsgaMarkers(internals, usgaDataLookup, usgaCourse, true);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------
|
||||
// 5. Fallback population.
|
||||
|
||||
// 5a. Active Country with no Provinces.
|
||||
{
|
||||
bool populateCountryNoProvinces = SacsRandomHelper.GetInt32(1, 17) == 1;
|
||||
if (populateCountryNoProvinces)
|
||||
{
|
||||
SaxGolfUsgaCountry.Params prmCountry = new SaxGolfUsgaCountry.Params();
|
||||
prmCountry.HasProvinces = SacsHierarchyItem.Params.BoolState.False;
|
||||
prmCountry.StatusCat = SaxGolfUsgaCountry.StatusCat.ActiveOnly;
|
||||
prmCountry.ResultsPaging.Set(1,4);
|
||||
prmCountry.RandomOrder = true;
|
||||
List<SaxGolfUsgaCountry> countriesNoProvinces = internals.ReferenceGolfMgr.GetUsgaCountryList(prmCountry).Randomise();
|
||||
disposableItems.AddRange(countriesNoProvinces);
|
||||
if (countriesNoProvinces.Any())
|
||||
{
|
||||
SaxGolfUsgaCountry usgaCountry = countriesNoProvinces[0];
|
||||
List<SaxGolfUsgaDataLookup.ProvinceData> provincesData = usgaDataLookup.LookupUsgaProvincesForCountry(usgaCountry.CountryCode);
|
||||
SaLogger.Info($"{SysUtil.Fn} USGA Provinces populated for {usgaCountry.CountryCode} {usgaCountry.CountryName} [Fallback]: {provincesData.Count}.", true);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 5b. Active Province with no Facilities (courses).
|
||||
{
|
||||
bool populateProvinceNoFacilities = SacsRandomHelper.GetInt32(1, 3) == 1;
|
||||
if (populateProvinceNoFacilities)
|
||||
{
|
||||
// Active Provinces with no Facilities.
|
||||
SaxGolfUsgaProvince.Params prmProvince = new SaxGolfUsgaProvince.Params();
|
||||
prmProvince.HasFacilities = SacsHierarchyItem.Params.BoolState.False;
|
||||
prmProvince.StatusCat = SaxGolfUsgaProvince.StatusCat.ActiveOnly;
|
||||
prmProvince.ResultsPaging.Set(1, 4);
|
||||
prmProvince.RandomOrder = true;
|
||||
List<SaxGolfUsgaProvince> provincesNoFacilities = internals.ReferenceGolfMgr.GetUsgaProvinceList(prmProvince).Randomise();
|
||||
disposableItems.AddRange(provincesNoFacilities);
|
||||
if (provincesNoFacilities.Any())
|
||||
{
|
||||
// Province has no Facilities - populate courses.
|
||||
SaxGolfUsgaProvince usgaProvince = provincesNoFacilities[0];
|
||||
List<SaxGolfUsgaDataLookup.CourseData> coursesData = LookupUsgaCourses(internals, usgaDataLookup, usgaProvince, false, true);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 5c. Populate active Course with no Markers.
|
||||
{
|
||||
bool populateCourseNoMarkers = SacsRandomHelper.GetInt32(1, 2) == 1;
|
||||
if (populateCourseNoMarkers)
|
||||
{
|
||||
SaxGolfUsgaCourse.Params prmCourse = new SaxGolfUsgaCourse.Params();
|
||||
prmCourse.HasMarkers = SacsHierarchyItem.Params.BoolState.False;
|
||||
prmCourse.StatusCat = SaxGolfUsgaCourse.StatusCat.ActiveOnly;
|
||||
prmCourse.ResultsPaging.Set(1, 4);
|
||||
prmCourse.RandomOrder = true;
|
||||
List<SaxGolfUsgaCourse> coursesNoMarkers = internals.ReferenceGolfMgr.GetUsgaCourseList(prmCourse).Randomise();
|
||||
disposableItems.AddRange(coursesNoMarkers);
|
||||
if (coursesNoMarkers.Any())
|
||||
{
|
||||
SaxGolfUsgaCourse usgaCourse = coursesNoMarkers[0];
|
||||
List<SaxGolfUsgaDataLookup.MarkerData> markersData = LookupUsgaMarkers(internals, usgaDataLookup, usgaCourse, false, true);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------
|
||||
|
||||
SaLogger.Warn($"{SysUtil.Fn} No data population task found to execute.");
|
||||
|
||||
//-----------------------------------------------------------
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
private static List<SaxGolfUsgaDataLookup.CourseData> LookupUsgaCourses(SaxInternals internals, SaxGolfUsgaDataLookup usgaDataLookup, SaxGolfUsgaProvince usgaProvince, bool refresh, bool fallback = false)
|
||||
{
|
||||
List<SaxGolfUsgaDataLookup.CourseData> coursesData = new List<CourseData>();
|
||||
SaxGolfUsgaCountry usgaCountry = internals.ReferenceGolfMgr.GetUsgaCountryById(usgaProvince.CountryId);
|
||||
if (usgaCountry != null)
|
||||
{
|
||||
coursesData = usgaDataLookup.LookupUsgaCoursesForCountryAndProvince(usgaCountry.CountryCode, usgaProvince.ProvinceCode);
|
||||
List<String> annotations = new List<string>();
|
||||
if (usgaProvince.Priority) annotations.Add("Priority");
|
||||
if (fallback) annotations.Add("Fallback");
|
||||
SaLogger.Info($"{SysUtil.Fn} USGA Courses refreshed for {usgaCountry.CountryCode} {usgaCountry.CountryName} - {usgaProvince.ProvinceCode} {usgaProvince.ProvinceName}" + (annotations.Any() ? $" [{annotations.Concat(", ")}]" : "") + $": {coursesData.Count}.", true);
|
||||
}
|
||||
else SaLogger.Error($"{SysUtil.Fn} USGA Country not found for Id {usgaProvince.CountryId} for Province {usgaProvince.ProvinceCode} {usgaProvince.ProvinceName}.");
|
||||
return coursesData;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
private static List<SaxGolfUsgaDataLookup.MarkerData> LookupUsgaMarkers(SaxInternals internals, SaxGolfUsgaDataLookup usgaDataLookup, SaxGolfUsgaCourse usgaCourse, bool refresh, bool fallback = false)
|
||||
{
|
||||
SaxGolfUsgaFacility usgaFacility = internals.ReferenceGolfMgr.GetUsgaFacilityById(usgaCourse.FacilityId);
|
||||
SaxGolfUsgaProvince usgaProvince = internals.ReferenceGolfMgr.GetUsgaProvinceById(usgaFacility?.ProvinceId);
|
||||
SaxGolfUsgaCountry usgaCountry = internals.ReferenceGolfMgr.GetUsgaCountryById(usgaProvince?.CountryId);
|
||||
List<SaxGolfUsgaDataLookup.MarkerData> markersData = new List<MarkerData>();
|
||||
if (usgaFacility != null)
|
||||
{
|
||||
if (usgaProvince != null)
|
||||
{
|
||||
if (usgaCountry != null)
|
||||
{
|
||||
markersData = usgaDataLookup.LookupUsgaMarkersForCourse(usgaCourse.UsgaCourseId);
|
||||
List<String> annotations = new List<string>();
|
||||
if (usgaCourse.Priority) annotations.Add("Priority");
|
||||
if (fallback) annotations.Add("Fallback");
|
||||
SaLogger.Info($"{SysUtil.Fn} USGA Markers " + (refresh ? "refreshed" : "populated") + $" for {usgaCountry.CountryCode} {usgaCountry.CountryName} - {usgaProvince.ProvinceCode} {usgaProvince.ProvinceName} - {usgaCourse.Caption} [Id: {usgaCourse.UsgaCourseId}" + (annotations.Any() ? $"{annotations.Concat("", ", ")}" : "") + $"]: {markersData.Count}.", true);
|
||||
}
|
||||
else SaLogger.Error($"{SysUtil.Fn} Missing Country for Province {usgaProvince.ProvinceName}. Country Id: {usgaProvince.CountryId}.");
|
||||
}
|
||||
else SaLogger.Error($"{SysUtil.Fn} Missing Province for Facility {usgaFacility.FacilityName}. Province Id: {usgaFacility.ProvinceId}.");
|
||||
}
|
||||
else SaLogger.Error($"{SysUtil.Fn} Missing Facility for Course {usgaCourse.FullName}. Facility Id: {usgaCourse.FacilityId}.");
|
||||
return markersData;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
}
|
||||
//=======================================================================
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,178 @@
|
||||
using DocumentFormat.OpenXml.InkML;
|
||||
using HtmlAgilityPack;
|
||||
using MailKit;
|
||||
using Microsoft.Net.Http.Headers;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using Sarand.Net.Standard.Base.App;
|
||||
using Sarand.Net.Standard.Base.Bus;
|
||||
using Sarand.Net.Standard.Base.Core;
|
||||
using Sarand.Net.Standard.Base.Dbas;
|
||||
using Sarand.Net.Standard.Base.Helpers;
|
||||
using Sarand.Net.Standard.Base.Net;
|
||||
using Sarand.Net.Standard.Base.Utils;
|
||||
using Saxonite.Net.Core.Web.Base.Controllers;
|
||||
using Saxonite.Net.Standard.Base.App;
|
||||
using Saxonite.Net.Standard.Base.Bus;
|
||||
using Saxonite.Net.Standard.Base.Bus.Reference;
|
||||
using Saxonite.Net.Standard.Base.Mgr.Reference;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading;
|
||||
|
||||
namespace Saxonite.Net.Core.Web.Base.Procs
|
||||
{
|
||||
//======================================================================
|
||||
public partial class SaxOrganisationEventsLookup : SaxProcess_Web
|
||||
{
|
||||
//-------------------------------------------------------------------
|
||||
// Definitions.
|
||||
public enum Task
|
||||
{
|
||||
LookupEvents
|
||||
}
|
||||
|
||||
public new class Config : SaxProcess_Web.Config
|
||||
{
|
||||
public Config(SaxSessionContext sessionContext, DbUpdateInfo dbUpdateInfo) : base(sessionContext, dbUpdateInfo)
|
||||
{ }
|
||||
/// <summary>Organisations.</summary>
|
||||
public HashSet<SysId> OrganisationIdsIncluded { get; } = new HashSet<SysId>();
|
||||
/// <summary>Tasks to be run under this instance of the USGA Data Lookup process.</summary>
|
||||
public HashSet<Task> Tasks { get; } = new HashSet<Task>();
|
||||
}
|
||||
|
||||
private class EventData
|
||||
{
|
||||
public DateTime EventAt { get; set; }
|
||||
public String Caption { get; set; }
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Data members.
|
||||
private Config config;
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Construction.
|
||||
public SaxOrganisationEventsLookup(Config config) : base(config)
|
||||
{
|
||||
this.config = config;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Properties.
|
||||
|
||||
public override string ProcessDescription => "Organisation Events Lookup";
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Run the process.
|
||||
protected override bool Run()
|
||||
{
|
||||
// Execute selected tasks.
|
||||
foreach (Task task in config.Tasks)
|
||||
{
|
||||
switch (task)
|
||||
{
|
||||
case Task.LookupEvents:
|
||||
LookupEventsForOrganisations();
|
||||
break;
|
||||
}
|
||||
if (!OK) break;
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------
|
||||
// Event lookup.
|
||||
//------------------------------------------------------------------
|
||||
|
||||
/// <summary>
|
||||
/// Organisation event lookup.
|
||||
/// </summary>
|
||||
private bool LookupEventsForOrganisations()
|
||||
{
|
||||
if (!OK) return false;
|
||||
|
||||
using (DisposableCollection<IDisposable> disposableItems = new DisposableCollection<IDisposable>())
|
||||
{
|
||||
foreach (SysId organisationId in config.OrganisationIdsIncluded)
|
||||
{
|
||||
SaxOrganisation organisation = AccountMgr.GetOrganisationById(organisationId);
|
||||
if (organisation == null)
|
||||
{
|
||||
AddWarningMessage($"Organisation not found for Id: {organisationId}.");
|
||||
continue;
|
||||
}
|
||||
LookupOrganisationEvents(organisation);
|
||||
}
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Organisation event lookup.
|
||||
/// </summary>
|
||||
private bool LookupOrganisationEvents(SaxOrganisation organisation)
|
||||
{
|
||||
List<EventData> eventsData = new List<EventData>();
|
||||
|
||||
try
|
||||
{
|
||||
|
||||
|
||||
// Query Countries on USGA website.
|
||||
CancellationToken cancelToken = new CancellationToken();
|
||||
SacsHttpRequestData request = new SacsHttpRequestData(cancelToken) { Url = "https://ncrdb.usga.org/" };
|
||||
SacsHttpResponseData response = SacsHttpClient.DoRequest(request).Result;
|
||||
String data = response.Data;
|
||||
|
||||
if (!StringUtil.IsBlank(response.Data))
|
||||
{
|
||||
// Parse HTML.
|
||||
HtmlDocument htmlDoc = new HtmlDocument();
|
||||
htmlDoc.LoadHtml(response.Data);
|
||||
|
||||
// Identify type of event schedule on page.
|
||||
HtmlNode mobiscrollEventCalendarNode = htmlDoc.GetElementbyId("mobiscroll-event-calendar");
|
||||
if (mobiscrollEventCalendarNode != null)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
if (eventsData.Any())
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
catch (Exception exc)
|
||||
{
|
||||
SaLogger.Warn($"{SysUtil.Fn} {ExceptionUtil.GetLogMessage(exc, "querying organisation events", 8)}");
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Organisation event lookup by MobiScroll calendar.
|
||||
/// </summary>
|
||||
private bool LookupOrganisationEvents_MobiScrollCalendar(SaxOrganisation organisation, List<EventData> eventsData, HtmlNode calendarNode)
|
||||
{
|
||||
|
||||
HtmlNode headerNode = calendarNode.Descendants("div").First(node => node.HasClass("mbsc-calendar-header"));
|
||||
if (headerNode != null)
|
||||
{
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------
|
||||
}
|
||||
//======================================================================
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
using Sarand.Net.Standard.Base.Dbas;
|
||||
using Sarand.Net.Standard.Proc.Excel;
|
||||
using Saxonite.Net.Standard.Base.App;
|
||||
using Saxonite.Net.Standard.Base.Procs;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Saxonite.Net.Core.Web.Base.Procs
|
||||
{
|
||||
//=======================================================================
|
||||
public abstract class SaxProcess_Web : SaxProcess_Base
|
||||
{
|
||||
//-------------------------------------------------------------------
|
||||
// Definitions.
|
||||
public new class Config : SaxProcess_Base.Config
|
||||
{
|
||||
protected Config(SaxSessionContext sessionContext, DbUpdateInfo dbUpdateInfo) : base(sessionContext, dbUpdateInfo)
|
||||
{ }
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Data members.
|
||||
private Config config;
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Construction.
|
||||
protected SaxProcess_Web(Config config) : base(config)
|
||||
{
|
||||
this.config = config;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Excel Spreadsheet utilities.
|
||||
//-------------------------------------------------------------------
|
||||
protected override SaMsExcelColumnHeading_Config GetExcelColumnHeadingConfig()
|
||||
{
|
||||
SaMsExcelColumnHeading_Config configHeading = base.GetExcelColumnHeadingConfig();
|
||||
return configHeading;
|
||||
}
|
||||
|
||||
protected override SaMsExcelStyleAttr GetExcelDefaultWorkbookStyle()
|
||||
{
|
||||
SaMsExcelStyleAttr styleAttr = base.GetExcelDefaultWorkbookStyle();
|
||||
return styleAttr;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
}
|
||||
//=======================================================================
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net10.0</TargetFramework>
|
||||
<RootNamespace>Saxonite.Net.Core.Web</RootNamespace>
|
||||
</PropertyGroup>
|
||||
|
||||
<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="..\SaxoniteStandardBase\SaxoniteStandardBase.csproj" />
|
||||
<ProjectReference Include="..\SaxoniteStandardDbas\SaxoniteStandardDbas.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Folder Include="Base\Core\" />
|
||||
<Folder Include="Resources\" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<FrameworkReference Include="Microsoft.AspNetCore.App" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="HtmlAgilityPack" Version="1.13.1" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation" Version="10.0.13" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Include="Resources\**\*.*" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"version": 1,
|
||||
"isRoot": true,
|
||||
"tools": {
|
||||
"dotnet-ef": {
|
||||
"version": "5.0.5",
|
||||
"commands": [
|
||||
"dotnet-ef"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Saxonite.Net.Core.Web.Admin.App
|
||||
{
|
||||
//=======================================================================
|
||||
public class Program
|
||||
{
|
||||
//-------------------------------------------------------------------
|
||||
public static void Main(string[] args)
|
||||
{
|
||||
try
|
||||
{
|
||||
CreateHostBuilder(args).Build().Run();
|
||||
}
|
||||
finally
|
||||
{
|
||||
// Cleanup - globals, async processes etc.
|
||||
if (SaxApplication_Admin.AppInstance != null)
|
||||
SaxApplication_Admin.AppInstance.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
public static IHostBuilder CreateHostBuilder(string[] args) =>
|
||||
Host.CreateDefaultBuilder(args)
|
||||
.ConfigureWebHostDefaults(webBuilder =>
|
||||
{
|
||||
webBuilder.UseStartup<SaxStartup_Admin>();
|
||||
});
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
}
|
||||
//=======================================================================
|
||||
}
|
||||
@@ -0,0 +1,245 @@
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using Sarand.Net.Standard.Base.App;
|
||||
using Sarand.Net.Standard.Base.Bus;
|
||||
using Sarand.Net.Standard.Base.Core;
|
||||
using Sarand.Net.Standard.Base.Dbas;
|
||||
using Sarand.Net.Standard.Base.Email;
|
||||
using Sarand.Net.Standard.Base.IO;
|
||||
using Sarand.Net.Standard.Base.Utils;
|
||||
using Sarand.Net.Standard.Dbas.Base;
|
||||
using Saxonite.Net.Core.Web.Admin.Consoles;
|
||||
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.Bus;
|
||||
using Saxonite.Net.Standard.Base.Consoles;
|
||||
using Saxonite.Net.Standard.Base.Helpers;
|
||||
using Saxonite.Net.Standard.Base.Mgr;
|
||||
using Saxonite.Net.Standard.Dbas.App;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Saxonite.Net.Core.Web.Admin.App
|
||||
{
|
||||
//=======================================================================
|
||||
public class SaxApplication_Admin : SaxApplication_Web
|
||||
{
|
||||
//-------------------------------------------------------------------
|
||||
// Data members.
|
||||
private bool generateDatabaseDefinitions = true;
|
||||
private bool populateRegions = false;
|
||||
private Dictionary<String, SaxAppConfig> appConfigs = new Dictionary<string, SaxAppConfig>();
|
||||
private Dictionary<String, SaxEmailConfig> emailConfigs = new Dictionary<string, SaxEmailConfig>();
|
||||
// Session contexts.
|
||||
private class SessionContextData_Admin : SessionContextData_Web
|
||||
{
|
||||
public SessionContextData_Admin(SaxSessionContext_Web sessionContext) : base(sessionContext) { }
|
||||
}
|
||||
private readonly Dictionary<int, SessionContextData_Admin> sessionContexts = new Dictionary<int, SessionContextData_Admin>();
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Construction.
|
||||
public SaxApplication_Admin(IConfiguration configuration) : base(Sax.Application.Admin)
|
||||
{
|
||||
InitialiseTemporaryLoggingFolder();
|
||||
try
|
||||
{
|
||||
AppInstance = this;
|
||||
Configuration = configuration;
|
||||
ConsoleHelper_Admin = new SaxConsoleHelper_Admin(this);
|
||||
}
|
||||
catch (Exception exc)
|
||||
{
|
||||
SaLogger.Error($"{GetType().Name}.CTR {ExceptionUtil.GetErrorStateMessage(exc)}");
|
||||
throw;
|
||||
}
|
||||
}
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
// Clear globals.
|
||||
AppInstance = null;
|
||||
// Console helper.
|
||||
if (ConsoleHelper_Admin != null)
|
||||
ConsoleHelper_Admin.Dispose();
|
||||
ConsoleHelper_Admin = null;
|
||||
}
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Properties.
|
||||
public static SaxApplication_Admin AppInstance { get; private set; }
|
||||
public override SaxConsoleHelper ConsoleHelper { get { return ConsoleHelper_Admin; } }
|
||||
public SaxConsoleHelper_Admin ConsoleHelper_Admin { 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.Admin.Session.Cookie.Name; } }
|
||||
// Startup messages - for debugging. See Admin.Views._Layout.
|
||||
public List<String> Messages { get; } = new List<String>();
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Initialisation.
|
||||
/// <summary>Initialise environment - from Startup.</summary>
|
||||
internal void InitWebHostEnvironment(IWebHostEnvironment env)
|
||||
{
|
||||
InitEnvironment(env);
|
||||
}
|
||||
/// <summary>Initialise environment - from internal (above) or unit tests.</summary>
|
||||
protected void InitEnvironment(IWebHostEnvironment env)
|
||||
{
|
||||
base.InitEnvironment(env, "Sax-Web-Adm");
|
||||
|
||||
try
|
||||
{
|
||||
// Application configuration.
|
||||
appConfigs = SaxAppConfigHelper.ExtractAppConfigs(SaxConfiguration.GetSection("AppConfigs"));
|
||||
emailConfigs = SaxEmailConfigHelper.ExtractEmailConfigs(SaxConfiguration.GetSection("EmailConfigs"));
|
||||
|
||||
// Ensure root log folder ends with 'Admin' folder.
|
||||
LoggingRootFolder = AppConfig.Logging.RootFolder;
|
||||
if (!StringUtil.IsBlank(LoggingRootFolder) && !Regex.IsMatch(LoggingRootFolder, "[\\\\/]Admin$", RegexOptions.IgnoreCase))
|
||||
LoggingRootFolder = StringUtil.CombineFilePath(LoggingRootFolder, "Admin");
|
||||
|
||||
// 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.IsEmpty(LoggingRootFolder))
|
||||
{
|
||||
if (SaxSystem.ComputerName.EqualsCI("WIN-BPCLM1QUOMT"))
|
||||
LoggingRootFolder = @"D:\Saxonite\Logs\" + (Development ? "Dev" : "Test");
|
||||
}
|
||||
if (DirectoryUtil.DirectoryExists(LoggingRootFolder))
|
||||
SaLogger.LogFolder = LoggingRootFolder;
|
||||
LogApplicationStart(SysUtil.Fn);
|
||||
|
||||
//Messages.Add($"Database location: {AppConfig.CoreDatabase.Location}");
|
||||
//Messages.Add($"LoggingRootFolder: {SaLogger.LogFolder}");
|
||||
//Messages.Add($"OdbcDrivers: {OdbcUtil.GetOdbcDriverNames().Concat(", ")}");
|
||||
//Messages.Add($"DbConnection: {coreDatabase.ConnectionString}");
|
||||
|
||||
// Session context - only one context available/necessary (for now).
|
||||
SessionContextData_Admin sessionContextData = new SessionContextData_Admin(new SaxSessionContext_Web(100, ApplicationType));
|
||||
ConfigureDatabaseConnection(sessionContextData, Sax.Database.Core);
|
||||
ConfigureDatabaseConnection(sessionContextData, Sax.Database.Reference);
|
||||
ConfigureDatabaseConnection(sessionContextData, Sax.Database.Support);
|
||||
sessionContexts.Add(sessionContextData.SessionContext.Index, sessionContextData);
|
||||
SessionContext = sessionContextData.SessionContext;
|
||||
}
|
||||
catch (Exception exc)
|
||||
{
|
||||
SaLogger.Error(SysUtil.Fn + " " + ExceptionUtil.GetLogMessage(exc));
|
||||
}
|
||||
|
||||
// Occasional startup processing.
|
||||
if (generateDatabaseDefinitions)
|
||||
GenerateDatabaseDefinitions(SessionContext);
|
||||
if (populateRegions)
|
||||
populateRegionsFromDataFile(SessionContext);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
private void GenerateDatabaseDefinitions(SaxSessionContext sessionContext)
|
||||
{
|
||||
// Generate database definitions.
|
||||
if (!generateDatabaseDefinitions || !SaxSystem.DebugMode || SessionContext == null) return;
|
||||
if (!StringUtil.EmptyOnNull(EnvironmentName).EqualsCI("Development")) return;
|
||||
|
||||
// Core database.
|
||||
ISacsDatabase coreDatabase = GetDatabase(sessionContext, Sax.Database.Core);
|
||||
if (coreDatabase != null && !StringUtil.IsEmpty(coreDatabase.ConnectionString))
|
||||
{
|
||||
SaxDbDfnGenerator.Generate(Sax.Database.Core, coreDatabase.ConnectionString);
|
||||
//SaUpdateLogDbDfnGenerator.Generate(database.ConnectionString);
|
||||
}
|
||||
|
||||
// Reference database.
|
||||
ISacsDatabase referenceDatabase = GetDatabase(sessionContext, Sax.Database.Reference);
|
||||
if (referenceDatabase != null && !StringUtil.IsEmpty(referenceDatabase.ConnectionString))
|
||||
SaxDbDfnGenerator.Generate(Sax.Database.Reference, referenceDatabase.ConnectionString);
|
||||
|
||||
// Support database.
|
||||
ISacsDatabase supportDatabase = GetDatabase(sessionContext, Sax.Database.Support);
|
||||
if (supportDatabase != null && !StringUtil.IsEmpty(supportDatabase.ConnectionString))
|
||||
SaxDbDfnGenerator.Generate(Sax.Database.Support, supportDatabase.ConnectionString);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
private void populateRegionsFromDataFile(SaxSessionContext sessionContext)
|
||||
{
|
||||
using (SaxInternals internals = new SaxInternals(sessionContext))
|
||||
{
|
||||
SaxReferenceMgr referenceMgr = internals.ReferenceMgr;
|
||||
String regionsData = SaxResourceHelper.GetResourceText(SaxResourceHelper.TextResource.Data_CountriesWithRegions_Txt);
|
||||
String[] regionDataValues = regionsData.Split("\n");
|
||||
SysId parentRegionId = null;
|
||||
for (int idx = 0; idx < regionDataValues.Length; idx++)
|
||||
{
|
||||
String regionData = regionDataValues[idx].ReplaceAll("\r", "");
|
||||
if (StringUtil.IsEmpty(regionData)) continue;
|
||||
if (regionData.Length > 3 && regionData[2] == ':')
|
||||
{
|
||||
String iso2Code = regionData.Substring(0, 2);
|
||||
String name = regionData.Substring(3);
|
||||
SaxRegion region = getRegionByName(referenceMgr, name);
|
||||
if (region == null)
|
||||
{
|
||||
region = referenceMgr.CreateRegion();
|
||||
region.RegionType = Sax.RegionType.Country;
|
||||
region.CountryIso2Code = iso2Code;
|
||||
region.Name = name;
|
||||
region.RegionIdParent = parentRegionId;
|
||||
if (!referenceMgr.InsertRegion(region, new DbUpdateInfo(new SysId(), "", "")))
|
||||
{
|
||||
SaLogger.Error("Failed to insert region - " + referenceMgr.ErrorStateMessage);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Sub continent.
|
||||
SaxRegion region = getRegionByName(referenceMgr, regionData);
|
||||
if (region == null)
|
||||
{
|
||||
region = referenceMgr.CreateRegion();
|
||||
region.RegionType = Sax.RegionType.SubContinent;
|
||||
region.Name = regionData;
|
||||
if (!referenceMgr.InsertRegion(region, new DbUpdateInfo(new SysId(), "", "")))
|
||||
{
|
||||
SaLogger.Error("Failed to insert region - " + referenceMgr.ErrorStateMessage);
|
||||
return;
|
||||
}
|
||||
}
|
||||
parentRegionId = region.Id;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
private SaxRegion getRegionByName(SaxReferenceMgr referenceMgr, String name)
|
||||
{
|
||||
SaxRegion.Params prmRegion = new SaxRegion.Params();
|
||||
prmRegion.NameFull = name;
|
||||
return referenceMgr.GetRegion(prmRegion);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
}
|
||||
//=======================================================================
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
using Microsoft.Extensions.Localization;
|
||||
using Saxonite.Net.Core.Web.Base.App;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Saxonite.Net.Core.Web
|
||||
{
|
||||
// <summary>
|
||||
/// Dummy classes to group shared resources - named as per '.resx' file in root namespace.
|
||||
/// <para>Required to create the IStringLocalizer instance using the type from the class.</para>
|
||||
/// <para>Name of the class is used as the prefix for localisation filenames.</para>
|
||||
/// <para>Resource files are in the Localization ResourcesPath in Startup.cs.</para>
|
||||
/// </summary>
|
||||
public class SaxAdminProperties { }
|
||||
// Class must be in Root/Default Namespace to reference properties with same name.
|
||||
// NB 'Assembly name' must be the same as 'Default Namespace' until 'Root Namespace' can be set (.Net Core 2.1?).
|
||||
// Ref. Project Properties - Application.
|
||||
}
|
||||
|
||||
namespace Saxonite.Net.Core.Web.Admin.App
|
||||
{
|
||||
//=======================================================================
|
||||
public class SaxLocaliser_Admin : SaxLocaliser
|
||||
{
|
||||
//-------------------------------------------------------------------
|
||||
// Data members.
|
||||
private readonly IStringLocalizer<SaxAdminProperties> adminProperties;
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
/// <summary>
|
||||
/// Localisers are supplied using construction injection.
|
||||
/// </summary>
|
||||
public SaxLocaliser_Admin(IStringLocalizer<SaxAdminProperties> webAppProperties)
|
||||
{
|
||||
this.adminProperties = webAppProperties;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Properties.
|
||||
public override IStringLocalizer MainProperties { get { return adminProperties; } }
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
}
|
||||
//=======================================================================
|
||||
}
|
||||
@@ -0,0 +1,91 @@
|
||||
using Newtonsoft.Json;
|
||||
using Sarand.Net.Standard.Base.Bus;
|
||||
using Sarand.Net.Standard.Base.Helpers;
|
||||
using Saxonite.Net.Core.Web.Admin.Controllers;
|
||||
using Saxonite.Net.Core.Web.Base.App;
|
||||
using Saxonite.Net.Standard.Base.App;
|
||||
using Saxonite.Net.Standard.Base.Bus;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Saxonite.Net.Core.Web.Admin.App
|
||||
{
|
||||
//=======================================================================
|
||||
public class SaxSessionData_Admin : SaxSessionData_Web
|
||||
{
|
||||
//-------------------------------------------------------------------
|
||||
// Construction.
|
||||
[JsonConstructor]
|
||||
private SaxSessionData_Admin(long sessionIdx, int itemIdx, SaxSessionContext sessionContext) :
|
||||
base(sessionIdx, itemIdx, sessionContext)
|
||||
{ }
|
||||
/// <summary>
|
||||
/// SessionData construction.
|
||||
/// <para>SessionContext and UserAccount must be supplied.</para>
|
||||
/// <para>Organisation is optional.</para>
|
||||
/// </summary>
|
||||
public SaxSessionData_Admin(SaxSessionContext sessionContext, SaxUserAccount userAccount, List<SaxUserRole> userRoles) :
|
||||
base(sessionContext, userAccount, userRoles)
|
||||
{ }
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Properties.
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// User details.
|
||||
private class UserData_Admin : UserData
|
||||
{
|
||||
public UserData_Admin(SaxSessionContext sessionContext, SaxUserAccount userAccount, List<SaxUserRole> userRoles) :
|
||||
base(sessionContext, userAccount, userRoles)
|
||||
{ }
|
||||
public UserData_Admin(UserData userData) :
|
||||
base(userData)
|
||||
{ }
|
||||
}
|
||||
protected override UserData CreateUserData(SaxSessionContext sessionContext, SaxUserAccount userAccount, List<SaxUserRole> userRoles) { return new UserData_Admin(sessionContext, userAccount, userRoles); }
|
||||
/// <summary>User - JSON deserialisation route.</summary>
|
||||
public new UserData User { get { return base.User; } set { SetUser(new UserData_Admin(value)); } }
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// General filters.
|
||||
public class FilterData
|
||||
{
|
||||
// Sport.
|
||||
public SysId SportId { get; set; }
|
||||
// Region.
|
||||
public SysId RegionId { get; set; }
|
||||
}
|
||||
public FilterData Filter { get; private set; } = new FilterData();
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// System.
|
||||
public class SystemData
|
||||
{
|
||||
// Databases.
|
||||
public class DatabaseData
|
||||
{
|
||||
}
|
||||
public DatabaseData Database { get; private set; } = new DatabaseData();
|
||||
|
||||
// Logs.
|
||||
public class LogsData
|
||||
{
|
||||
public class FilterData
|
||||
{
|
||||
public String Folder { get; set; }
|
||||
public String Year { get; set; }
|
||||
public String Month { get; set; }
|
||||
}
|
||||
public FilterData Filter { get; private set; } = new FilterData();
|
||||
}
|
||||
public LogsData Logs { get; private set; } = new LogsData();
|
||||
}
|
||||
public SystemData System { get; private set; } = new SystemData();
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
//-------------------------------------------------------------------
|
||||
}
|
||||
//=======================================================================
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.AspNetCore.HttpsPolicy;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using Saxonite.Net.Core.Web.Admin.Consoles;
|
||||
using Saxonite.Net.Core.Web.Base.App;
|
||||
using Saxonite.Net.Standard.Base.App;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Saxonite.Net.Core.Web.Admin.App
|
||||
{
|
||||
//=======================================================================
|
||||
public class SaxStartup_Admin : SaxStartup
|
||||
{
|
||||
//-------------------------------------------------------------------
|
||||
// Data members.
|
||||
private SaxApplication_Admin application = null;
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Construction.
|
||||
public SaxStartup_Admin(IConfiguration configuration) : base(configuration)
|
||||
{
|
||||
// Initialise application.
|
||||
application = new SaxApplication_Admin(Configuration);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// This method gets called by the runtime. Use this method to add services to the container.
|
||||
public void ConfigureServices(IServiceCollection services)
|
||||
{
|
||||
// Common configuration.
|
||||
ConfigureServicesConfig configureServicesConfig = new ConfigureServicesConfig();
|
||||
configureServicesConfig.services = services;
|
||||
configureServicesConfig.sessionCookieName = Sax.Config.Admin.Session.Cookie.Name;
|
||||
configureServicesConfig.sessionCookieHttpOnly = Sax.Config.Admin.Session.Cookie.HttpOnly;
|
||||
configureServicesConfig.sessionIdleTimeout = Sax.Config.Admin.Session.Cookie.IdleTimeout;
|
||||
ConfigureServices(configureServicesConfig);
|
||||
|
||||
// Application localisation.
|
||||
services.AddSingleton<SaxLocaliser, SaxLocaliser_Admin>();
|
||||
|
||||
services.Configure<CookiePolicyOptions>(options =>
|
||||
{
|
||||
// This lambda determines whether user consent for non-essential cookies is needed for a given request.
|
||||
options.CheckConsentNeeded = context => true;
|
||||
options.MinimumSameSitePolicy = Microsoft.AspNetCore.Http.SameSiteMode.None;
|
||||
});
|
||||
|
||||
// Hosted (schedule) services.
|
||||
services.AddHostedService<SaxHostedServiceConsole_Admin>();
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
|
||||
public void Configure(IApplicationBuilder app, IHostApplicationLifetime hostApplicationLifetime, IWebHostEnvironment env)
|
||||
{
|
||||
application.InitWebHostEnvironment(env);
|
||||
|
||||
// Common configuration.
|
||||
ConfigureConfig configureConfig = new ConfigureConfig();
|
||||
configureConfig.app = app;
|
||||
configureConfig.hostApplicationLifetime = hostApplicationLifetime;
|
||||
configureConfig.env = env;
|
||||
Configure(configureConfig);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
}
|
||||
//=======================================================================
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
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;
|
||||
using Saxonite.Net.Standard.Base.Consoles;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace Saxonite.Net.Core.Web.Admin.Consoles
|
||||
{
|
||||
//=======================================================================
|
||||
public class SaxActivityConsole_Admin : SaxActivityConsole_Web
|
||||
{
|
||||
//-------------------------------------------------------------------
|
||||
// Data members.
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
public SaxActivityConsole_Admin(SaxSessionContext sessionContext) :
|
||||
base(sessionContext)
|
||||
{
|
||||
SaLogger.Info(SysUtil.Fn + "");
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Utilities.
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
}
|
||||
//=======================================================================
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
using Sarand.Net.Standard.Base.Utils;
|
||||
using Saxonite.Net.Core.Web.Admin.App;
|
||||
using Saxonite.Net.Core.Web.Base.Consoles;
|
||||
using Saxonite.Net.Standard.Base.App;
|
||||
using Saxonite.Net.Standard.Base.Consoles;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Saxonite.Net.Core.Web.Admin.Consoles
|
||||
{
|
||||
//=======================================================================
|
||||
public class SaxConsoleHelper_Admin : SaxConsoleHelper_Web
|
||||
{
|
||||
//-------------------------------------------------------------------
|
||||
// Data members:
|
||||
private readonly SaxApplication_Admin app;
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Construction.
|
||||
public SaxConsoleHelper_Admin(SaxApplication_Admin app)
|
||||
{
|
||||
this.app = app;
|
||||
}
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
// Clear process consoles.
|
||||
foreach (SaxProcessConsole_Admin processConsole in processConsoles.Values)
|
||||
{
|
||||
processConsole.Dispose();
|
||||
}
|
||||
processConsoles.Clear();
|
||||
}
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Data cache console.
|
||||
public override SaxDataCacheConsole GetDataCacheConsole(SaxSessionContext sessionContext)
|
||||
{
|
||||
//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_Admin> processConsoles { get; } = new Dictionary<ushort, SaxProcessConsole_Admin>();
|
||||
public SaxProcessConsole GetProcessConsole(SaxSessionContext sessionContext)
|
||||
{
|
||||
if (sessionContext == null) throw new NotSupportedException($"{SysUtil.Fn} Session Context must be specified.");
|
||||
SaxProcessConsole_Admin processConsole = processConsoles.GetValueOrDefault(sessionContext.Index, null);
|
||||
if (processConsole == null)
|
||||
{
|
||||
processConsole = processConsoles[sessionContext.Index] = new SaxProcessConsole_Admin(sessionContext);
|
||||
}
|
||||
return processConsole;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Activity console.
|
||||
public override SaxActivityConsole CreateActivityConsole(SaxSessionContext sessionContext)
|
||||
{
|
||||
return new SaxActivityConsole_Admin(sessionContext);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Email console.
|
||||
public override SaxEmailConsole CreateEmailConsole(SaxSessionContext sessionContext)
|
||||
{
|
||||
SaxEmailConsole emailConsole = new SaxEmailConsole_Web(app.EmailConfig);
|
||||
return emailConsole;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
}
|
||||
//=======================================================================
|
||||
}
|
||||
@@ -0,0 +1,124 @@
|
||||
using Sarand.Net.Standard.Base.App;
|
||||
using Sarand.Net.Standard.Base.Bus;
|
||||
using Sarand.Net.Standard.Base.Core;
|
||||
using Sarand.Net.Standard.Base.Dbas;
|
||||
using Sarand.Net.Standard.Base.Tasks;
|
||||
using Sarand.Net.Standard.Base.Utils;
|
||||
using Saxonite.Net.Core.Web.Admin.App;
|
||||
using Saxonite.Net.Core.Web.Base.Consoles;
|
||||
using Saxonite.Net.Core.Web.Base.Procs;
|
||||
using Saxonite.Net.Standard.Base.App;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Saxonite.Net.Core.Web.Admin.Consoles
|
||||
{
|
||||
//=======================================================================
|
||||
public class SaxHostedServiceConsole_Admin : SaxHostedServiceConsole_Web
|
||||
{
|
||||
//-------------------------------------------------------------------
|
||||
// Definitions.
|
||||
private enum ProcessType { Unknown = 0, GolfUsgaReferenceLookup }
|
||||
|
||||
/// <summary>
|
||||
/// Process tracking data to control when process is run.
|
||||
/// </summary>
|
||||
private class ProcessControlData
|
||||
{
|
||||
// Construction.
|
||||
public ProcessControlData(ProcessType processType, TimeSpan minTimeBetweenRuns)
|
||||
{
|
||||
this.ProcessType = processType;
|
||||
this.MinTimeBetweenRuns = minTimeBetweenRuns;
|
||||
ResetRunTime();
|
||||
}
|
||||
// Properties.
|
||||
public ProcessType ProcessType { get; }
|
||||
public TimeSpan MinTimeBetweenRuns { get; }
|
||||
public DateTime LastRunAt { get; private set; }
|
||||
// Utilities.
|
||||
public bool ReadyToRun()
|
||||
{
|
||||
//SaLogger.Info($"{SysUtil.Fn} Process: {ProcessType}. Secs since last run: {(DateTime.Now - LastRunAt).TotalSeconds}. Seconds between runs: {MinTimeBetweenRuns.TotalSeconds}.");
|
||||
return (DateTime.Now - LastRunAt) > MinTimeBetweenRuns;
|
||||
}
|
||||
public void ResetRunTime()
|
||||
{
|
||||
LastRunAt = DateTime.Now;
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Data members.
|
||||
private Dictionary<ProcessType, ProcessControlData> processes { get; } = new Dictionary<ProcessType, ProcessControlData>();
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Construction.
|
||||
public SaxHostedServiceConsole_Admin()
|
||||
{
|
||||
InitialiseProcesses();
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Clean-up.
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
|
||||
/// <summary>
|
||||
/// Periodic processing to execute application processes as required.
|
||||
/// <para>- See parent class for timer logic.</para>
|
||||
/// </summary>
|
||||
protected override void DoWork(object state)
|
||||
{
|
||||
//SaLogger.Info($"{SysUtil.Fn} Timed Background Service is working. State: {state}");
|
||||
SaxSessionContext sessionContext = SaxApplication_Admin.AppInstance.SessionContext;
|
||||
DbUpdateInfo dbUpdateInfo = new DbUpdateInfo(new SysId(), "AdminScheduled", SacsSystem.ComputerName);
|
||||
|
||||
// Check for cancellation.
|
||||
var token = ProcessTaskData.CancellationToken;
|
||||
if (token.IsCancellationRequested) return;
|
||||
|
||||
// Identify processes that are ready to run.
|
||||
foreach (ProcessControlData process in processes.Where(item => item.Value.ReadyToRun()).Select(item => item.Value))
|
||||
{
|
||||
//SaLogger.Info($"{SysUtil.Fn} Executing process: {process.ProcessType}.");
|
||||
process.ResetRunTime();
|
||||
switch (process.ProcessType)
|
||||
{
|
||||
case ProcessType.GolfUsgaReferenceLookup:
|
||||
// Run on separate thread.
|
||||
Task task = new Task(() =>
|
||||
{
|
||||
SaxGolfUsgaDataLookup.ExecuteScheduledUsgaDataLookup(sessionContext, dbUpdateInfo, ProcessTaskData);
|
||||
}, ProcessTaskData.CancellationToken);
|
||||
task.Start();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Initialisation.
|
||||
|
||||
private void InitialiseProcesses()
|
||||
{
|
||||
if (Sax.Config.Admin.Processes.Scheduled.UsgaGolfDataLookup.Enabled)
|
||||
InitialiseProcess(ProcessType.GolfUsgaReferenceLookup, TimeSpan.FromMinutes(MathUtil.Constrain(Sax.Config.Admin.Processes.Scheduled.UsgaGolfDataLookup.MinsBetweenExecution, 2, 120)));
|
||||
}
|
||||
|
||||
private void InitialiseProcess(ProcessType processType, TimeSpan minTimeBetweenRuns)
|
||||
{
|
||||
if (!processes.ContainsKey(processType))
|
||||
processes[processType] = new ProcessControlData(processType, minTimeBetweenRuns);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
}
|
||||
//=======================================================================
|
||||
}
|
||||
@@ -0,0 +1,133 @@
|
||||
using MimeKit;
|
||||
using Sarand.Net.Standard.Base.Core;
|
||||
using Sarand.Net.Standard.Base.Procs;
|
||||
using Saxonite.Net.Core.Web.Admin.Procs;
|
||||
using Saxonite.Net.Core.Web.Base.Procs;
|
||||
using Saxonite.Net.Standard.Base.App;
|
||||
using Saxonite.Net.Standard.Base.Consoles;
|
||||
using Saxonite.Net.Standard.Base.Procs;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace Saxonite.Net.Core.Web.Admin.Consoles
|
||||
{
|
||||
//=======================================================================
|
||||
public class SaxProcessConsole_Admin : SaxProcessConsole
|
||||
{
|
||||
//-------------------------------------------------------------------
|
||||
// Definitions.
|
||||
public enum ProcessType
|
||||
{
|
||||
OrganisationUpload,
|
||||
GolfUsgaDataLookup
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Process cache - to sustain processes outside of request/response timescales.
|
||||
internal class ProcessData
|
||||
{
|
||||
public ProcessData(SaxProcess_Web process)
|
||||
{
|
||||
this.Process = process;
|
||||
|
||||
}
|
||||
public SaxProcess_Web Process { get; }
|
||||
}
|
||||
// Cache.
|
||||
private Dictionary<ProcessType, ProcessData> processes { get; } = new Dictionary<ProcessType, ProcessData>();
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Data members.
|
||||
//private SaxInternals internals = null;
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Construction.
|
||||
public SaxProcessConsole_Admin(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_Web GetProcess(ProcessType processType)
|
||||
{
|
||||
return processes.GetValueOrDefault(processType, null)?.Process;
|
||||
}
|
||||
|
||||
public bool IsProcessing(ProcessType processType)
|
||||
{
|
||||
SaxProcess_Web 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_Web 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_Web process)
|
||||
{
|
||||
ClearProcess(processType);
|
||||
processes.Add(processType, new ProcessData(process));
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Specific processes.
|
||||
//-------------------------------------------------------------------
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Organisation Upload.
|
||||
public SaxOrganisationUploader GetOrganisationUploader()
|
||||
{
|
||||
return GetProcess(ProcessType.OrganisationUpload) as SaxOrganisationUploader;
|
||||
}
|
||||
public void SetProcess(SaxOrganisationUploader process)
|
||||
{
|
||||
SetProcess(ProcessType.OrganisationUpload, process);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Organisation Upload.
|
||||
public SaxGolfUsgaDataLookup GetGolfUsgaDataLookup()
|
||||
{
|
||||
return GetProcess(ProcessType.GolfUsgaDataLookup) as SaxGolfUsgaDataLookup;
|
||||
}
|
||||
public void SetProcess(SaxGolfUsgaDataLookup process)
|
||||
{
|
||||
SetProcess(ProcessType.OrganisationUpload, process);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
}
|
||||
//=======================================================================
|
||||
}
|
||||
+187
@@ -0,0 +1,187 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Routing;
|
||||
using Sarand.Net.Standard.Base.Bus;
|
||||
using Sarand.Net.Standard.Base.Core;
|
||||
using Sarand.Net.Standard.Base.Dbas;
|
||||
using Sarand.Net.Standard.Base.Utils;
|
||||
using Sarand.Net.Standard.Dbas.Data;
|
||||
using Saxonite.Net.Core.Web.Admin.Models;
|
||||
using Saxonite.Net.Standard.Base.App;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Saxonite.Net.Core.Web.Admin.Controllers
|
||||
{
|
||||
//=======================================================================
|
||||
// Home Controller - Ajax - Application Stats
|
||||
//=======================================================================
|
||||
partial class HomeController
|
||||
{
|
||||
//-------------------------------------------------------------------
|
||||
// Application Stats data.
|
||||
private class ApplicationStatsData
|
||||
{
|
||||
public class UserStatsData
|
||||
{
|
||||
public String Caption { get; set; }
|
||||
public AjaxResponse_Data.ItemLabelValue Awaiting { get; set; }
|
||||
public String UsersLink { get; set; }
|
||||
public String AwaitingLink { get; set; }
|
||||
public List<AjaxResponse_Data.ItemLabelValue> OnlineStats { get; set; }
|
||||
public String OnlineLink { get; set; }
|
||||
}
|
||||
public UserStatsData User { get; } = new UserStatsData();
|
||||
public class OrganisationStatsData
|
||||
{
|
||||
public String Caption { get; set; }
|
||||
public AjaxResponse_Data.ItemLabelValue Awaiting { get; set; }
|
||||
public String OrganisationsLink { get; set; }
|
||||
public String AwaitingLink { get; set; }
|
||||
}
|
||||
public OrganisationStatsData Organisation { get; } = new OrganisationStatsData();
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Get Application Stats ajax request.
|
||||
//-------------------------------------------------------------------
|
||||
private class AjaxResponse_ApplicationStats : AjaxResponse_Data
|
||||
{
|
||||
// Construction.
|
||||
public AjaxResponse_ApplicationStats(SaxModel_Admin model) : base(model) { }
|
||||
// Table list.
|
||||
public ApplicationStatsData Stats { get; } = new ApplicationStatsData();
|
||||
}
|
||||
//-------------------------------------------------------------------
|
||||
[HttpPost]
|
||||
[Route("Home/Ajax/GetApplicationStats")]
|
||||
public IActionResult Ajax_GetApplicationStats(Model_Sport model)
|
||||
{
|
||||
String messageTitle = Localiser["home.caption.application"];
|
||||
AjaxResponse_ApplicationStats responseData = new AjaxResponse_ApplicationStats(model);
|
||||
|
||||
// Validate session.
|
||||
if (!ValidUserSession)
|
||||
return GetAjaxResult_InvalidSession(responseData);
|
||||
|
||||
// Captions.
|
||||
responseData.Stats.User.Caption = Localiser["user.caption.users"];
|
||||
responseData.Stats.Organisation.Caption = Localiser["caption.organisations"];
|
||||
|
||||
// Core Database connection.
|
||||
ISacsDatabase db = Internals.CoreDatabase;
|
||||
|
||||
// Query to count items awaiting activation.
|
||||
Dictionary<String, int> tableRowCounts = new Dictionary<string, int>(StringComparer.OrdinalIgnoreCase);
|
||||
List<String> query = new List<string>()
|
||||
{
|
||||
// User accounts.
|
||||
"SELECT",
|
||||
"ItemType = '" + DbQuery.FormatForCondition(nameof(Sax.DataItemType.UserAccount)) + "',",
|
||||
"ItemCount = Count(*)",
|
||||
"FROM UserAccount ua",
|
||||
"WHERE ua.Status = 'AWA'",
|
||||
// Organisations.
|
||||
"UNION SELECT",
|
||||
"ItemType = '" + DbQuery.FormatForCondition(nameof(Sax.DataItemType.Organisation)) + "',",
|
||||
"ItemCount = Count(*)",
|
||||
"FROM Organisation org",
|
||||
"WHERE org.Status = 'AWA'",
|
||||
};
|
||||
using (DbResultSet dbResultSet = DbResultSet_DataReader.ExecuteQuery(db, query.Concat("\n")))
|
||||
{
|
||||
while (dbResultSet != null && dbResultSet.NextRecord())
|
||||
{
|
||||
NamedValue.Map values = dbResultSet.GetRecordValues();
|
||||
Sax.DataItemType itemType = EnumUtil.ParseEnum(values.GetValue("ItemType").ToString(), Sax.DataItemType.Unknown);
|
||||
int itemCount = (int)values.GetValue("ItemCount").AsLong();
|
||||
switch (itemType)
|
||||
{
|
||||
case Sax.DataItemType.UserAccount:
|
||||
responseData.Stats.User.Awaiting = new AjaxResponse_Data.ItemLabelValue() { Label = Localiser["label.awaiting.activation"], Value = itemCount.ToString() };
|
||||
responseData.Stats.User.UsersLink = Url.Action("", "User").TrimStart('/');
|
||||
responseData.Stats.User.AwaitingLink = Url.Action("", "User", new RouteValueDictionary() { { "sta", "Await" } }).TrimStart('/');
|
||||
break;
|
||||
case Sax.DataItemType.Organisation:
|
||||
responseData.Stats.Organisation.Awaiting = new AjaxResponse_Data.ItemLabelValue() { Label = Localiser["label.awaiting.activation"], Value = itemCount.ToString() };
|
||||
responseData.Stats.Organisation.OrganisationsLink = Url.Action("", "Organisation").TrimStart('/');
|
||||
responseData.Stats.Organisation.AwaitingLink = Url.Action("", "Organisation", new RouteValueDictionary() { { "sta", "Await" } }).TrimStart('/');
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Query to count users online.
|
||||
DateTime today = DateTime.Today;
|
||||
DateTime now = DateTime.Now;
|
||||
const String online5Mins = "Online5Mins";
|
||||
const String online15Mins = "Online15Mins";
|
||||
const String online30Mins = "Online30Mins";
|
||||
const String online60Mins = "Online60Mins";
|
||||
const String onlineToday = "OnlineToday";
|
||||
const String onlineWeek = "OnlineWeek";
|
||||
const String onlineMonth = "OnlineMonth";
|
||||
query = new List<string>()
|
||||
{
|
||||
// Users Online last 5 mins.
|
||||
"Select '" + online5Mins + "' ItemType, (Select Count(*) From UserOnline Where OnlineAt>=" + DbQuery.FormatDateTimeForCondition(now.AddMinutes(-5)) + ") ItemCount ",
|
||||
"Union Select '" + online15Mins + "' ItemType, (Select Count(*) From UserOnline Where OnlineAt>=" + DbQuery.FormatDateTimeForCondition(now.AddMinutes(-15)) + ") ItemCount ",
|
||||
"Union Select '" + online30Mins + "' ItemType, (Select Count(*) From UserOnline Where OnlineAt>=" + DbQuery.FormatDateTimeForCondition(now.AddMinutes(-30)) + ") ItemCount ",
|
||||
"Union Select '" + online60Mins + "' ItemType, (Select Count(*) From UserOnline Where OnlineAt>=" + DbQuery.FormatDateTimeForCondition(now.AddMinutes(-60)) + ") ItemCount ",
|
||||
"Union Select '" + onlineToday + "' ItemType, (Select Count(*) From UserOnline Where OnlineAt>=" + DbQuery.FormatDateForCondition(today) + ") ItemCount ",
|
||||
"Union Select '" + onlineWeek + "' ItemType, (Select Count(*) From UserOnline Where OnlineAt>=" + DbQuery.FormatDateForCondition(DateUtil.StartOfWorkingWeek(today)) + ") ItemCount ",
|
||||
"Union Select '" + onlineMonth + "' ItemType, (Select Count(*) From UserOnline Where OnlineAt>=" + DbQuery.FormatDateForCondition(DateUtil.StartOfMonth(today)) + ") ItemCount ",
|
||||
};
|
||||
using (DbResultSet dbResultSet = DbResultSet_DataReader.ExecuteQuery(db, query.Concat("\n")))
|
||||
{
|
||||
while (dbResultSet != null && dbResultSet.NextRecord())
|
||||
{
|
||||
if (responseData.Stats.User.OnlineStats == null)
|
||||
responseData.Stats.User.OnlineStats = new List<AjaxResponse_Data.ItemLabelValue>();
|
||||
NamedValue.Map values = dbResultSet.GetRecordValues();
|
||||
String itemType = values.GetValue("ItemType").ToString();
|
||||
int itemCount = (int)values.GetValue("ItemCount").AsLong();
|
||||
switch (itemType)
|
||||
{
|
||||
case online5Mins:
|
||||
if (itemCount > 0)
|
||||
responseData.Stats.User.OnlineStats.Add(new AjaxResponse_Data.ItemLabelValue() { Label = Localiser["label.online.last5Mins"], Value = itemCount.ToString() });
|
||||
break;
|
||||
case online15Mins:
|
||||
if (itemCount > 0)
|
||||
responseData.Stats.User.OnlineStats.Add(new AjaxResponse_Data.ItemLabelValue() { Label = Localiser["label.online.last15Mins"], Value = itemCount.ToString() });
|
||||
break;
|
||||
case online30Mins:
|
||||
if (itemCount > 0)
|
||||
responseData.Stats.User.OnlineStats.Add(new AjaxResponse_Data.ItemLabelValue() { Label = Localiser["label.online.last30Mins"], Value = itemCount.ToString() });
|
||||
break;
|
||||
case online60Mins:
|
||||
if (itemCount > 0)
|
||||
responseData.Stats.User.OnlineStats.Add(new AjaxResponse_Data.ItemLabelValue() { Label = Localiser["label.online.last60Mins"], Value = itemCount.ToString() });
|
||||
break;
|
||||
case onlineToday:
|
||||
if (itemCount > 0)
|
||||
responseData.Stats.User.OnlineStats.Add(new AjaxResponse_Data.ItemLabelValue() { Label = Localiser["label.online.today"], Value = itemCount.ToString() });
|
||||
break;
|
||||
case onlineWeek:
|
||||
if (itemCount > 0)
|
||||
responseData.Stats.User.OnlineStats.Add(new AjaxResponse_Data.ItemLabelValue() { Label = Localiser["label.online.thisWeek"], Value = itemCount.ToString() });
|
||||
break;
|
||||
case onlineMonth:
|
||||
if (itemCount > 0)
|
||||
responseData.Stats.User.OnlineStats.Add(new AjaxResponse_Data.ItemLabelValue() { Label = Localiser["label.online.thisMonth"], Value = itemCount.ToString() });
|
||||
break;
|
||||
}
|
||||
responseData.Stats.User.OnlineLink = Url.Action("", "UsersOnline", new RouteValueDictionary() { }).TrimStart('/');
|
||||
}
|
||||
}
|
||||
|
||||
// Complete response.
|
||||
responseData.Success = true;
|
||||
return Json(responseData);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
}
|
||||
//=======================================================================
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Sarand.Net.Standard.Base.App;
|
||||
using Sarand.Net.Standard.Base.Bus;
|
||||
using Sarand.Net.Standard.Base.Core;
|
||||
using Sarand.Net.Standard.Base.Utils;
|
||||
using Saxonite.Net.Core.Web.Admin.Models;
|
||||
using Saxonite.Net.Core.Web.Base.App;
|
||||
using Saxonite.Net.Core.Web.Base.Controllers;
|
||||
using Saxonite.Net.Standard.Base.Bus;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Saxonite.Net.Core.Web.Admin.Controllers
|
||||
{
|
||||
//=======================================================================
|
||||
public partial class HomeController : SaxController_Admin
|
||||
{
|
||||
//-------------------------------------------------------------------
|
||||
// Construction.
|
||||
public HomeController(SaxLocaliser localiser, ILogger<HomeController> logger) :
|
||||
base(localiser, logger)
|
||||
{
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
[HttpGet]
|
||||
public IActionResult Index()
|
||||
{
|
||||
if (!ValidUserSession)
|
||||
AutoLoginUser();
|
||||
|
||||
// Redirect to sign-in if not signed-in.
|
||||
if (!ValidUserSession)
|
||||
{
|
||||
ClearKeepLoggedInCookie();
|
||||
return RedirectToAction("", "Security");
|
||||
}
|
||||
|
||||
// Home page.
|
||||
Model_Home model = new Model_Home(Localiser);
|
||||
model.ProhibitCache = false;
|
||||
return View(model);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
|
||||
public IActionResult Error()
|
||||
{
|
||||
return View(new ErrorViewModel(Localiser) { RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier });
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
}
|
||||
//=======================================================================
|
||||
}
|
||||
@@ -0,0 +1,208 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Net.Http.Headers;
|
||||
using Sarand.Net.Standard.Base.Bus;
|
||||
using Sarand.Net.Standard.Base.Utils;
|
||||
using Saxonite.Net.Core.Web.Base.App;
|
||||
using Saxonite.Net.Standard.Base.App;
|
||||
using Saxonite.Net.Standard.Base.Bus;
|
||||
using System;
|
||||
using System.Collections.Specialized;
|
||||
|
||||
namespace Saxonite.Net.Core.Web.Admin.Controllers
|
||||
{
|
||||
//=======================================================================
|
||||
// Admin Image Controller - delivers dynamic images.
|
||||
//=======================================================================
|
||||
public partial class ImageController : SaxController_Admin
|
||||
{
|
||||
//-------------------------------------------------------------------
|
||||
// Data members.
|
||||
public static String ParamName_OrganisationLogoEncrypted { get; } = "ole";
|
||||
public static String ParamName_ItemImageEncrypted { get; } = "iie";
|
||||
public static String ParamName_OrganisationId { get; } = "ori";
|
||||
public static String ParamName_ItemImageId { get; } = "iii";
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Construction.
|
||||
public ImageController(SaxLocaliser localiser, ILogger<HomeController> logger) :
|
||||
base(localiser, logger)
|
||||
{
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Account Contact image request.
|
||||
//-------------------------------------------------------------------
|
||||
/// <summary>
|
||||
/// Get the Account Contact Image for the specified account.
|
||||
/// <para>Current User Account is used if no other specified in the encrypted parameter.</para>
|
||||
/// <para>Encrypted parameter:</para>
|
||||
/// <para>- uaie: User Account Id encrypted.</para>
|
||||
/// </summary>
|
||||
[HttpGet]
|
||||
[Route("Image/Account/Contact")]
|
||||
public IActionResult GetAccountContactImage(String uaie)
|
||||
{
|
||||
String userAccountIdParam = "";// ToDo Decrypt from uaie value.
|
||||
SysId userAccountId = SysId.ToSysId(userAccountIdParam);
|
||||
if (!SysId.IsValid(userAccountId))
|
||||
userAccountId = SessionUserAccountId;
|
||||
return GetAccountContactImage(userAccountId, Sax.ImageType.Avatar);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Account Contact Image Profile/Upload request.
|
||||
//-------------------------------------------------------------------
|
||||
/// <summary>
|
||||
/// Get the current Account Profile Contact Image for the specified account.
|
||||
/// <para>Account is always current User Account - this request is only fir use from the user's own profile page.</para>
|
||||
/// <para>'Uploaded' avatar image will take precedence as this will be the latest if present.</para>
|
||||
/// <para>NB Avoid caching this image as it will change whenever a new one is uploaded.</para>
|
||||
/// </summary>
|
||||
[HttpGet]
|
||||
[Route("Image/Account/Contact/Profile")]
|
||||
[Route("Image/Account/Contact/Upload")]
|
||||
[ResponseCache(NoStore = true, Location = ResponseCacheLocation.None)]
|
||||
public IActionResult GetAccountContactImage()
|
||||
{
|
||||
// Response should not be cached.
|
||||
Response.Headers[HeaderNames.CacheControl] = "no-cache, no-store, must-revalidate, max-age=0";
|
||||
Response.Headers[HeaderNames.Expires] = "-1";
|
||||
SysId userAccountId = SessionUserAccountId;
|
||||
return GetAccountContactImage(userAccountId, Sax.ImageType.Avatar_Upload);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
/// <summary>
|
||||
/// Get the Avatar image for the specified user account.
|
||||
/// </summary>
|
||||
/// <param name="imageTypePriority"></param>
|
||||
/// <returns></returns>
|
||||
private IActionResult GetAccountContactImage(SysId userAccountId, Sax.ImageType imageTypePriority)
|
||||
{
|
||||
// Validate session and referrer.
|
||||
if (!ValidReferer || !ValidUserSession) return Forbid();
|
||||
ItemId userItemId = new ItemId((short)Sax.DataItemType.UserAccount, userAccountId);
|
||||
|
||||
// Retrieve account contact images.
|
||||
SaxItemImage.Params prmItemImage = new SaxItemImage.Params();
|
||||
prmItemImage.ItemIdsIncluded.Add(userItemId);
|
||||
prmItemImage.ImageTypesIncluded.Add(Sax.ImageType.Avatar);
|
||||
prmItemImage.ImageTypesIncluded.Add(Sax.ImageType.Avatar_Upload);
|
||||
prmItemImage.StatusCat = SaxItemImage.StatusCat.ActiveOnly;
|
||||
SaxItemImage itemImage = null;
|
||||
foreach (SaxItemImage itemImageCandidate in ItemDataMgr.GetItemImageList(prmItemImage))
|
||||
{
|
||||
// One of the 'Avatar' image types will take precedence.
|
||||
if (itemImage == null || itemImageCandidate.ImageType == imageTypePriority)
|
||||
itemImage = itemImageCandidate;
|
||||
}
|
||||
|
||||
if (itemImage == null)
|
||||
return NotFound();
|
||||
|
||||
// Construct response.
|
||||
return File(itemImage.ImageData, itemImage.ContentType);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Organisation logo.
|
||||
//-------------------------------------------------------------------
|
||||
/// <summary>
|
||||
/// Get the logo for the specified Organisation.
|
||||
/// <para>Method parameter name (ole) must match name of encrypted parameter.</para>
|
||||
/// <para>Encrypted parameters:</para>
|
||||
/// <para>- ori: Organisation Id.</para>
|
||||
/// </summary>
|
||||
[HttpGet]
|
||||
[Route("Image/Organisation/Logo")]
|
||||
public IActionResult GetOrganisationLogo(String ole)
|
||||
{
|
||||
return GetOrganisationLogo(ole, false);
|
||||
}
|
||||
/// <summary>
|
||||
/// Get the logo for the specified Organisation.
|
||||
/// <para>Method parameter name (ole) must match name of encrypted parameter.</para>
|
||||
/// <para>Encrypted parameters:</para>
|
||||
/// <para>- ori: Organisation Id.</para>
|
||||
/// </summary>
|
||||
[HttpGet]
|
||||
[Route("Image/Organisation/Logo/Upload")]
|
||||
public IActionResult GetOrganisationLogoUpload(String ole)
|
||||
{
|
||||
return GetOrganisationLogo(ole, true);
|
||||
}
|
||||
private IActionResult GetOrganisationLogo(String encryptedParams, bool allowUploadImage)
|
||||
{
|
||||
// Validate session and referrer.
|
||||
if (!ValidReferer || !ValidUserSession) return Forbid();
|
||||
|
||||
// Extract encrypted parameters.
|
||||
NameValueCollection parameters = ExtractSessionParams(encryptedParams);
|
||||
if (parameters.Count < 1) return Forbid();
|
||||
|
||||
// Organisation Id.
|
||||
SysId organisationId = SysId.ToSysId(parameters.Get(ParamName_OrganisationId));
|
||||
if (!SysId.IsValid(organisationId)) return Forbid();
|
||||
ItemId organisationItemId = new ItemId((short)Sax.DataItemType.Organisation, organisationId);
|
||||
|
||||
// Query Organisation Logo images.
|
||||
SaxItemImage.Params prmItemImage = new SaxItemImage.Params();
|
||||
prmItemImage.ItemIdsIncluded.Add(organisationItemId);
|
||||
prmItemImage.ImageTypesIncluded.Add(Sax.ImageType.OrganisationLogo);
|
||||
if (allowUploadImage)
|
||||
prmItemImage.ImageTypesIncluded.Add(Sax.ImageType.OrganisationLogo_Upload);
|
||||
prmItemImage.StatusCat = SaxItemImage.StatusCat.ActiveOnly;
|
||||
SaxItemImage itemImage = null;
|
||||
foreach (SaxItemImage itemImageCandidate in ItemDataMgr.GetItemImageList(prmItemImage))
|
||||
{
|
||||
// The 'Upload' image will take precedence if allowed.
|
||||
if (itemImage == null || itemImageCandidate.ImageType == Sax.ImageType.OrganisationLogo_Upload)
|
||||
itemImage = itemImageCandidate;
|
||||
}
|
||||
|
||||
if (itemImage == null)
|
||||
return NotFound();
|
||||
|
||||
// Construct response.
|
||||
Response.Headers[HeaderNames.CacheControl] = "no-cache, no-store, must-revalidate, max-age=0";
|
||||
Response.Headers[HeaderNames.Expires] = "-1";
|
||||
return File(itemImage.ImageData, itemImage.ContentType);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Item image.
|
||||
//-------------------------------------------------------------------
|
||||
/// <summary>
|
||||
/// Get the specified Item Image.
|
||||
/// <para>Method parameter name (iie) must match name of encrypted parameter.</para>
|
||||
/// <para>Encrypted parameters:</para>
|
||||
/// <para>- iii: Item Image Id.</para>
|
||||
/// </summary>
|
||||
[HttpGet]
|
||||
[Route("Image/Item")]
|
||||
public IActionResult GetItemImage(String iie)
|
||||
{
|
||||
// Validate session and referrer.
|
||||
if (!ValidReferer || !ValidUserSession) return Forbid();
|
||||
ItemId userItemId = new ItemId((short)Sax.DataItemType.UserAccount, SessionUserAccountId);
|
||||
|
||||
// Extract encrypted parameters.
|
||||
NameValueCollection parameters = ExtractSessionParams(iie);
|
||||
if (parameters.Count < 1) return Forbid();
|
||||
|
||||
// Item Image.
|
||||
SysId itemImageId = SysId.ToSysId(parameters.Get(ParamName_ItemImageId));
|
||||
if (!SysId.IsValid(itemImageId)) return Forbid();
|
||||
SaxItemImage itemImage = ItemDataMgr.GetItemImageById(itemImageId);
|
||||
if (itemImage == null)
|
||||
return NotFound();
|
||||
|
||||
// Construct response.
|
||||
return File(itemImage.ImageData, itemImage.ContentType);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
}
|
||||
//=======================================================================
|
||||
}
|
||||
+255
@@ -0,0 +1,255 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Sarand.Net.Standard.Base.App;
|
||||
using Sarand.Net.Standard.Base.Bus;
|
||||
using Sarand.Net.Standard.Base.Core;
|
||||
using Sarand.Net.Standard.Base.Email;
|
||||
using Sarand.Net.Standard.Base.Utils;
|
||||
using Saxonite.Net.Core.Web.Admin.Models;
|
||||
using Saxonite.Net.Standard.Base.App;
|
||||
using Saxonite.Net.Standard.Base.Bus;
|
||||
using Saxonite.Net.Standard.Base.Helpers;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Saxonite.Net.Core.Web.Admin.Controllers
|
||||
{
|
||||
//=======================================================================
|
||||
// Controller: Organisation - Ajax - Activation
|
||||
//=======================================================================
|
||||
partial class OrganisationController
|
||||
{
|
||||
//-------------------------------------------------------------------
|
||||
// Get Organisation Activation Info ajax request.
|
||||
//-------------------------------------------------------------------
|
||||
private class AjaxResponse_OrganisationActivationInfo : AjaxResponse_Data
|
||||
{
|
||||
// Construction.
|
||||
public AjaxResponse_OrganisationActivationInfo(SaxModel_Admin model) : base(model) { }
|
||||
// Organisation details.
|
||||
public OrganisationItemData organisation { get; } = new OrganisationItemData();
|
||||
// Member awaiting activation.
|
||||
public List<MemberListData> Members { get; } = new List<MemberListData>();
|
||||
}
|
||||
//-------------------------------------------------------------------
|
||||
[HttpPost]
|
||||
[Route("Organisation/Ajax/GetActivationInfo")]
|
||||
public IActionResult Ajax_GetActivationInfo(Model_Organisation model)
|
||||
{
|
||||
String messageTitle = Localiser["caption.organisation"];
|
||||
AjaxResponse_OrganisationActivationInfo responseData = new AjaxResponse_OrganisationActivationInfo(model);
|
||||
|
||||
// Validate session.
|
||||
if (!ValidUserSession)
|
||||
return GetAjaxResult_InvalidSession(responseData);
|
||||
|
||||
// Record disposable items as they are created so all can be disposed when needed.
|
||||
using (DisposableCollection<IDisposable> disposableItems = new DisposableCollection<IDisposable>())
|
||||
{
|
||||
|
||||
if (StringUtil.IsEmpty(AppConfig.URL.Online.Root))
|
||||
return Json(responseData.SetPopupMessage(messageTitle, "Root online URL not specified."));
|
||||
|
||||
// Identify item.
|
||||
SysId organisationId = SysId.ToSysId(model.OrganisationId);
|
||||
if (!SysId.IsValid(organisationId))
|
||||
{
|
||||
SaLogger.Warn($"{SysUtil.Fn} Request to get activation info without valid organisation Id.");
|
||||
return Json(responseData.SetPopupMessage(messageTitle, Localiser["msg.error.item.id.not.specified"]));
|
||||
}
|
||||
|
||||
// Retrieve item.
|
||||
SaxOrganisation organisation = AccountMgr.GetOrganisationById(organisationId);
|
||||
disposableItems.Add(organisation);
|
||||
if (organisation == null)
|
||||
{
|
||||
SaLogger.Warn($"{SysUtil.Fn} Failed to retrieve organisation. Id: '{model.OrganisationId}'");
|
||||
return Json(responseData.SetPopupMessage(messageTitle, Localiser["msg.error.item.id.not.found"]));
|
||||
}
|
||||
|
||||
// Organisation address.
|
||||
SaxItemAddress address = ItemDataMgr.GetFirstItemAddressByItemAndType(organisation.GetItemId());
|
||||
disposableItems.Add(address);
|
||||
|
||||
// Construct response.
|
||||
PopulateOrganisationResponseItemData(organisation, address, responseData.organisation);
|
||||
GetOrganisationMembers(model, organisationId, responseData.Members, true);
|
||||
}
|
||||
|
||||
// Complete response.
|
||||
responseData.Success = true;
|
||||
|
||||
return Json(responseData);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
private class OrganisationMemberData : SacsDisposable
|
||||
{
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
if (UserOrganisation != null) UserOrganisation.Dispose(); UserOrganisation = null;
|
||||
if (UserAccount != null) UserAccount.Dispose(); UserAccount = null;
|
||||
}
|
||||
}
|
||||
public SaxUserOrganisation UserOrganisation { get; set; }
|
||||
public SaxUserAccount UserAccount { get; set; }
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Activate Organisation ajax request.
|
||||
//-------------------------------------------------------------------
|
||||
[HttpPost]
|
||||
[Route("Organisation/Ajax/Activate")]
|
||||
[Route("Organisation/Ajax/ActivateItem")]
|
||||
public IActionResult Ajax_Activate(Model_OrganisationActivation model)
|
||||
{
|
||||
String messageTitle = Localiser["caption.organisation"];
|
||||
AjaxResponse_Organisation responseData = new AjaxResponse_Organisation(model);
|
||||
|
||||
// Validate session.
|
||||
if (!ValidUserSession)
|
||||
return GetAjaxResult_InvalidSession(responseData);
|
||||
|
||||
// Record disposable items as they are created so all can be disposed when needed.
|
||||
using (DisposableCollection<IDisposable> disposableItems = new DisposableCollection<IDisposable>())
|
||||
{
|
||||
|
||||
// Retrieve existing item.
|
||||
SysId organisationId = SysId.ToSysId(model.OrganisationId);
|
||||
SaxOrganisation organisation = AccountMgr.GetOrganisationById(organisationId);
|
||||
disposableItems.Add(organisation);
|
||||
if (organisation == null)
|
||||
{
|
||||
SaLogger.Warn($"{SysUtil.Fn} Failed to retrieve organisation. Id: '{model.OrganisationId}'");
|
||||
return Json(responseData.SetPopupMessage(messageTitle, Localiser["msg.error.item.id.not.found"]));
|
||||
}
|
||||
|
||||
// Organisation address.
|
||||
SaxItemAddress address = ItemDataMgr.GetFirstItemAddressByItemAndType(organisation.GetItemId());
|
||||
disposableItems.Add(address);
|
||||
|
||||
// Retrieve users.
|
||||
List<OrganisationMemberData> organisationMembersToActivate = new List<OrganisationMemberData>();
|
||||
foreach (String userOrganisationId in model.OrganisationMemberIds)
|
||||
{
|
||||
if (userOrganisationId == null) continue;
|
||||
OrganisationMemberData organisationMember = new OrganisationMemberData();
|
||||
disposableItems.Add(organisationMember);
|
||||
organisationMember.UserOrganisation = AccountMgr.GetUserOrganisationById(SysId.ToSysId(userOrganisationId));
|
||||
organisationMember.UserAccount = AccountMgr.GetUserAccountById(organisationMember.UserOrganisation?.UserAccountId ?? null);
|
||||
if (organisationMember.UserOrganisation == null)
|
||||
{
|
||||
SaLogger.Warn($"{SysUtil.Fn} Failed to retrieve user organisation. Id: '{userOrganisationId}'");
|
||||
return Json(responseData.SetPopupMessage(messageTitle, Localiser["msg.error.system"]));
|
||||
}
|
||||
if (organisationMember.UserAccount == null)
|
||||
{
|
||||
SaLogger.Warn($"{SysUtil.Fn} Failed to retrieve user account . Id: '{organisationMember.UserOrganisation.UserAccountId}'");
|
||||
return Json(responseData.SetPopupMessage(messageTitle, Localiser["msg.error.system"]));
|
||||
}
|
||||
if (organisationMember.UserAccount.Status != SaStatus.Awaiting)
|
||||
{
|
||||
SaLogger.Warn($"{SysUtil.Fn} User organisation is not awaiting. Id: '{userOrganisationId}'. Status: {organisationMember.UserAccount.StatusDesc}");
|
||||
return Json(responseData.SetPopupMessage(messageTitle, Localiser["msg.error.system"]));
|
||||
}
|
||||
// Check if this user is to be activated.
|
||||
bool activateUser = false;
|
||||
String controlName_Activate = $"MemberActivate_{userOrganisationId}";
|
||||
foreach (String key in Request.Form.Keys)
|
||||
{
|
||||
if (key.EqualsCI(controlName_Activate))
|
||||
{
|
||||
activateUser = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (activateUser)
|
||||
organisationMembersToActivate.Add(organisationMember);
|
||||
}
|
||||
|
||||
if (organisationMembersToActivate.IsEmpty())
|
||||
{
|
||||
// No users to be activated.
|
||||
// Check that organisation already has active members.
|
||||
if (AccountMgr.GetOrganisationMemberCount(organisation.Id) < 1)
|
||||
{
|
||||
SaLogger.Warn($"{SysUtil.Fn} Unable to activate Organisation - no active members. Id: '{SysId.ToString(organisationId)}");
|
||||
return Json(responseData.SetPopupMessage(messageTitle, Localiser["organisation.activate.msg.no.active.members"]));
|
||||
}
|
||||
}
|
||||
|
||||
// Activate organisation.
|
||||
organisation.Status = Sarand.Net.Standard.Base.Core.SaStatus.Active;
|
||||
if (!AccountMgr.UpdateOrganisation(organisation, DbUpdateInfo))
|
||||
{
|
||||
SaLogger.Warn($"{SysUtil.Fn} Failed to update organisation [Id:{SysId.ToString(organisation.Id)}]: {AccountMgr.ErrorStateMessage}");
|
||||
return Json(responseData.SetPopupMessage(messageTitle, Localiser["msg.error.item.update.failed"] + "\n\n" + AccountMgr.ErrorStateMessage));
|
||||
}
|
||||
|
||||
// Activate awaiting members and send welcome email to each.
|
||||
foreach (OrganisationMemberData organisationMember in organisationMembersToActivate)
|
||||
{
|
||||
if (organisationMember.UserOrganisation == null) continue;
|
||||
if (AccountMgr.UpdateUserOrganisation(organisationMember.UserOrganisation, DbUpdateInfo))
|
||||
{
|
||||
if (organisationMember.UserAccount == null) continue;
|
||||
organisationMember.UserAccount.Status = SaStatus.Active;
|
||||
if (AccountMgr.UpdateUserAccount(organisationMember.UserAccount, DbUpdateInfo))
|
||||
{
|
||||
// Send activation email.
|
||||
if (SendAccountActivatedEmail(this, organisationMember.UserAccount))
|
||||
SaLogger.Info($"{SysUtil.Fn} User Activation email sent to {organisationMember.UserAccount.EmailAddress}", true);
|
||||
else SaLogger.Warn($"{SysUtil.Fn} Failed to send User Activation email to {organisationMember.UserAccount.EmailAddress}");
|
||||
}
|
||||
else
|
||||
SaLogger.Warn($"{SysUtil.Fn} Failed to update user account [Id:{SysId.ToString(organisationMember.UserAccount.Id)}]: {AccountMgr.ErrorStateMessage}");
|
||||
}
|
||||
else
|
||||
SaLogger.Warn($"{SysUtil.Fn} Failed to update user organisation [Id:{SysId.ToString(organisationMember.UserOrganisation.Id)}]: {AccountMgr.ErrorStateMessage}");
|
||||
}
|
||||
|
||||
// Construct response.
|
||||
PopulateOrganisationResponseItemData(organisation, address, responseData.organisation);
|
||||
}
|
||||
|
||||
// Complete response.
|
||||
responseData.Success = true;
|
||||
return Json(responseData);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
/// <summary>
|
||||
/// Generate the User Activation email.
|
||||
/// <para>NB URL must be to the Online application.</para>
|
||||
/// <para>NB Encryption must be done with the Online logic.</para>
|
||||
/// </summary>
|
||||
public static bool SendAccountActivatedEmail(SaxController_Admin controller, SaxUserAccount userAccount)
|
||||
{
|
||||
SaEmailData emailData = new SaEmailData();
|
||||
emailData.Config = controller.EmailConfig;
|
||||
emailData.AddressesTo.Add(userAccount.EmailAddress);
|
||||
emailData.Subject = controller.Localiser["user.activate.email.subject"];
|
||||
PopulateAccountActivatedEmailBody(controller, emailData, userAccount);
|
||||
return controller.EmailConsole.SendEmail(emailData);
|
||||
}
|
||||
private static void PopulateAccountActivatedEmailBody(SaxController_Admin controller, SaEmailData emailData, SaxUserAccount userAccount)
|
||||
{
|
||||
// Will need to handle culture (language/country) as and when introduced.
|
||||
emailData.MessageBody = SaxResourceHelper.GetResourceText(SaxResourceHelper.TextResource.Email_Security_AccountActivated_Html);
|
||||
emailData.HtmlBody = true;
|
||||
|
||||
// Replace dynamic tags.
|
||||
controller.EmailConsole.ReplaceDynamicEmailBodyTags(emailData, null, userAccount);
|
||||
|
||||
// Replace dynamic tag for link back to change password page.
|
||||
SaEmailConsole.ReplaceDynamicEmailTag(emailData, "[#Link.RequestPassword]", SecurityController.GenerateRequestPasswordLink(controller, userAccount.Id, userAccount.EmailAddress, "", true));
|
||||
SaEmailConsole.ReplaceDynamicEmailTag(emailData, "[#Link.SignIn]", controller.AppConfig.URL.Online.Root + "Security/SignIn");
|
||||
SaEmailConsole.ReplaceDynamicEmailTag(emailData, "[#Link.ExpiresMinutes]", SecurityController.GetRequestPasswordEmailLinkExpiresMinutes(controller).ToString());
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
}
|
||||
}
|
||||
+656
@@ -0,0 +1,656 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Sarand.Net.Standard.Base.App;
|
||||
using Sarand.Net.Standard.Base.Bus;
|
||||
using Sarand.Net.Standard.Base.Core;
|
||||
using Sarand.Net.Standard.Base.Dbas;
|
||||
using Sarand.Net.Standard.Base.Utils;
|
||||
using Saxonite.Net.Core.Web.Admin.Models;
|
||||
using Saxonite.Net.Standard.Base.App;
|
||||
using Saxonite.Net.Standard.Base.Bus;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Saxonite.Net.Core.Web.Admin.Controllers
|
||||
{
|
||||
//=======================================================================
|
||||
// Controller: Organisation - Ajax - Associations
|
||||
//=======================================================================
|
||||
partial class OrganisationController
|
||||
{
|
||||
//-------------------------------------------------------------------
|
||||
// Association type combinations.
|
||||
//-------------------------------------------------------------------
|
||||
private static readonly String optionLabel_AffiliatedTo = "Affiliated to";
|
||||
private static readonly String optionLabel_Affiliate = "Affiliation for";
|
||||
private static readonly String optionLabel_Partner = "Partner";
|
||||
// Associations are between two items (From & To) but in the context of
|
||||
// displaying associations for an organisation, the organisation may be
|
||||
// the 'From' item (normal) or the 'To' item (reversed).
|
||||
private class AssociationTypeData
|
||||
{
|
||||
public AssociationTypeData()
|
||||
{
|
||||
// No parameter construction - populating association details for individual item (see Populate()).
|
||||
}
|
||||
public AssociationTypeData(Sax.AssociationTypeOption associationTypeOption)
|
||||
{
|
||||
// Population on construction - generic association type definitions, eg. for drop down menu options.
|
||||
Populate(associationTypeOption);
|
||||
}
|
||||
public void Populate(Sax.AssociationTypeOption associationTypeOption)
|
||||
{
|
||||
// Default labels - option to select association etc.
|
||||
Type = ((int)associationTypeOption).ToString();
|
||||
Label = GetOptionLabel(associationTypeOption);
|
||||
}
|
||||
public void Populate(Sax.AssociationType associationType, bool reversed)
|
||||
{
|
||||
// Default labels - option to select association etc.
|
||||
Populate(GetAssociationTypeOption(associationType, reversed));
|
||||
}
|
||||
public void Populate(Sax.AssociationType associationType, bool reversed, String label)
|
||||
{
|
||||
// Populate for specific labels, eg. to identify nature of associated organisation.
|
||||
Sax.AssociationTypeOption associationTypeOption = GetAssociationTypeOption(associationType, reversed);
|
||||
Type = ((int)associationTypeOption).ToString();
|
||||
Label = label;
|
||||
}
|
||||
// Properties.
|
||||
public String Type { get; set; }
|
||||
public String Label { get; set; }
|
||||
// Utilities.
|
||||
public static Sax.AssociationTypeOption GetAssociationTypeOption(Sax.AssociationType associationType, bool reversed)
|
||||
{
|
||||
switch (associationType)
|
||||
{
|
||||
case Sax.AssociationType.Affiliate: return reversed ? Sax.AssociationTypeOption.AffiliateChild : Sax.AssociationTypeOption.AffiliateParent;
|
||||
case Sax.AssociationType.Partner: return Sax.AssociationTypeOption.Partner;
|
||||
}
|
||||
return Sax.AssociationTypeOption.Unknown;
|
||||
}
|
||||
public static String GetOptionLabel(Sax.AssociationTypeOption associationTypeOption)
|
||||
{
|
||||
switch (associationTypeOption)
|
||||
{
|
||||
case Sax.AssociationTypeOption.AffiliateParent: return optionLabel_AffiliatedTo;
|
||||
case Sax.AssociationTypeOption.AffiliateChild: return optionLabel_Affiliate;
|
||||
case Sax.AssociationTypeOption.Partner: return optionLabel_Partner;
|
||||
}
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Association data.
|
||||
//-------------------------------------------------------------------
|
||||
private class AssociationListData : AjaxResponse_Data.ItemData_Base
|
||||
{
|
||||
public class OrganisationData
|
||||
{
|
||||
public String Id { get; set; }
|
||||
public String Name { get; set; }
|
||||
public String Sport { get; set; }
|
||||
public String Region { get; set; }
|
||||
}
|
||||
public OrganisationData Organisation { get; } = new OrganisationData();
|
||||
public OrganisationData OrganisationAssoc { get; } = new OrganisationData();
|
||||
public AssociationTypeData Assoc { get; } = new AssociationTypeData();
|
||||
}
|
||||
private class AssociationItemData : AssociationListData
|
||||
{
|
||||
}
|
||||
private void PopulateAssociationResponseListData(SaxModel_Admin model, AssociationListData data, SaxItemAssociation itemAssociation, SaxOrganisation organisation, SaxOrganisation organisationAssoc)
|
||||
{
|
||||
data.Id = SysId.ToString(itemAssociation.Id);
|
||||
// Organisation.
|
||||
data.Organisation.Id = SysId.ToString(organisation.Id);
|
||||
data.Organisation.Name = organisation.Name;
|
||||
// Associated Organisation.
|
||||
data.OrganisationAssoc.Id = SysId.ToString(organisationAssoc.Id);
|
||||
data.OrganisationAssoc.Name = organisationAssoc.Name;
|
||||
if (!organisation.SportIdPrimary.Equals(organisationAssoc.SportIdPrimary))
|
||||
data.OrganisationAssoc.Sport = model.GetSportName(organisationAssoc.SportIdPrimary);
|
||||
if (!organisation.RegionIdPrimary.Equals(organisationAssoc.RegionIdPrimary))
|
||||
data.OrganisationAssoc.Region = model.GetRegionName(organisationAssoc.RegionIdPrimary);
|
||||
// Association type.
|
||||
bool associationReversed = itemAssociation.ItemIdTo.Id.Equals(organisation.Id);
|
||||
String associationLabel = "";
|
||||
if (itemAssociation.AssociationType == Sax.AssociationType.Affiliate)
|
||||
associationLabel = associationReversed ? "Member organisation" : associationLabel = "Parent organisation";
|
||||
else if (itemAssociation.AssociationType == Sax.AssociationType.Partner)
|
||||
associationLabel = "Partner organisation";
|
||||
data.Assoc.Populate(itemAssociation.AssociationType, associationReversed, associationLabel);
|
||||
// Common properties.
|
||||
data.StatusCode = itemAssociation.StatusCode;
|
||||
data.StatusDesc = itemAssociation.StatusDesc;
|
||||
}
|
||||
private void PopulateAssociationResponseItemData(SaxModel_Admin model, AssociationItemData data, SaxItemAssociation itemAssociation, SaxOrganisation organisation, SaxOrganisation organisationAssoc)
|
||||
{
|
||||
PopulateAssociationResponseListData(model, data, itemAssociation, organisation, organisationAssoc);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Get Organisation Association List ajax request.
|
||||
//-------------------------------------------------------------------
|
||||
private class AjaxResponse_AssociationList : AjaxResponse_Data
|
||||
{
|
||||
// Construction.
|
||||
public AjaxResponse_AssociationList(SaxModel_Admin model) : base(model) { }
|
||||
// Association list.
|
||||
public List<AssociationListData> Associations { get; } = new List<AssociationListData>();
|
||||
// Reference data.
|
||||
public List<AssociationTypeData> AssociationTypes { get; } = new List<AssociationTypeData>();
|
||||
public List<CodeDesc> Statuses { get; } = new List<CodeDesc>();
|
||||
public String DefaultStatusCode { get; set; }
|
||||
}
|
||||
//-------------------------------------------------------------------
|
||||
[HttpPost]
|
||||
[Route("Organisation/Ajax/GetAssociationList")]
|
||||
[Route("Organisation/Ajax/GetAssociations")]
|
||||
public IActionResult Ajax_GetAssociationList(Model_OrganisationAssociations model)
|
||||
{
|
||||
String messageTitle = Localiser["caption.organisation.associations"];
|
||||
AjaxResponse_AssociationList responseData = new AjaxResponse_AssociationList(model);
|
||||
|
||||
// Validate session.
|
||||
if (!ValidUserSession)
|
||||
return GetAjaxResult_InvalidSession(responseData);
|
||||
|
||||
// Organisation Id is mandatory.
|
||||
SysId organisationId = SysId.ToSysId(model.Filter.OrganisationId);
|
||||
if (!SysId.IsValid(organisationId))
|
||||
{
|
||||
SaLogger.Warn($"{SysUtil.Fn} Request to retrieve associations without valid organisation Id.");
|
||||
return Json(responseData.SetPopupMessage(messageTitle, Localiser["msg.error.item.id.not.specified"]));
|
||||
}
|
||||
|
||||
// Reference data - association types.
|
||||
// 'Label' is option caption to add new association of the specified type.
|
||||
responseData.AssociationTypes.Add(new AssociationTypeData(Sax.AssociationTypeOption.AffiliateParent));
|
||||
responseData.AssociationTypes.Add(new AssociationTypeData(Sax.AssociationTypeOption.AffiliateChild));
|
||||
responseData.AssociationTypes.Add(new AssociationTypeData(Sax.AssociationTypeOption.Partner));
|
||||
|
||||
// Reference data - statuses.
|
||||
foreach (SaStatus status in SaxItemAssociation.ValidStatuses.FindAll(item => item != SaStatus.Deleted))
|
||||
responseData.Statuses.Add(SacsSystem.GetStatusCode(status), Localiser.GetStatusCaption(status));
|
||||
responseData.DefaultStatusCode = SacsSystem.GetStatusCode(SaxItemAssociation.DefaultStatus);
|
||||
|
||||
// Get organisation associations.
|
||||
GetOrganisationAssociations(model, organisationId, responseData.Associations);
|
||||
|
||||
if (model.Paging.IsPaged)
|
||||
model.Paging.ItemCount = (ushort)responseData.Associations.Count;
|
||||
|
||||
// Complete response.
|
||||
responseData.SetPaging(model);
|
||||
responseData.Success = true;
|
||||
return Json(responseData);
|
||||
}
|
||||
private void GetOrganisationAssociations(SaxModel_Admin model, SysId organisationId, List<AssociationListData> associations)
|
||||
{
|
||||
// Record disposable items as they are created so all can be disposed when needed.
|
||||
using (DisposableCollection<IDisposable> disposableItems = new DisposableCollection<IDisposable>())
|
||||
{
|
||||
|
||||
// Item filter.
|
||||
SaxItemAssociation.Params prmItemAssociation = new SaxItemAssociation.Params();
|
||||
prmItemAssociation.ItemIdsIncluded.Add(new ItemId((short)Sax.DataItemType.Organisation, organisationId));
|
||||
prmItemAssociation.StatusCat = SaxItemAssociation.StatusCat.NotDeleted;
|
||||
model.Paging.ItemTotal = (ulong)ItemDataMgr.GetItemAssociationCount(prmItemAssociation);
|
||||
model.PopulatePagingTo(prmItemAssociation.ResultsPaging);
|
||||
|
||||
// Item columns.
|
||||
ColumnDfn colId = ItemDataMgr.GetItemAssociationColumnDfn(SaxItemAssociation.Column.Id);
|
||||
ColumnDfn colItemTypeFrom = ItemDataMgr.GetItemAssociationColumnDfn(SaxItemAssociation.Column.ItemTypeFrom);
|
||||
ColumnDfn colItemIdFrom = ItemDataMgr.GetItemAssociationColumnDfn(SaxItemAssociation.Column.ItemIdFrom);
|
||||
ColumnDfn colOrganisationFrom_Name = ItemDataMgr.GetItemAssociationColumnDfn(SaxItemAssociation.Column.OrganisationFrom_Name);
|
||||
ColumnDfn colOrganisationFrom_SportIdPrimary = ItemDataMgr.GetItemAssociationColumnDfn(SaxItemAssociation.Column.OrganisationFrom_SportIdPrimary);
|
||||
ColumnDfn colOrganisationFrom_RegionIdPrimary = ItemDataMgr.GetItemAssociationColumnDfn(SaxItemAssociation.Column.OrganisationFrom_RegionIdPrimary);
|
||||
ColumnDfn colItemTypeTo = ItemDataMgr.GetItemAssociationColumnDfn(SaxItemAssociation.Column.ItemTypeTo);
|
||||
ColumnDfn colItemIdTo = ItemDataMgr.GetItemAssociationColumnDfn(SaxItemAssociation.Column.ItemIdTo);
|
||||
ColumnDfn colOrganisationTo_Name = ItemDataMgr.GetItemAssociationColumnDfn(SaxItemAssociation.Column.OrganisationTo_Name);
|
||||
ColumnDfn colOrganisationTo_SportIdPrimary = ItemDataMgr.GetItemAssociationColumnDfn(SaxItemAssociation.Column.OrganisationTo_SportIdPrimary);
|
||||
ColumnDfn colOrganisationTo_RegionIdPrimary = ItemDataMgr.GetItemAssociationColumnDfn(SaxItemAssociation.Column.OrganisationTo_RegionIdPrimary);
|
||||
ColumnDfn colAssociationType = ItemDataMgr.GetItemAssociationColumnDfn(SaxItemAssociation.Column.AssociationType);
|
||||
ColumnDfn colStatus = ItemDataMgr.GetItemAssociationColumnDfn(SaxItemAssociation.Column.Status);
|
||||
List<ColumnDfn> columns = new List<ColumnDfn>()
|
||||
{
|
||||
colId,
|
||||
colItemTypeFrom, colItemIdFrom, colOrganisationFrom_Name, colOrganisationFrom_SportIdPrimary, colOrganisationFrom_RegionIdPrimary,
|
||||
colItemTypeTo, colItemIdTo, colOrganisationTo_Name, colOrganisationTo_SportIdPrimary, colOrganisationTo_RegionIdPrimary,
|
||||
colAssociationType,
|
||||
colStatus
|
||||
};
|
||||
|
||||
// Query items.
|
||||
using (DbResultSet resultSet = ItemDataMgr.ExecuteItemAssociationQuery(columns, prmItemAssociation))
|
||||
{
|
||||
while (resultSet != null && resultSet.HasRows && resultSet.NextRecord())
|
||||
{
|
||||
NamedValue.Map values = resultSet.GetRecordValues();
|
||||
AssociationListData associationData = new AssociationListData()
|
||||
{
|
||||
Id = values.GetString(colId.DataName),
|
||||
StatusCode = values.GetString(colStatus.DataName),
|
||||
StatusDesc = SacsSystem.GetStatusDescForCode(values.GetString(colStatus.DataName)),
|
||||
};
|
||||
// Items.
|
||||
bool associationReversed = false;
|
||||
ItemId itemIdFrom = new ItemId((short)values.GetLong(colItemTypeFrom.DataName), new SysId(values.GetLong(colItemIdFrom.DataName)));
|
||||
String organisationNameFrom = values.GetString(colOrganisationFrom_Name.DataName);
|
||||
SysId sportIdFrom = new SysId(values.GetLong(colOrganisationFrom_SportIdPrimary.DataName));
|
||||
SysId regionIdFrom = new SysId(values.GetLong(colOrganisationFrom_RegionIdPrimary.DataName));
|
||||
ItemId itemIdTo = new ItemId((short)values.GetLong(colItemTypeTo.DataName), new SysId(values.GetLong(colItemIdTo.DataName)));
|
||||
String organisationNameTo = values.GetString(colOrganisationTo_Name.DataName);
|
||||
SysId sportIdTo = new SysId(values.GetLong(colOrganisationTo_SportIdPrimary.DataName));
|
||||
SysId regionIdTo = new SysId(values.GetLong(colOrganisationTo_RegionIdPrimary.DataName));
|
||||
if (ItemId.IsValid(itemIdFrom) && ItemId.IsValid(itemIdTo) && itemIdFrom.Type == (int)Sax.DataItemType.Organisation && itemIdTo.Type == (int)Sax.DataItemType.Organisation)
|
||||
{
|
||||
if (itemIdFrom.Id.Equals(organisationId))
|
||||
{
|
||||
associationData.Organisation.Id = SysId.ToString(itemIdFrom.Id);
|
||||
associationData.Organisation.Name = organisationNameFrom;
|
||||
associationData.OrganisationAssoc.Id = SysId.ToString(itemIdTo.Id);
|
||||
associationData.OrganisationAssoc.Name = organisationNameTo;
|
||||
if (!sportIdFrom.Equals(sportIdTo))
|
||||
associationData.OrganisationAssoc.Sport = model.GetSportName(sportIdTo);
|
||||
if (!regionIdFrom.Equals(regionIdTo))
|
||||
associationData.OrganisationAssoc.Sport = model.GetRegionName(regionIdTo);
|
||||
}
|
||||
else if (itemIdTo.Id.Equals(organisationId))
|
||||
{
|
||||
associationReversed = true;
|
||||
associationData.Organisation.Id = SysId.ToString(itemIdTo.Id);
|
||||
associationData.Organisation.Name = organisationNameTo;
|
||||
associationData.OrganisationAssoc.Id = SysId.ToString(itemIdFrom.Id);
|
||||
associationData.OrganisationAssoc.Name = organisationNameFrom;
|
||||
if (!sportIdFrom.Equals(sportIdTo))
|
||||
associationData.OrganisationAssoc.Sport = model.GetSportName(sportIdFrom);
|
||||
if (!regionIdFrom.Equals(regionIdTo))
|
||||
associationData.OrganisationAssoc.Sport = model.GetRegionName(regionIdFrom);
|
||||
}
|
||||
else if (SacsSystem.DebugMode)
|
||||
// Track invalid associations, ie. where neither item is this organisation.
|
||||
Debugger.Break();
|
||||
}
|
||||
else if (SacsSystem.DebugMode)
|
||||
// Track invalid associations, ie. where either item is not an organisation.
|
||||
Debugger.Break();
|
||||
// Association type.
|
||||
Sax.AssociationType associationType = (Sax.AssociationType)values.GetLong(colAssociationType.DataName);
|
||||
associationData.Assoc.Populate(associationType, associationReversed);
|
||||
// Add association to the list.
|
||||
associations.Add(associationData);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Get Organisation Association ajax request.
|
||||
//-------------------------------------------------------------------
|
||||
private class AjaxResponse_Association : AjaxResponse_Data
|
||||
{
|
||||
// Construction.
|
||||
public AjaxResponse_Association(SaxModel_Admin model) : base(model) { }
|
||||
// Association details.
|
||||
public AssociationItemData Association { get; } = new AssociationItemData();
|
||||
}
|
||||
//-------------------------------------------------------------------
|
||||
[HttpPost]
|
||||
[Route("Organisation/Ajax/GetAssociation")]
|
||||
public IActionResult Ajax_GetAssociation(Model_OrganisationAssociations model)
|
||||
{
|
||||
String messageTitle = Localiser["caption.organisation.association"];
|
||||
AjaxResponse_Association responseData = new AjaxResponse_Association(model);
|
||||
|
||||
// Validate session.
|
||||
if (!ValidUserSession)
|
||||
return GetAjaxResult_InvalidSession(responseData);
|
||||
|
||||
// Record disposable items as they are created so all can be disposed when needed.
|
||||
using (DisposableCollection<IDisposable> disposableItems = new DisposableCollection<IDisposable>())
|
||||
{
|
||||
|
||||
// Identify item.
|
||||
SysId itemAssociationId = SysId.ToSysId(model.ItemAssociationId);
|
||||
if (!SysId.IsValid(itemAssociationId))
|
||||
return Json(responseData.SetPopupMessage(messageTitle, Localiser["msg.error.item.id.not.specified"]));
|
||||
|
||||
// Retrieve association.
|
||||
SaxItemAssociation itemAssociation = ItemDataMgr.GetItemAssociationById(itemAssociationId);
|
||||
disposableItems.Add(itemAssociation);
|
||||
if (itemAssociation == null)
|
||||
{
|
||||
SaLogger.Warn($"{SysUtil.Fn} Failed to retrieve Item Association for Id: '{model.ItemAssociationId}'");
|
||||
return Json(responseData.SetPopupMessage(messageTitle, Localiser["msg.error.item.id.not.found"]));
|
||||
}
|
||||
|
||||
// Identify organisations.
|
||||
SysId organisationId = SysId.ToSysId(model.OrganisationId);
|
||||
SysId organisationIdAssoc = null;
|
||||
if (!SysId.IsValid(organisationId))
|
||||
{
|
||||
SaLogger.Warn($"{SysUtil.Fn} Organisation Id must be supplied.");
|
||||
return Json(responseData.SetPopupMessage(messageTitle, Localiser["msg.error.data.incomplete"]));
|
||||
}
|
||||
|
||||
// Validate the association.
|
||||
if (itemAssociation.ItemIdFrom.Type != (int)Sax.DataItemType.Organisation)
|
||||
{
|
||||
SaLogger.Warn($"{SysUtil.Fn} Inconsistent association 'From' item type: {AssociationTypeCodes.GetCodeForType(itemAssociation.ItemIdFrom.Type)}. Expected: Organisation.");
|
||||
return Json(responseData.SetPopupMessage(messageTitle, Localiser["msg.error.data.inconsistent"]));
|
||||
}
|
||||
if (itemAssociation.ItemIdTo.Type != (int)Sax.DataItemType.Organisation)
|
||||
{
|
||||
SaLogger.Warn($"{SysUtil.Fn} Inconsistent association 'To' item type: {AssociationTypeCodes.GetCodeForType(itemAssociation.ItemIdTo.Type)}. Expected: Organisation.");
|
||||
return Json(responseData.SetPopupMessage(messageTitle, Localiser["msg.error.data.inconsistent"]));
|
||||
}
|
||||
|
||||
// Identify organisations from association items.
|
||||
// The specified organisation must be one or other of the association's items.
|
||||
if (itemAssociation.ItemIdFrom.Id.Equals(organisationId))
|
||||
organisationIdAssoc = itemAssociation.ItemIdTo.Id;
|
||||
else if (itemAssociation.ItemIdTo.Id.Equals(organisationId))
|
||||
organisationIdAssoc = itemAssociation.ItemIdFrom.Id;
|
||||
else
|
||||
{
|
||||
SaLogger.Warn($"{SysUtil.Fn} Inconsistent association - Specified organisation is neither item.");
|
||||
return Json(responseData.SetPopupMessage(messageTitle, Localiser["msg.error.data.inconsistent"]));
|
||||
}
|
||||
|
||||
// Retrieve Organisation.
|
||||
SaxOrganisation organisation = AccountMgr.GetOrganisationById(organisationId);
|
||||
disposableItems.Add(organisation);
|
||||
if (organisation == null)
|
||||
{
|
||||
SaLogger.Warn($"{SysUtil.Fn} Failed to retrieve Organisation for Id: '{organisationId}'");
|
||||
return Json(responseData.SetPopupMessage(messageTitle, Localiser["msg.error.system"]));
|
||||
}
|
||||
|
||||
// Retrieve associated Organisation.
|
||||
SaxOrganisation organisationAssoc = AccountMgr.GetOrganisationById(organisationIdAssoc);
|
||||
disposableItems.Add(organisationAssoc);
|
||||
if (organisationAssoc == null)
|
||||
{
|
||||
SaLogger.Warn($"{SysUtil.Fn} Failed to retrieve associated Organisation for Id: '{organisationIdAssoc}'");
|
||||
return Json(responseData.SetPopupMessage(messageTitle, Localiser["msg.error.system"]));
|
||||
}
|
||||
|
||||
// Construct response.
|
||||
PopulateAssociationResponseItemData(model, responseData.Association, itemAssociation, organisation, organisationAssoc);
|
||||
}
|
||||
|
||||
responseData.Success = true;
|
||||
return Json(responseData);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Store Organisation Association ajax request.
|
||||
//-------------------------------------------------------------------
|
||||
[HttpPost]
|
||||
[Route("Organisation/Ajax/StoreAssociation")]
|
||||
public IActionResult Ajax_StoreAssociation(Model_OrganisationAssociations model)
|
||||
{
|
||||
String messageTitle = Localiser["caption.organisation.association"];
|
||||
AjaxResponse_Association responseData = new AjaxResponse_Association(model);
|
||||
|
||||
// Validate session.
|
||||
if (!ValidUserSession)
|
||||
return GetAjaxResult_InvalidSession(responseData);
|
||||
|
||||
// Validate item properties.
|
||||
model.ValidateOrganisationAssociationData(responseData);
|
||||
if (responseData.HasControlErrors())
|
||||
return Json(responseData);
|
||||
|
||||
// Record disposable items as they are created so all can be disposed when needed.
|
||||
using (DisposableCollection<IDisposable> disposableItems = new DisposableCollection<IDisposable>())
|
||||
{
|
||||
|
||||
// Organisation.
|
||||
SysId organisationId = SysId.ToSysId(model.OrganisationId);
|
||||
SaxOrganisation organisation = AccountMgr.GetOrganisationById(organisationId);
|
||||
disposableItems.Add(organisation);
|
||||
if (organisation == null)
|
||||
{
|
||||
SaLogger.Warn($"{SysUtil.Fn} Failed to retrieve Organisation for Id: {model.OrganisationId}");
|
||||
return Json(responseData.SetPopupMessage(messageTitle, Localiser["msg.error.data.incomplete"]));
|
||||
}
|
||||
|
||||
// Associated Organisation.
|
||||
SysId organisationIdAssoc = SysId.ToSysId(model.OrganisationIdAssoc);
|
||||
SaxOrganisation organisationAssoc = AccountMgr.GetOrganisationById(organisationIdAssoc);
|
||||
disposableItems.Add(organisationAssoc);
|
||||
if (organisationAssoc == null)
|
||||
{
|
||||
SaLogger.Warn($"{SysUtil.Fn} Failed to retrieve associated Organisation for Id: {model.OrganisationIdAssoc}");
|
||||
return Json(responseData.SetPopupMessage(messageTitle, Localiser["msg.error.data.incomplete"]));
|
||||
}
|
||||
if (organisationIdAssoc.Equals(organisationId))
|
||||
{
|
||||
SaLogger.Warn($"{SysUtil.Fn} Associated organisation must not be the same as the organisation.");
|
||||
return Json(responseData.SetPopupMessage(messageTitle, Localiser["msg.error.data.inconsistent"]));
|
||||
}
|
||||
|
||||
// Association type.
|
||||
Sax.AssociationType associationType = model.GetAssociationTypeForOption(model.Association.GetAssociationTypeOption());
|
||||
if ((int)associationType < 1)
|
||||
{
|
||||
SaLogger.Warn($"{SysUtil.Fn} Association Type must be specified.");
|
||||
return Json(responseData.SetPopupMessage(messageTitle, Localiser["msg.error.data.inconsistent"]));
|
||||
}
|
||||
Sax.AssociationTypeOption associationTypeOption = model.Association.GetAssociationTypeOption();
|
||||
if ((int)associationTypeOption < 1)
|
||||
{
|
||||
SaLogger.Warn($"{SysUtil.Fn} Association Type Option must be specified.");
|
||||
return Json(responseData.SetPopupMessage(messageTitle, Localiser["msg.error.data.inconsistent"]));
|
||||
}
|
||||
if (!model.IsConsistentWith(associationTypeOption, associationType))
|
||||
{
|
||||
SaLogger.Warn($"{SysUtil.Fn} Association Type Option ({associationTypeOption}) is inconsistent with Association Type ({associationType}).");
|
||||
return Json(responseData.SetPopupMessage(messageTitle, Localiser["msg.error.data.inconsistent"]));
|
||||
}
|
||||
|
||||
// Identify From/To items.
|
||||
ItemId itemIdFrom = organisation.GetItemId();
|
||||
ItemId itemIdTo = organisationAssoc.GetItemId();
|
||||
if (model.IsAssociationTypeDirectionReversed(associationTypeOption))
|
||||
{
|
||||
itemIdFrom = organisationAssoc.GetItemId();
|
||||
itemIdTo = organisation.GetItemId();
|
||||
}
|
||||
|
||||
// Retrieve existing association.
|
||||
SysId itemAssociationId = SysId.ToSysId(model.ItemAssociationId);
|
||||
if (SysId.IsValid(itemAssociationId) == StringUtil.ToBool(model.NewItem))
|
||||
{
|
||||
// Inconsistentcy between the 'Existing' flag and whether the Item Association Id has been specified.
|
||||
SaLogger.Warn($"{SysUtil.Fn} Item Association Id " + (StringUtil.ToBool(model.NewItem) ? "specified for new item" : "not specified for existing item") + ".");
|
||||
return Json(responseData.SetPopupMessage(messageTitle, Localiser["msg.error.data.inconsistent"]));
|
||||
}
|
||||
SaxItemAssociation itemAssociation = ItemDataMgr.GetItemAssociationById(itemAssociationId);
|
||||
if (itemAssociation == null && StringUtil.ToBool(model.NewItem))
|
||||
{
|
||||
// Check whether there's a matching association for the 'new' association with 'deleted' status.
|
||||
SaxItemAssociation.Params prmItemAsociation = new SaxItemAssociation.Params();
|
||||
prmItemAsociation.ItemIdsIncluded.Add(organisation.GetItemId());
|
||||
prmItemAsociation.AssociationTypesIncluded.Add(associationType);
|
||||
prmItemAsociation.StatusCat = SaxItemAssociation.StatusCat.DeletedOnly;
|
||||
foreach (SaxItemAssociation itemAssociationCandidate in ItemDataMgr.GetItemAssociationList(prmItemAsociation))
|
||||
{
|
||||
if (itemAssociationCandidate.ItemIdFrom.Equals(organisationAssoc.GetItemId()) || itemAssociationCandidate.ItemIdTo.Equals(organisationAssoc.GetItemId()))
|
||||
{
|
||||
itemAssociation = itemAssociationCandidate;
|
||||
itemAssociation.Status = SaxItemAssociation.DefaultStatus;
|
||||
break;
|
||||
}
|
||||
disposableItems.Add(itemAssociationCandidate);
|
||||
}
|
||||
}
|
||||
disposableItems.Add(itemAssociation);
|
||||
if (itemAssociation == null && SysId.IsValid(itemAssociationId))
|
||||
{
|
||||
SaLogger.Warn($"{SysUtil.Fn} Failed to retrieve item association for Id: '{itemAssociationId}'");
|
||||
return Json(responseData.SetPopupMessage(messageTitle, Localiser["msg.error.item.id.not.found"]));
|
||||
}
|
||||
|
||||
if (itemAssociation != null)
|
||||
{
|
||||
// Check if item relationship has been reversed, eg. from parent to child.
|
||||
bool associationReversed = itemAssociation.ItemIdTo.Id.Equals(organisation.Id);
|
||||
if (model.IsAssociationTypeDirectionReversed(associationTypeOption) != model.IsAssociationTypeDirectionReversed(AssociationTypeData.GetAssociationTypeOption(itemAssociation.AssociationType, associationReversed)))
|
||||
{
|
||||
// Logical direction has been reversed from that stored.
|
||||
// Items must be switched.
|
||||
ItemId itemAssociationItemIdFrom = itemAssociation.ItemIdFrom;
|
||||
itemAssociation.ItemIdFrom = itemAssociation.ItemIdTo;
|
||||
itemAssociation.ItemIdTo = itemAssociationItemIdFrom;
|
||||
}
|
||||
// Validate From/To items.
|
||||
if (!itemAssociation.ItemIdFrom.Equals(itemIdFrom))
|
||||
{
|
||||
SaLogger.Warn($"{SysUtil.Fn} Inconsistent association - expected 'From' Item Id: {SysId.ToString(itemIdFrom.Id)}. Found: {SysId.ToString(itemAssociation.ItemIdFrom.Id)}");
|
||||
return Json(responseData.SetPopupMessage(messageTitle, Localiser["msg.error.system"]));
|
||||
}
|
||||
if (!itemAssociation.ItemIdTo.Equals(itemIdTo))
|
||||
{
|
||||
SaLogger.Warn($"{SysUtil.Fn} Inconsistent association - expected 'To' Item Id: {SysId.ToString(itemIdTo.Id)}. Found: {SysId.ToString(itemAssociation.ItemIdTo.Id)}");
|
||||
return Json(responseData.SetPopupMessage(messageTitle, Localiser["msg.error.system"]));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Item Association not identified.
|
||||
|
||||
// Check for deleted association that can be reused.
|
||||
SaxItemAssociation.Params itemAssociationParams = new SaxItemAssociation.Params();
|
||||
|
||||
if (itemAssociation != null)
|
||||
itemAssociation.Status = SaxItemAssociation.DefaultStatus;
|
||||
else
|
||||
{
|
||||
// Association not found - create a new one.
|
||||
itemAssociation = ItemDataMgr.CreateItemAssociation(itemIdFrom, itemIdTo, associationType);
|
||||
}
|
||||
disposableItems.Add(itemAssociation);
|
||||
}
|
||||
|
||||
// Populate item properties.
|
||||
if (model.Association.StatusCode != null)
|
||||
itemAssociation.Status = model.Association.GetStatus();
|
||||
|
||||
// Store item.
|
||||
if (!SysId.IsValid(itemAssociation.Id))
|
||||
{
|
||||
if (!ItemDataMgr.InsertItemAssociation(itemAssociation, DbUpdateInfo))
|
||||
{
|
||||
SaLogger.Warn($"{SysUtil.Fn} Failed to insert item association: {ItemDataMgr.ErrorStateMessage}");
|
||||
return Json(responseData.SetPopupMessage(messageTitle, Localiser["msg.error.item.insert.failed"] + "\n\n" + ItemDataMgr.ErrorStateMessage));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!ItemDataMgr.UpdateItemAssociation(itemAssociation, DbUpdateInfo))
|
||||
{
|
||||
SaLogger.Warn($"{SysUtil.Fn} Failed to update item association [Id:{SysId.ToString(itemAssociation.Id)}]: {ItemDataMgr.ErrorStateMessage}");
|
||||
return Json(responseData.SetPopupMessage(messageTitle, Localiser["msg.error.item.update.failed"] + "\n\n" + ItemDataMgr.ErrorStateMessage));
|
||||
}
|
||||
}
|
||||
|
||||
// Construct response.
|
||||
PopulateAssociationResponseItemData(model, responseData.Association, itemAssociation, organisation, organisationAssoc);
|
||||
}
|
||||
|
||||
responseData.Success = true;
|
||||
return Json(responseData);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Remove Organisation Association ajax request.
|
||||
//-------------------------------------------------------------------
|
||||
[HttpPost]
|
||||
[Route("Organisation/Ajax/RemoveAssociation")]
|
||||
public IActionResult Ajax_RemoveAssociation(Model_OrganisationAssociations model)
|
||||
{
|
||||
String messageTitle = Localiser["caption.organisation.association"];
|
||||
AjaxResponse_Association responseData = new AjaxResponse_Association(model);
|
||||
|
||||
// Validate session.
|
||||
if (!ValidUserSession)
|
||||
return GetAjaxResult_InvalidSession(responseData);
|
||||
|
||||
// Record disposable items as they are created so all can be disposed when needed.
|
||||
using (DisposableCollection<IDisposable> disposableItems = new DisposableCollection<IDisposable>())
|
||||
{
|
||||
|
||||
// Organisation.
|
||||
SysId organisationId = SysId.ToSysId(model.OrganisationId);
|
||||
SaxOrganisation organisation = AccountMgr.GetOrganisationById(organisationId);
|
||||
disposableItems.Add(organisation);
|
||||
if (organisation == null)
|
||||
{
|
||||
SaLogger.Warn($"{SysUtil.Fn} Failed to retrieve Organisation for Id: '{model.OrganisationId}'");
|
||||
return Json(responseData.SetPopupMessage(messageTitle, Localiser["msg.error.data.incomplete"]));
|
||||
}
|
||||
|
||||
// Association Organisation.
|
||||
SysId organisationIdAssoc = SysId.ToSysId(model.OrganisationIdAssoc);
|
||||
SaxOrganisation organisationAssoc = AccountMgr.GetOrganisationById(organisationIdAssoc);
|
||||
disposableItems.Add(organisationAssoc);
|
||||
if (organisationAssoc == null)
|
||||
{
|
||||
SaLogger.Warn($"{SysUtil.Fn} Failed to retrieve associated Organisation for Id: '{model.OrganisationIdAssoc}'");
|
||||
return Json(responseData.SetPopupMessage(messageTitle, Localiser["msg.error.data.incomplete"]));
|
||||
}
|
||||
if (organisationIdAssoc.Equals(organisationId))
|
||||
{
|
||||
SaLogger.Warn($"{SysUtil.Fn} Associated organisation must not be the same as the organisation.");
|
||||
return Json(responseData.SetPopupMessage(messageTitle, Localiser["msg.error.data.inconsistent"]));
|
||||
}
|
||||
|
||||
// Item Association.
|
||||
SysId itemAssociationId = SysId.ToSysId(model.ItemAssociationId);
|
||||
SaxItemAssociation itemAssociation = ItemDataMgr.GetItemAssociationById(itemAssociationId);
|
||||
disposableItems.Add(itemAssociation);
|
||||
if (itemAssociation == null)
|
||||
{
|
||||
SaLogger.Warn($"{SysUtil.Fn} Failed to retrieve Item Association for Id: '{itemAssociationId}'");
|
||||
return Json(responseData.SetPopupMessage(messageTitle, Localiser["msg.error.item.id.not.found"]));
|
||||
}
|
||||
|
||||
// Validate association Item Ids.
|
||||
if (!itemAssociation.ItemIdFrom.Id.Equals(organisation.Id) && !itemAssociation.ItemIdTo.Id.Equals(organisation.Id))
|
||||
{
|
||||
SaLogger.Warn($"{SysUtil.Fn} Inconsistent item association properties. Organisation must be 'From' or 'To' item");
|
||||
return Json(responseData.SetPopupMessage(messageTitle, Localiser["msg.error.data.inconsistent"]));
|
||||
}
|
||||
if (!itemAssociation.ItemIdFrom.Id.Equals(organisationAssoc.Id) && !itemAssociation.ItemIdTo.Id.Equals(organisationAssoc.Id))
|
||||
{
|
||||
SaLogger.Warn($"{SysUtil.Fn} Inconsistent item association properties. Associated Organisation must be 'From' or 'To' item");
|
||||
return Json(responseData.SetPopupMessage(messageTitle, Localiser["msg.error.data.inconsistent"]));
|
||||
}
|
||||
|
||||
// Logically delete item.
|
||||
itemAssociation.Status = SaStatus.Deleted;
|
||||
if (!ItemDataMgr.UpdateItemAssociation(itemAssociation, DbUpdateInfo))
|
||||
{
|
||||
SaLogger.Warn($"{SysUtil.Fn} Failed to update Item Association [Id:{SysId.ToString(itemAssociation.Id)}]: {ItemDataMgr.ErrorStateMessage}");
|
||||
return Json(responseData.SetPopupMessage(messageTitle, Localiser["msg.error.item.update.failed"] + "\n\n" + ItemDataMgr.ErrorStateMessage));
|
||||
}
|
||||
|
||||
// Construct response.
|
||||
PopulateAssociationResponseItemData(model, responseData.Association, itemAssociation, organisation, organisationAssoc);
|
||||
}
|
||||
|
||||
responseData.Success = true;
|
||||
return Json(responseData);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
}
|
||||
//=======================================================================
|
||||
}
|
||||
+315
@@ -0,0 +1,315 @@
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Sarand.Net.Standard.Base.App;
|
||||
using Sarand.Net.Standard.Base.Bus;
|
||||
using Sarand.Net.Standard.Base.Core;
|
||||
using Sarand.Net.Standard.Base.Dbas;
|
||||
using Sarand.Net.Standard.Base.Helpers;
|
||||
using Sarand.Net.Standard.Base.Utils;
|
||||
using Saxonite.Net.Core.Web.Admin.Models;
|
||||
using Saxonite.Net.Standard.Base.App;
|
||||
using Saxonite.Net.Standard.Base.Bus;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Specialized;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Saxonite.Net.Core.Web.Admin.Controllers
|
||||
{
|
||||
//=======================================================================
|
||||
// Controller: Organisation - Ajax - Images
|
||||
//=======================================================================
|
||||
partial class OrganisationController
|
||||
{
|
||||
//-------------------------------------------------------------------
|
||||
private class OrganisationImagesData : OrganisationItemData
|
||||
{
|
||||
}
|
||||
private void PopulateOrganisationResponseImagesData(SaxOrganisation organisation, SaxItemAddress address, OrganisationImagesData data)
|
||||
{
|
||||
PopulateOrganisationResponseItemData(organisation, address, data);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Get Organisation Images ajax request.
|
||||
//-------------------------------------------------------------------
|
||||
private class AjaxResponse_OrganisationImages : AjaxResponse_Data
|
||||
{
|
||||
// Construction.
|
||||
public AjaxResponse_OrganisationImages(SaxModel_Admin model) : base(model) { }
|
||||
// Organisation details.
|
||||
public OrganisationImagesData organisation { get; } = new OrganisationImagesData();
|
||||
// Reference data.
|
||||
public List<String> ImageContentTypes { get; set; }
|
||||
}
|
||||
//-------------------------------------------------------------------
|
||||
[HttpPost]
|
||||
[Route("Organisation/Ajax/GetImages")]
|
||||
[Route("Organisation/Ajax/GetItemImages")]
|
||||
public IActionResult Ajax_GetImages(Model_Organisation model)
|
||||
{
|
||||
String messageTitle = Localiser["caption.organisation"];
|
||||
AjaxResponse_OrganisationImages responseData = new AjaxResponse_OrganisationImages(model);
|
||||
|
||||
// Validate session.
|
||||
if (!ValidUserSession)
|
||||
return GetAjaxResult_InvalidSession(responseData);
|
||||
|
||||
// Record disposable items as they are created so all can be disposed when needed.
|
||||
using (DisposableCollection<IDisposable> disposableItems = new DisposableCollection<IDisposable>())
|
||||
{
|
||||
|
||||
// Reference data - Image content types.
|
||||
responseData.ImageContentTypes = SaxItemImage.GetValidContentTypes(Sax.DataItemType.Organisation);
|
||||
|
||||
// Identify item.
|
||||
SysId organisationId = SysId.ToSysId(model.OrganisationId);
|
||||
if (!SysId.IsValid(organisationId))
|
||||
return Json(responseData.SetPopupMessage(messageTitle, Localiser["msg.error.item.id.not.specified"]));
|
||||
|
||||
// Retrieve item.
|
||||
SaxOrganisation organisation = AccountMgr.GetOrganisationById(organisationId);
|
||||
disposableItems.Add(organisation);
|
||||
if (organisation == null)
|
||||
{
|
||||
SaLogger.Warn($"{SysUtil.Fn} Failed to retrieve organisation for Id: '{model.OrganisationId}'");
|
||||
return Json(responseData.SetPopupMessage(messageTitle, Localiser["msg.error.item.id.not.found"]));
|
||||
}
|
||||
|
||||
// Organisation address.
|
||||
SaxItemAddress address = ItemDataMgr.GetFirstItemAddressByItemAndType(organisation.GetItemId());
|
||||
disposableItems.Add(address);
|
||||
|
||||
// Construct response.
|
||||
PopulateOrganisationResponseImagesData(organisation, address, responseData.organisation);
|
||||
|
||||
// Complete response.
|
||||
responseData.Success = true;
|
||||
}
|
||||
return Json(responseData);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Account - Upload Contact Image.
|
||||
// Ref. http://www.binaryintellect.net/articles/474dc031-087f-4b81-b994-9ca2adb949d6.aspx
|
||||
//-------------------------------------------------------------------
|
||||
private class AjaxResponse_UploadOrganisationLogoImage : AjaxResponse_Data
|
||||
{
|
||||
// Construction.
|
||||
public AjaxResponse_UploadOrganisationLogoImage(SaxModel_Admin model) : base(model) { }
|
||||
// Uploaded image URL.
|
||||
public String ImageUrl { get; set; }
|
||||
// Upload message.
|
||||
public String UploadMsg { get; set; }
|
||||
}
|
||||
// Ajax request.
|
||||
[HttpPost]
|
||||
[Route("Organisation/Ajax/UploadLogo")]
|
||||
[Route("Organisation/Ajax/UploadLogoImage")]
|
||||
public IActionResult UploadOrganisationLogoImage(Model_Organisation model)
|
||||
{
|
||||
AjaxResponse_UploadOrganisationLogoImage responseData = new AjaxResponse_UploadOrganisationLogoImage(model);
|
||||
String messageTitle = Localiser["caption.organisation"];
|
||||
|
||||
// Validate session and referrer.
|
||||
if (!ValidReferer) return Forbid();
|
||||
if (!ValidUserSession) return GetAjaxResult_InvalidSession(responseData);
|
||||
RefreshModel(model);
|
||||
|
||||
// Record disposable items as they are created so all can be disposed when needed.
|
||||
using (DisposableCollection<IDisposable> disposableItems = new DisposableCollection<IDisposable>())
|
||||
{
|
||||
// Retrieve organisation.
|
||||
SysId organisationId = SysId.ToSysId(model.OrganisationId);
|
||||
if (!SysId.IsValid(organisationId))
|
||||
return Json(responseData.SetPopupMessage(messageTitle, Localiser["msg.error.item.id.not.specified"]));
|
||||
SaxOrganisation organisation = AccountMgr.GetOrganisationById(organisationId);
|
||||
disposableItems.Add(organisation);
|
||||
if (organisation == null)
|
||||
{
|
||||
SaLogger.Warn($"{SysUtil.Fn} Failed to retrieve organisation for Id: '{model.OrganisationId}'");
|
||||
return Json(responseData.SetPopupMessage(messageTitle, Localiser["msg.error.item.id.not.found"]));
|
||||
}
|
||||
|
||||
// Validate number of images.
|
||||
if (model.OrganisationLogoImage.IsEmpty())
|
||||
{
|
||||
SaLogger.Warn($"{SysUtil.Fn} No image file supplied for upload");
|
||||
return Json(responseData);
|
||||
}
|
||||
if (model.OrganisationLogoImage.Count != 1)
|
||||
{
|
||||
SaLogger.Warn($"{SysUtil.Fn} Invalid number of image files uploaded: {model.OrganisationLogoImage.Count}");
|
||||
return Json(responseData.SetControlError("OrganisationLogoImage", Localiser["msg.upload.image.single"]));
|
||||
}
|
||||
IFormFile file = model.OrganisationLogoImage[0];
|
||||
|
||||
// Image properties.
|
||||
byte[] imageData = null;
|
||||
using (MemoryStream fileStream = new MemoryStream())
|
||||
{
|
||||
file.CopyTo(fileStream);
|
||||
imageData = fileStream.ToArray();
|
||||
}
|
||||
|
||||
// Validate content type.
|
||||
if (StringUtil.IsEmpty(file.ContentType) || !SaxItemImage.GetValidContentTypes(Sax.DataItemType.Organisation).ContainsCI(file.ContentType))
|
||||
return Json(responseData.SetControlError("OrganisationLogoImage", Localiser["msg.upload.image.invalid.content.type"]));
|
||||
Sarand.Net.Standard.Base.Core.Sacs.MimeType mimeTypeExpected = SacsContentTypeHelper.GetMimeTypeFromContentType(file.ContentType);
|
||||
|
||||
// Validate the image.
|
||||
ImageUtils.ImageConfig imageConfig = null;
|
||||
if (mimeTypeExpected == Sarand.Net.Standard.Base.Core.Sacs.MimeType.Svg)
|
||||
imageConfig = ImageUtils.VerifySvgImageData(imageData);
|
||||
else
|
||||
imageConfig = ImageUtils.VerifyImageData(imageData);
|
||||
if (!imageConfig.ValidImage)
|
||||
return Json(responseData.SetControlError("OrganisationLogoImage", Localiser["msg.upload.image.invalid"]));
|
||||
|
||||
// Validate mime type.
|
||||
if (!SaxItemImage.GetValidMimeTypes(Sax.DataItemType.Organisation).Contains(imageConfig.MimeType))
|
||||
return Json(responseData.SetControlError("OrganisationLogoImage", Localiser["msg.upload.image.invalid.mime"]));
|
||||
if (imageConfig.MimeType != mimeTypeExpected)
|
||||
{
|
||||
SaLogger.Warn($"{SysUtil.Fn} Image upload - inconsistent Mime. Filename: {file.FileName}. Mime: {imageConfig.MimeType}. Expected Mime: {mimeTypeExpected}.");
|
||||
return Json(responseData.SetControlError("OrganisationLogoImage", Localiser["msg.upload.image.invalid"]));
|
||||
}
|
||||
|
||||
// Resize the image if required.
|
||||
if (!ImageUtils.ConstrainImage(imageConfig, Sax.Config.Organisation.Logo.WidthMax, Sax.Config.Organisation.Logo.HeightMax))
|
||||
return Json(responseData.SetControlError("OrganisationLogoImage", Localiser["msg.upload.image.resize.failed"]));
|
||||
|
||||
// Image belongs to the organisation.
|
||||
ItemId organisationItemId = organisation.GetItemId();
|
||||
|
||||
// Store uploaded image as 'Upload' Logo - awaiting confirmation that the details are to be saved.
|
||||
SaxItemImage itemImage = ItemDataMgr.GetItemImage(organisationItemId, Sax.ImageType.OrganisationLogo_Upload, SaxItemImage.StatusCat.Any);
|
||||
if (itemImage == null)
|
||||
itemImage = ItemDataMgr.CreateItemImage(organisationItemId, Sax.ImageType.OrganisationLogo_Upload);
|
||||
itemImage.Filename = file.FileName;
|
||||
itemImage.Mime = SacsContentTypeHelper.GetMimeTypeFromContentType(file.ContentType).ToString().ToLower();
|
||||
itemImage.ContentType = file.ContentType;
|
||||
itemImage.ImageData = imageConfig.ImageData;
|
||||
itemImage.Width = imageConfig.Width;
|
||||
itemImage.Height = imageConfig.Height;
|
||||
itemImage.Status = SaxItemImage.DefaultStatus;
|
||||
|
||||
if (!SysId.IsValid(itemImage.Id))
|
||||
{
|
||||
if (!ItemDataMgr.InsertItemImage(itemImage, DbUpdateInfo))
|
||||
{
|
||||
SaLogger.Warn($"{SysUtil.Fn} Failed to insert uploaded image - {ItemDataMgr.ErrorStateMessage}");
|
||||
return Json(responseData.SetControlError("OrganisationLogoImage", Localiser["msg.error.item.insert.failed"]));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!ItemDataMgr.UpdateItemImage(itemImage, DbUpdateInfo))
|
||||
{
|
||||
SaLogger.Warn($"{SysUtil.Fn} Failed to update uploaded image - {ItemDataMgr.ErrorStateMessage}");
|
||||
return Json(responseData.SetControlError("OrganisationLogoImage", Localiser["msg.error.item.insert.failed"]));
|
||||
}
|
||||
}
|
||||
|
||||
// Return image url with response.
|
||||
responseData.ImageUrl = GetOrganisationLogoLink(organisation.Id, true);
|
||||
}
|
||||
|
||||
// Complete response.
|
||||
responseData.SetNotifyMessage(messageTitle, "Image uploaded.");
|
||||
responseData.Success = true;
|
||||
return Json(responseData);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Store Organisation Images ajax request.
|
||||
//-------------------------------------------------------------------
|
||||
[HttpPost]
|
||||
[Route("Organisation/Ajax/StoreImages")]
|
||||
public IActionResult Ajax_StoreImages(Model_Organisation model)
|
||||
{
|
||||
String messageTitle = Localiser["caption.organisation"];
|
||||
AjaxResponse_OrganisationImages responseData = new AjaxResponse_OrganisationImages(model);
|
||||
|
||||
// Validate session.
|
||||
if (!ValidUserSession)
|
||||
return GetAjaxResult_InvalidSession(responseData);
|
||||
|
||||
// Record disposable items as they are created so all can be disposed when needed.
|
||||
using (DisposableCollection<IDisposable> disposableItems = new DisposableCollection<IDisposable>())
|
||||
{
|
||||
|
||||
// Validate item properties.
|
||||
model.ValidateOrganisationData(responseData);
|
||||
if (responseData.HasControlErrors())
|
||||
return Json(responseData);
|
||||
|
||||
// Retrieve organisation.
|
||||
SysId organisationId = SysId.ToSysId(model.OrganisationId);
|
||||
SaxOrganisation organisation = AccountMgr.GetOrganisationById(organisationId);
|
||||
disposableItems.Add(organisation);
|
||||
if (organisation == null)
|
||||
{
|
||||
SaLogger.Warn($"{SysUtil.Fn} Failed to retrieve organisation for Id: '{model.OrganisationId}'");
|
||||
return Json(responseData.SetPopupMessage(messageTitle, Localiser["msg.error.item.id.not.found"]));
|
||||
}
|
||||
|
||||
// Organisation address.
|
||||
SaxItemAddress address = ItemDataMgr.GetFirstItemAddressByItemAndType(organisation.GetItemId());
|
||||
disposableItems.Add(address);
|
||||
|
||||
// Check for uploaded logo image.
|
||||
ItemId organisationItemId = organisation.GetItemId();
|
||||
SaxItemImage itemImageLogoUploaded = ItemDataMgr.GetItemImage(organisationItemId, Sax.ImageType.OrganisationLogo_Upload, SaxItemImage.StatusCat.ActiveOnly);
|
||||
disposableItems.Add(itemImageLogoUploaded);
|
||||
if (itemImageLogoUploaded != null)
|
||||
{
|
||||
// Retrieve current OrganisationLogo image.
|
||||
SaxItemImage itemImageLogo = ItemDataMgr.GetItemImage(organisationItemId, Sax.ImageType.OrganisationLogo, SaxItemImage.StatusCat.Any);
|
||||
if (itemImageLogo == null)
|
||||
itemImageLogo = ItemDataMgr.CreateItemImage(organisationItemId, Sax.ImageType.OrganisationLogo);
|
||||
disposableItems.Add(itemImageLogo);
|
||||
// Copy properties from uploaded image.
|
||||
itemImageLogo.Filename = itemImageLogoUploaded.Filename;
|
||||
itemImageLogo.Mime = itemImageLogoUploaded.Mime;
|
||||
itemImageLogo.ContentType = itemImageLogoUploaded.ContentType;
|
||||
itemImageLogo.Width = itemImageLogoUploaded.Width;
|
||||
itemImageLogo.Height = itemImageLogoUploaded.Height;
|
||||
itemImageLogo.ImageData = itemImageLogoUploaded.ImageData;
|
||||
itemImageLogo.Status = SaxItemImage.DefaultStatus;
|
||||
if (!SysId.IsValid(itemImageLogo.Id))
|
||||
{
|
||||
if (!ItemDataMgr.InsertItemImage(itemImageLogo, DbUpdateInfo))
|
||||
{
|
||||
SaLogger.Warn($"{SysUtil.Fn} Failed to insert logo image - {ItemDataMgr.ErrorStateMessage}");
|
||||
return Json(responseData.SetControlError("AccountContactImage", Localiser["msg.error.item.insert.failed"]));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!ItemDataMgr.UpdateItemImage(itemImageLogo, DbUpdateInfo))
|
||||
{
|
||||
SaLogger.Warn($"{SysUtil.Fn} Failed to update logo image - {ItemDataMgr.ErrorStateMessage}");
|
||||
return Json(responseData.SetControlError("AccountContactImage", Localiser["msg.error.item.update.failed"]));
|
||||
}
|
||||
}
|
||||
// Logically delete the uplaoded image.
|
||||
itemImageLogoUploaded.Status = SaStatus.Deleted;
|
||||
if (!ItemDataMgr.UpdateItemImage(itemImageLogoUploaded, DbUpdateInfo))
|
||||
SaLogger.Warn($"{SysUtil.Fn} Failed to logically delete uploaded logo image - {ItemDataMgr.ErrorStateMessage}");
|
||||
}
|
||||
|
||||
// Construct response.
|
||||
PopulateOrganisationResponseImagesData(organisation, address, responseData.organisation);
|
||||
}
|
||||
// Complete response.
|
||||
responseData.Success = true;
|
||||
return Json(responseData);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
}
|
||||
//=======================================================================
|
||||
}
|
||||
+466
@@ -0,0 +1,466 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Sarand.Net.Standard.Base.App;
|
||||
using Sarand.Net.Standard.Base.Bus;
|
||||
using Sarand.Net.Standard.Base.Core;
|
||||
using Sarand.Net.Standard.Base.Dbas;
|
||||
using Sarand.Net.Standard.Base.Utils;
|
||||
using Saxonite.Net.Core.Web.Admin.Models;
|
||||
using Saxonite.Net.Standard.Base.App;
|
||||
using Saxonite.Net.Standard.Base.Bus;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Saxonite.Net.Core.Web.Admin.Controllers
|
||||
{
|
||||
//=======================================================================
|
||||
// Controller: Organisation - Ajax - Members
|
||||
//=======================================================================
|
||||
partial class OrganisationController
|
||||
{
|
||||
//-------------------------------------------------------------------
|
||||
// Member data.
|
||||
private class MemberListData : AjaxResponse_Data.ItemData_Base
|
||||
{
|
||||
// User.
|
||||
public String UserAccountId { get; set; }
|
||||
public bool? Self { get; set; } = null;
|
||||
public String EmailAddress { get; set; }
|
||||
public String DisplayName { get; set; }
|
||||
public String UserStatusCode { get; set; }
|
||||
public String UserStatusDesc { get; set; }
|
||||
public bool? UserActive { get { return UserStatusCode.EqualsCI(SacsSystem.GetStatusCode(SaStatus.Active)) ? true : (bool?)null; } }
|
||||
// Organisation.
|
||||
public String OrganisationId { get; set; }
|
||||
public String OrganisationName { get; set; }
|
||||
// Organisation user.
|
||||
public int RoleCount { get; set; }
|
||||
public bool? Member { get; set; } = null;
|
||||
}
|
||||
private class MemberItemData : MemberListData
|
||||
{
|
||||
// Organisation user.
|
||||
public List<String> RoleCodes { get; } = new List<string>();
|
||||
}
|
||||
private void PopulateMemberResponseListData(MemberListData data, SaxUserOrganisation userOrganisation, SaxUserAccount userAccount, SaxOrganisation organisation)
|
||||
{
|
||||
data.Id = SysId.ToString(userOrganisation.Id);
|
||||
// User.
|
||||
data.UserAccountId = SysId.ToString(userAccount.Id);
|
||||
if (userAccount.Id.Equals(SessionUserAccountId)) data.Self = true;
|
||||
data.EmailAddress = userAccount.EmailAddress;
|
||||
data.DisplayName = userAccount.GetDisplayName();
|
||||
data.UserStatusCode = userAccount.StatusCode;
|
||||
data.UserStatusDesc = userAccount.StatusDesc;
|
||||
// Organisation.
|
||||
data.OrganisationId = SysId.ToString(organisation.Id);
|
||||
data.OrganisationName = organisation.Name;
|
||||
// Organisation user:
|
||||
data.RoleCount = userOrganisation.OrganisationRoleCount - 1;
|
||||
data.StatusCode = userOrganisation.StatusCode;
|
||||
data.StatusDesc = userOrganisation.StatusDesc;
|
||||
if (userOrganisation.GetOrganisationRoles().ToList().Exists(item => item == Sax.OrganisationRole.Member))
|
||||
data.Member = true;
|
||||
}
|
||||
private void PopulateMemberResponseItemData(MemberItemData data, SaxUserOrganisation userOrganisation, SaxUserAccount userAccount, SaxOrganisation organisation)
|
||||
{
|
||||
PopulateMemberResponseListData(data, userOrganisation, userAccount, organisation);
|
||||
// Organisation user:
|
||||
// Exclude 'Member' role.
|
||||
foreach (Sax.OrganisationRole organisationRole in userOrganisation.GetOrganisationRoles().ToList().FindAll(item => item != Sax.OrganisationRole.Member))
|
||||
data.RoleCodes.Add(OrganisationRoleCodes.GetCodeForType(organisationRole));
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Get Organisation Member List ajax request.
|
||||
//-------------------------------------------------------------------
|
||||
private class AjaxResponse_MemberList : AjaxResponse_Data
|
||||
{
|
||||
// Construction.
|
||||
public AjaxResponse_MemberList(SaxModel_Admin model) : base(model) { }
|
||||
// Member list.
|
||||
public List<MemberListData> Members { get; } = new List<MemberListData>();
|
||||
// Reference data.
|
||||
public List<CodeDesc> MemberRoles { get; } = new List<CodeDesc>();
|
||||
public List<CodeDesc> Statuses { get; } = new List<CodeDesc>();
|
||||
public String DefaultStatusCode { get; set; }
|
||||
}
|
||||
//-------------------------------------------------------------------
|
||||
[HttpPost]
|
||||
[Route("Organisation/Ajax/GetMemberList")]
|
||||
public IActionResult Ajax_GetMemberList(Model_OrganisationMembers model)
|
||||
{
|
||||
String messageTitle = Localiser["caption.organisation.members"];
|
||||
AjaxResponse_MemberList responseData = new AjaxResponse_MemberList(model);
|
||||
|
||||
// Validate session.
|
||||
if (!ValidUserSession)
|
||||
return GetAjaxResult_InvalidSession(responseData);
|
||||
|
||||
// Organisation Id filter is mandatory.
|
||||
SysId organisationId = SysId.ToSysId(model.Filter.OrganisationId);
|
||||
if (!SysId.IsValid(organisationId))
|
||||
{
|
||||
SaLogger.Warn($"{SysUtil.Fn} Request to retrieve members without valid organisation Id.");
|
||||
return Json(responseData.SetPopupMessage(messageTitle, Localiser["msg.error.item.id.not.specified"]));
|
||||
}
|
||||
|
||||
// Reference data - organisation roles.
|
||||
// Exclude 'Member' as this is added automatically when stored.
|
||||
foreach (TypeCodeDesc organisationRole in OrganisationRoleCodes.FindAll(item => item.Type != (int)Sax.OrganisationRole.Member))
|
||||
responseData.MemberRoles.Add(organisationRole.Code, Localiser.GetOrganisationRoleCaption((Sax.OrganisationRole)organisationRole.Type));
|
||||
|
||||
// Reference data - statuses.
|
||||
foreach (SaStatus status in SaxUserOrganisation.ValidStatuses.FindAll(item => item != SaStatus.Deleted))
|
||||
responseData.Statuses.Add(SacsSystem.GetStatusCode(status), Localiser.GetStatusCaption(status));
|
||||
responseData.DefaultStatusCode = SacsSystem.GetStatusCode(SaxUserOrganisation.DefaultStatus);
|
||||
|
||||
// Get organisation members.
|
||||
GetOrganisationMembers(model, organisationId, responseData.Members, false);
|
||||
|
||||
if (model.Paging.IsPaged)
|
||||
model.Paging.ItemCount = (ushort)responseData.Members.Count;
|
||||
|
||||
// Complete response.
|
||||
responseData.SetPaging(model);
|
||||
responseData.Success = true;
|
||||
return Json(responseData);
|
||||
}
|
||||
private void GetOrganisationMembers(SaxModel_Admin model, SysId organisationId, List<MemberListData> members, bool inactiveOnly)
|
||||
{
|
||||
// Item filter.
|
||||
SaxUserOrganisation.Params prmUserOrganisation = new SaxUserOrganisation.Params();
|
||||
prmUserOrganisation.OrganisationIdsIncluded.Add(organisationId);
|
||||
prmUserOrganisation.OrganisationMembersOnly = true;
|
||||
prmUserOrganisation.UserAccountStatusCat = inactiveOnly ? SaxUserAccount.StatusCat.InactiveOnly : SaxUserAccount.StatusCat.NotDeleted;
|
||||
prmUserOrganisation.StatusCat = SaxUserOrganisation.StatusCat.NotDeleted;
|
||||
model.Paging.ItemTotal = (ulong)AccountMgr.GetUserOrganisationCount(prmUserOrganisation);
|
||||
model.PopulatePagingTo(prmUserOrganisation.ResultsPaging);
|
||||
|
||||
// Item columns.
|
||||
ColumnDfn colId = AccountMgr.GetUserOrganisationColumnDfn(SaxUserOrganisation.Column.Id);
|
||||
ColumnDfn colUserAccountId = AccountMgr.GetUserOrganisationColumnDfn(SaxUserOrganisation.Column.UserAccountId);
|
||||
ColumnDfn colUserEmailAddress = AccountMgr.GetUserOrganisationColumnDfn(SaxUserOrganisation.Column.User_EmailAddress);
|
||||
ColumnDfn colUserDisplayName = AccountMgr.GetUserOrganisationColumnDfn(SaxUserOrganisation.Column.User_DisplayName);
|
||||
ColumnDfn colUserStatus = AccountMgr.GetUserOrganisationColumnDfn(SaxUserOrganisation.Column.User_Status);
|
||||
ColumnDfn colOrganisationId = AccountMgr.GetUserOrganisationColumnDfn(SaxUserOrganisation.Column.OrganisationId);
|
||||
ColumnDfn colOrganisationName = AccountMgr.GetUserOrganisationColumnDfn(SaxUserOrganisation.Column.Organisation_Name);
|
||||
ColumnDfn colRoleCodes = AccountMgr.GetUserOrganisationColumnDfn(SaxUserOrganisation.Column.OrganisationRoleCodes);
|
||||
ColumnDfn colRoleCount = AccountMgr.GetUserOrganisationColumnDfn(SaxUserOrganisation.Column.OrganisationRoleCount);
|
||||
ColumnDfn colStatus = AccountMgr.GetUserOrganisationColumnDfn(SaxUserOrganisation.Column.Status);
|
||||
List<ColumnDfn> columns = new List<ColumnDfn>()
|
||||
{
|
||||
colId, colUserAccountId,
|
||||
colUserEmailAddress, colUserDisplayName, colUserStatus,
|
||||
colOrganisationId, colOrganisationName,
|
||||
colRoleCodes, colRoleCount,
|
||||
colStatus
|
||||
};
|
||||
|
||||
// Query items.
|
||||
using (DbResultSet resultSet = AccountMgr.ExecuteUserOrganisationQuery(columns, prmUserOrganisation))
|
||||
{
|
||||
while (resultSet != null && resultSet.HasRows && resultSet.NextRecord())
|
||||
{
|
||||
NamedValue.Map values = resultSet.GetRecordValues();
|
||||
MemberListData memberData = new MemberListData()
|
||||
{
|
||||
Id = values.GetString(colId.DataName),
|
||||
// User.
|
||||
UserAccountId = values.GetString(colUserAccountId.DataName),
|
||||
EmailAddress = values.GetString(colUserEmailAddress.DataName),
|
||||
DisplayName = AccountMgr.GetUserOrganisationDataValue(colUserDisplayName, values).ToString(),
|
||||
UserStatusCode = values.GetString(colUserStatus.DataName),
|
||||
UserStatusDesc = SacsSystem.GetStatusDescForCode(values.GetString(colUserStatus.DataName)),
|
||||
// Organisation.
|
||||
OrganisationId = values.GetString(colOrganisationId.DataName),
|
||||
OrganisationName = values.GetString(colOrganisationName.DataName),
|
||||
// Role count - 1 to ignore 'Member' role.
|
||||
RoleCount = (int)values.GetLong(colRoleCount.DataName) - 1,
|
||||
StatusCode = values.GetString(colStatus.DataName),
|
||||
StatusDesc = SacsSystem.GetStatusDescForCode(values.GetString(colStatus.DataName)),
|
||||
Member = (values.GetLong(colRoleCount.DataName) > 0) ? true : (bool?)null
|
||||
};
|
||||
members.Add(memberData);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Get Organisation Member ajax request.
|
||||
//-------------------------------------------------------------------
|
||||
private class AjaxResponse_Member : AjaxResponse_Data
|
||||
{
|
||||
// Construction.
|
||||
public AjaxResponse_Member(SaxModel_Admin model) : base(model) { }
|
||||
// Member details.
|
||||
public MemberItemData Member { get; } = new MemberItemData();
|
||||
}
|
||||
//-------------------------------------------------------------------
|
||||
[HttpPost]
|
||||
[Route("Organisation/Ajax/GetMember")]
|
||||
public IActionResult Ajax_GetMember(Model_OrganisationMembers model)
|
||||
{
|
||||
String messageTitle = Localiser["caption.organisation.member"];
|
||||
AjaxResponse_Member responseData = new AjaxResponse_Member(model);
|
||||
|
||||
// Validate session.
|
||||
if (!ValidUserSession)
|
||||
return GetAjaxResult_InvalidSession(responseData);
|
||||
|
||||
// Record disposable items as they are created so all can be disposed when needed.
|
||||
using (DisposableCollection<IDisposable> disposableItems = new DisposableCollection<IDisposable>())
|
||||
{
|
||||
|
||||
// Identify item.
|
||||
SysId userOrganisationId = SysId.ToSysId(model.UserOrganisationId);
|
||||
if (!SysId.IsValid(userOrganisationId))
|
||||
return Json(responseData.SetPopupMessage(messageTitle, Localiser["msg.error.item.id.not.specified"]));
|
||||
|
||||
// Retrieve item.
|
||||
SaxUserOrganisation userOrganisation = AccountMgr.GetUserOrganisationById(userOrganisationId);
|
||||
disposableItems.Add(userOrganisation);
|
||||
if (userOrganisation == null)
|
||||
{
|
||||
SaLogger.Warn($"{SysUtil.Fn} Failed to retrieve User Organisation for Id: '{model.UserOrganisationId}'");
|
||||
return Json(responseData.SetPopupMessage(messageTitle, Localiser["msg.error.item.id.not.found"]));
|
||||
}
|
||||
|
||||
// Retrieve User Account.
|
||||
SaxUserAccount userAccount = AccountMgr.GetUserAccountById(userOrganisation.UserAccountId);
|
||||
disposableItems.Add(userAccount);
|
||||
if (userAccount == null)
|
||||
{
|
||||
SaLogger.Warn($"{SysUtil.Fn} Failed to retrieve user account for Id: '{userOrganisation.UserAccountId}'");
|
||||
return Json(responseData.SetPopupMessage(messageTitle, Localiser["msg.error.item.id.not.found"]));
|
||||
}
|
||||
|
||||
// Retrieve Organisation.
|
||||
SaxOrganisation organisation = AccountMgr.GetOrganisationById(userOrganisation.OrganisationId);
|
||||
disposableItems.Add(organisation);
|
||||
if (organisation == null)
|
||||
{
|
||||
SaLogger.Warn($"{SysUtil.Fn} Failed to retrieve organisation for Id: '{userOrganisation.OrganisationId}'");
|
||||
return Json(responseData.SetPopupMessage(messageTitle, Localiser["msg.error.item.id.not.found"]));
|
||||
}
|
||||
|
||||
// Construct response.
|
||||
PopulateMemberResponseItemData(responseData.Member, userOrganisation, userAccount, organisation);
|
||||
}
|
||||
|
||||
responseData.Success = true;
|
||||
return Json(responseData);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Store Organisation Member ajax request.
|
||||
//-------------------------------------------------------------------
|
||||
[HttpPost]
|
||||
[Route("Organisation/Ajax/StoreMember")]
|
||||
public IActionResult Ajax_StoreMember(Model_OrganisationMembers model)
|
||||
{
|
||||
String messageTitle = Localiser["caption.organisation.member"];
|
||||
AjaxResponse_Member responseData = new AjaxResponse_Member(model);
|
||||
|
||||
// Validate session.
|
||||
if (!ValidUserSession)
|
||||
return GetAjaxResult_InvalidSession(responseData);
|
||||
|
||||
// Validate item properties.
|
||||
model.ValidateOrganisationMemberData(responseData);
|
||||
if (responseData.HasControlErrors())
|
||||
return Json(responseData);
|
||||
|
||||
// Record disposable items as they are created so all can be disposed when needed.
|
||||
using (DisposableCollection<IDisposable> disposableItems = new DisposableCollection<IDisposable>())
|
||||
{
|
||||
|
||||
// User account.
|
||||
SysId userAccountId = SysId.ToSysId(model.MemberUserAccountId);
|
||||
SaxUserAccount userAccount = null;
|
||||
if (!SysId.IsValid(userAccountId) && !StringUtil.IsEmpty(model.MemberUserEmailAddress))
|
||||
{
|
||||
userAccount = AccountMgr.GetUserAccountByEmailAddress(model.MemberUserEmailAddress);
|
||||
disposableItems.Add(userAccount);
|
||||
userAccountId = userAccount?.Id ?? new SysId();
|
||||
}
|
||||
if (!SysId.IsValid(userAccountId))
|
||||
{
|
||||
SaLogger.Warn($"{SysUtil.Fn} User Account must be identified");
|
||||
return Json(responseData.SetPopupMessage(messageTitle, Localiser["msg.error.data.incomplete"]));
|
||||
}
|
||||
|
||||
// Organisation.
|
||||
SysId organisationId = SysId.ToSysId(model.MemberOrganisationId);
|
||||
SaxOrganisation organisation = null;
|
||||
if (!SysId.IsValid(organisationId))
|
||||
{
|
||||
SaLogger.Warn($"{SysUtil.Fn} Organisation Id must be specified");
|
||||
return Json(responseData.SetPopupMessage(messageTitle, Localiser["msg.error.data.incomplete"]));
|
||||
}
|
||||
|
||||
// Retrieve existing item.
|
||||
SysId userOrganisationId = SysId.ToSysId(model.UserOrganisationId);
|
||||
SaxUserOrganisation userOrganisation = AccountMgr.GetUserOrganisationById(userOrganisationId);
|
||||
disposableItems.Add(userOrganisation);
|
||||
if (userOrganisation == null && SysId.IsValid(userOrganisationId))
|
||||
{
|
||||
SaLogger.Warn($"{SysUtil.Fn} Failed to retrieve user organisation for Id: '{userOrganisationId}'");
|
||||
return Json(responseData.SetPopupMessage(messageTitle, Localiser["msg.error.item.id.not.found"]));
|
||||
}
|
||||
if (userOrganisation != null && (!userOrganisation.UserAccountId.Equals(userAccountId) || !userOrganisation.OrganisationId.Equals(organisationId)))
|
||||
{
|
||||
// Either User Account and/or Organisation Ids don't match.
|
||||
SaLogger.Warn($"{SysUtil.Fn} Inconsistent user organisation properties. UserAccountId: {userOrganisation.UserAccountId} vs {userAccountId}. OrganisationId: {userOrganisation.OrganisationId} vs {organisationId}.");
|
||||
return Json(responseData.SetPopupMessage(messageTitle, Localiser["msg.error.item.id.not.found"]));
|
||||
}
|
||||
|
||||
// User Organisation not identified.
|
||||
if (userOrganisation == null)
|
||||
{
|
||||
// See whether user has an 'interest' in the organisation.
|
||||
SaxUserOrganisation.Params prmUserOrganisation = new SaxUserOrganisation.Params();
|
||||
prmUserOrganisation.UserAccountIdsIncluded.Add(userAccountId);
|
||||
prmUserOrganisation.OrganisationIdsIncluded.Add(organisationId);
|
||||
prmUserOrganisation.OrganisationMembersOnly = false;
|
||||
prmUserOrganisation.StatusCat = SaxUserOrganisation.StatusCat.Any;
|
||||
userOrganisation = AccountMgr.GetUserOrganisation(prmUserOrganisation);
|
||||
if (userOrganisation != null)
|
||||
userOrganisation.Status = SaStatus.Active;
|
||||
else
|
||||
// Organisation not found for user.
|
||||
userOrganisation = AccountMgr.CreateUserOrganisation(userAccountId, organisationId);
|
||||
disposableItems.Add(userOrganisation);
|
||||
}
|
||||
|
||||
// Retrieve associated items.
|
||||
if (userAccount == null)
|
||||
{
|
||||
userAccount = AccountMgr.GetUserAccountById(userAccountId);
|
||||
disposableItems.Add(userAccount);
|
||||
}
|
||||
if (organisation == null)
|
||||
{
|
||||
organisation = AccountMgr.GetOrganisationById(organisationId);
|
||||
disposableItems.Add(organisation);
|
||||
}
|
||||
|
||||
// Populate item properties.
|
||||
if (model.MemberRoleCodes != null)
|
||||
userOrganisation.OrganisationRoles = SaxUserOrganisation.GetOrganisationRolesFromCodes(model.GetMemberRoleCodes());
|
||||
userOrganisation.AddOrganisationRole(Sax.OrganisationRole.Member);
|
||||
if (model.MemberStatusCode != null)
|
||||
userOrganisation.Status = model.MemberStatus;
|
||||
|
||||
// Store item.
|
||||
if (!SysId.IsValid(userOrganisation.Id))
|
||||
{
|
||||
if (!AccountMgr.InsertUserOrganisation(userOrganisation, DbUpdateInfo))
|
||||
{
|
||||
SaLogger.Warn($"{SysUtil.Fn} Failed to insert user organisation: {AccountMgr.ErrorStateMessage}");
|
||||
return Json(responseData.SetPopupMessage(messageTitle, Localiser["msg.error.item.insert.failed"] + "\n\n" + AccountMgr.ErrorStateMessage));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!AccountMgr.UpdateUserOrganisation(userOrganisation, DbUpdateInfo))
|
||||
{
|
||||
SaLogger.Warn($"{SysUtil.Fn} Failed to update user organisation [Id:{SysId.ToString(userOrganisation.Id)}]: {AccountMgr.ErrorStateMessage}");
|
||||
return Json(responseData.SetPopupMessage(messageTitle, Localiser["msg.error.item.update.failed"] + "\n\n" + AccountMgr.ErrorStateMessage));
|
||||
}
|
||||
}
|
||||
|
||||
// Construct response.
|
||||
PopulateMemberResponseItemData(responseData.Member, userOrganisation, userAccount, organisation);
|
||||
}
|
||||
|
||||
responseData.Success = true;
|
||||
return Json(responseData);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Remove Organisation Member ajax request.
|
||||
//-------------------------------------------------------------------
|
||||
[HttpPost]
|
||||
[Route("Organisation/Ajax/RemoveMember")]
|
||||
public IActionResult Ajax_RemoveMember(Model_OrganisationMembers model)
|
||||
{
|
||||
String messageTitle = Localiser["caption.organisation.member"];
|
||||
AjaxResponse_Member responseData = new AjaxResponse_Member(model);
|
||||
|
||||
// Validate session.
|
||||
if (!ValidUserSession)
|
||||
return GetAjaxResult_InvalidSession(responseData);
|
||||
|
||||
// Record disposable items as they are created so all can be disposed when needed.
|
||||
using (DisposableCollection<IDisposable> disposableItems = new DisposableCollection<IDisposable>())
|
||||
{
|
||||
|
||||
// Organisation.
|
||||
SysId organisationId = SysId.ToSysId(model.OrganisationId);
|
||||
SaxOrganisation organisation = AccountMgr.GetOrganisationById(organisationId);
|
||||
if (organisation == null)
|
||||
{
|
||||
SaLogger.Warn($"{SysUtil.Fn} Failed to retrieve Organisation for Id: '{model.OrganisationId}'");
|
||||
return Json(responseData.SetPopupMessage(messageTitle, Localiser["msg.error.data.incomplete"]));
|
||||
}
|
||||
disposableItems.Add(organisation);
|
||||
|
||||
// User Organisation.
|
||||
SysId userOrganisationId = SysId.ToSysId(model.UserOrganisationId);
|
||||
SaxUserOrganisation userOrganisation = AccountMgr.GetUserOrganisationById(userOrganisationId);
|
||||
disposableItems.Add(userOrganisation);
|
||||
if (userOrganisation == null)
|
||||
{
|
||||
SaLogger.Warn($"{SysUtil.Fn} Failed to retrieve user organisation for Id: '{userOrganisationId}'");
|
||||
return Json(responseData.SetPopupMessage(messageTitle, Localiser["msg.error.item.id.not.found"]));
|
||||
}
|
||||
if (!userOrganisation.OrganisationId.Equals(organisation.Id))
|
||||
{
|
||||
SaLogger.Warn($"{SysUtil.Fn} Inconsistent user organisation properties. OrganisationId: {userOrganisation.OrganisationId} vs {organisation.Id}.");
|
||||
return Json(responseData.SetPopupMessage(messageTitle, Localiser["msg.error.data.inconsistent"]));
|
||||
}
|
||||
|
||||
// User Account.
|
||||
SaxUserAccount userAccount = AccountMgr.GetUserAccountById(userOrganisation.UserAccountId);
|
||||
disposableItems.Add(userAccount);
|
||||
if (userAccount == null)
|
||||
{
|
||||
SaLogger.Warn($"{SysUtil.Fn} Failed to retrieve user account for Id: '{userOrganisation.UserAccountId}'");
|
||||
return Json(responseData.SetPopupMessage(messageTitle, Localiser["msg.error.system"]));
|
||||
}
|
||||
|
||||
// Remove all roles and store.
|
||||
userOrganisation.ClearOrganisationRoles();
|
||||
|
||||
// Store item.
|
||||
if (!SysId.IsValid(userOrganisation.Id))
|
||||
{
|
||||
if (!AccountMgr.InsertUserOrganisation(userOrganisation, DbUpdateInfo))
|
||||
{
|
||||
SaLogger.Warn($"{SysUtil.Fn} Failed to insert user organisation: {AccountMgr.ErrorStateMessage}");
|
||||
return Json(responseData.SetPopupMessage(messageTitle, Localiser["msg.error.item.insert.failed"] + "\n\n" + AccountMgr.ErrorStateMessage));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!AccountMgr.UpdateUserOrganisation(userOrganisation, DbUpdateInfo))
|
||||
{
|
||||
SaLogger.Warn($"{SysUtil.Fn} Failed to update user organisation [Id:{SysId.ToString(userOrganisation.Id)}]: {AccountMgr.ErrorStateMessage}");
|
||||
return Json(responseData.SetPopupMessage(messageTitle, Localiser["msg.error.item.update.failed"] + "\n\n" + AccountMgr.ErrorStateMessage));
|
||||
}
|
||||
}
|
||||
|
||||
// Construct response.
|
||||
PopulateMemberResponseItemData(responseData.Member, userOrganisation, userAccount, organisation);
|
||||
}
|
||||
|
||||
responseData.Success = true;
|
||||
return Json(responseData);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
}
|
||||
//=======================================================================
|
||||
}
|
||||
+147
@@ -0,0 +1,147 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Sarand.Net.Standard.Base.App;
|
||||
using Sarand.Net.Standard.Base.Bus;
|
||||
using Sarand.Net.Standard.Base.Core;
|
||||
using Sarand.Net.Standard.Base.Email;
|
||||
using Sarand.Net.Standard.Base.Utils;
|
||||
using Saxonite.Net.Core.Web.Admin.Consoles;
|
||||
using Saxonite.Net.Core.Web.Admin.Models;
|
||||
using Saxonite.Net.Core.Web.Admin.Procs;
|
||||
using Saxonite.Net.Standard.Base.App;
|
||||
using Saxonite.Net.Standard.Base.Bus;
|
||||
using Saxonite.Net.Standard.Base.Helpers;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Saxonite.Net.Core.Web.Admin.Controllers
|
||||
{
|
||||
//=======================================================================
|
||||
// Controller: Organisation - Ajax - Upload
|
||||
//=======================================================================
|
||||
partial class OrganisationController
|
||||
{
|
||||
//-------------------------------------------------------------------
|
||||
// Definitions.
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Organisation Uploader process info.
|
||||
//-------------------------------------------------------------------
|
||||
private class AjaxResponse_OrganisationUploadInfo : AjaxResponse_Data
|
||||
{
|
||||
// Construction.
|
||||
public AjaxResponse_OrganisationUploadInfo(SaxModel_Admin model) : base(model) { }
|
||||
}
|
||||
//-------------------------------------------------------------------
|
||||
[HttpPost]
|
||||
[Route("Organisation/Ajax/UploadInfo")]
|
||||
public IActionResult Ajax_OrganisationUploadInfo(SaxModel_Admin model)
|
||||
{
|
||||
String fn = GetType().Name + ".Ajax_OrganisationUploadInfo";
|
||||
String messageTitle = Localiser["caption.upload.organisations"];
|
||||
AjaxResponse_OrganisationUploadInfo responseData = new AjaxResponse_OrganisationUploadInfo(model);
|
||||
|
||||
// Validate session.
|
||||
if (!ValidUserSession)
|
||||
return GetAjaxResult_InvalidSession(responseData);
|
||||
|
||||
// Record disposable items as they are created so all can be disposed when needed.
|
||||
using (DisposableCollection<IDisposable> disposableItems = new DisposableCollection<IDisposable>())
|
||||
{
|
||||
|
||||
// Process console.
|
||||
SaxProcessConsole_Admin processConsole = GetProcessConsole_Admin(SessionContext);
|
||||
if (processConsole == null)
|
||||
return Json(responseData.SetPopupMessage(messageTitle, Localiser["msg.error.system"]));
|
||||
|
||||
try
|
||||
{
|
||||
|
||||
// Check whether upload is in progress.
|
||||
if (processConsole.IsProcessing(SaxProcessConsole_Admin.ProcessType.OrganisationUpload))
|
||||
return Json(responseData.SetPopupMessage(messageTitle, Localiser["msg.process.in.progress"]));
|
||||
|
||||
}
|
||||
catch (Exception exc)
|
||||
{
|
||||
SaLogger.Warn(fn + " " + exc.GetType().Name + " initialising organisation uploader.");
|
||||
return Json(responseData.SetPopupMessage(messageTitle, exc.GetType().Name + " initialising organisation uploader."));
|
||||
}
|
||||
}
|
||||
|
||||
// Complete response.
|
||||
responseData.Success = true;
|
||||
|
||||
return Json(responseData);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Upload Organisations.
|
||||
//-------------------------------------------------------------------
|
||||
private class AjaxResponse_OrganisationUpload : AjaxResponse_Data
|
||||
{
|
||||
// Construction.
|
||||
public AjaxResponse_OrganisationUpload(SaxModel_Admin model) : base(model) { }
|
||||
}
|
||||
//-------------------------------------------------------------------
|
||||
[HttpPost]
|
||||
[Route("Organisation/Ajax/Upload")]
|
||||
public IActionResult Ajax_UploadOrganisations(Model_OrganisationUpload model)
|
||||
{
|
||||
String fn = GetType().Name + ".Ajax_UploadOrganisations";
|
||||
String messageTitle = Localiser["caption.upload.organisations"];
|
||||
AjaxResponse_OrganisationUpload responseData = new AjaxResponse_OrganisationUpload(model);
|
||||
|
||||
// Validate session.
|
||||
if (!ValidUserSession)
|
||||
return GetAjaxResult_InvalidSession(responseData);
|
||||
|
||||
// Record disposable items as they are created so all can be disposed when needed.
|
||||
using (DisposableCollection<IDisposable> disposableItems = new DisposableCollection<IDisposable>())
|
||||
{
|
||||
|
||||
// Validate supplied data properties.
|
||||
if (!model.ValidateProperties(responseData))
|
||||
return Json(responseData);
|
||||
|
||||
// Process console.
|
||||
SaxProcessConsole_Admin processConsole = GetProcessConsole_Admin(SessionContext);
|
||||
if (processConsole == null)
|
||||
return Json(responseData.SetPopupMessage(messageTitle, Localiser["msg.error.system"]));
|
||||
|
||||
try
|
||||
{
|
||||
|
||||
// Check whether upload is in progress.
|
||||
if (processConsole.IsProcessing(SaxProcessConsole_Admin.ProcessType.OrganisationUpload))
|
||||
return Json(responseData.SetPopupMessage(messageTitle, Localiser["msg.process.in.progress"]));
|
||||
|
||||
// Create the upload process.
|
||||
SaxOrganisationUploader.Config processConfig = new SaxOrganisationUploader.Config(SessionContext, DbUpdateInfo, model.OrganisationDataFile[0]);
|
||||
processConfig.SheetNameOrNumber = model.SheetNameOrNumber;
|
||||
processConfig.HeaderRowPos = (uint)StringUtil.ToInt(model.HeaderRow);
|
||||
processConfig.FirstDataRowPos = (uint)StringUtil.ToInt(model.FirstDataRow);
|
||||
SaxOrganisationUploader process = new SaxOrganisationUploader(processConfig);
|
||||
|
||||
// Store the process and run.
|
||||
processConsole.SetProcess(process);
|
||||
process.RunAsync();
|
||||
|
||||
}
|
||||
catch (Exception exc)
|
||||
{
|
||||
SaLogger.Warn(fn + " " + exc.GetType().Name + " initialising organisation uploader.");
|
||||
return Json(responseData.SetPopupMessage(messageTitle, exc.GetType().Name + " initialising organisation uploader."));
|
||||
}
|
||||
}
|
||||
|
||||
// Complete response.
|
||||
responseData.Success = true;
|
||||
|
||||
return Json(responseData);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,491 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Sarand.Net.Standard.Base.App;
|
||||
using Sarand.Net.Standard.Base.Bus;
|
||||
using Sarand.Net.Standard.Base.Core;
|
||||
using Sarand.Net.Standard.Base.Dbas;
|
||||
using Sarand.Net.Standard.Base.Utils;
|
||||
using Saxonite.Net.Core.Web.Admin.Models;
|
||||
using Saxonite.Net.Core.Web.Admin.Procs;
|
||||
using Saxonite.Net.Standard.Base.App;
|
||||
using Saxonite.Net.Standard.Base.Bus;
|
||||
using Saxonite.Net.Standard.Base.Mgr;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Specialized;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Saxonite.Net.Core.Web.Admin.Controllers
|
||||
{
|
||||
//=======================================================================
|
||||
// Controller: Organisation - Ajax
|
||||
//=======================================================================
|
||||
partial class OrganisationController
|
||||
{
|
||||
//-------------------------------------------------------------------
|
||||
// Organisation data.
|
||||
private class OrganisationListData : AjaxResponse_Data.ItemData_Base
|
||||
{
|
||||
public String Name { get; set; }
|
||||
public String TypeCode { get; set; }
|
||||
public String TypeDesc { get; set; }
|
||||
public String CategoryCode { get; set; }
|
||||
public String CategoryDesc { get; set; }
|
||||
public long MemberCount { get; set; }
|
||||
// Sport.
|
||||
public String SportId { get; set; }
|
||||
public String SportName { get; set; }
|
||||
// Primary Region.
|
||||
public class RegionData
|
||||
{
|
||||
public String Id { get; set; }
|
||||
public String Name { get; set; }
|
||||
public bool? Country { get; set; } = null;
|
||||
}
|
||||
public RegionData RegionPrimary { get; } = new RegionData();
|
||||
// Address.
|
||||
public String AddressSummary { get; set; }
|
||||
// Logo.
|
||||
public String LogoImageUrl { get; set; }
|
||||
}
|
||||
private class OrganisationItemData : OrganisationListData
|
||||
{
|
||||
public String About { get; set; }
|
||||
public String Facilities { get; set; }
|
||||
public List<AjaxResponse_Data.ContactMethodData> ContactMethods { get; set; }
|
||||
public AjaxResponse_Data.AddressData Address { get; set; }
|
||||
}
|
||||
private void PopulateOrganisationResponseListData(SaxOrganisation organisation, OrganisationListData data)
|
||||
{
|
||||
data.Id = SysId.ToString(organisation.Id);
|
||||
data.Name = organisation.Name;
|
||||
data.TypeCode = OrganisationTypeCodes.GetCodeForType(organisation.OrganisationType);
|
||||
data.TypeDesc = OrganisationTypeCodes.GetDescForType(organisation.OrganisationType);
|
||||
data.CategoryCode = OrganisationCategoryCodes.GetCodeForType(organisation.OrganisationCategory);
|
||||
data.CategoryDesc = OrganisationCategoryCodes.GetDescForType(organisation.OrganisationCategory);
|
||||
data.MemberCount = AccountMgr.GetOrganisationMemberCount(organisation.Id);
|
||||
// Sport.
|
||||
data.SportId = SysId.ToString(organisation.SportIdPrimary, null);
|
||||
using (SaxSport sport = ReferenceMgr.GetSportById(organisation.SportIdPrimary))
|
||||
data.SportName = sport?.Name ?? null;
|
||||
// Primary region.
|
||||
data.RegionPrimary.Id = SysId.ToString(organisation.RegionIdPrimary, null);
|
||||
SaxRegion.Data region = Internals.GetRegion(organisation.RegionIdPrimary);
|
||||
if (region != null)
|
||||
{
|
||||
data.RegionPrimary.Name = region.Name;
|
||||
data.RegionPrimary.Country = region.RegionType == Sax.RegionType.Country ? true : (bool?)null;
|
||||
}
|
||||
// Common properties.
|
||||
data.StatusCode = organisation.StatusCode;
|
||||
data.StatusDesc = organisation.StatusDesc;
|
||||
|
||||
// Organisation Logo image url.
|
||||
if (ItemDataMgr.ItemHasActiveImage(organisation.GetItemId(), Sax.ImageType.OrganisationLogo))
|
||||
data.LogoImageUrl = GetOrganisationLogoLink(organisation.Id, false);
|
||||
}
|
||||
private void PopulateOrganisationResponseItemData(SaxOrganisation organisation, SaxItemAddress address, OrganisationItemData data)
|
||||
{
|
||||
PopulateOrganisationResponseListData(organisation, data);
|
||||
data.About = StringUtil.OnEmpty(organisation.About, null);
|
||||
data.Facilities = StringUtil.OnEmpty(organisation.Facilities, null);
|
||||
// Contact methods.
|
||||
SaxContactData contactData = new SaxContactData(organisation.ContactData);
|
||||
foreach (Sax.ContactMethod method in contactData.Methods)
|
||||
{
|
||||
if (data.ContactMethods == null) data.ContactMethods = new List<AjaxResponse_Data.ContactMethodData>();
|
||||
data.ContactMethods.Add(new AjaxResponse_Data.ContactMethodData() { Method = method.ToString(), MethodCaption = Localiser.GetContactMethodCaption(method), Value = contactData.GetContactMethodValue(method) });
|
||||
}
|
||||
// Address.
|
||||
if (address != null && !address.IsStatusDeleted)
|
||||
{
|
||||
data.Address = new AjaxResponse_Data.AddressData();
|
||||
data.Address.Id = address.Id.ToString(null);
|
||||
data.Address.Line1 = StringUtil.OnEmpty(address.Line1, null);
|
||||
data.Address.Line2 = StringUtil.OnEmpty(address.Line2, null);
|
||||
data.Address.Line3 = StringUtil.OnEmpty(address.Line3, null);
|
||||
data.Address.Town = address.Town;
|
||||
data.Address.RegionIdProvince = SysId.ToString(address.RegionIdProvince, null);
|
||||
data.Address.RegionNameProvince = StringUtil.OnEmpty(address.Province, null);
|
||||
data.Address.RegionIdCountry = SysId.ToString(address.RegionIdCountry, null);
|
||||
data.Address.RegionNameCountry = StringUtil.OnEmpty(address.Country, null);
|
||||
data.Address.PostalCode = StringUtil.OnEmpty(address.PostalCode, null);
|
||||
}
|
||||
// Common properties.
|
||||
data.Notes = organisation.Notes;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Get Organisation List ajax request.
|
||||
//-------------------------------------------------------------------
|
||||
private class AjaxResponse_OrganisationList : AjaxResponse_Data
|
||||
{
|
||||
// Construction.
|
||||
public AjaxResponse_OrganisationList(SaxModel_Admin model) : base(model) { }
|
||||
// Organisation list.
|
||||
public List<OrganisationListData> Organisations { get; } = new List<OrganisationListData>();
|
||||
// Reference data.
|
||||
public List<AjaxResponse_Data.ItemCodeDesc> ContactMethods { get; } = new List<ItemCodeDesc>();
|
||||
public List<CodeDesc> Statuses { get; } = new List<CodeDesc>();
|
||||
public String DefaultStatusCode { get; set; }
|
||||
public List<String> UploadContentTypes { get; set; }
|
||||
}
|
||||
//-------------------------------------------------------------------
|
||||
[HttpPost]
|
||||
[Route("Organisation/Ajax/GetList")]
|
||||
public IActionResult Ajax_GetList(Model_Organisation model)
|
||||
{
|
||||
String fn = GetType().Name + ".Ajax_GetList";
|
||||
String messageTitle = Localiser["caption.organisations"];
|
||||
AjaxResponse_OrganisationList responseData = new AjaxResponse_OrganisationList(model);
|
||||
|
||||
// Validate session.
|
||||
if (!ValidUserSession)
|
||||
return GetAjaxResult_InvalidSession(responseData);
|
||||
|
||||
// Reference data - contact methods.
|
||||
List<Sax.ContactMethod> validContactMethods = SaxOrganisation.ValidContactMethods;
|
||||
foreach (TypeCodeDesc contactMethod in ContactMethodCodes.OrderBy(item => item.Desc))
|
||||
{
|
||||
// Skip methods that aren't associated with Organisations.
|
||||
if (!validContactMethods.Contains((Sax.ContactMethod)contactMethod.Type)) continue;
|
||||
responseData.ContactMethods.Add(new AjaxResponse_Data.ItemCodeDesc() { Code = contactMethod.Code, Desc = Localiser.GetContactMethodCaption((Sax.ContactMethod)contactMethod.Type) });
|
||||
}
|
||||
|
||||
// Reference data - statuses.
|
||||
foreach (SaStatus status in SaxOrganisation.ValidStatuses.FindAll(item => item != SaStatus.Deleted))
|
||||
responseData.Statuses.Add(SacsSystem.GetStatusCode(status), Localiser.GetStatusCaption(status));
|
||||
responseData.DefaultStatusCode = SacsSystem.GetStatusCode(SaxOrganisation.DefaultStatus);
|
||||
|
||||
// Reference data - Image content types.
|
||||
responseData.UploadContentTypes = SaxOrganisationUploader.ValidContentTypes;
|
||||
|
||||
// Store filter values.
|
||||
SysId filterSportId = SysId.ToSysId(model.Filter.OrganisationSportId);
|
||||
SessionData_Admin.Filter.SportId = SysId.IsValid(filterSportId) ? filterSportId : null;
|
||||
SysId filterRegionId = SysId.ToSysId(model.Filter.OrganisationRegionId);
|
||||
SessionData_Admin.Filter.RegionId = SysId.IsValid(filterRegionId) ? filterRegionId : null;
|
||||
|
||||
// Item filter.
|
||||
SaxOrganisation.Params prmOrganisation = GetOrganisationListFilter(model, AccountMgr);
|
||||
model.Paging.ItemTotal = (ulong)AccountMgr.GetOrganisationCount(prmOrganisation);
|
||||
model.PopulatePagingTo(prmOrganisation.ResultsPaging);
|
||||
|
||||
// Item columns.
|
||||
ColumnDfn colId = AccountMgr.GetOrganisationColumnDfn(SaxOrganisation.Column.Id);
|
||||
ColumnDfn colName = AccountMgr.GetOrganisationColumnDfn(SaxOrganisation.Column.Name);
|
||||
ColumnDfn colOrganisationType = AccountMgr.GetOrganisationColumnDfn(SaxOrganisation.Column.OrganisationType);
|
||||
ColumnDfn colOrganisationCategory = AccountMgr.GetOrganisationColumnDfn(SaxOrganisation.Column.OrganisationCategory);
|
||||
ColumnDfn colUserCount = AccountMgr.GetOrganisationColumnDfn(SaxOrganisation.Column.User_Count);
|
||||
ColumnDfn colMemberCount = AccountMgr.GetOrganisationColumnDfn(SaxOrganisation.Column.Member_Count);
|
||||
ColumnDfn colLogoCount = AccountMgr.GetOrganisationColumnDfn(SaxOrganisation.Column.LogoImage_Count);
|
||||
ColumnDfn colSportId = AccountMgr.GetOrganisationColumnDfn(SaxOrganisation.Column.SportId);
|
||||
ColumnDfn colSportName = AccountMgr.GetOrganisationColumnDfn(SaxOrganisation.Column.Sport_Name);
|
||||
ColumnDfn colRegionId = AccountMgr.GetOrganisationColumnDfn(SaxOrganisation.Column.RegionId);
|
||||
ColumnDfn colRegionName = AccountMgr.GetOrganisationColumnDfn(SaxOrganisation.Column.Region_Name);
|
||||
ColumnDfn colStatus = AccountMgr.GetOrganisationColumnDfn(SaxOrganisation.Column.Status);
|
||||
List<ColumnDfn> columns = new List<ColumnDfn>()
|
||||
{
|
||||
colId,
|
||||
colName,
|
||||
colOrganisationType,
|
||||
colOrganisationCategory,
|
||||
colUserCount, colMemberCount, colLogoCount,
|
||||
colSportId, colSportName,
|
||||
colRegionId, colRegionName,
|
||||
colStatus
|
||||
};
|
||||
|
||||
// Query items.
|
||||
using (DbResultSet resultSet = AccountMgr.ExecuteOrganisationQuery(columns, prmOrganisation))
|
||||
{
|
||||
while (resultSet != null && resultSet.HasRows && resultSet.NextRecord())
|
||||
{
|
||||
NamedValue.Map values = resultSet.GetRecordValues();
|
||||
SysId organisationId = new SysId(values.GetLong(colId.DataName));
|
||||
OrganisationListData organisationData = new OrganisationListData()
|
||||
{
|
||||
Id = organisationId.ToString(),
|
||||
Name = values.GetString(colName.DataName),
|
||||
TypeCode = values.GetString(colOrganisationType.DataName),
|
||||
TypeDesc = OrganisationTypeCodes.GetDescForCode(values.GetString(colOrganisationType.DataName)),
|
||||
CategoryCode = values.GetString(colOrganisationCategory.DataName),
|
||||
CategoryDesc = OrganisationCategoryCodes.GetDescForCode(values.GetString(colOrganisationCategory.DataName)),
|
||||
MemberCount = StringUtil.ToLong(values.GetString(colMemberCount.DataName)),
|
||||
SportId = SysId.ToString(new SysId(values.GetLong(colSportId.DataName)), null),
|
||||
SportName = StringUtil.OnEmpty(values.GetString(colSportName.DataName), null),
|
||||
StatusCode = values.GetString(colStatus.DataName),
|
||||
StatusDesc = SacsSystem.GetStatusDescForCode(values.GetString(colStatus.DataName))
|
||||
};
|
||||
// Logo image.
|
||||
if (StringUtil.ToLong(values.GetString(colLogoCount.DataName)) > 0)
|
||||
organisationData.LogoImageUrl = GetOrganisationLogoLink(organisationId, false);
|
||||
// Primary region.
|
||||
organisationData.RegionPrimary.Id = SysId.ToString(new SysId(values.GetLong(colRegionId.DataName)), null);
|
||||
organisationData.RegionPrimary.Name = StringUtil.OnEmpty(values.GetString(colRegionName.DataName), null);
|
||||
// Add item to list.
|
||||
responseData.Organisations.Add(organisationData);
|
||||
}
|
||||
}
|
||||
if (model.Paging.IsPaged)
|
||||
model.Paging.ItemCount = (ushort)responseData.Organisations.Count;
|
||||
|
||||
// Complete response.
|
||||
responseData.SetPaging(model);
|
||||
responseData.Success = true;
|
||||
return Json(responseData);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
/// <summary>
|
||||
/// Construct Organisation filter params.
|
||||
/// <para>- Shared with Organisation Exporter process.</para>
|
||||
/// </summary>
|
||||
/// <param name="model"></param>
|
||||
/// <returns></returns>
|
||||
public static SaxOrganisation.Params GetOrganisationListFilter(Model_Organisation model, SaxAccountMgr accountMgr)
|
||||
{
|
||||
// Item filter.
|
||||
SaxOrganisation.Params prmOrganisation = new SaxOrganisation.Params();
|
||||
prmOrganisation.OrganisationFilter = model.Filter.Organisation;
|
||||
prmOrganisation.OrganisationType = model.FilterOrganisationType;
|
||||
prmOrganisation.OrganisationCategory = model.FilterOrganisationCategory;
|
||||
prmOrganisation.SportIdsIncluded.AddId(SysId.ToSysId(model.Filter.OrganisationSportId));
|
||||
prmOrganisation.RegionIdsIncluded.AddId(SysId.ToSysId(model.Filter.OrganisationRegionId));
|
||||
prmOrganisation.StatusCat = model.Filter.OrganisationStatusCategoryCode != null ? model.FilterOrganisationStatusCategory : SaxOrganisation.StatusCat.NotDeleted;
|
||||
prmOrganisation.SortColumns.Add(accountMgr.GetOrganisationColumnDfn(SaxOrganisation.Column.Name));
|
||||
return prmOrganisation;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Get Organisation ajax request.
|
||||
//-------------------------------------------------------------------
|
||||
private class AjaxResponse_Organisation : AjaxResponse_Data
|
||||
{
|
||||
// Construction.
|
||||
public AjaxResponse_Organisation(SaxModel_Admin model) : base(model) { }
|
||||
// Organisation details.
|
||||
public OrganisationItemData organisation { get; } = new OrganisationItemData();
|
||||
}
|
||||
//-------------------------------------------------------------------
|
||||
[HttpPost]
|
||||
[Route("Organisation/Ajax/GetItem")]
|
||||
public IActionResult Ajax_GetItem(Model_Organisation model)
|
||||
{
|
||||
String fn = GetType().Name + ".Ajax_GetItem";
|
||||
String messageTitle = Localiser["caption.organisation"];
|
||||
AjaxResponse_Organisation responseData = new AjaxResponse_Organisation(model);
|
||||
|
||||
// Validate session.
|
||||
if (!ValidUserSession)
|
||||
return GetAjaxResult_InvalidSession(responseData);
|
||||
|
||||
// Record disposable items as they are created so all can be disposed when needed.
|
||||
using (DisposableCollection<IDisposable> disposableItems = new DisposableCollection<IDisposable>())
|
||||
{
|
||||
|
||||
// Identify item.
|
||||
SysId organisationId = SysId.ToSysId(model.OrganisationId);
|
||||
if (!SysId.IsValid(organisationId))
|
||||
return Json(responseData.SetPopupMessage(messageTitle, Localiser["msg.error.item.id.not.specified"]));
|
||||
|
||||
// Retrieve item.
|
||||
SaxOrganisation organisation = AccountMgr.GetOrganisationById(organisationId);
|
||||
disposableItems.Add(organisation);
|
||||
if (organisation == null)
|
||||
{
|
||||
SaLogger.Warn(fn + " Failed to retrieve organisation for Id: '" + model.OrganisationId + "'");
|
||||
return Json(responseData.SetPopupMessage(messageTitle, Localiser["msg.error.item.id.not.found"]));
|
||||
}
|
||||
|
||||
// Organisation address.
|
||||
SaxItemAddress address = ItemDataMgr.GetFirstItemAddressByItemAndType(organisation.GetItemId());
|
||||
disposableItems.Add(address);
|
||||
|
||||
// Construct response.
|
||||
PopulateOrganisationResponseItemData(organisation, address, responseData.organisation);
|
||||
|
||||
// Complete response.
|
||||
responseData.Success = true;
|
||||
}
|
||||
return Json(responseData);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Store Organisation ajax request.
|
||||
//-------------------------------------------------------------------
|
||||
[HttpPost]
|
||||
[Route("Organisation/Ajax/StoreItem")]
|
||||
public IActionResult Ajax_StoreItem(Model_Organisation model)
|
||||
{
|
||||
String fn = GetType().Name + ".Ajax_StoreItem";
|
||||
String messageTitle = Localiser["caption.organisation"];
|
||||
AjaxResponse_Organisation responseData = new AjaxResponse_Organisation(model);
|
||||
|
||||
// Validate session.
|
||||
if (!ValidUserSession)
|
||||
return GetAjaxResult_InvalidSession(responseData);
|
||||
|
||||
// Record disposable items as they are created so all can be disposed when needed.
|
||||
using (DisposableCollection<IDisposable> disposableItems = new DisposableCollection<IDisposable>())
|
||||
{
|
||||
|
||||
// Validate item properties.
|
||||
model.ValidateOrganisationData(responseData);
|
||||
if (responseData.HasControlErrors())
|
||||
return Json(responseData);
|
||||
|
||||
// Retrieve existing item.
|
||||
SysId organisationId = SysId.ToSysId(model.OrganisationId);
|
||||
SaxOrganisation organisation = AccountMgr.GetOrganisationById(organisationId);
|
||||
disposableItems.Add(organisation);
|
||||
if (organisation == null && SysId.IsValid(organisationId))
|
||||
{
|
||||
SaLogger.Warn(fn + " Failed to retrieve organisation for Id: '" + model.OrganisationId + "'");
|
||||
return Json(responseData.SetPopupMessage(messageTitle, Localiser["msg.error.item.id.not.found"]));
|
||||
}
|
||||
|
||||
// Create new item if required.
|
||||
if (organisation == null)
|
||||
{
|
||||
organisation = AccountMgr.CreateOrganisation();
|
||||
disposableItems.Add(organisation);
|
||||
}
|
||||
|
||||
// Organisation address.
|
||||
SaxItemAddress organisationAddress = ItemDataMgr.GetFirstItemAddressByItemAndType(organisation.GetItemId());
|
||||
disposableItems.Add(organisationAddress);
|
||||
|
||||
// Populate item properties.
|
||||
if (model.OrganisationName != null)
|
||||
organisation.Name = model.OrganisationName;
|
||||
if (model.OrganisationTypeValue != null)
|
||||
organisation.OrganisationType = model.OrganisationType;
|
||||
if (model.OrganisationCategoryValue != null)
|
||||
organisation.OrganisationCategory = model.OrganisationCategory;
|
||||
if (model.OrganisationSportId != null)
|
||||
organisation.SportIdPrimary = SysId.ToSysId(model.OrganisationSportId);
|
||||
if (model.OrganisationRegionIdPrimary != null)
|
||||
organisation.RegionIdPrimary = SysId.ToSysId(model.OrganisationRegionIdPrimary);
|
||||
if (model.OrganisationAbout != null)
|
||||
organisation.About = model.OrganisationAbout;
|
||||
if (model.OrganisationFacilities != null)
|
||||
organisation.Facilities = model.OrganisationFacilities;
|
||||
if (model.ContactData != null)
|
||||
organisation.ContactData = model.ContactData.GetContactData();
|
||||
// Common properties.
|
||||
if (model.OrganisationStatusCode != null)
|
||||
organisation.Status = model.OrganisationStatus;
|
||||
if (model.OrganisationNotes != null)
|
||||
organisation.Notes = model.OrganisationNotes;
|
||||
|
||||
// Store item.
|
||||
if (!SysId.IsValid(organisation.Id))
|
||||
{
|
||||
if (!AccountMgr.InsertOrganisation(organisation, DbUpdateInfo))
|
||||
{
|
||||
SaLogger.Warn(fn + " Failed to insert organisation: " + AccountMgr.ErrorStateMessage);
|
||||
return Json(responseData.SetPopupMessage(messageTitle, Localiser["msg.error.item.insert.failed"] + "\n\n" + AccountMgr.ErrorStateMessage));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!AccountMgr.UpdateOrganisation(organisation, DbUpdateInfo))
|
||||
{
|
||||
SaLogger.Warn(fn + " Failed to update organisation [Id:" + SysId.ToString(organisation.Id) + "]: " + AccountMgr.ErrorStateMessage);
|
||||
return Json(responseData.SetPopupMessage(messageTitle, Localiser["msg.error.item.update.failed"] + "\n\n" + AccountMgr.ErrorStateMessage));
|
||||
}
|
||||
}
|
||||
|
||||
if (model.Address.IsSpecified())
|
||||
{
|
||||
// The form includes address fields.
|
||||
if (model.Address.IsPopulated())
|
||||
{
|
||||
// Organisation regions.
|
||||
SaxRegion.Data regionCountry = Internals.GetRegion(SysId.ToSysId(model.Address.RegionIdCountry));
|
||||
if (regionCountry == null)
|
||||
// Default to Organisation's primary region.
|
||||
regionCountry = Internals.GetRegion(organisation.RegionIdPrimary);
|
||||
if (regionCountry != null && regionCountry.RegionType != Sax.RegionType.Country)
|
||||
regionCountry = null;
|
||||
SaxRegion.Data regionProvince = null;
|
||||
|
||||
// Create Organisation address if required.
|
||||
if (organisationAddress == null)
|
||||
{
|
||||
organisationAddress = ItemDataMgr.CreateItemAddress(organisation.GetItemId(), SaxItemAddress.DefaultOrganisationAddressType);
|
||||
disposableItems.Add(organisationAddress);
|
||||
}
|
||||
|
||||
// Store address.
|
||||
if (model.Address.Line1 != null)
|
||||
organisationAddress.Line1 = model.Address.Line1;
|
||||
if (model.Address.Line2 != null)
|
||||
organisationAddress.Line2 = model.Address.Line2;
|
||||
if (model.Address.Line3 != null)
|
||||
organisationAddress.Line3 = model.Address.Line3;
|
||||
if (model.Address.Town != null)
|
||||
organisationAddress.Town = model.Address.Town;
|
||||
if (regionProvince != null)
|
||||
{
|
||||
organisationAddress.Province = regionProvince.Name;
|
||||
organisationAddress.RegionIdProvince = regionProvince.Id;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (model.Address.Province != null)
|
||||
organisationAddress.Province = model.Address.Province;
|
||||
}
|
||||
if (regionCountry != null)
|
||||
{
|
||||
organisationAddress.Country = regionCountry.Name;
|
||||
organisationAddress.RegionIdCountry = regionCountry.Id;
|
||||
}
|
||||
organisationAddress.PostalCode = model.Address.PostalCode;
|
||||
organisationAddress.Status = SaxItemAddress.DefaultStatus;
|
||||
|
||||
// Store address.
|
||||
if (!SysId.IsValid(organisationAddress.Id))
|
||||
{
|
||||
// Create new address.
|
||||
if (!ItemDataMgr.InsertItemAddress(organisationAddress, DbUpdateInfo))
|
||||
{
|
||||
SaLogger.Warn(fn + " Failed to insert organisation address - " + ItemDataMgr.ErrorStateMessage);
|
||||
return Json(responseData.SetGoHome(messageTitle, Localiser["msg.error.system"]));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Update existing address.
|
||||
if (!ItemDataMgr.UpdateItemAddress(organisationAddress, DbUpdateInfo))
|
||||
{
|
||||
SaLogger.Warn(fn + " Failed to update organisation address - " + ItemDataMgr.ErrorStateMessage);
|
||||
return Json(responseData.SetGoHome(messageTitle, Localiser["msg.error.system"]));
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (organisationAddress != null && !organisationAddress.IsStatusDeleted)
|
||||
{
|
||||
// Address not populated - delete it.
|
||||
if (!ItemDataMgr.DeleteItemAddress(organisationAddress, DbUpdateInfo))
|
||||
{
|
||||
SaLogger.Warn(fn + " Failed to delete organisation address - " + ItemDataMgr.ErrorStateMessage);
|
||||
return Json(responseData.SetGoHome(messageTitle, Localiser["msg.error.system"]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Construct response.
|
||||
PopulateOrganisationResponseItemData(organisation, organisationAddress, responseData.organisation);
|
||||
|
||||
// Complete response.
|
||||
responseData.Success = true;
|
||||
}
|
||||
return Json(responseData);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
}
|
||||
//=======================================================================
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Sarand.Net.Standard.Base.App;
|
||||
using Sarand.Net.Standard.Base.Bus;
|
||||
using Sarand.Net.Standard.Base.Core;
|
||||
using Sarand.Net.Standard.Base.Email;
|
||||
using Sarand.Net.Standard.Base.Helpers;
|
||||
using Sarand.Net.Standard.Base.Utils;
|
||||
using Sarand.Net.Standard.Proc.Excel;
|
||||
using Saxonite.Net.Core.Web.Admin.Consoles;
|
||||
using Saxonite.Net.Core.Web.Admin.Models;
|
||||
using Saxonite.Net.Core.Web.Admin.Procs;
|
||||
using Saxonite.Net.Core.Web.Base.Controllers;
|
||||
using Saxonite.Net.Standard.Base.App;
|
||||
using Saxonite.Net.Standard.Base.Bus;
|
||||
using Saxonite.Net.Standard.Base.Helpers;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Saxonite.Net.Core.Web.Admin.Controllers
|
||||
{
|
||||
//=======================================================================
|
||||
// Controller: Organisation - Download
|
||||
//=======================================================================
|
||||
partial class OrganisationController
|
||||
{
|
||||
//-------------------------------------------------------------------
|
||||
// Definitions.
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Download Organisations.
|
||||
//-------------------------------------------------------------------
|
||||
[HttpPost]
|
||||
[Route("Organisation/Download")]
|
||||
public IActionResult Ajax_DownloadOrganisations(Model_OrganisationDownload model)
|
||||
{
|
||||
String fn = GetType().Name + ".Ajax_DownloadOrganisations";
|
||||
|
||||
// Validate session.
|
||||
if (!ValidUserSession)
|
||||
return Unauthorized();
|
||||
|
||||
// Record disposable items as they are created so all can be disposed when needed.
|
||||
using (DisposableCollection<IDisposable> disposableItems = new DisposableCollection<IDisposable>())
|
||||
{
|
||||
|
||||
// Validate supplied data properties.
|
||||
if (!model.ValidateProperties())
|
||||
return BadRequest();
|
||||
|
||||
// Export data.
|
||||
SaxOrganisationExporter.Config exporterConfig = new SaxOrganisationExporter.Config(SessionContext, DbUpdateInfo, GetOrganisationListFilter(model, AccountMgr));
|
||||
exporterConfig.Format = SaxOrganisationExporter.ExportFormat.Excel_Open;
|
||||
exporterConfig.IncludeId = StringUtil.ToBool(model.IncludeId);
|
||||
SaxOrganisationExporter exporter = new SaxOrganisationExporter(exporterConfig);
|
||||
if (exporter.RunProcess())
|
||||
{
|
||||
// Organisations exported successfully.
|
||||
byte[] data = exporter.GetDocumentData();
|
||||
using (MemoryStream content = new MemoryStream(data))
|
||||
{
|
||||
String contentType = exporter.GetContentType();
|
||||
var fileName = "Sportierre-Organisations-" + DateTime.Now.ToString("yyyyMMdd") + ".xlsx";
|
||||
return File(content.ToArray(), contentType, fileName);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Problems occurred.
|
||||
}
|
||||
}
|
||||
return NoContent();
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,119 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Sarand.Net.Standard.Base.Bus;
|
||||
using Sarand.Net.Standard.Base.Utils;
|
||||
using Saxonite.Net.Core.Web.Admin.Models;
|
||||
using Saxonite.Net.Core.Web.Base.App;
|
||||
using Saxonite.Net.Core.Web.Base.Controllers;
|
||||
using Saxonite.Net.Standard.Base.Bus;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Saxonite.Net.Core.Web.Admin.Controllers
|
||||
{
|
||||
//=======================================================================
|
||||
public partial class OrganisationController : SaxController_Admin
|
||||
{
|
||||
//-------------------------------------------------------------------
|
||||
// Construction.
|
||||
public OrganisationController(SaxLocaliser localiser, ILogger<HomeController> logger) :
|
||||
base(localiser, logger)
|
||||
{
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
[HttpGet]
|
||||
public IActionResult Index(String sta)
|
||||
{
|
||||
// Validate session.
|
||||
if (!ValidUserSession)
|
||||
AutoLoginUser();
|
||||
if (!ValidUserSession)
|
||||
return RedirectToAction("", "");
|
||||
|
||||
// Model.
|
||||
Model_Organisation model = new Model_Organisation(Localiser);
|
||||
|
||||
// Stored Sport filter.
|
||||
model.Filter.OrganisationSportId = SessionData_Admin.Filter.SportId?.ToString() ?? null;
|
||||
using (SaxSport filterSport = ReferenceMgr.GetSportById(SessionData_Admin.Filter.SportId))
|
||||
model.Filter.OrganisationSportName = Localiser.GetSportName(SessionData_Admin.Filter.SportId, filterSport?.Name ?? "");
|
||||
// Stored Region filter.
|
||||
model.Filter.OrganisationRegionId = SessionData_Admin.Filter.RegionId?.ToString() ?? null;
|
||||
using (SaxRegion filterRegion = ReferenceMgr.GetRegionById(SessionData_Admin.Filter.RegionId))
|
||||
model.Filter.OrganisationRegionName = Localiser.GetRegionName(SessionData_Admin.Filter.RegionId, filterRegion?.Name ?? "");
|
||||
|
||||
// Paging.
|
||||
model.Paging.PageNo = 1;
|
||||
model.Paging.PageLength = 8;
|
||||
|
||||
// Default status.
|
||||
if (sta.StartsWithCI("Awa"))
|
||||
model.Filter.OrganisationStatusCategoryCode = nameof(SaxOrganisation.StatusCat.AwaitingOnly);
|
||||
|
||||
return View(model);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
/// <summary>
|
||||
/// Organisation Members action.
|
||||
/// <para>- POST action to allow Organisation Id to be supplied, eg. from Organsiations page.</para>
|
||||
/// </summary>
|
||||
[HttpPost]
|
||||
public IActionResult Members(Model_OrganisationMembers model)
|
||||
{
|
||||
// Validate session.
|
||||
if (!ValidUserSession)
|
||||
AutoLoginUser();
|
||||
if (!ValidUserSession)
|
||||
return RedirectToAction("", "");
|
||||
|
||||
// Retrieve organisation.
|
||||
SaxOrganisation organisation = AccountMgr.GetOrganisationById(SysId.ToSysId(model.OrganisationId));
|
||||
if (organisation == null)
|
||||
RedirectToAction("", "Organisation");
|
||||
model.Filter.OrganisationId= SysId.ToString(organisation.Id);
|
||||
model.Filter.OrganisationName = organisation.Name;
|
||||
|
||||
// Paging.
|
||||
model.Paging.PageNo = 1;
|
||||
model.Paging.PageLength = 12;
|
||||
|
||||
return View(model);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
/// <summary>
|
||||
/// Organisation Associations action.
|
||||
/// <para>- POST action to allow Organisation Id to be supplied, eg. from Organsiations page.</para>
|
||||
/// </summary>
|
||||
[HttpPost]
|
||||
public IActionResult Associations(Model_OrganisationAssociations model)
|
||||
{
|
||||
// Validate session.
|
||||
if (!ValidUserSession)
|
||||
AutoLoginUser();
|
||||
if (!ValidUserSession)
|
||||
return RedirectToAction("", "");
|
||||
|
||||
// Retrieve organisation.
|
||||
SaxOrganisation organisation = AccountMgr.GetOrganisationById(SysId.ToSysId(model.OrganisationId));
|
||||
if (organisation == null)
|
||||
RedirectToAction("", "Organisation");
|
||||
model.Filter.OrganisationId = SysId.ToString(organisation.Id);
|
||||
model.Filter.OrganisationName = organisation.Name;
|
||||
|
||||
// Paging.
|
||||
model.Paging.PageNo = 1;
|
||||
model.Paging.PageLength = 12;
|
||||
|
||||
return View(model);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
}
|
||||
//=======================================================================
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Saxonite.Net.Core.Web.Admin.Models;
|
||||
using Saxonite.Net.Core.Web.Base.App;
|
||||
using Saxonite.Net.Core.Web.Base.Controllers;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Saxonite.Net.Core.Web.Admin.Controllers
|
||||
{
|
||||
//=======================================================================
|
||||
public class PoliciesController : SaxController_Admin
|
||||
{
|
||||
//-------------------------------------------------------------------
|
||||
// Construction.
|
||||
public PoliciesController(SaxLocaliser localiser, ILogger<HomeController> logger) :
|
||||
base(localiser, logger)
|
||||
{
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
[HttpGet]
|
||||
public IActionResult Index()
|
||||
{
|
||||
Model_Policies model = new Model_Policies(Localiser);
|
||||
return View(model);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
[HttpGet]
|
||||
public IActionResult Privacy()
|
||||
{
|
||||
Model_Policies model = new Model_Policies(Localiser);
|
||||
return View(model);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
}
|
||||
//=======================================================================
|
||||
}
|
||||
+46
@@ -0,0 +1,46 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Saxonite.Net.Core.Web.Admin.Models.Reference;
|
||||
using Saxonite.Net.Core.Web.Base.App;
|
||||
using Saxonite.Net.Core.Web.Base.Controllers;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Saxonite.Net.Core.Web.Admin.Controllers.Reference
|
||||
{
|
||||
//=======================================================================
|
||||
public partial class ReferenceBaseballController : SaxController_Admin
|
||||
{
|
||||
//-------------------------------------------------------------------
|
||||
// Construction.
|
||||
public ReferenceBaseballController(SaxLocaliser localiser, ILogger<HomeController> logger) :
|
||||
base(localiser, logger)
|
||||
{
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
[HttpGet]
|
||||
[Route("Reference/Baseball")]
|
||||
public IActionResult Index()
|
||||
{
|
||||
// Validate session.
|
||||
if (!ValidUserSession)
|
||||
AutoLoginUser();
|
||||
if (!ValidUserSession)
|
||||
return RedirectToAction("", "");
|
||||
|
||||
// Paging.
|
||||
Model_ReferenceBaseball model = new Model_ReferenceBaseball(Localiser);
|
||||
//model.Paging.PageNo = 1;
|
||||
//model.Paging.PageLength = 12;
|
||||
|
||||
return View("/Views/Reference/Baseball/Index.cshtml",model);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
}
|
||||
//=======================================================================
|
||||
}
|
||||
+76
@@ -0,0 +1,76 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Sarand.Net.Standard.Base.App;
|
||||
using Sarand.Net.Standard.Base.Bus;
|
||||
using Sarand.Net.Standard.Base.Core;
|
||||
using Sarand.Net.Standard.Base.Dbas;
|
||||
using Sarand.Net.Standard.Base.Utils;
|
||||
using Saxonite.Net.Core.Web.Admin.Models;
|
||||
using Saxonite.Net.Core.Web.Admin.Models.Reference;
|
||||
using Saxonite.Net.Standard.Base.App;
|
||||
using Saxonite.Net.Standard.Base.Bus;
|
||||
using Saxonite.Net.Standard.Base.Bus.Reference;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Saxonite.Net.Core.Web.Admin.Controllers.Reference
|
||||
{
|
||||
//=======================================================================
|
||||
// Reference Baseball Controller - Ajax requests - Stats.
|
||||
//=======================================================================
|
||||
partial class ReferenceBaseballController
|
||||
{
|
||||
//-------------------------------------------------------------------
|
||||
// Get Stats ajax request.
|
||||
//-------------------------------------------------------------------
|
||||
private class AjaxResponse_ReferenceBaseballStats : AjaxResponse_Data
|
||||
{
|
||||
// Construction.
|
||||
public AjaxResponse_ReferenceBaseballStats(SaxModel_Admin model) : base(model) { }
|
||||
// Statistics.
|
||||
public List<StatsGroupData> Groups { get; } = new List<StatsGroupData>();
|
||||
}
|
||||
//-------------------------------------------------------------------
|
||||
[HttpPost]
|
||||
[Route("Reference/Baseball/Ajax/GetStats")]
|
||||
[Route("Reference/Baseball/Ajax/Stats")]
|
||||
public IActionResult Ajax_GetUsgaStats(Model_ReferenceBaseball model)
|
||||
{
|
||||
String fn = GetType().Name + ".Ajax_GetUsgaStats";
|
||||
String messageTitle = Localiser["caption.reference.baseball"];
|
||||
AjaxResponse_ReferenceBaseballStats responseData = new AjaxResponse_ReferenceBaseballStats(model);
|
||||
|
||||
// Validate session.
|
||||
if (!ValidUserSession)
|
||||
return GetAjaxResult_InvalidSession(responseData);
|
||||
|
||||
// Statistics.
|
||||
responseData.Groups.Add(PopulateCoreStatsData(model));
|
||||
|
||||
// Complete response.
|
||||
responseData.Success = true;
|
||||
return Json(responseData);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
private AjaxResponse_Data.StatsGroupData PopulateCoreStatsData(Model_ReferenceBaseball model)
|
||||
{
|
||||
AjaxResponse_Data.StatsGroupData group = new AjaxResponse_Data.StatsGroupData() { Caption = "Core" };
|
||||
|
||||
// Sports.
|
||||
List<SaxSport.Data> sports = GetSportsByName("Baseball", true);
|
||||
|
||||
// Organisations.
|
||||
SaxOrganisation.Params prmOrganisation = new SaxOrganisation.Params();
|
||||
prmOrganisation.SportIdsIncluded.AddIds(sports.Select(item => item.Id));
|
||||
prmOrganisation.StatusCat = SaxOrganisation.StatusCat.ActiveOnly;
|
||||
group.Stats.Add(new AjaxResponse_Data.StatData() { Caption = "Active Organisations", Value = AccountMgr.GetOrganisationCount(prmOrganisation).ToString() });
|
||||
|
||||
return group;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
}
|
||||
//=======================================================================
|
||||
}
|
||||
+33
@@ -0,0 +1,33 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using NPOI.SS.Formula.Functions;
|
||||
using Sarand.Net.Standard.Base.App;
|
||||
using Sarand.Net.Standard.Base.Bus;
|
||||
using Sarand.Net.Standard.Base.Core;
|
||||
using Sarand.Net.Standard.Base.Dbas;
|
||||
using Sarand.Net.Standard.Base.Utils;
|
||||
using Saxonite.Net.Core.Web.Admin.Consoles;
|
||||
using Saxonite.Net.Core.Web.Admin.Models;
|
||||
using Saxonite.Net.Core.Web.Admin.Models.Reference;
|
||||
using Saxonite.Net.Core.Web.Admin.Procs;
|
||||
using Saxonite.Net.Core.Web.Base.Procs;
|
||||
using Saxonite.Net.Standard.Base.App;
|
||||
using Saxonite.Net.Standard.Base.Bus;
|
||||
using Saxonite.Net.Standard.Base.Bus.Reference;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Saxonite.Net.Core.Web.Admin.Controllers.Reference
|
||||
{
|
||||
//=======================================================================
|
||||
// Reference Baseball Controller - Ajax requests.
|
||||
//=======================================================================
|
||||
partial class ReferenceBaseballController
|
||||
{
|
||||
//-------------------------------------------------------------------
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
}
|
||||
//=======================================================================
|
||||
}
|
||||
+64
@@ -0,0 +1,64 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Sarand.Net.Standard.Base.App;
|
||||
using Sarand.Net.Standard.Base.Utils;
|
||||
using Saxonite.Net.Core.Web.Admin.Models;
|
||||
using Saxonite.Net.Core.Web.Base.Models;
|
||||
using Saxonite.Net.Standard.Base.App;
|
||||
using Saxonite.Net.Standard.Base.Helpers;
|
||||
using System;
|
||||
|
||||
namespace Saxonite.Net.Core.Web.Admin.Controllers.Reference
|
||||
{
|
||||
//=======================================================================
|
||||
// Admin Reference Controller - Contact Method Ajax actions only.
|
||||
//=======================================================================
|
||||
partial class ReferenceController
|
||||
{
|
||||
//-------------------------------------------------------------------
|
||||
// Validate Contact Method.
|
||||
//-------------------------------------------------------------------
|
||||
private class AjaxResponse_ValidateContactMethod : AjaxResponse_Data
|
||||
{
|
||||
public AjaxResponse_ValidateContactMethod(SaxModel_Base model) : base(model) { }
|
||||
}
|
||||
[HttpPost]
|
||||
[Route("Reference/Ajax/ValidateContactMethod")]
|
||||
public IActionResult Ajax_ValidateContactMethod(Model_ContactMethod model)
|
||||
{
|
||||
String fn = GetType().Name + ".Ajax_ValidateContactMethod";
|
||||
String messageTitle = Localiser["caption.contact.method"];
|
||||
AjaxResponse_ValidateContactMethod responseData = new AjaxResponse_ValidateContactMethod(model);
|
||||
|
||||
// Validate session and referrer.
|
||||
if (!ValidReferer) return Forbid();
|
||||
if (!ValidUserSession) return GetAjaxResult_InvalidSession(responseData);
|
||||
|
||||
// Validate method.
|
||||
Sax.ContactMethod method = EnumUtil.ParseEnum(model.ContactMethod, Sax.ContactMethod.Unknown);
|
||||
if (model.ContactMethod.IsEmpty() || (int)method < 1)
|
||||
responseData.SetControlError(nameof(model.ContactMethod), Localiser["msg.validation.mandatory.value"]);
|
||||
|
||||
// Validate method.
|
||||
if (model.ContactValue.IsEmpty())
|
||||
responseData.SetControlError(nameof(model.ContactValue), Localiser["msg.validation.mandatory.value"]);
|
||||
|
||||
// Method specific value validation.
|
||||
if (!model.ContactValue.IsEmpty() && !SaxContactMethodHelper.IsValidContactMethodValue(method, model.ContactValue))
|
||||
{
|
||||
// Log invalid values so that the validation can be adjusted if needed.
|
||||
SaLogger.Warn(fn + " Invalid contact method value. Mathod: " + method.ToString() + ". Value: " + model.ContactValue);
|
||||
responseData.SetControlError(nameof(model.ContactValue), Localiser["msg.validation.invalid.value"]);
|
||||
}
|
||||
|
||||
if (responseData.HasControlErrors())
|
||||
return Json(responseData);
|
||||
|
||||
// Complete response.
|
||||
responseData.Success = true;
|
||||
return Json(responseData);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
}
|
||||
//=======================================================================
|
||||
}
|
||||
+31
@@ -0,0 +1,31 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Sarand.Net.Standard.Base.App;
|
||||
using Sarand.Net.Standard.Base.Bus;
|
||||
using Sarand.Net.Standard.Base.Core;
|
||||
using Sarand.Net.Standard.Base.Dbas;
|
||||
using Saxonite.Net.Core.Web.Base.App;
|
||||
using Saxonite.Net.Standard.Base.App;
|
||||
using Saxonite.Net.Standard.Base.Bus;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Saxonite.Net.Core.Web.Admin.Controllers.Reference
|
||||
{
|
||||
//=======================================================================
|
||||
// Admin Reference Controller - Ajax actions only.
|
||||
//=======================================================================
|
||||
public partial class ReferenceController : SaxController_Admin
|
||||
{
|
||||
//-------------------------------------------------------------------
|
||||
// Construction.
|
||||
public ReferenceController(SaxLocaliser localiser, ILogger<HomeController> logger) :
|
||||
base(localiser, logger)
|
||||
{}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
}
|
||||
//=======================================================================
|
||||
}
|
||||
+300
@@ -0,0 +1,300 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Sarand.Net.Standard.Base.App;
|
||||
using Sarand.Net.Standard.Base.Bus;
|
||||
using Sarand.Net.Standard.Base.Core;
|
||||
using Sarand.Net.Standard.Base.Dbas;
|
||||
using Sarand.Net.Standard.Base.Utils;
|
||||
using Saxonite.Net.Core.Web.Admin.Models;
|
||||
using Saxonite.Net.Core.Web.Admin.Models.Reference;
|
||||
using Saxonite.Net.Standard.Base.App;
|
||||
using Saxonite.Net.Standard.Base.Bus;
|
||||
using Saxonite.Net.Standard.Base.Bus.Reference;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Saxonite.Net.Core.Web.Admin.Controllers.Reference
|
||||
{
|
||||
//=======================================================================
|
||||
// Reference Golf Controller - Ajax requests - Stats.
|
||||
//=======================================================================
|
||||
partial class ReferenceGolfController
|
||||
{
|
||||
//-------------------------------------------------------------------
|
||||
// Get Stats ajax request.
|
||||
//-------------------------------------------------------------------
|
||||
private class AjaxResponse_ReferenceGolfStats : AjaxResponse_Data
|
||||
{
|
||||
// Construction.
|
||||
public AjaxResponse_ReferenceGolfStats(SaxModel_Admin model) : base(model) { }
|
||||
// Statistics.
|
||||
public List<StatsGroupData> Groups { get; } = new List<StatsGroupData>();
|
||||
}
|
||||
//-------------------------------------------------------------------
|
||||
[HttpPost]
|
||||
[Route("Reference/Golf/Ajax/GetUsgaStats")]
|
||||
[Route("Reference/Golf/Ajax/GetStats")]
|
||||
[Route("Reference/Golf/Ajax/Stats")]
|
||||
public IActionResult Ajax_GetUsgaStats(Model_ReferenceGolf model)
|
||||
{
|
||||
String fn = GetType().Name + ".Ajax_GetUsgaStats";
|
||||
String messageTitle = Localiser["caption.reference.golf"];
|
||||
AjaxResponse_ReferenceGolfStats responseData = new AjaxResponse_ReferenceGolfStats(model);
|
||||
|
||||
// Validate session.
|
||||
if (!ValidUserSession)
|
||||
return GetAjaxResult_InvalidSession(responseData);
|
||||
|
||||
// Statistics.
|
||||
responseData.Groups.Add(PopulateCountryStatsData());
|
||||
responseData.Groups.Add(PopulateProvinceStatsData());
|
||||
responseData.Groups.Add(PopulateFacilityStatsData());
|
||||
responseData.Groups.Add(PopulateCourseStatsData());
|
||||
responseData.Groups.Add(PopulateMarkerStatsData());
|
||||
|
||||
// Complete response.
|
||||
responseData.Success = true;
|
||||
return Json(responseData);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
private AjaxResponse_Data.StatsGroupData PopulateCountryStatsData()
|
||||
{
|
||||
AjaxResponse_Data.StatsGroupData group = new AjaxResponse_Data.StatsGroupData() { Caption = "Countries" };
|
||||
|
||||
// All countries.
|
||||
SaxGolfUsgaCountry.Params prmCountry = new SaxGolfUsgaCountry.Params();
|
||||
prmCountry.StatusCat = SaxGolfUsgaCountry.StatusCat.Any;
|
||||
group.Stats.Add(new AjaxResponse_Data.StatData() { Caption = "Total", Value = ReferenceGolfMgr.GetUsgaCountryCount(prmCountry).ToString() });
|
||||
|
||||
// Active countries.
|
||||
prmCountry = new SaxGolfUsgaCountry.Params();
|
||||
prmCountry.StatusCat = SaxGolfUsgaCountry.StatusCat.ActiveOnly;
|
||||
group.Stats.Add(new AjaxResponse_Data.StatData() { Caption = "Active", Value = ReferenceGolfMgr.GetUsgaCountryCount(prmCountry).ToString() });
|
||||
|
||||
// Inctive countries.
|
||||
prmCountry = new SaxGolfUsgaCountry.Params();
|
||||
prmCountry.StatusCat = SaxGolfUsgaCountry.StatusCat.InactiveOnly;
|
||||
group.Stats.Add(new AjaxResponse_Data.StatData() { Caption = "Inactive", Value = ReferenceGolfMgr.GetUsgaCountryCount(prmCountry).ToString() });
|
||||
|
||||
// Deleted countries.
|
||||
prmCountry = new SaxGolfUsgaCountry.Params();
|
||||
prmCountry.StatusCat = SaxGolfUsgaCountry.StatusCat.DeletedOnly;
|
||||
group.Stats.Add(new AjaxResponse_Data.StatData() { Caption = "Deleted", Value = ReferenceGolfMgr.GetUsgaCountryCount(prmCountry).ToString() });
|
||||
|
||||
// Priority countries without provinces.
|
||||
prmCountry = new SaxGolfUsgaCountry.Params();
|
||||
prmCountry.PriorityFlagState = SacsHierarchyItem.Params.FlagState.True;
|
||||
prmCountry.HasProvinces = SacsHierarchyItem.Params.BoolState.False;
|
||||
prmCountry.StatusCat = SaxGolfUsgaCountry.StatusCat.ActiveOnly;
|
||||
group.Stats.Add(new AjaxResponse_Data.StatData() { Caption = "Priority no provinces", Value = ReferenceGolfMgr.GetUsgaCountryCount(prmCountry).ToString() });
|
||||
|
||||
// Non-Priority countries without provinces.
|
||||
prmCountry = new SaxGolfUsgaCountry.Params();
|
||||
prmCountry.PriorityFlagState = SacsHierarchyItem.Params.FlagState.False;
|
||||
prmCountry.HasProvinces = SacsHierarchyItem.Params.BoolState.False;
|
||||
prmCountry.StatusCat = SaxGolfUsgaCountry.StatusCat.ActiveOnly;
|
||||
group.Stats.Add(new AjaxResponse_Data.StatData() { Caption = "Non-priority no provinces", Value = ReferenceGolfMgr.GetUsgaCountryCount(prmCountry).ToString() });
|
||||
|
||||
// Priority countries with provinces.
|
||||
prmCountry = new SaxGolfUsgaCountry.Params();
|
||||
prmCountry.PriorityFlagState = SacsHierarchyItem.Params.FlagState.True;
|
||||
prmCountry.HasProvinces = SacsHierarchyItem.Params.BoolState.True;
|
||||
prmCountry.StatusCat = SaxGolfUsgaCountry.StatusCat.ActiveOnly;
|
||||
group.Stats.Add(new AjaxResponse_Data.StatData() { Caption = "Priority with provinces", Value = ReferenceGolfMgr.GetUsgaCountryCount(prmCountry).ToString() });
|
||||
|
||||
// Non-Priority countries with provinces.
|
||||
prmCountry = new SaxGolfUsgaCountry.Params();
|
||||
prmCountry.PriorityFlagState = SacsHierarchyItem.Params.FlagState.False;
|
||||
prmCountry.HasProvinces = SacsHierarchyItem.Params.BoolState.True;
|
||||
prmCountry.StatusCat = SaxGolfUsgaCountry.StatusCat.ActiveOnly;
|
||||
group.Stats.Add(new AjaxResponse_Data.StatData() { Caption = "Non-priority with provinces", Value = ReferenceGolfMgr.GetUsgaCountryCount(prmCountry).ToString() });
|
||||
|
||||
return group;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
private AjaxResponse_Data.StatsGroupData PopulateProvinceStatsData()
|
||||
{
|
||||
AjaxResponse_Data.StatsGroupData group = new AjaxResponse_Data.StatsGroupData() { Caption = "Provinces" };
|
||||
|
||||
// All provinces.
|
||||
SaxGolfUsgaProvince.Params prmProvince = new SaxGolfUsgaProvince.Params();
|
||||
prmProvince.StatusCat = SaxGolfUsgaProvince.StatusCat.Any;
|
||||
group.Stats.Add(new AjaxResponse_Data.StatData() { Caption = "Total", Value = ReferenceGolfMgr.GetUsgaProvinceCount(prmProvince).ToString() });
|
||||
|
||||
// Active provinces.
|
||||
prmProvince = new SaxGolfUsgaProvince.Params();
|
||||
prmProvince.StatusCat = SaxGolfUsgaProvince.StatusCat.ActiveOnly;
|
||||
group.Stats.Add(new AjaxResponse_Data.StatData() { Caption = "Active", Value = ReferenceGolfMgr.GetUsgaProvinceCount(prmProvince).ToString() });
|
||||
|
||||
// Inctive provinces.
|
||||
prmProvince = new SaxGolfUsgaProvince.Params();
|
||||
prmProvince.StatusCat = SaxGolfUsgaProvince.StatusCat.InactiveOnly;
|
||||
group.Stats.Add(new AjaxResponse_Data.StatData() { Caption = "Inactive", Value = ReferenceGolfMgr.GetUsgaProvinceCount(prmProvince).ToString() });
|
||||
|
||||
// Deleted provinces.
|
||||
prmProvince = new SaxGolfUsgaProvince.Params();
|
||||
prmProvince.StatusCat = SaxGolfUsgaProvince.StatusCat.DeletedOnly;
|
||||
group.Stats.Add(new AjaxResponse_Data.StatData() { Caption = "Deleted", Value = ReferenceGolfMgr.GetUsgaProvinceCount(prmProvince).ToString() });
|
||||
|
||||
// Priority provinces without facilities.
|
||||
prmProvince = new SaxGolfUsgaProvince.Params();
|
||||
prmProvince.PriorityFlagState = SacsHierarchyItem.Params.FlagState.True;
|
||||
prmProvince.HasFacilities = SacsHierarchyItem.Params.BoolState.False;
|
||||
prmProvince.StatusCat = SaxGolfUsgaProvince.StatusCat.ActiveOnly;
|
||||
group.Stats.Add(new AjaxResponse_Data.StatData() { Caption = "Priority no facilities", Value = ReferenceGolfMgr.GetUsgaProvinceCount(prmProvince).ToString() });
|
||||
|
||||
// Non-Priority provinces without facilities.
|
||||
prmProvince = new SaxGolfUsgaProvince.Params();
|
||||
prmProvince.PriorityFlagState = SacsHierarchyItem.Params.FlagState.False;
|
||||
prmProvince.HasFacilities = SacsHierarchyItem.Params.BoolState.False;
|
||||
prmProvince.StatusCat = SaxGolfUsgaProvince.StatusCat.ActiveOnly;
|
||||
group.Stats.Add(new AjaxResponse_Data.StatData() { Caption = "Non-priority no facilities", Value = ReferenceGolfMgr.GetUsgaProvinceCount(prmProvince).ToString() });
|
||||
|
||||
// Priority provinces with facilities.
|
||||
prmProvince = new SaxGolfUsgaProvince.Params();
|
||||
prmProvince.PriorityFlagState = SacsHierarchyItem.Params.FlagState.True;
|
||||
prmProvince.HasFacilities = SacsHierarchyItem.Params.BoolState.True;
|
||||
prmProvince.StatusCat = SaxGolfUsgaProvince.StatusCat.ActiveOnly;
|
||||
group.Stats.Add(new AjaxResponse_Data.StatData() { Caption = "Priority with facilities", Value = ReferenceGolfMgr.GetUsgaProvinceCount(prmProvince).ToString() });
|
||||
|
||||
// Non-Priority provinces with facilities.
|
||||
prmProvince = new SaxGolfUsgaProvince.Params();
|
||||
prmProvince.PriorityFlagState = SacsHierarchyItem.Params.FlagState.False;
|
||||
prmProvince.HasFacilities = SacsHierarchyItem.Params.BoolState.True;
|
||||
prmProvince.StatusCat = SaxGolfUsgaProvince.StatusCat.ActiveOnly;
|
||||
group.Stats.Add(new AjaxResponse_Data.StatData() { Caption = "Non-priority with facilities", Value = ReferenceGolfMgr.GetUsgaProvinceCount(prmProvince).ToString() });
|
||||
|
||||
return group;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
private AjaxResponse_Data.StatsGroupData PopulateFacilityStatsData()
|
||||
{
|
||||
AjaxResponse_Data.StatsGroupData group = new AjaxResponse_Data.StatsGroupData() { Caption = "Facilities" };
|
||||
|
||||
// All facilities.
|
||||
SaxGolfUsgaFacility.Params prmFacility = new SaxGolfUsgaFacility.Params();
|
||||
prmFacility.StatusCat = SaxGolfUsgaFacility.StatusCat.Any;
|
||||
group.Stats.Add(new AjaxResponse_Data.StatData() { Caption = "Total", Value = ReferenceGolfMgr.GetUsgaFacilityCount(prmFacility).ToString() });
|
||||
|
||||
// Active facilities.
|
||||
prmFacility = new SaxGolfUsgaFacility.Params();
|
||||
prmFacility.StatusCat = SaxGolfUsgaFacility.StatusCat.ActiveOnly;
|
||||
group.Stats.Add(new AjaxResponse_Data.StatData() { Caption = "Active", Value = ReferenceGolfMgr.GetUsgaFacilityCount(prmFacility).ToString() });
|
||||
|
||||
// Inctive facilities.
|
||||
prmFacility = new SaxGolfUsgaFacility.Params();
|
||||
prmFacility.StatusCat = SaxGolfUsgaFacility.StatusCat.InactiveOnly;
|
||||
group.Stats.Add(new AjaxResponse_Data.StatData() { Caption = "Inactive", Value = ReferenceGolfMgr.GetUsgaFacilityCount(prmFacility).ToString() });
|
||||
|
||||
// Deleted facilities.
|
||||
prmFacility = new SaxGolfUsgaFacility.Params();
|
||||
prmFacility.StatusCat = SaxGolfUsgaFacility.StatusCat.DeletedOnly;
|
||||
group.Stats.Add(new AjaxResponse_Data.StatData() { Caption = "Deleted", Value = ReferenceGolfMgr.GetUsgaFacilityCount(prmFacility).ToString() });
|
||||
|
||||
// Facilities without courses.
|
||||
prmFacility = new SaxGolfUsgaFacility.Params();
|
||||
prmFacility.HasCourses = SacsHierarchyItem.Params.BoolState.False;
|
||||
prmFacility.StatusCat = SaxGolfUsgaFacility.StatusCat.ActiveOnly;
|
||||
group.Stats.Add(new AjaxResponse_Data.StatData() { Caption = "No courses", Value = ReferenceGolfMgr.GetUsgaFacilityCount(prmFacility).ToString() });
|
||||
|
||||
// Priority facilities with courses.
|
||||
prmFacility = new SaxGolfUsgaFacility.Params();
|
||||
prmFacility.HasCourses = SacsHierarchyItem.Params.BoolState.True;
|
||||
prmFacility.StatusCat = SaxGolfUsgaFacility.StatusCat.ActiveOnly;
|
||||
group.Stats.Add(new AjaxResponse_Data.StatData() { Caption = "With courses", Value = ReferenceGolfMgr.GetUsgaFacilityCount(prmFacility).ToString() });
|
||||
|
||||
return group;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
private AjaxResponse_Data.StatsGroupData PopulateCourseStatsData()
|
||||
{
|
||||
AjaxResponse_Data.StatsGroupData group = new AjaxResponse_Data.StatsGroupData() { Caption = "Courses" };
|
||||
|
||||
// All courses.
|
||||
SaxGolfUsgaCourse.Params prmCourse = new SaxGolfUsgaCourse.Params();
|
||||
prmCourse.StatusCat = SaxGolfUsgaCourse.StatusCat.Any;
|
||||
group.Stats.Add(new AjaxResponse_Data.StatData() { Caption = "Total", Value = ReferenceGolfMgr.GetUsgaCourseCount(prmCourse).ToString() });
|
||||
|
||||
// Active courses.
|
||||
prmCourse = new SaxGolfUsgaCourse.Params();
|
||||
prmCourse.StatusCat = SaxGolfUsgaCourse.StatusCat.ActiveOnly;
|
||||
group.Stats.Add(new AjaxResponse_Data.StatData() { Caption = "Active", Value = ReferenceGolfMgr.GetUsgaCourseCount(prmCourse).ToString() });
|
||||
|
||||
// Inctive courses.
|
||||
prmCourse = new SaxGolfUsgaCourse.Params();
|
||||
prmCourse.StatusCat = SaxGolfUsgaCourse.StatusCat.InactiveOnly;
|
||||
group.Stats.Add(new AjaxResponse_Data.StatData() { Caption = "Inactive", Value = ReferenceGolfMgr.GetUsgaCourseCount(prmCourse).ToString() });
|
||||
|
||||
// Deleted courses.
|
||||
prmCourse = new SaxGolfUsgaCourse.Params();
|
||||
prmCourse.StatusCat = SaxGolfUsgaCourse.StatusCat.DeletedOnly;
|
||||
group.Stats.Add(new AjaxResponse_Data.StatData() { Caption = "Deleted", Value = ReferenceGolfMgr.GetUsgaCourseCount(prmCourse).ToString() });
|
||||
|
||||
// Priority courses without markers.
|
||||
prmCourse = new SaxGolfUsgaCourse.Params();
|
||||
prmCourse.PriorityFlagState = SacsHierarchyItem.Params.FlagState.True;
|
||||
prmCourse.HasMarkers = SacsHierarchyItem.Params.BoolState.False;
|
||||
prmCourse.StatusCat = SaxGolfUsgaCourse.StatusCat.ActiveOnly;
|
||||
group.Stats.Add(new AjaxResponse_Data.StatData() { Caption = "Priority no markers", Value = ReferenceGolfMgr.GetUsgaCourseCount(prmCourse).ToString() });
|
||||
|
||||
// Non-Priority courses without markers.
|
||||
prmCourse = new SaxGolfUsgaCourse.Params();
|
||||
prmCourse.PriorityFlagState = SacsHierarchyItem.Params.FlagState.False;
|
||||
prmCourse.HasMarkers = SacsHierarchyItem.Params.BoolState.False;
|
||||
prmCourse.StatusCat = SaxGolfUsgaCourse.StatusCat.ActiveOnly;
|
||||
group.Stats.Add(new AjaxResponse_Data.StatData() { Caption = "Non-priority no markers", Value = ReferenceGolfMgr.GetUsgaCourseCount(prmCourse).ToString() });
|
||||
|
||||
// Priority courses with markers.
|
||||
prmCourse = new SaxGolfUsgaCourse.Params();
|
||||
prmCourse.PriorityFlagState = SacsHierarchyItem.Params.FlagState.True;
|
||||
prmCourse.HasMarkers = SacsHierarchyItem.Params.BoolState.True;
|
||||
prmCourse.StatusCat = SaxGolfUsgaCourse.StatusCat.ActiveOnly;
|
||||
group.Stats.Add(new AjaxResponse_Data.StatData() { Caption = "Priority with markers", Value = ReferenceGolfMgr.GetUsgaCourseCount(prmCourse).ToString() });
|
||||
|
||||
// Non-Priority courses with markers.
|
||||
prmCourse = new SaxGolfUsgaCourse.Params();
|
||||
prmCourse.PriorityFlagState = SacsHierarchyItem.Params.FlagState.False;
|
||||
prmCourse.HasMarkers = SacsHierarchyItem.Params.BoolState.True;
|
||||
prmCourse.StatusCat = SaxGolfUsgaCourse.StatusCat.ActiveOnly;
|
||||
group.Stats.Add(new AjaxResponse_Data.StatData() { Caption = "Non-priority with markers", Value = ReferenceGolfMgr.GetUsgaCourseCount(prmCourse).ToString() });
|
||||
|
||||
return group;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
private AjaxResponse_Data.StatsGroupData PopulateMarkerStatsData()
|
||||
{
|
||||
AjaxResponse_Data.StatsGroupData group = new AjaxResponse_Data.StatsGroupData() { Caption = "Markers" };
|
||||
|
||||
// All markers.
|
||||
SaxGolfUsgaMarker.Params prmMarker = new SaxGolfUsgaMarker.Params();
|
||||
prmMarker.StatusCat = SaxGolfUsgaMarker.StatusCat.Any;
|
||||
group.Stats.Add(new AjaxResponse_Data.StatData() { Caption = "Total", Value = ReferenceGolfMgr.GetUsgaMarkerCount(prmMarker).ToString() });
|
||||
|
||||
// Active markers.
|
||||
prmMarker = new SaxGolfUsgaMarker.Params();
|
||||
prmMarker.StatusCat = SaxGolfUsgaMarker.StatusCat.ActiveOnly;
|
||||
group.Stats.Add(new AjaxResponse_Data.StatData() { Caption = "Active", Value = ReferenceGolfMgr.GetUsgaMarkerCount(prmMarker).ToString() });
|
||||
|
||||
// Inctive markers.
|
||||
prmMarker = new SaxGolfUsgaMarker.Params();
|
||||
prmMarker.StatusCat = SaxGolfUsgaMarker.StatusCat.InactiveOnly;
|
||||
group.Stats.Add(new AjaxResponse_Data.StatData() { Caption = "Inactive", Value = ReferenceGolfMgr.GetUsgaMarkerCount(prmMarker).ToString() });
|
||||
|
||||
// Deleted markers.
|
||||
prmMarker = new SaxGolfUsgaMarker.Params();
|
||||
prmMarker.StatusCat = SaxGolfUsgaMarker.StatusCat.DeletedOnly;
|
||||
group.Stats.Add(new AjaxResponse_Data.StatData() { Caption = "Deleted", Value = ReferenceGolfMgr.GetUsgaMarkerCount(prmMarker).ToString() });
|
||||
|
||||
return group;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
}
|
||||
//=======================================================================
|
||||
}
|
||||
+590
@@ -0,0 +1,590 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using NPOI.SS.Formula.Functions;
|
||||
using Sarand.Net.Standard.Base.App;
|
||||
using Sarand.Net.Standard.Base.Bus;
|
||||
using Sarand.Net.Standard.Base.Core;
|
||||
using Sarand.Net.Standard.Base.Dbas;
|
||||
using Sarand.Net.Standard.Base.Utils;
|
||||
using Saxonite.Net.Core.Web.Admin.Consoles;
|
||||
using Saxonite.Net.Core.Web.Admin.Models;
|
||||
using Saxonite.Net.Core.Web.Admin.Models.Reference;
|
||||
using Saxonite.Net.Core.Web.Admin.Procs;
|
||||
using Saxonite.Net.Core.Web.Base.Procs;
|
||||
using Saxonite.Net.Standard.Base.App;
|
||||
using Saxonite.Net.Standard.Base.Bus;
|
||||
using Saxonite.Net.Standard.Base.Bus.Reference;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Saxonite.Net.Core.Web.Admin.Controllers.Reference
|
||||
{
|
||||
//=======================================================================
|
||||
// Reference Golf Controller - Ajax requests.
|
||||
//=======================================================================
|
||||
partial class ReferenceGolfController
|
||||
{
|
||||
//-------------------------------------------------------------------
|
||||
// USGA Country data.
|
||||
private class UsgaCountryListData : AjaxResponse_Data.ItemData_Base
|
||||
{
|
||||
public String Code { get; set; }
|
||||
public String Name { get; set; }
|
||||
public bool? PriorityPopulate { get; set; }
|
||||
public long? ProvinceCount { get; set; }
|
||||
public long? ProvinceCountActive { get; set; }
|
||||
public long? FacilityCount { get; set; }
|
||||
public long? FacilityCountActive { get; set; }
|
||||
public decimal? CoursesPercent { get; set; }
|
||||
public String CoursesPercentFmt { get { return (CoursesPercent ?? 0.0m) > 0 ? $"{((decimal)CoursesPercent).ToString("N0")}%" : null; } }
|
||||
}
|
||||
private class UsgaCountryItemData : UsgaCountryListData
|
||||
{
|
||||
}
|
||||
private void PopulateUsgaCountryResponseListData(SaxGolfUsgaCountry country, UsgaCountryListData data)
|
||||
{
|
||||
data.Id = SysId.ToString(country.Id);
|
||||
data.Code = country.CountryCode;
|
||||
data.Name = country.CountryName;
|
||||
data.StatusCode = country.StatusCode;
|
||||
data.StatusDesc = country.StatusDesc;
|
||||
}
|
||||
private void PopulateUsgaCountryResponseItemData(SaxGolfUsgaCountry country, UsgaCountryItemData data)
|
||||
{
|
||||
PopulateUsgaCountryResponseListData(country, data);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// USGA Province data.
|
||||
private class UsgaProvinceListData : AjaxResponse_Data.ItemData_Base
|
||||
{
|
||||
public String Code { get; set; }
|
||||
public String Name { get; set; }
|
||||
public bool? PriorityPopulate { get; set; }
|
||||
public long? FacilityCount { get; set; }
|
||||
public long? FacilityCountActive { get; set; }
|
||||
public long? CourseCount { get; set; }
|
||||
public long? CourseCountActive { get; set; }
|
||||
public decimal? MarkersPercent { get; set; }
|
||||
public String MarkersPercentFmt { get { return (MarkersPercent ?? 0.0m) > 0 ? $"{((decimal)MarkersPercent).ToString("N0")}%" : null; } }
|
||||
}
|
||||
private class UsgaProvinceItemData : UsgaProvinceListData
|
||||
{
|
||||
}
|
||||
private void PopulateUsgaProvinceResponseListData(SaxGolfUsgaProvince province, UsgaProvinceListData data)
|
||||
{
|
||||
data.Id = SysId.ToString(province.Id);
|
||||
data.Code = province.ProvinceCode;
|
||||
data.Name = province.ProvinceName;
|
||||
data.StatusCode = province.StatusCode;
|
||||
data.StatusDesc = province.StatusDesc;
|
||||
}
|
||||
private void PopulateUsgaProvinceResponseItemData(SaxGolfUsgaProvince province, UsgaProvinceItemData data)
|
||||
{
|
||||
PopulateUsgaProvinceResponseListData(province, data);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// USGA Course data.
|
||||
private class UsgaCourseListData : AjaxResponse_Data.ItemData_Base
|
||||
{
|
||||
public long? UsgaCourseId { get; set; }
|
||||
public String Caption { get; set; }
|
||||
public String Name { get; set; }
|
||||
public String FullName { get; set; }
|
||||
public String Address1 { get; set; }
|
||||
public String Address2 { get; set; }
|
||||
public String City { get; set; }
|
||||
public bool? PriorityPopulate { get; set; }
|
||||
public long? MarkerCount { get; set; }
|
||||
public long? MarkerCountActive { get; set; }
|
||||
}
|
||||
private class UsgaCourseItemData : UsgaCourseListData
|
||||
{
|
||||
}
|
||||
private void PopulateUsgaCourseResponseListData(SaxGolfUsgaCourse course, UsgaCourseListData data)
|
||||
{
|
||||
data.Id = SysId.ToString(course.Id);
|
||||
data.Caption = course.Caption;
|
||||
data.Name = course.CourseName;
|
||||
data.FullName = course.FullName;
|
||||
data.Address1 = course.Address1;
|
||||
data.Address2 = course.Address2;
|
||||
data.City = course.City;
|
||||
data.StatusCode = course.StatusCode;
|
||||
data.StatusDesc = course.StatusDesc;
|
||||
}
|
||||
private void PopulateUsgaCourseResponseItemData(SaxGolfUsgaCourse course, UsgaCourseItemData data)
|
||||
{
|
||||
PopulateUsgaCourseResponseListData(course, data);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// USGA Marker data.
|
||||
private class UsgaMarkerListData : AjaxResponse_Data.ItemData_Base
|
||||
{
|
||||
public long? UsgaMarkerId { get; set; }
|
||||
public String Caption { get; set; }
|
||||
public short? Holes { get; set; }
|
||||
public String HolesCaption { get; set; }
|
||||
public String Tee { get; set; }
|
||||
public String Gender { get; set; }
|
||||
public short? SlopeRating { get; set; }
|
||||
public short? Par { get; set; }
|
||||
public decimal? CourseRating { get; set; }
|
||||
public decimal? BogeyRating { get; set; }
|
||||
public short? Length { get; set; }
|
||||
}
|
||||
private class UsgaMarkerItemData : UsgaMarkerListData
|
||||
{
|
||||
}
|
||||
private void PopulateUsgaMarkerResponseListData(SaxGolfUsgaMarker marker, UsgaMarkerListData data)
|
||||
{
|
||||
data.Id = SysId.ToString(marker.Id);
|
||||
data.Caption = marker.Caption;
|
||||
data.Holes = marker.Holes;
|
||||
data.HolesCaption = marker.HolesCaption;
|
||||
data.Tee = marker.Tee;
|
||||
data.Gender = marker.Gender;
|
||||
data.SlopeRating = marker.SlopeRating;
|
||||
data.Par = marker.Par;
|
||||
data.Gender = marker.Gender;
|
||||
data.BogeyRating = marker.BogeyRating;
|
||||
data.Length = marker.Length;
|
||||
data.StatusCode = marker.StatusCode;
|
||||
data.StatusDesc = marker.StatusDesc;
|
||||
}
|
||||
private void PopulateUsgaMarkerResponseItemData(SaxGolfUsgaMarker course, UsgaMarkerItemData data)
|
||||
{
|
||||
PopulateUsgaMarkerResponseListData(course, data);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Get Country List ajax request.
|
||||
//-------------------------------------------------------------------
|
||||
private class AjaxResponse_ReferenceGolf_CountryList : AjaxResponse_Data
|
||||
{
|
||||
// Construction.
|
||||
public AjaxResponse_ReferenceGolf_CountryList(SaxModel_Admin model) : base(model) { }
|
||||
// Country list.
|
||||
public List<UsgaCountryListData> Countries { get; } = new List<UsgaCountryListData>();
|
||||
}
|
||||
//-------------------------------------------------------------------
|
||||
[HttpPost]
|
||||
[Route("Reference/Golf/Ajax/GetUsgaCountryList")]
|
||||
[Route("Reference/Golf/Ajax/GetUsgaCountries")]
|
||||
[Route("Reference/Golf/Ajax/GetCountryList")]
|
||||
[Route("Reference/Golf/Ajax/GetCountries")]
|
||||
public IActionResult Ajax_GetCountryList(Model_ReferenceGolf model)
|
||||
{
|
||||
String messageTitle = Localiser["caption.reference.golf"];
|
||||
AjaxResponse_ReferenceGolf_CountryList responseData = new AjaxResponse_ReferenceGolf_CountryList(model);
|
||||
|
||||
// Validate session.
|
||||
if (!ValidUserSession)
|
||||
return GetAjaxResult_InvalidSession(responseData);
|
||||
|
||||
// Item columns.
|
||||
ColumnDfn colId = ReferenceGolfMgr.GetUsgaCountryColumnDfn(SaxGolfUsgaCountry.Column.Id);
|
||||
ColumnDfn colCode = ReferenceGolfMgr.GetUsgaCountryColumnDfn(SaxGolfUsgaCountry.Column.CountryCode);
|
||||
ColumnDfn colName = ReferenceGolfMgr.GetUsgaCountryColumnDfn(SaxGolfUsgaCountry.Column.CountryName);
|
||||
ColumnDfn colProvinceCount_All = ReferenceGolfMgr.GetUsgaCountryColumnDfn(SaxGolfUsgaCountry.Column.ProvinceCount_All);
|
||||
ColumnDfn colProvinceCount_Active = ReferenceGolfMgr.GetUsgaCountryColumnDfn(SaxGolfUsgaCountry.Column.ProvinceCount_Active);
|
||||
ColumnDfn colFacilityCount_All = ReferenceGolfMgr.GetUsgaCountryColumnDfn(SaxGolfUsgaCountry.Column.FacilityCount_All);
|
||||
ColumnDfn colFacilityCount_Active = ReferenceGolfMgr.GetUsgaCountryColumnDfn(SaxGolfUsgaCountry.Column.FacilityCount_Active);
|
||||
ColumnDfn colCoursesPercent = ReferenceGolfMgr.GetUsgaCountryColumnDfn(SaxGolfUsgaCountry.Column.FacilityPercent);
|
||||
ColumnDfn colFlags = ReferenceGolfMgr.GetUsgaCountryColumnDfn(SaxGolfUsgaCountry.Column.Flags);
|
||||
ColumnDfn colStatus = ReferenceGolfMgr.GetUsgaCountryColumnDfn(SaxGolfUsgaCountry.Column.Status);
|
||||
List<ColumnDfn> columns = new List<ColumnDfn>()
|
||||
{
|
||||
colId, colCode, colName, colProvinceCount_All, colProvinceCount_Active, colFacilityCount_All, colFacilityCount_Active, colCoursesPercent, colFlags, colStatus
|
||||
};
|
||||
|
||||
// Item filter.
|
||||
SaxGolfUsgaCountry.Params prmUsgaCountry = new SaxGolfUsgaCountry.Params();
|
||||
prmUsgaCountry.CountryFilter = model.Filter.CountrySearch;
|
||||
prmUsgaCountry.StatusCat = SaxGolfUsgaCountry.StatusCat.Any;
|
||||
model.Paging.ItemTotal = (ulong)ReferenceGolfMgr.GetUsgaCountryCount(prmUsgaCountry);
|
||||
model.PopulatePagingTo(prmUsgaCountry.ResultsPaging);
|
||||
|
||||
// Sort order.
|
||||
prmUsgaCountry.SortColumns.Add(colName);
|
||||
|
||||
// Query items.
|
||||
using (DbResultSet resultSet = ReferenceGolfMgr.ExecuteUsgaCountryQuery(columns, prmUsgaCountry))
|
||||
{
|
||||
while (resultSet != null && resultSet.HasRows && resultSet.NextRecord())
|
||||
{
|
||||
NamedValue.Map values = resultSet.GetRecordValues();
|
||||
ushort flags = (ushort)values.GetLong(colFlags.DataName);
|
||||
UsgaCountryListData provinceData = new UsgaCountryListData()
|
||||
{
|
||||
Id = values.GetString(colId.DataName),
|
||||
Code = values.GetString(colCode.DataName),
|
||||
Name = values.GetString(colName.DataName),
|
||||
PriorityPopulate = SacsHierarchyItem.GetFlag(flags, SaxGolfUsgaCountry.Flag_Priority),
|
||||
ProvinceCount = values.GetLong(colProvinceCount_All.DataName),
|
||||
ProvinceCountActive = values.GetLong(colProvinceCount_Active.DataName),
|
||||
FacilityCount = values.GetLong(colFacilityCount_All.DataName),
|
||||
FacilityCountActive = values.GetLong(colFacilityCount_Active.DataName),
|
||||
CoursesPercent = values.GetDecimal(colCoursesPercent.DataName),
|
||||
StatusCode = values.GetString(colStatus.DataName),
|
||||
StatusDesc = SacsSystem.GetStatusDescForCode(values.GetString(colStatus.DataName))
|
||||
};
|
||||
responseData.Countries.Add(provinceData);
|
||||
}
|
||||
}
|
||||
if (model.Paging.IsPaged)
|
||||
model.Paging.ItemCount = (ushort)responseData.Countries.Count;
|
||||
|
||||
// Complete response.
|
||||
responseData.SetPaging(model);
|
||||
responseData.Success = true;
|
||||
return Json(responseData);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Get Province List ajax request.
|
||||
//-------------------------------------------------------------------
|
||||
private class AjaxResponse_ReferenceGolf_ProvinceList : AjaxResponse_Data
|
||||
{
|
||||
// Construction.
|
||||
public AjaxResponse_ReferenceGolf_ProvinceList(SaxModel_Admin model) : base(model) { }
|
||||
// Province list.
|
||||
public List<UsgaProvinceListData> Provinces { get; } = new List<UsgaProvinceListData>();
|
||||
}
|
||||
//-------------------------------------------------------------------
|
||||
[HttpPost]
|
||||
[Route("Reference/Golf/Ajax/GetUsgaProvinceList")]
|
||||
[Route("Reference/Golf/Ajax/GetUsgaProvinces")]
|
||||
[Route("Reference/Golf/Ajax/GetProvinceList")]
|
||||
[Route("Reference/Golf/Ajax/GetProvinces")]
|
||||
public IActionResult Ajax_GetProvinceList(Model_ReferenceGolf model)
|
||||
{
|
||||
String messageTitle = Localiser["caption.reference.golf"];
|
||||
AjaxResponse_ReferenceGolf_ProvinceList responseData = new AjaxResponse_ReferenceGolf_ProvinceList(model);
|
||||
|
||||
// Validate session.
|
||||
if (!ValidUserSession)
|
||||
return GetAjaxResult_InvalidSession(responseData);
|
||||
|
||||
// Item columns.
|
||||
ColumnDfn colId = ReferenceGolfMgr.GetUsgaProvinceColumnDfn(SaxGolfUsgaProvince.Column.Id);
|
||||
ColumnDfn colCode = ReferenceGolfMgr.GetUsgaProvinceColumnDfn(SaxGolfUsgaProvince.Column.ProvinceCode);
|
||||
ColumnDfn colName = ReferenceGolfMgr.GetUsgaProvinceColumnDfn(SaxGolfUsgaProvince.Column.ProvinceName);
|
||||
ColumnDfn colFacilityCount_All = ReferenceGolfMgr.GetUsgaProvinceColumnDfn(SaxGolfUsgaProvince.Column.FacilityCount_All);
|
||||
ColumnDfn colFacilityCount_Active = ReferenceGolfMgr.GetUsgaProvinceColumnDfn(SaxGolfUsgaProvince.Column.FacilityCount_Active);
|
||||
ColumnDfn colCourseCount_All = ReferenceGolfMgr.GetUsgaProvinceColumnDfn(SaxGolfUsgaProvince.Column.CourseCount_All);
|
||||
ColumnDfn colCourseCount_Active = ReferenceGolfMgr.GetUsgaProvinceColumnDfn(SaxGolfUsgaProvince.Column.CourseCount_Active);
|
||||
ColumnDfn colMarkersPercent = ReferenceGolfMgr.GetUsgaProvinceColumnDfn(SaxGolfUsgaProvince.Column.MarkerPercent);
|
||||
ColumnDfn colFlags = ReferenceGolfMgr.GetUsgaProvinceColumnDfn(SaxGolfUsgaProvince.Column.Flags);
|
||||
ColumnDfn colStatus = ReferenceGolfMgr.GetUsgaProvinceColumnDfn(SaxGolfUsgaProvince.Column.Status);
|
||||
List<ColumnDfn> columns = new List<ColumnDfn>()
|
||||
{
|
||||
colId, colCode, colName, colFacilityCount_All, colFacilityCount_Active, colCourseCount_All, colCourseCount_Active, colMarkersPercent, colFlags, colStatus
|
||||
};
|
||||
|
||||
// Item filter.
|
||||
SaxGolfUsgaProvince.Params prmUsgaProvince = new SaxGolfUsgaProvince.Params();
|
||||
if (StringUtil.ToLong(model.Filter.CountryId) > 0)
|
||||
prmUsgaProvince.CountryIdsIncluded.Add(SysId.ToSysId(model.Filter.CountryId));
|
||||
prmUsgaProvince.ProvinceFilter = model.Filter.ProvinceSearch;
|
||||
prmUsgaProvince.StatusCat = SaxGolfUsgaProvince.StatusCat.Any;
|
||||
model.Paging.ItemTotal = (ulong)ReferenceGolfMgr.GetUsgaProvinceCount(prmUsgaProvince);
|
||||
model.PopulatePagingTo(prmUsgaProvince.ResultsPaging);
|
||||
|
||||
// Sort order.
|
||||
prmUsgaProvince.SortColumns.Add(colCode);
|
||||
|
||||
// Query items.
|
||||
using (DbResultSet resultSet = ReferenceGolfMgr.ExecuteUsgaProvinceQuery(columns, prmUsgaProvince))
|
||||
{
|
||||
while (resultSet != null && resultSet.HasRows && resultSet.NextRecord())
|
||||
{
|
||||
NamedValue.Map values = resultSet.GetRecordValues();
|
||||
ushort flags = (ushort)values.GetLong(colFlags.DataName);
|
||||
UsgaProvinceListData provinceData = new UsgaProvinceListData()
|
||||
{
|
||||
Id = values.GetString(colId.DataName),
|
||||
Code = values.GetString(colCode.DataName),
|
||||
Name = values.GetString(colName.DataName),
|
||||
PriorityPopulate = SacsHierarchyItem.GetFlag(flags, SaxGolfUsgaProvince.Flag_Priority),
|
||||
FacilityCount = values.GetLong(colFacilityCount_All.DataName),
|
||||
FacilityCountActive = values.GetLong(colFacilityCount_Active.DataName),
|
||||
CourseCount = values.GetLong(colCourseCount_All.DataName),
|
||||
CourseCountActive = values.GetLong(colCourseCount_Active.DataName),
|
||||
MarkersPercent = values.GetDecimal(colMarkersPercent.DataName),
|
||||
StatusCode = values.GetString(colStatus.DataName),
|
||||
StatusDesc = SacsSystem.GetStatusDescForCode(values.GetString(colStatus.DataName))
|
||||
};
|
||||
responseData.Provinces.Add(provinceData);
|
||||
}
|
||||
}
|
||||
if (model.Paging.IsPaged)
|
||||
model.Paging.ItemCount = (ushort)responseData.Provinces.Count;
|
||||
|
||||
// Complete response.
|
||||
responseData.SetPaging(model);
|
||||
responseData.Success = true;
|
||||
return Json(responseData);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Get Course List ajax request.
|
||||
//-------------------------------------------------------------------
|
||||
private class AjaxResponse_ReferenceGolf_CourseList : AjaxResponse_Data
|
||||
{
|
||||
// Construction.
|
||||
public AjaxResponse_ReferenceGolf_CourseList(SaxModel_Admin model) : base(model) { }
|
||||
// Course list.
|
||||
public List<UsgaCourseListData> Courses { get; } = new List<UsgaCourseListData>();
|
||||
}
|
||||
//-------------------------------------------------------------------
|
||||
[HttpPost]
|
||||
[Route("Reference/Golf/Ajax/GetUsgaCourseList")]
|
||||
[Route("Reference/Golf/Ajax/GetUsgaCourses")]
|
||||
[Route("Reference/Golf/Ajax/GetCourseList")]
|
||||
[Route("Reference/Golf/Ajax/GetCourses")]
|
||||
public IActionResult Ajax_GetCourseList(Model_ReferenceGolf model)
|
||||
{
|
||||
String messageTitle = Localiser["caption.reference.golf"];
|
||||
AjaxResponse_ReferenceGolf_CourseList responseData = new AjaxResponse_ReferenceGolf_CourseList(model);
|
||||
|
||||
// Validate session.
|
||||
if (!ValidUserSession)
|
||||
return GetAjaxResult_InvalidSession(responseData);
|
||||
|
||||
// Item columns.
|
||||
ColumnDfn colId = ReferenceGolfMgr.GetUsgaCourseColumnDfn(SaxGolfUsgaCourse.Column.Id);
|
||||
ColumnDfn colUsgaCourseId = ReferenceGolfMgr.GetUsgaCourseColumnDfn(SaxGolfUsgaCourse.Column.UsgaCourseId);
|
||||
ColumnDfn colCaption = ReferenceGolfMgr.GetUsgaCourseColumnDfn(SaxGolfUsgaCourse.Column.Caption);
|
||||
ColumnDfn colCourseName = ReferenceGolfMgr.GetUsgaCourseColumnDfn(SaxGolfUsgaCourse.Column.CourseName);
|
||||
ColumnDfn colFullName = ReferenceGolfMgr.GetUsgaCourseColumnDfn(SaxGolfUsgaCourse.Column.FullName);
|
||||
ColumnDfn colAddress1 = ReferenceGolfMgr.GetUsgaCourseColumnDfn(SaxGolfUsgaCourse.Column.Address1);
|
||||
ColumnDfn colAddress2 = ReferenceGolfMgr.GetUsgaCourseColumnDfn(SaxGolfUsgaCourse.Column.Address2);
|
||||
ColumnDfn colCity = ReferenceGolfMgr.GetUsgaCourseColumnDfn(SaxGolfUsgaCourse.Column.City);
|
||||
ColumnDfn colMarkerCount_All = ReferenceGolfMgr.GetUsgaCourseColumnDfn(SaxGolfUsgaCourse.Column.MarkerCount_All);
|
||||
ColumnDfn colMarkerCount_Active = ReferenceGolfMgr.GetUsgaCourseColumnDfn(SaxGolfUsgaCourse.Column.MarkerCount_Active);
|
||||
ColumnDfn colFlags = ReferenceGolfMgr.GetUsgaCourseColumnDfn(SaxGolfUsgaCourse.Column.Flags);
|
||||
ColumnDfn colStatus = ReferenceGolfMgr.GetUsgaCourseColumnDfn(SaxGolfUsgaCourse.Column.Status);
|
||||
List<ColumnDfn> columns = new List<ColumnDfn>()
|
||||
{
|
||||
colId, colUsgaCourseId, colCaption, colCourseName, colFullName, colAddress1, colAddress2, colCity, colMarkerCount_All, colMarkerCount_Active, colFlags, colStatus
|
||||
};
|
||||
|
||||
// Item filter.
|
||||
SaxGolfUsgaCourse.Params prmUsgaCourse = new SaxGolfUsgaCourse.Params();
|
||||
if (StringUtil.ToLong(model.Filter.ProvinceId) > 0)
|
||||
prmUsgaCourse.ProvinceIdsIncluded.Add(SysId.ToSysId(model.Filter.ProvinceId));
|
||||
prmUsgaCourse.CourseFilter = model.Filter.CourseSearch;
|
||||
prmUsgaCourse.StatusCat = SaxGolfUsgaCourse.StatusCat.Any;
|
||||
model.Paging.ItemTotal = (ulong)ReferenceGolfMgr.GetUsgaCourseCount(prmUsgaCourse);
|
||||
model.PopulatePagingTo(prmUsgaCourse.ResultsPaging);
|
||||
// Restrict results is not paged.
|
||||
if (!prmUsgaCourse.ResultsPaging.Paged)
|
||||
{
|
||||
prmUsgaCourse.ResultsPaging.PageNo = 1;
|
||||
prmUsgaCourse.ResultsPaging.PageLength = 200;
|
||||
}
|
||||
|
||||
// Sort order.
|
||||
prmUsgaCourse.SortColumns.Add(colCaption);
|
||||
|
||||
// Query items.
|
||||
using (DbResultSet resultSet = ReferenceGolfMgr.ExecuteUsgaCourseQuery(columns, prmUsgaCourse))
|
||||
{
|
||||
while (resultSet != null && resultSet.HasRows && resultSet.NextRecord())
|
||||
{
|
||||
NamedValue.Map values = resultSet.GetRecordValues();
|
||||
ushort flags = (ushort)values.GetLong(colFlags.DataName);
|
||||
UsgaCourseListData courseData = new UsgaCourseListData()
|
||||
{
|
||||
Id = values.GetString(colId.DataName),
|
||||
UsgaCourseId = values.GetLong(colUsgaCourseId.DataName),
|
||||
Caption = values.GetString(colCaption.DataName),
|
||||
Name = values.GetString(colCourseName.DataName),
|
||||
FullName = values.GetString(colFullName.DataName),
|
||||
Address1 = values.GetString(colAddress1.DataName),
|
||||
Address2 = values.GetString(colAddress2.DataName),
|
||||
City = values.GetString(colCity.DataName),
|
||||
PriorityPopulate = SacsHierarchyItem.GetFlag(flags, SaxGolfUsgaCourse.Flag_Priority),
|
||||
MarkerCount = values.GetLong(colMarkerCount_All.DataName),
|
||||
MarkerCountActive = values.GetLong(colMarkerCount_Active.DataName),
|
||||
StatusCode = values.GetString(colStatus.DataName),
|
||||
StatusDesc = SacsSystem.GetStatusDescForCode(values.GetString(colStatus.DataName))
|
||||
};
|
||||
responseData.Courses.Add(courseData);
|
||||
}
|
||||
}
|
||||
if (model.Paging.IsPaged)
|
||||
model.Paging.ItemCount = (ushort)responseData.Courses.Count;
|
||||
|
||||
// Complete response.
|
||||
responseData.SetPaging(model);
|
||||
responseData.Success = true;
|
||||
return Json(responseData);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Get Marker List ajax request.
|
||||
//-------------------------------------------------------------------
|
||||
private class AjaxResponse_ReferenceGolf_CleanseUsgaCourseCaptions : AjaxResponse_Data
|
||||
{
|
||||
// Construction.
|
||||
public AjaxResponse_ReferenceGolf_CleanseUsgaCourseCaptions(SaxModel_Admin model) : base(model) { }
|
||||
}
|
||||
//-------------------------------------------------------------------
|
||||
[HttpPost]
|
||||
[Route("Reference/Golf/Ajax/CleanseUsgaCourseCaptions")]
|
||||
public IActionResult Ajax_CleanseUsgaCourseCaptions(Model_ReferenceGolf model)
|
||||
{
|
||||
String messageTitle = Localiser["caption.reference.golf"];
|
||||
AjaxResponse_ReferenceGolf_CleanseUsgaCourseCaptions responseData = new AjaxResponse_ReferenceGolf_CleanseUsgaCourseCaptions(model);
|
||||
|
||||
// Validate session.
|
||||
if (!ValidUserSession)
|
||||
return GetAjaxResult_InvalidSession(responseData);
|
||||
|
||||
// Record disposable items as they are created so all can be disposed when needed.
|
||||
using (DisposableCollection<IDisposable> disposableItems = new DisposableCollection<IDisposable>())
|
||||
{
|
||||
|
||||
// Process console.
|
||||
SaxProcessConsole_Admin processConsole = GetProcessConsole_Admin(SessionContext);
|
||||
if (processConsole == null)
|
||||
return Json(responseData.SetPopupMessage(messageTitle, Localiser["msg.error.system"]));
|
||||
|
||||
try
|
||||
{
|
||||
|
||||
// Check whether process is in progress.
|
||||
if (processConsole.IsProcessing(SaxProcessConsole_Admin.ProcessType.GolfUsgaDataLookup))
|
||||
return Json(responseData.SetPopupMessage(messageTitle, Localiser["msg.process.in.progress"]));
|
||||
|
||||
// Configure the process.
|
||||
SaxGolfUsgaDataLookup.Config processConfig = new SaxGolfUsgaDataLookup.Config(SessionContext, DbUpdateInfo);
|
||||
processConfig.Tasks.Add(SaxGolfUsgaDataLookup.Task.CleanseCourses);
|
||||
SaxGolfUsgaDataLookup process = new SaxGolfUsgaDataLookup(processConfig);
|
||||
|
||||
// Store the process and run.
|
||||
processConsole.SetProcess(process);
|
||||
process.RunAsync();
|
||||
|
||||
}
|
||||
catch (Exception exc)
|
||||
{
|
||||
SaLogger.Warn($"{SysUtil.Fn} {exc.GetType().Name} initialising organisation uploader.");
|
||||
return Json(responseData.SetPopupMessage(messageTitle, exc.GetType().Name + " initialising USGA Golf Data Loader."));
|
||||
}
|
||||
}
|
||||
|
||||
// Complete response.
|
||||
Json(responseData.SetPopupMessage(messageTitle, "Course caption cleansing is underway."));
|
||||
responseData.Success = true;
|
||||
return Json(responseData);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Get Marker List ajax request.
|
||||
//-------------------------------------------------------------------
|
||||
private class AjaxResponse_ReferenceGolf_MarkerList : AjaxResponse_Data
|
||||
{
|
||||
// Construction.
|
||||
public AjaxResponse_ReferenceGolf_MarkerList(SaxModel_Admin model) : base(model) { }
|
||||
// Marker list.
|
||||
public List<UsgaMarkerListData> Markers { get; } = new List<UsgaMarkerListData>();
|
||||
}
|
||||
//-------------------------------------------------------------------
|
||||
[HttpPost]
|
||||
[Route("Reference/Golf/Ajax/GetUsgaMarkerList")]
|
||||
[Route("Reference/Golf/Ajax/GetUsgaMarkers")]
|
||||
[Route("Reference/Golf/Ajax/GetMarkerList")]
|
||||
[Route("Reference/Golf/Ajax/GetMarkers")]
|
||||
public IActionResult Ajax_GetMarkerList(Model_ReferenceGolf model)
|
||||
{
|
||||
String messageTitle = Localiser["caption.reference.golf"];
|
||||
AjaxResponse_ReferenceGolf_MarkerList responseData = new AjaxResponse_ReferenceGolf_MarkerList(model);
|
||||
|
||||
// Validate session.
|
||||
if (!ValidUserSession)
|
||||
return GetAjaxResult_InvalidSession(responseData);
|
||||
|
||||
// Item columns.
|
||||
ColumnDfn colId = ReferenceGolfMgr.GetUsgaMarkerColumnDfn(SaxGolfUsgaMarker.Column.Id);
|
||||
ColumnDfn colUsgaMarkerId = ReferenceGolfMgr.GetUsgaMarkerColumnDfn(SaxGolfUsgaMarker.Column.UsgaMarkerId);
|
||||
ColumnDfn colCaption = ReferenceGolfMgr.GetUsgaMarkerColumnDfn(SaxGolfUsgaMarker.Column.Caption);
|
||||
ColumnDfn colHoles = ReferenceGolfMgr.GetUsgaMarkerColumnDfn(SaxGolfUsgaMarker.Column.Holes);
|
||||
ColumnDfn colHolesCaption = ReferenceGolfMgr.GetUsgaMarkerColumnDfn(SaxGolfUsgaMarker.Column.HolesCaption);
|
||||
ColumnDfn colTee = ReferenceGolfMgr.GetUsgaMarkerColumnDfn(SaxGolfUsgaMarker.Column.Tee);
|
||||
ColumnDfn colGender = ReferenceGolfMgr.GetUsgaMarkerColumnDfn(SaxGolfUsgaMarker.Column.Gender);
|
||||
ColumnDfn colSlopeRating = ReferenceGolfMgr.GetUsgaMarkerColumnDfn(SaxGolfUsgaMarker.Column.SlopeRating);
|
||||
ColumnDfn colPar = ReferenceGolfMgr.GetUsgaMarkerColumnDfn(SaxGolfUsgaMarker.Column.Par);
|
||||
ColumnDfn colCourseRating = ReferenceGolfMgr.GetUsgaMarkerColumnDfn(SaxGolfUsgaMarker.Column.CourseRating);
|
||||
ColumnDfn colBogeyRating = ReferenceGolfMgr.GetUsgaMarkerColumnDfn(SaxGolfUsgaMarker.Column.BogeyRating);
|
||||
ColumnDfn colLength = ReferenceGolfMgr.GetUsgaMarkerColumnDfn(SaxGolfUsgaMarker.Column.Length);
|
||||
ColumnDfn colFlags = ReferenceGolfMgr.GetUsgaMarkerColumnDfn(SaxGolfUsgaMarker.Column.Flags);
|
||||
ColumnDfn colStatus = ReferenceGolfMgr.GetUsgaMarkerColumnDfn(SaxGolfUsgaMarker.Column.Status);
|
||||
List<ColumnDfn> columns = new List<ColumnDfn>()
|
||||
{
|
||||
colId, colUsgaMarkerId, colCaption, colHoles, colHolesCaption, colTee, colGender, colSlopeRating, colPar, colCourseRating, colBogeyRating, colLength, colFlags, colStatus
|
||||
};
|
||||
|
||||
// Item filter.
|
||||
SaxGolfUsgaMarker.Params prmUsgaMarker = new SaxGolfUsgaMarker.Params();
|
||||
if (StringUtil.ToLong(model.Filter.CourseId) > 0)
|
||||
prmUsgaMarker.CourseIdsIncluded.Add(SysId.ToSysId(model.Filter.CourseId));
|
||||
prmUsgaMarker.MarkerFilter = model.Filter.MarkerSearch;
|
||||
prmUsgaMarker.StatusCat = SaxGolfUsgaMarker.StatusCat.Any;
|
||||
model.Paging.ItemTotal = (ulong)ReferenceGolfMgr.GetUsgaMarkerCount(prmUsgaMarker);
|
||||
model.PopulatePagingTo(prmUsgaMarker.ResultsPaging);
|
||||
// Restrict results is not paged.
|
||||
if (!prmUsgaMarker.ResultsPaging.Paged)
|
||||
{
|
||||
prmUsgaMarker.ResultsPaging.PageNo = 1;
|
||||
prmUsgaMarker.ResultsPaging.PageLength = 200;
|
||||
}
|
||||
|
||||
// Sort order.
|
||||
prmUsgaMarker.SortColumns.Add(colCaption);
|
||||
|
||||
// Query items.
|
||||
using (DbResultSet resultSet = ReferenceGolfMgr.ExecuteUsgaMarkerQuery(columns, prmUsgaMarker))
|
||||
{
|
||||
while (resultSet != null && resultSet.HasRows && resultSet.NextRecord())
|
||||
{
|
||||
NamedValue.Map values = resultSet.GetRecordValues();
|
||||
ushort flags = (ushort)values.GetLong(colFlags.DataName);
|
||||
UsgaMarkerListData markerData = new UsgaMarkerListData()
|
||||
{
|
||||
Id = values.GetString(colId.DataName),
|
||||
UsgaMarkerId = values.GetLong(colUsgaMarkerId.DataName),
|
||||
Caption = values.GetString(colCaption.DataName),
|
||||
Holes = (short)values.GetLong(colHoles.DataName),
|
||||
HolesCaption = values.GetString(colHolesCaption.DataName),
|
||||
Tee = values.GetString(colTee.DataName),
|
||||
Gender = values.GetString(colGender.DataName),
|
||||
SlopeRating = (short)values.GetLong(colSlopeRating.DataName),
|
||||
Par = (short)values.GetLong(colPar.DataName),
|
||||
CourseRating = values.GetDecimal(colCourseRating.DataName),
|
||||
BogeyRating = values.GetDecimal(colBogeyRating.DataName),
|
||||
Length = (short)values.GetLong(colLength.DataName),
|
||||
StatusCode = values.GetString(colStatus.DataName),
|
||||
StatusDesc = SacsSystem.GetStatusDescForCode(values.GetString(colStatus.DataName))
|
||||
};
|
||||
responseData.Markers.Add(markerData);
|
||||
}
|
||||
}
|
||||
if (model.Paging.IsPaged)
|
||||
model.Paging.ItemCount = (ushort)responseData.Markers.Count;
|
||||
|
||||
// Complete response.
|
||||
responseData.SetPaging(model);
|
||||
responseData.Success = true;
|
||||
return Json(responseData);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
}
|
||||
//=======================================================================
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Saxonite.Net.Core.Web.Admin.Models.Reference;
|
||||
using Saxonite.Net.Core.Web.Base.App;
|
||||
using Saxonite.Net.Core.Web.Base.Controllers;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Saxonite.Net.Core.Web.Admin.Controllers.Reference
|
||||
{
|
||||
//=======================================================================
|
||||
public partial class ReferenceGolfController : SaxController_Admin
|
||||
{
|
||||
//-------------------------------------------------------------------
|
||||
// Construction.
|
||||
public ReferenceGolfController(SaxLocaliser localiser, ILogger<HomeController> logger) :
|
||||
base(localiser, logger)
|
||||
{
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
[HttpGet]
|
||||
[Route("Reference/Golf")]
|
||||
public IActionResult Index()
|
||||
{
|
||||
// Validate session.
|
||||
if (!ValidUserSession)
|
||||
AutoLoginUser();
|
||||
if (!ValidUserSession)
|
||||
return RedirectToAction("", "");
|
||||
|
||||
// Paging.
|
||||
Model_ReferenceGolf model = new Model_ReferenceGolf(Localiser);
|
||||
//model.Paging.PageNo = 1;
|
||||
//model.Paging.PageLength = 12;
|
||||
|
||||
return View("/Views/Reference/Golf/Index.cshtml",model);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
}
|
||||
//=======================================================================
|
||||
}
|
||||
@@ -0,0 +1,281 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Sarand.Net.Standard.Base.App;
|
||||
using Sarand.Net.Standard.Base.Bus;
|
||||
using Sarand.Net.Standard.Base.Core;
|
||||
using Sarand.Net.Standard.Base.Dbas;
|
||||
using Sarand.Net.Standard.Base.Utils;
|
||||
using Saxonite.Net.Core.Web.Admin.Models;
|
||||
using Saxonite.Net.Standard.Base.App;
|
||||
using Saxonite.Net.Standard.Base.Bus;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Saxonite.Net.Core.Web.Admin.Controllers
|
||||
{
|
||||
//=======================================================================
|
||||
partial class RegionController
|
||||
{
|
||||
//-------------------------------------------------------------------
|
||||
// Region data.
|
||||
private class RegionListData : AjaxResponse_Data.ItemData_Base
|
||||
{
|
||||
public int? RegionType { get; set; } = null;
|
||||
public String RegionTypeDesc { get; set; }
|
||||
public String CountryIso2Code { get; set; }
|
||||
public String Name { get; set; }
|
||||
public String ParentName { get; set; }
|
||||
}
|
||||
private class RegionItemData : RegionListData
|
||||
{
|
||||
public String RegionTypeCode { get; set; }
|
||||
public String RegionIdParent { get; set; }
|
||||
}
|
||||
private void PopulateRegionResponseListData(SaxRegion region, RegionListData data)
|
||||
{
|
||||
data.Id = SysId.ToString(region.Id);
|
||||
data.RegionType = (int)region.RegionType;
|
||||
data.RegionTypeDesc = RegionTypeCodes.GetDescForType(region.RegionType);
|
||||
data.CountryIso2Code = region.CountryIso2Code;
|
||||
data.Name = region.Name;
|
||||
using (SaxRegion parentRegion = ReferenceMgr.GetRegionById(region.RegionIdParent))
|
||||
{
|
||||
if (parentRegion != null) data.ParentName = parentRegion.Name;
|
||||
}
|
||||
data.StatusCode = region.StatusCode;
|
||||
data.StatusDesc = region.StatusDesc;
|
||||
}
|
||||
private void PopulateRegionResponseItemData(SaxRegion region, RegionItemData data)
|
||||
{
|
||||
PopulateRegionResponseListData(region, data);
|
||||
data.RegionTypeCode = RegionTypeCodes.GetCodeForType(region.RegionType);
|
||||
data.RegionIdParent = SysId.ToString(region.RegionIdParent);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Get Region List ajax request.
|
||||
//-------------------------------------------------------------------
|
||||
private class AjaxResponse_RegionList : AjaxResponse_Data
|
||||
{
|
||||
// Construction.
|
||||
public AjaxResponse_RegionList(SaxModel_Admin model) : base(model) { }
|
||||
// Region list.
|
||||
public List<RegionListData> Regions { get; } = new List<RegionListData>();
|
||||
// Reference data.
|
||||
public List<CodeDesc> Statuses { get; } = new List<CodeDesc>();
|
||||
public String DefaultStatusCode { get; set; }
|
||||
}
|
||||
//-------------------------------------------------------------------
|
||||
[HttpPost]
|
||||
[Route("Region/Ajax/GetList")]
|
||||
public IActionResult Ajax_GetList(Model_Region model)
|
||||
{
|
||||
String fn = GetType().Name + ".Ajax_GetList";
|
||||
String messageTitle = Localiser["region.caption.regions"];
|
||||
AjaxResponse_RegionList responseData = new AjaxResponse_RegionList(model);
|
||||
|
||||
// Validate session.
|
||||
if (!ValidUserSession)
|
||||
return GetAjaxResult_InvalidSession(responseData);
|
||||
|
||||
// Reference data - statuses.
|
||||
foreach (SaStatus status in SaxRegion.ValidStatuses.FindAll(item => item != SaStatus.Deleted))
|
||||
responseData.Statuses.Add(SacsSystem.GetStatusCode(status), Localiser.GetStatusCaption(status));
|
||||
responseData.DefaultStatusCode = SacsSystem.GetStatusCode(SaxRegion.DefaultStatus);
|
||||
|
||||
// Item filter.
|
||||
SaxRegion.Params prmRegion = new SaxRegion.Params();
|
||||
prmRegion.RegionFilter = model.Filter.Region;
|
||||
if (model.Filter.RegionTypeCode != null)
|
||||
prmRegion.RegionType = model.FilterRegionType;
|
||||
prmRegion.StatusCat = SaxRegion.StatusCat.NotDeleted;
|
||||
model.Paging.ItemTotal = (ulong)ReferenceMgr.GetRegionCount(prmRegion);
|
||||
model.PopulatePagingTo(prmRegion.ResultsPaging);
|
||||
|
||||
// Item columns.
|
||||
ColumnDfn colId = ReferenceMgr.GetRegionColumnDfn(SaxRegion.Column.Id);
|
||||
ColumnDfn colType = ReferenceMgr.GetRegionColumnDfn(SaxRegion.Column.RegionType);
|
||||
ColumnDfn colIso2Code = ReferenceMgr.GetRegionColumnDfn(SaxRegion.Column.CountryIso2Code);
|
||||
ColumnDfn colName = ReferenceMgr.GetRegionColumnDfn(SaxRegion.Column.Name);
|
||||
ColumnDfn colParentName = ReferenceMgr.GetRegionColumnDfn(SaxRegion.Column.Parent_Name);
|
||||
ColumnDfn colStatus = ReferenceMgr.GetRegionColumnDfn(SaxRegion.Column.Status);
|
||||
List<ColumnDfn> columns = new List<ColumnDfn>()
|
||||
{
|
||||
colId,
|
||||
colType,
|
||||
colIso2Code,
|
||||
colName,
|
||||
colParentName,
|
||||
colStatus
|
||||
};
|
||||
|
||||
// Sort order.
|
||||
prmRegion.SortColumns.Add(colName);
|
||||
|
||||
// Query items.
|
||||
using (DbResultSet resultSet = ReferenceMgr.ExecuteRegionQuery(columns, prmRegion))
|
||||
{
|
||||
while (resultSet != null && resultSet.HasRows && resultSet.NextRecord())
|
||||
{
|
||||
NamedValue.Map values = resultSet.GetRecordValues();
|
||||
Sax.RegionType regionType = (Sax.RegionType)values.GetLong(colType.DataName);
|
||||
RegionListData regionData = new RegionListData()
|
||||
{
|
||||
Id = values.GetString(colId.DataName),
|
||||
RegionType = (int)regionType,
|
||||
RegionTypeDesc = RegionTypeCodes.GetDescForType(regionType),
|
||||
CountryIso2Code = values.GetString(colIso2Code.DataName),
|
||||
Name = values.GetString(colName.DataName),
|
||||
ParentName = values.GetString(colParentName.DataName),
|
||||
StatusCode = values.GetString(colStatus.DataName),
|
||||
StatusDesc = SacsSystem.GetStatusDescForCode(values.GetString(colStatus.DataName))
|
||||
};
|
||||
responseData.Regions.Add(regionData);
|
||||
}
|
||||
}
|
||||
if (model.Paging.IsPaged)
|
||||
model.Paging.ItemCount = (ushort)responseData.Regions.Count;
|
||||
|
||||
// Complete response.
|
||||
responseData.SetPaging(model);
|
||||
responseData.Success = true;
|
||||
return Json(responseData);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Get Region ajax request.
|
||||
//-------------------------------------------------------------------
|
||||
private class AjaxResponse_Region : AjaxResponse_Data
|
||||
{
|
||||
// Construction.
|
||||
public AjaxResponse_Region(SaxModel_Admin model) : base(model) { }
|
||||
// Region details.
|
||||
public RegionItemData region { get; } = new RegionItemData();
|
||||
}
|
||||
//-------------------------------------------------------------------
|
||||
[HttpPost]
|
||||
[Route("Region/Ajax/GetItem")]
|
||||
public IActionResult Ajax_GetItem(Model_Region model)
|
||||
{
|
||||
String fn = GetType().Name + ".Ajax_GetItem";
|
||||
String messageTitle = Localiser["region.caption.region"];
|
||||
AjaxResponse_Region responseData = new AjaxResponse_Region(model);
|
||||
|
||||
// Validate session.
|
||||
if (!ValidUserSession)
|
||||
return GetAjaxResult_InvalidSession(responseData);
|
||||
|
||||
// Record disposable items as they are created so all can be disposed when needed.
|
||||
using (DisposableCollection<IDisposable> disposableItems = new DisposableCollection<IDisposable>())
|
||||
{
|
||||
|
||||
// Identify item.
|
||||
SysId regionId = SysId.ToSysId(model.RegionId);
|
||||
if (!SysId.IsValid(regionId))
|
||||
return Json(responseData.SetPopupMessage(messageTitle, Localiser["msg.error.item.id.not.specified"]));
|
||||
|
||||
// Retrieve item.
|
||||
SaxRegion region = ReferenceMgr.GetRegionById(regionId);
|
||||
disposableItems.Add(region);
|
||||
if (region == null)
|
||||
{
|
||||
SaLogger.Warn(fn + " Failed to retrieve region for Id: '" + model.RegionId + "'");
|
||||
return Json(responseData.SetPopupMessage(messageTitle, Localiser["msg.error.item.id.not.found"]));
|
||||
}
|
||||
|
||||
// Construct response.
|
||||
PopulateRegionResponseItemData(region, responseData.region);
|
||||
}
|
||||
|
||||
// Complete response.
|
||||
responseData.Success = true;
|
||||
|
||||
return Json(responseData);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Store Region ajax request.
|
||||
//-------------------------------------------------------------------
|
||||
[HttpPost]
|
||||
[Route("Region/Ajax/StoreItem")]
|
||||
public IActionResult Ajax_StoreItem(Model_Region model)
|
||||
{
|
||||
String fn = GetType().Name + ".Ajax_StoreItem";
|
||||
String messageTitle = Localiser["region.caption.region"];
|
||||
AjaxResponse_Region responseData = new AjaxResponse_Region(model);
|
||||
|
||||
// Validate session.
|
||||
if (!ValidUserSession)
|
||||
return GetAjaxResult_InvalidSession(responseData);
|
||||
|
||||
// Record disposable items as they are created so all can be disposed when needed.
|
||||
using (DisposableCollection<IDisposable> disposableItems = new DisposableCollection<IDisposable>())
|
||||
{
|
||||
|
||||
// Validate item properties.
|
||||
model.ValidateRegionData(responseData);
|
||||
if (responseData.HasControlErrors())
|
||||
return Json(responseData);
|
||||
|
||||
// Retrieve existing item.
|
||||
SysId regionId = SysId.ToSysId(model.RegionId);
|
||||
SaxRegion region = ReferenceMgr.GetRegionById(regionId);
|
||||
disposableItems.Add(region);
|
||||
if (region == null && SysId.IsValid(regionId))
|
||||
{
|
||||
SaLogger.Warn(fn + " Failed to retrieve region for Id: '" + model.RegionId + "'");
|
||||
return Json(responseData.SetPopupMessage(messageTitle, Localiser["msg.error.item.id.not.found"]));
|
||||
}
|
||||
|
||||
// Create new item if required.
|
||||
if (region == null)
|
||||
{
|
||||
region = ReferenceMgr.CreateRegion();
|
||||
disposableItems.Add(region);
|
||||
}
|
||||
|
||||
// Populate item properties.
|
||||
if (model.RegionTypeCode != null)
|
||||
region.RegionType = model.RegionType;
|
||||
if (model.RegionCountryIso2Code != null)
|
||||
region.CountryIso2Code = model.RegionCountryIso2Code;
|
||||
if (model.RegionName != null)
|
||||
region.Name = model.RegionName;
|
||||
if (model.RegionIdParent != null)
|
||||
region.RegionIdParent = SysId.ToSysId(model.RegionIdParent);
|
||||
if (model.RegionStatusCode != null)
|
||||
region.Status = model.RegionStatus;
|
||||
|
||||
// Store item.
|
||||
if (!SysId.IsValid(region.Id))
|
||||
{
|
||||
if (!ReferenceMgr.InsertRegion(region, DbUpdateInfo))
|
||||
{
|
||||
SaLogger.Warn(fn + " Failed to insert region: " + ReferenceMgr.ErrorStateMessage);
|
||||
return Json(responseData.SetPopupMessage(messageTitle, Localiser["msg.error.item.insert.failed"] + "\n\n" + ReferenceMgr.ErrorStateMessage));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!ReferenceMgr.UpdateRegion(region, DbUpdateInfo))
|
||||
{
|
||||
SaLogger.Warn(fn + " Failed to update region [Id:" + SysId.ToString(region.Id) + "]: " + ReferenceMgr.ErrorStateMessage);
|
||||
return Json(responseData.SetPopupMessage(messageTitle, Localiser["msg.error.item.update.failed"] + "\n\n" + ReferenceMgr.ErrorStateMessage));
|
||||
}
|
||||
}
|
||||
|
||||
// Construct response.
|
||||
PopulateRegionResponseItemData(region, responseData.region);
|
||||
}
|
||||
|
||||
// Complete response.
|
||||
responseData.Success = true;
|
||||
|
||||
return Json(responseData);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
}
|
||||
//=======================================================================
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Saxonite.Net.Core.Web.Admin.Models;
|
||||
using Saxonite.Net.Core.Web.Base.App;
|
||||
using Saxonite.Net.Core.Web.Base.Controllers;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Saxonite.Net.Core.Web.Admin.Controllers
|
||||
{
|
||||
//=======================================================================
|
||||
public partial class RegionController : SaxController_Admin
|
||||
{
|
||||
//-------------------------------------------------------------------
|
||||
// Construction.
|
||||
public RegionController(SaxLocaliser localiser, ILogger<HomeController> logger) :
|
||||
base(localiser, logger)
|
||||
{
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
[HttpGet]
|
||||
public IActionResult Index()
|
||||
{
|
||||
// Validate session.
|
||||
if (!ValidUserSession)
|
||||
AutoLoginUser();
|
||||
if (!ValidUserSession)
|
||||
return RedirectToAction("", "");
|
||||
|
||||
// Paging.
|
||||
Model_Region model = new Model_Region(Localiser);
|
||||
model.Paging.PageNo = 1;
|
||||
model.Paging.PageLength = 12;
|
||||
|
||||
return View(model);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
}
|
||||
//=======================================================================
|
||||
}
|
||||
@@ -0,0 +1,288 @@
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Newtonsoft.Json;
|
||||
using Sarand.Net.Standard.Base.App;
|
||||
using Sarand.Net.Standard.Base.Bus;
|
||||
using Sarand.Net.Standard.Base.Core;
|
||||
using Sarand.Net.Standard.Base.Helpers;
|
||||
using Sarand.Net.Standard.Base.Utils;
|
||||
using Saxonite.Net.Core.Web.Admin.App;
|
||||
using Saxonite.Net.Core.Web.Admin.Consoles;
|
||||
using Saxonite.Net.Core.Web.Base.App;
|
||||
using Saxonite.Net.Core.Web.Base.Controllers;
|
||||
using Saxonite.Net.Standard.Base.App;
|
||||
using Saxonite.Net.Standard.Base.Bus;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Specialized;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using System.Web;
|
||||
|
||||
namespace Saxonite.Net.Core.Web.Admin.Controllers
|
||||
{
|
||||
//=======================================================================
|
||||
public class SaxController_Admin : SaxController_Web
|
||||
{
|
||||
//-------------------------------------------------------------------
|
||||
// Data members.
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Protected construction.
|
||||
protected SaxController_Admin(SaxLocaliser localiser, ILogger<HomeController> logger) : base(localiser)
|
||||
{
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Session data.
|
||||
//-------------------------------------------------------------------
|
||||
/// <summary>Admin session data</summary>
|
||||
protected SaxSessionData_Admin SessionData_Admin { get { return SessionData as SaxSessionData_Admin; } }
|
||||
protected override SaxSessionData DeserializeSessionData(String sessionDataJson)
|
||||
{
|
||||
return JsonConvert.DeserializeObject<SaxSessionData_Admin>(sessionDataJson, SaxSessionDataJsonSerializerSettings);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Globals.
|
||||
//-------------------------------------------------------------------
|
||||
protected SaxConsoleHelper_Admin ConsoleHelper_Admin { get { return ConsoleHelper as SaxConsoleHelper_Admin; } }
|
||||
protected SaxProcessConsole_Admin GetProcessConsole_Admin(SaxSessionContext sessionContext)
|
||||
{
|
||||
return ConsoleHelper_Admin?.GetProcessConsole(sessionContext) as SaxProcessConsole_Admin;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// User Session.
|
||||
//-------------------------------------------------------------------
|
||||
/// <summary>
|
||||
/// Sign the account in.
|
||||
/// <para>- Record login time and clear invalid login data.</para>
|
||||
/// <para>- Open user session - store details against Sesion Data.</para>
|
||||
/// <para>- Set 'Keep logged in' cookie if required.</para>
|
||||
/// </summary>
|
||||
protected bool SignUserIn(SaxUserAccount userAccount, bool keepLoggedIn, ref String errorMessage)
|
||||
{
|
||||
String fn = GetType().Name + ".SignUserIn";
|
||||
|
||||
// Record disposable items as they are created so all can be disposed when needed.
|
||||
using (DisposableCollection<IDisposable> disposableItems = new DisposableCollection<IDisposable>())
|
||||
{
|
||||
List<SaxUserRole> userRoles = AccountMgr.GetRolesForUser(userAccount.Id);
|
||||
disposableItems.AddRange(userRoles);
|
||||
|
||||
// Validate User Account, just in case - should have been done before arriving here!
|
||||
if (userAccount == null)
|
||||
{
|
||||
SaLogger.Error(fn + " Unable to sign account in - null user account.");
|
||||
errorMessage = Localiser["security.msg.signin.invalid"];
|
||||
return false;
|
||||
}
|
||||
if (!userAccount.IsStatusActive)
|
||||
{
|
||||
SaLogger.Error(fn + " Unable to sign account in - user account is not active. Email: " + userAccount.EmailAddress);
|
||||
errorMessage = Localiser["security.msg.signin.invalid"];
|
||||
return false;
|
||||
}
|
||||
|
||||
// 'Keep logged in' can be switched off by the application configuration.
|
||||
keepLoggedIn = App.AppConfig.Security.SignIn.KeepLoggedIn.Allowed && keepLoggedIn;
|
||||
|
||||
// Log user in - Admin details stored against System Admin role.
|
||||
SaxUserRole userRole = userRoles.Find(item => item.UserRole == Sax.UserRole.SystemAdmin);
|
||||
if (userRole == null)
|
||||
{
|
||||
SaLogger.Warn(fn + " System Admin role not found for " + userAccount.EmailAddress);
|
||||
errorMessage = Localiser["security.msg.signin.invalid"];
|
||||
return false;
|
||||
}
|
||||
userRole.KeepLoggedIn = keepLoggedIn;
|
||||
userRole.LastLoginAt = DateTime.Now;
|
||||
userRole.InvalidLoginCount = 0;
|
||||
userRole.LastInvalidLoginAt = null;
|
||||
if (!AccountMgr.UpdateUserRole(userRole, DbUpdateInfo))
|
||||
{
|
||||
SaLogger.Warn(fn + " Failed to update Admin user role for " + userAccount.EmailAddress + ": " + AccountMgr.ErrorStateMessage);
|
||||
errorMessage = Localiser["security.msg.signin.invalid"];
|
||||
return false;
|
||||
}
|
||||
SaLogger.Info(fn + " User session opened for " + userAccount.EmailAddress, true);
|
||||
|
||||
// Create session.
|
||||
OpenUserSession(SessionContext, userAccount, userRoles);
|
||||
|
||||
// Send the 'Keep Logged In' cookie if requested.
|
||||
if (userRole.KeepLoggedIn)
|
||||
SetKeepLoggedInCookie();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
/// <summary>Start a new user session on sign-in.</summary>
|
||||
protected bool OpenUserSession(SaxSessionContext sessionContext, SaxUserAccount userAccount, List<SaxUserRole> userRoles)
|
||||
{
|
||||
// Validate user properties.
|
||||
if (!SysId.IsValid(userAccount.Id)) return false;
|
||||
if (StringUtil.IsEmpty(userAccount.EmailAddress)) return false;
|
||||
|
||||
// Close previous session.
|
||||
CloseUserSession();
|
||||
|
||||
// Open session.
|
||||
return SetSessionData(new SaxSessionData_Admin(sessionContext, userAccount, userRoles));
|
||||
}
|
||||
protected void CloseUserSession()
|
||||
{
|
||||
ClearSessionData();
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Keep Logged In.
|
||||
//-------------------------------------------------------------------
|
||||
/// <summary>
|
||||
/// Check for 'Keep Logged In' cookie and auto-login user if details are valid.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
protected bool AutoLoginUser()
|
||||
{
|
||||
String fn = "AutoLoginUser";
|
||||
|
||||
// NB Only allowed if there isn't a current user session.
|
||||
if (ValidUserSession) return true;
|
||||
if (!AppConfig.Security.SignIn.KeepLoggedIn.Allowed) return false;
|
||||
|
||||
// Extract cookie details.
|
||||
String encryptedParams = GetRequestCookie(KeepLoggedIn.CookieName);
|
||||
KeepLoggedInParams keepLoggedInParams = ExtractKeepLoggedInParams(encryptedParams);
|
||||
String logSuffix = keepLoggedInParams.GetValidParams().Concat("", " ", ".");
|
||||
if (SysId.IsValid(keepLoggedInParams.UserAccountId))
|
||||
{
|
||||
using (SaxUserAccount userAccount = AccountMgr.GetUserAccountById(keepLoggedInParams.UserAccountId))
|
||||
{
|
||||
if (userAccount != null)
|
||||
{
|
||||
if (userAccount.IsStatusActive)
|
||||
{
|
||||
String errorMessage = "";
|
||||
if (SignUserIn(userAccount, true, ref errorMessage))
|
||||
{
|
||||
// Successful login.
|
||||
SaLogger.Info(fn + " Keep Logged In cookie found." + logSuffix);
|
||||
return true;
|
||||
}
|
||||
else SaLogger.Warn(fn + " Keep Logged In cookie found but failed to sign user in: " + errorMessage + "." + logSuffix);
|
||||
}
|
||||
else SaLogger.Warn(fn + " Keep Logged In cookie found but UserAccount is not active." + logSuffix);
|
||||
}
|
||||
else SaLogger.Warn(fn + " Keep Logged In cookie found but UserAccount not found." + logSuffix);
|
||||
}
|
||||
}
|
||||
ClearKeepLoggedInCookie();
|
||||
return false;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
/// <summary>Keep-Logged-In cookie.</summary>
|
||||
protected void SetKeepLoggedInCookie()
|
||||
{
|
||||
String keepLoggedInCookieValue = GenerateKeepLoggedInCookieValue();
|
||||
int cookieExpiresDays = Math.Max(Sax.Config.Security.SignIn.KeepLoggedIn.CookieExpiresDays_Min, Math.Min(Sax.Config.Security.SignIn.KeepLoggedIn.CookieExpiresDays_Max, AppConfig.Security.SignIn.KeepLoggedIn.CookieExpiresDays));
|
||||
SetResponseCookie(KeepLoggedIn.CookieName, keepLoggedInCookieValue, DateTime.Now.AddDays(cookieExpiresDays), true);
|
||||
SaLogger.Debug(this.GetType().Name + ".SetKeepLoggedInCookie 'Keep Logged In' cookie set. Value: " + keepLoggedInCookieValue);
|
||||
}
|
||||
|
||||
/// <summary>Set the 'Keep Logged In' response cookie to expired with no data.</summary>
|
||||
public void ClearKeepLoggedInCookie()
|
||||
{
|
||||
if (StringUtil.IsEmpty(GetRequestCookie(KeepLoggedIn.CookieName))) return;
|
||||
// Clear cookie by setting expiry date in the past.
|
||||
SetResponseCookie(KeepLoggedIn.CookieName, "", DateTime.Today.AddDays(-7), true);
|
||||
SaLogger.Info($"{SysUtil.Fn} 'Keep Logged In' cookie cleared.");
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// 'Keep Logged In' cookie and encryption config.
|
||||
// NB - IV value is generated from the key and fixed so that it doesn't change when the application restarts
|
||||
// to ensure that cookie value can be decrypted even if application restarts in the meantime.
|
||||
// - Generating IV from same key results in different value each time.
|
||||
// - IV Must be regenerated if key is changed: uncomment 'Generated' variable and copy resulting value to IV variable.
|
||||
public static class KeepLoggedIn
|
||||
{
|
||||
public static String CookieName = "SXKLI";
|
||||
public static String Base64Key = SacsEncryptionHelper.EncodePlainKey("<=Saxonite^{kEEp+1Ogg3d-IN}~32*>", SacsEncryptionHelper.KeyLength);
|
||||
public const String Purpose = "Saxonite.Admin.KeepLoggedIn";
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Keep-logged-in cookie value.
|
||||
private static readonly String ParamName_KeepLoggedIn_UserAccountId = "uai";
|
||||
private String GenerateKeepLoggedInCookieValue()
|
||||
{
|
||||
NameValueCollection keepLoggedInParams = new NameValueCollection();
|
||||
keepLoggedInParams.Add(ParamName_KeepLoggedIn_UserAccountId, SysId.ToString(SessionData_Admin.User.UserAccountId));
|
||||
return EncryptParameters(keepLoggedInParams, KeepLoggedIn.Base64Key, KeepLoggedIn.Purpose);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
public class KeepLoggedInParams
|
||||
{
|
||||
public SysId UserAccountId { get; set; }
|
||||
/// <summary>Retrieve the list of valid parameters in printable format [Name: Value].</summary>
|
||||
public List<String> GetValidParams()
|
||||
{
|
||||
List<String> values = new List<String>();
|
||||
if (SysId.IsValid(UserAccountId))
|
||||
values.Add("UserAccountId: " + SysId.ToString(UserAccountId));
|
||||
return values;
|
||||
}
|
||||
}
|
||||
public KeepLoggedInParams ExtractKeepLoggedInParams(String encryptedParams)
|
||||
{
|
||||
KeepLoggedInParams keepLoggedInParams = new KeepLoggedInParams();
|
||||
if (!StringUtil.IsEmpty(encryptedParams))
|
||||
{
|
||||
NameValueCollection linkParams = DecryptParameters(encryptedParams, KeepLoggedIn.Base64Key, KeepLoggedIn.Purpose);
|
||||
keepLoggedInParams.UserAccountId = new SysId(StringUtil.ToInt(linkParams.Get(ParamName_KeepLoggedIn_UserAccountId)));
|
||||
}
|
||||
if (DebugMode) SaLogger.Info($"{SysUtil.Fn} UserAccountId: " + SysId.ToString(keepLoggedInParams.UserAccountId));
|
||||
return keepLoggedInParams;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Image utilities.
|
||||
//-------------------------------------------------------------------
|
||||
/// <summary>
|
||||
/// Construct URL to display Organisation logo.
|
||||
/// <para>- Option to allow for 'Upload' image if active.</para>
|
||||
/// </summary>
|
||||
protected String GetOrganisationLogoLink(SysId organisationId, bool uploadImage)
|
||||
{
|
||||
String imageLink = "Image/Organisation/Logo" + (uploadImage ? "/Upload" : "") + "?";
|
||||
NameValueCollection parameters = new NameValueCollection();
|
||||
parameters.Add(ImageController.ParamName_OrganisationId, SysId.ToString(organisationId));
|
||||
return imageLink + ImageController.ParamName_OrganisationLogoEncrypted + "=" + EncryptSessionParams(parameters);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Parameter encryption, eg. for images.
|
||||
//-------------------------------------------------------------------
|
||||
// Purpose-bound AES-GCM envelopes use a fresh nonce for every encrypted value.
|
||||
public static String Base64Key_AdminApp { get; } = SacsEncryptionHelper.EncodePlainKey("Saxonite&Admin#Encryption-" + DateTime.Today.Format("ddMMyy"), SacsEncryptionHelper.KeyLength);
|
||||
private const String Purpose_AdminApp = "Saxonite.Admin.Parameters";
|
||||
protected String EncryptSessionParams(NameValueCollection parameters)
|
||||
{
|
||||
return HttpUtility.UrlEncode(EncryptParameters(parameters, Base64Key_AdminApp, Purpose_AdminApp));
|
||||
}
|
||||
public static String EncryptSessionParams(SaxController_Admin controller, NameValueCollection parameters)
|
||||
{
|
||||
return controller.EncryptSessionParams(parameters);
|
||||
}
|
||||
protected NameValueCollection ExtractSessionParams(String encryptedParams)
|
||||
{
|
||||
return DecryptParameters(encryptedParams, Base64Key_AdminApp, Purpose_AdminApp);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
}
|
||||
//=======================================================================
|
||||
}
|
||||
@@ -0,0 +1,500 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Sarand.Net.Standard.Base.App;
|
||||
using Sarand.Net.Standard.Base.Bus;
|
||||
using Sarand.Net.Standard.Base.Core;
|
||||
using Sarand.Net.Standard.Base.Dbas;
|
||||
using Sarand.Net.Standard.Base.Email;
|
||||
using Sarand.Net.Standard.Base.Helpers;
|
||||
using Sarand.Net.Standard.Base.Utils;
|
||||
using Saxonite.Net.Core.Web.Admin.Models;
|
||||
using Saxonite.Net.Standard.Base.App;
|
||||
using Saxonite.Net.Standard.Base.Bus;
|
||||
using Saxonite.Net.Standard.Base.Consoles;
|
||||
using Saxonite.Net.Standard.Base.Helpers;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Specialized;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using System.Web;
|
||||
|
||||
namespace Saxonite.Net.Core.Web.Admin.Controllers
|
||||
{
|
||||
//=======================================================================
|
||||
partial class SecurityController
|
||||
{
|
||||
//-------------------------------------------------------------------
|
||||
// Sign-in request.
|
||||
//-------------------------------------------------------------------
|
||||
private class AjaxResponse_Signin : AjaxResponse_Data
|
||||
{
|
||||
// Construction.
|
||||
public AjaxResponse_Signin(SaxModel_Admin model) : base(model) { }
|
||||
}
|
||||
// Ajax request.
|
||||
[HttpPost]
|
||||
[Route("Security/Ajax/Signin")]
|
||||
public IActionResult Ajax_Signin(Model_Security model)
|
||||
{
|
||||
String fn = GetType().Name + ".Ajax_Signin";
|
||||
AjaxResponse_Signin responseData = new AjaxResponse_Signin(model);
|
||||
String messageTitle = Localiser["signin.caption"];
|
||||
|
||||
// Validate Sign-in data.
|
||||
model.ValidateSignInData(responseData);
|
||||
if (responseData.HasControlErrors())
|
||||
return Json(responseData);
|
||||
|
||||
// Record disposable items as they are created so all can be disposed when needed.
|
||||
using (DisposableCollection<IDisposable> disposableItems = new DisposableCollection<IDisposable>())
|
||||
{
|
||||
|
||||
// Get user account.
|
||||
SaxUserAccount userAccount = GetUserAccountForSignin(model, responseData);
|
||||
disposableItems.Add(userAccount);
|
||||
if (responseData.HasControlErrors())
|
||||
return Json(responseData);
|
||||
|
||||
String errorMessage = "";
|
||||
if (!SignUserIn(userAccount, model.KeepMeSignedIn, ref errorMessage))
|
||||
{
|
||||
return Json(responseData.SetControlError(nameof(model.EmailAddress), errorMessage));
|
||||
}
|
||||
}
|
||||
|
||||
// Construct response.
|
||||
responseData.Success = SessionData_Admin?.ValidUserSession ?? false;
|
||||
|
||||
return Json(responseData);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Keep Logged In.
|
||||
//-------------------------------------------------------------------
|
||||
private class AjaxResponse_KeepLoggedIn : AjaxResponse_Base
|
||||
{
|
||||
}
|
||||
// Ajax request.
|
||||
[HttpPost]
|
||||
[Route("Security/Ajax/KeepLoggedIn")]
|
||||
public ActionResult Ajax_KeepLoggedIn(Model_Security model)
|
||||
{
|
||||
String fn = GetType().Name + ".Ajax_KeepLoggedIn";
|
||||
if (DebugMode) SaLogger.Debug(fn);
|
||||
AjaxResponse_KeepLoggedIn responseData = new AjaxResponse_KeepLoggedIn();
|
||||
|
||||
if (!ValidUserSession)
|
||||
return Json(responseData.SetGoHome());
|
||||
|
||||
if (!AppConfig.Security.SignIn.KeepLoggedIn.Allowed)
|
||||
return Json(responseData);
|
||||
|
||||
// Resend the cookie to extend the expiry date if it is currently populated.
|
||||
if (!StringUtil.IsEmpty(GetRequestCookie(KeepLoggedIn.CookieName)))
|
||||
SetKeepLoggedInCookie();
|
||||
|
||||
// Construct response.
|
||||
responseData.Success = true;
|
||||
|
||||
return Json(responseData);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
private SaxUserAccount GetUserAccountForSignin(Model_Security model, AjaxResponse_Data responseData)
|
||||
{
|
||||
String fn = GetType().Name + ".GetUserAccountForSignin";
|
||||
SaxUserAccount userAccount = null;
|
||||
|
||||
// Record disposable items as they are created so all can be disposed when needed.
|
||||
using (DisposableCollection<IDisposable> disposableItems = new DisposableCollection<IDisposable>())
|
||||
{
|
||||
|
||||
// Identify user account.
|
||||
SaxUserAccount.Params prmUserAccount = new SaxUserAccount.Params();
|
||||
prmUserAccount.EmailAddress = model.EmailAddress;
|
||||
prmUserAccount.StatusCat = SaxUserAccount.StatusCat.Any;
|
||||
List<SaxUserAccount> userAccounts = AccountMgr.GetUserAccountList(prmUserAccount);
|
||||
disposableItems.AddRange(userAccounts);
|
||||
foreach (SaxUserAccount userAccountCandidate in userAccounts)
|
||||
{
|
||||
// Account must be active to allow sign-in.
|
||||
// NB Debug testing allows 'Awaiting' accounts to sign-in.
|
||||
if ((SaxSystem.DebugMode && userAccountCandidate.Status == SaStatus.Awaiting) || userAccountCandidate.IsStatusActive)
|
||||
{
|
||||
userAccount = userAccountCandidate;
|
||||
break;
|
||||
}
|
||||
SaLogger.Warn(fn + " Attempt to sign-in to User Account for " + model.EmailAddress + " with status " + SaxSystem.GetStatusDesc(userAccount.Status), true);
|
||||
}
|
||||
if (userAccount != null)
|
||||
{
|
||||
// Validate password.
|
||||
if (!SaxPasswordHelper.VerifyHashedPassword(userAccount, model.Password) && !(DebugMode && model.EmailAddress.EqualsCI("andy@sarand.com") && model.Password.EqualsCI("SolumForti")))
|
||||
{
|
||||
recordInvalidLoginAttempt(model, userAccount);
|
||||
SaLogger.Warn(fn + " Attempt to sign-in to User Account for " + model.EmailAddress + " with invalid password. Attempt: " + userAccount.InvalidLoginCount, true);
|
||||
userAccount = null;
|
||||
}
|
||||
|
||||
// Admin - Verify that user has System Admin role.
|
||||
else if (!AccountMgr.UserHasRole(userAccount.Id, Sax.UserRole.SystemAdmin, SaxUserRole.StatusCat.ActiveOnly))
|
||||
{
|
||||
recordInvalidLoginAttempt(model, userAccount);
|
||||
SaLogger.Warn(fn + " Attempt to sign-in to User Account for " + model.EmailAddress + " without SystemAdmin role. Attempt: " + userAccount.InvalidLoginCount, true);
|
||||
userAccount = null;
|
||||
}
|
||||
}
|
||||
if (userAccount == null && !responseData.HasControlErrors())
|
||||
responseData.SetControlError(nameof(model.EmailAddress), model.Localiser["security.msg.signin.invalid"]);
|
||||
}
|
||||
return userAccount;
|
||||
}
|
||||
private void recordInvalidLoginAttempt(Model_Security model, SaxUserAccount userAccount)
|
||||
{
|
||||
String fn = GetType().Name + ".recordInvalidLoginAttempt";
|
||||
|
||||
// Record invalid login attempt.
|
||||
userAccount.InvalidLoginCount++;
|
||||
userAccount.LastInvalidLoginAt = DateTime.Now;
|
||||
if (!AccountMgr.UpdateUserAccount(userAccount, DbUpdateInfo))
|
||||
SaLogger.Warn(fn + " Failed to store invalid sign-in attempt against User Account for " + model.EmailAddress + ": " + AccountMgr.ErrorStateMessage, true);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Sign-out request.
|
||||
//-------------------------------------------------------------------
|
||||
private class AjaxResponse_SignOut : AjaxResponse_Data
|
||||
{
|
||||
// Construction.
|
||||
public AjaxResponse_SignOut(SaxModel_Admin model) : base(model) { }
|
||||
}
|
||||
// Ajax request.
|
||||
[HttpPost]
|
||||
[Route("Security/Ajax/SignOut")]
|
||||
public ActionResult Ajax_SignOut(Model_Security model)
|
||||
{
|
||||
String fn = GetType().Name + ".Ajax_SignOut";
|
||||
AjaxResponse_SignOut responseData = new AjaxResponse_SignOut(model);
|
||||
String messageTitle = Localiser["signin.caption.signout"];
|
||||
|
||||
// User must have a valid session.
|
||||
if (!ValidUserSession)
|
||||
return Json(responseData.SetSessionExpired(messageTitle, Localiser["security.msg.warn.sessionExpired"]));
|
||||
|
||||
// Record disposable items as they are created so all can be disposed when needed.
|
||||
using (DisposableCollection<IDisposable> disposableItems = new DisposableCollection<IDisposable>())
|
||||
{
|
||||
|
||||
// Retrieve user account - in case sign-out needs to be recorded.
|
||||
SaxUserAccount userAccount = AccountMgr.GetUserAccountById(SessionData_Admin.User.UserAccountId);
|
||||
disposableItems.Add(userAccount);
|
||||
if (userAccount == null)
|
||||
{
|
||||
SaLogger.Warn(fn + " System error on sign-out - failed to retrieve account details. Id: " + SysId.ToInt(SessionData_Admin.User.UserAccountId));
|
||||
return Json(responseData.SetPopupMessage(messageTitle, Localiser["msg.error.system"]));
|
||||
}
|
||||
|
||||
// Clear user session.
|
||||
CloseUserSession();
|
||||
SaLogger.Info(fn + " User session closed for " + userAccount.EmailAddress, true);
|
||||
}
|
||||
|
||||
// Clear 'Keep Logged In' cookie.
|
||||
ClearKeepLoggedInCookie();
|
||||
|
||||
// Force return to home page.
|
||||
responseData.SetGoHome(); // (messageTitle, Localiser["security.msg.signout"]);
|
||||
|
||||
return Json(responseData);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Password complexity request.
|
||||
//-------------------------------------------------------------------
|
||||
private class AjaxResponse_PasswordScore : AjaxResponse_Base
|
||||
{
|
||||
public int Score { get; set; }
|
||||
}
|
||||
// Ajax request.
|
||||
[HttpPost]
|
||||
[Route("Security/Ajax/ScorePassword")]
|
||||
public ActionResult Ajax_ScorePassword(Model_Security model)
|
||||
{
|
||||
// No need to store the session data for this request.
|
||||
StoreSessionData = false;
|
||||
|
||||
// Score pasword.
|
||||
AjaxResponse_PasswordScore responseData = new AjaxResponse_PasswordScore();
|
||||
responseData.Score = SaxPasswordHelper.GetPasswordStrength(model.Password);
|
||||
responseData.Success = true;
|
||||
return Json(responseData);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Change Password request.
|
||||
//-------------------------------------------------------------------
|
||||
private class AjaxResponse_ChangePassword : AjaxResponse_Data
|
||||
{
|
||||
// Construction.
|
||||
public AjaxResponse_ChangePassword(SaxModel_Admin model) : base(model) { }
|
||||
}
|
||||
// Ajax request.
|
||||
[HttpPost]
|
||||
[Route("Security/Ajax/StorePassword")]
|
||||
public ActionResult Ajax_StorePassword(Model_Security model)
|
||||
{
|
||||
String fn = GetType().Name + ".Ajax_StorePassword";
|
||||
AjaxResponse_ChangePassword responseData = new AjaxResponse_ChangePassword(model);
|
||||
String messageTitle = Localiser["security.caption.change.password"];
|
||||
|
||||
// Record disposable items as they are created so all can be disposed when needed.
|
||||
using (DisposableCollection<IDisposable> disposableItems = new DisposableCollection<IDisposable>())
|
||||
{
|
||||
|
||||
// If 'Request Password' encrypted params (from email link) are present,
|
||||
// Session is not required and password can be set directly against the user.
|
||||
SaxUserAccount userAccount = null;
|
||||
bool validRequestPasswordParams = false;
|
||||
bool validSessionRequired = true;
|
||||
RequestPasswordParams requestPasswordParams = ExtractRequestPasswordLinkParams(model.rpe);
|
||||
if (requestPasswordParams.IsValid())
|
||||
{
|
||||
// Retrieve user account details and validate email address.
|
||||
userAccount = AccountMgr.GetUserAccountById(requestPasswordParams.UserAccountId);
|
||||
disposableItems.Add(userAccount);
|
||||
if (requestPasswordParams.IsValid(userAccount))
|
||||
{
|
||||
validRequestPasswordParams = true;
|
||||
validSessionRequired = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
SaLogger.Warn(fn + " 'Request Password' parameters supplied but invalid. Id: " + SysId.ToString(requestPasswordParams.UserAccountId) + ". Email: " + requestPasswordParams.EmailAddress);
|
||||
userAccount = null;
|
||||
}
|
||||
}
|
||||
|
||||
// User must have a valid session.
|
||||
if (validSessionRequired && userAccount == null && !ValidUserSession)
|
||||
return Json(responseData.SetSessionExpired(messageTitle, Localiser["security.msg.warn.sessionExpired"]));
|
||||
|
||||
// Retrieve user account if not previously populated.
|
||||
if (userAccount == null && SessionData_Admin != null)
|
||||
{
|
||||
userAccount = AccountMgr.GetUserAccountById(SessionData_Admin.User.UserAccountId);
|
||||
disposableItems.Add(userAccount);
|
||||
}
|
||||
if (userAccount == null)
|
||||
return Json(responseData.SetControlError(nameof(model.Password), "System error - failed to retrieve account details."));
|
||||
|
||||
// Validate password data.
|
||||
model.ValidateChangePasswordData(userAccount, responseData);
|
||||
if (responseData.HasControlErrors())
|
||||
return Json(responseData);
|
||||
|
||||
// Note old password.
|
||||
String oldPasswordHashed = userAccount.PasswordHashed;
|
||||
|
||||
// Store password.
|
||||
userAccount.PasswordHashed = SaxPasswordHelper.GetPasswordHash(userAccount, model.Password);
|
||||
userAccount.PasswordChangedAt = DateTime.Now;
|
||||
// Remove new password from history if present.
|
||||
for (int passwordHistoryIdx = 0; passwordHistoryIdx < userAccount.PasswordHistory.Count; passwordHistoryIdx++)
|
||||
{
|
||||
// Compare history password to new value.
|
||||
if (SaxPasswordHelper.VerifyHashedPassword(userAccount, model.Password, userAccount.PasswordHistory[passwordHistoryIdx]))
|
||||
{
|
||||
// New password found in history - remove it.
|
||||
userAccount.PasswordHistory.RemoveAt(passwordHistoryIdx);
|
||||
passwordHistoryIdx--;
|
||||
}
|
||||
}
|
||||
userAccount.PasswordHistory.Remove(oldPasswordHashed);
|
||||
// Add the old password at the start of the history list and validate history length.
|
||||
userAccount.PasswordHistory.Add(oldPasswordHashed);
|
||||
while (userAccount.PasswordHistory.Count > 10)
|
||||
userAccount.PasswordHistory.RemoveAt(userAccount.PasswordHistory.Count - 1);
|
||||
if (!AccountMgr.UpdateUserAccount(userAccount, DbUpdateInfo))
|
||||
{
|
||||
SaLogger.Warn(fn + " Failed to change password for " + userAccount.EmailAddress + ": " + AccountMgr.ErrorStateMessage);
|
||||
return Json(responseData.SetControlError(nameof(model.Password), Localiser["security.msg.change.password.failed"]));
|
||||
}
|
||||
SaLogger.Info(fn + " Password changed for " + userAccount.EmailAddress, true);
|
||||
|
||||
// Construct response.
|
||||
responseData.Success = true;
|
||||
if (validRequestPasswordParams)
|
||||
responseData.SetPopupMessage(messageTitle, Localiser["security.msg.request.password.saved"]);
|
||||
}
|
||||
|
||||
return Json(responseData);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Request Password request.
|
||||
//-------------------------------------------------------------------
|
||||
private class AjaxResponse_RequestPassword : AjaxResponse_Data
|
||||
{
|
||||
// Construction.
|
||||
public AjaxResponse_RequestPassword(SaxModel_Admin model) : base(model) { }
|
||||
/// <summary>Message to be displayed for the user to 'OK' before returning to the Sign-in page.</summary>
|
||||
public String SuccessMsg { get; set; }
|
||||
}
|
||||
// Ajax request.
|
||||
[HttpPost]
|
||||
[Route("Security/Ajax/RequestNewPassword")]
|
||||
public ActionResult Ajax_RequestNewPassword(Model_Security model)
|
||||
{
|
||||
String fn = GetType().Name + ".Ajax_RequestNewPassword";
|
||||
AjaxResponse_RequestPassword responseData = new AjaxResponse_RequestPassword(model);
|
||||
String messageTitle = Localiser["security.caption.request.password"];
|
||||
|
||||
// Validate data.
|
||||
model.ValidateRequestPasswordData(responseData);
|
||||
if (responseData.HasControlErrors())
|
||||
return Json(responseData);
|
||||
|
||||
// Record disposable items as they are created so all can be disposed when needed.
|
||||
using (DisposableCollection<IDisposable> disposableItems = new DisposableCollection<IDisposable>())
|
||||
{
|
||||
|
||||
// Retrieve user account.
|
||||
SaxUserAccount userAccount = AccountMgr.GetUserAccountByEmailAddress(model.EmailAddress);
|
||||
disposableItems.Add(userAccount);
|
||||
if (userAccount == null)
|
||||
SaLogger.Warn(fn + " Unable to send password request email to " + model.EmailAddress + " - account does not exist");
|
||||
else if (!userAccount.IsStatusActive)
|
||||
SaLogger.Warn(fn + " Unable to send password request email to " + model.EmailAddress + " - account is not active");
|
||||
else if (!AccountMgr.UserHasRole(userAccount.Id, Sax.UserRole.SystemAdmin))
|
||||
SaLogger.Warn(fn + " Unable to send password request email to " + model.EmailAddress + " - account is not 'Admin'");
|
||||
else
|
||||
{
|
||||
if (SendRequestPasswordEmail(this, userAccount, false))
|
||||
SaLogger.Info(fn + " Password request email sent to " + model.EmailAddress, true);
|
||||
else SaLogger.Warn(fn + " Failed to send password request email to " + model.EmailAddress);
|
||||
}
|
||||
}
|
||||
|
||||
// Construct response.
|
||||
responseData.Success = true;
|
||||
responseData.SuccessMsg = Localiser["security.msg.request.password.email.sent"];
|
||||
|
||||
return Json(responseData);
|
||||
}
|
||||
public static bool SendRequestPasswordEmail(SaxController_Admin controller, SaxUserAccount userAccount, bool onlineContext)
|
||||
{
|
||||
// Send password request email.
|
||||
SaEmailData emailData = new SaEmailData();
|
||||
emailData.Config = controller.EmailConfig;
|
||||
emailData.AddressesTo.Add(userAccount.EmailAddress);
|
||||
emailData.Subject = controller.Localiser["security.caption.request.password"];
|
||||
PopulateRequestPasswordEmailBody(controller, emailData, userAccount, onlineContext);
|
||||
return controller.EmailConsole.SendEmail(emailData);
|
||||
}
|
||||
private static void PopulateRequestPasswordEmailBody(SaxController_Admin controller, SaEmailData emailData, SaxUserAccount userAccount, bool onlineContext)
|
||||
{
|
||||
// Will need to handle culture (language/country) as and when introduced.
|
||||
emailData.MessageBody = SaxResourceHelper.GetResourceText(SaxResourceHelper.TextResource.Email_Security_RequestPassword_Html);
|
||||
emailData.HtmlBody = true;
|
||||
|
||||
// Replace dynamic tags.
|
||||
controller.EmailConsole.ReplaceDynamicEmailBodyTags(emailData, null, userAccount);
|
||||
|
||||
// Replace dynamic tag for link back to change password page.
|
||||
SaEmailConsole.ReplaceDynamicEmailTag(emailData, "[#Link.RequestPassword]", GenerateRequestPasswordLink(controller, userAccount.Id, userAccount.EmailAddress, "", onlineContext));
|
||||
SaEmailConsole.ReplaceDynamicEmailTag(emailData, "[#Link.ExpiresMinutes]", GetRequestPasswordEmailLinkExpiresMinutes(controller).ToString());
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Password request link.
|
||||
private static String ParamName_RequestPasswordEncrypted { get; } = "rpe";
|
||||
private static String ParamName_UserAccountId { get; } = "uai";
|
||||
private static String ParamName_EmailAddress { get; } = "ema";
|
||||
private static String ParamName_ExpiresAt { get; } = "exp";
|
||||
private static String ParamName_Token { get; } = "tok";
|
||||
private static String Base64Key_RequestPassword_Admin { get; } = SacsEncryptionHelper.EncodePlainKey("{~Saxonite@@Request^Password=}", SacsEncryptionHelper.KeyLength);
|
||||
private const String Purpose_RequestPassword_Admin = "Saxonite.Admin.RequestPassword";
|
||||
/// <summary>
|
||||
/// Generate Request Password link.
|
||||
/// <para>NB For an Online application request (from teh ASdmin system), must ensure that the URL and encryption parameters are switched.</para>
|
||||
/// </summary>
|
||||
internal static String GenerateRequestPasswordLink(SaxController_Admin controller, SysId userAccountId, String emailAddress, String requestPasswordToken, bool onlineContext)
|
||||
{
|
||||
// Base URL.
|
||||
String baseUrl = onlineContext ? controller.AppConfig.URL.Online.Root : controller.GetRedirectLocation(RedirectLocation.WebAppBase);
|
||||
String requestPassword_Base64Key = onlineContext ? Base64Key_RequestPassword_Online : Base64Key_RequestPassword_Admin;
|
||||
String requestPassword_Purpose = onlineContext ? Purpose_RequestPassword_Online : Purpose_RequestPassword_Admin;
|
||||
|
||||
NameValueCollection parameters = new NameValueCollection();
|
||||
parameters.Add(ParamName_UserAccountId, SysId.ToString(userAccountId));
|
||||
parameters.Add(ParamName_EmailAddress, emailAddress);
|
||||
parameters.Add(ParamName_ExpiresAt, DateUtil.Format(DateTime.Now.AddMinutes(GetRequestPasswordEmailLinkExpiresMinutes(controller)), DateUtil.Format_XmlDateTime));
|
||||
parameters.Add(ParamName_Token, requestPasswordToken);
|
||||
String link =
|
||||
baseUrl + "Security/ChangePassword?" +
|
||||
ParamName_RequestPasswordEncrypted + "=" + HttpUtility.UrlEncode(EncryptParameters(parameters, requestPassword_Base64Key, requestPassword_Purpose));
|
||||
return link;
|
||||
}
|
||||
internal static int GetRequestPasswordEmailLinkExpiresMinutes(SaxController_Admin controller)
|
||||
{
|
||||
int expiresMinutes = controller.AppConfig.Security.SignIn.PasswordRequest.EmailLinkExpiresMins;
|
||||
int expiresMinutes_Min = Sax.Config.Security.SignIn.PasswordRequest.EmailLinkExpiresMins_Min;
|
||||
int expiresMinutes_Max = Sax.Config.Security.SignIn.PasswordRequest.EmailLinkExpiresMins_Max;
|
||||
return Math.Max(expiresMinutes_Min, Math.Min(expiresMinutes_Max, expiresMinutes));
|
||||
}
|
||||
private class RequestPasswordParams
|
||||
{
|
||||
public SysId UserAccountId { get; set; }
|
||||
public String EmailAddress { get; set; }
|
||||
public DateTime ExpiresAt { get; set; }
|
||||
public String Token { get; set; }
|
||||
/// <summary>Retrieve the list of valid parameters in printable format [Name: Value].</summary>
|
||||
public List<String> GetValidParams()
|
||||
{
|
||||
List<String> values = new List<String>();
|
||||
if (SysId.IsValid(UserAccountId))
|
||||
values.Add("UserAccountId: " + SysId.ToString(UserAccountId));
|
||||
if (!StringUtil.IsEmpty(EmailAddress))
|
||||
values.Add("Email: " + EmailAddress);
|
||||
if (DateUtil.IsValid(ExpiresAt))
|
||||
values.Add("Expires: " + DateUtil.FormatXmlDateTime(ExpiresAt));
|
||||
if (!StringUtil.IsEmpty(Token))
|
||||
values.Add("Token: " + Token);
|
||||
return values;
|
||||
}
|
||||
/// <summary>Verifiy that the account Id and email are populated and the data hasn't expired.</summary>
|
||||
public bool IsValid()
|
||||
{
|
||||
return
|
||||
SysId.IsValid(UserAccountId) &&
|
||||
!StringUtil.IsEmpty(EmailAddress) &&
|
||||
DateUtil.IsValid(ExpiresAt) && ExpiresAt >= DateTime.Now;
|
||||
}
|
||||
/// <summary>Verify that the data is valid and the account details match.</summary>
|
||||
public bool IsValid(SaxUserAccount userAccount)
|
||||
{
|
||||
return
|
||||
IsValid() &&
|
||||
userAccount != null &&
|
||||
userAccount.Id.Equals(UserAccountId) &&
|
||||
userAccount.EmailAddress.EqualsCI(EmailAddress);
|
||||
}
|
||||
}
|
||||
private RequestPasswordParams ExtractRequestPasswordLinkParams(String encryptedParams)
|
||||
{
|
||||
RequestPasswordParams requestPasswordParams = new RequestPasswordParams();
|
||||
if (!StringUtil.IsEmpty(encryptedParams))
|
||||
{
|
||||
NameValueCollection linkParams = DecryptParameters(encryptedParams, Base64Key_RequestPassword_Admin, Purpose_RequestPassword_Admin);
|
||||
requestPasswordParams.UserAccountId = new SysId(StringUtil.ToInt(linkParams.Get(ParamName_UserAccountId)));
|
||||
requestPasswordParams.EmailAddress = linkParams.Get(ParamName_EmailAddress);
|
||||
requestPasswordParams.ExpiresAt = DateUtil.ParseXmlDateTime(linkParams.Get(ParamName_ExpiresAt));
|
||||
requestPasswordParams.Token = linkParams.Get(ParamName_Token);
|
||||
}
|
||||
return requestPasswordParams;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
}
|
||||
//=======================================================================
|
||||
}
|
||||
@@ -0,0 +1,143 @@
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Primitives;
|
||||
using Sarand.Net.Standard.Base.App;
|
||||
using Sarand.Net.Standard.Base.Bus;
|
||||
using Sarand.Net.Standard.Base.Core;
|
||||
using Sarand.Net.Standard.Base.Helpers;
|
||||
using Sarand.Net.Standard.Base.Utils;
|
||||
using Saxonite.Net.Core.Web.Admin.App;
|
||||
using Saxonite.Net.Core.Web.Admin.Models;
|
||||
using Saxonite.Net.Core.Web.Base.App;
|
||||
using Saxonite.Net.Core.Web.Base.Controllers;
|
||||
using Saxonite.Net.Standard.Base.App;
|
||||
using Saxonite.Net.Standard.Base.Bus;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Specialized;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading.Tasks;
|
||||
using System.Web;
|
||||
|
||||
namespace Saxonite.Net.Core.Web.Admin.Controllers
|
||||
{
|
||||
//=======================================================================
|
||||
public partial class SecurityController : SaxController_Admin
|
||||
{
|
||||
//-------------------------------------------------------------------
|
||||
// Data members.
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Construction.
|
||||
public SecurityController(SaxLocaliser localiser, ILogger<HomeController> logger) :
|
||||
base(localiser, logger)
|
||||
{
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
[HttpGet]
|
||||
public IActionResult Index()
|
||||
{
|
||||
return RedirectToAction("Signin", "Security");
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
[HttpGet]
|
||||
public IActionResult Signin()
|
||||
{
|
||||
// Redirect home if signed-in.
|
||||
if (ValidUserSession)
|
||||
return RedirectToAction("", "");
|
||||
|
||||
Model_Security model = new Model_Security(Localiser);
|
||||
return View(model);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Security - Change password
|
||||
/// <summary>
|
||||
/// Security - Change Password action.
|
||||
/// <para>- GET from request password email link.</para>
|
||||
/// <para>- POST with user signed-in. Browser cache prohibited.</para>
|
||||
/// </summary>
|
||||
[HttpGet, HttpPost]
|
||||
public IActionResult ChangePassword(Model_Security model)
|
||||
{
|
||||
String fn = GetType().Name + ".ChangePassword";
|
||||
bool validSessionRequired = true;
|
||||
|
||||
if (Request.Method.EqualsCI(HttpMethods.Get))
|
||||
{
|
||||
// Check for encrypted parameters from 'Request Password' email link.
|
||||
// NB Only allowed as a 'GET' request.
|
||||
String encryptedParams = Request.Query[ParamName_RequestPasswordEncrypted];
|
||||
RequestPasswordParams requestPasswordParams = ExtractRequestPasswordLinkParams(encryptedParams);
|
||||
if (requestPasswordParams.IsValid())
|
||||
{
|
||||
String logSuffix = requestPasswordParams.GetValidParams().Concat("", " ", ".");
|
||||
using (SaxUserAccount userAccount = AccountMgr.GetUserAccountById(requestPasswordParams.UserAccountId))
|
||||
{
|
||||
if (userAccount.IsStatusActive)
|
||||
{
|
||||
if (AccountMgr.UserHasRole(userAccount.Id, Sax.UserRole.SystemAdmin))
|
||||
{
|
||||
if (requestPasswordParams.IsValid(userAccount))
|
||||
{
|
||||
model.rpe = encryptedParams;
|
||||
validSessionRequired = false;
|
||||
}
|
||||
else SaLogger.Warn(fn + " 'Request Password' parameters supplied but invalid. " + logSuffix);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Account is active but not 'Admin'.
|
||||
// Redirect to Online application if URL is available and not already redirected ('rpe2' parameter).
|
||||
String redirectParamName = ParamName_RequestPasswordEncrypted + "2";
|
||||
SaLogger.Warn(fn + " 'Request Password' parameters supplied but account is not 'Admin'. " + logSuffix);
|
||||
if (!Request.Query.Keys.Contains(redirectParamName) && !StringUtil.IsEmpty(AppConfig.URL.Online.Root))
|
||||
{
|
||||
UriBuilder uri = new UriBuilder(Regex.Replace(AppConfig.URL.Online.Root,"/$","") + "/Security/ChangePassword");
|
||||
uri.Query = ParamName_RequestPasswordEncrypted + "=" + Uri.EscapeDataString(encryptedParams) + "&" + redirectParamName;
|
||||
return Redirect(uri.Uri.OriginalString);
|
||||
}
|
||||
}
|
||||
}
|
||||
else SaLogger.Warn(fn + " 'Request Password' parameters supplied but account is not active. " + logSuffix);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Must have a valid session to change password unless linked from Request Password above.
|
||||
if (validSessionRequired && !ValidUserSession)
|
||||
return RedirectToAction("", "");
|
||||
|
||||
// Configure page.
|
||||
|
||||
return View(model);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Security - Request Password
|
||||
//-------------------------------------------------------------------
|
||||
/// <summary>
|
||||
/// Sign-in Request Password action.
|
||||
/// <para>- User not signed-in.</para>
|
||||
/// <para>- GET only with browser cache allowed.</para>
|
||||
/// </summary>
|
||||
[HttpGet]
|
||||
public IActionResult RequestPassword()
|
||||
{
|
||||
Model_Security model = new Model_Security(Localiser);
|
||||
|
||||
// Configure page.
|
||||
model.ProhibitCache = false;
|
||||
|
||||
return View(model);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
}
|
||||
//=======================================================================
|
||||
}
|
||||
@@ -0,0 +1,286 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Sarand.Net.Standard.Base.App;
|
||||
using Sarand.Net.Standard.Base.Bus;
|
||||
using Sarand.Net.Standard.Base.Core;
|
||||
using Sarand.Net.Standard.Base.Dbas;
|
||||
using Sarand.Net.Standard.Base.Utils;
|
||||
using Saxonite.Net.Core.Web.Admin.Models;
|
||||
using Saxonite.Net.Standard.Base.App;
|
||||
using Saxonite.Net.Standard.Base.Bus;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Saxonite.Net.Core.Web.Admin.Controllers
|
||||
{
|
||||
//=======================================================================
|
||||
// Sport Controller - Ajax requests.
|
||||
//=======================================================================
|
||||
partial class SportController
|
||||
{
|
||||
//-------------------------------------------------------------------
|
||||
// Sport data.
|
||||
private class SportListData : AjaxResponse_Data.ItemData_Base
|
||||
{
|
||||
public String Name { get; set; }
|
||||
public String GroupingCode { get; set; }
|
||||
public String GroupingDesc { get; set; }
|
||||
public String SportIdParent { get; set; }
|
||||
public String SportNameParent { get; set; }
|
||||
public String SpecialityLabelCode { get; set; }
|
||||
public String SpecialityLabelDesc { get; set; }
|
||||
}
|
||||
private class SportItemData : SportListData
|
||||
{
|
||||
}
|
||||
private void PopulateSportResponseListData(SaxSport sport, SaxSport parentSport, SportListData data)
|
||||
{
|
||||
data.Id = SysId.ToString(sport.Id);
|
||||
data.GroupingCode = SportGroupingCodes.GetCodeForType(sport.Grouping);
|
||||
data.GroupingDesc = SportGroupingCodes.GetDescForType(sport.Grouping);
|
||||
data.SportNameParent = parentSport?.Name ?? null;
|
||||
data.SportIdParent = parentSport?.Id.ToString() ?? null;
|
||||
data.Name = sport.Name;
|
||||
data.SpecialityLabelCode = SportSpecialityLabelCodes.GetCodeForType(sport.SpecialityLabel);
|
||||
data.SpecialityLabelDesc = SportSpecialityLabelCodes.GetDescForType(sport.SpecialityLabel);
|
||||
data.StatusCode = sport.StatusCode;
|
||||
data.StatusDesc = sport.StatusDesc;
|
||||
}
|
||||
private void PopulateSportResponseItemData(SaxSport sport, SaxSport parentSport, SportItemData data)
|
||||
{
|
||||
PopulateSportResponseListData(sport, parentSport, data);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Get Sport List ajax request.
|
||||
//-------------------------------------------------------------------
|
||||
private class AjaxResponse_SportList : AjaxResponse_Data
|
||||
{
|
||||
// Construction.
|
||||
public AjaxResponse_SportList(SaxModel_Admin model) : base(model) { }
|
||||
// Sport list.
|
||||
public List<SportListData> Sports { get; } = new List<SportListData>();
|
||||
// Reference data.
|
||||
public List<CodeDesc> Statuses { get; } = new List<CodeDesc>();
|
||||
public String DefaultStatusCode { get; set; }
|
||||
}
|
||||
//-------------------------------------------------------------------
|
||||
[HttpPost]
|
||||
[Route("Sport/Ajax/GetList")]
|
||||
public IActionResult Ajax_GetList(Model_Sport model)
|
||||
{
|
||||
String fn = GetType().Name + ".Ajax_GetList";
|
||||
String messageTitle = Localiser["sport.caption.sports"];
|
||||
AjaxResponse_SportList responseData = new AjaxResponse_SportList(model);
|
||||
|
||||
// Validate session.
|
||||
if (!ValidUserSession)
|
||||
return GetAjaxResult_InvalidSession(responseData);
|
||||
|
||||
// Reference data - statuses.
|
||||
foreach (SaStatus status in SaxSport.ValidStatuses.FindAll(item => item != SaStatus.Deleted))
|
||||
responseData.Statuses.Add(SacsSystem.GetStatusCode(status), Localiser.GetStatusCaption(status));
|
||||
responseData.DefaultStatusCode = SacsSystem.GetStatusCode(SaxSport.DefaultStatus);
|
||||
|
||||
// Item filter.
|
||||
SaxSport.Params prmSport = new SaxSport.Params();
|
||||
prmSport.SportFilter = model.Filter.Sport;
|
||||
prmSport.StatusCat = SaxSport.StatusCat.NotDeleted;
|
||||
model.Paging.ItemTotal = (ulong)ReferenceMgr.GetSportCount(prmSport);
|
||||
model.PopulatePagingTo(prmSport.ResultsPaging);
|
||||
|
||||
// Item columns.
|
||||
ColumnDfn colId = ReferenceMgr.GetSportColumnDfn(SaxSport.Column.Id);
|
||||
ColumnDfn colGrouping = ReferenceMgr.GetSportColumnDfn(SaxSport.Column.Grouping);
|
||||
ColumnDfn colParentId = ReferenceMgr.GetSportColumnDfn(SaxSport.Column.SportIdParent);
|
||||
ColumnDfn colParentName = ReferenceMgr.GetSportColumnDfn(SaxSport.Column.ParentSport_Name);
|
||||
ColumnDfn colName = ReferenceMgr.GetSportColumnDfn(SaxSport.Column.Name);
|
||||
ColumnDfn colSpecialityLabel = ReferenceMgr.GetSportColumnDfn(SaxSport.Column.SpecialityLabel);
|
||||
ColumnDfn colStatus = ReferenceMgr.GetSportColumnDfn(SaxSport.Column.Status);
|
||||
List<ColumnDfn> columns = new List<ColumnDfn>()
|
||||
{
|
||||
colId, colGrouping, colParentId, colParentName,
|
||||
colName, colSpecialityLabel, colStatus
|
||||
};
|
||||
|
||||
// Sort order.
|
||||
prmSport.SortColumns.Add(colName);
|
||||
|
||||
// Query items.
|
||||
using (DbResultSet resultSet = ReferenceMgr.ExecuteSportQuery(columns, prmSport))
|
||||
{
|
||||
while (resultSet != null && resultSet.HasRows && resultSet.NextRecord())
|
||||
{
|
||||
NamedValue.Map values = resultSet.GetRecordValues();
|
||||
Sax.SportGrouping grouping = (Sax.SportGrouping)values.GetLong(colGrouping.DataName);
|
||||
Sax.SportSpecialityLabel specialityLabel = (Sax.SportSpecialityLabel)values.GetLong(colSpecialityLabel.DataName);
|
||||
SportListData sportData = new SportListData()
|
||||
{
|
||||
Id = values.GetString(colId.DataName),
|
||||
GroupingCode = SportGroupingCodes.GetCodeForType(grouping),
|
||||
GroupingDesc = SportGroupingCodes.GetDescForType(grouping),
|
||||
SportIdParent = values.GetString(colParentId.DataName),
|
||||
SportNameParent = values.GetString(colParentName.DataName),
|
||||
Name = values.GetString(colName.DataName),
|
||||
SpecialityLabelCode = SportSpecialityLabelCodes.GetCodeForType(specialityLabel),
|
||||
SpecialityLabelDesc = SportSpecialityLabelCodes.GetDescForType(specialityLabel),
|
||||
StatusCode = values.GetString(colStatus.DataName),
|
||||
StatusDesc = SacsSystem.GetStatusDescForCode(values.GetString(colStatus.DataName))
|
||||
};
|
||||
responseData.Sports.Add(sportData);
|
||||
}
|
||||
}
|
||||
if (model.Paging.IsPaged)
|
||||
model.Paging.ItemCount = (ushort)responseData.Sports.Count;
|
||||
|
||||
// Complete response.
|
||||
responseData.SetPaging(model);
|
||||
responseData.Success = true;
|
||||
return Json(responseData);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Get Sport ajax request.
|
||||
//-------------------------------------------------------------------
|
||||
private class AjaxResponse_Sport : AjaxResponse_Data
|
||||
{
|
||||
// Construction.
|
||||
public AjaxResponse_Sport(SaxModel_Admin model) : base(model) { }
|
||||
// Sport details.
|
||||
public SportItemData sport { get; } = new SportItemData();
|
||||
}
|
||||
//-------------------------------------------------------------------
|
||||
[HttpPost]
|
||||
[Route("Sport/Ajax/GetItem")]
|
||||
public IActionResult Ajax_GetItem(Model_Sport model)
|
||||
{
|
||||
String fn = GetType().Name + ".Ajax_GetItem";
|
||||
String messageTitle = Localiser["sport.caption.sport"];
|
||||
AjaxResponse_Sport responseData = new AjaxResponse_Sport(model);
|
||||
|
||||
// Validate session.
|
||||
if (!ValidUserSession)
|
||||
return GetAjaxResult_InvalidSession(responseData);
|
||||
|
||||
// Record disposable items as they are created so all can be disposed when needed.
|
||||
using (DisposableCollection<IDisposable> disposableItems = new DisposableCollection<IDisposable>())
|
||||
{
|
||||
|
||||
// Identify item.
|
||||
SysId sportId = SysId.ToSysId(model.SportId);
|
||||
if (!SysId.IsValid(sportId))
|
||||
return Json(responseData.SetPopupMessage(messageTitle, Localiser["msg.error.item.id.not.specified"]));
|
||||
|
||||
// Retrieve item.
|
||||
SaxSport sport = ReferenceMgr.GetSportById(sportId);
|
||||
disposableItems.Add(sport);
|
||||
if (sport == null)
|
||||
{
|
||||
SaLogger.Warn(fn + " Failed to retrieve sport for Id: '" + model.SportId + "'");
|
||||
return Json(responseData.SetPopupMessage(messageTitle, Localiser["msg.error.item.id.not.found"]));
|
||||
}
|
||||
|
||||
// Parent sport.
|
||||
SaxSport parentSport = ReferenceMgr.GetSportById(sport.SportIdParent);
|
||||
disposableItems.Add(parentSport);
|
||||
|
||||
// Construct response.
|
||||
PopulateSportResponseItemData(sport, parentSport, responseData.sport);
|
||||
}
|
||||
|
||||
// Complete response.
|
||||
responseData.Success = true;
|
||||
|
||||
return Json(responseData);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Store Sport ajax request.
|
||||
//-------------------------------------------------------------------
|
||||
[HttpPost]
|
||||
[Route("Sport/Ajax/StoreItem")]
|
||||
public IActionResult Ajax_StoreItem(Model_Sport model)
|
||||
{
|
||||
String fn = GetType().Name + ".Ajax_StoreItem";
|
||||
String messageTitle = Localiser["sport.caption.sport"];
|
||||
AjaxResponse_Sport responseData = new AjaxResponse_Sport(model);
|
||||
|
||||
// Validate session.
|
||||
if (!ValidUserSession)
|
||||
return GetAjaxResult_InvalidSession(responseData);
|
||||
|
||||
// Record disposable items as they are created so all can be disposed when needed.
|
||||
using (DisposableCollection<IDisposable> disposableItems = new DisposableCollection<IDisposable>())
|
||||
{
|
||||
|
||||
// Validate item properties.
|
||||
model.ValidateSportData(responseData);
|
||||
if (responseData.HasControlErrors())
|
||||
return Json(responseData);
|
||||
|
||||
// Retrieve existing item.
|
||||
SysId sportId = SysId.ToSysId(model.SportId);
|
||||
SaxSport sport = ReferenceMgr.GetSportById(sportId);
|
||||
disposableItems.Add(sport);
|
||||
if (sport == null && SysId.IsValid(sportId))
|
||||
{
|
||||
SaLogger.Warn(fn + " Failed to retrieve sport for Id: '" + model.SportId + "'");
|
||||
return Json(responseData.SetPopupMessage(messageTitle, Localiser["msg.error.item.id.not.found"]));
|
||||
}
|
||||
|
||||
// Create new item if required.
|
||||
if (sport == null)
|
||||
{
|
||||
sport = ReferenceMgr.CreateSport();
|
||||
disposableItems.Add(sport);
|
||||
}
|
||||
|
||||
// Populate item properties.
|
||||
if (model.SportGroupingCode != null)
|
||||
sport.Grouping = model.SportGrouping;
|
||||
if (model.SportIdParent != null)
|
||||
sport.SportIdParent = SysId.ToSysId(model.SportIdParent);
|
||||
if (model.SportName != null)
|
||||
sport.Name = model.SportName;
|
||||
if (model.SportSpecialityLabelCode != null)
|
||||
sport.SpecialityLabel = model.SportSpecialityLabel;
|
||||
if (model.SportStatusCode != null)
|
||||
sport.Status = model.SportStatus;
|
||||
|
||||
// Store item.
|
||||
if (!SysId.IsValid(sport.Id))
|
||||
{
|
||||
if (!ReferenceMgr.InsertSport(sport, DbUpdateInfo))
|
||||
{
|
||||
SaLogger.Warn(fn + " Failed to insert sport: " + ReferenceMgr.ErrorStateMessage);
|
||||
return Json(responseData.SetPopupMessage(messageTitle, Localiser["msg.error.item.insert.failed"] + "\n\n" + ReferenceMgr.ErrorStateMessage));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!ReferenceMgr.UpdateSport(sport, DbUpdateInfo))
|
||||
{
|
||||
SaLogger.Warn(fn + " Failed to update sport [Id:" + SysId.ToString(sport.Id) + "]: " + ReferenceMgr.ErrorStateMessage);
|
||||
return Json(responseData.SetPopupMessage(messageTitle, Localiser["msg.error.item.update.failed"] + "\n\n" + ReferenceMgr.ErrorStateMessage));
|
||||
}
|
||||
}
|
||||
|
||||
// Parent sport.
|
||||
SaxSport parentSport = ReferenceMgr.GetSportById(sport.SportIdParent);
|
||||
disposableItems.Add(parentSport);
|
||||
|
||||
// Construct response.
|
||||
PopulateSportResponseItemData(sport, parentSport, responseData.sport);
|
||||
}
|
||||
|
||||
// Complete response.
|
||||
responseData.Success = true;
|
||||
|
||||
return Json(responseData);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
}
|
||||
//=======================================================================
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Saxonite.Net.Core.Web.Admin.Models;
|
||||
using Saxonite.Net.Core.Web.Base.App;
|
||||
using Saxonite.Net.Core.Web.Base.Controllers;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Saxonite.Net.Core.Web.Admin.Controllers
|
||||
{
|
||||
//=======================================================================
|
||||
public partial class SportController : SaxController_Admin
|
||||
{
|
||||
//-------------------------------------------------------------------
|
||||
// Construction.
|
||||
public SportController(SaxLocaliser localiser, ILogger<HomeController> logger) :
|
||||
base(localiser, logger)
|
||||
{
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
[HttpGet]
|
||||
public IActionResult Index()
|
||||
{
|
||||
// Validate session.
|
||||
if (!ValidUserSession)
|
||||
AutoLoginUser();
|
||||
if (!ValidUserSession)
|
||||
return RedirectToAction("", "");
|
||||
|
||||
// Paging.
|
||||
Model_Sport model = new Model_Sport(Localiser);
|
||||
model.Paging.PageNo = 1;
|
||||
model.Paging.PageLength = 12;
|
||||
|
||||
return View(model);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
}
|
||||
//=======================================================================
|
||||
}
|
||||
+351
@@ -0,0 +1,351 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Sarand.Net.Standard.Base.App;
|
||||
using Sarand.Net.Standard.Base.Bus;
|
||||
using Sarand.Net.Standard.Base.Core;
|
||||
using Sarand.Net.Standard.Base.Dbas;
|
||||
using Saxonite.Net.Standard.Base.App;
|
||||
using Saxonite.Net.Core.Web.Admin.Models;
|
||||
using Saxonite.Net.Core.Web.Admin.Models.Support;
|
||||
using Saxonite.Net.Core.Web.Base.App;
|
||||
using Saxonite.Net.Standard.Base.Bus;
|
||||
using Saxonite.Net.Standard.Base.Bus.Support;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Sarand.Net.Standard.Base.Utils;
|
||||
|
||||
namespace Saxonite.Net.Core.Web.Admin.Controllers.Support
|
||||
{
|
||||
//=======================================================================
|
||||
// UserReport Controller - Ajax requests.
|
||||
//=======================================================================
|
||||
partial class Controller_UserReport
|
||||
{
|
||||
//-------------------------------------------------------------------
|
||||
// UserReport data.
|
||||
private class UserReportListData : AjaxResponse_Data.ItemData_Base
|
||||
{
|
||||
// Account Id only populated while account names are being queried, then nulled.
|
||||
public SysId UserAccountId { get; set; }
|
||||
public String UserDisplayName { get; set; }
|
||||
public String ReportTypeCode { get; set; }
|
||||
public String ReportTypeDesc { get; set; }
|
||||
public String Title { get; set; }
|
||||
public String RecordedOnDisp { get; set; }
|
||||
}
|
||||
private class UserReportItemData : UserReportListData
|
||||
{
|
||||
public String ReportType { get; set; }
|
||||
public String Report { get; set; }
|
||||
public String RecordedOnForm { get; set; }
|
||||
}
|
||||
private void PopulateUserReportResponseListData(SaxModel_Admin model, SaxUserReport userReport, SaxUserAccount userAccount, UserReportListData data)
|
||||
{
|
||||
data.Id = SysId.ToString(userReport.Id);
|
||||
data.UserDisplayName = userAccount.GetDisplayName();
|
||||
data.ReportTypeCode = UserReportTypeCodes.GetCodeForType(userReport.ReportType);
|
||||
data.ReportTypeDesc = model.Localiser.GetUserReportTypeCaption(userReport.ReportType);
|
||||
data.Title = userReport.Title;
|
||||
data.RecordedOnDisp = model.FormatDateForDisplay(userReport.RecordedOn);
|
||||
data.StatusCode = userReport.StatusCode;
|
||||
data.StatusDesc = userReport.StatusDesc;
|
||||
}
|
||||
private void PopulateUserReportResponseItemData(Model_UserReport model, SaxUserReport userReport, SaxUserAccount userAccount, UserReportItemData data)
|
||||
{
|
||||
PopulateUserReportResponseListData(model, userReport, userAccount, data);
|
||||
data.Report = userReport.Report;
|
||||
data.RecordedOnForm = model.FormatDateForForm(userReport.RecordedOn);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Ajax - User Report list.
|
||||
//-------------------------------------------------------------------
|
||||
private class AjaxResponse_UserReportList : AjaxResponse_Data
|
||||
{
|
||||
// Construction.
|
||||
public AjaxResponse_UserReportList(SaxModel_Admin model) : base(model) { }
|
||||
// UserReport list.
|
||||
public List<UserReportListData> Reports { get; } = new List<UserReportListData>();
|
||||
// Reference data.
|
||||
public List<ItemCodeDesc> ReportTypes { get; } = new List<ItemCodeDesc>();
|
||||
public List<ItemCodeDesc> Statuses { get; } = new List<ItemCodeDesc>();
|
||||
public String DefaultStatusCode { get; set; }
|
||||
}
|
||||
//-------------------------------------------------------------------
|
||||
[HttpPost]
|
||||
[Route("UserReport/Ajax/GetList")]
|
||||
public IActionResult Ajax_GetList(Model_UserReport model)
|
||||
{
|
||||
String fn = GetType().Name + ".Ajax_GetList";
|
||||
String messageTitle = Localiser["caption.user.reports"];
|
||||
AjaxResponse_UserReportList responseData = new AjaxResponse_UserReportList(model);
|
||||
|
||||
// Validate session.
|
||||
if (!ValidUserSession)
|
||||
return GetAjaxResult_InvalidSession(responseData);
|
||||
|
||||
// Reference data - report types.
|
||||
responseData.ReportTypes.Add(new AjaxResponse_Data.ItemCodeDesc());
|
||||
List<Sax.UserReportType> validReportTypes = new List<Sax.UserReportType>(EnumUtil.GetValues<Sax.UserReportType>());
|
||||
foreach (TypeCodeDesc reportType in UserReportTypeCodes)
|
||||
{
|
||||
if (!validReportTypes.Contains((Sax.UserReportType)reportType.Type)) continue;
|
||||
responseData.ReportTypes.Add(new AjaxResponse_Data.ItemCodeDesc() { Code = reportType.Code, Desc = Localiser.GetUserReportTypeCaption((Sax.UserReportType)reportType.Type) });
|
||||
}
|
||||
|
||||
// Reference data - statuses.
|
||||
foreach (SaStatus status in SaxUserReport.ValidStatuses.FindAll(item => item != SaStatus.Deleted))
|
||||
responseData.Statuses.Add(new AjaxResponse_Data.ItemCodeDesc() { Code = SacsSystem.GetStatusCode(status), Desc = Localiser.GetStatusCaption(status) });
|
||||
responseData.DefaultStatusCode = SacsSystem.GetStatusCode(SaxUserReport.DefaultStatus);
|
||||
|
||||
// Item filter.
|
||||
SaxUserReport.Params prmUserReport = new SaxUserReport.Params();
|
||||
prmUserReport.UserReportFilter = model.Filter.Report;
|
||||
prmUserReport.StatusCat = SaxUserReport.StatusCat.NotDeleted;
|
||||
model.Paging.ItemTotal = (ulong)SupportMgr.GetUserReportCount(prmUserReport);
|
||||
model.PopulatePagingTo(prmUserReport.ResultsPaging);
|
||||
|
||||
// Item columns.
|
||||
ColumnDfn colId = SupportMgr.GetUserReportColumnDfn(SaxUserReport.Column.Id);
|
||||
ColumnDfn colUserAccountId = SupportMgr.GetUserReportColumnDfn(SaxUserReport.Column.UserAccountId);
|
||||
ColumnDfn colReportType = SupportMgr.GetUserReportColumnDfn(SaxUserReport.Column.ReportType);
|
||||
ColumnDfn colTitle = SupportMgr.GetUserReportColumnDfn(SaxUserReport.Column.Title);
|
||||
ColumnDfn colRecordedOn = SupportMgr.GetUserReportColumnDfn(SaxUserReport.Column.RecordedOn);
|
||||
ColumnDfn colStatus = SupportMgr.GetUserReportColumnDfn(SaxUserReport.Column.Status);
|
||||
List<ColumnDfn> columns = new List<ColumnDfn>()
|
||||
{
|
||||
colId, colUserAccountId, colReportType, colTitle,
|
||||
colRecordedOn, colStatus
|
||||
};
|
||||
|
||||
// Sort order.
|
||||
prmUserReport.SortColumns.Add(colRecordedOn);
|
||||
prmUserReport.SortColumns.Last().SortAscending = false;
|
||||
prmUserReport.SortColumns.Add(colId);
|
||||
prmUserReport.SortColumns.Last().SortAscending = false;
|
||||
|
||||
// User account details must be queried separately - different database!
|
||||
HashSet<SysId> userAccountIds = new HashSet<SysId>();
|
||||
|
||||
// Query items.
|
||||
using (DbResultSet resultSet = SupportMgr.ExecuteUserReportQuery(columns, prmUserReport))
|
||||
{
|
||||
while (resultSet != null && resultSet.HasRows && resultSet.NextRecord())
|
||||
{
|
||||
NamedValue.Map values = resultSet.GetRecordValues();
|
||||
SysId userAccountId = new SysId(values.GetLong(colUserAccountId.DataName));
|
||||
userAccountIds.AddId(userAccountId);
|
||||
Sax.UserReportType reportType = (Sax.UserReportType)values.GetLong(colReportType.DataName);
|
||||
UserReportListData userReportData = new UserReportListData()
|
||||
{
|
||||
Id = values.GetString(colId.DataName),
|
||||
UserAccountId = userAccountId,
|
||||
ReportTypeCode = UserReportTypeCodes.GetCodeForType(reportType),
|
||||
ReportTypeDesc = model.Localiser.GetUserReportTypeCaption(reportType),
|
||||
Title = values.GetString(colTitle.DataName),
|
||||
RecordedOnDisp = model.FormatDateForDisplay(values.GetDate(colRecordedOn.DataName)),
|
||||
StatusCode = values.GetString(colStatus.DataName),
|
||||
StatusDesc = SacsSystem.GetStatusDescForCode(values.GetString(colStatus.DataName))
|
||||
};
|
||||
responseData.Reports.Add(userReportData);
|
||||
}
|
||||
}
|
||||
if (model.Paging.IsPaged)
|
||||
model.Paging.ItemCount = (ushort)responseData.Reports.Count;
|
||||
|
||||
// Query and populate User Account details.
|
||||
if (userAccountIds.Any())
|
||||
{
|
||||
// User Account columns.
|
||||
ColumnDfn colUserAccount_Id = AccountMgr.GetUserAccountColumnDfn(SaxUserAccount.Column.Id);
|
||||
ColumnDfn colUserAccount_Title = AccountMgr.GetUserAccountColumnDfn(SaxUserAccount.Column.Title);
|
||||
ColumnDfn colUserAccount_FirstName = AccountMgr.GetUserAccountColumnDfn(SaxUserAccount.Column.FirstName);
|
||||
ColumnDfn colUserAccount_LastName = AccountMgr.GetUserAccountColumnDfn(SaxUserAccount.Column.LastName);
|
||||
List<ColumnDfn> userAccountCols = new List<ColumnDfn>() { colUserAccount_Id, colUserAccount_Title, colUserAccount_FirstName, colUserAccount_LastName };
|
||||
// User Account filter.
|
||||
SaxUserAccount.Params prmUserAccount = new SaxUserAccount.Params();
|
||||
prmUserAccount.IdsIncluded.AddRange(userAccountIds);
|
||||
prmUserAccount.StatusCat = SaxUserAccount.StatusCat.Any;
|
||||
// Query user accounts and populate properties to report list.
|
||||
using (DbResultSet resultSet = AccountMgr.ExecuteUserAccountQuery(userAccountCols, prmUserAccount))
|
||||
{
|
||||
while (resultSet != null && resultSet.HasRows && resultSet.NextRecord())
|
||||
{
|
||||
NamedValue.Map values = resultSet.GetRecordValues();
|
||||
SysId userAccountId = new SysId(values.GetLong(colUserAccount_Id.DataName));
|
||||
String title = values.GetString(colUserAccount_Title.DataName);
|
||||
String firstName = values.GetString(colUserAccount_FirstName.DataName);
|
||||
String lastName = values.GetString(colUserAccount_LastName.DataName);
|
||||
foreach (UserReportListData userReportData in responseData.Reports.FindAll(item => SysId.InvalidOnNull(item.UserAccountId).Equals(userAccountId)))
|
||||
{
|
||||
userReportData.UserDisplayName = SaxUserAccount.GetDisplayName(title, firstName, lastName);
|
||||
userReportData.UserAccountId = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Clear any remaining User Account Ids.
|
||||
foreach (UserReportListData userReportData in responseData.Reports.FindAll(item => item.UserAccountId != null))
|
||||
userReportData.UserAccountId = null;
|
||||
}
|
||||
|
||||
// Complete response.
|
||||
responseData.SetPaging(model);
|
||||
responseData.Success = true;
|
||||
return Json(responseData);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Ajax - User Report properties.
|
||||
//-------------------------------------------------------------------
|
||||
private class AjaxResponse_UserReport : AjaxResponse_Data
|
||||
{
|
||||
// Construction.
|
||||
public AjaxResponse_UserReport(SaxModel_Admin model) : base(model) { }
|
||||
// UserReport details.
|
||||
public UserReportItemData Report { get; } = new UserReportItemData();
|
||||
}
|
||||
//-------------------------------------------------------------------
|
||||
[HttpPost]
|
||||
[Route("UserReport/Ajax/GetItem")]
|
||||
public IActionResult Ajax_GetItem(Model_UserReport model)
|
||||
{
|
||||
String fn = GetType().Name + ".Ajax_GetItem";
|
||||
String messageTitle = Localiser["caption.user.report"];
|
||||
AjaxResponse_UserReport responseData = new AjaxResponse_UserReport(model);
|
||||
|
||||
// Validate session.
|
||||
if (!ValidUserSession)
|
||||
return GetAjaxResult_InvalidSession(responseData);
|
||||
|
||||
// Record disposable items as they are created so all can be disposed when needed.
|
||||
using (DisposableCollection<IDisposable> disposableItems = new DisposableCollection<IDisposable>())
|
||||
{
|
||||
|
||||
// Identify item.
|
||||
SysId userReportId = SysId.ToSysId(model.UserReport.Id);
|
||||
if (!SysId.IsValid(userReportId))
|
||||
return Json(responseData.SetPopupMessage(messageTitle, Localiser["msg.error.item.id.not.specified"]));
|
||||
|
||||
// Retrieve item.
|
||||
SaxUserReport userReport = SupportMgr.GetUserReportById(userReportId);
|
||||
disposableItems.Add(userReport);
|
||||
if (userReport == null)
|
||||
{
|
||||
SaLogger.Warn(fn + " Failed to retrieve userReport for Id: '" + model.UserReport.Id + "'");
|
||||
return Json(responseData.SetPopupMessage(messageTitle, Localiser["msg.error.item.id.not.found"]));
|
||||
}
|
||||
|
||||
// Retrieve user.
|
||||
SaxUserAccount userAccount = AccountMgr.GetUserAccountById(userReport.UserAccountId);
|
||||
disposableItems.Add(userAccount);
|
||||
|
||||
// Construct response.
|
||||
PopulateUserReportResponseItemData(model, userReport, userAccount, responseData.Report);
|
||||
}
|
||||
|
||||
// Complete response.
|
||||
responseData.Success = true;
|
||||
|
||||
return Json(responseData);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Ajax - User Report storage.
|
||||
//-------------------------------------------------------------------
|
||||
[HttpPost]
|
||||
[Route("UserReport/Ajax/StoreItem")]
|
||||
public IActionResult Ajax_StoreItem(Model_UserReport model)
|
||||
{
|
||||
String fn = GetType().Name + ".Ajax_StoreItem";
|
||||
String messageTitle = Localiser["caption.user.report"];
|
||||
AjaxResponse_UserReport responseData = new AjaxResponse_UserReport(model);
|
||||
|
||||
// Validate session.
|
||||
if (!ValidUserSession)
|
||||
return GetAjaxResult_InvalidSession(responseData);
|
||||
|
||||
// Record disposable items as they are created so all can be disposed when needed.
|
||||
using (DisposableCollection<IDisposable> disposableItems = new DisposableCollection<IDisposable>())
|
||||
{
|
||||
|
||||
// Validate item properties.
|
||||
model.ValidateUserReportData(responseData);
|
||||
if (responseData.HasControlErrors())
|
||||
return Json(responseData);
|
||||
|
||||
// Retrieve existing item.
|
||||
SysId userReportId = SysId.ToSysId(model.UserReport.Id);
|
||||
if (StringUtil.ToBool(model.UserReport.Exists) && !SysId.IsValid(userReportId))
|
||||
{
|
||||
SaLogger.Warn(fn + " Item Id not supplied for existing item.");
|
||||
return Json(responseData.SetPopupMessage(messageTitle, Localiser["msg.error.system"]));
|
||||
}
|
||||
if (!StringUtil.ToBool(model.UserReport.Exists) && SysId.IsValid(userReportId))
|
||||
{
|
||||
SaLogger.Warn(fn + " Item Id supplied for new item: '" + model.UserReport.Id + "'");
|
||||
return Json(responseData.SetPopupMessage(messageTitle, Localiser["msg.error.system"]));
|
||||
}
|
||||
SaxUserReport userReport = SupportMgr.GetUserReportById(userReportId);
|
||||
disposableItems.Add(userReport);
|
||||
if (userReport == null && SysId.IsValid(userReportId))
|
||||
{
|
||||
SaLogger.Warn(fn + " Failed to retrieve userReport for Id: '" + model.UserReport.Id + "'");
|
||||
return Json(responseData.SetPopupMessage(messageTitle, Localiser["msg.error.item.id.not.found"]));
|
||||
}
|
||||
|
||||
// Create new item if required.
|
||||
if (userReport == null)
|
||||
{
|
||||
userReport = SupportMgr.CreateUserReport(SessionUserAccountId);
|
||||
disposableItems.Add(userReport);
|
||||
userReport.RecordedOn = DateTime.Today;
|
||||
}
|
||||
|
||||
// Populate item properties.
|
||||
if (model.UserReport.ReportType != null)
|
||||
userReport.ReportType = model.UserReportType;
|
||||
if (model.UserReport.Title != null)
|
||||
userReport.Title = model.UserReport.Title;
|
||||
if (model.UserReport.Report != null)
|
||||
userReport.Report = model.UserReport.Report;
|
||||
if (model.UserReport.Status != null)
|
||||
userReport.Status = model.UserReportStatus;
|
||||
|
||||
// Store item.
|
||||
if (!SysId.IsValid(userReport.Id))
|
||||
{
|
||||
if (!SupportMgr.InsertUserReport(userReport, DbUpdateInfo))
|
||||
{
|
||||
SaLogger.Warn(fn + " Failed to insert userReport: " + SupportMgr.ErrorStateMessage);
|
||||
return Json(responseData.SetPopupMessage(messageTitle, Localiser["msg.error.item.insert.failed"] + "\n\n" + SupportMgr.ErrorStateMessage));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!SupportMgr.UpdateUserReport(userReport, DbUpdateInfo))
|
||||
{
|
||||
SaLogger.Warn(fn + " Failed to update userReport [Id:" + SysId.ToString(userReport.Id) + "]: " + SupportMgr.ErrorStateMessage);
|
||||
return Json(responseData.SetPopupMessage(messageTitle, Localiser["msg.error.item.update.failed"] + "\n\n" + SupportMgr.ErrorStateMessage));
|
||||
}
|
||||
}
|
||||
|
||||
// Retrieve user.
|
||||
SaxUserAccount userAccount = AccountMgr.GetUserAccountById(userReport.UserAccountId);
|
||||
disposableItems.Add(userAccount);
|
||||
|
||||
// Construct response.
|
||||
PopulateUserReportResponseItemData(model, userReport, userAccount, responseData.Report);
|
||||
}
|
||||
|
||||
// Complete response.
|
||||
responseData.Success = true;
|
||||
|
||||
return Json(responseData);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
}
|
||||
//=======================================================================
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Saxonite.Net.Core.Web.Admin.Models.Support;
|
||||
using Saxonite.Net.Core.Web.Base.App;
|
||||
using System;
|
||||
|
||||
namespace Saxonite.Net.Core.Web.Admin.Controllers.Support
|
||||
{
|
||||
//=======================================================================
|
||||
public partial class Controller_UserReport : SaxController_Admin_Support
|
||||
{
|
||||
//-------------------------------------------------------------------
|
||||
// Data members.
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Construction.
|
||||
public Controller_UserReport(SaxLocaliser localiser, ILogger<HomeController> logger) :
|
||||
base(localiser, logger)
|
||||
{
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Properties.
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Index page.
|
||||
[HttpGet]
|
||||
[Route("UserReport")]
|
||||
[Route("UserReport/Index")]
|
||||
public IActionResult Index(String sta)
|
||||
{
|
||||
// Validate session.
|
||||
if (!ValidUserSession)
|
||||
return RedirectToAction("", "");
|
||||
|
||||
// Model.
|
||||
Model_UserReport model = new Model_UserReport(Localiser);
|
||||
|
||||
return View("/Views/Support/UserReport/Index.cshtml", model);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
}
|
||||
//=======================================================================
|
||||
}
|
||||
+28
@@ -0,0 +1,28 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Saxonite.Net.Core.Web.Admin.Models.Support;
|
||||
using Saxonite.Net.Core.Web.Base.App;
|
||||
using System;
|
||||
|
||||
namespace Saxonite.Net.Core.Web.Admin.Controllers.Support
|
||||
{
|
||||
//=======================================================================
|
||||
public abstract class SaxController_Admin_Support : SaxController_Admin
|
||||
{
|
||||
//-------------------------------------------------------------------
|
||||
// Data members.
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Protected construction.
|
||||
protected SaxController_Admin_Support(SaxLocaliser localiser, ILogger<HomeController> logger) :
|
||||
base(localiser, logger)
|
||||
{
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Properties.
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
}
|
||||
//=======================================================================
|
||||
}
|
||||
+407
@@ -0,0 +1,407 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Sarand.Net.Standard.Base.App;
|
||||
using Sarand.Net.Standard.Base.Bus;
|
||||
using Sarand.Net.Standard.Base.Core;
|
||||
using Sarand.Net.Standard.Base.Dbas;
|
||||
using Sarand.Net.Standard.Base.Helpers;
|
||||
using Sarand.Net.Standard.Base.Procs;
|
||||
using Sarand.Net.Standard.Base.Utils;
|
||||
using Sarand.Net.Standard.Dbas.Data;
|
||||
using Sarand.Net.Standard.Dbas.Proc;
|
||||
using Saxonite.Net.Core.Web.Admin.Models;
|
||||
using Saxonite.Net.Standard.Base.App;
|
||||
using Saxonite.Net.Standard.Base.Bus;
|
||||
using Saxonite.Net.Standard.Dbas.App;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Saxonite.Net.Core.Web.Admin.Controllers.System
|
||||
{
|
||||
//=======================================================================
|
||||
// System - Ajax - Database controller
|
||||
//=======================================================================
|
||||
partial class SystemController
|
||||
{
|
||||
//-------------------------------------------------------------------
|
||||
// Database data.
|
||||
private class DatabaseTableData
|
||||
{
|
||||
public String SchemaName { get; set; }
|
||||
public String TableName { get; set; }
|
||||
public String QualifiedName { get; set; }
|
||||
public int RowCount { get; set; }
|
||||
public int ColumnCount { get; set; }
|
||||
public int IndexCount { get; set; }
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Get Database Table List ajax request.
|
||||
//-------------------------------------------------------------------
|
||||
private class AjaxResponse_DatabaseTableList : AjaxResponse_Data
|
||||
{
|
||||
// Construction.
|
||||
public AjaxResponse_DatabaseTableList(SaxModel_Admin model) : base(model) { }
|
||||
// Table list.
|
||||
public List<DatabaseTableData> Tables { get; } = new List<DatabaseTableData>();
|
||||
}
|
||||
//-------------------------------------------------------------------
|
||||
[HttpPost]
|
||||
[Route("System/Ajax/GetDatabaseTables")]
|
||||
public IActionResult Ajax_GetDatabaseTables(Model_System model)
|
||||
{
|
||||
String fn = GetType().Name + ".Ajax_GetDatabaseTables";
|
||||
String messageTitle = Localiser["system.caption.database"];
|
||||
AjaxResponse_DatabaseTableList responseData = new AjaxResponse_DatabaseTableList(model);
|
||||
|
||||
// Validate session.
|
||||
if (!ValidUserSession)
|
||||
return GetAjaxResult_InvalidSession(responseData);
|
||||
|
||||
// Record disposable items as they are created so all can be disposed when needed.
|
||||
using (DisposableCollection<IDisposable> disposableItems = new DisposableCollection<IDisposable>())
|
||||
{
|
||||
// Database connection.
|
||||
Sax.Database databaseInstance = EnumUtil.ParseEnum(StringUtil.EmptyOnNull(model.DatabaseFilter.Instance), Sax.Database.Core);
|
||||
ISacsDatabase db = App.GetDatabase(SessionContext, databaseInstance);
|
||||
|
||||
// Database table row counts.
|
||||
Dictionary<String, int> tableRowCounts = new Dictionary<string, int>(StringComparer.OrdinalIgnoreCase);
|
||||
String query =
|
||||
"SELECT QUOTENAME(SCHEMA_NAME(sOBJ.schema_id)) + '.' + QUOTENAME(sOBJ.name) As [TableName], SUM(sPTN.Rows) As [RowCount] " +
|
||||
"FROM sys.objects AS sOBJ " +
|
||||
"INNER JOIN sys.partitions AS sPTN ON sOBJ.object_id = sPTN.object_id " +
|
||||
"WHERE sOBJ.type = 'U' AND sOBJ.is_ms_shipped = 0x0 AND index_id< 2 /*Index Id: 0:Heap,1:Clustered*/ " +
|
||||
"GROUP BY sOBJ.schema_id, sOBJ.name";
|
||||
using (DbResultSet dbResultSet = DbResultSet_DataReader.ExecuteQuery(db, query))
|
||||
{
|
||||
while (dbResultSet != null && dbResultSet.NextRecord())
|
||||
{
|
||||
tableRowCounts.Add(dbResultSet.GetRecordValues().GetValue("TableName").ToString(), (int)dbResultSet.GetRecordValues().GetValue("RowCount").AsLong());
|
||||
}
|
||||
}
|
||||
|
||||
// Database tables.
|
||||
List<DbDfnTable> tableDfns = db.GetTableDfns();
|
||||
foreach (DbDfnTable tableDfn in tableDfns.OrderBy(item => item.Name))
|
||||
{
|
||||
// Filter by table name.
|
||||
if (!StringUtil.IsEmpty(model.DatabaseFilter.Search) && !tableDfn.Name.ContainsCI(model.DatabaseFilter.Search))
|
||||
continue;
|
||||
|
||||
DatabaseTableData tableData = new DatabaseTableData();
|
||||
tableData.SchemaName = tableDfn.Schema;
|
||||
tableData.TableName = tableDfn.Name;
|
||||
tableData.QualifiedName = tableDfn.QualifiedName;
|
||||
tableData.ColumnCount = tableDfn.ColumnCount;
|
||||
tableData.IndexCount = tableDfn.IndexCount;
|
||||
|
||||
// Row count.
|
||||
tableData.RowCount = tableRowCounts.GetValueOrDefault(tableDfn.QuotedQualifiedName, 0);
|
||||
|
||||
responseData.Tables.Add(tableData);
|
||||
}
|
||||
}
|
||||
|
||||
// Complete response.
|
||||
responseData.Success = true;
|
||||
return Json(responseData);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Validate Database Schema ajax request.
|
||||
//-------------------------------------------------------------------
|
||||
private class DbSchemaItemResponseData
|
||||
{
|
||||
public int Id { get; set; }
|
||||
public String SchemaName { get; set; }
|
||||
public String TableName { get; set; }
|
||||
public String ColumnName { get; set; }
|
||||
public int ColumnPosition { get; set; }
|
||||
public String IndexName { get; set; }
|
||||
public String Comment { get; set; }
|
||||
}
|
||||
private class AjaxResponse_ValidateDatabaseSchema : AjaxResponse_Data
|
||||
{
|
||||
// Construction.
|
||||
public AjaxResponse_ValidateDatabaseSchema(SaxModel_Admin model) : base(model) { }
|
||||
// Database instance.
|
||||
public String Instance { get; set; }
|
||||
// Schema validation list.
|
||||
public List<DbSchemaItemResponseData> Items { get; } = new List<DbSchemaItemResponseData>();
|
||||
}
|
||||
//-------------------------------------------------------------------
|
||||
[HttpPost]
|
||||
[Route("System/Ajax/ValidateDatabaseSchema")]
|
||||
public IActionResult Ajax_ValidateDatabaseSchema(Model_System model)
|
||||
{
|
||||
String fn = GetType().Name + ".Ajax_ValidateDatabaseSchema";
|
||||
String messageTitle = Localiser["system.caption.database"];
|
||||
AjaxResponse_ValidateDatabaseSchema responseData = new AjaxResponse_ValidateDatabaseSchema(model);
|
||||
|
||||
// Validate session.
|
||||
if (!ValidUserSession)
|
||||
return GetAjaxResult_InvalidSession(responseData);
|
||||
|
||||
// Record disposable items as they are created so all can be disposed when needed.
|
||||
using (DisposableCollection<IDisposable> disposableItems = new DisposableCollection<IDisposable>())
|
||||
{
|
||||
|
||||
// Database instance.
|
||||
Sax.Database databaseInstance = EnumUtil.ParseEnum(StringUtil.EmptyOnNull(model.DatabaseFilter.Instance), Sax.Database.Unknown);
|
||||
if (databaseInstance <= 0)
|
||||
return Json(responseData.SetPopupMessage(messageTitle, "Database instance must be specified"));
|
||||
responseData.Instance = databaseInstance.ToString();
|
||||
|
||||
// Database connection.
|
||||
ISacsDatabase db = App.GetDatabase(SessionContext, databaseInstance);
|
||||
if (db == null)
|
||||
return Json(responseData.SetPopupMessage(messageTitle, "Unrecognised database instance specified: " + model.DatabaseFilter.Instance));
|
||||
|
||||
// Retrieve XML database schema definition.
|
||||
var assembly = typeof(SaxSystem_Dbas).GetTypeInfo().Assembly;
|
||||
String xmlSchema = SacsResourceHelper.GetManifestResourceAsText(assembly, "", "SaxDbDfn_" + databaseInstance.ToString() + ".xml");
|
||||
if (StringUtil.IsEmpty(xmlSchema))
|
||||
return Json(responseData.SetPopupMessage(messageTitle, "Failed to extract XML schema definition."));
|
||||
|
||||
// Extract schema from XML definition.
|
||||
SaDbProcess_ConvertDbSchema.Config cfgSchemaConvert = new SaDbProcess_ConvertDbSchema.Config();
|
||||
SaDbProcess_ConvertDbSchema procSchemaConvert = new SaDbProcess_ConvertDbSchema(cfgSchemaConvert);
|
||||
List<DbDfnTable> tables = procSchemaConvert.ConvertXmlToTables(xmlSchema);
|
||||
if (procSchemaConvert.HasErrorMessage())
|
||||
return Json(responseData.SetPopupMessage(messageTitle, "Failed to convert XML schema: " + procSchemaConvert.GetErrorMessage()));
|
||||
|
||||
SaDbProcess_CompareDatabaseSchemas.Config cfgSchemaCompare = new SaDbProcess_CompareDatabaseSchemas.Config(tables, db);
|
||||
cfgSchemaCompare.HideIdenticalObjects = true;
|
||||
cfgSchemaCompare.IgnorePosition = true;
|
||||
SaDbProcess_CompareDatabaseSchemas procSchemaCompare = new SaDbProcess_CompareDatabaseSchemas(cfgSchemaCompare);
|
||||
procSchemaCompare.OnSchemaComparisonItemAdded += OnSchemaComparisonItemAdded;
|
||||
procSchemaCompare.RunProcess();
|
||||
|
||||
List<SaDbProcess_CompareDatabaseSchemas.SchemaComparisonItem> schemaComparisonItems = procSchemaCompare.GetSchemaComparisonItems();
|
||||
foreach (SaDbProcess_CompareDatabaseSchemas.SchemaComparisonItem schemaComparisonItem in schemaComparisonItems)
|
||||
{
|
||||
DbSchemaItemResponseData item = new DbSchemaItemResponseData()
|
||||
{
|
||||
Id = schemaComparisonItem.Id,
|
||||
SchemaName = schemaComparisonItem.SchemaName,
|
||||
TableName = schemaComparisonItem.TableName,
|
||||
ColumnName = schemaComparisonItem.ColumnName,
|
||||
ColumnPosition = schemaComparisonItem.ColumnPosition,
|
||||
IndexName = schemaComparisonItem.IndexName,
|
||||
Comment = schemaComparisonItem.Comment
|
||||
};
|
||||
responseData.Items.Add(item);
|
||||
}
|
||||
}
|
||||
|
||||
// Complete response.
|
||||
responseData.Success = true;
|
||||
return Json(responseData);
|
||||
}
|
||||
|
||||
// Processing events.
|
||||
public void OnSchemaComparisonItemAdded(object sender, SaDbProcess_CompareDatabaseSchemas.SchemaComparisonItemAddedEventArgs e)
|
||||
{
|
||||
SaDbProcess_CompareDatabaseSchemas proc = sender as SaDbProcess_CompareDatabaseSchemas;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Database Table ajax request.
|
||||
//-------------------------------------------------------------------
|
||||
private class AjaxResponseData_Table
|
||||
{
|
||||
public AjaxResponseData_Table(DbDfnTable tableDfn)
|
||||
{
|
||||
Schema = tableDfn.Schema;
|
||||
Name = tableDfn.Name;
|
||||
if (!StringUtil.IsEmpty(tableDfn.Remarks))
|
||||
Remarks = tableDfn.Remarks;
|
||||
foreach (DbDfnColumn columnDfn in tableDfn.Columns)
|
||||
Columns.Add(new AjaxResponseData_Column(columnDfn));
|
||||
foreach (DbDfnIndex indexDfn in tableDfn.Indices)
|
||||
Indices.Add(new AjaxResponseData_Index(indexDfn));
|
||||
}
|
||||
public String Schema { get; }
|
||||
public String Name { get; }
|
||||
public String QualifiedName { get { return (!StringUtil.IsEmpty(Schema) ? Schema + "." : "") + Name; } }
|
||||
public String QuotedQualifiedName { get { return (!StringUtil.IsEmpty(Schema) ? "[" + Schema + "]." : "") + "[" + Name + "]"; } }
|
||||
public String Remarks { get; set; } = String.Empty;
|
||||
public List<AjaxResponse_Data.ItemLabelValue> Properties { get; } = new List<AjaxResponse_Data.ItemLabelValue>();
|
||||
public List<AjaxResponseData_Column> Columns { get; } = new List<AjaxResponseData_Column>();
|
||||
public List<AjaxResponseData_Index> Indices { get; } = new List<AjaxResponseData_Index>();
|
||||
}
|
||||
private class AjaxResponseData_Column
|
||||
{
|
||||
public int Pos { get; }
|
||||
public String Name { get; }
|
||||
public String Format { get; }
|
||||
public String DataTypeName { get; }
|
||||
public short? DataTypeNative { get; }
|
||||
public String DataTypeNameNative { get; }
|
||||
public bool? IsIdentity { get; }
|
||||
public long? Size { get; }
|
||||
public long? BufferLen { get; }
|
||||
public short? DecimalDigits { get; }
|
||||
public bool? Nullable { get; }
|
||||
public bool? IsNullable { get; }
|
||||
public String Remarks { get; }
|
||||
public AjaxResponseData_Column(DbDfnColumn columnDfn)
|
||||
{
|
||||
Pos = columnDfn.Pos;
|
||||
Name = columnDfn.Name;
|
||||
Format = columnDfn.GetFormat();
|
||||
if (!StringUtil.IsEmpty(columnDfn.DataTypeName))
|
||||
DataTypeName = columnDfn.DataTypeName;
|
||||
if (columnDfn.DataTypeNative > 0)
|
||||
DataTypeNative = columnDfn.DataTypeNative;
|
||||
if (!StringUtil.IsEmpty(columnDfn.DataTypeNameNative))
|
||||
DataTypeNameNative = columnDfn.DataTypeNameNative;
|
||||
if (columnDfn.IsIdentity)
|
||||
IsIdentity = columnDfn.IsIdentity;
|
||||
if (columnDfn.Size > 0)
|
||||
Size = columnDfn.Size;
|
||||
if (columnDfn.BufferLen > 0)
|
||||
BufferLen = columnDfn.BufferLen;
|
||||
if (columnDfn.DecimalDigits > 0)
|
||||
DecimalDigits = columnDfn.DecimalDigits;
|
||||
if (columnDfn.Nullable == DbColumnNullable.Nullable)
|
||||
Nullable = true;
|
||||
if (columnDfn.IsNullable)
|
||||
IsNullable = columnDfn.IsNullable;
|
||||
if (!StringUtil.IsEmpty(columnDfn.Remarks))
|
||||
Remarks = columnDfn.Remarks;
|
||||
}
|
||||
}
|
||||
private class AjaxResponseData_Index
|
||||
{
|
||||
public String Name { get; }
|
||||
public int? IndexType { get; }
|
||||
public bool? Unique { get; }
|
||||
public bool? Primary { get; }
|
||||
public bool? Clustered { get; }
|
||||
public bool? Nullable { get; }
|
||||
public int? Pages { get; }
|
||||
public int? UniqueValues { get; }
|
||||
public List<AjaxResponseData_IndexColumn> Columns { get; } = new List<AjaxResponseData_IndexColumn>();
|
||||
public AjaxResponseData_Index(DbDfnIndex indexDfn)
|
||||
{
|
||||
Name = indexDfn.Name;
|
||||
if (indexDfn.IndexType > 0)
|
||||
IndexType = indexDfn.IndexType;
|
||||
if (indexDfn.Unique)
|
||||
Unique = indexDfn.Unique;
|
||||
if (indexDfn.Primary)
|
||||
Primary = indexDfn.Primary;
|
||||
if (indexDfn.Clustered)
|
||||
Clustered = indexDfn.Clustered;
|
||||
if (indexDfn.Nullable)
|
||||
Nullable = indexDfn.Nullable;
|
||||
if (indexDfn.Pages > 0)
|
||||
Pages = indexDfn.Pages;
|
||||
if (indexDfn.UniqueValues > 0)
|
||||
UniqueValues = indexDfn.UniqueValues;
|
||||
foreach (DbDfnIndexColumn indexColumnDfn in indexDfn.Columns)
|
||||
Columns.Add(new AjaxResponseData_IndexColumn(indexColumnDfn));
|
||||
}
|
||||
}
|
||||
private class AjaxResponseData_IndexColumn
|
||||
{
|
||||
public short Seq { get; }
|
||||
public String Name { get; }
|
||||
public bool? Desc { get; }
|
||||
public AjaxResponseData_IndexColumn(DbDfnIndexColumn indexColumnDfn)
|
||||
{
|
||||
Seq = indexColumnDfn.Seq;
|
||||
Name = indexColumnDfn.Name;
|
||||
if (!indexColumnDfn.Ascend)
|
||||
Desc = true;
|
||||
}
|
||||
}
|
||||
private class AjaxResponse_DatabaseTable : AjaxResponse_Data
|
||||
{
|
||||
// Construction.
|
||||
public AjaxResponse_DatabaseTable(SaxModel_Admin model) : base(model) { }
|
||||
// Database table.
|
||||
public String PopupTitle { get; set; }
|
||||
public AjaxResponseData_Table Table { get; set; }
|
||||
}
|
||||
//-------------------------------------------------------------------
|
||||
[HttpPost]
|
||||
[Route("System/Ajax/GetDatabaseTable")]
|
||||
public IActionResult Ajax_GetDatabaseTable(Model_System model)
|
||||
{
|
||||
String fn = GetType().Name + ".Ajax_GetDatabaseTable";
|
||||
String messageTitle = Localiser["system.caption.database"];
|
||||
AjaxResponse_DatabaseTable responseData = new AjaxResponse_DatabaseTable(model);
|
||||
|
||||
// Validate session.
|
||||
if (!ValidUserSession)
|
||||
return GetAjaxResult_InvalidSession(responseData);
|
||||
|
||||
// Record disposable items as they are created so all can be disposed when needed.
|
||||
using (DisposableCollection<IDisposable> disposableItems = new DisposableCollection<IDisposable>())
|
||||
{
|
||||
|
||||
// Parameters.
|
||||
if (StringUtil.IsEmpty(model.DatabaseTable.Name))
|
||||
return Json(responseData.SetPopupMessage(messageTitle, "Table name must be supplied."));
|
||||
|
||||
// Database instance.
|
||||
Sax.Database databaseInstance = EnumUtil.ParseEnum(StringUtil.EmptyOnNull(model.DatabaseTable.Instance), Sax.Database.Unknown);
|
||||
if (databaseInstance <= 0)
|
||||
return Json(responseData.SetPopupMessage(messageTitle, "Database instance must be specified"));
|
||||
|
||||
// Database connection.
|
||||
ISacsDatabase db = App.GetDatabase(SessionContext, databaseInstance);
|
||||
|
||||
// Table definition.
|
||||
DbDfnTable tableDfn = db.GetTableDfn(model.DatabaseTable.Name, true);
|
||||
if (tableDfn == null)
|
||||
return Json(responseData.SetPopupMessage(messageTitle, "Invalid Table name supplied."));
|
||||
|
||||
// Populate table response.
|
||||
responseData.Table = new AjaxResponseData_Table(tableDfn);
|
||||
responseData.PopupTitle = Localiser["label.table"] + ": " + tableDfn.Name;
|
||||
|
||||
// Database sizing.
|
||||
String query = "Exec sp_SpaceUsed [" + tableDfn.QualifiedName + "];";
|
||||
using (DbResultSet dbResultSet = DbResultSet_DataReader.ExecuteQuery(db, query))
|
||||
{
|
||||
if (dbResultSet != null && dbResultSet.NextRecord())
|
||||
{
|
||||
// Row count.
|
||||
long rows = StringUtil.ToLong(dbResultSet.GetRecordValues().GetValue("rows").ToString());
|
||||
if (rows > 0)
|
||||
responseData.Table.Properties.Add(new AjaxResponse_Data.ItemLabelValue() { Label = "Rows", Value = rows.ToString() });
|
||||
// Reserved space.
|
||||
String reserved = dbResultSet.GetRecordValues().GetValue("reserved").AsString();
|
||||
if (!StringUtil.IsEmpty(reserved))
|
||||
responseData.Table.Properties.Add(new AjaxResponse_Data.ItemLabelValue() { Label = "Reserved", Value = reserved });
|
||||
// Data space.
|
||||
String data = dbResultSet.GetRecordValues().GetValue("data").AsString();
|
||||
if (!StringUtil.IsEmpty(data))
|
||||
responseData.Table.Properties.Add(new AjaxResponse_Data.ItemLabelValue() { Label = "Data", Value = data });
|
||||
// Index space.
|
||||
String index = dbResultSet.GetRecordValues().GetValue("index_size").AsString();
|
||||
if (!StringUtil.IsEmpty(index))
|
||||
responseData.Table.Properties.Add(new AjaxResponse_Data.ItemLabelValue() { Label = "Indices", Value = index });
|
||||
// Unused space.
|
||||
String unused = dbResultSet.GetRecordValues().GetValue("unused").AsString();
|
||||
if (!StringUtil.IsEmpty(unused))
|
||||
responseData.Table.Properties.Add(new AjaxResponse_Data.ItemLabelValue() { Label = "Unused", Value = unused });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Complete response.
|
||||
responseData.Success = true;
|
||||
return Json(responseData);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
}
|
||||
//=======================================================================
|
||||
}
|
||||
+301
@@ -0,0 +1,301 @@
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Sarand.Net.Standard.Base.App;
|
||||
using Sarand.Net.Standard.Base.Bus;
|
||||
using Sarand.Net.Standard.Base.Core;
|
||||
using Sarand.Net.Standard.Base.Dbas;
|
||||
using Sarand.Net.Standard.Base.IO;
|
||||
using Sarand.Net.Standard.Base.Utils;
|
||||
using Saxonite.Net.Core.Web.Admin.Models;
|
||||
using Saxonite.Net.Standard.Base.App;
|
||||
using Saxonite.Net.Standard.Base.Bus;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Saxonite.Net.Core.Web.Admin.Controllers.System
|
||||
{
|
||||
//=======================================================================
|
||||
// System - Ajax - Logs controller
|
||||
//=======================================================================
|
||||
partial class SystemController
|
||||
{
|
||||
//-------------------------------------------------------------------
|
||||
// Database data.
|
||||
private class LogFolderData
|
||||
{
|
||||
public String Name { get; set; }
|
||||
}
|
||||
private class LogFileData
|
||||
{
|
||||
public String Name { get; set; }
|
||||
public String UpdateFmt { get; set; }
|
||||
public long Size { get; set; }
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Get Log Folder List ajax request.
|
||||
//-------------------------------------------------------------------
|
||||
private class AjaxResponse_LogFolderList : AjaxResponse_Data
|
||||
{
|
||||
// Construction.
|
||||
public AjaxResponse_LogFolderList(SaxModel_Admin model) : base(model) { }
|
||||
// Log file list.
|
||||
public List<LogFolderData> Folders { get; } = new List<LogFolderData>();
|
||||
}
|
||||
//-------------------------------------------------------------------
|
||||
/// <summary>
|
||||
/// Retrieve the list of folders under the root folder.
|
||||
/// <para>- These should correspond to applications (admin, api, online etc).</para>
|
||||
/// </summary>
|
||||
[HttpPost]
|
||||
[Route("System/Ajax/Logs/GetFolderList")]
|
||||
[Route("System/Ajax/Logs/GetFolders")]
|
||||
public IActionResult Ajax_GetLogFolderList(Model_System model)
|
||||
{
|
||||
String fn = GetType().Name + ".Ajax_GetLogFolderList";
|
||||
String messageTitle = Localiser["system.caption.logs"];
|
||||
AjaxResponse_LogFolderList responseData = new AjaxResponse_LogFolderList(model);
|
||||
|
||||
// Validate session.
|
||||
if (!ValidUserSession)
|
||||
return GetAjaxResult_InvalidSession(responseData);
|
||||
|
||||
// Identify folders in root log folder.
|
||||
String rootLogFolder = model.LoggingRootFolder;
|
||||
foreach (String folder in Directory.EnumerateDirectories(rootLogFolder))
|
||||
{
|
||||
String folderName = Path.GetFileName(folder);
|
||||
if (folderName.IsMatch("^(Online|Admin|Api)$", RegexOptions.IgnoreCase))
|
||||
responseData.Folders.Add(new LogFolderData() { Name = folderName });
|
||||
}
|
||||
|
||||
// Complete response.
|
||||
responseData.Success = true;
|
||||
|
||||
return Json(responseData);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Get Log Year Folder List ajax request.
|
||||
//-------------------------------------------------------------------
|
||||
private class AjaxResponse_LogYearList : AjaxResponse_Data
|
||||
{
|
||||
// Construction.
|
||||
public AjaxResponse_LogYearList(SaxModel_Admin model) : base(model) { }
|
||||
// Log file list.
|
||||
public List<LogFolderData> Years { get; } = new List<LogFolderData>();
|
||||
}
|
||||
//-------------------------------------------------------------------
|
||||
/// <summary>
|
||||
/// Retrieve the list of year folders under the selected folder.
|
||||
/// </summary>
|
||||
[HttpPost]
|
||||
[Route("System/Ajax/Logs/GetYearList")]
|
||||
[Route("System/Ajax/Logs/GetYears")]
|
||||
public IActionResult Ajax_GetLogYearList(Model_System model)
|
||||
{
|
||||
String fn = GetType().Name + ".Ajax_GetLogYearList";
|
||||
String messageTitle = Localiser["system.caption.logs"];
|
||||
AjaxResponse_LogYearList responseData = new AjaxResponse_LogYearList(model);
|
||||
|
||||
// Validate session.
|
||||
if (!ValidUserSession)
|
||||
return GetAjaxResult_InvalidSession(responseData);
|
||||
|
||||
// Store filter properties to session.
|
||||
SessionData_Admin.System.Logs.Filter.Folder = model.LogsFilter.Folder;
|
||||
SessionData_Admin.System.Logs.Filter.Year = "";
|
||||
SessionData_Admin.System.Logs.Filter.Month = "";
|
||||
|
||||
// Identify folders in selected log folder.
|
||||
String logFolder = Path.Combine(model.LoggingRootFolder, model.LogsFilter.Folder);
|
||||
foreach (String folder in Directory.EnumerateDirectories(logFolder))
|
||||
{
|
||||
String folderName = Path.GetFileName(folder);
|
||||
if (folderName.IsMatch("^\\d{4}$"))
|
||||
responseData.Years.Add(new LogFolderData() { Name = folderName });
|
||||
}
|
||||
|
||||
// Complete response.
|
||||
responseData.Success = true;
|
||||
|
||||
return Json(responseData);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Get Log Month Folder List ajax request.
|
||||
//-------------------------------------------------------------------
|
||||
private class AjaxResponse_LogMonthList : AjaxResponse_Data
|
||||
{
|
||||
// Construction.
|
||||
public AjaxResponse_LogMonthList(SaxModel_Admin model) : base(model) { }
|
||||
// Log file list.
|
||||
public List<LogFolderData> Months { get; } = new List<LogFolderData>();
|
||||
}
|
||||
//-------------------------------------------------------------------
|
||||
/// <summary>
|
||||
/// Retrieve the list of year folders under the selected folder.
|
||||
/// </summary>
|
||||
[HttpPost]
|
||||
[Route("System/Ajax/Logs/GetMonthList")]
|
||||
[Route("System/Ajax/Logs/GetMonths")]
|
||||
public IActionResult Ajax_GetLogMonthList(Model_System model)
|
||||
{
|
||||
String fn = GetType().Name + ".Ajax_GetLogMonthList";
|
||||
String messageTitle = Localiser["system.caption.logs"];
|
||||
AjaxResponse_LogMonthList responseData = new AjaxResponse_LogMonthList(model);
|
||||
|
||||
// Validate session.
|
||||
if (!ValidUserSession)
|
||||
return GetAjaxResult_InvalidSession(responseData);
|
||||
|
||||
// Store filter properties to session.
|
||||
SessionData_Admin.System.Logs.Filter.Folder = model.LogsFilter.Folder;
|
||||
SessionData_Admin.System.Logs.Filter.Year = model.LogsFilter.Year;
|
||||
SessionData_Admin.System.Logs.Filter.Month = "";
|
||||
//SessionData_Admin.System.Logs.Filter.Month = model.LogsFilter.Month;
|
||||
|
||||
// Identify folders in selected year folder.
|
||||
String logFolder = Path.Combine(model.LoggingRootFolder, model.LogsFilter.Folder, model.LogsFilter.Year);
|
||||
foreach (String folder in Directory.EnumerateDirectories(logFolder))
|
||||
{
|
||||
String folderName = Path.GetFileName(folder);
|
||||
if (folderName.IsMatch("^\\d{6}$"))
|
||||
responseData.Months.Add(new LogFolderData() { Name = folderName });
|
||||
}
|
||||
|
||||
// Complete response.
|
||||
responseData.Success = true;
|
||||
|
||||
return Json(responseData);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Get Log File List ajax request.
|
||||
//-------------------------------------------------------------------
|
||||
private class AjaxResponse_LogFileList : AjaxResponse_Data
|
||||
{
|
||||
// Construction.
|
||||
public AjaxResponse_LogFileList(SaxModel_Admin model) : base(model) { }
|
||||
// Log file list.
|
||||
public List<LogFileData> Files { get; } = new List<LogFileData>();
|
||||
}
|
||||
//-------------------------------------------------------------------
|
||||
[HttpPost]
|
||||
[Route("System/Ajax/Logs/GetFileList")]
|
||||
[Route("System/Ajax/Logs/GetFiles")]
|
||||
public IActionResult Ajax_GetLogFileList(Model_System model)
|
||||
{
|
||||
String fn = GetType().Name + ".Ajax_GetLogFileList";
|
||||
String messageTitle = Localiser["system.caption.logs"];
|
||||
AjaxResponse_LogFileList responseData = new AjaxResponse_LogFileList(model);
|
||||
|
||||
// Validate session.
|
||||
if (!ValidUserSession)
|
||||
return GetAjaxResult_InvalidSession(responseData);
|
||||
|
||||
// Store filter properties to session.
|
||||
SessionData_Admin.System.Logs.Filter.Folder = model.LogsFilter.Folder;
|
||||
SessionData_Admin.System.Logs.Filter.Year = model.LogsFilter.Year;
|
||||
SessionData_Admin.System.Logs.Filter.Month = model.LogsFilter.Month;
|
||||
|
||||
// Identify folders in selected year folder.
|
||||
String logFolder = Path.Combine(model.LoggingRootFolder, model.LogsFilter.Folder, model.LogsFilter.Year, model.LogsFilter.Month);
|
||||
DirectoryInfo folder = new DirectoryInfo(logFolder);
|
||||
foreach (FileInfo file in folder.EnumerateFiles())
|
||||
{
|
||||
responseData.Files.Add(new LogFileData() { Name = file.Name, UpdateFmt = file.LastWriteTime.ToString("d-MMM-yy HH:mm"), Size = file.Length });
|
||||
}
|
||||
|
||||
// Complete response.
|
||||
responseData.Success = true;
|
||||
|
||||
return Json(responseData);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Get Log File ajax request.
|
||||
//-------------------------------------------------------------------
|
||||
private class AjaxResponse_LogFile : AjaxResponse_Data
|
||||
{
|
||||
// Construction.
|
||||
public AjaxResponse_LogFile(SaxModel_Admin model) : base(model) { }
|
||||
// Log file.
|
||||
public class LogFileData
|
||||
{
|
||||
public String Path { get; set; }
|
||||
public String Name { get; set; }
|
||||
public String Data { get; set; }
|
||||
public String Html { get; set; } = "";
|
||||
}
|
||||
public LogFileData File { get; } = new LogFileData();
|
||||
}
|
||||
//-------------------------------------------------------------------
|
||||
[HttpPost]
|
||||
[Route("System/Ajax/Logs/GetFile")]
|
||||
[Route("System/Ajax/Logs/GetLogFile")]
|
||||
public IActionResult Ajax_GetLogFile(Model_System model)
|
||||
{
|
||||
String fn = GetType().Name + ".Ajax_GetLogFile";
|
||||
String messageTitle = Localiser["system.caption.logs"];
|
||||
AjaxResponse_LogFile responseData = new AjaxResponse_LogFile(model);
|
||||
|
||||
// Validate session.
|
||||
if (!ValidUserSession)
|
||||
return GetAjaxResult_InvalidSession(responseData);
|
||||
|
||||
// Store filter properties to session.
|
||||
SessionData_Admin.System.Logs.Filter.Folder = model.LogsFilter.Folder;
|
||||
SessionData_Admin.System.Logs.Filter.Year = model.LogsFilter.Year;
|
||||
SessionData_Admin.System.Logs.Filter.Month = model.LogsFilter.Month;
|
||||
|
||||
// Identify folders in selected year folder.
|
||||
responseData.File.Path = Path.Combine(model.LoggingRootFolder, model.LogsFilter.Folder, model.LogsFilter.Year, model.LogsFilter.Month, model.LogsFilter.Filename);
|
||||
responseData.File.Name = Path.GetFileName(responseData.File.Path);
|
||||
try
|
||||
{
|
||||
String[] fileLines = FileUtil.ReadAllFileLines(responseData.File.Path);
|
||||
responseData.File.Data = String.Join("\n", fileLines);
|
||||
// Construct html data.
|
||||
foreach (var fileLine in fileLines)
|
||||
{
|
||||
String line = fileLine;
|
||||
List<String> classNames = new List<string>();
|
||||
if (fileLine.IsMatch("^\t{2}"))
|
||||
{
|
||||
line = Regex.Replace(fileLine, "^\t+", "");
|
||||
classNames.Add("tab2");
|
||||
}
|
||||
if (fileLine.IsMatch("^\t"))
|
||||
{
|
||||
line = Regex.Replace(fileLine, "^\t", "");
|
||||
classNames.Add("tab");
|
||||
}
|
||||
if (line.IsMatch("\\d{8}:\\d{6}\\s+(error|err)\\s+", RegexOptions.IgnoreCase))
|
||||
classNames.Add("err");
|
||||
else if (line.IsMatch("\\d{8}:\\d{6}\\s+(warn|wrn)\\s+", RegexOptions.IgnoreCase))
|
||||
classNames.Add("wrn");
|
||||
else if (line.IsMatch("\\d{8}:\\d{6}\\s+(info|inf)\\s+", RegexOptions.IgnoreCase))
|
||||
classNames.Add("inf");
|
||||
responseData.File.Html += $"<div class='{String.Join(" ", classNames)}'>" + line + "</div>";
|
||||
}
|
||||
}
|
||||
catch (Exception exc)
|
||||
{
|
||||
SaLogger.Warn($"{SysUtil.Fn} {ExceptionUtil.GetLogMessage(exc, "reading log file", 0)}");
|
||||
}
|
||||
|
||||
// Complete response.
|
||||
responseData.Success = true;
|
||||
|
||||
return Json(responseData);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
}
|
||||
//=======================================================================
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Sarand.Net.Standard.Base.App;
|
||||
using Sarand.Net.Standard.Base.Bus;
|
||||
using Sarand.Net.Standard.Base.Core;
|
||||
using Sarand.Net.Standard.Base.Utils;
|
||||
using Saxonite.Net.Core.Web.Admin.Models;
|
||||
using Saxonite.Net.Core.Web.Base.App;
|
||||
using Saxonite.Net.Core.Web.Base.Controllers;
|
||||
using Saxonite.Net.Standard.Base.Bus;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Saxonite.Net.Core.Web.Admin.Controllers.System
|
||||
{
|
||||
//=======================================================================
|
||||
public partial class SystemController : SaxController_Admin
|
||||
{
|
||||
//-------------------------------------------------------------------
|
||||
// Construction.
|
||||
public SystemController(SaxLocaliser localiser, ILogger<HomeController> logger) :
|
||||
base(localiser, logger)
|
||||
{
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
/// <summary>
|
||||
/// System - Home.
|
||||
/// <para>- No 'System' home page for now, redirect to home page.</para>
|
||||
/// </summary>
|
||||
[HttpGet]
|
||||
public IActionResult Index()
|
||||
{
|
||||
return RedirectToAction("", "");
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
/// <summary>
|
||||
/// System - Database page.
|
||||
/// </summary>
|
||||
[HttpGet]
|
||||
public IActionResult Database(Model_System model)
|
||||
{
|
||||
// Validate session.
|
||||
if (!ValidUserSession)
|
||||
AutoLoginUser();
|
||||
if (!ValidUserSession)
|
||||
return RedirectToAction("", "");
|
||||
|
||||
model.AdditionalFiles_JS.Add("js/sax-sys-db.js");
|
||||
return View(model);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
/// <summary>
|
||||
/// System - Logs page.
|
||||
/// </summary>
|
||||
[HttpGet]
|
||||
public IActionResult Logs(Model_System model)
|
||||
{
|
||||
// Validate session.
|
||||
if (!ValidUserSession)
|
||||
AutoLoginUser();
|
||||
if (!ValidUserSession)
|
||||
return RedirectToAction("", "");
|
||||
|
||||
model.AdditionalFiles_JS.Add("js/sax-sys-logs.js");
|
||||
model.LogsFilter.Folder = StringUtil.OnBlank(SessionData_Admin.System.Logs.Filter.Folder, "Admin");
|
||||
model.LogsFilter.Year = StringUtil.OnBlank(SessionData_Admin.System.Logs.Filter.Year, DateTime.Today.ToString("yyyy"));
|
||||
model.LogsFilter.Month = StringUtil.OnBlank(SessionData_Admin.System.Logs.Filter.Month, DateTime.Today.ToString("yyyyMM"));
|
||||
|
||||
return View(model);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
}
|
||||
//=======================================================================
|
||||
}
|
||||
@@ -0,0 +1,567 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Sarand.Net.Standard.Base.App;
|
||||
using Sarand.Net.Standard.Base.Bus;
|
||||
using Sarand.Net.Standard.Base.Core;
|
||||
using Sarand.Net.Standard.Base.Dbas;
|
||||
using Sarand.Net.Standard.Base.Utils;
|
||||
using Saxonite.Net.Core.Web.Admin.Models;
|
||||
using Saxonite.Net.Standard.Base.App;
|
||||
using Saxonite.Net.Standard.Base.Bus;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Saxonite.Net.Core.Web.Admin.Controllers
|
||||
{
|
||||
//=======================================================================
|
||||
partial class UserController
|
||||
{
|
||||
//-------------------------------------------------------------------
|
||||
// User data.
|
||||
private class UserListData : AjaxResponse_Data.ItemData_Base
|
||||
{
|
||||
public String EmailAddress { get; set; }
|
||||
public String DisplayName { get; set; }
|
||||
public String Title { get; set; }
|
||||
public String FirstName { get; set; }
|
||||
public String LastName { get; set; }
|
||||
public String RegionNameCountry { get; set; }
|
||||
public String RegionNameProvince { get; set; }
|
||||
public int? UserSportCount { get; set; } = null;
|
||||
public int? UserRoleCount { get; set; } = null;
|
||||
public bool? SystemAdmin { get; set; } = null;
|
||||
public String LastOnlineLoginAt { get; set; }
|
||||
public String LastAdminLoginAt { get; set; }
|
||||
}
|
||||
private class UserItemData : UserListData
|
||||
{
|
||||
public String RegionIdCountry { get; set; }
|
||||
public String RegionIdProvince { get; set; }
|
||||
// User sports.
|
||||
public class UserSportData
|
||||
{
|
||||
public String SportId { get; set; }
|
||||
public String SportName { get; set; }
|
||||
}
|
||||
public List<UserSportData> Sports { get; set; }
|
||||
// User roles.
|
||||
public List<String> userRoleCodes { get; } = new List<string>();
|
||||
}
|
||||
private void PopulateUserResponseListData(SaxModel_Admin model, UserListData data, SaxUserAccount user, List<SaxUserSport> userSports, List<SaxUserRole> userRoles)
|
||||
{
|
||||
data.Id = SysId.ToString(user.Id);
|
||||
data.EmailAddress = user.EmailAddress;
|
||||
data.DisplayName = user.GetDisplayName();
|
||||
data.Title = user.Title;
|
||||
data.FirstName = user.FirstName;
|
||||
data.LastName = user.LastName;
|
||||
data.RegionNameCountry = model.GetRegionName(user.RegionIdCountry);
|
||||
data.RegionNameProvince = model.GetRegionName(user.RegionIdProvince);
|
||||
// User sports.
|
||||
// User roles.
|
||||
if (userRoles?.GetUserRolesByStatus(SaStatus.Active).Count > 0)
|
||||
data.UserRoleCount = userRoles.GetUserRolesByStatus(SaStatus.Active).Count;
|
||||
data.SystemAdmin = (userRoles != null && userRoles.Exists(item => item.UserRole == Sax.UserRole.SystemAdmin) ? true : (bool?)null);
|
||||
data.LastOnlineLoginAt = model.FormatDateTimeForDisplay(user.LastLoginAt);
|
||||
data.StatusCode = user.StatusCode;
|
||||
data.StatusDesc = user.StatusDesc;
|
||||
// System Admin role.
|
||||
SaxUserRole userRole_SystemAdmin = userRoles.Find(item => item.UserRole == Sax.UserRole.SystemAdmin);
|
||||
if (userRole_SystemAdmin != null)
|
||||
data.LastAdminLoginAt = model.FormatDateTimeForDisplay(userRole_SystemAdmin.LastLoginAt);
|
||||
}
|
||||
private void PopulateUserResponseItemData(SaxModel_Admin model, UserItemData data, SaxUserAccount user, List<SaxUserSport> userSports, List<SaxUserRole> userRoles)
|
||||
{
|
||||
PopulateUserResponseListData(model, data, user, userSports, userRoles);
|
||||
|
||||
data.RegionIdCountry = SysId.ToString(user.RegionIdCountry);
|
||||
data.RegionIdProvince = SysId.ToString(user.RegionIdProvince);
|
||||
|
||||
// User sports.
|
||||
if (userSports != null && !userSports.IsEmpty())
|
||||
{
|
||||
data.Sports = new List<UserItemData.UserSportData>();
|
||||
List<SaxSport> sports = ReferenceMgr.GetSportListByIds(userSports.GetSportIds());
|
||||
foreach (SaxUserSport userSport in userSports)
|
||||
{
|
||||
SaxSport sport = sports.GetSportById(userSport.SportId);
|
||||
UserItemData.UserSportData userSportData = new UserItemData.UserSportData()
|
||||
{
|
||||
SportId = SysId.ToString(userSport.SportId),
|
||||
SportName = sport?.Name ?? null
|
||||
};
|
||||
data.Sports.Add(userSportData);
|
||||
}
|
||||
}
|
||||
|
||||
// User roles.
|
||||
if (userRoles != null)
|
||||
{
|
||||
foreach (SaxUserRole userRole in userRoles.GetUserRolesByStatus(SaStatus.Active))
|
||||
data.userRoleCodes.Add(UserRoleCodes.GetCodeForType(userRole.UserRole));
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Utilities.
|
||||
private List<SaxUserSport> GetUserSports(SysId userAccountId, SaxUserSport.StatusCat statusCat = SaxUserSport.StatusCat.NotDeleted)
|
||||
{
|
||||
if (!SysId.IsValid(userAccountId)) return new List<SaxUserSport>();
|
||||
SaxUserSport.Params prmUserSport = new SaxUserSport.Params();
|
||||
prmUserSport.UserAccountIdsIncluded.Add(userAccountId);
|
||||
prmUserSport.StatusCat = statusCat;
|
||||
return AccountMgr.GetUserSportList(prmUserSport);
|
||||
}
|
||||
private List<SaxUserRole> GetUserRoles(SysId userAccountId, SaxUserRole.StatusCat statusCat = SaxUserRole.StatusCat.NotDeleted)
|
||||
{
|
||||
if (!SysId.IsValid(userAccountId)) return new List<SaxUserRole>();
|
||||
SaxUserRole.Params prmUserRole = new SaxUserRole.Params();
|
||||
prmUserRole.UserAccountIdsIncluded.Add(userAccountId);
|
||||
prmUserRole.StatusCat = statusCat;
|
||||
return AccountMgr.GetUserRoleList(prmUserRole);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Get User List ajax request.
|
||||
//-------------------------------------------------------------------
|
||||
private class AjaxResponse_UserList : AjaxResponse_Data
|
||||
{
|
||||
// Construction.
|
||||
public AjaxResponse_UserList(SaxModel_Admin model) : base(model) { }
|
||||
// User list.
|
||||
public List<UserListData> Users { get; } = new List<UserListData>();
|
||||
// Reference data.
|
||||
public List<CodeDesc> UserRoles { get; } = new List<CodeDesc>();
|
||||
public List<CodeDesc> Statuses { get; } = new List<CodeDesc>();
|
||||
public String DefaultStatusCode { get; set; }
|
||||
}
|
||||
//-------------------------------------------------------------------
|
||||
[HttpPost]
|
||||
[Route("User/Ajax/GetList")]
|
||||
[Route("User/Ajax/GetUsers")]
|
||||
[Route("User/Ajax/GetUserList")]
|
||||
public IActionResult Ajax_GetUserList(Model_User model)
|
||||
{
|
||||
String fn = GetType().Name + ".Ajax_GetUserList";
|
||||
String messageTitle = Localiser["user.caption.users"];
|
||||
AjaxResponse_UserList responseData = new AjaxResponse_UserList(model);
|
||||
|
||||
// Validate session and referrer.
|
||||
if (!ValidReferer) return Forbid();
|
||||
if (!ValidUserSession) return GetAjaxResult_InvalidSession(responseData);
|
||||
RefreshModel(model);
|
||||
|
||||
// Reference data - user roles.
|
||||
foreach (TypeCodeDesc userRole in UserRoleCodes)
|
||||
responseData.UserRoles.Add(userRole.Code, Localiser.GetUserRoleCaption((Sax.UserRole)userRole.Type));
|
||||
responseData.DefaultStatusCode = SacsSystem.GetStatusCode(SaxUserAccount.DefaultStatus);
|
||||
|
||||
// Reference data - statuses.
|
||||
foreach (SaStatus status in SaxUserAccount.ValidStatuses.FindAll(item => item != SaStatus.Deleted))
|
||||
responseData.Statuses.Add(SacsSystem.GetStatusCode(status), Localiser.GetStatusCaption(status));
|
||||
|
||||
// Store filter values.
|
||||
SysId filterSportId = SysId.ToSysId(model.Filter.UserSportId);
|
||||
SessionData_Admin.Filter.SportId = SysId.IsValid(filterSportId) ? filterSportId : null;
|
||||
SysId filterRegionId = SysId.ToSysId(model.Filter.UserRegionId);
|
||||
SessionData_Admin.Filter.RegionId = SysId.IsValid(filterRegionId) ? filterRegionId : null;
|
||||
|
||||
// Item filter.
|
||||
SaxUserAccount.Params prmUserAccount = new SaxUserAccount.Params();
|
||||
prmUserAccount.UserFilterPartial = model.Filter.User;
|
||||
prmUserAccount.SportIdsIncluded.AddId(SysId.ToSysId(model.Filter.UserSportId));
|
||||
prmUserAccount.RegionIdsIncluded.AddId(SysId.ToSysId(model.Filter.UserRegionId));
|
||||
prmUserAccount.StatusCat = model.Filter.UserStatusCategoryCode != null ? model.FilterUserStatusCategory : SaxUserAccount.StatusCat.NotDeleted;
|
||||
model.Paging.ItemTotal = (ulong)AccountMgr.GetUserAccountCount(prmUserAccount);
|
||||
model.PopulatePagingTo(prmUserAccount.ResultsPaging);
|
||||
|
||||
// Item columns.
|
||||
ColumnDfn colId = AccountMgr.GetUserAccountColumnDfn(SaxUserAccount.Column.Id);
|
||||
ColumnDfn colEmail = AccountMgr.GetUserAccountColumnDfn(SaxUserAccount.Column.EmailAddress);
|
||||
ColumnDfn colTitle = AccountMgr.GetUserAccountColumnDfn(SaxUserAccount.Column.Title);
|
||||
ColumnDfn colFirstName = AccountMgr.GetUserAccountColumnDfn(SaxUserAccount.Column.FirstName);
|
||||
ColumnDfn colLastName = AccountMgr.GetUserAccountColumnDfn(SaxUserAccount.Column.LastName);
|
||||
ColumnDfn colCountryName = AccountMgr.GetUserAccountColumnDfn(SaxUserAccount.Column.RegionCountry_Name);
|
||||
ColumnDfn colProvinceName = AccountMgr.GetUserAccountColumnDfn(SaxUserAccount.Column.RegionProvince_Name);
|
||||
ColumnDfn colUserRoleCount = AccountMgr.GetUserAccountColumnDfn(SaxUserAccount.Column.UserRoleCount);
|
||||
ColumnDfn colSystemAdminUser = AccountMgr.GetUserAccountColumnDfn(SaxUserAccount.Column.SystemAdminUser);
|
||||
ColumnDfn colUserSportCount = AccountMgr.GetUserAccountColumnDfn(SaxUserAccount.Column.UserSportCount_Active);
|
||||
ColumnDfn colLastLogin = AccountMgr.GetUserAccountColumnDfn(SaxUserAccount.Column.LastLoginAt);
|
||||
ColumnDfn colAdminLastLogin = AccountMgr.GetUserAccountColumnDfn(SaxUserAccount.Column.LastAdminLoginAt);
|
||||
ColumnDfn colStatus = AccountMgr.GetUserAccountColumnDfn(SaxUserAccount.Column.Status);
|
||||
List<ColumnDfn> columns = new List<ColumnDfn>()
|
||||
{
|
||||
colId, colEmail, colTitle, colFirstName, colLastName,
|
||||
colCountryName, colProvinceName,
|
||||
colUserSportCount, colUserRoleCount,
|
||||
colSystemAdminUser, colLastLogin, colAdminLastLogin,
|
||||
colStatus
|
||||
};
|
||||
|
||||
// Query items.
|
||||
using (DbResultSet resultSet = AccountMgr.ExecuteUserAccountQuery(columns, prmUserAccount))
|
||||
{
|
||||
while (resultSet != null && resultSet.HasRows && resultSet.NextRecord())
|
||||
{
|
||||
NamedValue.Map values = resultSet.GetRecordValues();
|
||||
UserListData userData = new UserListData()
|
||||
{
|
||||
Id = values.GetString(colId.DataName),
|
||||
EmailAddress = values.GetString(colEmail.DataName),
|
||||
Title = values.GetString(colTitle.DataName),
|
||||
FirstName = values.GetString(colFirstName.DataName),
|
||||
LastName = values.GetString(colLastName.DataName),
|
||||
RegionNameCountry = values.GetString(colCountryName.DataName),
|
||||
RegionNameProvince = values.GetString(colProvinceName.DataName),
|
||||
UserSportCount = StringUtil.ToInt(values.GetString(colUserSportCount.DataName)),
|
||||
UserRoleCount = StringUtil.ToInt(values.GetString(colUserRoleCount.DataName)),
|
||||
SystemAdmin = StringUtil.ToBool(values.GetString(colSystemAdminUser.DataName)),
|
||||
LastOnlineLoginAt = model.FormatDateTimeForDisplay(values.GetDateTime(colLastLogin.DataName)),
|
||||
LastAdminLoginAt = model.FormatDateTimeForDisplay(values.GetDateTime(colAdminLastLogin.DataName)),
|
||||
StatusCode = values.GetString(colStatus.DataName),
|
||||
StatusDesc = SacsSystem.GetStatusDescForCode(values.GetString(colStatus.DataName))
|
||||
};
|
||||
if (userData.UserSportCount < 1) userData.UserSportCount = null;
|
||||
if (userData.UserRoleCount < 1) userData.UserRoleCount = null;
|
||||
if (userData.SystemAdmin == false) userData.SystemAdmin = null;
|
||||
userData.DisplayName = SaxUserAccount.GetDisplayName(userData.Title, userData.FirstName, userData.LastName);
|
||||
responseData.Users.Add(userData);
|
||||
}
|
||||
}
|
||||
if (model.Paging.IsPaged)
|
||||
model.Paging.ItemCount = (ushort)responseData.Users.Count;
|
||||
|
||||
// Complete response.
|
||||
responseData.SetPaging(model);
|
||||
responseData.Success = true;
|
||||
return Json(responseData);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Get User ajax request.
|
||||
//-------------------------------------------------------------------
|
||||
private class AjaxResponse_User : AjaxResponse_Data
|
||||
{
|
||||
// Construction.
|
||||
public AjaxResponse_User(SaxModel_Admin model) : base(model) { }
|
||||
// User details.
|
||||
public UserItemData user { get; } = new UserItemData();
|
||||
}
|
||||
//-------------------------------------------------------------------
|
||||
[HttpPost]
|
||||
[Route("User/Ajax/GetItem")]
|
||||
[Route("User/Ajax/GetUser")]
|
||||
public IActionResult Ajax_GetUser(Model_User model)
|
||||
{
|
||||
String fn = GetType().Name + ".Ajax_GetUser";
|
||||
String messageTitle = Localiser["user.caption.user"];
|
||||
AjaxResponse_User responseData = new AjaxResponse_User(model);
|
||||
|
||||
// Validate session and referrer.
|
||||
if (!ValidReferer) return Forbid();
|
||||
if (!ValidUserSession) return GetAjaxResult_InvalidSession(responseData);
|
||||
RefreshModel(model);
|
||||
|
||||
// Record disposable items as they are created so all can be disposed when needed.
|
||||
using (DisposableCollection<IDisposable> disposableItems = new DisposableCollection<IDisposable>())
|
||||
{
|
||||
|
||||
// Identify item.
|
||||
SysId userAccountId = SysId.ToSysId(model.UserId);
|
||||
if (!SysId.IsValid(userAccountId))
|
||||
return Json(responseData.SetPopupMessage(messageTitle, Localiser["msg.error.item.id.not.specified"]));
|
||||
|
||||
// Retrieve item.
|
||||
SaxUserAccount user = AccountMgr.GetUserAccountById(userAccountId);
|
||||
disposableItems.Add(user);
|
||||
if (user == null)
|
||||
{
|
||||
SaLogger.Warn(fn + " Failed to retrieve user for Id: '" + userAccountId + "'");
|
||||
return Json(responseData.SetPopupMessage(messageTitle, Localiser["msg.error.item.id.not.found"]));
|
||||
}
|
||||
|
||||
// User Sports.
|
||||
List<SaxUserSport> userSports = GetUserSports(user.Id, SaxUserSport.StatusCat.ActiveOnly);
|
||||
disposableItems.AddRange(userSports);
|
||||
|
||||
// User Roles.
|
||||
List<SaxUserRole> userRoles = GetUserRoles(user.Id, SaxUserRole.StatusCat.ActiveOnly);
|
||||
disposableItems.AddRange(userRoles);
|
||||
|
||||
// Construct response.
|
||||
PopulateUserResponseItemData(model, responseData.user, user, userSports, userRoles);
|
||||
responseData.Success = true;
|
||||
}
|
||||
return Json(responseData);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Get User by email ajax request.
|
||||
//-------------------------------------------------------------------
|
||||
[HttpPost]
|
||||
[Route("User/Ajax/GetUserByEmail")]
|
||||
public IActionResult Ajax_GetUserByEmail(Model_User model)
|
||||
{
|
||||
String fn = GetType().Name + ".Ajax_GetUserByEmail";
|
||||
String messageTitle = Localiser["user.caption.user"];
|
||||
AjaxResponse_User responseData = new AjaxResponse_User(model);
|
||||
StoreSessionData = false;
|
||||
|
||||
// Validate session and referrer.
|
||||
if (!ValidReferer) return Forbid();
|
||||
if (!ValidUserSession) return GetAjaxResult_InvalidSession(responseData);
|
||||
RefreshModel(model);
|
||||
|
||||
// Record disposable items as they are created so all can be disposed when needed.
|
||||
using (DisposableCollection<IDisposable> disposableItems = new DisposableCollection<IDisposable>())
|
||||
{
|
||||
|
||||
// Identify user.
|
||||
if (StringUtil.IsEmpty(model.UserEmailAddress))
|
||||
{
|
||||
SaLogger.Warn(fn + " Attempt to get user details with blank email.");
|
||||
return Json(responseData);
|
||||
}
|
||||
|
||||
// Retrieve user.
|
||||
SaxUserAccount user = AccountMgr.GetUserAccountByEmailAddress(model.UserEmailAddress);
|
||||
disposableItems.Add(user);
|
||||
if (user == null)
|
||||
{
|
||||
SaLogger.Warn(fn + " Failed to retrieve user for Email: " + model.UserEmailAddress);
|
||||
return Json(responseData);
|
||||
}
|
||||
|
||||
// User Sports.
|
||||
List<SaxUserSport> userSports = GetUserSports(user.Id, SaxUserSport.StatusCat.ActiveOnly);
|
||||
disposableItems.AddRange(userSports);
|
||||
|
||||
// User Roles.
|
||||
List<SaxUserRole> userRoles = GetUserRoles(user.Id, SaxUserRole.StatusCat.ActiveOnly);
|
||||
disposableItems.AddRange(userRoles);
|
||||
|
||||
// Construct response.
|
||||
PopulateUserResponseItemData(model, responseData.user, user, userSports, userRoles);
|
||||
responseData.Success = true;
|
||||
}
|
||||
return Json(responseData);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Store User ajax request.
|
||||
//-------------------------------------------------------------------
|
||||
[HttpPost]
|
||||
[Route("User/Ajax/StoreItem")]
|
||||
[Route("User/Ajax/StoreUser")]
|
||||
public IActionResult Ajax_StoreUser(Model_User model)
|
||||
{
|
||||
String fn = GetType().Name + ".Ajax_StoreUser";
|
||||
String messageTitle = Localiser["user.caption.user"];
|
||||
AjaxResponse_User responseData = new AjaxResponse_User(model);
|
||||
|
||||
// Validate session and referrer.
|
||||
if (!ValidReferer) return Forbid();
|
||||
if (!ValidUserSession) return GetAjaxResult_InvalidSession(responseData);
|
||||
RefreshModel(model);
|
||||
|
||||
// Validate item properties.
|
||||
model.ValidateUserData(responseData);
|
||||
if (responseData.HasControlErrors())
|
||||
return Json(responseData);
|
||||
|
||||
// Record disposable items as they are created so all can be disposed when needed.
|
||||
using (DisposableCollection<IDisposable> disposableItems = new DisposableCollection<IDisposable>())
|
||||
{
|
||||
|
||||
// Retrieve existing item.
|
||||
SysId userAccountId = SysId.ToSysId(model.UserId);
|
||||
SaxUserAccount user = AccountMgr.GetUserAccountById(userAccountId);
|
||||
disposableItems.Add(user);
|
||||
if (user == null && SysId.IsValid(userAccountId))
|
||||
{
|
||||
SaLogger.Warn(fn + " Failed to retrieve user for Id: '" + model.UserId + "'");
|
||||
return Json(responseData.SetPopupMessage(messageTitle, Localiser["msg.error.item.id.not.found"]));
|
||||
}
|
||||
|
||||
// User roles, including deleted in case of reassignment.
|
||||
List<SaxUserRole> userRoles = new List<SaxUserRole>();
|
||||
if (user != null) userRoles = GetUserRoles(user.Id, SaxUserRole.StatusCat.Any);
|
||||
disposableItems.AddRange(userRoles);
|
||||
if (model.UserRoleCodes != null)
|
||||
{
|
||||
List<String> userRoleCodes = model.GetUserRoleCodes();
|
||||
foreach (String userRoleCode in userRoleCodes)
|
||||
{
|
||||
// Role to activate.
|
||||
Sax.UserRole role = (Sax.UserRole)UserRoleCodes.GetTypeForCode(userRoleCode);
|
||||
SaxUserRole userRole = userRoles.GetUserRoleByRole(role);
|
||||
if (userRole == null)
|
||||
{
|
||||
userRole = AccountMgr.CreateUserRole(user?.Id, role);
|
||||
userRoles.Add(userRole);
|
||||
}
|
||||
userRole.Status = SaStatus.Active;
|
||||
}
|
||||
// Roles to deactivate.
|
||||
foreach (SaxUserRole userRole in userRoles)
|
||||
{
|
||||
if (!userRoleCodes.Exists(item => item.EqualsCI(UserRoleCodes.GetCodeForType(userRole.UserRole))))
|
||||
userRole.Status = SaStatus.Inactive;
|
||||
}
|
||||
}
|
||||
|
||||
// Create new item if required.
|
||||
if (user == null)
|
||||
{
|
||||
user = AccountMgr.CreateUserAccount();
|
||||
if (model.UserEmailAddress != null)
|
||||
user.EmailAddress = model.UserEmailAddress;
|
||||
}
|
||||
|
||||
// Populate item properties.
|
||||
if (model.UserTitle != null)
|
||||
user.Title = model.UserTitle;
|
||||
if (model.UserFirstName != null)
|
||||
user.FirstName = model.UserFirstName;
|
||||
if (model.UserLastName != null)
|
||||
user.LastName = model.UserLastName;
|
||||
if (model.UserRegionIdCountry != null)
|
||||
user.RegionIdCountry = SysId.ToSysId(model.UserRegionIdCountry);
|
||||
if (model.UserRegionIdProvince != null)
|
||||
user.RegionIdProvince = SysId.ToSysId(model.UserRegionIdProvince);
|
||||
if (model.UserStatusCode != null)
|
||||
user.Status = model.UserStatus;
|
||||
|
||||
// Store item.
|
||||
if (!SysId.IsValid(user.Id))
|
||||
{
|
||||
if (!AccountMgr.InsertUserAccount(user, DbUpdateInfo))
|
||||
{
|
||||
SaLogger.Warn(fn + " Failed to insert user: " + AccountMgr.ErrorStateMessage);
|
||||
return Json(responseData.SetPopupMessage(messageTitle, Localiser["msg.error.item.insert.failed"] + "\n\n" + AccountMgr.ErrorStateMessage));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!AccountMgr.UpdateUserAccount(user, DbUpdateInfo))
|
||||
{
|
||||
SaLogger.Warn(fn + " Failed to update user [Id:" + SysId.ToString(user.Id) + "]: " + AccountMgr.ErrorStateMessage);
|
||||
return Json(responseData.SetPopupMessage(messageTitle, Localiser["msg.error.item.update.failed"] + "\n\n" + AccountMgr.ErrorStateMessage));
|
||||
}
|
||||
}
|
||||
|
||||
if (model.UserRoleCodes != null)
|
||||
{
|
||||
// Associated data - User Roles.
|
||||
foreach (SaxUserRole userRole in (userRoles))
|
||||
{
|
||||
// Store User Role.
|
||||
if (!SysId.IsValid(userRole.Id))
|
||||
{
|
||||
// Apply User Account Id if not yet done (for new user).
|
||||
if (!SysId.IsValid(userRole.UserAccountId))
|
||||
userRole.UserAccountId = user.Id;
|
||||
if (!AccountMgr.InsertUserRole(userRole, DbUpdateInfo))
|
||||
SaLogger.Warn(fn + " Failed to insert user role: " + AccountMgr.ErrorStateMessage);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!AccountMgr.UpdateUserRole(userRole, DbUpdateInfo))
|
||||
SaLogger.Warn(fn + " Failed to update user role [Id:" + SysId.ToString(userRole.Id) + "]: " + AccountMgr.ErrorStateMessage);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// User Sports.
|
||||
List<SaxUserSport> userSports = GetUserSports(user.Id, SaxUserSport.StatusCat.ActiveOnly);
|
||||
disposableItems.AddRange(userSports);
|
||||
|
||||
// Construct response.
|
||||
PopulateUserResponseItemData(model, responseData.user, user, userSports, userRoles.GetUserRolesByStatus(SaStatus.Active));
|
||||
responseData.Success = true;
|
||||
}
|
||||
return Json(responseData);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Send User Emails ajax request.
|
||||
//-------------------------------------------------------------------
|
||||
[HttpPost]
|
||||
[Route("User/Ajax/SendEmails")]
|
||||
public IActionResult Ajax_SendEmails(Model_User model)
|
||||
{
|
||||
String fn = GetType().Name + ".Ajax_SendEmails";
|
||||
String messageTitle = Localiser["label.emails"];
|
||||
AjaxResponse_User responseData = new AjaxResponse_User(model);
|
||||
|
||||
// Validate session and referrer.
|
||||
if (!ValidReferer) return Forbid();
|
||||
if (!ValidUserSession) return GetAjaxResult_InvalidSession(responseData);
|
||||
RefreshModel(model);
|
||||
|
||||
// Record disposable items as they are created so all can be disposed when needed.
|
||||
using (DisposableCollection<IDisposable> disposableItems = new DisposableCollection<IDisposable>())
|
||||
{
|
||||
|
||||
// Retrieve user.
|
||||
SysId userAccountId = SysId.ToSysId(model.UserId);
|
||||
SaxUserAccount userAccount = AccountMgr.GetUserAccountById(userAccountId);
|
||||
disposableItems.Add(userAccount);
|
||||
if (userAccount == null)
|
||||
{
|
||||
SaLogger.Warn(fn + " Failed to retrieve user for Id: '" + model.UserId + "'");
|
||||
return Json(responseData.SetPopupMessage(messageTitle, Localiser["msg.error.item.id.not.found"]));
|
||||
}
|
||||
|
||||
// User roles.
|
||||
List<SaxUserRole> userRoles = GetUserRoles(userAccount.Id, SaxUserRole.StatusCat.Any);
|
||||
disposableItems.AddRange(userRoles);
|
||||
bool systemAdmin = userRoles.Exists(item => item.UserRole == Sax.UserRole.SystemAdmin);
|
||||
|
||||
// Email types to send.
|
||||
bool sendAcountActivationOnline = StringUtil.ToBool(model.UserEmailAcountActivationOnline);
|
||||
bool sendRequestPasswordOnline = StringUtil.ToBool(model.UserEmailRequestPasswordOnline);
|
||||
bool sendRequestPasswordAdmin = StringUtil.ToBool(model.UserEmailRequestPasswordAdmin);
|
||||
if (!sendAcountActivationOnline && !sendRequestPasswordOnline && !sendRequestPasswordAdmin)
|
||||
return Json(responseData.SetPopupMessage(messageTitle, Localiser["msg.validation.select.option"]));
|
||||
if (sendRequestPasswordAdmin && !systemAdmin)
|
||||
return Json(responseData.SetPopupMessage(messageTitle, Localiser["user.msg.not.system.admin"]));
|
||||
|
||||
// Send emails.
|
||||
int emailsSentCount = 0;
|
||||
if (sendAcountActivationOnline)
|
||||
{
|
||||
if (!OrganisationController.SendAccountActivatedEmail(this, userAccount))
|
||||
return Json(responseData.SetPopupMessage(messageTitle, "Failed to send Online Account Activation email."));
|
||||
emailsSentCount++;
|
||||
}
|
||||
if (sendRequestPasswordOnline)
|
||||
{
|
||||
if (!SecurityController.SendRequestPasswordEmail(this, userAccount, true))
|
||||
return Json(responseData.SetPopupMessage(messageTitle, "Failed to send Online Request Password email."));
|
||||
emailsSentCount++;
|
||||
}
|
||||
if (sendRequestPasswordAdmin)
|
||||
{
|
||||
if (!SecurityController.SendRequestPasswordEmail(this, userAccount, false))
|
||||
return Json(responseData.SetPopupMessage(messageTitle, "Failed to send Admin Request Password email."));
|
||||
emailsSentCount++;
|
||||
}
|
||||
|
||||
// User Sports.
|
||||
List<SaxUserSport> userSports = GetUserSports(userAccount.Id, SaxUserSport.StatusCat.ActiveOnly);
|
||||
disposableItems.AddRange(userSports);
|
||||
|
||||
// Construct response.
|
||||
PopulateUserResponseItemData(model, responseData.user, userAccount, userSports, userRoles.GetUserRolesByStatus(SaStatus.Active));
|
||||
responseData.SetNotifyMessage(messageTitle, "Emails sent: " + emailsSentCount);
|
||||
responseData.Success = true;
|
||||
}
|
||||
return Json(responseData);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
}
|
||||
//=======================================================================
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Sarand.Net.Standard.Base.Utils;
|
||||
using Saxonite.Net.Core.Web.Admin.Models;
|
||||
using Saxonite.Net.Core.Web.Base.App;
|
||||
using Saxonite.Net.Core.Web.Base.Controllers;
|
||||
using Saxonite.Net.Standard.Base.Bus;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Saxonite.Net.Core.Web.Admin.Controllers
|
||||
{
|
||||
//=======================================================================
|
||||
public partial class UserController : SaxController_Admin
|
||||
{
|
||||
//-------------------------------------------------------------------
|
||||
// Construction.
|
||||
public UserController(SaxLocaliser localiser, ILogger<HomeController> logger) :
|
||||
base(localiser, logger)
|
||||
{
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
[HttpGet]
|
||||
public IActionResult Index(String sta)
|
||||
{
|
||||
// Validate session.
|
||||
if (!ValidUserSession)
|
||||
AutoLoginUser();
|
||||
if (!ValidUserSession)
|
||||
return RedirectToAction("", "");
|
||||
|
||||
// Model.
|
||||
Model_User model = new Model_User(Localiser);
|
||||
|
||||
// Stored Sport filter.
|
||||
model.Filter.UserSportId = SessionData_Admin.Filter.SportId?.ToString() ?? null;
|
||||
using (SaxSport filterSport = ReferenceMgr.GetSportById(SessionData_Admin.Filter.SportId))
|
||||
model.Filter.UserSportName = Localiser.GetSportName(SessionData_Admin.Filter.SportId, filterSport?.Name ?? "");
|
||||
// Stored Region filter.
|
||||
model.Filter.UserRegionId = SessionData_Admin.Filter.RegionId?.ToString() ?? null;
|
||||
using (SaxRegion filterRegion = ReferenceMgr.GetRegionById(SessionData_Admin.Filter.RegionId))
|
||||
model.Filter.UserRegionName = Localiser.GetRegionName(SessionData_Admin.Filter.RegionId, filterRegion?.Name ?? "");
|
||||
|
||||
// Paging.
|
||||
model.Paging.PageNo = 1;
|
||||
model.Paging.PageLength = 12;
|
||||
|
||||
// Default status.
|
||||
if (sta.StartsWithCI("Awa"))
|
||||
model.Filter.UserStatusCategoryCode = nameof(SaxUserAccount.StatusCat.AwaitingOnly);
|
||||
|
||||
return View(model);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
}
|
||||
//=======================================================================
|
||||
}
|
||||
@@ -0,0 +1,190 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Sarand.Net.Standard.Base.App;
|
||||
using Sarand.Net.Standard.Base.Bus;
|
||||
using Sarand.Net.Standard.Base.Core;
|
||||
using Sarand.Net.Standard.Base.Dbas;
|
||||
using Sarand.Net.Standard.Base.Utils;
|
||||
using Saxonite.Net.Core.Web.Admin.Models;
|
||||
using Saxonite.Net.Standard.Base.App;
|
||||
using Saxonite.Net.Standard.Base.Bus;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Saxonite.Net.Core.Web.Admin.Controllers
|
||||
{
|
||||
//=======================================================================
|
||||
partial class UsersOnlineController
|
||||
{
|
||||
//-------------------------------------------------------------------
|
||||
// User data.
|
||||
private class UserListData : AjaxResponse_Data.ItemData_Base
|
||||
{
|
||||
public String EmailAddress { get; set; }
|
||||
public String DisplayName { get; set; }
|
||||
public String Title { get; set; }
|
||||
public String FirstName { get; set; }
|
||||
public String LastName { get; set; }
|
||||
public String LastLoginAt { get; set; }
|
||||
public String OnlineAt { get; set; }
|
||||
}
|
||||
private class UserItemData : UserListData
|
||||
{
|
||||
}
|
||||
private void PopulateUserResponseListData(SaxModel_Admin model, UserListData data, SaxUserAccount user, SaxUserOnline userOnline)
|
||||
{
|
||||
data.Id = SysId.ToString(user.Id);
|
||||
data.EmailAddress = user.EmailAddress;
|
||||
data.DisplayName = user.GetDisplayName();
|
||||
data.Title = user.Title;
|
||||
data.FirstName = user.FirstName;
|
||||
data.LastName = user.LastName;
|
||||
data.LastLoginAt = model.FormatDateTimeForDisplay(user.LastLoginAt);
|
||||
if (userOnline != null)
|
||||
data.OnlineAt = model.FormatDateTimeForDisplay(userOnline.OnlineAt);
|
||||
}
|
||||
private void PopulateUserResponseItemData(SaxModel_Admin model, UserItemData data, SaxUserAccount user, SaxUserOnline userOnline)
|
||||
{
|
||||
PopulateUserResponseListData(model, data, user, userOnline);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Utilities.
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Get User List ajax request.
|
||||
//-------------------------------------------------------------------
|
||||
private class AjaxResponse_UserList : AjaxResponse_Data
|
||||
{
|
||||
// Construction.
|
||||
public AjaxResponse_UserList(SaxModel_Admin model) : base(model) { }
|
||||
// User list.
|
||||
public List<UserListData> Users { get; } = new List<UserListData>();
|
||||
}
|
||||
//-------------------------------------------------------------------
|
||||
[HttpPost]
|
||||
[Route("UsersOnline/Ajax/GetList")]
|
||||
[Route("UsersOnline/Ajax/GetUsers")]
|
||||
[Route("UsersOnline/Ajax/GetUserList")]
|
||||
public IActionResult Ajax_GetUsersOnlineList(Model_User model)
|
||||
{
|
||||
String fn = GetType().Name + ".Ajax_GetUsersOnlineList";
|
||||
String messageTitle = Localiser["label.users.online"];
|
||||
AjaxResponse_UserList responseData = new AjaxResponse_UserList(model);
|
||||
|
||||
// Validate session and referrer.
|
||||
if (!ValidReferer) return Forbid();
|
||||
if (!ValidUserSession) return GetAjaxResult_InvalidSession(responseData);
|
||||
RefreshModel(model);
|
||||
|
||||
// Item filter.
|
||||
SaxUserOnline.Params prmUserOnline = new SaxUserOnline.Params();
|
||||
prmUserOnline.UserFilterPartial = model.Filter.User;
|
||||
prmUserOnline.SportIdsIncluded.AddId(SysId.ToSysId(model.Filter.UserSportId));
|
||||
prmUserOnline.RegionIdsIncluded.AddId(SysId.ToSysId(model.Filter.UserRegionId));
|
||||
model.Paging.ItemTotal = (ulong)AccountMgr.GetUserOnlineCount(prmUserOnline);
|
||||
model.PopulatePagingTo(prmUserOnline.ResultsPaging);
|
||||
|
||||
// Item columns.
|
||||
ColumnDfn colUserAccountId = AccountMgr.GetUserOnlineColumnDfn(SaxUserOnline.Column.UserAccountId);
|
||||
ColumnDfn colEmail = AccountMgr.GetUserOnlineColumnDfn(SaxUserOnline.Column.EmailAddress);
|
||||
ColumnDfn colTitle = AccountMgr.GetUserOnlineColumnDfn(SaxUserOnline.Column.Title);
|
||||
ColumnDfn colFirstName = AccountMgr.GetUserOnlineColumnDfn(SaxUserOnline.Column.FirstName);
|
||||
ColumnDfn colLastName = AccountMgr.GetUserOnlineColumnDfn(SaxUserOnline.Column.LastName);
|
||||
ColumnDfn colLastLogin = AccountMgr.GetUserOnlineColumnDfn(SaxUserOnline.Column.LastLoginAt);
|
||||
ColumnDfn colOnlineAt = AccountMgr.GetUserOnlineColumnDfn(SaxUserOnline.Column.OnlineAt);
|
||||
List<ColumnDfn> columns = new List<ColumnDfn>()
|
||||
{
|
||||
colUserAccountId,
|
||||
colEmail, colTitle, colFirstName, colLastName,
|
||||
colLastLogin, colOnlineAt
|
||||
};
|
||||
|
||||
// Query items.
|
||||
using (DbResultSet resultSet = AccountMgr.ExecuteUserOnlineQuery(columns, prmUserOnline))
|
||||
{
|
||||
while (resultSet != null && resultSet.HasRows && resultSet.NextRecord())
|
||||
{
|
||||
NamedValue.Map values = resultSet.GetRecordValues();
|
||||
UserListData userData = new UserListData()
|
||||
{
|
||||
Id = values.GetString(colUserAccountId.DataName),
|
||||
EmailAddress = values.GetString(colEmail.DataName),
|
||||
Title = values.GetString(colTitle.DataName),
|
||||
FirstName = values.GetString(colFirstName.DataName),
|
||||
LastName = values.GetString(colLastName.DataName),
|
||||
LastLoginAt = model.FormatDateTimeForDisplay(values.GetDateTime(colLastLogin.DataName)),
|
||||
OnlineAt = model.FormatDateTimeForDisplay(values.GetDateTime(colOnlineAt.DataName)),
|
||||
};
|
||||
userData.DisplayName = SaxUserAccount.GetDisplayName(userData.Title, userData.FirstName, userData.LastName);
|
||||
responseData.Users.Add(userData);
|
||||
}
|
||||
}
|
||||
if (model.Paging.IsPaged)
|
||||
model.Paging.ItemCount = (ushort)responseData.Users.Count;
|
||||
|
||||
// Complete response.
|
||||
responseData.SetPaging(model);
|
||||
responseData.Success = true;
|
||||
return Json(responseData);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Get User ajax request.
|
||||
//-------------------------------------------------------------------
|
||||
private class AjaxResponse_User : AjaxResponse_Data
|
||||
{
|
||||
// Construction.
|
||||
public AjaxResponse_User(SaxModel_Admin model) : base(model) { }
|
||||
// User details.
|
||||
public UserItemData user { get; } = new UserItemData();
|
||||
}
|
||||
//-------------------------------------------------------------------
|
||||
[HttpPost]
|
||||
[Route("UsersOnline/Ajax/GetItem")]
|
||||
[Route("UsersOnline/Ajax/GetUser")]
|
||||
public IActionResult Ajax_GetUser(Model_User model)
|
||||
{
|
||||
String fn = GetType().Name + ".Ajax_GetUser";
|
||||
String messageTitle = Localiser["user.caption.user"];
|
||||
AjaxResponse_User responseData = new AjaxResponse_User(model);
|
||||
|
||||
// Validate session and referrer.
|
||||
if (!ValidReferer) return Forbid();
|
||||
if (!ValidUserSession) return GetAjaxResult_InvalidSession(responseData);
|
||||
RefreshModel(model);
|
||||
|
||||
// Record disposable items as they are created so all can be disposed when needed.
|
||||
using (DisposableCollection<IDisposable> disposableItems = new DisposableCollection<IDisposable>())
|
||||
{
|
||||
|
||||
// Identify item.
|
||||
SysId userAccountId = SysId.ToSysId(model.UserId);
|
||||
if (!SysId.IsValid(userAccountId))
|
||||
return Json(responseData.SetPopupMessage(messageTitle, Localiser["msg.error.item.id.not.specified"]));
|
||||
|
||||
// Retrieve item.
|
||||
SaxUserAccount user = AccountMgr.GetUserAccountById(userAccountId);
|
||||
disposableItems.Add(user);
|
||||
if (user == null)
|
||||
{
|
||||
SaLogger.Warn(fn + " Failed to retrieve user for Id: '" + userAccountId + "'");
|
||||
return Json(responseData.SetPopupMessage(messageTitle, Localiser["msg.error.item.id.not.found"]));
|
||||
}
|
||||
|
||||
// User Online.
|
||||
SaxUserOnline userOnline = AccountMgr.GetUserOnlineByUserAccountId(user.Id);
|
||||
disposableItems.Add(userOnline);
|
||||
|
||||
// Construct response.
|
||||
PopulateUserResponseItemData(model, responseData.user, user, userOnline);
|
||||
responseData.Success = true;
|
||||
}
|
||||
return Json(responseData);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
}
|
||||
//=======================================================================
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Sarand.Net.Standard.Base.Utils;
|
||||
using Saxonite.Net.Core.Web.Admin.Models;
|
||||
using Saxonite.Net.Core.Web.Base.App;
|
||||
using Saxonite.Net.Core.Web.Base.Controllers;
|
||||
using Saxonite.Net.Standard.Base.Bus;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Saxonite.Net.Core.Web.Admin.Controllers
|
||||
{
|
||||
//=======================================================================
|
||||
public partial class UsersOnlineController : SaxController_Admin
|
||||
{
|
||||
//-------------------------------------------------------------------
|
||||
// Construction.
|
||||
public UsersOnlineController(SaxLocaliser localiser, ILogger<HomeController> logger) :
|
||||
base(localiser, logger)
|
||||
{
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
[HttpGet]
|
||||
public IActionResult Index(String sta)
|
||||
{
|
||||
// Validate session.
|
||||
if (!ValidUserSession)
|
||||
AutoLoginUser();
|
||||
if (!ValidUserSession)
|
||||
return RedirectToAction("", "");
|
||||
|
||||
// Paging.
|
||||
Model_UsersOnline model = new Model_UsersOnline(Localiser);
|
||||
model.Paging.PageNo = 1;
|
||||
model.Paging.PageLength = 12;
|
||||
|
||||
return View(model);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
}
|
||||
//=======================================================================
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
using Saxonite.Net.Core.Web.Base.App;
|
||||
using System;
|
||||
|
||||
namespace Saxonite.Net.Core.Web.Admin.Models
|
||||
{
|
||||
//=======================================================================
|
||||
public class ErrorViewModel : SaxModel_Admin
|
||||
{
|
||||
//-------------------------------------------------------------------
|
||||
// Construction.
|
||||
public ErrorViewModel(SaxLocaliser localiser) :
|
||||
base(localiser)
|
||||
{
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
public string RequestId { get; set; }
|
||||
|
||||
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
}
|
||||
//=======================================================================
|
||||
}
|
||||
@@ -0,0 +1,156 @@
|
||||
using Sacs.Web.Components;
|
||||
using Sarand.Net.Standard.Base.App;
|
||||
using Sarand.Net.Standard.Base.Bus;
|
||||
using Sarand.Net.Standard.Base.Core;
|
||||
using Sarand.Net.Standard.Base.Helpers;
|
||||
using Sarand.Net.Standard.Base.Utils;
|
||||
using Saxonite.Base.App;
|
||||
using Saxonite.Net.Core.Web.Base.App;
|
||||
using Saxonite.Net.Core.Web.Base.Controllers;
|
||||
using Saxonite.Net.Standard.Base.App;
|
||||
using Saxonite.Net.Standard.Base.Bus;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Saxonite.Net.Core.Web.Admin.Models
|
||||
{
|
||||
//=======================================================================
|
||||
/// <summary>
|
||||
/// Address model data properties.
|
||||
/// </summary>
|
||||
public class ModelData_Address : ModelData_Admin
|
||||
{
|
||||
//-------------------------------------------------------------------
|
||||
// Construction.
|
||||
public ModelData_Address(SaxModel_Admin model, String controlNameSuffix) : base(model)
|
||||
{
|
||||
this.ControlNameSuffix = StringUtil.EmptyOnNull(controlNameSuffix) + "Address";
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Properties.
|
||||
private String ControlNameSuffix { get; }
|
||||
// Address properties.
|
||||
public String Id { get; set; }
|
||||
public String Line1 { get; set; }
|
||||
public String Line2 { get; set; }
|
||||
public String Line3 { get; set; }
|
||||
public String Town { get; set; }
|
||||
public String Province { get; set; }
|
||||
public String RegionIdProvince { get; set; }
|
||||
public String RegionIdCountry { get; set; }
|
||||
public String PostalCode { get; set; }
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Utilities.
|
||||
/// <summary>Have any address values been supplied by the form.</summary>
|
||||
public bool IsSpecified()
|
||||
{
|
||||
if (Id != null || Line1 != null || Town != null || Province != null || RegionIdCountry != null || PostalCode != null)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
/// <summary>Have any address values been populated on the form.</summary>
|
||||
public bool IsPopulated()
|
||||
{
|
||||
if (SysId.IsValid(SysId.ToSysId(Id)) || !StringUtil.IsEmpty(Line1) || !StringUtil.IsEmpty(Town) || !StringUtil.IsEmpty(Province) || !StringUtil.IsEmpty(RegionIdCountry) || !StringUtil.IsEmpty(PostalCode))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Validation.
|
||||
//-------------------------------------------------------------------
|
||||
// Address.
|
||||
public bool ValidateAddressData(SaxModel_Admin model, SaController.AjaxResponse_Data responseData)
|
||||
{
|
||||
// Are any properties populated.
|
||||
bool populated = IsPopulated();
|
||||
|
||||
// Address Line 1 - optional.
|
||||
if (Line1 != null)
|
||||
{
|
||||
responseData.SetControlValue(ControlNameSuffix + "Line1", Line1);
|
||||
if (StringUtil.GetLength(Line1) > Model.GetControlMaxLength(SaxDbDfn_Core.ColumnIdx.ItemAddress_Line1))
|
||||
responseData.SetControlError(ControlNameSuffix + "Line1", Model.Localiser["msg.validation.maximum.length", Model.GetControlMaxLength(SaxDbDfn_Core.ColumnIdx.ItemAddress_Line1)]);
|
||||
}
|
||||
|
||||
// Address Line 2 - optional.
|
||||
if (Line2 != null)
|
||||
{
|
||||
responseData.SetControlValue(ControlNameSuffix + "Line2", Line2);
|
||||
if (!StringUtil.IsEmpty(Line2))
|
||||
{
|
||||
if (StringUtil.GetLength(Line2) > Model.GetControlMaxLength(SaxDbDfn_Core.ColumnIdx.ItemAddress_Line2))
|
||||
responseData.SetControlError(ControlNameSuffix + "Line2", Model.Localiser["msg.validation.maximum.length", Model.GetControlMaxLength(SaxDbDfn_Core.ColumnIdx.ItemAddress_Line2)]);
|
||||
}
|
||||
}
|
||||
|
||||
// Address Line 3 - optional.
|
||||
if (Line3 != null)
|
||||
{
|
||||
responseData.SetControlValue(ControlNameSuffix + "Line3", Line3);
|
||||
if (!StringUtil.IsEmpty(Line3))
|
||||
{
|
||||
if (StringUtil.GetLength(Line3) > Model.GetControlMaxLength(SaxDbDfn_Core.ColumnIdx.ItemAddress_Line3))
|
||||
responseData.SetControlError(ControlNameSuffix + "Line3", Model.Localiser["msg.validation.maximum.length", Model.GetControlMaxLength(SaxDbDfn_Core.ColumnIdx.ItemAddress_Line3)]);
|
||||
}
|
||||
}
|
||||
|
||||
// Address Town - mandatory if any value populated.
|
||||
if (Town != null)
|
||||
{
|
||||
String controlName = ControlNameSuffix + nameof(Town);
|
||||
responseData.SetControlValue(controlName, Town);
|
||||
if (StringUtil.IsEmpty(Town) && populated)
|
||||
responseData.SetControlError(controlName, Model.Localiser["msg.validation.mandatory.value"]);
|
||||
else if (StringUtil.GetLength(Town) > Model.GetControlMaxLength(SaxDbDfn_Core.ColumnIdx.ItemAddress_Town))
|
||||
responseData.SetControlError(controlName, Model.Localiser["msg.validation.maximum.length", Model.GetControlMaxLength(SaxDbDfn_Core.ColumnIdx.ItemAddress_Town)]);
|
||||
}
|
||||
|
||||
// Address Province - optional.
|
||||
if (Province != null)
|
||||
{
|
||||
String controlName = ControlNameSuffix + nameof(Province);
|
||||
responseData.SetControlValue(controlName, Province);
|
||||
if (!StringUtil.IsEmpty(Province))
|
||||
{
|
||||
if (StringUtil.GetLength(Province) > Model.GetControlMaxLength(SaxDbDfn_Core.ColumnIdx.ItemAddress_Province))
|
||||
responseData.SetControlError(controlName, Model.Localiser["msg.validation.maximum.length", Model.GetControlMaxLength(SaxDbDfn_Core.ColumnIdx.ItemAddress_Province)]);
|
||||
}
|
||||
}
|
||||
|
||||
// Address Country - mandatory if any value populated.
|
||||
if (RegionIdCountry != null)
|
||||
{
|
||||
String controlName = ControlNameSuffix + nameof(RegionIdCountry);
|
||||
if (!SysId.IsValid(SysId.ToSysId(RegionIdCountry)) && populated)
|
||||
responseData.SetControlError(controlName, Model.Localiser["msg.validation.mandatory.value"]);
|
||||
else if (SysId.IsValid(SysId.ToSysId(RegionIdCountry)))
|
||||
{
|
||||
SaxRegion.Data region = model.Internals.GetRegion(SysId.ToSysId(RegionIdCountry));
|
||||
if (region == null || region.RegionType != Sax.RegionType.Country)
|
||||
responseData.SetControlError(controlName, Model.Localiser["msg.validation.invalid.value"]);
|
||||
}
|
||||
}
|
||||
|
||||
// Address PostalCode - optional.
|
||||
if (PostalCode != null)
|
||||
{
|
||||
responseData.SetControlValue(ControlNameSuffix + "PostalCode", PostalCode);
|
||||
if (!StringUtil.IsEmpty(PostalCode))
|
||||
{
|
||||
if (StringUtil.GetLength(PostalCode) > Model.GetControlMaxLength(SaxDbDfn_Core.ColumnIdx.ItemAddress_PostalCode))
|
||||
responseData.SetControlError(ControlNameSuffix + "PostalCode", Model.Localiser["msg.validation.maximum.length", Model.GetControlMaxLength(SaxDbDfn_Core.ColumnIdx.ItemAddress_PostalCode)]);
|
||||
}
|
||||
}
|
||||
|
||||
return !responseData.HasControlErrors();
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
}
|
||||
//=======================================================================
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
using Sarand.Net.Standard.Base.App;
|
||||
using Sarand.Net.Standard.Base.Bus;
|
||||
using Sarand.Net.Standard.Base.Core;
|
||||
using Sarand.Net.Standard.Base.Helpers;
|
||||
using Sarand.Net.Standard.Base.Utils;
|
||||
using Saxonite.Base.App;
|
||||
using Saxonite.Net.Core.Web.Base.App;
|
||||
using Saxonite.Net.Core.Web.Base.Controllers;
|
||||
using Saxonite.Net.Standard.Base.App;
|
||||
using Saxonite.Net.Standard.Base.Bus;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Saxonite.Net.Core.Web.Admin.Models
|
||||
{
|
||||
//=======================================================================
|
||||
/// <summary>
|
||||
/// Online model data.
|
||||
/// </summary>
|
||||
public class ModelData_Admin
|
||||
{
|
||||
//-------------------------------------------------------------------
|
||||
// Construction.
|
||||
public ModelData_Admin(SaxModel_Admin model)
|
||||
{
|
||||
this.Model = model;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Properties.
|
||||
public SaxModel_Admin Model { get; }
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
}
|
||||
//=======================================================================
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
using Saxonite.Net.Core.Web.Base.App;
|
||||
using Saxonite.Net.Core.Web.Base.Models;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Saxonite.Net.Core.Web.Admin.Models
|
||||
{
|
||||
//=======================================================================
|
||||
public class Model_ContactMethod : SaxModel_Admin
|
||||
{
|
||||
//-------------------------------------------------------------------
|
||||
// Construction.
|
||||
public Model_ContactMethod(SaxLocaliser localiser) :
|
||||
base(localiser)
|
||||
{
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Form properties.
|
||||
public String ContactMethod { get; set; }
|
||||
public String ContactValue { get; set; }
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
}
|
||||
//=======================================================================
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
using Saxonite.Net.Core.Web.Base.App;
|
||||
using Saxonite.Net.Core.Web.Base.Models;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Saxonite.Net.Core.Web.Admin.Models
|
||||
{
|
||||
//=======================================================================
|
||||
public class Model_Home : SaxModel_Admin
|
||||
{
|
||||
//-------------------------------------------------------------------
|
||||
// Construction.
|
||||
public Model_Home(SaxLocaliser localiser) :
|
||||
base(localiser)
|
||||
{
|
||||
AdditionalFiles_JS.Add("js/sax-home.js");
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
}
|
||||
//=======================================================================
|
||||
}
|
||||
@@ -0,0 +1,245 @@
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc.Rendering;
|
||||
using Sarand.Net.Standard.Base.App;
|
||||
using Sarand.Net.Standard.Base.Bus;
|
||||
using Sarand.Net.Standard.Base.Core;
|
||||
using Sarand.Net.Standard.Base.Utils;
|
||||
using Saxonite.Base.App;
|
||||
using Saxonite.Net.Core.Web.Base.App;
|
||||
using Saxonite.Net.Core.Web.Base.Controllers;
|
||||
using Saxonite.Net.Standard.Base.App;
|
||||
using Saxonite.Net.Standard.Base.Bus;
|
||||
using Saxonite.Net.Standard.Base.Helpers;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Saxonite.Net.Core.Web.Admin.Models
|
||||
{
|
||||
//=======================================================================
|
||||
public class Model_Organisation : SaxModel_Admin
|
||||
{
|
||||
//-------------------------------------------------------------------
|
||||
// Construction.
|
||||
public Model_Organisation(SaxLocaliser localiser) :
|
||||
base(localiser)
|
||||
{
|
||||
AdditionalFiles_JS.Add("js/sax-org.js");
|
||||
Address = new ModelData_Address(this, "");
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Organisation filter properties.
|
||||
public class FilterData
|
||||
{
|
||||
public String Organisation { get; set; }
|
||||
public String OrganisationTypeCode { get; set; }
|
||||
public String OrganisationCategoryCode { get; set; }
|
||||
public String OrganisationSportId { get; set; }
|
||||
public String OrganisationSportName { get; set; }
|
||||
public String OrganisationRegionId { get; set; }
|
||||
public String OrganisationRegionName { get; set; }
|
||||
public String OrganisationStatusCategoryCode { get; set; }
|
||||
}
|
||||
public FilterData Filter { get; } = new FilterData();
|
||||
public Sax.OrganisationType FilterOrganisationType
|
||||
{
|
||||
get { return (Sax.OrganisationType)OrganisationTypeCodes.GetTypeForCode(Filter.OrganisationTypeCode); }
|
||||
}
|
||||
public Sax.OrganisationCategory FilterOrganisationCategory
|
||||
{
|
||||
get { return (Sax.OrganisationCategory)OrganisationCategoryCodes.GetTypeForCode(Filter.OrganisationCategoryCode); }
|
||||
}
|
||||
public SaxOrganisation.StatusCat FilterOrganisationStatusCategory
|
||||
{
|
||||
get { return EnumUtil.ParseEnum(Filter.OrganisationStatusCategoryCode, SaxOrganisation.StatusCat.Any); }
|
||||
}
|
||||
/// <summary>Organisation Status Categories for filter.</summary>
|
||||
public IEnumerable<SelectListItem> OrganisationFilterStatusCategoriesForSelect
|
||||
{
|
||||
get
|
||||
{
|
||||
List<CodeDesc> statusCategories = new List<CodeDesc>();
|
||||
statusCategories.Add(SaxOrganisation.StatusCat.Any.ToString(), Localiser["label.any"]);
|
||||
statusCategories.Add(SaxOrganisation.StatusCat.AwaitingOnly.ToString(), "Awaiting");
|
||||
statusCategories.Add(SaxOrganisation.StatusCat.ActiveOnly.ToString(), "Active");
|
||||
statusCategories.Add(SaxOrganisation.StatusCat.InactiveOnly.ToString(), "Inactive");
|
||||
statusCategories.Add(SaxOrganisation.StatusCat.NotDeleted.ToString(), "Not deleted");
|
||||
statusCategories.Add(SaxOrganisation.StatusCat.DeletedOnly.ToString(), "Deleted");
|
||||
return new SelectList(statusCategories, "Code", "Desc", SaxOrganisation.StatusCat.Any.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Organisation properties.
|
||||
public String OrganisationId { get; set; }
|
||||
public String OrganisationName { get; set; }
|
||||
public String OrganisationTypeValue { get; set; }
|
||||
public Sax.OrganisationType OrganisationType { get { return (Sax.OrganisationType)OrganisationTypeCodes.GetTypeForCode(OrganisationTypeValue); } }
|
||||
public String OrganisationCategoryValue { get; set; }
|
||||
public Sax.OrganisationCategory OrganisationCategory { get { return (Sax.OrganisationCategory)OrganisationCategoryCodes.GetTypeForCode(OrganisationCategoryValue); } }
|
||||
public String OrganisationSportId { get; set; }
|
||||
public String OrganisationRegionIdPrimary { get; set; }
|
||||
public String OrganisationAbout { get; set; }
|
||||
public String OrganisationFacilities { get; set; }
|
||||
// Common properties.
|
||||
public String OrganisationNotes { get; set; }
|
||||
public String OrganisationStatusCode { get; set; }
|
||||
public SaStatus OrganisationStatus { get { return SacsSystem.GetStatusForCode(OrganisationStatusCode); } }
|
||||
// Contact Methods.
|
||||
/// <summary>Placeholder field value to indicate the number of Contact Methods in form (even if none are populated).</summary>
|
||||
public String ContactMethods { get; set; }
|
||||
public String[] ContactMethod { get; set; }
|
||||
public String[] ContactValue { get; set; }
|
||||
/// <summary>Contact methods to be populated during validation.</summary>
|
||||
public SaxContactData ContactData { get; set; }
|
||||
// Address.
|
||||
public ModelData_Address Address { get; }
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Images.
|
||||
public List<IFormFile> OrganisationLogoImage { get; set; }
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Utilities.
|
||||
public bool IsSportMandatory()
|
||||
{
|
||||
return SaxOrganisation.IsSportMandatory(OrganisationCategory);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Validation.
|
||||
//-------------------------------------------------------------------
|
||||
// Organisation validation.
|
||||
public bool ValidateOrganisationData(SaxController_Base.AjaxResponse_Data responseData)
|
||||
{
|
||||
String fn = this.GetType().Name + ".ValidateOrganisationData";
|
||||
|
||||
// Organisation name.
|
||||
if (OrganisationName != null)
|
||||
{
|
||||
responseData.SetControlValue(nameof(OrganisationName), OrganisationName);
|
||||
if (StringUtil.IsEmpty(OrganisationName))
|
||||
responseData.SetControlError(nameof(OrganisationName), Localiser["msg.validation.mandatory.value"]);
|
||||
else if (StringUtil.GetLength(OrganisationName) > GetControlMaxLength(SaxDbDfn_Core.ColumnIdx.Organisation_Name))
|
||||
responseData.SetControlError(nameof(OrganisationName), Localiser["msg.validation.maximum.length", GetControlMaxLength(SaxDbDfn_Core.ColumnIdx.Organisation_Name)]);
|
||||
}
|
||||
|
||||
// Organisation type.
|
||||
if (OrganisationTypeValue != null)
|
||||
{
|
||||
if (StringUtil.IsEmpty(OrganisationTypeValue))
|
||||
responseData.SetControlError(nameof(OrganisationTypeValue), Localiser["msg.validation.mandatory.value"]);
|
||||
}
|
||||
|
||||
// Organisation category.
|
||||
if (OrganisationCategoryValue != null)
|
||||
{
|
||||
if (StringUtil.IsEmpty(OrganisationCategoryValue))
|
||||
responseData.SetControlError(nameof(OrganisationCategoryValue), Localiser["msg.validation.mandatory.value"]);
|
||||
}
|
||||
|
||||
// Organisation sport.
|
||||
if (OrganisationSportId != null)
|
||||
{
|
||||
if (SysId.IsValid(SysId.ToSysId(OrganisationSportId)) || IsSportMandatory())
|
||||
{
|
||||
using (SaxSport sport = ReferenceMgr.GetSportById(SysId.ToSysId(OrganisationSportId)))
|
||||
{
|
||||
if (sport == null)
|
||||
responseData.SetControlError(nameof(OrganisationSportId), Localiser["msg.validation.invalid.value"]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Organisation primary region.
|
||||
if (OrganisationRegionIdPrimary != null)
|
||||
{
|
||||
using (SaxRegion region = ReferenceMgr.GetRegionById(SysId.ToSysId(OrganisationRegionIdPrimary)))
|
||||
{
|
||||
if (region == null)
|
||||
responseData.SetControlError(nameof(OrganisationRegionIdPrimary), Localiser["msg.validation.invalid.value"]);
|
||||
else if (region.RegionType != Sax.RegionType.Country && region.RegionType != Sax.RegionType.Continent && region.RegionType != Sax.RegionType.World)
|
||||
responseData.SetControlError(nameof(OrganisationRegionIdPrimary), "Organisation region must be a country or international region");
|
||||
}
|
||||
|
||||
if (!StringUtil.IsEmpty(OrganisationName))
|
||||
{
|
||||
// Name must be unqiue within region.
|
||||
SaxOrganisation.Params prmOrganisation = new SaxOrganisation.Params();
|
||||
if (SysId.IsValid(SysId.ToSysId(OrganisationId)))
|
||||
prmOrganisation.IdsExcluded.Add(SysId.ToSysId(OrganisationId));
|
||||
prmOrganisation.NameFull = OrganisationName;
|
||||
prmOrganisation.RegionIdsIncluded.Add(SysId.ToSysId(OrganisationRegionIdPrimary));
|
||||
prmOrganisation.StatusCat = SaxOrganisation.StatusCat.Any;
|
||||
if (AccountMgr.GetOrganisationCount(prmOrganisation) > 0)
|
||||
responseData.SetControlError(nameof(OrganisationName), Localiser["msg.validation.duplicate.value"]);
|
||||
}
|
||||
}
|
||||
|
||||
// Organisation about.
|
||||
if (OrganisationAbout != null)
|
||||
{
|
||||
responseData.SetControlValue(nameof(OrganisationAbout), OrganisationAbout);
|
||||
if (StringUtil.GetLength(OrganisationAbout) > GetControlMaxLength(SaxDbDfn_Core.ColumnIdx.Organisation_About))
|
||||
responseData.SetControlError(nameof(OrganisationAbout), Localiser["msg.validation.maximum.length", GetControlMaxLength(SaxDbDfn_Core.ColumnIdx.Organisation_About)]);
|
||||
}
|
||||
|
||||
// Organisation facilities.
|
||||
if (OrganisationFacilities != null)
|
||||
{
|
||||
responseData.SetControlValue(nameof(OrganisationFacilities), OrganisationFacilities);
|
||||
if (StringUtil.GetLength(OrganisationFacilities) > GetControlMaxLength(SaxDbDfn_Core.ColumnIdx.Organisation_Facilities))
|
||||
responseData.SetControlError(nameof(OrganisationFacilities), Localiser["msg.validation.maximum.length", GetControlMaxLength(SaxDbDfn_Core.ColumnIdx.Organisation_Facilities)]);
|
||||
}
|
||||
|
||||
// Contact Methods.
|
||||
if (ContactMethods != null)
|
||||
{
|
||||
ContactData = new SaxContactData("");
|
||||
ContactMethod = ContactMethod ?? new String[0];
|
||||
ContactValue = ContactValue ?? new String[0];
|
||||
for (int idx = 0; idx < ContactMethod.Length && idx < ContactValue.Length; idx++)
|
||||
{
|
||||
String methodValue = ContactMethod[idx];
|
||||
String value = ContactValue[idx];
|
||||
if (methodValue == null && value == null) continue;
|
||||
Sax.ContactMethod method = EnumUtil.ParseEnum(methodValue, Sax.ContactMethod.Unknown);
|
||||
if (method > 0 && !value.IsEmpty() && SaxContactMethodHelper.IsValidContactMethodValue(method, value))
|
||||
ContactData.SetContactMethodValue(method, value);
|
||||
else SaLogger.Warn(fn + " Invalid Contact Method data. Method: " + methodValue + ". Value: " + value);
|
||||
}
|
||||
if (ContactData.Methods.Count != ContactMethods.ToInt())
|
||||
{
|
||||
SaLogger.Warn(fn + " Inconsistent Contact Methods received. Expected: " + ContactMethods + ". Received: " + ContactData.Methods.Count);
|
||||
responseData.SetPopupMessage(Localiser["caption.contact.method"], "System error");
|
||||
}
|
||||
}
|
||||
|
||||
// Organisation notes.
|
||||
if (OrganisationNotes != null)
|
||||
{
|
||||
responseData.SetControlValue(nameof(OrganisationNotes), OrganisationNotes);
|
||||
if (StringUtil.GetLength(OrganisationNotes) > GetControlMaxLength(SaxDbDfn_Core.ColumnIdx.Organisation_Notes))
|
||||
responseData.SetControlError(nameof(OrganisationNotes), Localiser["msg.validation.maximum.length", GetControlMaxLength(SaxDbDfn_Core.ColumnIdx.Organisation_Notes)]);
|
||||
}
|
||||
|
||||
// Organisation status.
|
||||
if (OrganisationStatusCode != null)
|
||||
{
|
||||
if (StringUtil.IsEmpty(OrganisationStatusCode))
|
||||
responseData.SetControlError(nameof(OrganisationStatus), Localiser["msg.validation.mandatory.value"]);
|
||||
else if (!SaxOrganisation.ValidStatuses.Contains(OrganisationStatus))
|
||||
responseData.SetControlError(nameof(OrganisationStatus), Localiser["msg.validation.invalid.value"]);
|
||||
}
|
||||
|
||||
// Validate address fields.
|
||||
if (Address != null)
|
||||
Address.ValidateAddressData(this, responseData);
|
||||
|
||||
return !responseData.HasControlErrors();
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
}
|
||||
//=======================================================================
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
using Sarand.Net.Standard.Base.App;
|
||||
using Sarand.Net.Standard.Base.Bus;
|
||||
using Sarand.Net.Standard.Base.Core;
|
||||
using Sarand.Net.Standard.Base.Utils;
|
||||
using Saxonite.Base.App;
|
||||
using Saxonite.Net.Core.Web.Base.App;
|
||||
using Saxonite.Net.Core.Web.Base.Controllers;
|
||||
using Saxonite.Net.Core.Web.Base.Models;
|
||||
using Saxonite.Net.Standard.Base.App;
|
||||
using Saxonite.Net.Standard.Base.Bus;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Saxonite.Net.Core.Web.Admin.Models
|
||||
{
|
||||
//=======================================================================
|
||||
/// <summary>
|
||||
/// Model for Organisation Activation.
|
||||
/// <para>NB Only used for Ajax activation request.</para>
|
||||
/// </summary>
|
||||
public class Model_OrganisationActivation : SaxModel_Admin
|
||||
{
|
||||
//-------------------------------------------------------------------
|
||||
// Construction.
|
||||
public Model_OrganisationActivation(SaxLocaliser localiser) :
|
||||
base(localiser)
|
||||
{
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Organisation properties.
|
||||
public String OrganisationId { get; set; }
|
||||
/// <summary>
|
||||
/// List of User Organisation Ids that were offered for activation.
|
||||
/// </summary>
|
||||
public List<String> OrganisationMemberIds { get; set; }
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
}
|
||||
//=======================================================================
|
||||
}
|
||||
@@ -0,0 +1,149 @@
|
||||
using Sarand.Net.Standard.Base.App;
|
||||
using Sarand.Net.Standard.Base.Bus;
|
||||
using Sarand.Net.Standard.Base.Core;
|
||||
using Sarand.Net.Standard.Base.Utils;
|
||||
using Saxonite.Base.App;
|
||||
using Saxonite.Net.Core.Web.Base.App;
|
||||
using Saxonite.Net.Core.Web.Base.Controllers;
|
||||
using Saxonite.Net.Core.Web.Base.Models;
|
||||
using Saxonite.Net.Standard.Base.App;
|
||||
using Saxonite.Net.Standard.Base.Bus;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Saxonite.Net.Core.Web.Admin.Models
|
||||
{
|
||||
//=======================================================================
|
||||
public class Model_OrganisationAssociations : SaxModel_Admin
|
||||
{
|
||||
//-------------------------------------------------------------------
|
||||
// Definitions.
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Construction.
|
||||
public Model_OrganisationAssociations(SaxLocaliser localiser) :
|
||||
base(localiser)
|
||||
{
|
||||
AdditionalFiles_JS.Add("js/sax-org-ass.js");
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// List configuration.
|
||||
public class FilterData
|
||||
{
|
||||
public String OrganisationId { get; set; }
|
||||
public String OrganisationName { get; set; }
|
||||
}
|
||||
public FilterData Filter { get; } = new FilterData();
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Item association.
|
||||
public String ItemAssociationId { get; set; }
|
||||
/// <summary>Flag to indicate that a new association needs to be created - must be consistent with validity of Item Association Id.</summary>
|
||||
public String NewItem { get; set; }
|
||||
// Organisation.
|
||||
public String OrganisationId { get; set; }
|
||||
// Associated organisation.
|
||||
public String OrganisationIdAssoc { get; set; }
|
||||
public class AssociationData
|
||||
{
|
||||
// Association type option.
|
||||
public String TypeOption { get; set; }
|
||||
public Sax.AssociationTypeOption GetAssociationTypeOption() { return EnumUtil.ParseEnum(TypeOption, Sax.AssociationTypeOption.Unknown); }
|
||||
// Association properties.
|
||||
public String StatusCode { get; set; }
|
||||
public SaStatus GetStatus() { return SacsSystem.GetStatusForCode(StatusCode); }
|
||||
}
|
||||
public AssociationData Association { get; } = new AssociationData();
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Utilities.
|
||||
public bool IsAssociationTypeDirectionReversed(Sax.AssociationTypeOption associationTypeOption)
|
||||
{
|
||||
switch (associationTypeOption)
|
||||
{
|
||||
case Sax.AssociationTypeOption.AffiliateChild:
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
public Sax.AssociationType GetAssociationTypeForOption(Sax.AssociationTypeOption associationTypeOption)
|
||||
{
|
||||
switch (associationTypeOption)
|
||||
{
|
||||
case Sax.AssociationTypeOption.AffiliateParent:
|
||||
case Sax.AssociationTypeOption.AffiliateChild:
|
||||
return Sax.AssociationType.Affiliate;
|
||||
case Sax.AssociationTypeOption.Partner:
|
||||
return Sax.AssociationType.Partner;
|
||||
}
|
||||
return Sax.AssociationType.Unknown;
|
||||
}
|
||||
public bool IsConsistentWith(Sax.AssociationTypeOption associationTypeOption, Sax.AssociationType associationType)
|
||||
{
|
||||
switch (associationType)
|
||||
{
|
||||
case Sax.AssociationType.Affiliate:
|
||||
return new List<Sax.AssociationTypeOption>() { Sax.AssociationTypeOption.AffiliateChild, Sax.AssociationTypeOption.AffiliateParent }.Contains(associationTypeOption);
|
||||
case Sax.AssociationType.Partner:
|
||||
return new List<Sax.AssociationTypeOption>() { Sax.AssociationTypeOption.Partner }.Contains(associationTypeOption);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Validation.
|
||||
//-------------------------------------------------------------------
|
||||
// Organisation association validation.
|
||||
public bool ValidateOrganisationAssociationData(SaxController_Base.AjaxResponse_Data responseData)
|
||||
{
|
||||
|
||||
// Associated Organisation.
|
||||
if (OrganisationIdAssoc != null)
|
||||
{
|
||||
// Mandatory.
|
||||
String controlName = "OrganisationIdAssoc";
|
||||
if (!SysId.IsValid(SysId.ToSysId(OrganisationIdAssoc)))
|
||||
responseData.SetControlError(controlName, Localiser["msg.validation.mandatory.value"]);
|
||||
// Must exist.
|
||||
else if (!AccountMgr.OrganisationExistsById(SysId.ToSysId(OrganisationIdAssoc)))
|
||||
responseData.SetControlError(controlName, Localiser["msg.validation.invalid.value"]);
|
||||
// Not same as primary organisation.
|
||||
else if (OrganisationId != null && SysId.ToSysId(OrganisationId).Equals(SysId.ToSysId(OrganisationIdAssoc)))
|
||||
responseData.SetControlError(controlName, Localiser["msg.validation.invalid.value"]);
|
||||
}
|
||||
|
||||
// Association type option.
|
||||
if (Association.TypeOption != null)
|
||||
{
|
||||
// Mandatory.
|
||||
String controlName = "AssociationTypeOption";
|
||||
if (StringUtil.IsEmpty(Association.TypeOption))
|
||||
responseData.SetControlError(controlName, Localiser["msg.validation.mandatory.value"]);
|
||||
// Valid value.
|
||||
else if ((int)Association.GetAssociationTypeOption() < 1)
|
||||
responseData.SetControlError(controlName, Localiser["msg.validation.invalid.value"]);
|
||||
}
|
||||
|
||||
// Association status.
|
||||
if (Association.StatusCode != null)
|
||||
{
|
||||
// Mandatory.
|
||||
String controlName = "AssociationStatus";
|
||||
if (StringUtil.IsEmpty(Association.StatusCode))
|
||||
responseData.SetControlError(controlName, Localiser["msg.validation.mandatory.value"]);
|
||||
// Valid value.
|
||||
else if (!SaxOrganisation.ValidStatuses.Contains(Association.GetStatus()))
|
||||
responseData.SetControlError(controlName, Localiser["msg.validation.invalid.value"]);
|
||||
}
|
||||
|
||||
return !responseData.HasControlErrors();
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
}
|
||||
//=======================================================================
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Sarand.Net.Standard.Base.App;
|
||||
using Sarand.Net.Standard.Base.Bus;
|
||||
using Sarand.Net.Standard.Base.Core;
|
||||
using Sarand.Net.Standard.Base.Utils;
|
||||
using Sarand.Net.Standard.Proc.Excel;
|
||||
using Saxonite.Base.App;
|
||||
using Saxonite.Net.Core.Web.Base.App;
|
||||
using Saxonite.Net.Core.Web.Base.Controllers;
|
||||
using Saxonite.Net.Core.Web.Base.Models;
|
||||
using Saxonite.Net.Standard.Base.App;
|
||||
using Saxonite.Net.Standard.Base.Bus;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Saxonite.Net.Core.Web.Admin.Models
|
||||
{
|
||||
//=======================================================================
|
||||
/// <summary>
|
||||
/// Model for Organisation Download.
|
||||
/// </summary>
|
||||
public class Model_OrganisationDownload : Model_Organisation
|
||||
{
|
||||
//-------------------------------------------------------------------
|
||||
// Construction.
|
||||
public Model_OrganisationDownload(SaxLocaliser localiser) :
|
||||
base(localiser)
|
||||
{
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Properties.
|
||||
public String IncludeId { get; set; }
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Validation.
|
||||
//-------------------------------------------------------------------
|
||||
public bool ValidateProperties()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
}
|
||||
//=======================================================================
|
||||
}
|
||||
@@ -0,0 +1,110 @@
|
||||
using Sarand.Net.Standard.Base.App;
|
||||
using Sarand.Net.Standard.Base.Bus;
|
||||
using Sarand.Net.Standard.Base.Core;
|
||||
using Sarand.Net.Standard.Base.Utils;
|
||||
using Saxonite.Base.App;
|
||||
using Saxonite.Net.Core.Web.Base.App;
|
||||
using Saxonite.Net.Core.Web.Base.Controllers;
|
||||
using Saxonite.Net.Core.Web.Base.Models;
|
||||
using Saxonite.Net.Standard.Base.App;
|
||||
using Saxonite.Net.Standard.Base.Bus;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Saxonite.Net.Core.Web.Admin.Models
|
||||
{
|
||||
//=======================================================================
|
||||
public class Model_OrganisationMembers : SaxModel_Admin
|
||||
{
|
||||
//-------------------------------------------------------------------
|
||||
// Construction.
|
||||
public Model_OrganisationMembers(SaxLocaliser localiser) :
|
||||
base(localiser)
|
||||
{
|
||||
AdditionalFiles_JS.Add("js/sax-org-mbr.js");
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// List configuration.
|
||||
public class FilterData
|
||||
{
|
||||
public String OrganisationId { get; set; }
|
||||
public String OrganisationName { get; set; }
|
||||
}
|
||||
public FilterData Filter { get; } = new FilterData();
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Organisation.
|
||||
public String OrganisationId { get; set; }
|
||||
// User Organisation (member) properties.
|
||||
public String UserOrganisationId { get; set; }
|
||||
[EmailAddress]
|
||||
public String MemberUserEmailAddress{ get; set; }
|
||||
public String MemberUserAccountId { get; set; }
|
||||
public String MemberOrganisationId { get; set; }
|
||||
public String MemberRoleCodeDelim = ",";
|
||||
public List<String> MemberRoleCodes { get; set; }
|
||||
public List<String> GetMemberRoleCodes()
|
||||
{
|
||||
List<String> codes = new List<string>();
|
||||
foreach (String code in MemberRoleCodes)
|
||||
{
|
||||
if (StringUtil.IsEmpty(code)) continue;
|
||||
codes.AddRange(code.Split(MemberRoleCodeDelim));
|
||||
}
|
||||
return codes;
|
||||
}
|
||||
public String MemberStatusCode { get; set; }
|
||||
public SaStatus MemberStatus { get { return SacsSystem.GetStatusForCode(MemberStatusCode); } }
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Validation.
|
||||
//-------------------------------------------------------------------
|
||||
// Organisation member validation.
|
||||
public bool ValidateOrganisationMemberData(SaxController_Base.AjaxResponse_Data responseData)
|
||||
{
|
||||
// User email address.
|
||||
if (MemberUserEmailAddress != null)
|
||||
{
|
||||
responseData.SetControlValue(nameof(MemberUserEmailAddress), MemberUserEmailAddress);
|
||||
if (StringUtil.IsEmpty(MemberUserEmailAddress))
|
||||
responseData.SetControlError(nameof(MemberUserEmailAddress), Localiser["msg.validation.mandatory.value"]);
|
||||
else if (!AccountMgr.UserAccountExistsByEmailAddress(MemberUserEmailAddress))
|
||||
responseData.SetControlError(nameof(MemberUserEmailAddress), Localiser["msg.validation.invalid.value"]);
|
||||
}
|
||||
else
|
||||
{
|
||||
// User Account.
|
||||
if (MemberUserAccountId != null)
|
||||
{
|
||||
SysId memberUserAccountId = SysId.ToSysId(MemberUserAccountId);
|
||||
if (!SysId.IsValid(memberUserAccountId))
|
||||
responseData.SetControlError(nameof(MemberUserAccountId), Localiser["msg.validation.mandatory.value"]);
|
||||
}
|
||||
}
|
||||
|
||||
// Member roles.
|
||||
if (MemberRoleCodes != null)
|
||||
{
|
||||
// Roles can be left empty as the 'Member' role is automatically applied.
|
||||
}
|
||||
|
||||
// User Organisation status.
|
||||
if (MemberStatusCode != null)
|
||||
{
|
||||
if (StringUtil.IsEmpty(MemberStatusCode))
|
||||
responseData.SetControlError(nameof(MemberStatus), Localiser["msg.validation.mandatory.value"]);
|
||||
else if (!SaxOrganisation.ValidStatuses.Contains(MemberStatus))
|
||||
responseData.SetControlError(nameof(MemberStatus), Localiser["msg.validation.invalid.value"]);
|
||||
}
|
||||
|
||||
return !responseData.HasControlErrors();
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
}
|
||||
//=======================================================================
|
||||
}
|
||||
@@ -0,0 +1,92 @@
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Sarand.Net.Standard.Base.App;
|
||||
using Sarand.Net.Standard.Base.Bus;
|
||||
using Sarand.Net.Standard.Base.Core;
|
||||
using Sarand.Net.Standard.Base.Utils;
|
||||
using Sarand.Net.Standard.Proc.Excel;
|
||||
using Saxonite.Base.App;
|
||||
using Saxonite.Net.Core.Web.Base.App;
|
||||
using Saxonite.Net.Core.Web.Base.Controllers;
|
||||
using Saxonite.Net.Core.Web.Base.Models;
|
||||
using Saxonite.Net.Standard.Base.App;
|
||||
using Saxonite.Net.Standard.Base.Bus;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Saxonite.Net.Core.Web.Admin.Models
|
||||
{
|
||||
//=======================================================================
|
||||
/// <summary>
|
||||
/// Model for Organisation Upload.
|
||||
/// </summary>
|
||||
public class Model_OrganisationUpload : SaxModel_Admin
|
||||
{
|
||||
//-------------------------------------------------------------------
|
||||
// Construction.
|
||||
public Model_OrganisationUpload(SaxLocaliser localiser) :
|
||||
base(localiser)
|
||||
{
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Organisation data files - only one allowed per request.
|
||||
public List<IFormFile> OrganisationDataFile { get; set; }
|
||||
// Data file properties.
|
||||
public String SheetNameOrNumber { get; set; } = "1";
|
||||
public String HeaderRow { get; set; } = "1";
|
||||
public String FirstDataRow { get; set; } = "2";
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Validation.
|
||||
//-------------------------------------------------------------------
|
||||
public bool ValidateProperties(SaxController_Base.AjaxResponse_Data responseData)
|
||||
{
|
||||
|
||||
// Data file.
|
||||
{
|
||||
String controlName = nameof(OrganisationDataFile);
|
||||
// A single data file must be supplied.
|
||||
if (OrganisationDataFile == null || !OrganisationDataFile.Any())
|
||||
responseData.SetControlError(controlName, Localiser["msg.error.data.file.missing"]);
|
||||
else if (OrganisationDataFile != null && OrganisationDataFile.Count() > 1)
|
||||
responseData.SetControlError(controlName, Localiser["msg.error.data.file.multiple"]);
|
||||
}
|
||||
|
||||
// Sheet name or number.
|
||||
{
|
||||
String controlName = nameof(SheetNameOrNumber);
|
||||
if (StringUtil.IsBlank(SheetNameOrNumber))
|
||||
responseData.SetControlError(controlName, Localiser["msg.validation.mandatory.value"]);
|
||||
else if (!ExcelHelper.IsValidSheetName(SheetNameOrNumber))
|
||||
responseData.SetControlError(controlName, Localiser["msg.error.sheet.name.invalid"]);
|
||||
}
|
||||
|
||||
// Header row position (from 1).
|
||||
{
|
||||
String controlName = nameof(HeaderRow);
|
||||
if (StringUtil.IsBlank(HeaderRow))
|
||||
responseData.SetControlError(controlName, Localiser["msg.validation.mandatory.value"]);
|
||||
else if (!StringUtil.IsNumeric(HeaderRow) || StringUtil.ToInt(HeaderRow) < 1)
|
||||
responseData.SetControlError(controlName, Localiser["msg.error.spreadsheet.row.invalid"]);
|
||||
}
|
||||
|
||||
// First data row position (from 1).
|
||||
{
|
||||
String controlName = nameof(FirstDataRow);
|
||||
if (StringUtil.IsBlank(FirstDataRow))
|
||||
responseData.SetControlError(controlName, Localiser["msg.validation.mandatory.value"]);
|
||||
else if (!StringUtil.IsNumeric(FirstDataRow) || StringUtil.ToInt(FirstDataRow) < 1)
|
||||
responseData.SetControlError(controlName, Localiser["msg.error.spreadsheet.row.invalid"]);
|
||||
}
|
||||
|
||||
return !responseData.HasControlErrors();
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
}
|
||||
//=======================================================================
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
using Saxonite.Net.Core.Web.Base.App;
|
||||
using Saxonite.Net.Core.Web.Base.Models;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Saxonite.Net.Core.Web.Admin.Models
|
||||
{
|
||||
//=======================================================================
|
||||
public class Model_Policies : SaxModel_Admin
|
||||
{
|
||||
//-------------------------------------------------------------------
|
||||
// Construction.
|
||||
public Model_Policies(SaxLocaliser localiser) :
|
||||
base(localiser)
|
||||
{
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Properties.
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
}
|
||||
//=======================================================================
|
||||
}
|
||||
@@ -0,0 +1,153 @@
|
||||
using Sarand.Net.Standard.Base.App;
|
||||
using Sarand.Net.Standard.Base.Bus;
|
||||
using Sarand.Net.Standard.Base.Core;
|
||||
using Sarand.Net.Standard.Base.Utils;
|
||||
using Saxonite.Base.App;
|
||||
using Saxonite.Net.Core.Web.Base.App;
|
||||
using Saxonite.Net.Core.Web.Base.Controllers;
|
||||
using Saxonite.Net.Core.Web.Base.Models;
|
||||
using Saxonite.Net.Standard.Base.App;
|
||||
using Saxonite.Net.Standard.Base.Bus;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Saxonite.Net.Core.Web.Admin.Models
|
||||
{
|
||||
//=======================================================================
|
||||
public class Model_Region : SaxModel_Admin
|
||||
{
|
||||
//-------------------------------------------------------------------
|
||||
// Construction.
|
||||
public Model_Region(SaxLocaliser localiser) :
|
||||
base(localiser)
|
||||
{
|
||||
AdditionalFiles_JS.Add("js/sax-rgn.js");
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// List properties.
|
||||
public class FilterData
|
||||
{
|
||||
public String Region { get; set; }
|
||||
public String RegionTypeCode { get; set; }
|
||||
}
|
||||
public FilterData Filter { get; } = new FilterData();
|
||||
public Sax.RegionType FilterRegionType
|
||||
{
|
||||
get { return (Sax.RegionType)RegionTypeCodes.GetTypeForCode(Filter.RegionTypeCode); }
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Region properties.
|
||||
public String RegionId { get; set; }
|
||||
public String RegionTypeCode { get; set; }
|
||||
public Sax.RegionType RegionType
|
||||
{
|
||||
get { return (Sax.RegionType)RegionTypeCodes.GetTypeForCode(RegionTypeCode); }
|
||||
set { RegionTypeCode = RegionTypeCodes.GetCodeForType(value); }
|
||||
}
|
||||
public String RegionCountryIso2Code { get; set; }
|
||||
public String RegionName { get; set; }
|
||||
public String RegionIdParent { get; set; }
|
||||
public String RegionStatusCode { get; set; }
|
||||
public SaStatus RegionStatus { get { return SacsSystem.GetStatusForCode(RegionStatusCode); } }
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Validation.
|
||||
//-------------------------------------------------------------------
|
||||
// Region.
|
||||
public bool ValidateRegionData(SaxController_Base.AjaxResponse_Data responseData)
|
||||
{
|
||||
// Region Type.
|
||||
if (RegionTypeCode != null)
|
||||
{
|
||||
responseData.SetControlValue(nameof(RegionTypeCode), RegionTypeCode);
|
||||
if (StringUtil.IsEmpty(RegionTypeCode) || (int)RegionType < 1)
|
||||
responseData.SetControlError(nameof(RegionTypeCode), Localiser["msg.validation.mandatory.value"]);
|
||||
}
|
||||
|
||||
// Region ISO2 code.
|
||||
if (RegionCountryIso2Code != null)
|
||||
{
|
||||
RegionCountryIso2Code = RegionCountryIso2Code.ToUpperInvariant();
|
||||
responseData.SetControlValue(nameof(RegionCountryIso2Code), RegionCountryIso2Code);
|
||||
if (RegionType == Sax.RegionType.Country)
|
||||
{
|
||||
if (StringUtil.IsEmpty(RegionCountryIso2Code))
|
||||
responseData.SetControlError(nameof(RegionCountryIso2Code), Localiser["msg.validation.mandatory.value"]);
|
||||
else if (StringUtil.GetLength(RegionCountryIso2Code) != GetControlMaxLength(SaxDbDfn_Core.ColumnIdx.Region_CountryIso2Code))
|
||||
responseData.SetControlError(nameof(RegionCountryIso2Code), Localiser["msg.validation.invalid.length", GetControlMaxLength(SaxDbDfn_Core.ColumnIdx.Region_CountryIso2Code)]);
|
||||
else
|
||||
{
|
||||
// Check for duplicate code.
|
||||
SaxRegion.Params prmRegion = new SaxRegion.Params();
|
||||
SysId regionId = SysId.ToSysId(RegionId);
|
||||
if (SysId.IsValid(regionId))
|
||||
prmRegion.IdsExcluded.Add(regionId);
|
||||
prmRegion.CountryIso2CodesIncluded.Add(RegionCountryIso2Code);
|
||||
prmRegion.StatusCat = SaxRegion.StatusCat.Any;
|
||||
if (ReferenceMgr.GetRegionCount(prmRegion) > 0)
|
||||
responseData.SetControlError(nameof(RegionCountryIso2Code), Localiser["msg.validation.duplicate.value"]);
|
||||
}
|
||||
}
|
||||
else if ((int)RegionType > 0 && RegionType != Sax.RegionType.Country)
|
||||
{
|
||||
if (!StringUtil.IsEmpty(RegionCountryIso2Code))
|
||||
responseData.SetControlError(nameof(RegionCountryIso2Code), Localiser["msg.validation.invalid.value"]);
|
||||
}
|
||||
}
|
||||
|
||||
// Region name.
|
||||
if (RegionName != null)
|
||||
{
|
||||
responseData.SetControlValue(nameof(RegionName), RegionName);
|
||||
if (StringUtil.IsEmpty(RegionName))
|
||||
responseData.SetControlError(nameof(RegionName), Localiser["msg.validation.mandatory.value"]);
|
||||
else if (StringUtil.GetLength(RegionName) > GetControlMaxLength(SaxDbDfn_Core.ColumnIdx.Region_Name))
|
||||
responseData.SetControlError(nameof(RegionName), Localiser["msg.validation.maximum.length", GetControlMaxLength(SaxDbDfn_Core.ColumnIdx.Region_Name)]);
|
||||
else
|
||||
{
|
||||
// Check for duplicate name.
|
||||
SaxRegion.Params prmRegion = new SaxRegion.Params();
|
||||
SysId regionId = SysId.ToSysId(RegionId);
|
||||
if (SysId.IsValid(regionId))
|
||||
prmRegion.IdsExcluded.Add(regionId);
|
||||
prmRegion.NameFull = RegionName;
|
||||
prmRegion.StatusCat = SaxRegion.StatusCat.Any;
|
||||
if (ReferenceMgr.GetRegionCount(prmRegion) > 0)
|
||||
responseData.SetControlError(nameof(RegionName), Localiser["msg.validation.duplicate.value"]);
|
||||
}
|
||||
}
|
||||
|
||||
// Parent region.
|
||||
if (!StringUtil.IsEmpty(RegionIdParent))
|
||||
{
|
||||
SaxRegion parentRegion = ReferenceMgr.GetRegionById(SysId.ToSysId(RegionIdParent));
|
||||
if (parentRegion != null)
|
||||
{
|
||||
if (RegionType<= 0 || SaxRegion.IsValidParentRegionType(RegionType, parentRegion.RegionType))
|
||||
{
|
||||
}
|
||||
else responseData.SetControlError(nameof(RegionIdParent), Localiser["region.msg.parent.type.invalid"]);
|
||||
}
|
||||
else responseData.SetControlError(nameof(RegionIdParent), Localiser["msg.validation.invalid.value"]);
|
||||
}
|
||||
|
||||
// Region status.
|
||||
if (RegionStatusCode != null)
|
||||
{
|
||||
if (StringUtil.IsEmpty(RegionStatusCode))
|
||||
responseData.SetControlError(nameof(RegionStatus), Localiser["msg.validation.mandatory.value"]);
|
||||
else if (!SaxRegion.ValidStatuses.Contains(RegionStatus))
|
||||
responseData.SetControlError(nameof(RegionStatus), Localiser["msg.validation.invalid.value"]);
|
||||
}
|
||||
|
||||
return !responseData.HasControlErrors();
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
}
|
||||
//=======================================================================
|
||||
}
|
||||
@@ -0,0 +1,113 @@
|
||||
using Sarand.Net.Standard.Base.Core;
|
||||
using Sarand.Net.Standard.Base.Helpers;
|
||||
using Sarand.Net.Standard.Base.Utils;
|
||||
using Saxonite.Net.Core.Web.Base.App;
|
||||
using Saxonite.Net.Core.Web.Base.Controllers;
|
||||
using Saxonite.Net.Core.Web.Base.Models;
|
||||
using Saxonite.Net.Standard.Base.Bus;
|
||||
using Saxonite.Net.Standard.Base.Helpers;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Saxonite.Net.Core.Web.Admin.Models
|
||||
{
|
||||
//=======================================================================
|
||||
public class Model_Security : SaxModel_Admin
|
||||
{
|
||||
//-------------------------------------------------------------------
|
||||
// Construction.
|
||||
public Model_Security(SaxLocaliser localiser) :
|
||||
base(localiser)
|
||||
{
|
||||
//AdditionalFiles_CSS.Add("css/sax-security.css");
|
||||
AdditionalFiles_JS.Add("js/sax-security.js");
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Page configuration.
|
||||
public bool RequestPasswordMode { get { return !StringUtil.IsEmpty(rpe); } }
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Form properties.
|
||||
public String EmailAddress { get; set; }
|
||||
public String PasswordCurrent { get; set; }
|
||||
public String Password { get; set; }
|
||||
public String PasswordConfirm { get; set; }
|
||||
public bool KeepMeSignedIn { get; set; }
|
||||
/// <summary>Request Password Encrypted params - to allow Change Password without session or requiring old password.</summary>
|
||||
public String rpe { get; set; }
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Validation.
|
||||
//-------------------------------------------------------------------
|
||||
// Sign-in.
|
||||
public bool ValidateSignInData(SaxController_Base.AjaxResponse_Data responseData)
|
||||
{
|
||||
// Email address.
|
||||
responseData.SetControlValue(nameof(EmailAddress), EmailAddress);
|
||||
if (StringUtil.IsEmpty(EmailAddress))
|
||||
responseData.SetControlError(nameof(EmailAddress), Localiser["msg.validation.mandatory.value"]);
|
||||
else if (!SacsDataValidationHelper.IsValidEmailAddress(EmailAddress))
|
||||
responseData.SetControlError(nameof(EmailAddress), Localiser["msg.validation.invalid.value"]);
|
||||
|
||||
// Password.
|
||||
// NB Do not return the password value in the response.
|
||||
if (StringUtil.IsEmpty(Password))
|
||||
responseData.SetControlError(nameof(Password), Localiser["msg.validation.mandatory.value"]);
|
||||
|
||||
return !responseData.HasControlErrors();
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Change password.
|
||||
public bool ValidateChangePasswordData(SaxUserAccount userAccount, SaxController_Base.AjaxResponse_Data responseData)
|
||||
{
|
||||
// Validate Passwords.
|
||||
// NB Do not return the password values in the response.
|
||||
// NB Only validate populated values - any null values are not part of the form for this request.
|
||||
// - 'Current' password is not shown when changing password from 'Request Password' email link.
|
||||
if (PasswordCurrent != null && StringUtil.IsEmpty(PasswordCurrent))
|
||||
responseData.SetControlError(nameof(PasswordCurrent), Localiser["msg.validation.mandatory.value"]);
|
||||
if (StringUtil.IsEmpty(Password))
|
||||
responseData.SetControlError(nameof(Password), Localiser["msg.validation.mandatory.value"]);
|
||||
if (StringUtil.IsEmpty(PasswordConfirm))
|
||||
responseData.SetControlError(nameof(PasswordConfirm), Localiser["msg.validation.mandatory.value"]);
|
||||
if (!StringUtil.IsEmpty(Password) && !StringUtil.IsEmpty(PasswordConfirm))
|
||||
{
|
||||
if (!Password.Equals(PasswordConfirm))
|
||||
responseData.SetControlError(nameof(PasswordConfirm), Localiser["msg.validation.invalid.value"]);
|
||||
if (!SaxPasswordHelper.IsValidPassword(Password))
|
||||
responseData.SetControlError(nameof(PasswordConfirm), Localiser.GetText("msg.warn.password.invalid", new object[] { SaxPasswordHelper.Params.MinLength, SaxPasswordHelper.Params.MinLengthNoComplexity }));
|
||||
}
|
||||
|
||||
if (!responseData.HasControlErrors())
|
||||
{
|
||||
if (PasswordCurrent != null && !SaxPasswordHelper.VerifyHashedPassword(userAccount, PasswordCurrent))
|
||||
responseData.SetControlError(nameof(PasswordCurrent), Localiser["security.change.password.current.invalid"]);
|
||||
if (SaxPasswordHelper.VerifyHashedPassword(userAccount, Password))
|
||||
responseData.SetControlError(nameof(Password), Localiser["security.change.password.not.changed"]);
|
||||
}
|
||||
|
||||
return !responseData.HasControlErrors();
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Request Password.
|
||||
public bool ValidateRequestPasswordData(SaxController_Base.AjaxResponse_Data responseData)
|
||||
{
|
||||
// Email address.
|
||||
responseData.SetControlValue(nameof(EmailAddress), EmailAddress);
|
||||
if (StringUtil.IsEmpty(EmailAddress))
|
||||
responseData.SetControlError(nameof(EmailAddress), Localiser["msg.validation.mandatory.value"]);
|
||||
else if (!SacsDataValidationHelper.IsValidEmailAddress(EmailAddress))
|
||||
responseData.SetControlError(nameof(EmailAddress), Localiser["msg.validation.invalid.value"]);
|
||||
|
||||
return !responseData.HasControlErrors();
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
}
|
||||
//=======================================================================
|
||||
}
|
||||
@@ -0,0 +1,135 @@
|
||||
using Sarand.Net.Standard.Base.App;
|
||||
using Sarand.Net.Standard.Base.Bus;
|
||||
using Sarand.Net.Standard.Base.Core;
|
||||
using Sarand.Net.Standard.Base.Utils;
|
||||
using Saxonite.Base.App;
|
||||
using Saxonite.Net.Core.Web.Base.App;
|
||||
using Saxonite.Net.Core.Web.Base.Controllers;
|
||||
using Saxonite.Net.Core.Web.Base.Models;
|
||||
using Saxonite.Net.Standard.Base.App;
|
||||
using Saxonite.Net.Standard.Base.Bus;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Saxonite.Net.Core.Web.Admin.Models
|
||||
{
|
||||
//=======================================================================
|
||||
public class Model_Sport : SaxModel_Admin
|
||||
{
|
||||
//-------------------------------------------------------------------
|
||||
// Construction.
|
||||
public Model_Sport(SaxLocaliser localiser) :
|
||||
base(localiser)
|
||||
{
|
||||
AdditionalFiles_JS.Add("js/sax-sport.js");
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Sport list configuration.
|
||||
public class FilterData
|
||||
{
|
||||
public String Sport { get; set; }
|
||||
}
|
||||
public FilterData Filter { get; } = new FilterData();
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Sport properties.
|
||||
public String SportId { get; set; }
|
||||
public String SportName { get; set; }
|
||||
public String SportGroupingCode { get; set; }
|
||||
public Sax.SportGrouping SportGrouping { get { return (Sax.SportGrouping)SportGroupingCodes.GetTypeForCode(SportGroupingCode); } }
|
||||
public String SportIdParent { get; set; }
|
||||
public String SportIdsParents { get; set; }
|
||||
public String SportIdsChildren { get; set; }
|
||||
public String SportSpecialityLabelCode { get; set; }
|
||||
public Sax.SportSpecialityLabel SportSpecialityLabel { get { return (Sax.SportSpecialityLabel)SportSpecialityLabelCodes.GetTypeForCode(SportSpecialityLabelCode); } }
|
||||
public String SportStatusCode { get; set; }
|
||||
public SaStatus SportStatus { get { return SacsSystem.GetStatusForCode(SportStatusCode); } }
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Validation.
|
||||
//-------------------------------------------------------------------
|
||||
// Sport.
|
||||
public bool ValidateSportData(SaxController_Base.AjaxResponse_Data responseData)
|
||||
{
|
||||
// Record disposable items as they are created so all can be disposed when needed.
|
||||
using (DisposableCollection<IDisposable> disposableItems = new DisposableCollection<IDisposable>())
|
||||
{
|
||||
|
||||
// Sport Grouping.
|
||||
if (SportGroupingCode != null)
|
||||
{
|
||||
String controlName = nameof(SportGrouping);
|
||||
if (StringUtil.IsEmpty(SportGroupingCode))
|
||||
responseData.SetControlError(controlName, Localiser["msg.validation.mandatory.value"]);
|
||||
else if (SportGrouping <= 0)
|
||||
responseData.SetControlError(controlName, Localiser["msg.validation.invalid.value"]);
|
||||
}
|
||||
|
||||
// Parent sport.
|
||||
SysId sportIdParent = SysId.ToSysId(SportIdParent);
|
||||
if (SportIdParent != null && SysId.IsValid(sportIdParent))
|
||||
{
|
||||
String controlName = "SportParent";
|
||||
SaxSport sport = ReferenceMgr.GetSportById(SysId.ToSysId(SportIdParent));
|
||||
disposableItems.Add(sport);
|
||||
if (sport == null)
|
||||
responseData.SetControlError(controlName, Localiser["msg.validation.invalid.value"]);
|
||||
else if (SysId.IsValid(sport.SportIdParent))
|
||||
responseData.SetControlError(controlName, Localiser["msg.validation.invalid.value"]);
|
||||
}
|
||||
|
||||
// Sport name.
|
||||
if (SportName != null)
|
||||
{
|
||||
String controlName = nameof(SportName);
|
||||
responseData.SetControlValue(controlName, SportName);
|
||||
if (StringUtil.IsEmpty(SportName))
|
||||
responseData.SetControlError(controlName, Localiser["msg.validation.mandatory.value"]);
|
||||
else if (StringUtil.GetLength(SportName) > GetControlMaxLength(SaxDbDfn_Core.ColumnIdx.Sport_Name))
|
||||
responseData.SetControlError(controlName, Localiser["msg.validation.maximum.length", GetControlMaxLength(SaxDbDfn_Core.ColumnIdx.Sport_Name)]);
|
||||
else
|
||||
{
|
||||
// Check for duplicate name.
|
||||
SaxSport.Params prmSport = new SaxSport.Params();
|
||||
SysId sportId = SysId.ToSysId(SportId);
|
||||
if (SysId.IsValid(sportId))
|
||||
prmSport.IdsExcluded.Add(sportId);
|
||||
prmSport.NameFull = SportName;
|
||||
prmSport.StatusCat = SaxSport.StatusCat.Any;
|
||||
if (ReferenceMgr.GetSportCount(prmSport) > 0)
|
||||
responseData.SetControlError(controlName, Localiser["msg.validation.duplicate.value"]);
|
||||
}
|
||||
}
|
||||
|
||||
// Sport Speciality Label.
|
||||
if (SportSpecialityLabelCode != null)
|
||||
{
|
||||
String controlName = nameof(SportSpecialityLabel);
|
||||
if (!StringUtil.IsEmpty(SportSpecialityLabelCode))
|
||||
{
|
||||
if (SportSpecialityLabel <= 0)
|
||||
responseData.SetControlError(controlName, Localiser["msg.validation.invalid.value"]);
|
||||
}
|
||||
}
|
||||
|
||||
// Sport status.
|
||||
if (SportStatusCode != null)
|
||||
{
|
||||
String controlName = nameof(SportStatus);
|
||||
if (StringUtil.IsEmpty(SportStatusCode))
|
||||
responseData.SetControlError(controlName, Localiser["msg.validation.mandatory.value"]);
|
||||
else if (!SaxSport.ValidStatuses.Contains(SportStatus))
|
||||
responseData.SetControlError(controlName, Localiser["msg.validation.invalid.value"]);
|
||||
}
|
||||
|
||||
}
|
||||
return !responseData.HasControlErrors();
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
}
|
||||
//=======================================================================
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
using Microsoft.AspNetCore.Mvc.Rendering;
|
||||
using Sarand.Net.Standard.Base.App;
|
||||
using Sarand.Net.Standard.Base.Core;
|
||||
using Saxonite.Net.Core.Web.Base.App;
|
||||
using Saxonite.Net.Core.Web.Base.Models;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Saxonite.Net.Core.Web.Admin.Models
|
||||
{
|
||||
//=======================================================================
|
||||
public class Model_System : SaxModel_Admin
|
||||
{
|
||||
//-------------------------------------------------------------------
|
||||
// Construction.
|
||||
public Model_System(SaxLocaliser localiser) :
|
||||
base(localiser)
|
||||
{
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Properties.
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Database page properties.
|
||||
public class DatabaseFilterData
|
||||
{
|
||||
public String Instance { get; set; }
|
||||
public String Search { get; set; }
|
||||
}
|
||||
public DatabaseFilterData DatabaseFilter { get; } = new DatabaseFilterData();
|
||||
public class DatabaseTableData
|
||||
{
|
||||
public String Instance { get; set; }
|
||||
public String Name { get; set; }
|
||||
}
|
||||
public DatabaseTableData DatabaseTable { get; } = new DatabaseTableData();
|
||||
|
||||
public IEnumerable<SelectListItem> GetDatabases()
|
||||
{
|
||||
List<CodeDesc> items = new List<CodeDesc>();
|
||||
if (SessionData?.ValidUserSession ?? false)
|
||||
{
|
||||
items.Add("Core", Localiser["label.core"]);
|
||||
items.Add("Reference", Localiser["label.reference"]);
|
||||
items.Add("Support", Localiser["label.support"]);
|
||||
}
|
||||
return new SelectList(items, "Code", "Desc");
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Logs page properties.
|
||||
public String LoggingRootFolder { get; } = Regex.Replace(SaLogger.LogFolder, "[\\\\/]Admin$", "");
|
||||
// Log file filter.
|
||||
public class LogsFilterData
|
||||
{
|
||||
public String Folder { get; set; }
|
||||
public String Year { get; set; }
|
||||
public String Month { get; set; }
|
||||
public String Filename { get; set; }
|
||||
}
|
||||
public LogsFilterData LogsFilter { get; } = new LogsFilterData();
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
}
|
||||
//=======================================================================
|
||||
}
|
||||
@@ -0,0 +1,225 @@
|
||||
using Microsoft.AspNetCore.Mvc.Rendering;
|
||||
using Sarand.Net.Standard.Base.App;
|
||||
using Sarand.Net.Standard.Base.Bus;
|
||||
using Sarand.Net.Standard.Base.Core;
|
||||
using Sarand.Net.Standard.Base.Helpers;
|
||||
using Sarand.Net.Standard.Base.Utils;
|
||||
using Saxonite.Base.App;
|
||||
using Saxonite.Net.Core.Web.Base.App;
|
||||
using Saxonite.Net.Core.Web.Base.Controllers;
|
||||
using Saxonite.Net.Core.Web.Base.Models;
|
||||
using Saxonite.Net.Standard.Base.App;
|
||||
using Saxonite.Net.Standard.Base.Bus;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Saxonite.Net.Core.Web.Admin.Models
|
||||
{
|
||||
//=======================================================================
|
||||
public class Model_User : SaxModel_Admin
|
||||
{
|
||||
//-------------------------------------------------------------------
|
||||
// Construction.
|
||||
public Model_User(SaxLocaliser localiser) :
|
||||
base(localiser)
|
||||
{
|
||||
AdditionalFiles_JS.Add("js/sax-usr.js");
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// User filter properties.
|
||||
public class FilterData
|
||||
{
|
||||
public String User { get; set; }
|
||||
public String UserSportId { get; set; }
|
||||
public String UserSportName { get; set; }
|
||||
public String UserRegionId { get; set; }
|
||||
public String UserRegionName { get; set; }
|
||||
public String UserStatusCategoryCode { get; set; }
|
||||
}
|
||||
public FilterData Filter { get; } = new FilterData();
|
||||
public SaxUserAccount.StatusCat FilterUserStatusCategory
|
||||
{
|
||||
get { return EnumUtil.ParseEnum(Filter.UserStatusCategoryCode, SaxUserAccount.StatusCat.Any); }
|
||||
}
|
||||
/// <summary>User Status Categories for filter.</summary>
|
||||
public IEnumerable<SelectListItem> UserFilterStatusCategoriesForSelect
|
||||
{
|
||||
get
|
||||
{
|
||||
List<CodeDesc> statusCategories = new List<CodeDesc>();
|
||||
statusCategories.Add(SaxUserAccount.StatusCat.Any.ToString(), Localiser["label.any"]);
|
||||
statusCategories.Add(SaxUserAccount.StatusCat.AwaitingOnly.ToString(), "Awaiting");
|
||||
statusCategories.Add(SaxUserAccount.StatusCat.ActiveOnly.ToString(), "Active");
|
||||
statusCategories.Add(SaxUserAccount.StatusCat.InactiveOnly.ToString(), "Inactive");
|
||||
statusCategories.Add(SaxUserAccount.StatusCat.NotDeleted.ToString(), "Not deleted");
|
||||
statusCategories.Add(SaxUserAccount.StatusCat.DeletedOnly.ToString(), "Deleted");
|
||||
return new SelectList(statusCategories, "Code", "Desc", SaxUserAccount.StatusCat.Any.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// User properties.
|
||||
public String UserId { get; set; }
|
||||
[EmailAddress]
|
||||
public String UserEmailAddress { get; set; }
|
||||
public String UserTitle { get; set; }
|
||||
public String UserFirstName { get; set; }
|
||||
public String UserLastName { get; set; }
|
||||
public String UserRegionIdCountry { get; set; }
|
||||
public String UserRegionIdProvince { get; set; }
|
||||
public String UserRoleCodeDelim = ",";
|
||||
public new List<String> UserRoleCodes { get; set; }
|
||||
public List<String> GetUserRoleCodes()
|
||||
{
|
||||
List<String> codes = new List<string>();
|
||||
foreach (String code in UserRoleCodes)
|
||||
{
|
||||
if (StringUtil.IsEmpty(code)) continue;
|
||||
codes.AddRange(code.Split(UserRoleCodeDelim));
|
||||
}
|
||||
return codes;
|
||||
}
|
||||
public String UserStatusCode { get; set; }
|
||||
public SaStatus UserStatus { get { return SacsSystem.GetStatusForCode(UserStatusCode); } }
|
||||
// User emails.
|
||||
public String UserEmailAcountActivationOnline { get; set; }
|
||||
public String UserEmailRequestPasswordOnline { get; set; }
|
||||
public String UserEmailRequestPasswordAdmin { get; set; }
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Validation.
|
||||
//-------------------------------------------------------------------
|
||||
// User.
|
||||
public bool ValidateUserData(SaxController_Base.AjaxResponse_Data responseData)
|
||||
{
|
||||
// Record disposable items as they are created so all can be disposed when needed.
|
||||
using (DisposableCollection<IDisposable> disposableItems = new DisposableCollection<IDisposable>())
|
||||
{
|
||||
|
||||
// User email.
|
||||
if (UserEmailAddress != null)
|
||||
{
|
||||
UserEmailAddress = UserEmailAddress.ToLowerInvariant();
|
||||
responseData.SetControlValue(nameof(UserEmailAddress), UserEmailAddress);
|
||||
if (StringUtil.IsEmpty(UserEmailAddress))
|
||||
responseData.SetControlError(nameof(UserEmailAddress), Localiser["msg.validation.mandatory.value"]);
|
||||
else if (StringUtil.GetLength(UserEmailAddress) > GetControlMaxLength(SaxDbDfn_Core.ColumnIdx.UserAccount_EmailAddress))
|
||||
responseData.SetControlError(nameof(UserEmailAddress), Localiser["msg.validation.maximum.length", GetControlMaxLength(SaxDbDfn_Core.ColumnIdx.UserAccount_EmailAddress)]);
|
||||
else if (!SacsDataValidationHelper.IsValidEmailAddress(UserEmailAddress))
|
||||
responseData.SetControlError(nameof(UserEmailAddress), Localiser["msg.validation.invalid.value"]);
|
||||
else
|
||||
{
|
||||
// Check for duplicate email address.
|
||||
SaxUserAccount.Params prmUserAccount = new SaxUserAccount.Params();
|
||||
SysId userAccountId = SysId.ToSysId(UserId);
|
||||
if (SysId.IsValid(userAccountId))
|
||||
prmUserAccount.IdsExcluded.Add(userAccountId);
|
||||
prmUserAccount.EmailAddress = UserEmailAddress;
|
||||
prmUserAccount.StatusCat = SaxUserAccount.StatusCat.Any;
|
||||
if (AccountMgr.GetUserAccountCount(prmUserAccount) > 0)
|
||||
responseData.SetControlError(nameof(UserEmailAddress), Localiser["msg.validation.duplicate.value"]);
|
||||
}
|
||||
}
|
||||
|
||||
// User title.
|
||||
if (UserTitle != null)
|
||||
{
|
||||
}
|
||||
|
||||
// User first name.
|
||||
if (UserFirstName != null)
|
||||
{
|
||||
responseData.SetControlValue(nameof(UserFirstName), UserFirstName);
|
||||
if (StringUtil.IsEmpty(UserFirstName))
|
||||
responseData.SetControlError(nameof(UserFirstName), Localiser["msg.validation.mandatory.value"]);
|
||||
else if (StringUtil.GetLength(UserFirstName) > GetControlMaxLength(SaxDbDfn_Core.ColumnIdx.UserAccount_FirstName))
|
||||
responseData.SetControlError(nameof(UserFirstName), Localiser["msg.validation.maximum.length", GetControlMaxLength(SaxDbDfn_Core.ColumnIdx.UserAccount_FirstName)]);
|
||||
}
|
||||
|
||||
// User last name.
|
||||
if (UserLastName != null)
|
||||
{
|
||||
responseData.SetControlValue(nameof(UserLastName), UserLastName);
|
||||
if (StringUtil.IsEmpty(UserLastName))
|
||||
responseData.SetControlError(nameof(UserLastName), Localiser["msg.validation.mandatory.value"]);
|
||||
else if (StringUtil.GetLength(UserLastName) > GetControlMaxLength(SaxDbDfn_Core.ColumnIdx.UserAccount_LastName))
|
||||
responseData.SetControlError(nameof(UserLastName), Localiser["msg.validation.maximum.length", GetControlMaxLength(SaxDbDfn_Core.ColumnIdx.UserAccount_LastName)]);
|
||||
}
|
||||
|
||||
// Country region.
|
||||
SaxRegion regionCountry = null;
|
||||
if (UserRegionIdCountry != null)
|
||||
{
|
||||
if (!SysId.IsValid(SysId.ToSysId(UserRegionIdCountry)))
|
||||
responseData.SetControlError(nameof(UserRegionIdCountry), Localiser["msg.validation.mandatory.value"]);
|
||||
else
|
||||
{
|
||||
regionCountry = ReferenceMgr.GetRegionById(SysId.ToSysId(UserRegionIdCountry));
|
||||
disposableItems.Add(regionCountry);
|
||||
if (regionCountry != null)
|
||||
{
|
||||
if (regionCountry.RegionType != Sax.RegionType.Country)
|
||||
{
|
||||
SaLogger.Warn($"{SysUtil.Fn} Invalid region type. Expected: Country. Found: " + regionCountry.RegionType.ToString());
|
||||
responseData.SetControlError(nameof(UserRegionIdCountry), Localiser["msg.validation.invalid.value"]);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
SaLogger.Warn($"{SysUtil.Fn} Failed to retrieve region for Id: " + UserRegionIdCountry);
|
||||
responseData.SetControlError(nameof(UserRegionIdCountry), Localiser["msg.validation.invalid.value"]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Province region.
|
||||
SaxRegion regionProvince = null;
|
||||
if (UserRegionIdProvince != null)
|
||||
{
|
||||
if (!UserRegionIdProvince.IsEmpty())
|
||||
{
|
||||
regionProvince = ReferenceMgr.GetRegionById(SysId.ToSysId(UserRegionIdProvince));
|
||||
disposableItems.Add(regionProvince);
|
||||
if (regionProvince != null)
|
||||
{
|
||||
if (regionProvince.RegionType != Sax.RegionType.Province)
|
||||
{
|
||||
SaLogger.Warn($"{SysUtil.Fn} Invalid region type. Expected: Province . Found: " + regionCountry.RegionType.ToString());
|
||||
responseData.SetControlError(nameof(UserRegionIdProvince), Localiser["msg.validation.invalid.value"]);
|
||||
}
|
||||
else if (regionCountry != null && !regionProvince.RegionIdParent.Equals(regionCountry.Id))
|
||||
{
|
||||
SaLogger.Warn($"{SysUtil.Fn} Invalid province region parent. Expected: " + regionCountry.Id.ToString() + " . Found: " + regionCountry.RegionIdParent.ToString());
|
||||
responseData.SetControlError(nameof(UserRegionIdProvince), Localiser["msg.validation.invalid.value"]);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
SaLogger.Warn($"{SysUtil.Fn} Failed to retrieve region for Id: " + UserRegionIdProvince);
|
||||
responseData.SetControlError(nameof(UserRegionIdProvince), Localiser["msg.validation.invalid.value"]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// User status.
|
||||
if (UserStatusCode != null)
|
||||
{
|
||||
if (StringUtil.IsEmpty(UserStatusCode))
|
||||
responseData.SetControlError(nameof(UserStatus), Localiser["msg.validation.mandatory.value"]);
|
||||
else if (!SaxUserAccount.ValidStatuses.Contains(UserStatus))
|
||||
responseData.SetControlError(nameof(UserStatus), Localiser["msg.validation.invalid.value"]);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return !responseData.HasControlErrors();
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
}
|
||||
//=======================================================================
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
using Microsoft.AspNetCore.Mvc.Rendering;
|
||||
using Sarand.Net.Standard.Base.App;
|
||||
using Sarand.Net.Standard.Base.Bus;
|
||||
using Sarand.Net.Standard.Base.Core;
|
||||
using Sarand.Net.Standard.Base.Helpers;
|
||||
using Sarand.Net.Standard.Base.Utils;
|
||||
using Saxonite.Base.App;
|
||||
using Saxonite.Net.Core.Web.Base.App;
|
||||
using Saxonite.Net.Core.Web.Base.Controllers;
|
||||
using Saxonite.Net.Core.Web.Base.Models;
|
||||
using Saxonite.Net.Standard.Base.App;
|
||||
using Saxonite.Net.Standard.Base.Bus;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Saxonite.Net.Core.Web.Admin.Models
|
||||
{
|
||||
//=======================================================================
|
||||
public class Model_UsersOnline : SaxModel_Admin
|
||||
{
|
||||
//-------------------------------------------------------------------
|
||||
// Construction.
|
||||
public Model_UsersOnline(SaxLocaliser localiser) :
|
||||
base(localiser)
|
||||
{
|
||||
AdditionalFiles_JS.Add("js/sax-usr-onl.js");
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// User filter properties.
|
||||
public class FilterData
|
||||
{
|
||||
public String User { get; set; }
|
||||
public String UserSportId { get; set; }
|
||||
public String UserRegionId { get; set; }
|
||||
}
|
||||
public FilterData Filter { get; } = new FilterData();
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// User properties.
|
||||
public String UserId { get; set; }
|
||||
[EmailAddress]
|
||||
public String UserEmailAddress { get; set; }
|
||||
public String UserTitle { get; set; }
|
||||
public String UserFirstName { get; set; }
|
||||
public String UserLastName { get; set; }
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
}
|
||||
//=======================================================================
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
using Sarand.Net.Standard.Base.App;
|
||||
using Sarand.Net.Standard.Base.Bus;
|
||||
using Sarand.Net.Standard.Base.Core;
|
||||
using Sarand.Net.Standard.Base.Utils;
|
||||
using Saxonite.Base.App;
|
||||
using Saxonite.Net.Core.Web.Base.App;
|
||||
using Saxonite.Net.Core.Web.Base.Controllers;
|
||||
using Saxonite.Net.Core.Web.Base.Models;
|
||||
using Saxonite.Net.Standard.Base.App;
|
||||
using Saxonite.Net.Standard.Base.Bus;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Saxonite.Net.Core.Web.Admin.Models.Reference
|
||||
{
|
||||
//=======================================================================
|
||||
public class Model_ReferenceBaseball : SaxModel_Admin
|
||||
{
|
||||
//-------------------------------------------------------------------
|
||||
// Construction.
|
||||
public Model_ReferenceBaseball(SaxLocaliser localiser) :
|
||||
base(localiser)
|
||||
{
|
||||
AdditionalFiles_JS.Add("js/ref/sax-ref-baseball.js");
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Reference Baseball list parameters.
|
||||
public class FilterData
|
||||
{
|
||||
}
|
||||
public FilterData Filter { get; } = new FilterData();
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Reference Baseball properties.
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Validation.
|
||||
//-------------------------------------------------------------------
|
||||
// Reference Baseball.
|
||||
public bool ValidateReferenceBaseballData(Sacs.Web.Components.SaController.AjaxResponse_Data responseData)
|
||||
{
|
||||
// Record disposable items as they are created so all can be disposed when needed.
|
||||
using (DisposableCollection<IDisposable> disposables = new DisposableCollection<IDisposable>())
|
||||
{
|
||||
|
||||
}
|
||||
return !responseData.HasControlErrors();
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
}
|
||||
//=======================================================================
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
using Sarand.Net.Standard.Base.App;
|
||||
using Sarand.Net.Standard.Base.Bus;
|
||||
using Sarand.Net.Standard.Base.Core;
|
||||
using Sarand.Net.Standard.Base.Utils;
|
||||
using Saxonite.Base.App;
|
||||
using Saxonite.Net.Core.Web.Base.App;
|
||||
using Saxonite.Net.Core.Web.Base.Controllers;
|
||||
using Saxonite.Net.Core.Web.Base.Models;
|
||||
using Saxonite.Net.Standard.Base.App;
|
||||
using Saxonite.Net.Standard.Base.Bus;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Saxonite.Net.Core.Web.Admin.Models.Reference
|
||||
{
|
||||
//=======================================================================
|
||||
public class Model_ReferenceGolf : SaxModel_Admin
|
||||
{
|
||||
//-------------------------------------------------------------------
|
||||
// Construction.
|
||||
public Model_ReferenceGolf(SaxLocaliser localiser) :
|
||||
base(localiser)
|
||||
{
|
||||
AdditionalFiles_JS.Add("js/ref/sax-ref-golf.js");
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Reference Golf list parameters.
|
||||
public class FilterData
|
||||
{
|
||||
public string CountrySearch { get; set; }
|
||||
public string CountryId { get; set; }
|
||||
public string ProvinceSearch { get; set; }
|
||||
public string ProvinceId { get; set; }
|
||||
public string CourseSearch { get; set; }
|
||||
public string CourseId { get; set; }
|
||||
public string MarkerSearch { get; set; }
|
||||
public string MarkerHoles { get; set; }
|
||||
public string MarkerGender { get; set; }
|
||||
}
|
||||
public FilterData Filter { get; } = new FilterData();
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Reference Golf properties.
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Validation.
|
||||
//-------------------------------------------------------------------
|
||||
// Reference Golf.
|
||||
public bool ValidateReferenceGolfData(Sacs.Web.Components.SaController.AjaxResponse_Data responseData)
|
||||
{
|
||||
// Record disposable items as they are created so all can be disposed when needed.
|
||||
using (DisposableCollection<IDisposable> disposables = new DisposableCollection<IDisposable>())
|
||||
{
|
||||
}
|
||||
return !responseData.HasControlErrors();
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
}
|
||||
//=======================================================================
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
using Sarand.Net.Standard.Base.Bus;
|
||||
using Saxonite.Net.Core.Web.Admin.App;
|
||||
using Saxonite.Net.Core.Web.Base.App;
|
||||
using Saxonite.Net.Core.Web.Base.Models;
|
||||
using Saxonite.Net.Standard.Base.Bus;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Saxonite.Net.Core.Web.Admin.Models
|
||||
{
|
||||
//=======================================================================
|
||||
public class SaxModel_Admin : SaxModel_Base
|
||||
{
|
||||
//-------------------------------------------------------------------
|
||||
// Protected construction.
|
||||
protected SaxModel_Admin(SaxLocaliser localiser) :
|
||||
base(localiser)
|
||||
{
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Properties.
|
||||
//-------------------------------------------------------------------
|
||||
// Session.
|
||||
public SaxSessionData_Admin SessionData_Admin { get { return SessionData as SaxSessionData_Admin; } }
|
||||
public SysId SessionUserAccountId { get { return SessionData_Admin?.User?.UserAccountId ?? null; } }
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Reference data.
|
||||
//-------------------------------------------------------------------
|
||||
public String GetSportName(SysId sportId)
|
||||
{
|
||||
using (SaxSport sport = ReferenceMgr.GetSportById(sportId))
|
||||
{
|
||||
if (sport != null) return sport.Name;
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
public String GetRegionName(SysId regionId)
|
||||
{
|
||||
using (SaxRegion region = ReferenceMgr.GetRegionById(regionId))
|
||||
{
|
||||
if (region != null) return region.Name;
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
}
|
||||
//=======================================================================
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user