Compare commits
86 Commits
main
...
feature/m4
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9322376b22 | ||
|
|
c85addf0f4 | ||
|
|
228dcd6a07 | ||
|
|
60e2651641 | ||
|
|
0af8981323 | ||
|
|
af909849f7 | ||
|
|
6fee678770 | ||
|
|
083fdf01dc | ||
|
|
af679472db | ||
|
|
bed1de3e07 | ||
|
|
cd47a8d0b7 | ||
|
|
cec49319da | ||
|
|
d97a87c61a | ||
|
|
06213688b7 | ||
|
|
c7e7b98fd9 | ||
|
|
1c9ff2374e | ||
|
|
1fa53f0bcd | ||
|
|
04a1213604 | ||
|
|
58dcc9f943 | ||
|
|
b8ad580ae5 | ||
|
|
e5122c677f | ||
|
|
5d5f113d89 | ||
|
|
7588f83965 | ||
|
|
ca2cf9581b | ||
|
|
8bfc3d497f | ||
|
|
edbd34de61 | ||
|
|
93d1fc20b4 | ||
|
|
a3a929e229 | ||
|
|
9521693e27 | ||
|
|
089c52fa99 | ||
|
|
10ef66ef25 | ||
|
|
28c2733e5b | ||
|
|
31d2ff8e64 | ||
|
|
a72bd5a012 | ||
|
|
a6230478d3 | ||
|
|
fc9b957591 | ||
|
|
4526b0ebe4 | ||
|
|
3124f6c97b | ||
|
|
ec9fc5fb47 | ||
|
|
7c32c816ec | ||
|
|
49d1259a84 | ||
|
|
196d638263 | ||
|
|
551a7f4017 | ||
|
|
2632c340c5 | ||
|
|
e089781795 | ||
|
|
6cbafa0f35 | ||
|
|
5ba8d23bcc | ||
|
|
c95a6c1145 | ||
|
|
9a07024fdd | ||
|
|
c12c1ab7d2 | ||
|
|
bdab9f37ba | ||
|
|
6cb9e3b5fd | ||
|
|
80265ec1da | ||
|
|
8ba97b6baf | ||
|
|
3ef49054ca | ||
|
|
e9be853362 | ||
|
|
5e489cdae0 | ||
|
|
1b780c4c44 | ||
|
|
6f30452ed8 | ||
|
|
d1b41814a2 | ||
|
|
f84d840e51 | ||
|
|
258ca8a837 | ||
|
|
45b8e1d223 | ||
|
|
d472923442 | ||
|
|
62a44568d1 | ||
|
|
1e3ec1cc22 | ||
|
|
587a38b149 | ||
|
|
661c2b388c | ||
|
|
5acaaa75b4 | ||
|
|
3d6a8f514c | ||
|
|
ec69a95c22 | ||
|
|
0eca913fde | ||
|
|
d0ac84f12c | ||
|
|
d8fbd445d1 | ||
|
|
66f1131863 | ||
|
|
de9a226272 | ||
|
|
a9a9e28924 | ||
|
|
5e9ad806d6 | ||
|
|
b9060d3ca1 | ||
|
|
592d0e109f | ||
|
|
92c41d3aa0 | ||
|
|
01589d617e | ||
|
|
c59acbd30c | ||
|
|
942473501e | ||
|
|
12ebd1fce9 | ||
|
|
063098808f |
91
.gitignore
vendored
91
.gitignore
vendored
@@ -1,81 +1,16 @@
|
|||||||
# --------------------------------------------------------------------------------------------------
|
|
||||||
# Core Visual Studio / .NET build outputs
|
|
||||||
# --------------------------------------------------------------------------------------------------
|
|
||||||
bin/
|
bin/
|
||||||
obj/
|
obj/
|
||||||
[Bb]uild/
|
|
||||||
[Dd]ebug*/
|
|
||||||
[Rr]elease*/
|
|
||||||
x64/
|
|
||||||
x86/
|
|
||||||
[Aa][Rr][Mm]/
|
|
||||||
[Aa][Rr][Mm]64/
|
|
||||||
_ReSharper.*/
|
|
||||||
*.user
|
|
||||||
*.userosscache
|
|
||||||
*.suo
|
|
||||||
*.cache
|
|
||||||
*.pdb
|
|
||||||
*.mpdb
|
|
||||||
*.opendb
|
|
||||||
*.VC.db
|
|
||||||
*.vscode/
|
|
||||||
|
|
||||||
# --------------------------------------------------------------------------------------------------
|
|
||||||
# Package artefacts (NuGet, npm, etc.)
|
|
||||||
# --------------------------------------------------------------------------------------------------
|
|
||||||
/packages/
|
|
||||||
*.nupkg
|
|
||||||
*.snupkg
|
|
||||||
*.nuspec
|
|
||||||
package-lock.json
|
|
||||||
packages.config
|
|
||||||
npm-debug.log*
|
|
||||||
yarn-error.log
|
|
||||||
|
|
||||||
# --------------------------------------------------------------------------------------------------
|
|
||||||
# TFS / TFVC specific files and folders
|
|
||||||
# --------------------------------------------------------------------------------------------------
|
|
||||||
$tf/
|
|
||||||
*$tf/
|
|
||||||
*.tf
|
|
||||||
*.tfs
|
|
||||||
.tfignore
|
|
||||||
|
|
||||||
# --------------------------------------------------------------------------------------------------
|
|
||||||
# IDE tooling and workspace settings
|
|
||||||
# --------------------------------------------------------------------------------------------------
|
|
||||||
.vs/
|
.vs/
|
||||||
.vscode/
|
*.user
|
||||||
*.swp
|
packages/
|
||||||
*.sln.docstates
|
F4SDHelper/packages.config
|
||||||
*.VC.VC.opendb
|
F4SDM42WebApi/packages.config
|
||||||
.idea/
|
F4SDM42WebApi/BasePackage/Assemblies/
|
||||||
.DS_Store
|
F4SDM42WebApi/Root/InstalledPackages/
|
||||||
Thumbs.db
|
F4SDHelper/bin/
|
||||||
|
F4SDHelper/obj/
|
||||||
# --------------------------------------------------------------------------------------------------
|
F4SDM42WebApi/bin/
|
||||||
# Test results and profiling data
|
F4SDM42WebApi/obj/
|
||||||
# --------------------------------------------------------------------------------------------------
|
artifacts/
|
||||||
[Tt]est[Rr]esult*/
|
Legacy/BasePackage/Assemblies/
|
||||||
[Bb]uild[Ll]og.*
|
Legacy/PackageTemplate/Assemblies/
|
||||||
*.trx
|
|
||||||
*.coverage
|
|
||||||
*.coveragexml
|
|
||||||
*.opencover.xml
|
|
||||||
*.dotCover
|
|
||||||
BenchmarkDotNet.Artifacts/
|
|
||||||
|
|
||||||
# --------------------------------------------------------------------------------------------------
|
|
||||||
# Miscellaneous recommended ignores
|
|
||||||
# --------------------------------------------------------------------------------------------------
|
|
||||||
_UpgradeReport_Files/
|
|
||||||
Backup*/
|
|
||||||
UpgradeLog*.XML
|
|
||||||
*.tmp
|
|
||||||
*.temp
|
|
||||||
*.log
|
|
||||||
*.bak
|
|
||||||
*.orig
|
|
||||||
*.scc
|
|
||||||
|
|
||||||
|
|||||||
32
AGENTS.md
Normal file
32
AGENTS.md
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
# Repository Instructions
|
||||||
|
|
||||||
|
## Git Completion
|
||||||
|
|
||||||
|
- After completing and verifying requested repository changes, create a Git commit and push the current branch to `origin` unless the user explicitly asks not to commit or push.
|
||||||
|
- Stage only files that belong to the completed task. Leave unrelated local changes, reference material, exports, and generated artifacts untouched.
|
||||||
|
- Report the commit hash and pushed branch to the user.
|
||||||
|
- This Git rule does not authorize any TFS check-in or upload.
|
||||||
|
|
||||||
|
## TFS and Git
|
||||||
|
|
||||||
|
- TFS remains active for the Matrix42 ESM 12.1.3-25.x legacy implementation.
|
||||||
|
- Import TFS changes into Git with `tools/Sync-TfsLegacy.ps1` and review them on a dedicated `sync/tfs-legacy` branch.
|
||||||
|
- Never copy a complete TFS workspace over the sandbox projects.
|
||||||
|
- Never push, check in, or otherwise publish changes to TFS automatically.
|
||||||
|
- The final transfer from Git into TFS is always performed and reviewed manually by the user in Visual Studio.
|
||||||
|
- Do not run `tf checkin`, `tf reconcile`, scripted TFS uploads, or equivalent commands.
|
||||||
|
|
||||||
|
## Platform Ownership
|
||||||
|
|
||||||
|
- `Legacy/` contains the .NET Framework 4.7.2 host for Matrix42 ESM 12.1.3-25.x.
|
||||||
|
- `F4SDM42WebApi/` and `PackageTemplate/` contain the sandboxed .NET 8 host for Matrix42 ESM 26.1 and newer.
|
||||||
|
- `F4SDHelper/Common/C4IT.F4SD.WebApi.Contracts.cs` contains contracts shared only by both Web API variants.
|
||||||
|
- The external `_Common/C4IT.F4SD.Base.Ticket.cs` is shared with other F4SD products and must not be changed merely to simplify this Web API.
|
||||||
|
- Keep platform-specific dependency resolution, controllers, package metadata, and journal access in their respective host.
|
||||||
|
|
||||||
|
## Builds
|
||||||
|
|
||||||
|
- Use `C4IT - F4SD - M42WebApi.sln` for the sandbox build.
|
||||||
|
- Use `C4IT - F4SD - M42WebApi.Legacy.sln` for the legacy build.
|
||||||
|
- `Release_signed` is the optional signed configuration for both variants.
|
||||||
|
- Package versions are derived from `SharedAssemblyInfo.cs`.
|
||||||
32
C4IT - F4SD - M42WebApi.Legacy.sln
Normal file
32
C4IT - F4SD - M42WebApi.Legacy.sln
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||||
|
# Visual Studio Version 17
|
||||||
|
VisualStudioVersion = 17.0.31903.59
|
||||||
|
MinimumVisualStudioVersion = 10.0.40219.1
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "F4SD - Helper (Legacy)", "Legacy\F4SDHelper\F4SD - Helper.Legacy.csproj", "{27A63A98-232D-4D54-A781-E9D493417D59}"
|
||||||
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "F4SD - M42WebApi (Legacy)", "Legacy\F4SDM42WebApi\F4SD - M42WebApi.Legacy.csproj", "{B6316CC4-4827-4D16-A005-DDB8055695BC}"
|
||||||
|
EndProject
|
||||||
|
Global
|
||||||
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
|
Debug|Any CPU = Debug|Any CPU
|
||||||
|
Release|Any CPU = Release|Any CPU
|
||||||
|
Release_signed|Any CPU = Release_signed|Any CPU
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||||
|
{27A63A98-232D-4D54-A781-E9D493417D59}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{27A63A98-232D-4D54-A781-E9D493417D59}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{27A63A98-232D-4D54-A781-E9D493417D59}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{27A63A98-232D-4D54-A781-E9D493417D59}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{27A63A98-232D-4D54-A781-E9D493417D59}.Release_signed|Any CPU.ActiveCfg = Release_signed|Any CPU
|
||||||
|
{27A63A98-232D-4D54-A781-E9D493417D59}.Release_signed|Any CPU.Build.0 = Release_signed|Any CPU
|
||||||
|
{B6316CC4-4827-4D16-A005-DDB8055695BC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{B6316CC4-4827-4D16-A005-DDB8055695BC}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{B6316CC4-4827-4D16-A005-DDB8055695BC}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{B6316CC4-4827-4D16-A005-DDB8055695BC}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{B6316CC4-4827-4D16-A005-DDB8055695BC}.Release_signed|Any CPU.ActiveCfg = Release_signed|Any CPU
|
||||||
|
{B6316CC4-4827-4D16-A005-DDB8055695BC}.Release_signed|Any CPU.Build.0 = Release_signed|Any CPU
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
|
HideSolutionNode = FALSE
|
||||||
|
EndGlobalSection
|
||||||
|
EndGlobal
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
|
|
||||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||||
# Visual Studio Version 17
|
# Visual Studio Version 18
|
||||||
VisualStudioVersion = 17.5.33424.131
|
VisualStudioVersion = 18.7.11919.86 stable
|
||||||
MinimumVisualStudioVersion = 10.0.40219.1
|
MinimumVisualStudioVersion = 10.0.40219.1
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "F4SD - M42WebApi", "F4SDM42WebApi\F4SD - M42WebApi.csproj", "{D8CBFFCA-0B43-4ACC-80EA-C944E7420CEE}"
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "F4SD - M42WebApi", "F4SDM42WebApi\F4SD - M42WebApi.csproj", "{D8CBFFCA-0B43-4ACC-80EA-C944E7420CEE}"
|
||||||
EndProject
|
EndProject
|
||||||
@@ -19,6 +19,7 @@ Global
|
|||||||
Debug_and_copy|Any CPU = Debug_and_copy|Any CPU
|
Debug_and_copy|Any CPU = Debug_and_copy|Any CPU
|
||||||
Debug|Any CPU = Debug|Any CPU
|
Debug|Any CPU = Debug|Any CPU
|
||||||
Release_and_copy|Any CPU = Release_and_copy|Any CPU
|
Release_and_copy|Any CPU = Release_and_copy|Any CPU
|
||||||
|
Release_signed|Any CPU = Release_signed|Any CPU
|
||||||
Release|Any CPU = Release|Any CPU
|
Release|Any CPU = Release|Any CPU
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||||
@@ -28,6 +29,8 @@ Global
|
|||||||
{D8CBFFCA-0B43-4ACC-80EA-C944E7420CEE}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
{D8CBFFCA-0B43-4ACC-80EA-C944E7420CEE}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
{D8CBFFCA-0B43-4ACC-80EA-C944E7420CEE}.Release_and_copy|Any CPU.ActiveCfg = Release_and_copy|Any CPU
|
{D8CBFFCA-0B43-4ACC-80EA-C944E7420CEE}.Release_and_copy|Any CPU.ActiveCfg = Release_and_copy|Any CPU
|
||||||
{D8CBFFCA-0B43-4ACC-80EA-C944E7420CEE}.Release_and_copy|Any CPU.Build.0 = Release_and_copy|Any CPU
|
{D8CBFFCA-0B43-4ACC-80EA-C944E7420CEE}.Release_and_copy|Any CPU.Build.0 = Release_and_copy|Any CPU
|
||||||
|
{D8CBFFCA-0B43-4ACC-80EA-C944E7420CEE}.Release_signed|Any CPU.ActiveCfg = Release_signed|Any CPU
|
||||||
|
{D8CBFFCA-0B43-4ACC-80EA-C944E7420CEE}.Release_signed|Any CPU.Build.0 = Release_signed|Any CPU
|
||||||
{D8CBFFCA-0B43-4ACC-80EA-C944E7420CEE}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
{D8CBFFCA-0B43-4ACC-80EA-C944E7420CEE}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
{D8CBFFCA-0B43-4ACC-80EA-C944E7420CEE}.Release|Any CPU.Build.0 = Release|Any CPU
|
{D8CBFFCA-0B43-4ACC-80EA-C944E7420CEE}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
{EB95E1FB-7A9E-4894-BD28-2D0BE2715EBE}.Debug_and_copy|Any CPU.ActiveCfg = Debug|Any CPU
|
{EB95E1FB-7A9E-4894-BD28-2D0BE2715EBE}.Debug_and_copy|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
@@ -36,6 +39,8 @@ Global
|
|||||||
{EB95E1FB-7A9E-4894-BD28-2D0BE2715EBE}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
{EB95E1FB-7A9E-4894-BD28-2D0BE2715EBE}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
{EB95E1FB-7A9E-4894-BD28-2D0BE2715EBE}.Release_and_copy|Any CPU.ActiveCfg = Release_and_copy|Any CPU
|
{EB95E1FB-7A9E-4894-BD28-2D0BE2715EBE}.Release_and_copy|Any CPU.ActiveCfg = Release_and_copy|Any CPU
|
||||||
{EB95E1FB-7A9E-4894-BD28-2D0BE2715EBE}.Release_and_copy|Any CPU.Build.0 = Release_and_copy|Any CPU
|
{EB95E1FB-7A9E-4894-BD28-2D0BE2715EBE}.Release_and_copy|Any CPU.Build.0 = Release_and_copy|Any CPU
|
||||||
|
{EB95E1FB-7A9E-4894-BD28-2D0BE2715EBE}.Release_signed|Any CPU.ActiveCfg = Release_signed|Any CPU
|
||||||
|
{EB95E1FB-7A9E-4894-BD28-2D0BE2715EBE}.Release_signed|Any CPU.Build.0 = Release_signed|Any CPU
|
||||||
{EB95E1FB-7A9E-4894-BD28-2D0BE2715EBE}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
{EB95E1FB-7A9E-4894-BD28-2D0BE2715EBE}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
{EB95E1FB-7A9E-4894-BD28-2D0BE2715EBE}.Release|Any CPU.Build.0 = Release|Any CPU
|
{EB95E1FB-7A9E-4894-BD28-2D0BE2715EBE}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
@@ -47,25 +52,6 @@ Global
|
|||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(SharedMSBuildProjectFiles) = preSolution
|
GlobalSection(SharedMSBuildProjectFiles) = preSolution
|
||||||
M42F4SDUUXWorkspace\M42F4SDUUXWorkspace.projitems*{c3d52a04-2461-4f35-8edf-de7226add677}*SharedItemsImports = 13
|
M42F4SDUUXWorkspace\M42F4SDUUXWorkspace.projitems*{c3d52a04-2461-4f35-8edf-de7226add677}*SharedItemsImports = 13
|
||||||
M42F4SDUUXWorkspace\M42F4SDUUXWorkspace.projitems*{d8cbffca-0b43-4acc-80ea-c944e7420cee}*SharedItemsImports = 4
|
M42F4SDUUXWorkspace\M42F4SDUUXWorkspace.projitems*{d8cbffca-0b43-4acc-80ea-c944e7420cee}*SharedItemsImports = 5
|
||||||
EndGlobalSection
|
|
||||||
GlobalSection(TeamFoundationVersionControl) = preSolution
|
|
||||||
SccNumberOfProjects = 5
|
|
||||||
SccEnterpriseProvider = {4CA58AB2-18FA-4F8D-95D4-32DDF27D184C}
|
|
||||||
SccTeamFoundationServer = https://consulting4it.visualstudio.com/
|
|
||||||
SccLocalPath0 = .
|
|
||||||
SccProjectUniqueName1 = F4SDHelper\\F4SD\u0020-\u0020Helper.csproj
|
|
||||||
SccProjectName1 = F4SDHelper
|
|
||||||
SccLocalPath1 = F4SDHelper
|
|
||||||
SccProjectUniqueName2 = F4SDM42WebApi\\F4SD\u0020-\u0020M42WebApi.csproj
|
|
||||||
SccProjectName2 = F4SDM42WebApi
|
|
||||||
SccLocalPath2 = F4SDM42WebApi
|
|
||||||
SccProjectUniqueName3 = M42F4SDUUXWorkspace\\F4SD\u0020-\u0020M42\u0020UUX\u0020Workspace.shproj
|
|
||||||
SccProjectName3 = M42F4SDUUXWorkspace
|
|
||||||
SccLocalPath3 = M42F4SDUUXWorkspace
|
|
||||||
SccProjectUniqueName4 = M42F4SDUUXWorkspace\\M42F4SDUUXWorkspace.projitems
|
|
||||||
SccProjectTopLevelParentUniqueName4 = M42F4SDUUXWorkspace\\F4SD\u0020-\u0020M42\u0020UUX\u0020Workspace.shproj
|
|
||||||
SccProjectName4 = M42F4SDUUXWorkspace
|
|
||||||
SccLocalPath4 = M42F4SDUUXWorkspace
|
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
EndGlobal
|
EndGlobal
|
||||||
|
|||||||
@@ -1,11 +1,2 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<configuration>
|
<configuration />
|
||||||
<runtime>
|
|
||||||
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
|
|
||||||
<dependentAssembly>
|
|
||||||
<assemblyIdentity name="Newtonsoft.Json" publicKeyToken="30ad4fe6b2a6aeed" culture="neutral" />
|
|
||||||
<bindingRedirect oldVersion="0.0.0.0-13.0.0.0" newVersion="13.0.0.0" />
|
|
||||||
</dependentAssembly>
|
|
||||||
</assemblyBinding>
|
|
||||||
</runtime>
|
|
||||||
</configuration>
|
|
||||||
|
|||||||
58
F4SDHelper/Common/C4IT.F4SD.WebApi.Contracts.cs
Normal file
58
F4SDHelper/Common/C4IT.F4SD.WebApi.Contracts.cs
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace C4IT.FASD.Base
|
||||||
|
{
|
||||||
|
public class cF4SDTicket : cF4SDTicketSummary
|
||||||
|
{
|
||||||
|
public enum enumTicketCreationSource
|
||||||
|
{
|
||||||
|
Unknown = 0,
|
||||||
|
Mail = 1,
|
||||||
|
Phone = 2,
|
||||||
|
F4SD = 3
|
||||||
|
}
|
||||||
|
|
||||||
|
public class cTicketJournalItem
|
||||||
|
{
|
||||||
|
public DateTime CreationDate { get; set; }
|
||||||
|
public string Header { get; set; }
|
||||||
|
public string CreatedBy { get; set; }
|
||||||
|
public string DescriptionHtml { get; set; }
|
||||||
|
public string Description { get; set; }
|
||||||
|
public bool IsVisibleForUser { get; set; }
|
||||||
|
public Guid ActivityObjectId { get; set; }
|
||||||
|
public Guid JournalId { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public Guid AffectedUserId { get; set; }
|
||||||
|
public Guid AssetId { get; set; }
|
||||||
|
public DateTime CreationDate { get; set; }
|
||||||
|
public DateTime? ClosingDate { get; set; }
|
||||||
|
public int CreationSourceId { get; set; }
|
||||||
|
public string CreationSource { get; set; }
|
||||||
|
public string Description { get; set; }
|
||||||
|
public string DescriptionHtml { get; set; }
|
||||||
|
public int PriorityId { get; set; }
|
||||||
|
public string Priority { get; set; }
|
||||||
|
public Guid CategoryId { get; set; }
|
||||||
|
public string Category { get; set; }
|
||||||
|
public string CategoryHierarchical { get; set; }
|
||||||
|
public string CIName { get; set; }
|
||||||
|
public string DirectLinkEdit { get; set; }
|
||||||
|
public Guid AssetCIId { get; set; }
|
||||||
|
public int AssetSKUAssetGroupId { get; set; }
|
||||||
|
public string AssetSKUAssetGroup { get; set; }
|
||||||
|
public int AssetSKUTypeId { get; set; }
|
||||||
|
public string AssetSKUType { get; set; }
|
||||||
|
public string DirectLinkPreview { get; set; }
|
||||||
|
public string DirectLinkClose { get; set; }
|
||||||
|
public string AffectedUser { get; set; }
|
||||||
|
public string SolutionHtml { get; set; }
|
||||||
|
public string Solution { get; set; }
|
||||||
|
public string AssetDomain { get; set; }
|
||||||
|
public string Urgency { get; set; }
|
||||||
|
public int UrgencyId { get; set; }
|
||||||
|
public string Impact { get; set; }
|
||||||
|
public int ImpactId { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,500 +0,0 @@
|
|||||||
using Newtonsoft.Json;
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using static C4IT.Logging.cLogManager;
|
|
||||||
|
|
||||||
namespace C4IT.FASD.Base
|
|
||||||
{
|
|
||||||
public enum enumFasdInformationClass
|
|
||||||
{
|
|
||||||
Unknown = -1,
|
|
||||||
Main = 0,
|
|
||||||
Computer = 1,
|
|
||||||
User = 2,
|
|
||||||
Ticket = 3
|
|
||||||
}
|
|
||||||
|
|
||||||
public enum enumF4sdSearchResultClass
|
|
||||||
{
|
|
||||||
Unknown = -1,
|
|
||||||
Computer = 0,
|
|
||||||
User = 1,
|
|
||||||
Phone = 2,
|
|
||||||
Ticket = 3
|
|
||||||
}
|
|
||||||
|
|
||||||
public enum enumF4sdSearchResultStatus
|
|
||||||
{
|
|
||||||
Unknown = -1,
|
|
||||||
Inactive = 0,
|
|
||||||
Active = 1
|
|
||||||
}
|
|
||||||
|
|
||||||
public enum enumFasdValueType
|
|
||||||
{
|
|
||||||
Unknown = 0,
|
|
||||||
STRING = 1,
|
|
||||||
GUID = 2,
|
|
||||||
INT = 3,
|
|
||||||
BIGINT = 4,
|
|
||||||
FLOAT = 5,
|
|
||||||
DATETIME = 6,
|
|
||||||
VERSION = 7,
|
|
||||||
MD5 = 8,
|
|
||||||
SID = 9,
|
|
||||||
IPV4 = 10,
|
|
||||||
IPV6 = 11,
|
|
||||||
TEXT = 12,
|
|
||||||
BOOLEAN = 13,
|
|
||||||
AUTOID = 255
|
|
||||||
};
|
|
||||||
|
|
||||||
public enum enumFasdCharCaseType { none = 0, lower = 1, upper = 2 };
|
|
||||||
|
|
||||||
public enum enumFasdConfigurationType
|
|
||||||
{
|
|
||||||
unknown = 0,
|
|
||||||
commonIcons,
|
|
||||||
menuSections,
|
|
||||||
quickActions,
|
|
||||||
copyTemplates,
|
|
||||||
healthCard
|
|
||||||
}
|
|
||||||
|
|
||||||
public class cFasdApiConnectionInfo
|
|
||||||
{
|
|
||||||
public string ServerVersion { get; set; }
|
|
||||||
public string MinCockpitVersion { get; set; }
|
|
||||||
public UInt64 ConfigRevision { get; set; } = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
public class cAgentApiConfiguration
|
|
||||||
{
|
|
||||||
public string LogonUrl { get; set; }
|
|
||||||
public string ApiUrl { get; set; }
|
|
||||||
public string ClientId { get; set; }
|
|
||||||
public string ClientSecret { get; set; }
|
|
||||||
public int? OrganizationCode { get; set; }
|
|
||||||
|
|
||||||
[JsonIgnore]
|
|
||||||
public static cAgentApiConfiguration Instance { get; set; }
|
|
||||||
}
|
|
||||||
|
|
||||||
public class cFasdApiSearchResultDefault
|
|
||||||
{
|
|
||||||
public enumF4sdSearchResultClass Type { get; set; }
|
|
||||||
public string Name { get; set; }
|
|
||||||
public Guid id { get; set; }
|
|
||||||
public enumF4sdSearchResultStatus Status { get; set; } = enumF4sdSearchResultStatus.Unknown;
|
|
||||||
public Dictionary<string, string> Infos { get; set; } = null;
|
|
||||||
|
|
||||||
static public enumF4sdSearchResultClass getSearchClass(enumFasdInformationClass infoClass)
|
|
||||||
{
|
|
||||||
switch (infoClass)
|
|
||||||
{
|
|
||||||
case enumFasdInformationClass.User:
|
|
||||||
return enumF4sdSearchResultClass.User;
|
|
||||||
case enumFasdInformationClass.Computer:
|
|
||||||
return enumF4sdSearchResultClass.Computer;
|
|
||||||
default:
|
|
||||||
return enumF4sdSearchResultClass.Unknown;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public class cF4sdIdentityEntry
|
|
||||||
{
|
|
||||||
public enumFasdInformationClass Class { get; set; }
|
|
||||||
public Guid Id { get; set; }
|
|
||||||
|
|
||||||
public static enumFasdInformationClass GetFromSearchResult(enumF4sdSearchResultClass searchResult)
|
|
||||||
{
|
|
||||||
var infoClass = enumFasdInformationClass.Unknown;
|
|
||||||
switch (searchResult)
|
|
||||||
{
|
|
||||||
case enumF4sdSearchResultClass.Computer:
|
|
||||||
infoClass = enumFasdInformationClass.Computer;
|
|
||||||
break;
|
|
||||||
case enumF4sdSearchResultClass.User:
|
|
||||||
case enumF4sdSearchResultClass.Phone:
|
|
||||||
infoClass = enumFasdInformationClass.User;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return infoClass;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public class cF4sdApiSearchResultRelation : cFasdApiSearchResultDefault
|
|
||||||
{
|
|
||||||
public DateTime LastUsed { get; set; }
|
|
||||||
public double UsingLevel { get; set; }
|
|
||||||
public List<cF4sdIdentityEntry> Identities { get; set; } = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public class cF4sdHealthCardRawDataRequest
|
|
||||||
{
|
|
||||||
public List<string> Tables { get; set; }
|
|
||||||
public List<cF4sdIdentityEntry> Identities { get; set; }
|
|
||||||
|
|
||||||
public int MaxAge { get; set; } = 14;
|
|
||||||
|
|
||||||
public DateTime RefTime { get; set; } = DateTime.Now.Date.ToUniversalTime();
|
|
||||||
}
|
|
||||||
|
|
||||||
public class cF4SDHealthCardRawData
|
|
||||||
{
|
|
||||||
public class cHealthCardTableColumn
|
|
||||||
{
|
|
||||||
public string ColumnName { get; set; }
|
|
||||||
public List<object> Values { get; set; } = new List<object>();
|
|
||||||
public bool IsIncomplete { get; set; } = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public class cHealthCardTable
|
|
||||||
{
|
|
||||||
public string Name { get; set; }
|
|
||||||
public int StartingIndex { get; set; } = 0;
|
|
||||||
public bool IsIncomplete { get; set; } = false;
|
|
||||||
public bool IsStatic { get; set; }
|
|
||||||
public DateTime[,] TimeFrames { get; set; }
|
|
||||||
public Dictionary<string, cHealthCardTableColumn> Columns { get; set; } = new Dictionary<string, cHealthCardTableColumn>();
|
|
||||||
}
|
|
||||||
|
|
||||||
public class cHealthCardDetailsTable
|
|
||||||
{
|
|
||||||
public string Name { get; set; }
|
|
||||||
public List<string> Columns { get; set; }
|
|
||||||
public Dictionary<int, List<object[]>> Values { get; set; }
|
|
||||||
}
|
|
||||||
|
|
||||||
public Guid Id { get; set; }
|
|
||||||
|
|
||||||
public Dictionary<string, cHealthCardTable> Tables { get; set; } = new Dictionary<string, cHealthCardTable>();
|
|
||||||
|
|
||||||
#region GetObjects
|
|
||||||
|
|
||||||
#region GetInteger
|
|
||||||
|
|
||||||
public static int? GetInteger(object Value, int? Default = null)
|
|
||||||
{
|
|
||||||
int? output = Default;
|
|
||||||
|
|
||||||
if (Value == null)
|
|
||||||
return output;
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var valuetype = Value.GetType();
|
|
||||||
|
|
||||||
if (Value is int @int)
|
|
||||||
output = @int;
|
|
||||||
if (Value is Int64 @int64)
|
|
||||||
output = Convert.ToInt32(@int64);
|
|
||||||
else if (Value is double @double)
|
|
||||||
output = Convert.ToInt32(@double);
|
|
||||||
else if (Value is string @string)
|
|
||||||
{
|
|
||||||
if (int.TryParse(@string, out int parsedInt))
|
|
||||||
output = parsedInt;
|
|
||||||
else
|
|
||||||
output = Default;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception E)
|
|
||||||
{
|
|
||||||
LogException(E);
|
|
||||||
}
|
|
||||||
|
|
||||||
return output;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int? GetIntegerByAddressInfo(string TableName, string TableColumn, int index = 0, int? Default = null)
|
|
||||||
{
|
|
||||||
int? output = Default;
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
if (Tables.TryGetValue(TableName, out var selectedTable))
|
|
||||||
if (selectedTable.Columns.TryGetValue(TableColumn, out var selectedColumn))
|
|
||||||
output = GetInteger(selectedColumn.Values[index], Default);
|
|
||||||
}
|
|
||||||
catch (Exception E)
|
|
||||||
{
|
|
||||||
LogException(E);
|
|
||||||
}
|
|
||||||
|
|
||||||
return output;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region GetString
|
|
||||||
|
|
||||||
public static string GetString(object Value, string Default = null)
|
|
||||||
{
|
|
||||||
string output = Default;
|
|
||||||
try
|
|
||||||
{
|
|
||||||
if (Value is int @int)
|
|
||||||
output = Convert.ToString(@int);
|
|
||||||
else if (Value is double @double)
|
|
||||||
output = Convert.ToString(@double);
|
|
||||||
else if (Value is string @string)
|
|
||||||
output = @string;
|
|
||||||
}
|
|
||||||
catch (Exception E)
|
|
||||||
{
|
|
||||||
LogException(E);
|
|
||||||
}
|
|
||||||
|
|
||||||
return output?.ToString();
|
|
||||||
}
|
|
||||||
|
|
||||||
public string GetStringByAddressInfo(string TableName, string TableColumn, int index = 0, string Default = null)
|
|
||||||
{
|
|
||||||
string output = Default;
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
if (Tables.TryGetValue(TableName, out var selectedTable))
|
|
||||||
if (selectedTable.Columns.TryGetValue(TableColumn, out var selectedColumn))
|
|
||||||
output = GetString(selectedColumn.Values[index], Default);
|
|
||||||
}
|
|
||||||
catch (Exception E)
|
|
||||||
{
|
|
||||||
LogException(E);
|
|
||||||
}
|
|
||||||
|
|
||||||
return output;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region GetVersion
|
|
||||||
|
|
||||||
public static Version GetVersion(object Value, Version Default = null)
|
|
||||||
{
|
|
||||||
Version output = Default;
|
|
||||||
|
|
||||||
if (Value == null)
|
|
||||||
return output;
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
if (Value is string @string)
|
|
||||||
{
|
|
||||||
if (Version.TryParse(@string, out var tempVersionFromString))
|
|
||||||
output = tempVersionFromString;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception E)
|
|
||||||
{
|
|
||||||
LogException(E);
|
|
||||||
}
|
|
||||||
|
|
||||||
return output;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Version GetVersionByAddressInfo(string TableName, string TableColumn, int index = 0, Version Default = null)
|
|
||||||
{
|
|
||||||
Version output = Default;
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
if (Tables.TryGetValue(TableName, out var selectedTable))
|
|
||||||
if (selectedTable.Columns.TryGetValue(TableColumn, out var selectedColumn))
|
|
||||||
output = GetVersion(selectedColumn.Values[index], Default);
|
|
||||||
}
|
|
||||||
catch (Exception E)
|
|
||||||
{
|
|
||||||
LogException(E);
|
|
||||||
}
|
|
||||||
|
|
||||||
return output;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region GetDateTime
|
|
||||||
|
|
||||||
public static DateTime? GetDateTime(object Value, DateTime? Default = null)
|
|
||||||
{
|
|
||||||
DateTime? output = Default;
|
|
||||||
|
|
||||||
if (Value == null)
|
|
||||||
return output;
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
if (Value is DateTime time)
|
|
||||||
output = time;
|
|
||||||
else if (Value is string @string)
|
|
||||||
{
|
|
||||||
var tempOutput = Convert.ToDateTime(@string);
|
|
||||||
DateTime.SpecifyKind(tempOutput, DateTimeKind.Utc);
|
|
||||||
if (tempOutput != null)
|
|
||||||
output = tempOutput;
|
|
||||||
else
|
|
||||||
output = Default;
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception E)
|
|
||||||
{
|
|
||||||
LogException(E);
|
|
||||||
}
|
|
||||||
|
|
||||||
return output;
|
|
||||||
}
|
|
||||||
|
|
||||||
public DateTime? GetDateTimeByAddressInfo(string TableName, string TableColumn, int index = 0, DateTime? Default = null)
|
|
||||||
{
|
|
||||||
DateTime? output = Default;
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
if (Tables.TryGetValue(TableName, out var selectedTable))
|
|
||||||
if (selectedTable.Columns.TryGetValue(TableColumn, out var selectedColumn))
|
|
||||||
output = GetDateTime(selectedColumn.Values[index], Default);
|
|
||||||
}
|
|
||||||
catch (Exception E)
|
|
||||||
{
|
|
||||||
LogException(E);
|
|
||||||
}
|
|
||||||
|
|
||||||
return output;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region GetDouble
|
|
||||||
|
|
||||||
public static double? GetDouble(object Value, double? Default = null)
|
|
||||||
{
|
|
||||||
double? output = Default;
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
if (Value is int @int)
|
|
||||||
output = Convert.ToDouble(@int);
|
|
||||||
else if (Value is Int64 @int64)
|
|
||||||
output = Convert.ToDouble(@int64);
|
|
||||||
else if (Value is double @double)
|
|
||||||
output = @double;
|
|
||||||
else if (Value is string @string)
|
|
||||||
{
|
|
||||||
if (double.TryParse(@string, System.Globalization.NumberStyles.Any, System.Globalization.CultureInfo.GetCultureInfo("en-US").NumberFormat, out double tempOutput))
|
|
||||||
output = tempOutput;
|
|
||||||
else
|
|
||||||
output = Default;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception E)
|
|
||||||
{
|
|
||||||
LogException(E);
|
|
||||||
}
|
|
||||||
|
|
||||||
return output;
|
|
||||||
}
|
|
||||||
|
|
||||||
public double? GetDoubleByAddressInfo(string TableName, string TableColumn, int index = 0, double? Default = null)
|
|
||||||
{
|
|
||||||
double? output = Default;
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
if (Tables.TryGetValue(TableName, out var selectedTable))
|
|
||||||
if (selectedTable.Columns.TryGetValue(TableColumn, out var selectedColumn))
|
|
||||||
output = GetDouble(selectedColumn.Values[index], Default);
|
|
||||||
}
|
|
||||||
catch (Exception E)
|
|
||||||
{
|
|
||||||
LogException(E);
|
|
||||||
}
|
|
||||||
|
|
||||||
return output;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
}
|
|
||||||
public class cApiM42TicketQueueInfo
|
|
||||||
{
|
|
||||||
public string QueueName { get; set; }
|
|
||||||
public Guid QueueID { get; set; }
|
|
||||||
}
|
|
||||||
|
|
||||||
public class cF4SDTicketSummary
|
|
||||||
{
|
|
||||||
public Guid TicketObjectId { get; set; }
|
|
||||||
public string Name { get; set; }
|
|
||||||
public string ActivityType { get; set; }
|
|
||||||
public string Summary { get; set; }
|
|
||||||
public string Sid { get; set; }
|
|
||||||
public string Status { get; set; }
|
|
||||||
public int StatusId { get; set; }
|
|
||||||
public string Urgency { get; set; }
|
|
||||||
public int UrgencyId { get; set; }
|
|
||||||
public string Impact { get; set; }
|
|
||||||
public int ImpactId { get; set; }
|
|
||||||
public string AssetCIName { get; set; }
|
|
||||||
public string AssetName { get; set; }
|
|
||||||
public string ServiceName { get; set; }
|
|
||||||
public Guid ServiceId { get; set; }
|
|
||||||
public bool IsPrimaryAccount { get; set; }
|
|
||||||
}
|
|
||||||
|
|
||||||
public class cF4SDTicket : cF4SDTicketSummary
|
|
||||||
{
|
|
||||||
public enum enumTicketCreationSource
|
|
||||||
{
|
|
||||||
Unknown = 0,
|
|
||||||
Mail = 1,
|
|
||||||
Phone = 2,
|
|
||||||
F4SD = 3
|
|
||||||
}
|
|
||||||
|
|
||||||
public class cTicketJournalItem
|
|
||||||
{
|
|
||||||
public DateTime CreationDate { get; set; }
|
|
||||||
public string Header { get; set; }
|
|
||||||
public string CreatedBy { get; set; }
|
|
||||||
public string DescriptionHtml { get; set; }
|
|
||||||
public string Description { get; set; }
|
|
||||||
public bool IsVisibleForUser { get; set; }
|
|
||||||
public Guid ActivityObjectId { get; set; }
|
|
||||||
public Guid JournalId { get; set; }
|
|
||||||
}
|
|
||||||
|
|
||||||
public Guid AffectedUserId { get; set; }
|
|
||||||
public Guid AssetId { get; set; }
|
|
||||||
public DateTime CreationDate { get; set; }
|
|
||||||
public DateTime? ClosingDate { get; set; }
|
|
||||||
public int CreationSourceId { get; set; }
|
|
||||||
public string CreationSource { get; set; }
|
|
||||||
|
|
||||||
public string Description { get; set; }
|
|
||||||
public string DescriptionHtml { get; set; }
|
|
||||||
public int PriorityId { get; set; }
|
|
||||||
public string Priority { get; set; }
|
|
||||||
public Guid CategoryId { get; set; }
|
|
||||||
public string Category { get; set; }
|
|
||||||
public string CategoryHierarchical { get; set; }
|
|
||||||
public string CIName { get; set; }
|
|
||||||
public string DirectLinkEdit { get; set; }
|
|
||||||
public Guid AssetCIId { get; set; }
|
|
||||||
public int AssetSKUAssetGroupId { get; set; }
|
|
||||||
public string AssetSKUAssetGroup { get; set; }
|
|
||||||
public int AssetSKUTypeId { get; set; }
|
|
||||||
public string AssetSKUType { get; set; }
|
|
||||||
public string DirectLinkPreview { get; set; }
|
|
||||||
public string DirectLinkClose { get; set; }
|
|
||||||
public string AffectedUser { get; set; }
|
|
||||||
public string SolutionHtml { get; set; }
|
|
||||||
public string Solution { get; set; }
|
|
||||||
public string AssetDomain { get; set; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,75 +1,46 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
|
||||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
|
||||||
<ProjectGuid>{EB95E1FB-7A9E-4894-BD28-2D0BE2715EBE}</ProjectGuid>
|
|
||||||
<OutputType>Library</OutputType>
|
<OutputType>Library</OutputType>
|
||||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
|
||||||
<RootNamespace>C4IT.F4SDM</RootNamespace>
|
<RootNamespace>C4IT.F4SDM</RootNamespace>
|
||||||
<AssemblyName>C4ITF4SDM42WebApiHelper</AssemblyName>
|
<AssemblyName>C4ITF4SDM42WebApiHelper</AssemblyName>
|
||||||
<TargetFrameworkVersion>v4.7.2</TargetFrameworkVersion>
|
<Nullable>disable</Nullable>
|
||||||
<FileAlignment>512</FileAlignment>
|
<ImplicitUsings>disable</ImplicitUsings>
|
||||||
<Deterministic>true</Deterministic>
|
<LangVersion>latestmajor</LangVersion>
|
||||||
<TargetFrameworkProfile />
|
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
||||||
<SccProjectName>SAK</SccProjectName>
|
<EnableDefaultCompileItems>false</EnableDefaultCompileItems>
|
||||||
<SccLocalPath>SAK</SccLocalPath>
|
<Configurations>Debug;Release;Debug_and_copy;Release_and_copy;Release_signed</Configurations>
|
||||||
<SccAuxPath>SAK</SccAuxPath>
|
<F4SDCommonRoot Condition="'$(F4SDCommonRoot)' == ''">$(MSBuildProjectDirectory)\..\..\_Common</F4SDCommonRoot>
|
||||||
<SccProvider>SAK</SccProvider>
|
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
|
||||||
<DebugSymbols>true</DebugSymbols>
|
<PropertyGroup Condition="'$(Configuration)' == 'Release_signed'">
|
||||||
<DebugType>full</DebugType>
|
|
||||||
<Optimize>false</Optimize>
|
|
||||||
<OutputPath>bin\Debug\</OutputPath>
|
|
||||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
|
||||||
<ErrorReport>prompt</ErrorReport>
|
|
||||||
<WarningLevel>4</WarningLevel>
|
|
||||||
</PropertyGroup>
|
|
||||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
|
||||||
<DebugType>pdbonly</DebugType>
|
|
||||||
<Optimize>true</Optimize>
|
<Optimize>true</Optimize>
|
||||||
<OutputPath>bin\Release\</OutputPath>
|
|
||||||
<DefineConstants>TRACE</DefineConstants>
|
|
||||||
<ErrorReport>prompt</ErrorReport>
|
|
||||||
<WarningLevel>4</WarningLevel>
|
|
||||||
</PropertyGroup>
|
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release_and_copy|AnyCPU'">
|
|
||||||
<OutputPath>bin\Release_and_copy\</OutputPath>
|
|
||||||
<DefineConstants>TRACE</DefineConstants>
|
|
||||||
<Optimize>true</Optimize>
|
|
||||||
<DebugType>pdbonly</DebugType>
|
|
||||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
|
||||||
<LangVersion>7.3</LangVersion>
|
|
||||||
<ErrorReport>prompt</ErrorReport>
|
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Reference Include="Newtonsoft.Json, Version=13.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
|
<Reference Include="Newtonsoft.Json">
|
||||||
<HintPath>..\packages\Newtonsoft.Json.13.0.3\lib\net45\Newtonsoft.Json.dll</HintPath>
|
<HintPath>..\F4SDM42WebApi\M42Libraries\26.1\Newtonsoft.Json.dll</HintPath>
|
||||||
|
<Private>false</Private>
|
||||||
</Reference>
|
</Reference>
|
||||||
<Reference Include="System" />
|
|
||||||
<Reference Include="System.Core" />
|
|
||||||
<Reference Include="System.Xml.Linq" />
|
|
||||||
<Reference Include="System.Data.DataSetExtensions" />
|
|
||||||
<Reference Include="Microsoft.CSharp" />
|
|
||||||
<Reference Include="System.Data" />
|
|
||||||
<Reference Include="System.Net.Http" />
|
|
||||||
<Reference Include="System.Xml" />
|
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||||
<Compile Include="..\..\..\Common Code\Logging\C4IT.Logging.LogManager.cs">
|
<Compile Include="..\..\..\Common Code\Logging\C4IT.Logging.LogManager.cs">
|
||||||
<Link>Common\C4IT.Logging.LogManager.cs</Link>
|
<Link>Common\C4IT.Logging.LogManager.cs</Link>
|
||||||
</Compile>
|
</Compile>
|
||||||
|
<Compile Include="$(F4SDCommonRoot)\C4IT.F4SD.Base.Ticket.cs">
|
||||||
|
<Link>Common\C4IT.F4SD.Base.Ticket.cs</Link>
|
||||||
|
</Compile>
|
||||||
|
<Compile Include="Common\C4IT.F4SD.WebApi.Contracts.cs" />
|
||||||
<Compile Include="..\SharedAssemblyInfo.cs">
|
<Compile Include="..\SharedAssemblyInfo.cs">
|
||||||
<Link>Properties\SharedAssemblyInfo.cs</Link>
|
<Link>Properties\SharedAssemblyInfo.cs</Link>
|
||||||
</Compile>
|
</Compile>
|
||||||
<Compile Include="Common\C4IT.FASD.Base.cs" />
|
|
||||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
|
||||||
<None Include="App.config" />
|
<Target Name="ValidateF4SDCommonSources" BeforeTargets="PrepareForBuild">
|
||||||
<None Include="packages.config" />
|
<Error Condition="!Exists('$(F4SDCommonRoot)\C4IT.F4SD.Base.Ticket.cs')"
|
||||||
</ItemGroup>
|
Text="Shared F4SD contract source not found. Set F4SDCommonRoot to the _Common directory containing C4IT.F4SD.Base.Ticket.cs." />
|
||||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
</Target>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<configuration>
|
|
||||||
<runtime>
|
|
||||||
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
|
|
||||||
<dependentAssembly>
|
|
||||||
<assemblyIdentity name="Newtonsoft.Json" publicKeyToken="30ad4fe6b2a6aeed" culture="neutral" />
|
|
||||||
<bindingRedirect oldVersion="0.0.0.0-12.0.0.0" newVersion="12.0.0.0" />
|
|
||||||
</dependentAssembly>
|
|
||||||
<dependentAssembly>
|
|
||||||
<assemblyIdentity name="System.Web.Http" publicKeyToken="31bf3856ad364e35" culture="neutral" />
|
|
||||||
<bindingRedirect oldVersion="0.0.0.0-5.2.3.0" newVersion="5.2.3.0" />
|
|
||||||
</dependentAssembly>
|
|
||||||
</assemblyBinding>
|
|
||||||
</runtime>
|
|
||||||
</configuration>
|
|
||||||
94
F4SDM42WebApi/BuildM42Package.ps1
Normal file
94
F4SDM42WebApi/BuildM42Package.ps1
Normal file
@@ -0,0 +1,94 @@
|
|||||||
|
param(
|
||||||
|
[Parameter(Mandatory = $true)]
|
||||||
|
[string]$TemplateDir,
|
||||||
|
|
||||||
|
[Parameter(Mandatory = $true)]
|
||||||
|
[string]$AssembliesDir,
|
||||||
|
|
||||||
|
[Parameter(Mandatory = $true)]
|
||||||
|
[string]$OutputRoot,
|
||||||
|
|
||||||
|
[Parameter(Mandatory = $true)]
|
||||||
|
[string]$PackageName,
|
||||||
|
|
||||||
|
[Parameter(Mandatory = $true)]
|
||||||
|
[string]$PackageVersion
|
||||||
|
)
|
||||||
|
|
||||||
|
$ErrorActionPreference = 'Stop'
|
||||||
|
|
||||||
|
function Normalize-FullPath {
|
||||||
|
param([string]$Path)
|
||||||
|
return [System.IO.Path]::GetFullPath($Path)
|
||||||
|
}
|
||||||
|
|
||||||
|
function Normalize-TextFileLineEndings {
|
||||||
|
param([string]$Path)
|
||||||
|
|
||||||
|
$content = [System.IO.File]::ReadAllText($Path)
|
||||||
|
$content = [regex]::Replace($content, '(?<!\r)\n', "`r`n")
|
||||||
|
[System.IO.File]::WriteAllText($Path, $content, [System.Text.UTF8Encoding]::new($true))
|
||||||
|
}
|
||||||
|
|
||||||
|
$templateDirFull = Normalize-FullPath $TemplateDir
|
||||||
|
$assembliesDirFull = Normalize-FullPath $AssembliesDir
|
||||||
|
$outputRootFull = Normalize-FullPath $OutputRoot
|
||||||
|
$packageDir = Join-Path $outputRootFull "$PackageName v$PackageVersion"
|
||||||
|
$zipPath = "$packageDir.zip"
|
||||||
|
|
||||||
|
if (-not (Test-Path -LiteralPath (Join-Path $templateDirFull 'package.json'))) {
|
||||||
|
throw "Package template not found: $templateDirFull"
|
||||||
|
}
|
||||||
|
|
||||||
|
if (-not (Get-ChildItem -LiteralPath $assembliesDirFull -Filter 'C4ITF4SDM42WebApi.dll' -File -Recurse | Select-Object -First 1)) {
|
||||||
|
throw "Package assemblies not found: $assembliesDirFull"
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Test-Path -LiteralPath $packageDir) {
|
||||||
|
Remove-Item -LiteralPath $packageDir -Recurse -Force
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Test-Path -LiteralPath $zipPath) {
|
||||||
|
Remove-Item -LiteralPath $zipPath -Force
|
||||||
|
}
|
||||||
|
|
||||||
|
New-Item -ItemType Directory -Path $packageDir -Force | Out-Null
|
||||||
|
Copy-Item -Path (Join-Path $templateDirFull '*') -Destination $packageDir -Recurse -Force
|
||||||
|
$packageAssembliesPath = Join-Path $packageDir 'Assemblies'
|
||||||
|
if (Test-Path -LiteralPath $packageAssembliesPath) {
|
||||||
|
Remove-Item -LiteralPath $packageAssembliesPath -Recurse -Force
|
||||||
|
}
|
||||||
|
Copy-Item -Path $assembliesDirFull -Destination $packageAssembliesPath -Recurse -Force
|
||||||
|
|
||||||
|
$packageJsonPath = Join-Path $packageDir 'package.json'
|
||||||
|
$packageJson = [System.IO.File]::ReadAllText($packageJsonPath)
|
||||||
|
$packageJson = [regex]::Replace($packageJson, '"Version"\s*:\s*"[^"]+"', "`"Version`": `"$PackageVersion`"")
|
||||||
|
$packageJson = [regex]::Replace($packageJson, '"LastUpdatedDate"\s*:\s*"[^"]+"', "`"LastUpdatedDate`": `"$(Get-Date -Format 'yyyy-MM-ddTHH:mm:ss')`"")
|
||||||
|
[System.IO.File]::WriteAllText($packageJsonPath, $packageJson, [System.Text.UTF8Encoding]::new($true))
|
||||||
|
|
||||||
|
$configDataPath = Join-Path $packageDir 'install\1010_Config_Data\02-01-0080 C4IT_F4SDConfigurationType.dat'
|
||||||
|
if (Test-Path -LiteralPath $configDataPath) {
|
||||||
|
$configData = [System.IO.File]::ReadAllText($configDataPath)
|
||||||
|
$configData = [regex]::Replace(
|
||||||
|
$configData,
|
||||||
|
'(<C4IT_AddonConfigClassBase>[\s\S]*?<Version>)[^<]*(</Version>)',
|
||||||
|
"`${1}$PackageVersion`${2}",
|
||||||
|
[System.Text.RegularExpressions.RegexOptions]::Singleline
|
||||||
|
)
|
||||||
|
|
||||||
|
if ($configData -notmatch "<Version>$([regex]::Escape($PackageVersion))</Version>") {
|
||||||
|
throw "Could not update C4IT_F4SDConfigurationType Version to $PackageVersion in $configDataPath"
|
||||||
|
}
|
||||||
|
|
||||||
|
[System.IO.File]::WriteAllText($configDataPath, $configData, [System.Text.UTF8Encoding]::new($true))
|
||||||
|
}
|
||||||
|
|
||||||
|
$textFileExtensions = @('.json', '.xml', '.dat', '.type', '.class', '.config', '.host')
|
||||||
|
Get-ChildItem -LiteralPath $packageDir -Recurse -File |
|
||||||
|
Where-Object { $textFileExtensions -contains $_.Extension.ToLowerInvariant() } |
|
||||||
|
ForEach-Object { Normalize-TextFileLineEndings $_.FullName }
|
||||||
|
|
||||||
|
Compress-Archive -Path (Join-Path $packageDir '*') -DestinationPath $zipPath -Force
|
||||||
|
|
||||||
|
Write-Host "Matrix42 package folder: $packageDir"
|
||||||
|
Write-Host "Matrix42 package zip: $zipPath"
|
||||||
26
F4SDM42WebApi/C4ITF4SDM42WebApi.dll.host.config
Normal file
26
F4SDM42WebApi/C4ITF4SDM42WebApi.dll.host.config
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8" ?>
|
||||||
|
<host xmlns="urn:m42/host.config">
|
||||||
|
<modules>
|
||||||
|
<module assembly="C4ITF4SDM42WebApi" />
|
||||||
|
<module assembly="Matrix42.DataLayer.Persistence" />
|
||||||
|
<module assembly="Matrix42.Services.WebApi" />
|
||||||
|
<module assembly="Matrix42.ServiceRepository.BizLogic" />
|
||||||
|
<module assembly="Matrix42.Pandora.ServiceStore" />
|
||||||
|
<module assembly="Matrix42.Pandora.Persistence" />
|
||||||
|
<module assembly="Matrix42.Pandora.BizLogic" />
|
||||||
|
<module assembly="Matrix42.Pandora.Services" />
|
||||||
|
<module assembly="Matrix42.Distributed.Redis.Cache" />
|
||||||
|
<module assembly="Matrix42.StorageService.BizLogic" />
|
||||||
|
<module assembly="Matrix42.MsTeamsNotification.BizLogic" />
|
||||||
|
<module assembly="Matrix42.ServiceConnection.Persistence" />
|
||||||
|
<module assembly="Matrix42.Auth.BizLogic" />
|
||||||
|
<module assembly="Matrix42.ServiceConnection.BizLogic" />
|
||||||
|
<module assembly="Matrix42.Integration.Aurora.General" />
|
||||||
|
<module assembly="Matrix42.Integration.Aurora.Search.BizLogic" />
|
||||||
|
<module assembly="update4u.SPS.ComplianceRules.BizLogic" />
|
||||||
|
<module assembly="update4u.SPS.Security" />
|
||||||
|
<module assembly="Matrix42.BizLogic.Journal" />
|
||||||
|
<module assembly="Matrix42.ServiceManager.BizLogic" />
|
||||||
|
</modules>
|
||||||
|
<sections></sections>
|
||||||
|
</host>
|
||||||
@@ -1,143 +1,114 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
|
||||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
|
||||||
<ProjectGuid>{D8CBFFCA-0B43-4ACC-80EA-C944E7420CEE}</ProjectGuid>
|
|
||||||
<OutputType>Library</OutputType>
|
<OutputType>Library</OutputType>
|
||||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
|
||||||
<RootNamespace>C4IT.F4SDM</RootNamespace>
|
<RootNamespace>C4IT.F4SDM</RootNamespace>
|
||||||
<AssemblyName>C4ITF4SDM42WebApi</AssemblyName>
|
<AssemblyName>C4ITF4SDM42WebApi</AssemblyName>
|
||||||
<TargetFrameworkVersion>v4.7.2</TargetFrameworkVersion>
|
<RuntimeIdentifiers>win-x64;linux-x64</RuntimeIdentifiers>
|
||||||
<FileAlignment>512</FileAlignment>
|
<AppendRuntimeIdentifierToOutputPath>true</AppendRuntimeIdentifierToOutputPath>
|
||||||
<Deterministic>true</Deterministic>
|
<Nullable>disable</Nullable>
|
||||||
<TargetFrameworkProfile />
|
<ImplicitUsings>disable</ImplicitUsings>
|
||||||
<SccProjectName>SAK</SccProjectName>
|
<LangVersion>latestmajor</LangVersion>
|
||||||
<SccLocalPath>SAK</SccLocalPath>
|
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
||||||
<SccAuxPath>SAK</SccAuxPath>
|
<EnableDefaultCompileItems>false</EnableDefaultCompileItems>
|
||||||
<SccProvider>SAK</SccProvider>
|
<Configurations>Debug;Release;Debug_and_copy;Release_and_copy;Release_signed</Configurations>
|
||||||
|
<M42ExtensionId>6673a25d-33d6-4072-91d9-abed4be1a966</M42ExtensionId>
|
||||||
|
<M42AssemblyPattern>C4ITF4SD*.*</M42AssemblyPattern>
|
||||||
|
<M42BuildPackage>true</M42BuildPackage>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
|
||||||
<DebugSymbols>true</DebugSymbols>
|
<PropertyGroup Condition="'$(Configuration)' == 'Release_signed'">
|
||||||
<DebugType>full</DebugType>
|
|
||||||
<Optimize>false</Optimize>
|
|
||||||
<OutputPath>bin\Debug\</OutputPath>
|
|
||||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
|
||||||
<ErrorReport>prompt</ErrorReport>
|
|
||||||
<WarningLevel>4</WarningLevel>
|
|
||||||
<DocumentationFile>
|
|
||||||
</DocumentationFile>
|
|
||||||
</PropertyGroup>
|
|
||||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
|
||||||
<DebugType>pdbonly</DebugType>
|
|
||||||
<Optimize>true</Optimize>
|
<Optimize>true</Optimize>
|
||||||
<OutputPath>bin\Release\</OutputPath>
|
<M42SignAssemblies>true</M42SignAssemblies>
|
||||||
<DefineConstants>TRACE</DefineConstants>
|
|
||||||
<ErrorReport>prompt</ErrorReport>
|
|
||||||
<WarningLevel>4</WarningLevel>
|
|
||||||
</PropertyGroup>
|
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug_and_copy|AnyCPU'">
|
|
||||||
<DebugSymbols>true</DebugSymbols>
|
|
||||||
<OutputPath>bin\Debug_and_copy\</OutputPath>
|
|
||||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
|
||||||
<DebugType>full</DebugType>
|
|
||||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
|
||||||
<LangVersion>7.3</LangVersion>
|
|
||||||
<ErrorReport>prompt</ErrorReport>
|
|
||||||
</PropertyGroup>
|
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release_and_copy|AnyCPU'">
|
|
||||||
<OutputPath>bin\Release_and_copy\</OutputPath>
|
|
||||||
<DefineConstants>TRACE</DefineConstants>
|
|
||||||
<Optimize>true</Optimize>
|
|
||||||
<DebugType>pdbonly</DebugType>
|
|
||||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
|
||||||
<LangVersion>7.3</LangVersion>
|
|
||||||
<ErrorReport>prompt</ErrorReport>
|
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Reference Include="Matrix42.Common, Version=12.0.3.3096, Culture=neutral, processorArchitecture=MSIL">
|
<Reference Include="Matrix42.Common">
|
||||||
<SpecificVersion>False</SpecificVersion>
|
<HintPath>M42Libraries\26.1\Matrix42.Common.dll</HintPath>
|
||||||
<HintPath>M42Libraries\Matrix42.Common.dll</HintPath>
|
<Private>false</Private>
|
||||||
</Reference>
|
</Reference>
|
||||||
<Reference Include="Matrix42.Contracts.Common, Version=12.0.3.3096, Culture=neutral, processorArchitecture=MSIL">
|
<Reference Include="Matrix42.Contracts.Common">
|
||||||
<SpecificVersion>False</SpecificVersion>
|
<HintPath>M42Libraries\26.1\Matrix42.Contracts.Common.dll</HintPath>
|
||||||
<HintPath>M42Libraries\Matrix42.Contracts.Common.dll</HintPath>
|
<Private>false</Private>
|
||||||
</Reference>
|
</Reference>
|
||||||
<Reference Include="Matrix42.Contracts.Platform, Version=12.0.3.3096, Culture=neutral, processorArchitecture=MSIL">
|
<Reference Include="Matrix42.Contracts.Platform">
|
||||||
<SpecificVersion>False</SpecificVersion>
|
<HintPath>M42Libraries\26.1\Matrix42.Contracts.Platform.dll</HintPath>
|
||||||
<HintPath>M42Libraries\Matrix42.Contracts.Platform.dll</HintPath>
|
<Private>false</Private>
|
||||||
</Reference>
|
</Reference>
|
||||||
<Reference Include="Matrix42.Contracts.ServiceManagement, Version=12.0.3.3096, Culture=neutral, processorArchitecture=MSIL">
|
<Reference Include="Matrix42.Contracts.ServiceManagement">
|
||||||
<SpecificVersion>False</SpecificVersion>
|
<HintPath>M42Libraries\26.1\Matrix42.Contracts.ServiceManagement.dll</HintPath>
|
||||||
<HintPath>M42Libraries\Matrix42.Contracts.ServiceManagement.dll</HintPath>
|
<Private>false</Private>
|
||||||
</Reference>
|
</Reference>
|
||||||
<Reference Include="Matrix42.Pandora.Contracts, Version=12.0.3.3096, Culture=neutral, processorArchitecture=MSIL">
|
<Reference Include="Matrix42.Hosting.Contracts">
|
||||||
<SpecificVersion>False</SpecificVersion>
|
<HintPath>M42Libraries\26.1\Matrix42.Hosting.Contracts.dll</HintPath>
|
||||||
<HintPath>M42Libraries\Matrix42.Pandora.Contracts.dll</HintPath>
|
<Private>false</Private>
|
||||||
</Reference>
|
</Reference>
|
||||||
<Reference Include="Matrix42.Services.Description.Contracts, Version=12.0.3.3096, Culture=neutral, processorArchitecture=MSIL">
|
<Reference Include="Matrix42.Configuration.Global">
|
||||||
<SpecificVersion>False</SpecificVersion>
|
<HintPath>M42Libraries\26.1\Matrix42.Configuration.Global.dll</HintPath>
|
||||||
<HintPath>M42Libraries\Matrix42.Services.Description.Contracts.dll</HintPath>
|
<Private>false</Private>
|
||||||
</Reference>
|
</Reference>
|
||||||
<Reference Include="Microsoft.QualityTools.Testing.Fakes, Version=12.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
<Reference Include="Matrix42.Pandora.Contracts">
|
||||||
<SpecificVersion>False</SpecificVersion>
|
<HintPath>M42Libraries\26.1\Matrix42.Pandora.Contracts.dll</HintPath>
|
||||||
|
<Private>false</Private>
|
||||||
</Reference>
|
</Reference>
|
||||||
<Reference Include="Newtonsoft.Json, Version=12.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
|
<Reference Include="Matrix42.Persistence.Contracts">
|
||||||
<HintPath>..\packages\Newtonsoft.Json.12.0.2\lib\net45\Newtonsoft.Json.dll</HintPath>
|
<HintPath>M42Libraries\26.1\Matrix42.Persistence.Contracts.dll</HintPath>
|
||||||
|
<Private>false</Private>
|
||||||
</Reference>
|
</Reference>
|
||||||
<Reference Include="System" />
|
<Reference Include="Matrix42.Services.Description.Contracts">
|
||||||
<Reference Include="System.Core" />
|
<HintPath>M42Libraries\26.1\Matrix42.Services.Description.Contracts.dll</HintPath>
|
||||||
<Reference Include="System.IO.Compression" />
|
<Private>false</Private>
|
||||||
<Reference Include="System.Web" />
|
|
||||||
<Reference Include="System.Web.Http, Version=5.2.3.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
|
||||||
<SpecificVersion>False</SpecificVersion>
|
|
||||||
<HintPath>M42Libraries\System.Web.Http.dll</HintPath>
|
|
||||||
</Reference>
|
</Reference>
|
||||||
<Reference Include="System.Web.OData, Version=5.9.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
<Reference Include="Matrix42.WebApi.Contracts">
|
||||||
<SpecificVersion>False</SpecificVersion>
|
<HintPath>M42Libraries\26.1\Matrix42.WebApi.Contracts.dll</HintPath>
|
||||||
<HintPath>M42Libraries\System.Web.OData.dll</HintPath>
|
<Private>false</Private>
|
||||||
</Reference>
|
</Reference>
|
||||||
<Reference Include="System.Xml.Linq" />
|
<Reference Include="Newtonsoft.Json">
|
||||||
<Reference Include="System.Data.DataSetExtensions" />
|
<HintPath>M42Libraries\26.1\Newtonsoft.Json.dll</HintPath>
|
||||||
<Reference Include="Microsoft.CSharp" />
|
<Private>false</Private>
|
||||||
<Reference Include="System.Data" />
|
|
||||||
<Reference Include="System.Net.Http" />
|
|
||||||
<Reference Include="System.Xml" />
|
|
||||||
<Reference Include="update4u.SPS.DataLayer, Version=12.0.3.3096, Culture=neutral, processorArchitecture=MSIL">
|
|
||||||
<SpecificVersion>False</SpecificVersion>
|
|
||||||
<HintPath>M42Libraries\update4u.SPS.DataLayer.dll</HintPath>
|
|
||||||
</Reference>
|
</Reference>
|
||||||
<Reference Include="update4u.SPS.Utility, Version=12.0.3.3096, Culture=neutral, processorArchitecture=MSIL">
|
<Reference Include="System.Net.Http.Formatting">
|
||||||
<SpecificVersion>False</SpecificVersion>
|
<HintPath>M42Libraries\26.1\System.Net.Http.Formatting.dll</HintPath>
|
||||||
<HintPath>M42Libraries\update4u.SPS.Utility.dll</HintPath>
|
<Private>false</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="System.Web.Http">
|
||||||
|
<HintPath>M42Libraries\26.1\System.Web.Http.dll</HintPath>
|
||||||
|
<Private>false</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="update4u.SPS.DataLayer">
|
||||||
|
<HintPath>M42Libraries\26.1\update4u.SPS.DataLayer.dll</HintPath>
|
||||||
|
<Private>false</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="update4u.SPS.Utility">
|
||||||
|
<HintPath>M42Libraries\26.1\update4u.SPS.Utility.dll</HintPath>
|
||||||
|
<Private>false</Private>
|
||||||
</Reference>
|
</Reference>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\F4SDHelper\F4SD - Helper.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<Compile Include="cM42LogEntry.cs" />
|
||||||
|
<Compile Include="TicketFilterService.cs" />
|
||||||
|
<Compile Include="F4SDM42DependencyRegistrator.cs" />
|
||||||
|
<Compile Include="F4SDHelperService.cs" />
|
||||||
|
<Compile Include="F4SDHelperService.UserId.cs" />
|
||||||
|
<Compile Include="F4SDM42WebApiController.cs" />
|
||||||
|
<Compile Include="..\Shared\TicketFilterCompiler.cs">
|
||||||
|
<Link>Shared\TicketFilterCompiler.cs</Link>
|
||||||
|
</Compile>
|
||||||
|
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||||
<Compile Include="..\SharedAssemblyInfo.cs">
|
<Compile Include="..\SharedAssemblyInfo.cs">
|
||||||
<Link>Properties\SharedAssemblyInfo.cs</Link>
|
<Link>Properties\SharedAssemblyInfo.cs</Link>
|
||||||
</Compile>
|
</Compile>
|
||||||
<Compile Include="cM42LogEntry.cs" />
|
|
||||||
<Compile Include="F4SDHelperService.cs" />
|
|
||||||
<Compile Include="F4SDM42WebApiController.cs" />
|
|
||||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\F4SDHelper\F4SD - Helper.csproj">
|
<None Update="C4ITF4SDM42WebApi.dll.host.config" CopyToOutputDirectory="PreserveNewest" />
|
||||||
<Project>{eb95e1fb-7a9e-4894-bd28-2d0be2715ebe}</Project>
|
|
||||||
<Name>F4SD - Helper</Name>
|
|
||||||
<Private>True</Private>
|
|
||||||
</ProjectReference>
|
|
||||||
</ItemGroup>
|
|
||||||
<ItemGroup>
|
|
||||||
<None Include="App.config" />
|
|
||||||
<None Include="deploy.ps1" />
|
|
||||||
<None Include="packages.config" />
|
|
||||||
<None Include="SignSourceFiles.cmd" />
|
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<Import Project="..\M42F4SDUUXWorkspace\M42F4SDUUXWorkspace.projitems" Label="Shared" />
|
<Import Project="..\M42F4SDUUXWorkspace\M42F4SDUUXWorkspace.projitems" Label="Shared" />
|
||||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
<Import Project="M42SandboxedExtension.targets" Condition="Exists('M42SandboxedExtension.targets')" />
|
||||||
<PropertyGroup>
|
|
||||||
<PostBuildEvent>@echo powershell -ExecutionPolicy Unrestricted $(ProjectDir)deploy.ps1 -ProjectDir $(ProjectDir) -SolutionDir $(SolutionDir) -OutDir $(OutDir) -ConfigurationName $(ConfigurationName)</PostBuildEvent>
|
|
||||||
</PropertyGroup>
|
|
||||||
</Project>
|
</Project>
|
||||||
310
F4SDM42WebApi/F4SDHelperService.UserId.cs
Normal file
310
F4SDM42WebApi/F4SDHelperService.UserId.cs
Normal file
@@ -0,0 +1,310 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Data;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
using C4IT.FASD.Base;
|
||||||
|
using C4IT.Logging;
|
||||||
|
|
||||||
|
using Matrix42.Common;
|
||||||
|
|
||||||
|
using update4u.SPS.DataLayer;
|
||||||
|
|
||||||
|
using static C4IT.Logging.cLogManager;
|
||||||
|
|
||||||
|
namespace C4IT.F4SD
|
||||||
|
{
|
||||||
|
public partial class F4SDHelperService
|
||||||
|
{
|
||||||
|
internal async Task<List<cF4SDTicketSummary>> getTicketListByUser(
|
||||||
|
Guid userId,
|
||||||
|
int hours,
|
||||||
|
int queueoption,
|
||||||
|
List<cApiM42TicketQueueInfo> queues,
|
||||||
|
cTicketFilterPolicy filters = null)
|
||||||
|
{
|
||||||
|
var method = MethodBase.GetCurrentMethod();
|
||||||
|
LogMethodBegin(method);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await Task.Delay(0);
|
||||||
|
if (userId == Guid.Empty)
|
||||||
|
return new List<cF4SDTicketSummary>();
|
||||||
|
|
||||||
|
var activityFilter = GetActivityFilter(userId, hours, ticketAndServiceRequestEnabled(), queueoption, queues);
|
||||||
|
activityFilter = await ApplyTicketFiltersAsync(activityFilter, filters);
|
||||||
|
if (string.IsNullOrWhiteSpace(activityFilter))
|
||||||
|
return new List<cF4SDTicketSummary>();
|
||||||
|
LogEntry($"Generating ticket list for userId '{userId}'. ASQL filter: {activityFilter}", LogLevels.Debug);
|
||||||
|
|
||||||
|
var activityTable = FragmentRequestBase.SimpleLoad(
|
||||||
|
SPSActivityClassBaseID,
|
||||||
|
"[Expression-ObjectID] as EOID, TicketNumber, Subject, Service.ID as ServiceId, Service.Name as ServiceName" +
|
||||||
|
", SUBQUERY(BasicSchemaObjectType as bso, bso.Name, bso.id = base.T(SPSCommonClassBase).TypeID) as ActivityType" +
|
||||||
|
", COALESCE(T(SPSActivityClassIncident).Asset.T(SPSComputerClassBase).Name, T(SPSActivityClassIncident).Asset.T(SPSAssetClassSIMCard).PhoneNumber, T(SPSActivityClassIncident).Asset.Name, T(SPSActivityClassIncident).Asset.objectid) as AssetName" +
|
||||||
|
", SUBQUERY(BasicSchemaObjectType AS t, t.Name, t.ID=base.T(SPSActivityClassIncident).Asset.T(SPSCommonClassBase).TypeID) as AssetCIName",
|
||||||
|
activityFilter);
|
||||||
|
|
||||||
|
if (activityTable?.Rows == null || activityTable.Rows.Count == 0)
|
||||||
|
return new List<cF4SDTicketSummary>();
|
||||||
|
|
||||||
|
var tickets = new List<cF4SDTicketSummary>(activityTable.Rows.Count);
|
||||||
|
foreach (DataRow entry in activityTable.Rows)
|
||||||
|
{
|
||||||
|
var activityId = getGuidFromObject(entry["EOID"]);
|
||||||
|
var ticketNumber = getStringFromObject(entry["TicketNumber"]);
|
||||||
|
var subject = getStringFromObject(entry["Subject"]);
|
||||||
|
if (string.IsNullOrEmpty(ticketNumber) || string.IsNullOrEmpty(subject))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
var state = GetActivityState(activityId);
|
||||||
|
tickets.Add(new cF4SDTicketSummary
|
||||||
|
{
|
||||||
|
TicketObjectId = activityId,
|
||||||
|
Name = ticketNumber,
|
||||||
|
ActivityType = getStringFromObject(entry["ActivityType"]),
|
||||||
|
Summary = subject,
|
||||||
|
StatusId = state.Item1,
|
||||||
|
Status = state.Item2,
|
||||||
|
AssetCIName = getStringFromObject(entry["AssetCIName"]),
|
||||||
|
AssetName = getStringFromObject(entry["AssetName"]),
|
||||||
|
ServiceId = getGuidFromObject(entry["ServiceId"]),
|
||||||
|
ServiceName = getStringFromObject(entry["ServiceName"]),
|
||||||
|
UserId = userId,
|
||||||
|
IsPrimaryAccount = true
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return tickets.OrderByDescending(ticket => ticket.Name).ToList();
|
||||||
|
}
|
||||||
|
catch (Exception exception)
|
||||||
|
{
|
||||||
|
LogException(exception);
|
||||||
|
return new List<cF4SDTicketSummary>();
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
LogMethodEnd(method);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal async Task<TicketOverviewCountsResult> getTicketOverviewCounts(
|
||||||
|
Guid userId,
|
||||||
|
string scope,
|
||||||
|
IEnumerable<string> keys,
|
||||||
|
int queueoption,
|
||||||
|
List<cApiM42TicketQueueInfo> queues,
|
||||||
|
cTicketFilterPolicy filters = null)
|
||||||
|
{
|
||||||
|
var method = MethodBase.GetCurrentMethod();
|
||||||
|
LogMethodBegin(method);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var useRoleScope = string.Equals(scope, "role", StringComparison.OrdinalIgnoreCase);
|
||||||
|
var normalizedKeys = (keys ?? Array.Empty<string>())
|
||||||
|
.Where(key => !string.IsNullOrWhiteSpace(key))
|
||||||
|
.Distinct(StringComparer.OrdinalIgnoreCase)
|
||||||
|
.ToList();
|
||||||
|
|
||||||
|
if (normalizedKeys.Count == 0)
|
||||||
|
normalizedKeys.AddRange(TicketOverviewKeys);
|
||||||
|
|
||||||
|
var entries = await LoadTicketOverviewEntries(userId, useRoleScope, queueoption, queues, filters);
|
||||||
|
List<TicketOverviewEntry> unassignedEntries = null;
|
||||||
|
if (!useRoleScope && normalizedKeys.Any(IsUnassignedOverviewKey))
|
||||||
|
unassignedEntries = await LoadTicketOverviewUnassignedEntriesForPersonalScope(userId, queueoption, queues, filters);
|
||||||
|
|
||||||
|
var counts = new Dictionary<string, int>(StringComparer.OrdinalIgnoreCase);
|
||||||
|
foreach (var key in normalizedKeys)
|
||||||
|
{
|
||||||
|
var source = !useRoleScope && IsUnassignedOverviewKey(key)
|
||||||
|
? unassignedEntries ?? new List<TicketOverviewEntry>()
|
||||||
|
: entries;
|
||||||
|
counts[key] = CountTicketOverviewEntries(source, key);
|
||||||
|
}
|
||||||
|
|
||||||
|
return CreateTicketOverviewCountsResult(counts);
|
||||||
|
}
|
||||||
|
catch (Exception exception)
|
||||||
|
{
|
||||||
|
LogException(exception);
|
||||||
|
return new TicketOverviewCountsResult();
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
LogMethodEnd(method);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal async Task<TicketOverviewCountsByRoleResult> getTicketOverviewCountsByRoles(
|
||||||
|
Guid userId,
|
||||||
|
IEnumerable<Guid> roleGuids,
|
||||||
|
IEnumerable<string> keys,
|
||||||
|
int queueoption,
|
||||||
|
List<cApiM42TicketQueueInfo> queues,
|
||||||
|
cTicketFilterPolicy filters = null)
|
||||||
|
{
|
||||||
|
var roleIds = await ResolveTicketOverviewRoleIdsAsync(userId, roleGuids);
|
||||||
|
return await getTicketOverviewCountsByRoles(null, roleIds, keys, queueoption, queues, filters);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal async Task<List<TicketOverviewRelationDto>> getTicketOverviewRelations(
|
||||||
|
Guid userId,
|
||||||
|
string scope,
|
||||||
|
string key,
|
||||||
|
int count,
|
||||||
|
int queueoption,
|
||||||
|
List<cApiM42TicketQueueInfo> queues,
|
||||||
|
cTicketFilterPolicy filters = null)
|
||||||
|
{
|
||||||
|
var method = MethodBase.GetCurrentMethod();
|
||||||
|
LogMethodBegin(method);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (userId == Guid.Empty || string.IsNullOrWhiteSpace(key))
|
||||||
|
return new List<TicketOverviewRelationDto>();
|
||||||
|
|
||||||
|
var useRoleScope = string.Equals(scope, "role", StringComparison.OrdinalIgnoreCase);
|
||||||
|
var entries = !useRoleScope && IsUnassignedOverviewKey(key)
|
||||||
|
? await LoadTicketOverviewUnassignedEntriesForPersonalScope(userId, queueoption, queues, filters)
|
||||||
|
: await LoadTicketOverviewEntries(userId, useRoleScope, queueoption, queues, filters);
|
||||||
|
|
||||||
|
var filtered = entries
|
||||||
|
.Where(entry => MatchesTicketOverviewKey(entry, key))
|
||||||
|
.OrderByDescending(entry => entry.CreatedDate);
|
||||||
|
if (count > 0)
|
||||||
|
filtered = filtered.Take(count).OrderByDescending(entry => entry.CreatedDate);
|
||||||
|
|
||||||
|
return filtered.Select(entry => new TicketOverviewRelationDto
|
||||||
|
{
|
||||||
|
Type = enumF4sdSearchResultClass.Ticket,
|
||||||
|
Name = entry.TicketNumber ?? string.Empty,
|
||||||
|
DisplayName = entry.TicketNumber ?? string.Empty,
|
||||||
|
id = entry.TicketId,
|
||||||
|
Status = enumF4sdSearchResultStatus.Active,
|
||||||
|
Infos = new Dictionary<string, string>
|
||||||
|
{
|
||||||
|
["Summary"] = entry.Summary ?? string.Empty,
|
||||||
|
["StatusId"] = ConvertM42State(entry.State),
|
||||||
|
["ActivityType"] = entry.ActivityType ?? string.Empty,
|
||||||
|
["UserDisplayName"] = entry.InitiatorDisplayName ?? string.Empty,
|
||||||
|
["UserAccount"] = entry.InitiatorAccount ?? string.Empty,
|
||||||
|
["UserDomain"] = entry.InitiatorDomain ?? string.Empty,
|
||||||
|
["UserSid"] = entry.InitiatorSid ?? string.Empty,
|
||||||
|
["Sids"] = entry.InitiatorSid ?? string.Empty,
|
||||||
|
["UserId"] = entry.InitiatorId == Guid.Empty ? string.Empty : entry.InitiatorId.ToString(),
|
||||||
|
["UserGuid"] = entry.InitiatorId == Guid.Empty ? string.Empty : entry.InitiatorId.ToString()
|
||||||
|
},
|
||||||
|
Identities = new List<cF4sdIdentityEntry>
|
||||||
|
{
|
||||||
|
new cF4sdIdentityEntry { Class = enumFasdInformationClass.Ticket, Id = entry.TicketId },
|
||||||
|
new cF4sdIdentityEntry { Class = enumFasdInformationClass.User, Id = entry.InitiatorId }
|
||||||
|
}
|
||||||
|
}).ToList();
|
||||||
|
}
|
||||||
|
catch (Exception exception)
|
||||||
|
{
|
||||||
|
LogException(exception);
|
||||||
|
return new List<TicketOverviewRelationDto>();
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
LogMethodEnd(method);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task<List<TicketOverviewEntry>> LoadTicketOverviewEntries(
|
||||||
|
Guid userId,
|
||||||
|
bool useRoleScope,
|
||||||
|
int queueoption,
|
||||||
|
List<cApiM42TicketQueueInfo> queues,
|
||||||
|
cTicketFilterPolicy filters = null)
|
||||||
|
{
|
||||||
|
if (userId == Guid.Empty)
|
||||||
|
return new List<TicketOverviewEntry>();
|
||||||
|
|
||||||
|
var filter = await BuildTicketOverviewFilterAsync(userId, useRoleScope, queueoption, queues, filters);
|
||||||
|
return await LoadTicketOverviewEntriesByFilter(filter);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task<List<TicketOverviewEntry>> LoadTicketOverviewUnassignedEntriesForPersonalScope(
|
||||||
|
Guid userId,
|
||||||
|
int queueoption,
|
||||||
|
List<cApiM42TicketQueueInfo> queues,
|
||||||
|
cTicketFilterPolicy filters = null)
|
||||||
|
{
|
||||||
|
if (userId == Guid.Empty)
|
||||||
|
return new List<TicketOverviewEntry>();
|
||||||
|
|
||||||
|
var roleIds = await ResolveTicketOverviewRoleIdsAsync(userId, null);
|
||||||
|
var filter = BuildTicketOverviewFilterForRoleIds(roleIds, null, queueoption, queues);
|
||||||
|
filter = await ApplyTicketFiltersAsync(filter, filters);
|
||||||
|
if (string.IsNullOrWhiteSpace(filter))
|
||||||
|
return new List<TicketOverviewEntry>();
|
||||||
|
|
||||||
|
return await LoadTicketOverviewEntriesByFilter(filter + " AND Recipient IS NULL");
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task<string> BuildTicketOverviewFilterAsync(
|
||||||
|
Guid userId,
|
||||||
|
bool useRoleScope,
|
||||||
|
int queueoption,
|
||||||
|
List<cApiM42TicketQueueInfo> queues,
|
||||||
|
cTicketFilterPolicy filters = null)
|
||||||
|
{
|
||||||
|
var filter = BuildTicketOverviewBaseFilter(queueoption, queues);
|
||||||
|
if (!useRoleScope)
|
||||||
|
return await ApplyTicketFiltersAsync(filter + $" AND (Recipient = '{Escape(userId.ToString("D"))}')", filters);
|
||||||
|
|
||||||
|
var roleIds = await ResolveTicketOverviewRoleIdsAsync(userId, null);
|
||||||
|
filter = BuildTicketOverviewFilterForRoleIds(roleIds, filter);
|
||||||
|
return await ApplyTicketFiltersAsync(filter, filters);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task<List<Guid>> ResolveTicketOverviewRoleIdsAsync(Guid userId, IEnumerable<Guid> roleGuids)
|
||||||
|
{
|
||||||
|
var roleIds = (roleGuids ?? Enumerable.Empty<Guid>())
|
||||||
|
.Where(id => id != Guid.Empty)
|
||||||
|
.Distinct()
|
||||||
|
.ToList();
|
||||||
|
if (roleIds.Count > 0 || userId == Guid.Empty)
|
||||||
|
return roleIds;
|
||||||
|
|
||||||
|
var roles = await getRoleMembershipById(userId) ?? new List<M42Role>();
|
||||||
|
return roles
|
||||||
|
.Where(role => role != null && role.Id != Guid.Empty)
|
||||||
|
.Select(role => role.Id)
|
||||||
|
.Distinct()
|
||||||
|
.ToList();
|
||||||
|
}
|
||||||
|
|
||||||
|
private string GetActivityFilter(
|
||||||
|
Guid userId,
|
||||||
|
int hours,
|
||||||
|
bool ticketAndServiceRequestEnabled,
|
||||||
|
int queueoption,
|
||||||
|
List<cApiM42TicketQueueInfo> queues)
|
||||||
|
{
|
||||||
|
var filter = $"Initiator = '{Escape(userId.ToString("D"))}'";
|
||||||
|
if (ticketAndServiceRequestEnabled)
|
||||||
|
{
|
||||||
|
filter += " AND (UsedInTypeSPSActivityTypeIncident IS NOT NULL" +
|
||||||
|
" OR UsedInTypeSPSActivityTypeTicket IS NOT NULL" +
|
||||||
|
" OR UsedInTypeSPSActivityTypeServiceRequest IS NOT NULL)";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
filter += " AND UsedInTypeSPSActivityTypeIncident IS NOT NULL";
|
||||||
|
}
|
||||||
|
|
||||||
|
var startDate = AsqlHelper.PrepareDateTime(DateTime.UtcNow.AddHours(-hours), true);
|
||||||
|
var endDate = AsqlHelper.PrepareDateTime(DateTime.UtcNow, true);
|
||||||
|
filter += " AND (T(SPSCommonClassBase).State <> 204" +
|
||||||
|
$" OR (ClosedDate > {startDate} AND ClosedDate < {endDate}))";
|
||||||
|
|
||||||
|
return AppendQueueFilter(filter, queueoption, queues);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -4,6 +4,7 @@ using C4IT.Logging;
|
|||||||
using Matrix42.Common;
|
using Matrix42.Common;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Specialized;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Data;
|
using System.Data;
|
||||||
using System.Data.SqlClient;
|
using System.Data.SqlClient;
|
||||||
@@ -19,7 +20,6 @@ using System.Reflection;
|
|||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using System.Web;
|
|
||||||
using update4u.SPS.DataLayer;
|
using update4u.SPS.DataLayer;
|
||||||
using update4u.SPS.DataLayer.Transaction;
|
using update4u.SPS.DataLayer.Transaction;
|
||||||
using static C4IT.FASD.Base.cF4SDTicket;
|
using static C4IT.FASD.Base.cF4SDTicket;
|
||||||
@@ -27,7 +27,7 @@ using static C4IT.Logging.cLogManager;
|
|||||||
|
|
||||||
namespace C4IT.F4SD
|
namespace C4IT.F4SD
|
||||||
{
|
{
|
||||||
public class F4SDHelperService
|
public partial class F4SDHelperService
|
||||||
{
|
{
|
||||||
private static Guid SPSUserClassBaseID = SPSDataEngineSchemaReader.ClassGetIDFromName("SPSUserClassBase");
|
private static Guid SPSUserClassBaseID = SPSDataEngineSchemaReader.ClassGetIDFromName("SPSUserClassBase");
|
||||||
private static Guid SPSAccountClassBaseID = SPSDataEngineSchemaReader.ClassGetIDFromName("SPSAccountClassBase");
|
private static Guid SPSAccountClassBaseID = SPSDataEngineSchemaReader.ClassGetIDFromName("SPSAccountClassBase");
|
||||||
@@ -54,6 +54,7 @@ namespace C4IT.F4SD
|
|||||||
|
|
||||||
private const string F4SDTicketTableName = "M42WPM-TICKETS-INFOS";
|
private const string F4SDTicketTableName = "M42WPM-TICKETS-INFOS";
|
||||||
private const string F4SDTicketStatusColumnName = "STATUS";
|
private const string F4SDTicketStatusColumnName = "STATUS";
|
||||||
|
private static bool? ticketAndServiceRequestEnabledCache;
|
||||||
|
|
||||||
|
|
||||||
public static IEnumerable<string> ReadLines(Func<Stream> streamProvider,
|
public static IEnumerable<string> ReadLines(Func<Stream> streamProvider,
|
||||||
@@ -70,6 +71,39 @@ namespace C4IT.F4SD
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static NameValueCollection ParseQueryString(string query)
|
||||||
|
{
|
||||||
|
var values = new NameValueCollection();
|
||||||
|
query = (query ?? string.Empty).TrimStart('?');
|
||||||
|
|
||||||
|
if (string.IsNullOrWhiteSpace(query))
|
||||||
|
return values;
|
||||||
|
|
||||||
|
foreach (var pair in query.Split(new[] { '&' }, StringSplitOptions.RemoveEmptyEntries))
|
||||||
|
{
|
||||||
|
var parts = pair.Split(new[] { '=' }, 2);
|
||||||
|
var key = WebUtility.UrlDecode(parts[0]);
|
||||||
|
var value = parts.Length > 1 ? WebUtility.UrlDecode(parts[1]) : string.Empty;
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(key))
|
||||||
|
values.Add(key, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
return values;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string ToQueryString(NameValueCollection queryString)
|
||||||
|
{
|
||||||
|
if (queryString == null || queryString.Count == 0)
|
||||||
|
return string.Empty;
|
||||||
|
|
||||||
|
return string.Join("&",
|
||||||
|
queryString.AllKeys
|
||||||
|
.Where(key => !string.IsNullOrEmpty(key))
|
||||||
|
.SelectMany(key => (queryString.GetValues(key) ?? new[] { string.Empty })
|
||||||
|
.Select(value => $"{WebUtility.UrlEncode(key)}={WebUtility.UrlEncode(value)}")));
|
||||||
|
}
|
||||||
|
|
||||||
internal async Task<string> getDirectLinkF4SD(Guid EOID, string type)
|
internal async Task<string> getDirectLinkF4SD(Guid EOID, string type)
|
||||||
{
|
{
|
||||||
var CM = MethodBase.GetCurrentMethod();
|
var CM = MethodBase.GetCurrentMethod();
|
||||||
@@ -78,7 +112,7 @@ namespace C4IT.F4SD
|
|||||||
{
|
{
|
||||||
LogEntry($"Generating F4SD URI for type: '{type}', GUID: '{EOID}'", LogLevels.Debug);
|
LogEntry($"Generating F4SD URI for type: '{type}', GUID: '{EOID}'", LogLevels.Debug);
|
||||||
var builder = new UriBuilder(c4itf4sdmonLinkBase);
|
var builder = new UriBuilder(c4itf4sdmonLinkBase);
|
||||||
var queryString = HttpUtility.ParseQueryString(builder.Query);
|
var queryString = ParseQueryString(builder.Query);
|
||||||
|
|
||||||
switch (type.ToLowerInvariant().Split('.').Last())
|
switch (type.ToLowerInvariant().Split('.').Last())
|
||||||
{
|
{
|
||||||
@@ -137,7 +171,7 @@ namespace C4IT.F4SD
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
builder.Query = queryString.ToString();
|
builder.Query = ToQueryString(queryString);
|
||||||
return string.IsNullOrEmpty(builder.Query) ? null : builder.ToString();
|
return string.IsNullOrEmpty(builder.Query) ? null : builder.ToString();
|
||||||
}
|
}
|
||||||
catch (Exception E)
|
catch (Exception E)
|
||||||
@@ -152,7 +186,7 @@ namespace C4IT.F4SD
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
internal async Task<List<cF4SDTicketSummary>> getTicketListByUser(string userSid, int hours, int queueoption, List<cApiM42TicketQueueInfo> queues)
|
internal async Task<List<cF4SDTicketSummary>> getTicketListByUser(string userSid, int hours, int queueoption, List<cApiM42TicketQueueInfo> queues, cTicketFilterPolicy filters = null)
|
||||||
{
|
{
|
||||||
var CM = MethodBase.GetCurrentMethod();
|
var CM = MethodBase.GetCurrentMethod();
|
||||||
LogMethodBegin(CM);
|
LogMethodBegin(CM);
|
||||||
@@ -163,6 +197,9 @@ namespace C4IT.F4SD
|
|||||||
|
|
||||||
var tickets = new List<cF4SDTicketSummary>();
|
var tickets = new List<cF4SDTicketSummary>();
|
||||||
var activityFilter = GetActivityFilter(userSid, hours, ticketAndServiceRequestEnabled(), queueoption, queues);
|
var activityFilter = GetActivityFilter(userSid, hours, ticketAndServiceRequestEnabled(), queueoption, queues);
|
||||||
|
activityFilter = await ApplyTicketFiltersAsync(activityFilter, filters);
|
||||||
|
if (string.IsNullOrWhiteSpace(activityFilter))
|
||||||
|
return new List<cF4SDTicketSummary>();
|
||||||
LogEntry($"ASql Filter: {activityFilter}");
|
LogEntry($"ASql Filter: {activityFilter}");
|
||||||
|
|
||||||
var activityTable = FragmentRequestBase.SimpleLoad(SPSActivityClassBaseID,
|
var activityTable = FragmentRequestBase.SimpleLoad(SPSActivityClassBaseID,
|
||||||
@@ -176,7 +213,7 @@ namespace C4IT.F4SD
|
|||||||
if (activityTable?.Rows == null || activityTable.Rows.Count == 0)
|
if (activityTable?.Rows == null || activityTable.Rows.Count == 0)
|
||||||
{
|
{
|
||||||
LogEntry($"No activity entries found for userSid: '{userSid}'", LogLevels.Warning);
|
LogEntry($"No activity entries found for userSid: '{userSid}'", LogLevels.Warning);
|
||||||
return null;
|
return new List<cF4SDTicketSummary>();
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0; i < activityTable.Rows.Count; i++)
|
for (int i = 0; i < activityTable.Rows.Count; i++)
|
||||||
@@ -257,7 +294,7 @@ namespace C4IT.F4SD
|
|||||||
catch (Exception E)
|
catch (Exception E)
|
||||||
{
|
{
|
||||||
LogException(E);
|
LogException(E);
|
||||||
return null;
|
return new List<cF4SDTicketSummary>();
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
@@ -275,14 +312,27 @@ namespace C4IT.F4SD
|
|||||||
"IncidentActive",
|
"IncidentActive",
|
||||||
"IncidentCritical",
|
"IncidentCritical",
|
||||||
"IncidentNewInfo",
|
"IncidentNewInfo",
|
||||||
|
"ServiceRequestsNew",
|
||||||
|
"ServiceRequestsActive",
|
||||||
|
"ServiceRequestsCritical",
|
||||||
|
"ServiceRequestsNewInfo",
|
||||||
"UnassignedTickets",
|
"UnassignedTickets",
|
||||||
"UnassignedTicketsCritical"
|
"UnassignedTicketsCritical"
|
||||||
};
|
};
|
||||||
|
|
||||||
|
public class TicketOverviewCapabilities
|
||||||
|
{
|
||||||
|
[JsonProperty("ticketAndServiceRequestsEnabled")]
|
||||||
|
public bool TicketAndServiceRequestsEnabled { get; set; } = true;
|
||||||
|
}
|
||||||
|
|
||||||
public class TicketOverviewCountsResult
|
public class TicketOverviewCountsResult
|
||||||
{
|
{
|
||||||
[JsonProperty("counts")]
|
[JsonProperty("counts")]
|
||||||
public Dictionary<string, int> Counts { get; set; } = new Dictionary<string, int>(StringComparer.OrdinalIgnoreCase);
|
public Dictionary<string, int> Counts { get; set; } = new Dictionary<string, int>(StringComparer.OrdinalIgnoreCase);
|
||||||
|
|
||||||
|
[JsonProperty("capabilities")]
|
||||||
|
public TicketOverviewCapabilities Capabilities { get; set; } = new TicketOverviewCapabilities();
|
||||||
}
|
}
|
||||||
|
|
||||||
public class TicketOverviewCountsByRoleResult
|
public class TicketOverviewCountsByRoleResult
|
||||||
@@ -332,7 +382,8 @@ namespace C4IT.F4SD
|
|||||||
string scope,
|
string scope,
|
||||||
IEnumerable<string> keys,
|
IEnumerable<string> keys,
|
||||||
int queueoption,
|
int queueoption,
|
||||||
List<cApiM42TicketQueueInfo> queues)
|
List<cApiM42TicketQueueInfo> queues,
|
||||||
|
cTicketFilterPolicy filters = null)
|
||||||
{
|
{
|
||||||
var CM = MethodBase.GetCurrentMethod();
|
var CM = MethodBase.GetCurrentMethod();
|
||||||
LogMethodBegin(CM);
|
LogMethodBegin(CM);
|
||||||
@@ -349,11 +400,11 @@ namespace C4IT.F4SD
|
|||||||
normalizedKeys.AddRange(TicketOverviewKeys);
|
normalizedKeys.AddRange(TicketOverviewKeys);
|
||||||
}
|
}
|
||||||
|
|
||||||
var entries = await LoadTicketOverviewEntries(sid, useRoleScope, queueoption, queues);
|
var entries = await LoadTicketOverviewEntries(sid, useRoleScope, queueoption, queues, filters);
|
||||||
List<TicketOverviewEntry> unassignedEntries = null;
|
List<TicketOverviewEntry> unassignedEntries = null;
|
||||||
if (!useRoleScope && normalizedKeys.Any(IsUnassignedOverviewKey))
|
if (!useRoleScope && normalizedKeys.Any(IsUnassignedOverviewKey))
|
||||||
{
|
{
|
||||||
unassignedEntries = await LoadTicketOverviewUnassignedEntriesForPersonalScope(sid, queueoption, queues);
|
unassignedEntries = await LoadTicketOverviewUnassignedEntriesForPersonalScope(sid, queueoption, queues, filters);
|
||||||
}
|
}
|
||||||
|
|
||||||
var counts = new Dictionary<string, int>(StringComparer.OrdinalIgnoreCase);
|
var counts = new Dictionary<string, int>(StringComparer.OrdinalIgnoreCase);
|
||||||
@@ -362,16 +413,15 @@ namespace C4IT.F4SD
|
|||||||
{
|
{
|
||||||
if (!useRoleScope && IsUnassignedOverviewKey(key))
|
if (!useRoleScope && IsUnassignedOverviewKey(key))
|
||||||
{
|
{
|
||||||
counts[key] = (unassignedEntries ?? new List<TicketOverviewEntry>())
|
counts[key] = CountTicketOverviewEntries(unassignedEntries, key);
|
||||||
.Count(entry => MatchesTicketOverviewKey(entry, key));
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
counts[key] = entries.Count(entry => MatchesTicketOverviewKey(entry, key));
|
counts[key] = CountTicketOverviewEntries(entries, key);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return new TicketOverviewCountsResult { Counts = counts };
|
return CreateTicketOverviewCountsResult(counts);
|
||||||
}
|
}
|
||||||
catch (Exception E)
|
catch (Exception E)
|
||||||
{
|
{
|
||||||
@@ -389,7 +439,8 @@ namespace C4IT.F4SD
|
|||||||
IEnumerable<Guid> roleGuids,
|
IEnumerable<Guid> roleGuids,
|
||||||
IEnumerable<string> keys,
|
IEnumerable<string> keys,
|
||||||
int queueoption,
|
int queueoption,
|
||||||
List<cApiM42TicketQueueInfo> queues)
|
List<cApiM42TicketQueueInfo> queues,
|
||||||
|
cTicketFilterPolicy filters = null)
|
||||||
{
|
{
|
||||||
var CM = MethodBase.GetCurrentMethod();
|
var CM = MethodBase.GetCurrentMethod();
|
||||||
LogMethodBegin(CM);
|
LogMethodBegin(CM);
|
||||||
@@ -409,7 +460,7 @@ namespace C4IT.F4SD
|
|||||||
if (roleIds.Count == 0)
|
if (roleIds.Count == 0)
|
||||||
return new TicketOverviewCountsByRoleResult();
|
return new TicketOverviewCountsByRoleResult();
|
||||||
|
|
||||||
var entries = await LoadTicketOverviewEntriesByRoleIds(roleIds, queueoption, queues);
|
var entries = await LoadTicketOverviewEntriesByRoleIds(roleIds, queueoption, queues, filters);
|
||||||
var entriesByRole = entries
|
var entriesByRole = entries
|
||||||
.GroupBy(entry => entry.RecipientRoleId)
|
.GroupBy(entry => entry.RecipientRoleId)
|
||||||
.ToDictionary(group => group.Key, group => group.ToList());
|
.ToDictionary(group => group.Key, group => group.ToList());
|
||||||
@@ -424,7 +475,7 @@ namespace C4IT.F4SD
|
|||||||
var counts = new Dictionary<string, int>(StringComparer.OrdinalIgnoreCase);
|
var counts = new Dictionary<string, int>(StringComparer.OrdinalIgnoreCase);
|
||||||
foreach (var key in normalizedKeys)
|
foreach (var key in normalizedKeys)
|
||||||
{
|
{
|
||||||
counts[key] = roleEntries.Count(entry => MatchesTicketOverviewKey(entry, key));
|
counts[key] = CountTicketOverviewEntries(roleEntries, key);
|
||||||
}
|
}
|
||||||
|
|
||||||
countsByRole[roleId.ToString()] = counts;
|
countsByRole[roleId.ToString()] = counts;
|
||||||
@@ -453,7 +504,8 @@ namespace C4IT.F4SD
|
|||||||
string key,
|
string key,
|
||||||
int count,
|
int count,
|
||||||
int queueoption,
|
int queueoption,
|
||||||
List<cApiM42TicketQueueInfo> queues)
|
List<cApiM42TicketQueueInfo> queues,
|
||||||
|
cTicketFilterPolicy filters = null)
|
||||||
{
|
{
|
||||||
var CM = MethodBase.GetCurrentMethod();
|
var CM = MethodBase.GetCurrentMethod();
|
||||||
LogMethodBegin(CM);
|
LogMethodBegin(CM);
|
||||||
@@ -466,11 +518,11 @@ namespace C4IT.F4SD
|
|||||||
List<TicketOverviewEntry> entries;
|
List<TicketOverviewEntry> entries;
|
||||||
if (!useRoleScope && IsUnassignedOverviewKey(key))
|
if (!useRoleScope && IsUnassignedOverviewKey(key))
|
||||||
{
|
{
|
||||||
entries = await LoadTicketOverviewUnassignedEntriesForPersonalScope(sid, queueoption, queues);
|
entries = await LoadTicketOverviewUnassignedEntriesForPersonalScope(sid, queueoption, queues, filters);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
entries = await LoadTicketOverviewEntries(sid, useRoleScope, queueoption, queues);
|
entries = await LoadTicketOverviewEntries(sid, useRoleScope, queueoption, queues, filters);
|
||||||
}
|
}
|
||||||
|
|
||||||
var filtered = entries
|
var filtered = entries
|
||||||
@@ -530,7 +582,8 @@ namespace C4IT.F4SD
|
|||||||
string sid,
|
string sid,
|
||||||
bool useRoleScope,
|
bool useRoleScope,
|
||||||
int queueoption,
|
int queueoption,
|
||||||
List<cApiM42TicketQueueInfo> queues)
|
List<cApiM42TicketQueueInfo> queues,
|
||||||
|
cTicketFilterPolicy filters = null)
|
||||||
{
|
{
|
||||||
var CM = MethodBase.GetCurrentMethod();
|
var CM = MethodBase.GetCurrentMethod();
|
||||||
LogMethodBegin(CM);
|
LogMethodBegin(CM);
|
||||||
@@ -541,7 +594,7 @@ namespace C4IT.F4SD
|
|||||||
if (string.IsNullOrWhiteSpace(sid))
|
if (string.IsNullOrWhiteSpace(sid))
|
||||||
return new List<TicketOverviewEntry>();
|
return new List<TicketOverviewEntry>();
|
||||||
|
|
||||||
var filter = await BuildTicketOverviewFilterAsync(sid, useRoleScope, queueoption, queues);
|
var filter = await BuildTicketOverviewFilterAsync(sid, useRoleScope, queueoption, queues, filters);
|
||||||
return await LoadTicketOverviewEntriesByFilter(filter);
|
return await LoadTicketOverviewEntriesByFilter(filter);
|
||||||
}
|
}
|
||||||
catch (Exception E)
|
catch (Exception E)
|
||||||
@@ -558,7 +611,8 @@ namespace C4IT.F4SD
|
|||||||
private async Task<List<TicketOverviewEntry>> LoadTicketOverviewUnassignedEntriesForPersonalScope(
|
private async Task<List<TicketOverviewEntry>> LoadTicketOverviewUnassignedEntriesForPersonalScope(
|
||||||
string sid,
|
string sid,
|
||||||
int queueoption,
|
int queueoption,
|
||||||
List<cApiM42TicketQueueInfo> queues)
|
List<cApiM42TicketQueueInfo> queues,
|
||||||
|
cTicketFilterPolicy filters = null)
|
||||||
{
|
{
|
||||||
var CM = MethodBase.GetCurrentMethod();
|
var CM = MethodBase.GetCurrentMethod();
|
||||||
LogMethodBegin(CM);
|
LogMethodBegin(CM);
|
||||||
@@ -571,6 +625,7 @@ namespace C4IT.F4SD
|
|||||||
|
|
||||||
var roleIds = await ResolveTicketOverviewRoleIdsAsync(sid, null);
|
var roleIds = await ResolveTicketOverviewRoleIdsAsync(sid, null);
|
||||||
var filter = BuildTicketOverviewFilterForRoleIds(roleIds, null, queueoption, queues);
|
var filter = BuildTicketOverviewFilterForRoleIds(roleIds, null, queueoption, queues);
|
||||||
|
filter = await ApplyTicketFiltersAsync(filter, filters);
|
||||||
if (string.IsNullOrWhiteSpace(filter))
|
if (string.IsNullOrWhiteSpace(filter))
|
||||||
return new List<TicketOverviewEntry>();
|
return new List<TicketOverviewEntry>();
|
||||||
|
|
||||||
@@ -591,7 +646,8 @@ namespace C4IT.F4SD
|
|||||||
private async Task<List<TicketOverviewEntry>> LoadTicketOverviewEntriesByRoleIds(
|
private async Task<List<TicketOverviewEntry>> LoadTicketOverviewEntriesByRoleIds(
|
||||||
IEnumerable<Guid> roleIds,
|
IEnumerable<Guid> roleIds,
|
||||||
int queueoption,
|
int queueoption,
|
||||||
List<cApiM42TicketQueueInfo> queues)
|
List<cApiM42TicketQueueInfo> queues,
|
||||||
|
cTicketFilterPolicy filters = null)
|
||||||
{
|
{
|
||||||
var CM = MethodBase.GetCurrentMethod();
|
var CM = MethodBase.GetCurrentMethod();
|
||||||
LogMethodBegin(CM);
|
LogMethodBegin(CM);
|
||||||
@@ -600,6 +656,7 @@ namespace C4IT.F4SD
|
|||||||
await Task.Delay(0);
|
await Task.Delay(0);
|
||||||
|
|
||||||
var filter = BuildTicketOverviewFilterForRoleIds(roleIds, null, queueoption, queues);
|
var filter = BuildTicketOverviewFilterForRoleIds(roleIds, null, queueoption, queues);
|
||||||
|
filter = await ApplyTicketFiltersAsync(filter, filters);
|
||||||
return await LoadTicketOverviewEntriesByFilter(filter);
|
return await LoadTicketOverviewEntriesByFilter(filter);
|
||||||
}
|
}
|
||||||
catch (Exception E)
|
catch (Exception E)
|
||||||
@@ -642,7 +699,7 @@ namespace C4IT.F4SD
|
|||||||
", SolutionTimeEscalated" +
|
", SolutionTimeEscalated" +
|
||||||
", UsedInTypeSPSActivityTypeTicket as TicketEoid" +
|
", UsedInTypeSPSActivityTypeTicket as TicketEoid" +
|
||||||
", UsedInTypeSPSActivityTypeIncident as IncidentEoid" +
|
", UsedInTypeSPSActivityTypeIncident as IncidentEoid" +
|
||||||
", UsedInTypeSPSActivityTypeAlert as AlertEoid" +
|
//", UsedInTypeSPSActivityTypeAlert as AlertEoid" +
|
||||||
", UsedInTypeSPSActivityTypeGroupTicket as ProblemEoid" +
|
", UsedInTypeSPSActivityTypeGroupTicket as ProblemEoid" +
|
||||||
", UsedInTypeSPSActivityTypeServiceRequest as ServiceRequestEoid" +
|
", UsedInTypeSPSActivityTypeServiceRequest as ServiceRequestEoid" +
|
||||||
", UsedInTypeSPSActivityTypeBase as TaskEoid" +
|
", UsedInTypeSPSActivityTypeBase as TaskEoid" +
|
||||||
@@ -661,7 +718,7 @@ namespace C4IT.F4SD
|
|||||||
|
|
||||||
var ticketEoid = getGuidFromObject(row["TicketEoid"]);
|
var ticketEoid = getGuidFromObject(row["TicketEoid"]);
|
||||||
var incidentEoid = getGuidFromObject(row["IncidentEoid"]);
|
var incidentEoid = getGuidFromObject(row["IncidentEoid"]);
|
||||||
var alertEoid = getGuidFromObject(row["AlertEoid"]);
|
//var alertEoid = getGuidFromObject(row["AlertEoid"]);
|
||||||
var problemEoid = getGuidFromObject(row["ProblemEoid"]);
|
var problemEoid = getGuidFromObject(row["ProblemEoid"]);
|
||||||
var serviceRequestEoid = getGuidFromObject(row["ServiceRequestEoid"]);
|
var serviceRequestEoid = getGuidFromObject(row["ServiceRequestEoid"]);
|
||||||
var taskEoid = getGuidFromObject(row["TaskEoid"]);
|
var taskEoid = getGuidFromObject(row["TaskEoid"]);
|
||||||
@@ -670,7 +727,7 @@ namespace C4IT.F4SD
|
|||||||
var activityType = ResolveTicketOverviewActivityType(
|
var activityType = ResolveTicketOverviewActivityType(
|
||||||
ticketEoid,
|
ticketEoid,
|
||||||
incidentEoid,
|
incidentEoid,
|
||||||
alertEoid,
|
//alertEoid,
|
||||||
problemEoid,
|
problemEoid,
|
||||||
serviceRequestEoid,
|
serviceRequestEoid,
|
||||||
taskEoid,
|
taskEoid,
|
||||||
@@ -714,7 +771,7 @@ namespace C4IT.F4SD
|
|||||||
private static string ResolveTicketOverviewActivityType(
|
private static string ResolveTicketOverviewActivityType(
|
||||||
Guid ticketEoid,
|
Guid ticketEoid,
|
||||||
Guid incidentEoid,
|
Guid incidentEoid,
|
||||||
Guid alertEoid,
|
//Guid alertEoid,
|
||||||
Guid problemEoid,
|
Guid problemEoid,
|
||||||
Guid serviceRequestEoid,
|
Guid serviceRequestEoid,
|
||||||
Guid taskEoid,
|
Guid taskEoid,
|
||||||
@@ -724,8 +781,8 @@ namespace C4IT.F4SD
|
|||||||
return "SPSActivityTypeIncident";
|
return "SPSActivityTypeIncident";
|
||||||
if (ticketEoid != Guid.Empty)
|
if (ticketEoid != Guid.Empty)
|
||||||
return "SPSActivityTypeTicket";
|
return "SPSActivityTypeTicket";
|
||||||
if (alertEoid != Guid.Empty)
|
//if (alerteoid != guid.empty)
|
||||||
return "SPSActivityTypeAlert";
|
// return "spsactivitytypealert";
|
||||||
if (problemEoid != Guid.Empty)
|
if (problemEoid != Guid.Empty)
|
||||||
return "SPSActivityTypeGroupTicket";
|
return "SPSActivityTypeGroupTicket";
|
||||||
if (serviceRequestEoid != Guid.Empty)
|
if (serviceRequestEoid != Guid.Empty)
|
||||||
@@ -742,7 +799,8 @@ namespace C4IT.F4SD
|
|||||||
string sid,
|
string sid,
|
||||||
bool useRoleScope,
|
bool useRoleScope,
|
||||||
int queueoption,
|
int queueoption,
|
||||||
List<cApiM42TicketQueueInfo> queues)
|
List<cApiM42TicketQueueInfo> queues,
|
||||||
|
cTicketFilterPolicy filters = null)
|
||||||
{
|
{
|
||||||
var filter = BuildTicketOverviewBaseFilter(queueoption, queues);
|
var filter = BuildTicketOverviewBaseFilter(queueoption, queues);
|
||||||
|
|
||||||
@@ -750,11 +808,12 @@ namespace C4IT.F4SD
|
|||||||
{
|
{
|
||||||
var recipientFilter = $"Recipient.Accounts.T(SPSAccountClassAd).Sid = '{Escape(sid)}'";
|
var recipientFilter = $"Recipient.Accounts.T(SPSAccountClassAd).Sid = '{Escape(sid)}'";
|
||||||
filter += $" AND ({recipientFilter})";
|
filter += $" AND ({recipientFilter})";
|
||||||
return filter;
|
return await ApplyTicketFiltersAsync(filter, filters);
|
||||||
}
|
}
|
||||||
|
|
||||||
var roleIds = await ResolveTicketOverviewRoleIdsAsync(sid, null);
|
var roleIds = await ResolveTicketOverviewRoleIdsAsync(sid, null);
|
||||||
return BuildTicketOverviewFilterForRoleIds(roleIds, filter);
|
filter = BuildTicketOverviewFilterForRoleIds(roleIds, filter);
|
||||||
|
return await ApplyTicketFiltersAsync(filter, filters);
|
||||||
}
|
}
|
||||||
|
|
||||||
private string BuildTicketOverviewBaseFilter(int queueoption, List<cApiM42TicketQueueInfo> queues)
|
private string BuildTicketOverviewBaseFilter(int queueoption, List<cApiM42TicketQueueInfo> queues)
|
||||||
@@ -900,7 +959,10 @@ namespace C4IT.F4SD
|
|||||||
if (entry == null || string.IsNullOrWhiteSpace(key))
|
if (entry == null || string.IsNullOrWhiteSpace(key))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
var isTicket = !entry.IsIncident;
|
// TODO: Fachlich klaeren, ob Service Requests zusaetzlich unter "Tickets" aggregiert werden sollen.
|
||||||
|
var isTicket = string.Equals(entry.ActivityType, "SPSActivityTypeTicket", StringComparison.OrdinalIgnoreCase)
|
||||||
|
|| (!entry.IsIncident && string.IsNullOrWhiteSpace(entry.ActivityType));
|
||||||
|
var isServiceRequest = string.Equals(entry.ActivityType, "SPSActivityTypeServiceRequest", StringComparison.OrdinalIgnoreCase);
|
||||||
var hasPerson = entry.RecipientId != Guid.Empty;
|
var hasPerson = entry.RecipientId != Guid.Empty;
|
||||||
var hasRole = entry.RecipientRoleId != Guid.Empty;
|
var hasRole = entry.RecipientRoleId != Guid.Empty;
|
||||||
var isCritical = entry.ReactionTimeEscalated || entry.SolutionTimeEscalated;
|
var isCritical = entry.ReactionTimeEscalated || entry.SolutionTimeEscalated;
|
||||||
@@ -925,6 +987,14 @@ namespace C4IT.F4SD
|
|||||||
return entry.IsIncident && isCritical;
|
return entry.IsIncident && isCritical;
|
||||||
case "IncidentNewInfo":
|
case "IncidentNewInfo":
|
||||||
return entry.IsIncident && entry.NewInformationReceived;
|
return entry.IsIncident && entry.NewInformationReceived;
|
||||||
|
case "ServiceRequestsNew":
|
||||||
|
return isServiceRequest && (entry.State == 200 || entry.State == 201);
|
||||||
|
case "ServiceRequestsActive":
|
||||||
|
return isServiceRequest && isActive;
|
||||||
|
case "ServiceRequestsCritical":
|
||||||
|
return isServiceRequest && isCritical;
|
||||||
|
case "ServiceRequestsNewInfo":
|
||||||
|
return isServiceRequest && entry.NewInformationReceived;
|
||||||
case "UnassignedTickets":
|
case "UnassignedTickets":
|
||||||
return !hasPerson && hasRole && isNew;
|
return !hasPerson && hasRole && isNew;
|
||||||
case "UnassignedTicketsCritical":
|
case "UnassignedTicketsCritical":
|
||||||
@@ -934,6 +1004,24 @@ namespace C4IT.F4SD
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static int CountTicketOverviewEntries(IEnumerable<TicketOverviewEntry> entries, string key)
|
||||||
|
{
|
||||||
|
return (entries ?? Enumerable.Empty<TicketOverviewEntry>())
|
||||||
|
.Count(entry => MatchesTicketOverviewKey(entry, key));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static TicketOverviewCountsResult CreateTicketOverviewCountsResult(Dictionary<string, int> counts)
|
||||||
|
{
|
||||||
|
return new TicketOverviewCountsResult
|
||||||
|
{
|
||||||
|
Counts = counts ?? new Dictionary<string, int>(StringComparer.OrdinalIgnoreCase),
|
||||||
|
Capabilities = new TicketOverviewCapabilities
|
||||||
|
{
|
||||||
|
TicketAndServiceRequestsEnabled = ticketAndServiceRequestEnabled()
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
private static bool GetBoolValue(object value)
|
private static bool GetBoolValue(object value)
|
||||||
{
|
{
|
||||||
if (value == null || value is DBNull)
|
if (value == null || value is DBNull)
|
||||||
@@ -1101,7 +1189,7 @@ namespace C4IT.F4SD
|
|||||||
presetParamsDyn.SPSActivityClassIncident.Asset = asset.Id;
|
presetParamsDyn.SPSActivityClassIncident.Asset = asset.Id;
|
||||||
}
|
}
|
||||||
var type = TicketAndServiceRequestEnabled ? "SPSActivityTypeTicket" : "SPSActivityTypeIncident";
|
var type = TicketAndServiceRequestEnabled ? "SPSActivityTypeTicket" : "SPSActivityTypeIncident";
|
||||||
var presetParams = HttpUtility.UrlEncode(JsonConvert.SerializeObject(presetParamsDyn));
|
var presetParams = WebUtility.UrlEncode(JsonConvert.SerializeObject(presetParamsDyn));
|
||||||
var directLink = string.Format(TicketDirectLinkCreateTemplate, F4SDM42WebApiController.defaultInstance.BaseUrl, type, presetParams);
|
var directLink = string.Format(TicketDirectLinkCreateTemplate, F4SDM42WebApiController.defaultInstance.BaseUrl, type, presetParams);
|
||||||
return new DirectLink()
|
return new DirectLink()
|
||||||
{
|
{
|
||||||
@@ -1123,18 +1211,23 @@ namespace C4IT.F4SD
|
|||||||
|
|
||||||
private static bool ticketAndServiceRequestEnabled()
|
private static bool ticketAndServiceRequestEnabled()
|
||||||
{
|
{
|
||||||
var configProvider = F4SDM42WebApiController.defaultInstance._globalConfigurationProvider;
|
if (ticketAndServiceRequestEnabledCache.HasValue)
|
||||||
|
return ticketAndServiceRequestEnabledCache.Value;
|
||||||
|
|
||||||
// using reflection because signature of "ReloadSettings" changed in ESM v12
|
try
|
||||||
var method = configProvider.GetType().GetMethod("ReloadSettings");
|
|
||||||
|
|
||||||
if (method != null)
|
|
||||||
{
|
{
|
||||||
var defaultParameters = method.GetParameters().Select(p => p.HasDefaultValue ? p.DefaultValue : null).ToArray();
|
var configProvider = F4SDM42WebApiController.defaultInstance?._globalConfigurationProvider;
|
||||||
method.Invoke(configProvider, defaultParameters);
|
var enabled = configProvider?.ServiceDeskConfiguration?.TicketAndServiceRequestEnabled ?? true;
|
||||||
|
ticketAndServiceRequestEnabledCache = enabled;
|
||||||
|
return enabled;
|
||||||
|
}
|
||||||
|
catch (Exception E)
|
||||||
|
{
|
||||||
|
LogException(E);
|
||||||
|
LogEntry("Could not read ServiceDeskConfiguration.TicketAndServiceRequestEnabled. Falling back to enabled ticket/service request mode.", LogLevels.Warning);
|
||||||
|
ticketAndServiceRequestEnabledCache = true;
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return configProvider.ServiceDeskConfiguration.TicketAndServiceRequestEnabled;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
internal async Task<List<cF4SDTicket>> getTicketDetails(List<Guid> ticketObjectIds)
|
internal async Task<List<cF4SDTicket>> getTicketDetails(List<Guid> ticketObjectIds)
|
||||||
@@ -1286,7 +1379,7 @@ namespace C4IT.F4SD
|
|||||||
viewOptionsDyn.type = CIName;
|
viewOptionsDyn.type = CIName;
|
||||||
viewOptionsDyn.viewType = "action";
|
viewOptionsDyn.viewType = "action";
|
||||||
viewOptionsDyn.actionId = TicketCloseActionId;
|
viewOptionsDyn.actionId = TicketCloseActionId;
|
||||||
var viewOptions = HttpUtility.UrlEncode(JsonConvert.SerializeObject(viewOptionsDyn));
|
var viewOptions = WebUtility.UrlEncode(JsonConvert.SerializeObject(viewOptionsDyn));
|
||||||
|
|
||||||
var ticketDirectLinkPreview = string.Format(TicketDirectLinkPreviewTemplate, F4SDM42WebApiController.defaultInstance.BaseUrl, CIName, ActivityEOID);
|
var ticketDirectLinkPreview = string.Format(TicketDirectLinkPreviewTemplate, F4SDM42WebApiController.defaultInstance.BaseUrl, CIName, ActivityEOID);
|
||||||
var ticketDirectLinkEdit = string.Format(TicketDirectLinkEditTemplate, F4SDM42WebApiController.defaultInstance.BaseUrl, CIName, ActivityEOID);
|
var ticketDirectLinkEdit = string.Format(TicketDirectLinkEditTemplate, F4SDM42WebApiController.defaultInstance.BaseUrl, CIName, ActivityEOID);
|
||||||
@@ -1368,26 +1461,9 @@ namespace C4IT.F4SD
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
await Task.Delay(0);
|
await Task.Delay(0);
|
||||||
List<cTicketJournalItem> journalEntries = new List<cTicketJournalItem>();
|
var entries = LoadJournalEntries(activityEOID);
|
||||||
var entries = F4SDM42WebApiController.defaultInstance._journalService.GetJournalList(activityEOID, false, 0, 50, "<a href=\"#\" class=\"mx-object-journal--link {0} {1}\">{2}</a>", 120);
|
LogEntry($"{entries.Count} Journal entries found for ObjectID={activityEOID}", LogLevels.Debug);
|
||||||
LogEntry($"{entries.Length} Journal entries found for ObjectID={activityEOID}", LogLevels.Debug);
|
return CreateTicketJournalItems(activityEOID, entries);
|
||||||
for (int i = 0; i < entries.Length; i++)
|
|
||||||
{
|
|
||||||
Matrix42.Contracts.Platform.Data.JournalEntryInfo item = entries[i];
|
|
||||||
LogEntry($"Journal entry {i + 1}/{entries.Length}: ID={item.Id}, CreatedDate={item.CreatedDate}, CreatedBy={item.Creator}, Header={item.Header}", LogLevels.Debug);
|
|
||||||
journalEntries.Add(new cTicketJournalItem()
|
|
||||||
{
|
|
||||||
JournalId = item.Id,
|
|
||||||
ActivityObjectId = activityEOID,
|
|
||||||
CreatedBy = item.Creator,
|
|
||||||
CreationDate = (DateTime)item.CreatedDate,
|
|
||||||
DescriptionHtml = item.Text,
|
|
||||||
Description = Matrix42.Common.Html.HtmlConverter.ConvertHtmlToPlainText(item.Text),
|
|
||||||
Header = item.Header,
|
|
||||||
IsVisibleForUser = item.VisibleInPortal
|
|
||||||
});
|
|
||||||
}
|
|
||||||
return journalEntries;
|
|
||||||
}
|
}
|
||||||
catch (Exception E)
|
catch (Exception E)
|
||||||
{
|
{
|
||||||
@@ -1400,6 +1476,151 @@ namespace C4IT.F4SD
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal static List<cTicketJournalItem> CreateTicketJournalItems(Guid activityEOID, IReadOnlyList<Matrix42.Contracts.Platform.Data.JournalEntryInfo> entries)
|
||||||
|
{
|
||||||
|
List<cTicketJournalItem> journalEntries = new List<cTicketJournalItem>();
|
||||||
|
for (int i = 0; i < entries.Count; i++)
|
||||||
|
{
|
||||||
|
Matrix42.Contracts.Platform.Data.JournalEntryInfo item = entries[i];
|
||||||
|
var text = item.Text ?? string.Empty;
|
||||||
|
var createdDate = item.CreatedDate ?? DateTime.MinValue;
|
||||||
|
|
||||||
|
LogEntry($"Journal entry {i + 1}/{entries.Count}: ID={item.Id}, CreatedDate={createdDate}, CreatedBy={item.Creator}, Header={item.Header}", LogLevels.Debug);
|
||||||
|
journalEntries.Add(new cTicketJournalItem()
|
||||||
|
{
|
||||||
|
JournalId = item.Id,
|
||||||
|
ActivityObjectId = activityEOID,
|
||||||
|
CreatedBy = item.Creator,
|
||||||
|
CreationDate = createdDate,
|
||||||
|
DescriptionHtml = text,
|
||||||
|
Description = string.IsNullOrEmpty(text) ? string.Empty : Matrix42.Common.Html.HtmlConverter.ConvertHtmlToPlainText(text),
|
||||||
|
Header = item.Header,
|
||||||
|
IsVisibleForUser = item.VisibleInPortal
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return journalEntries;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static IReadOnlyList<Matrix42.Contracts.Platform.Data.JournalEntryInfo> LoadJournalEntries(Guid activityEOID)
|
||||||
|
{
|
||||||
|
var journalService = F4SDM42WebApiController.defaultInstance.GetJournalService();
|
||||||
|
var serviceType = journalService.GetType();
|
||||||
|
var objectLinkTemplate = "<a href=\"#\" class=\"mx-object-journal--link {0} {1}\">{2}</a>";
|
||||||
|
var methods = serviceType
|
||||||
|
.GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)
|
||||||
|
.Where(IsJournalReaderMethod)
|
||||||
|
.OrderByDescending(method => method.GetParameters().Length)
|
||||||
|
.ToList();
|
||||||
|
|
||||||
|
foreach (var method in methods)
|
||||||
|
{
|
||||||
|
if (!TryBuildJournalListArguments(method, activityEOID, objectLinkTemplate, out var arguments))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var result = method.Invoke(journalService, arguments);
|
||||||
|
if (result is Matrix42.Contracts.Platform.Data.JournalEntryInfo[] arrayResult)
|
||||||
|
return arrayResult;
|
||||||
|
|
||||||
|
if (result is IEnumerable<Matrix42.Contracts.Platform.Data.JournalEntryInfo> enumerableResult)
|
||||||
|
return enumerableResult.ToList();
|
||||||
|
|
||||||
|
throw new MissingMethodException($"IJournalService.GetJournalList returned unsupported type '{result?.GetType().FullName ?? "<null>"}'.");
|
||||||
|
}
|
||||||
|
catch (TargetInvocationException ex) when (ex.InnerException != null)
|
||||||
|
{
|
||||||
|
throw ex.InnerException;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new MissingMethodException($"No compatible IJournalService.GetJournalList overload was found on '{serviceType.FullName}'. Available overloads: {string.Join("; ", methods.Select(FormatMethodSignature))}");
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool IsJournalReaderMethod(MethodInfo method)
|
||||||
|
{
|
||||||
|
var methodName = method.Name;
|
||||||
|
if (methodName.Contains("."))
|
||||||
|
methodName = methodName.Substring(methodName.LastIndexOf(".", StringComparison.Ordinal) + 1);
|
||||||
|
|
||||||
|
if (!(methodName.StartsWith("Get", StringComparison.OrdinalIgnoreCase) || methodName.StartsWith("Load", StringComparison.OrdinalIgnoreCase)))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (!methodName.Contains("Journal", StringComparison.OrdinalIgnoreCase))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (!method.GetParameters().Any(parameter => parameter.ParameterType == typeof(Guid)))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
var returnType = method.ReturnType;
|
||||||
|
if (returnType.IsArray)
|
||||||
|
return returnType.GetElementType()?.FullName == typeof(Matrix42.Contracts.Platform.Data.JournalEntryInfo).FullName;
|
||||||
|
|
||||||
|
if (returnType.FullName == typeof(Matrix42.Contracts.Platform.Data.JournalEntryInfo).FullName)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return returnType.GetInterfaces()
|
||||||
|
.Where(type => type.IsGenericType)
|
||||||
|
.Select(type => type.GetGenericArguments().FirstOrDefault())
|
||||||
|
.Any(type => type?.FullName == typeof(Matrix42.Contracts.Platform.Data.JournalEntryInfo).FullName);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool TryBuildJournalListArguments(MethodInfo method, Guid activityEOID, string objectLinkTemplate, out object[] arguments)
|
||||||
|
{
|
||||||
|
var parameters = method.GetParameters();
|
||||||
|
arguments = new object[parameters.Length];
|
||||||
|
|
||||||
|
for (int i = 0; i < parameters.Length; i++)
|
||||||
|
{
|
||||||
|
var parameter = parameters[i];
|
||||||
|
var parameterType = parameter.ParameterType;
|
||||||
|
var parameterName = parameter.Name ?? string.Empty;
|
||||||
|
var lowerName = parameterName.ToLowerInvariant();
|
||||||
|
|
||||||
|
if (parameterType == typeof(Guid))
|
||||||
|
{
|
||||||
|
arguments[i] = activityEOID;
|
||||||
|
}
|
||||||
|
else if (parameterType == typeof(bool))
|
||||||
|
{
|
||||||
|
arguments[i] = false;
|
||||||
|
}
|
||||||
|
else if (parameterType == typeof(int))
|
||||||
|
{
|
||||||
|
if (lowerName.Contains("time"))
|
||||||
|
arguments[i] = 120;
|
||||||
|
else if (lowerName.Contains("count") || lowerName.Contains("take") || lowerName.Contains("limit") || lowerName.Contains("size"))
|
||||||
|
arguments[i] = 50;
|
||||||
|
else
|
||||||
|
arguments[i] = 0;
|
||||||
|
}
|
||||||
|
else if (parameterType == typeof(string))
|
||||||
|
{
|
||||||
|
arguments[i] = lowerName.Contains("template") || lowerName.Contains("link") ? objectLinkTemplate : null;
|
||||||
|
}
|
||||||
|
else if (parameterType == typeof(string[]))
|
||||||
|
{
|
||||||
|
arguments[i] = null;
|
||||||
|
}
|
||||||
|
else if (parameter.HasDefaultValue)
|
||||||
|
{
|
||||||
|
arguments[i] = parameter.DefaultValue;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string FormatMethodSignature(MethodInfo method)
|
||||||
|
{
|
||||||
|
return $"{method.ReturnType.FullName} {method.Name}({string.Join(", ", method.GetParameters().Select(parameter => $"{parameter.ParameterType.FullName} {parameter.Name}"))})";
|
||||||
|
}
|
||||||
|
|
||||||
internal async Task<bool> updateActivitySolution(Guid objectId, string solutionHtml)
|
internal async Task<bool> updateActivitySolution(Guid objectId, string solutionHtml)
|
||||||
{
|
{
|
||||||
|
|
||||||
@@ -2056,18 +2277,6 @@ namespace C4IT.F4SD
|
|||||||
retVal.User = m42Users[0];
|
retVal.User = m42Users[0];
|
||||||
|
|
||||||
|
|
||||||
var user = F4SDM42WebApiController.defaultInstance._userProfile.GetInteractiveUserInfo(retVal.User.Id);
|
|
||||||
if (user != null)
|
|
||||||
{
|
|
||||||
retVal.User.Id = user.Id;
|
|
||||||
retVal.User.Currency = user.Currency;
|
|
||||||
retVal.User.Email = user.Email;
|
|
||||||
retVal.User.FirstName = user.FirstName;
|
|
||||||
retVal.User.LastName = user.LastName;
|
|
||||||
retVal.User.Phone = user.Phone;
|
|
||||||
retVal.User.Photo = user.Photo;
|
|
||||||
}
|
|
||||||
|
|
||||||
retVal.Roles = await getRoleMembershipById(retVal.User.Id);
|
retVal.Roles = await getRoleMembershipById(retVal.User.Id);
|
||||||
retVal.User.IsAdmin = retVal.Roles?.Where(i => i.Id == Administrators).FirstOrDefault() != null;
|
retVal.User.IsAdmin = retVal.Roles?.Where(i => i.Id == Administrators).FirstOrDefault() != null;
|
||||||
return retVal;
|
return retVal;
|
||||||
|
|||||||
38
F4SDM42WebApi/F4SDM42DependencyRegistrator.cs
Normal file
38
F4SDM42WebApi/F4SDM42DependencyRegistrator.cs
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
using System;
|
||||||
|
using System.Web.Http;
|
||||||
|
using System.Web.Http.Description;
|
||||||
|
|
||||||
|
using Matrix42.Hosting.Contracts;
|
||||||
|
|
||||||
|
using C4IT.Logging;
|
||||||
|
|
||||||
|
using static C4IT.Logging.cLogManager;
|
||||||
|
|
||||||
|
namespace C4IT.F4SD
|
||||||
|
{
|
||||||
|
public class F4SDM42DependencyRegistrator : IDependencyRegistrator
|
||||||
|
{
|
||||||
|
public void Register(IDependencyContainer container, IDependencyResolver resolver)
|
||||||
|
{
|
||||||
|
if (container == null)
|
||||||
|
throw new ArgumentNullException(nameof(container));
|
||||||
|
|
||||||
|
if (resolver == null)
|
||||||
|
throw new ArgumentNullException(nameof(resolver));
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (resolver.TryGet(typeof(IApiExplorer)) != null)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
// Existing mapping is incomplete in the sandbox host. Register a concrete instance below.
|
||||||
|
}
|
||||||
|
|
||||||
|
var httpConfiguration = new HttpConfiguration();
|
||||||
|
container.RegisterInstance(typeof(IApiExplorer), new ApiExplorer(httpConfiguration));
|
||||||
|
LogEntry("Registered System.Web.Http.Description.IApiExplorer for Matrix42 sandbox host.", LogLevels.Debug);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,10 +1,3 @@
|
|||||||
using C4IT.F4SDM;
|
|
||||||
using C4IT.FASD.Base;
|
|
||||||
using C4IT.Logging;
|
|
||||||
using Matrix42.Common;
|
|
||||||
using Matrix42.Contracts.ServiceManagement.ServiceContracts;
|
|
||||||
using Matrix42.Pandora.Contracts;
|
|
||||||
using Matrix42.Services.Description.Contracts;
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Data;
|
using System.Data;
|
||||||
@@ -12,13 +5,24 @@ using System.Linq;
|
|||||||
using System.Net;
|
using System.Net;
|
||||||
using System.Net.Http;
|
using System.Net.Http;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using System.Web;
|
|
||||||
using System.Web.Http;
|
using Matrix42.Common;
|
||||||
using System.Web.Http.Controllers;
|
using Matrix42.Contracts.Common.Security;
|
||||||
using System.Web.OData;
|
using Matrix42.Contracts.ServiceManagement.ServiceContracts;
|
||||||
using System.Web.OData.Query;
|
using Matrix42.Hosting.Contracts;
|
||||||
|
using Matrix42.Pandora.Contracts;
|
||||||
|
using Matrix42.Persistence.Contracts;
|
||||||
|
using Matrix42.Services.Description.Contracts;
|
||||||
|
using Matrix42.WebApi.Contracts;
|
||||||
|
using Matrix42.WebApi.Contracts.OData;
|
||||||
using update4u.SPS.Utility.GlobalConfiguration;
|
using update4u.SPS.Utility.GlobalConfiguration;
|
||||||
|
|
||||||
|
using C4IT.F4SDM;
|
||||||
|
using C4IT.FASD.Base;
|
||||||
|
using C4IT.Logging;
|
||||||
|
|
||||||
using static C4IT.FASD.Base.cF4SDTicket;
|
using static C4IT.FASD.Base.cF4SDTicket;
|
||||||
using static C4IT.Logging.cLogManager;
|
using static C4IT.Logging.cLogManager;
|
||||||
|
|
||||||
@@ -31,44 +35,35 @@ namespace C4IT.F4SD
|
|||||||
public static F4SDM42WebApiController defaultInstance;
|
public static F4SDM42WebApiController defaultInstance;
|
||||||
//private readonly IIncidentService _incidentService;
|
//private readonly IIncidentService _incidentService;
|
||||||
internal readonly GlobalConfigurationProvider _globalConfigurationProvider;
|
internal readonly GlobalConfigurationProvider _globalConfigurationProvider;
|
||||||
public readonly IJournalService _journalService;
|
|
||||||
//public readonly IObjectService _objectService;
|
//public readonly IObjectService _objectService;
|
||||||
//public readonly IFragmentService _fragmentService;
|
//public readonly IFragmentService _fragmentService;
|
||||||
internal readonly IEntityDataService _entityDataService;
|
private readonly IDependencyResolver _resolver;
|
||||||
internal readonly IPandoraUserProfile _userProfile;
|
private readonly IEnumerationProvider _enumerationProvider;
|
||||||
|
|
||||||
|
|
||||||
private readonly F4SDHelperService _f4stHelperService;
|
private readonly F4SDHelperService _f4stHelperService;
|
||||||
public string BaseUrl => $"{Request.RequestUri.Scheme}://{Request.RequestUri.Host}";
|
public string BaseUrl => Request?.RequestUri == null ? string.Empty : $"{Request.RequestUri.Scheme}://{Request.RequestUri.Host}";
|
||||||
public string EndpointBaseUrl => $"{BaseUrl}/m42Services/api/c4itf4sdwebapi";
|
public string EndpointBaseUrl => $"{BaseUrl}/m42Services/api/c4itf4sdwebapi";
|
||||||
public F4SDM42WebApiController(
|
|
||||||
//IObjectService objectService,
|
public F4SDM42WebApiController(IDependencyResolver resolver, IEnumerationProvider enumerationProvider)
|
||||||
//IIncidentService incidentService,
|
|
||||||
IJournalService journalService
|
|
||||||
//IFragmentService fragmentService,
|
|
||||||
, IEntityDataService entityDataService
|
|
||||||
, IPandoraUserProfile userProfile
|
|
||||||
)
|
|
||||||
{
|
{
|
||||||
|
_resolver = resolver ?? throw new ArgumentNullException(nameof(resolver));
|
||||||
|
_enumerationProvider = enumerationProvider ?? throw new ArgumentNullException(nameof(enumerationProvider));
|
||||||
defaultInstance = this;
|
defaultInstance = this;
|
||||||
//_objectService = objectService;
|
//_objectService = objectService;
|
||||||
//_fragmentService = fragmentService;
|
//_fragmentService = fragmentService;
|
||||||
//_incidentService = Guard.NullArgument(incidentService, "incidentService");
|
//_incidentService = Guard.NullArgument(incidentService, "incidentService");
|
||||||
|
|
||||||
_entityDataService = entityDataService;
|
|
||||||
_journalService = journalService;
|
|
||||||
_globalConfigurationProvider = GlobalConfigurationProvider.Instance;
|
_globalConfigurationProvider = GlobalConfigurationProvider.Instance;
|
||||||
_f4stHelperService = new F4SDHelperService();
|
_f4stHelperService = new F4SDHelperService();
|
||||||
_userProfile = userProfile;
|
EnsureInitialized();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static object initLock = new object();
|
private static readonly object initLock = new object();
|
||||||
protected override void Initialize(HttpControllerContext controllerContext)
|
private static void EnsureInitialized()
|
||||||
{
|
{
|
||||||
base.Initialize(controllerContext);
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
//System.Diagnostics.Debugger.Launch();
|
|
||||||
lock (initLock)
|
lock (initLock)
|
||||||
{
|
{
|
||||||
if (IsInitialized || F4SDM42LogsWebApiController.IsInitialized)
|
if (IsInitialized || F4SDM42LogsWebApiController.IsInitialized)
|
||||||
@@ -85,26 +80,50 @@ namespace C4IT.F4SD
|
|||||||
catch { };
|
catch { };
|
||||||
}
|
}
|
||||||
|
|
||||||
[Route("getDirectLinkCreateTicket"), HttpGet]
|
private T GetRequiredService<T>() where T : class
|
||||||
public async Task<F4SDHelperService.DirectLink> getDirectLinkCreateTicket(string sid = "", string assetname = "")
|
|
||||||
{
|
{
|
||||||
await Task.Delay(0);
|
var service = _resolver.TryGet<T>();
|
||||||
return await _f4stHelperService.getDirectLinkCreateTicket(sid, assetname);
|
if (service != null)
|
||||||
}
|
return service;
|
||||||
[Route("getDirectLinkF4SD"), HttpGet]
|
|
||||||
public async Task<string> getDirectLinkF4SD(Guid EOID, string Type)
|
throw new InvalidOperationException($"Required Matrix42 service is not registered: {typeof(T).FullName}");
|
||||||
{
|
|
||||||
return await _f4stHelperService.getDirectLinkF4SD(EOID, Type);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal IJournalService GetJournalService()
|
||||||
|
{
|
||||||
|
return GetRequiredService<IJournalService>();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Route("getDirectLinkCreateTicket"), HttpGet]
|
||||||
|
public async Task<F4SDHelperService.DirectLink> getDirectLinkCreateTicket([FromUri] string sid = "", [FromUri] string assetname = "")
|
||||||
|
{
|
||||||
|
await Task.Delay(0);
|
||||||
|
sid = QueryValue(sid, nameof(sid));
|
||||||
|
assetname = QueryValue(assetname, nameof(assetname));
|
||||||
|
return await _f4stHelperService.getDirectLinkCreateTicket(sid, assetname)
|
||||||
|
?? new F4SDHelperService.DirectLink();
|
||||||
|
}
|
||||||
|
[Route("getDirectLinkF4SD"), HttpGet]
|
||||||
|
public async Task<string> getDirectLinkF4SD([FromUri] Guid eoid, [FromUri] string type)
|
||||||
|
{
|
||||||
|
eoid = QueryValue(eoid, nameof(eoid));
|
||||||
|
type = QueryValue(type, nameof(type));
|
||||||
|
return await _f4stHelperService.getDirectLinkF4SD(eoid, type) ?? string.Empty;
|
||||||
|
}
|
||||||
|
|
||||||
|
[Obsolete("Use getTicketListForUser with a Matrix42 user ID.")]
|
||||||
[Route("getTicketList"), HttpGet]
|
[Route("getTicketList"), HttpGet]
|
||||||
public async Task<List<cF4SDTicketSummary>> getTicketList(
|
public async Task<List<cF4SDTicketSummary>> getTicketList(
|
||||||
string sid,
|
[FromUri] string sid,
|
||||||
int hours,
|
[FromUri] int hours,
|
||||||
int queueoption = 0,
|
[FromUri] int queueoption = 0,
|
||||||
string queues = ""
|
[FromUri] string queues = ""
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
|
sid = QueryValue(sid, nameof(sid));
|
||||||
|
hours = QueryValue(hours, nameof(hours));
|
||||||
|
queueoption = QueryValue(queueoption, nameof(queueoption));
|
||||||
|
queues = QueryValue(queues, nameof(queues));
|
||||||
var decodedPairs = ParseQueues(queues);
|
var decodedPairs = ParseQueues(queues);
|
||||||
|
|
||||||
// Nun weiterreichen an Service
|
// Nun weiterreichen an Service
|
||||||
@@ -113,35 +132,81 @@ namespace C4IT.F4SD
|
|||||||
hours,
|
hours,
|
||||||
queueoption,
|
queueoption,
|
||||||
decodedPairs
|
decodedPairs
|
||||||
);
|
) ?? new List<cF4SDTicketSummary>();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Route("getTicketListForUser"), HttpGet]
|
||||||
|
public async Task<List<cF4SDTicketSummary>> getTicketListForUser(
|
||||||
|
[FromUri] Guid userId,
|
||||||
|
[FromUri] int hours,
|
||||||
|
[FromUri] int queueoption = 0,
|
||||||
|
[FromUri] string queues = "")
|
||||||
|
{
|
||||||
|
userId = QueryValue(userId, nameof(userId));
|
||||||
|
hours = QueryValue(hours, nameof(hours));
|
||||||
|
queueoption = QueryValue(queueoption, nameof(queueoption));
|
||||||
|
queues = QueryValue(queues, nameof(queues));
|
||||||
|
|
||||||
|
return await _f4stHelperService.getTicketListByUser(
|
||||||
|
userId,
|
||||||
|
hours,
|
||||||
|
queueoption,
|
||||||
|
ParseQueues(queues)) ?? new List<cF4SDTicketSummary>();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Route("v2/getTicketList"), HttpPost]
|
||||||
|
public async Task<List<cF4SDTicketSummary>> getTicketListV2([FromBody] cTicketListFilterRequest request)
|
||||||
|
{
|
||||||
|
if (request?.UserId != Guid.Empty)
|
||||||
|
return await _f4stHelperService.getTicketListByUser(
|
||||||
|
request.UserId,
|
||||||
|
request.Hours,
|
||||||
|
0,
|
||||||
|
new List<cApiM42TicketQueueInfo>(),
|
||||||
|
request.Filters) ?? new List<cF4SDTicketSummary>();
|
||||||
|
|
||||||
|
return await _f4stHelperService.getTicketListByUser(
|
||||||
|
request?.Sid ?? string.Empty,
|
||||||
|
request?.Hours ?? 0,
|
||||||
|
0,
|
||||||
|
new List<cApiM42TicketQueueInfo>(),
|
||||||
|
request?.Filters) ?? new List<cF4SDTicketSummary>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
[Route("getTicketDetails"), HttpGet]
|
[Route("getTicketDetails"), HttpGet]
|
||||||
public async Task<cF4SDTicket> getTicketDetails(Guid objectId)
|
public async Task<cF4SDTicket> getTicketDetails([FromUri] Guid objectId)
|
||||||
{
|
{
|
||||||
|
objectId = QueryValue(objectId, nameof(objectId));
|
||||||
var tickets = await _f4stHelperService.getTicketDetails(new List<Guid>() { objectId });
|
var tickets = await _f4stHelperService.getTicketDetails(new List<Guid>() { objectId });
|
||||||
if (tickets.Count > 0)
|
if (tickets?.Count > 0)
|
||||||
return tickets[0];
|
return tickets[0];
|
||||||
else
|
|
||||||
return null;
|
return new cF4SDTicket { TicketObjectId = objectId };
|
||||||
}
|
}
|
||||||
|
|
||||||
[Route("getTicketHistory"), HttpGet]
|
[Route("getTicketHistory"), HttpGet]
|
||||||
public async Task<List<cTicketJournalItem>> getTicketHistory(Guid objectId)
|
public async Task<List<cTicketJournalItem>> getTicketHistory([FromUri] Guid objectId)
|
||||||
{
|
{
|
||||||
return await _f4stHelperService.GetJournalEntries(objectId);
|
objectId = QueryValue(objectId, nameof(objectId));
|
||||||
|
return await _f4stHelperService.GetJournalEntries(objectId) ?? new List<cTicketJournalItem>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Obsolete("Use getTicketOverviewCountsForUser with a Matrix42 user ID.")]
|
||||||
[Route("getTicketOverviewCounts"), HttpGet]
|
[Route("getTicketOverviewCounts"), HttpGet]
|
||||||
public async Task<F4SDHelperService.TicketOverviewCountsResult> getTicketOverviewCounts(
|
public async Task<F4SDHelperService.TicketOverviewCountsResult> getTicketOverviewCounts(
|
||||||
string sid,
|
[FromUri] string sid,
|
||||||
string scope = "personal",
|
[FromUri] string scope = "personal",
|
||||||
string keys = "",
|
[FromUri] string keys = "",
|
||||||
int queueoption = 0,
|
[FromUri] int queueoption = 0,
|
||||||
string queues = ""
|
[FromUri] string queues = ""
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
|
sid = QueryValue(sid, nameof(sid));
|
||||||
|
scope = QueryValue(scope, nameof(scope));
|
||||||
|
keys = QueryValue(keys, nameof(keys));
|
||||||
|
queueoption = QueryValue(queueoption, nameof(queueoption));
|
||||||
|
queues = QueryValue(queues, nameof(queues));
|
||||||
var parsedKeys = (keys ?? string.Empty)
|
var parsedKeys = (keys ?? string.Empty)
|
||||||
.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries)
|
.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries)
|
||||||
.Select(key => key.Trim())
|
.Select(key => key.Trim())
|
||||||
@@ -149,9 +214,57 @@ namespace C4IT.F4SD
|
|||||||
.ToList();
|
.ToList();
|
||||||
|
|
||||||
var decodedQueues = ParseQueues(queues);
|
var decodedQueues = ParseQueues(queues);
|
||||||
return await _f4stHelperService.getTicketOverviewCounts(sid, scope, parsedKeys, queueoption, decodedQueues);
|
return await _f4stHelperService.getTicketOverviewCounts(sid, scope, parsedKeys, queueoption, decodedQueues)
|
||||||
|
?? new F4SDHelperService.TicketOverviewCountsResult();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Route("getTicketOverviewCountsForUser"), HttpGet]
|
||||||
|
public async Task<F4SDHelperService.TicketOverviewCountsResult> getTicketOverviewCountsForUser(
|
||||||
|
[FromUri] Guid userId,
|
||||||
|
[FromUri] string scope = "personal",
|
||||||
|
[FromUri] string keys = "",
|
||||||
|
[FromUri] int queueoption = 0,
|
||||||
|
[FromUri] string queues = "")
|
||||||
|
{
|
||||||
|
userId = QueryValue(userId, nameof(userId));
|
||||||
|
scope = QueryValue(scope, nameof(scope));
|
||||||
|
keys = QueryValue(keys, nameof(keys));
|
||||||
|
queueoption = QueryValue(queueoption, nameof(queueoption));
|
||||||
|
queues = QueryValue(queues, nameof(queues));
|
||||||
|
|
||||||
|
var parsedKeys = (keys ?? string.Empty)
|
||||||
|
.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries)
|
||||||
|
.Select(key => key.Trim())
|
||||||
|
.Where(key => !string.IsNullOrWhiteSpace(key))
|
||||||
|
.ToList();
|
||||||
|
|
||||||
|
return await _f4stHelperService.getTicketOverviewCounts(
|
||||||
|
userId,
|
||||||
|
scope,
|
||||||
|
parsedKeys,
|
||||||
|
queueoption,
|
||||||
|
ParseQueues(queues)) ?? new F4SDHelperService.TicketOverviewCountsResult();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Route("v2/getTicketOverviewCounts"), HttpPost]
|
||||||
|
public async Task<IHttpActionResult> getTicketOverviewCountsV2(
|
||||||
|
[FromBody] cTicketOverviewFilterRequest request)
|
||||||
|
{
|
||||||
|
if (request == null || request.UserId == Guid.Empty)
|
||||||
|
return BadRequest("A Matrix42 user ID is required.");
|
||||||
|
|
||||||
|
var result = await _f4stHelperService.getTicketOverviewCounts(
|
||||||
|
request.UserId,
|
||||||
|
request.Scope,
|
||||||
|
request.Keys,
|
||||||
|
0,
|
||||||
|
new List<cApiM42TicketQueueInfo>(),
|
||||||
|
request.Filters) ?? new F4SDHelperService.TicketOverviewCountsResult();
|
||||||
|
|
||||||
|
return Ok(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Obsolete("Use getTicketOverviewCountsByRolesForUser with a Matrix42 user ID.")]
|
||||||
[Route("getTicketOverviewCountsByRoles"), HttpPost]
|
[Route("getTicketOverviewCountsByRoles"), HttpPost]
|
||||||
public async Task<F4SDHelperService.TicketOverviewCountsByRoleResult> getTicketOverviewCountsByRoles([FromBody] TicketOverviewCountsByRolesRequest request)
|
public async Task<F4SDHelperService.TicketOverviewCountsByRoleResult> getTicketOverviewCountsByRoles([FromBody] TicketOverviewCountsByRolesRequest request)
|
||||||
{
|
{
|
||||||
@@ -173,21 +286,103 @@ namespace C4IT.F4SD
|
|||||||
parsedKeys,
|
parsedKeys,
|
||||||
request?.QueueOption ?? 0,
|
request?.QueueOption ?? 0,
|
||||||
decodedQueues
|
decodedQueues
|
||||||
);
|
) ?? new F4SDHelperService.TicketOverviewCountsByRoleResult();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Route("getTicketOverviewCountsByRolesForUser"), HttpPost]
|
||||||
|
public async Task<F4SDHelperService.TicketOverviewCountsByRoleResult> getTicketOverviewCountsByRolesForUser(
|
||||||
|
[FromBody] TicketOverviewCountsByRolesForUserRequest request)
|
||||||
|
{
|
||||||
|
var parsedKeys = (request?.Keys ?? new List<string>())
|
||||||
|
.Where(key => !string.IsNullOrWhiteSpace(key))
|
||||||
|
.Select(key => key.Trim())
|
||||||
|
.Distinct(StringComparer.OrdinalIgnoreCase)
|
||||||
|
.ToList();
|
||||||
|
|
||||||
|
var roleGuids = (request?.RoleGuids ?? new List<Guid>())
|
||||||
|
.Where(roleId => roleId != Guid.Empty)
|
||||||
|
.Distinct()
|
||||||
|
.ToList();
|
||||||
|
|
||||||
|
return await _f4stHelperService.getTicketOverviewCountsByRoles(
|
||||||
|
request?.userId ?? Guid.Empty,
|
||||||
|
roleGuids,
|
||||||
|
parsedKeys,
|
||||||
|
request?.QueueOption ?? 0,
|
||||||
|
ParseQueues(request?.Queues ?? string.Empty))
|
||||||
|
?? new F4SDHelperService.TicketOverviewCountsByRoleResult();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Obsolete("Use getTicketOverviewRelationsForUser with a Matrix42 user ID.")]
|
||||||
[Route("getTicketOverviewRelations"), HttpGet]
|
[Route("getTicketOverviewRelations"), HttpGet]
|
||||||
public async Task<List<F4SDHelperService.TicketOverviewRelationDto>> getTicketOverviewRelations(
|
public async Task<List<F4SDHelperService.TicketOverviewRelationDto>> getTicketOverviewRelations(
|
||||||
string sid,
|
[FromUri] string sid,
|
||||||
string scope = "personal",
|
[FromUri] string scope = "personal",
|
||||||
string key = "",
|
[FromUri] string key = "",
|
||||||
int count = 0,
|
[FromUri] int count = 0,
|
||||||
int queueoption = 0,
|
[FromUri] int queueoption = 0,
|
||||||
string queues = ""
|
[FromUri] string queues = ""
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
|
sid = QueryValue(sid, nameof(sid));
|
||||||
|
scope = QueryValue(scope, nameof(scope));
|
||||||
|
key = QueryValue(key, nameof(key));
|
||||||
|
count = QueryValue(count, nameof(count));
|
||||||
|
queueoption = QueryValue(queueoption, nameof(queueoption));
|
||||||
|
queues = QueryValue(queues, nameof(queues));
|
||||||
var decodedQueues = ParseQueues(queues);
|
var decodedQueues = ParseQueues(queues);
|
||||||
return await _f4stHelperService.getTicketOverviewRelations(sid, scope, key, count, queueoption, decodedQueues);
|
return await _f4stHelperService.getTicketOverviewRelations(sid, scope, key, count, queueoption, decodedQueues)
|
||||||
|
?? new List<F4SDHelperService.TicketOverviewRelationDto>();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Route("getTicketOverviewRelationsForUser"), HttpGet]
|
||||||
|
public async Task<List<F4SDHelperService.TicketOverviewRelationDto>> getTicketOverviewRelationsForUser(
|
||||||
|
[FromUri] Guid userId,
|
||||||
|
[FromUri] string scope = "personal",
|
||||||
|
[FromUri] string key = "",
|
||||||
|
[FromUri] int count = 0,
|
||||||
|
[FromUri] int queueoption = 0,
|
||||||
|
[FromUri] string queues = "")
|
||||||
|
{
|
||||||
|
userId = QueryValue(userId, nameof(userId));
|
||||||
|
scope = QueryValue(scope, nameof(scope));
|
||||||
|
key = QueryValue(key, nameof(key));
|
||||||
|
count = QueryValue(count, nameof(count));
|
||||||
|
queueoption = QueryValue(queueoption, nameof(queueoption));
|
||||||
|
queues = QueryValue(queues, nameof(queues));
|
||||||
|
|
||||||
|
return await _f4stHelperService.getTicketOverviewRelations(
|
||||||
|
userId,
|
||||||
|
scope,
|
||||||
|
key,
|
||||||
|
count,
|
||||||
|
queueoption,
|
||||||
|
ParseQueues(queues)) ?? new List<F4SDHelperService.TicketOverviewRelationDto>();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Route("v2/getTicketOverviewRelations"), HttpPost]
|
||||||
|
public async Task<IHttpActionResult> getTicketOverviewRelationsV2(
|
||||||
|
[FromBody] cTicketOverviewFilterRequest request)
|
||||||
|
{
|
||||||
|
if (request == null || request.UserId == Guid.Empty)
|
||||||
|
return BadRequest("A Matrix42 user ID is required.");
|
||||||
|
|
||||||
|
var result = await _f4stHelperService.getTicketOverviewRelations(
|
||||||
|
request.UserId,
|
||||||
|
request.Scope,
|
||||||
|
request.Key,
|
||||||
|
request.Count,
|
||||||
|
0,
|
||||||
|
new List<cApiM42TicketQueueInfo>(),
|
||||||
|
request.Filters) ?? new List<F4SDHelperService.TicketOverviewRelationDto>();
|
||||||
|
|
||||||
|
return Ok(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Route("v2/getTicketFilterCapabilities"), HttpGet]
|
||||||
|
public cTicketFilterCapabilities getTicketFilterCapabilitiesV2()
|
||||||
|
{
|
||||||
|
return _f4stHelperService.GetTicketFilterCapabilities();
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
[Route("updateActivitySolution/{objectId}"), HttpPost]
|
[Route("updateActivitySolution/{objectId}"), HttpPost]
|
||||||
@@ -201,10 +396,13 @@ namespace C4IT.F4SD
|
|||||||
*/
|
*/
|
||||||
[Route("getPickup/{name}"), HttpGet]
|
[Route("getPickup/{name}"), HttpGet]
|
||||||
//[CacheOutput(UseETAG = true)]
|
//[CacheOutput(UseETAG = true)]
|
||||||
public async Task<HttpResponseMessage> getPickup(string name, [FromUri] EntityEnumerationVisibilityMode mode = EntityEnumerationVisibilityMode.None, [FromUri] Int32 group = -1)
|
public async Task<EntityEnumeration> getPickup([FromUri] string name, [FromUri] EntityEnumerationVisibilityMode mode = EntityEnumerationVisibilityMode.None, [FromUri] Int32 group = -1)
|
||||||
{
|
{
|
||||||
await Task.Delay(0);
|
await Task.Delay(0);
|
||||||
EntityEnumeration enumerationTemp = _entityDataService.GetEnumeration(name, mode);
|
name = QueryValue(name, nameof(name));
|
||||||
|
mode = QueryValue(mode, nameof(mode));
|
||||||
|
group = QueryValue(group, nameof(group));
|
||||||
|
EntityEnumeration enumerationTemp = GetEnumeration(name, mode);
|
||||||
var vals = enumerationTemp.Values;
|
var vals = enumerationTemp.Values;
|
||||||
|
|
||||||
if (group > -1)
|
if (group > -1)
|
||||||
@@ -224,51 +422,55 @@ namespace C4IT.F4SD
|
|||||||
Values = vals.ToArray()
|
Values = vals.ToArray()
|
||||||
};
|
};
|
||||||
//CacheOutputAttribute.RegisterResponseEtag($"enum_{enumeration.Name}_{(int)mode}", $"{enumeration.Name}_{(int)mode}", cultureInvariant: false, userInvariant: true, val);
|
//CacheOutputAttribute.RegisterResponseEtag($"enum_{enumeration.Name}_{(int)mode}", $"{enumeration.Name}_{(int)mode}", cultureInvariant: false, userInvariant: true, val);
|
||||||
return Request.CreateResponse(HttpStatusCode.OK, enumeration);
|
return enumeration;
|
||||||
}
|
}
|
||||||
|
|
||||||
[Route("getMyRoleMemberships", Order = 2), HttpGet]
|
[Route("getMyRoleMemberships"), HttpGet]
|
||||||
public async Task<HttpResponseMessage> getMyRoleMemberships()
|
public async Task<object> getMyRoleMemberships()
|
||||||
{
|
{
|
||||||
var User = _userProfile.GetInteractiveUserInfo();
|
var userId = GetCurrentUserId();
|
||||||
var filter = AsqlHelper.BuildInCondition("ID", new Guid[] { User.Id });
|
if (userId == Guid.Empty)
|
||||||
return Request.CreateResponse(HttpStatusCode.OK, await _f4stHelperService.UserPermissionsInfo(filter));
|
throw new UnauthorizedAccessException("Cannot determine the interactive Matrix42 user.");
|
||||||
|
|
||||||
|
var filter = AsqlHelper.BuildInCondition("ID", new Guid[] { userId });
|
||||||
|
return await _f4stHelperService.UserPermissionsInfo(filter) ?? new UserPermissionsInfo();
|
||||||
}
|
}
|
||||||
[HttpGet]
|
[HttpGet]
|
||||||
[Route("getRoleMemberships", Order = 1)]
|
[Route("getRoleMemberships")]
|
||||||
public async Task<HttpResponseMessage> getRoleMemberships([FromUri] GetRoleMembershipsRequest req)
|
public async Task<object> getRoleMemberships([FromUri] string sid = "", [FromUri] string upn = "", [FromUri] Guid? id = null)
|
||||||
{
|
{
|
||||||
|
sid = QueryValue(sid, nameof(sid));
|
||||||
|
upn = QueryValue(upn, nameof(upn));
|
||||||
|
id = QueryValue(id, nameof(id));
|
||||||
var filter = "";
|
var filter = "";
|
||||||
|
|
||||||
if (req.Id != null && req.Id.Value != Guid.Empty)
|
if (id != null && id.Value != Guid.Empty)
|
||||||
{
|
{
|
||||||
filter = AsqlHelper.BuildInCondition("ID", new Guid[] { req.Id.Value });
|
filter = AsqlHelper.BuildInCondition("ID", new Guid[] { id.Value });
|
||||||
}
|
}
|
||||||
else if (!string.IsNullOrEmpty(req.Sid))
|
else if (!string.IsNullOrEmpty(sid))
|
||||||
{
|
{
|
||||||
filter = AsqlHelper.BuildInCondition("Accounts.T(SPSAccountClassAD).Sid", new string[] { req.Sid });
|
filter = AsqlHelper.BuildInCondition("Accounts.T(SPSAccountClassAD).Sid", new string[] { sid });
|
||||||
}
|
}
|
||||||
else if (!string.IsNullOrEmpty(req.Upn))
|
else if (!string.IsNullOrEmpty(upn))
|
||||||
{
|
{
|
||||||
filter = AsqlHelper.BuildInCondition("Accounts.T(SPSAccountClassAD).UserPrincipalName", new string[] { req.Upn });
|
filter = AsqlHelper.BuildInCondition("Accounts.T(SPSAccountClassAD).UserPrincipalName", new string[] { upn });
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(filter))
|
if (!string.IsNullOrEmpty(filter))
|
||||||
{
|
{
|
||||||
return Request.CreateResponse(HttpStatusCode.OK, await _f4stHelperService.UserPermissionsInfo(filter));
|
return await _f4stHelperService.UserPermissionsInfo(filter) ?? new UserPermissionsInfo();
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public class GetRoleMembershipsRequest
|
return new UserPermissionsInfo();
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpGet]
|
||||||
|
[Route("getRoleMemberships/{userId}")]
|
||||||
|
public async Task<object> getRoleMembershipForUser([FromUri] Guid userId)
|
||||||
{
|
{
|
||||||
public Guid? Id { get; set; }
|
return await _f4stHelperService.UserPermissionsInfo(
|
||||||
public string Sid { get; set; }
|
AsqlHelper.BuildInCondition("ID", new[] { userId })) ?? new UserPermissionsInfo();
|
||||||
public string Upn { get; set; }
|
|
||||||
public GetRoleMembershipsRequest() { }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public class TicketOverviewCountsByRolesRequest
|
public class TicketOverviewCountsByRolesRequest
|
||||||
@@ -280,6 +482,136 @@ namespace C4IT.F4SD
|
|||||||
public string Queues { get; set; }
|
public string Queues { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public class TicketOverviewCountsByRolesForUserRequest
|
||||||
|
{
|
||||||
|
public Guid userId { get; set; }
|
||||||
|
public List<Guid> RoleGuids { get; set; } = new List<Guid>();
|
||||||
|
public List<string> Keys { get; set; } = new List<string>();
|
||||||
|
public int? QueueOption { get; set; }
|
||||||
|
public string Queues { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
private EntityEnumeration GetEnumeration(string name, EntityEnumerationVisibilityMode mode)
|
||||||
|
{
|
||||||
|
name = name?.Trim();
|
||||||
|
var dataTable = _enumerationProvider.GetEnumeration(name, GetVisibilityFilter(mode));
|
||||||
|
if (dataTable == null)
|
||||||
|
throw new InvalidOperationException($"Enumeration '{name}' was not found.");
|
||||||
|
|
||||||
|
var valueColumn = FindColumn(dataTable, "Value") ?? FindNumericColumn(dataTable);
|
||||||
|
if (string.IsNullOrEmpty(valueColumn))
|
||||||
|
throw new InvalidOperationException($"Enumeration '{name}' does not contain a numeric value column.");
|
||||||
|
|
||||||
|
var displayColumn = FindColumn(dataTable, "DisplayString")
|
||||||
|
?? FindColumn(dataTable, "DisplayExpression")
|
||||||
|
?? FindColumn(dataTable, "Name")
|
||||||
|
?? valueColumn;
|
||||||
|
var hiddenColumn = FindColumn(dataTable, "Hidden");
|
||||||
|
|
||||||
|
var values = dataTable.Rows.Cast<DataRow>()
|
||||||
|
.Select(row => new EntityEnumerationValue
|
||||||
|
{
|
||||||
|
Value = ConvertHelper.ParseInt(row[valueColumn], 0),
|
||||||
|
DisplayString = Convert.ToString(row[displayColumn]),
|
||||||
|
Hidden = hiddenColumn != null && ConvertHelper.ParseInt(row[hiddenColumn], 0) == 1,
|
||||||
|
Extentions = dataTable.Columns.Cast<DataColumn>()
|
||||||
|
.ToDictionary(column => column.ColumnName, column => row[column])
|
||||||
|
})
|
||||||
|
.ToArray();
|
||||||
|
|
||||||
|
return new EntityEnumeration
|
||||||
|
{
|
||||||
|
Name = name,
|
||||||
|
Values = values
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool? GetVisibilityFilter(EntityEnumerationVisibilityMode mode)
|
||||||
|
{
|
||||||
|
switch (mode)
|
||||||
|
{
|
||||||
|
case EntityEnumerationVisibilityMode.Visible:
|
||||||
|
return true;
|
||||||
|
case EntityEnumerationVisibilityMode.Hidden:
|
||||||
|
return false;
|
||||||
|
default:
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string FindColumn(DataTable dataTable, string columnName)
|
||||||
|
{
|
||||||
|
return dataTable.Columns.Cast<DataColumn>()
|
||||||
|
.FirstOrDefault(column => string.Equals(column.ColumnName, columnName, StringComparison.OrdinalIgnoreCase))
|
||||||
|
?.ColumnName;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string FindNumericColumn(DataTable dataTable)
|
||||||
|
{
|
||||||
|
var excludedNames = new HashSet<string>(StringComparer.OrdinalIgnoreCase)
|
||||||
|
{
|
||||||
|
"Hidden",
|
||||||
|
"Position",
|
||||||
|
"StateGroup"
|
||||||
|
};
|
||||||
|
|
||||||
|
return dataTable.Columns.Cast<DataColumn>()
|
||||||
|
.FirstOrDefault(column => !excludedNames.Contains(column.ColumnName) && IsNumericType(column.DataType))
|
||||||
|
?.ColumnName;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool IsNumericType(Type type)
|
||||||
|
{
|
||||||
|
return type == typeof(byte)
|
||||||
|
|| type == typeof(short)
|
||||||
|
|| type == typeof(int)
|
||||||
|
|| type == typeof(long)
|
||||||
|
|| type == typeof(sbyte)
|
||||||
|
|| type == typeof(ushort)
|
||||||
|
|| type == typeof(uint)
|
||||||
|
|| type == typeof(ulong);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Guid GetCurrentUserId()
|
||||||
|
{
|
||||||
|
var principal = Thread.CurrentPrincipal as IM42Principal;
|
||||||
|
return principal?.InteractivePrincipal?.M42Identity?.UserFragmentID
|
||||||
|
?? principal?.M42Identity?.UserFragmentID
|
||||||
|
?? Guid.Empty;
|
||||||
|
}
|
||||||
|
|
||||||
|
private string GetQueryValue(string name)
|
||||||
|
{
|
||||||
|
return Request?.GetQueryNameValuePairs()
|
||||||
|
.FirstOrDefault(pair => string.Equals(pair.Key, name, StringComparison.OrdinalIgnoreCase))
|
||||||
|
.Value;
|
||||||
|
}
|
||||||
|
|
||||||
|
private string QueryValue(string value, string name)
|
||||||
|
{
|
||||||
|
return GetQueryValue(name) ?? value ?? string.Empty;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int QueryValue(int value, string name)
|
||||||
|
{
|
||||||
|
return int.TryParse(GetQueryValue(name), out var parsed) ? parsed : value;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Guid QueryValue(Guid value, string name)
|
||||||
|
{
|
||||||
|
return Guid.TryParse(GetQueryValue(name), out var parsed) ? parsed : value;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Guid? QueryValue(Guid? value, string name)
|
||||||
|
{
|
||||||
|
return Guid.TryParse(GetQueryValue(name), out var parsed) ? parsed : value;
|
||||||
|
}
|
||||||
|
|
||||||
|
private TEnum QueryValue<TEnum>(TEnum value, string name) where TEnum : struct
|
||||||
|
{
|
||||||
|
return Enum.TryParse<TEnum>(GetQueryValue(name), true, out var parsed) ? parsed : value;
|
||||||
|
}
|
||||||
|
|
||||||
private static List<cApiM42TicketQueueInfo> ParseQueues(string queues)
|
private static List<cApiM42TicketQueueInfo> ParseQueues(string queues)
|
||||||
{
|
{
|
||||||
return (queues ?? string.Empty)
|
return (queues ?? string.Empty)
|
||||||
@@ -290,8 +622,8 @@ namespace C4IT.F4SD
|
|||||||
if (segments.Length != 2)
|
if (segments.Length != 2)
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
var name = HttpUtility.UrlDecode(segments[0]);
|
var name = WebUtility.UrlDecode(segments[0]);
|
||||||
var idStr = HttpUtility.UrlDecode(segments[1]);
|
var idStr = WebUtility.UrlDecode(segments[1]);
|
||||||
|
|
||||||
return Guid.TryParse(idStr, out var guid)
|
return Guid.TryParse(idStr, out var guid)
|
||||||
? new cApiM42TicketQueueInfo { QueueName = name, QueueID = guid }
|
? new cApiM42TicketQueueInfo { QueueName = name, QueueID = guid }
|
||||||
@@ -302,26 +634,33 @@ namespace C4IT.F4SD
|
|||||||
}
|
}
|
||||||
|
|
||||||
[Route("isAlive"), HttpGet]
|
[Route("isAlive"), HttpGet]
|
||||||
public HttpResponseMessage isAlive()
|
public IHttpActionResult isAlive()
|
||||||
{
|
{
|
||||||
return new HttpResponseMessage(HttpStatusCode.NoContent);
|
var response = new HttpResponseMessage(HttpStatusCode.NoContent)
|
||||||
|
{
|
||||||
|
RequestMessage = Request
|
||||||
|
};
|
||||||
|
response.Headers.ConnectionClose = true;
|
||||||
|
|
||||||
|
return ResponseMessage(response);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Route("loglevel"), HttpGet]
|
[Route("loglevel"), HttpGet]
|
||||||
public async Task<string> setDebugMode(string debug = "0")
|
public async Task<string> setDebugMode([FromUri] string debug = "0")
|
||||||
{
|
{
|
||||||
var CM = MethodBase.GetCurrentMethod();
|
var CM = MethodBase.GetCurrentMethod();
|
||||||
LogMethodBegin(CM);
|
LogMethodBegin(CM);
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
await Task.Delay(0);
|
await Task.Delay(0);
|
||||||
|
debug = QueryValue(debug, nameof(debug));
|
||||||
DefaultLogger.Manager.Level = debug == "1" || debug.Equals("true", StringComparison.OrdinalIgnoreCase) ? LogLevels.Debug : LogLevels.Info;
|
DefaultLogger.Manager.Level = debug == "1" || debug.Equals("true", StringComparison.OrdinalIgnoreCase) ? LogLevels.Debug : LogLevels.Info;
|
||||||
return DefaultLogger.Manager.Level.ToString();
|
return DefaultLogger.Manager.Level.ToString();
|
||||||
}
|
}
|
||||||
catch (Exception E)
|
catch (Exception E)
|
||||||
{
|
{
|
||||||
LogException(E);
|
LogException(E);
|
||||||
return null;
|
return string.Empty;
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
@@ -330,16 +669,23 @@ namespace C4IT.F4SD
|
|||||||
}
|
}
|
||||||
|
|
||||||
[Route("log"), HttpGet]
|
[Route("log"), HttpGet]
|
||||||
public HttpResponseMessage getLog(string download = "0", int count = 50, string filter = "")
|
public IHttpActionResult getLog([FromUri] string download = "0", [FromUri] int count = 50, [FromUri] string filter = "")
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
return _f4stHelperService.privGetLog(download, count, Request, filter);
|
download = QueryValue(download, nameof(download));
|
||||||
|
count = QueryValue(count, nameof(count));
|
||||||
|
filter = QueryValue(filter, nameof(filter));
|
||||||
|
var response = _f4stHelperService.privGetLog(download, count, Request, filter);
|
||||||
|
if (response == null)
|
||||||
|
return new StatusCodeResult(HttpStatusCode.NoContent);
|
||||||
|
|
||||||
|
return new ResponseMessageResult(response);
|
||||||
}
|
}
|
||||||
catch (Exception E)
|
catch (Exception E)
|
||||||
{
|
{
|
||||||
LogException(E);
|
LogException(E);
|
||||||
return null;
|
return new StatusCodeResult(HttpStatusCode.InternalServerError);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -350,10 +696,9 @@ namespace C4IT.F4SD
|
|||||||
|
|
||||||
public static bool IsInitialized { get; private set; } = false;
|
public static bool IsInitialized { get; private set; } = false;
|
||||||
|
|
||||||
private static object initLock = new object();
|
private static readonly object initLock = new object();
|
||||||
protected override void Initialize(HttpControllerContext controllerContext)
|
private static void EnsureInitialized()
|
||||||
{
|
{
|
||||||
base.Initialize(controllerContext);
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
lock (initLock)
|
lock (initLock)
|
||||||
@@ -377,25 +722,20 @@ namespace C4IT.F4SD
|
|||||||
public F4SDM42LogsWebApiController()
|
public F4SDM42LogsWebApiController()
|
||||||
{
|
{
|
||||||
_f4stHelperService = new F4SDHelperService();
|
_f4stHelperService = new F4SDHelperService();
|
||||||
|
EnsureInitialized();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Route(""), HttpGet]
|
[Route(""), HttpGet]
|
||||||
[EnableQuery]
|
|
||||||
public IEnumerable<cM42LogEntry> getLog2(ODataQueryOptions<cM42LogEntry> queryOptions)
|
public IEnumerable<cM42LogEntry> getLog2(ODataQueryOptions<cM42LogEntry> queryOptions)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
IQueryable<cM42LogEntry> queryable = _f4stHelperService.privGetLog2().AsQueryable();
|
return ApplyLogFilter(_f4stHelperService.privGetLog2(), queryOptions);
|
||||||
if (queryOptions.Filter != null)
|
|
||||||
{
|
|
||||||
queryable = queryOptions.Filter.ApplyTo(queryable, new ODataQuerySettings()).Cast<cM42LogEntry>();
|
|
||||||
}
|
|
||||||
return queryable;
|
|
||||||
}
|
}
|
||||||
catch (Exception E)
|
catch (Exception E)
|
||||||
{
|
{
|
||||||
LogException(E);
|
LogException(E);
|
||||||
return null;
|
return Enumerable.Empty<cM42LogEntry>();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -403,19 +743,30 @@ namespace C4IT.F4SD
|
|||||||
[HttpGet]
|
[HttpGet]
|
||||||
public int Log2Count(ODataQueryOptions<cM42LogEntry> queryOptions)
|
public int Log2Count(ODataQueryOptions<cM42LogEntry> queryOptions)
|
||||||
{
|
{
|
||||||
IQueryable<cM42LogEntry> queryable = _f4stHelperService.privGetLog2().AsQueryable();
|
return ApplyLogFilter(_f4stHelperService.privGetLog2(), queryOptions).Count();
|
||||||
if (queryOptions.Filter != null)
|
|
||||||
{
|
|
||||||
queryable = queryOptions.Filter.ApplyTo(queryable, new ODataQuerySettings()).Cast<cM42LogEntry>();
|
|
||||||
}
|
|
||||||
return queryable.Count();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[Route("{id}")]
|
[Route("{id}")]
|
||||||
[OperationType(OperationType.GetObject)]
|
[OperationType(OperationType.GetObject)]
|
||||||
public cM42LogEntry GetClass(int id)
|
public cM42LogEntry GetClass(int id)
|
||||||
{
|
{
|
||||||
return _f4stHelperService.privGetLog2(id);
|
return _f4stHelperService.privGetLog2(id) ?? new cM42LogEntry { LineNumber = id };
|
||||||
|
}
|
||||||
|
|
||||||
|
private static IEnumerable<cM42LogEntry> ApplyLogFilter(IEnumerable<cM42LogEntry> entries, ODataQueryOptions<cM42LogEntry> queryOptions)
|
||||||
|
{
|
||||||
|
var result = entries ?? Enumerable.Empty<cM42LogEntry>();
|
||||||
|
var filter = queryOptions?.Filter;
|
||||||
|
|
||||||
|
if (!string.IsNullOrWhiteSpace(filter))
|
||||||
|
{
|
||||||
|
result = result.Where(entry =>
|
||||||
|
(entry.Message?.IndexOf(filter, StringComparison.OrdinalIgnoreCase) ?? -1) >= 0 ||
|
||||||
|
(entry.logLvl?.IndexOf(filter, StringComparison.OrdinalIgnoreCase) ?? -1) >= 0 ||
|
||||||
|
(entry.Theme?.IndexOf(filter, StringComparison.OrdinalIgnoreCase) ?? -1) >= 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
28
F4SDM42WebApi/M42ExtensionScaffolder/.gitignore
vendored
Normal file
28
F4SDM42WebApi/M42ExtensionScaffolder/.gitignore
vendored
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
|
||||||
|
.idea/
|
||||||
|
.vs/
|
||||||
|
.vscode/
|
||||||
|
node_modules/
|
||||||
|
dist/
|
||||||
|
|
||||||
|
package-lock.json
|
||||||
|
workspace.json
|
||||||
|
|
||||||
|
.vs/
|
||||||
|
.libs/
|
||||||
|
.build/
|
||||||
|
|
||||||
|
bin/
|
||||||
|
obj/
|
||||||
|
|
||||||
|
*.user
|
||||||
|
|
||||||
|
/**/AssemblyInfoProduct.cs
|
||||||
|
/**/_Resharper.Caches
|
||||||
|
/Solutions/*.sln.DotSettings.user
|
||||||
|
/Solutions/**/*.csproj.user
|
||||||
|
/Solutions/**/packages/*.*
|
||||||
|
/Solutions/**/**/AssemblyInfoProduct.cs
|
||||||
|
/Solutions/TestResult/*.*
|
||||||
|
|
||||||
|
BasePackage/Assemblies/
|
||||||
14
F4SDM42WebApi/M42ExtensionScaffolder/README.md
Normal file
14
F4SDM42WebApi/M42ExtensionScaffolder/README.md
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
# M42ExtensionScaffolder
|
||||||
|
|
||||||
|
## Description
|
||||||
|
Template project acting as an extension scaffolder. Automatically generate extension structure including provided projects and runtimes
|
||||||
|
|
||||||
|
## Owner
|
||||||
|
Name: Titan
|
||||||
|
Email: dmytro.romanii@matrix42.com
|
||||||
|
|
||||||
|
## Product
|
||||||
|
M42 Enterprise
|
||||||
|
|
||||||
|
## Documentation
|
||||||
|
- [Service Information](./service-info.yml)
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<OutputType>Exe</OutputType>
|
||||||
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Microsoft.Extensions.Configuration" Version="10.0.0" />
|
||||||
|
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="10.0.0" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\Matrix42.Extensions.Scaffolder.Core\Matrix42.Extensions.Scaffolder.Core.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<None Update="appsettings.json">
|
||||||
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
|
</None>
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
||||||
@@ -0,0 +1,61 @@
|
|||||||
|
using Matrix42.Extensions.Scaffolder.Core;
|
||||||
|
using Matrix42.Extensions.Scaffolder.Core.Project;
|
||||||
|
using Microsoft.Extensions.Configuration;
|
||||||
|
|
||||||
|
namespace Matrix42.Extensions.Scaffolder.ConsoleApp
|
||||||
|
{
|
||||||
|
internal class Program
|
||||||
|
{
|
||||||
|
static void Main(string[] args)
|
||||||
|
{
|
||||||
|
var config = new ConfigurationBuilder()
|
||||||
|
.SetBasePath(Directory.GetCurrentDirectory()) // required for appsettings.json
|
||||||
|
.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
|
||||||
|
.Build();
|
||||||
|
|
||||||
|
var extensionPath = config["Scaffolder:ExtensionPath"];
|
||||||
|
var extensionIdStr = config["Scaffolder:ExtensionId"];
|
||||||
|
var extensionNamespace = config["Scaffolder:ExtensionNamespace"];
|
||||||
|
|
||||||
|
if (string.IsNullOrWhiteSpace(extensionPath))
|
||||||
|
throw new Exception("Scaffolder:ExtensionPath is missing in appsettings.json");
|
||||||
|
|
||||||
|
var extensionId = Guid.TryParse(extensionIdStr, out var gid) ? gid : Guid.NewGuid();
|
||||||
|
|
||||||
|
var options = new ExtensionScaffoldingOptions
|
||||||
|
{
|
||||||
|
ExtensionPath = extensionPath,
|
||||||
|
ExtensionId = extensionId,
|
||||||
|
ExtensionNamespace = extensionNamespace,
|
||||||
|
Projects = [
|
||||||
|
new ProjectDefinition
|
||||||
|
{
|
||||||
|
Prefix = "Services",
|
||||||
|
Runtimes = RuntimeTargets.WinCore | RuntimeTargets.LinuxCore,
|
||||||
|
Functionality = ProjectFunctionality.WebApi
|
||||||
|
},
|
||||||
|
|
||||||
|
new ProjectDefinition
|
||||||
|
{
|
||||||
|
Prefix = "Contracts",
|
||||||
|
Runtimes = RuntimeTargets.All,
|
||||||
|
Functionality = ProjectFunctionality.Custom
|
||||||
|
},
|
||||||
|
new ProjectDefinition
|
||||||
|
{
|
||||||
|
Prefix = "BizLogic",
|
||||||
|
Runtimes = RuntimeTargets.All,
|
||||||
|
Functionality = ProjectFunctionality.Custom
|
||||||
|
}
|
||||||
|
]
|
||||||
|
};
|
||||||
|
|
||||||
|
var scaffolder = new ExtensionScaffolder();
|
||||||
|
var projects = scaffolder.Generate(options);
|
||||||
|
|
||||||
|
Console.WriteLine("Generated projects:");
|
||||||
|
foreach (var p in projects)
|
||||||
|
Console.WriteLine(" - " + p);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"Scaffolder": {
|
||||||
|
"ExtensionPath": "C:\\Projects\\Matrix42\\Titan_Linux\\ESM-FieldServiceManagement-Extension_demo",
|
||||||
|
"ExtensionId": "c55407f9-9b46-4483-8b65-1bc1c3827efc",
|
||||||
|
"ExtensionNamespace": "Matrix42.FieldServiceManagement"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,206 @@
|
|||||||
|
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Layout assumptions
|
||||||
|
|
||||||
|
This .targets file lives in:
|
||||||
|
{ExtensionPath}\Extension.Assemblies.targets
|
||||||
|
|
||||||
|
We want to copy to:
|
||||||
|
BasePackage\Assemblies\
|
||||||
|
→ {ExtensionPath}\BasePackage\Assemblies\
|
||||||
|
|
||||||
|
Root\InstalledPackages\Assemblies\{ExtensionId}\
|
||||||
|
→ {ExtensionPath}\..\Root\InstalledPackages\Assemblies\{ExtensionId}\
|
||||||
|
|
||||||
|
Properties:
|
||||||
|
- M42BasePackageAssembliesDir (can override in csproj)
|
||||||
|
- M42RootAssembliesDir (needs M42ExtensionId)
|
||||||
|
- M42AssemblyPattern (default: $(MSBuildProjectName)*.*)
|
||||||
|
- M42DefaultRids (default: win-x64;linux-x64)
|
||||||
|
- M42ExtensionId (set in csproj)
|
||||||
|
- M42EnableRidBuild (true for net8.0 w/ RIDs, false for netstandard)
|
||||||
|
-->
|
||||||
|
<PropertyGroup>
|
||||||
|
<!-- BasePackage under extension root -->
|
||||||
|
<M42BasePackageAssembliesDir Condition="'$(M42BasePackageAssembliesDir)' == ''">$(MSBuildThisFileDirectory)BasePackage\Assemblies\</M42BasePackageAssembliesDir>
|
||||||
|
|
||||||
|
<!-- Root one level above extension root -->
|
||||||
|
<M42RootAssembliesDir Condition="'$(M42RootAssembliesDir)' == '' AND '$(M42ExtensionId)' != ''">$(MSBuildThisFileDirectory)..\Root\InstalledPackages\Assemblies\$(M42ExtensionId)\</M42RootAssembliesDir>
|
||||||
|
|
||||||
|
<!-- Pattern & default RIDs -->
|
||||||
|
<M42AssemblyPattern Condition="'$(M42AssemblyPattern)' == ''">$(MSBuildProjectName)*.*</M42AssemblyPattern>
|
||||||
|
<M42DefaultRids Condition="'$(M42DefaultRids)' == ''">win-x64;linux-x64</M42DefaultRids>
|
||||||
|
|
||||||
|
<!-- Enable multi-RID builds per project; can be set to false in csproj -->
|
||||||
|
<M42EnableRidBuild Condition="'$(M42EnableRidBuild)' == ''">true</M42EnableRidBuild>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
|
||||||
|
<!--
|
||||||
|
M42_BuildAllRids
|
||||||
|
|
||||||
|
Local only: if no RID was specified AND we're not in Azure DevOps,
|
||||||
|
build all default RIDs (M42DefaultRids) by re-invoking MSBuild
|
||||||
|
with RuntimeIdentifier and AppendRuntimeIdentifierToOutputPath=true.
|
||||||
|
|
||||||
|
This prevents the outer RID-less build by setting SkipBuild=true.
|
||||||
|
|
||||||
|
Skipped when M42EnableRidBuild=false (e.g. netstandard projects).
|
||||||
|
-->
|
||||||
|
<Target Name="M42_BuildAllRids"
|
||||||
|
BeforeTargets="Build"
|
||||||
|
Condition="'$(RuntimeIdentifier)' == ''
|
||||||
|
AND ( '$(TF_BUILD)' != 'True' OR '$(M42BuildAllRidsOnCI)' == 'true' )
|
||||||
|
AND '$(M42EnableRidBuild)' == 'true'">
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<_M42RidList Include="$(M42DefaultRids)" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<MSBuild Projects="$(MSBuildProjectFullPath)"
|
||||||
|
Targets="Restore;Build"
|
||||||
|
Properties="RuntimeIdentifier=%(_M42RidList.Identity);Configuration=$(Configuration);AppendRuntimeIdentifierToOutputPath=true"
|
||||||
|
BuildInParallel="true" />
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<SkipBuild>true</SkipBuild>
|
||||||
|
</PropertyGroup>
|
||||||
|
</Target>
|
||||||
|
|
||||||
|
|
||||||
|
<!--
|
||||||
|
M42_PostBuild_CopyRidless
|
||||||
|
|
||||||
|
For RID-less builds (RuntimeIdentifier == ''), copy top-level output files
|
||||||
|
that match M42AssemblyPattern directly from $(TargetDir) to:
|
||||||
|
|
||||||
|
1) BasePackage\Assemblies\
|
||||||
|
2) Root\InstalledPackages\Assemblies\{ExtId}\ (if configured)
|
||||||
|
|
||||||
|
Useful for projects that don't support RID-specific builds (e.g. netstandard),
|
||||||
|
or when M42EnableRidBuild=false.
|
||||||
|
-->
|
||||||
|
<Target Name="M42_PostBuild_CopyRidless"
|
||||||
|
AfterTargets="Build"
|
||||||
|
Condition="'$(RuntimeIdentifier)' == ''">
|
||||||
|
|
||||||
|
<Message Text="M42: RID-less copy from $(TargetDir) → $(M42BasePackageAssembliesDir)" Importance="high" />
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<_M42FlatRootRidless Include="$(TargetDir)$(M42AssemblyPattern)" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<!-- BasePackage flat copy -->
|
||||||
|
<MakeDir Directories="$(M42BasePackageAssembliesDir)"
|
||||||
|
Condition="!Exists('$(M42BasePackageAssembliesDir)')" />
|
||||||
|
|
||||||
|
<Copy
|
||||||
|
SourceFiles="@(_M42FlatRootRidless)"
|
||||||
|
DestinationFolder="$(M42BasePackageAssembliesDir)"
|
||||||
|
SkipUnchangedFiles="true"
|
||||||
|
Condition="Exists('$(TargetDir)')" />
|
||||||
|
|
||||||
|
<!-- Root flat copy (if configured) -->
|
||||||
|
<Message Text="M42: RID-less copy to Root → $(M42RootAssembliesDir)" Importance="high"
|
||||||
|
Condition="'$(M42RootAssembliesDir)' != ''" />
|
||||||
|
|
||||||
|
<MakeDir Directories="$(M42RootAssembliesDir)"
|
||||||
|
Condition="'$(M42RootAssembliesDir)' != '' AND !Exists('$(M42RootAssembliesDir)')" />
|
||||||
|
|
||||||
|
<Copy
|
||||||
|
SourceFiles="@(_M42FlatRootRidless)"
|
||||||
|
DestinationFolder="$(M42RootAssembliesDir)"
|
||||||
|
SkipUnchangedFiles="true"
|
||||||
|
Condition="'$(M42RootAssembliesDir)' != '' AND Exists('$(TargetDir)')" />
|
||||||
|
|
||||||
|
</Target>
|
||||||
|
|
||||||
|
|
||||||
|
<!--
|
||||||
|
M42_PostBuild_CopyRID
|
||||||
|
|
||||||
|
After each RID-specific build, copy assemblies to:
|
||||||
|
|
||||||
|
1) BasePackage\Assemblies\ (FLAT, from RID-less bin\...\netX\)
|
||||||
|
2) BasePackage\Assemblies\<RID>\... (RECURSIVE, from current RID build)
|
||||||
|
|
||||||
|
And, if M42RootAssembliesDir is set:
|
||||||
|
|
||||||
|
3) Root\InstalledPackages\Assemblies\{ExtId}\ (FLAT)
|
||||||
|
4) Root\InstalledPackages\Assemblies\{ExtId}\<RID>\ (RECURSIVE)
|
||||||
|
-->
|
||||||
|
<Target Name="M42_PostBuild_CopyRID"
|
||||||
|
AfterTargets="Build"
|
||||||
|
Condition="'$(RuntimeIdentifier)' != ''">
|
||||||
|
|
||||||
|
<Message Text="M42: RID=$(RuntimeIdentifier) TargetDir=$(TargetDir)" Importance="high" />
|
||||||
|
|
||||||
|
<!-- Parent of ...\netX\<rid>\ -->
|
||||||
|
<PropertyGroup>
|
||||||
|
<M42_RidlessTargetDir>$([System.IO.Path]::GetFullPath('$(TargetDir)..\'))</M42_RidlessTargetDir>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<!-- 1) FLAT copy from rid-less netX to BasePackage\Assemblies -->
|
||||||
|
<Message Text="M42: flat copy from $(M42_RidlessTargetDir) → $(M42BasePackageAssembliesDir)" Importance="high" />
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<_M42FlatRoot Include="$(M42_RidlessTargetDir)$(M42AssemblyPattern)" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<MakeDir Directories="$(M42BasePackageAssembliesDir)"
|
||||||
|
Condition="!Exists('$(M42BasePackageAssembliesDir)')" />
|
||||||
|
|
||||||
|
<Copy
|
||||||
|
SourceFiles="@(_M42FlatRoot)"
|
||||||
|
DestinationFolder="$(M42BasePackageAssembliesDir)"
|
||||||
|
SkipUnchangedFiles="true"
|
||||||
|
Condition="Exists('$(M42_RidlessTargetDir)')" />
|
||||||
|
|
||||||
|
|
||||||
|
<!-- 1b) FLAT copy to Root if configured -->
|
||||||
|
<Message Text="M42: flat copy to Root → $(M42RootAssembliesDir)" Importance="high"
|
||||||
|
Condition="'$(M42RootAssembliesDir)' != ''" />
|
||||||
|
|
||||||
|
<MakeDir Directories="$(M42RootAssembliesDir)"
|
||||||
|
Condition="'$(M42RootAssembliesDir)' != '' AND !Exists('$(M42RootAssembliesDir)')" />
|
||||||
|
|
||||||
|
<Copy
|
||||||
|
SourceFiles="@(_M42FlatRoot)"
|
||||||
|
DestinationFolder="$(M42RootAssembliesDir)"
|
||||||
|
SkipUnchangedFiles="true"
|
||||||
|
Condition="'$(M42RootAssembliesDir)' != '' AND Exists('$(M42_RidlessTargetDir)')" />
|
||||||
|
|
||||||
|
|
||||||
|
<!-- 2) RID copy to BasePackage\Assemblies\<RID>\... -->
|
||||||
|
<Message Text="M42: RID copy → $(M42BasePackageAssembliesDir)$(RuntimeIdentifier)\" Importance="high" />
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<_M42Rid Include="$(TargetDir)**\$(M42AssemblyPattern)" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<MakeDir Directories="$(M42BasePackageAssembliesDir)$(RuntimeIdentifier)"
|
||||||
|
Condition="!Exists('$(M42BasePackageAssembliesDir)$(RuntimeIdentifier)')" />
|
||||||
|
|
||||||
|
<Copy
|
||||||
|
SourceFiles="@(_M42Rid)"
|
||||||
|
DestinationFolder="$(M42BasePackageAssembliesDir)$(RuntimeIdentifier)\%(RecursiveDir)"
|
||||||
|
SkipUnchangedFiles="true" />
|
||||||
|
|
||||||
|
|
||||||
|
<!-- 2b) RID copy to Root\...\<RID>\... -->
|
||||||
|
<Message Text="M42: RID copy to Root → $(M42RootAssembliesDir)$(RuntimeIdentifier)\" Importance="high"
|
||||||
|
Condition="'$(M42RootAssembliesDir)' != ''" />
|
||||||
|
|
||||||
|
<MakeDir Directories="$(M42RootAssembliesDir)$(RuntimeIdentifier)"
|
||||||
|
Condition="'$(M42RootAssembliesDir)' != '' AND !Exists('$(M42RootAssembliesDir)$(RuntimeIdentifier)')" />
|
||||||
|
|
||||||
|
<Copy
|
||||||
|
SourceFiles="@(_M42Rid)"
|
||||||
|
DestinationFolder="$(M42RootAssembliesDir)$(RuntimeIdentifier)\%(RecursiveDir)"
|
||||||
|
SkipUnchangedFiles="true"
|
||||||
|
Condition="'$(M42RootAssembliesDir)' != ''" />
|
||||||
|
|
||||||
|
</Target>
|
||||||
|
|
||||||
|
</Project>
|
||||||
@@ -0,0 +1,232 @@
|
|||||||
|
using Matrix42.Extensions.Scaffolder.Core.ProjectGenerators;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
|
||||||
|
namespace Matrix42.Extensions.Scaffolder.Core;
|
||||||
|
|
||||||
|
public sealed class ExtensionScaffolder : IExtensionScaffolder
|
||||||
|
{
|
||||||
|
private readonly DefaultProjectGenerator _projectGenerator = new();
|
||||||
|
|
||||||
|
public IReadOnlyList<string> Generate(ExtensionScaffoldingOptions options)
|
||||||
|
{
|
||||||
|
if (options is null)
|
||||||
|
throw new ArgumentNullException(nameof(options));
|
||||||
|
|
||||||
|
|
||||||
|
if (string.IsNullOrWhiteSpace(options.ExtensionPath)) throw new ArgumentException("ExtensionPath must be set.", nameof(options));
|
||||||
|
|
||||||
|
if (string.IsNullOrWhiteSpace(options.ExtensionNamespace)) throw new ArgumentException("ExtensionNamespace must be set.", nameof(options));
|
||||||
|
|
||||||
|
if (options.Projects == null) throw new ArgumentException("Projects must be set.", nameof(options));
|
||||||
|
|
||||||
|
var result = new List<string>();
|
||||||
|
|
||||||
|
PrepareRootStructure(options);
|
||||||
|
PrepareBasePackage(options);
|
||||||
|
var solutionDir = PrepareSolutionFolder(options);
|
||||||
|
PrepareRootArtifacts(options);
|
||||||
|
PrepareSolutionFiles(options, solutionDir);
|
||||||
|
|
||||||
|
foreach (var def in options.Projects)
|
||||||
|
{
|
||||||
|
var csprojPath = _projectGenerator.GenerateProject(options, def);
|
||||||
|
result.Add(csprojPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
GenerateSolutionFile(options, solutionDir, result);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void PrepareRootStructure(ExtensionScaffoldingOptions options)
|
||||||
|
{
|
||||||
|
Directory.CreateDirectory(options.ExtensionPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void PrepareBasePackage(ExtensionScaffoldingOptions options)
|
||||||
|
{
|
||||||
|
var basePackageDir = Path.Combine(options.ExtensionPath, "BasePackage");
|
||||||
|
Directory.CreateDirectory(basePackageDir);
|
||||||
|
|
||||||
|
var packageJsonPath = Path.Combine(basePackageDir, "package.json");
|
||||||
|
if (!File.Exists(packageJsonPath))
|
||||||
|
{
|
||||||
|
var json = GetDefaultPackageJson(options);
|
||||||
|
File.WriteAllText(packageJsonPath, json);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates /Solutions/{ns} and returns that path (solution-level folder).
|
||||||
|
/// </summary>
|
||||||
|
private string PrepareSolutionFolder(ExtensionScaffoldingOptions options)
|
||||||
|
{
|
||||||
|
var solutionDir = Path.Combine(options.ExtensionPath, "Solutions", options.ExtensionNamespace);
|
||||||
|
Directory.CreateDirectory(solutionDir);
|
||||||
|
return solutionDir;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void PrepareRootArtifacts(ExtensionScaffoldingOptions options)
|
||||||
|
{
|
||||||
|
/*var azurePath = Path.Combine(options.ExtensionPath, "azure-pipelines-ci.yml");
|
||||||
|
if (!File.Exists(azurePath))
|
||||||
|
{
|
||||||
|
File.WriteAllText(azurePath, Templates.AzurePipelinesYml);
|
||||||
|
}*/
|
||||||
|
|
||||||
|
var azurePath = Path.Combine(options.ExtensionPath, "azure-pipelines-ci.yaml");
|
||||||
|
if (!File.Exists(azurePath))
|
||||||
|
{
|
||||||
|
var repoName = new DirectoryInfo(options.ExtensionPath).Name;
|
||||||
|
|
||||||
|
var content = Templates.GetAzurePiplineCi();
|
||||||
|
var replacedContent = content.Replace("{repoName}", repoName).Replace("{ns}", options.ExtensionNamespace);
|
||||||
|
File.WriteAllText(azurePath, replacedContent);
|
||||||
|
}
|
||||||
|
|
||||||
|
var gitignorePath = Path.Combine(options.ExtensionPath, ".gitignore");
|
||||||
|
if (!File.Exists(gitignorePath))
|
||||||
|
{
|
||||||
|
File.WriteAllText(gitignorePath, Templates.Gitignore);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*var veracodePath = Path.Combine(options.ExtensionPath, "PrepareVeracodeScan.cmd");
|
||||||
|
if (!File.Exists(veracodePath))
|
||||||
|
{
|
||||||
|
var content = Templates.PrepareVeracodeScanCmd.Replace("{ns}", options.ExtensionNamespace);
|
||||||
|
File.WriteAllText(veracodePath, content);
|
||||||
|
}*/
|
||||||
|
|
||||||
|
var targetsPath = Path.Combine(options.ExtensionPath, "Extension.Assemblies.targets");
|
||||||
|
if (!File.Exists(targetsPath))
|
||||||
|
{
|
||||||
|
var content = Templates.GetMatrix42AssembliesTargets();
|
||||||
|
File.WriteAllText(targetsPath, content);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Solution-level files that should live next to the .sln (e.g. BuildEvent.cmd).
|
||||||
|
/// </summary>
|
||||||
|
private void PrepareSolutionFiles(ExtensionScaffoldingOptions options, string solutionDir)
|
||||||
|
{
|
||||||
|
var buildEventPath = Path.Combine(solutionDir, "BuildEvent.cmd");
|
||||||
|
if (!File.Exists(buildEventPath))
|
||||||
|
{
|
||||||
|
var content = Templates.BuildEventCmdTemplate.Replace("{ns}", options.ExtensionNamespace);
|
||||||
|
File.WriteAllText(buildEventPath, content);
|
||||||
|
}
|
||||||
|
|
||||||
|
// If later you want to actually create the .sln here (for console scenario),
|
||||||
|
// this is the right place as well.
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string GetDefaultPackageJson(ExtensionScaffoldingOptions options) =>
|
||||||
|
$@"{{
|
||||||
|
""Id"": ""{options.ExtensionId}"",
|
||||||
|
""Vendor"": ""Not Specified"",
|
||||||
|
""Name"": ""{options.ExtensionNamespace}"",
|
||||||
|
""Version"": ""1.0"",
|
||||||
|
""Prerequisites"": {{
|
||||||
|
""MinimalRequiredProductVersion"": ""26.1.0"",
|
||||||
|
""DependentPackages"": []
|
||||||
|
}},
|
||||||
|
""SetupDirectives"": {{
|
||||||
|
""MaintenanceMode"": false,
|
||||||
|
""RecycleWebApplication"": false,
|
||||||
|
""RestartM42WindowsServices"": false
|
||||||
|
}},
|
||||||
|
""Sandboxed"": true
|
||||||
|
}}";
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates {ns}.sln under solutionDir and adds all csproj files to it.
|
||||||
|
/// </summary>
|
||||||
|
private void GenerateSolutionFile(
|
||||||
|
ExtensionScaffoldingOptions options,
|
||||||
|
string solutionDir,
|
||||||
|
IReadOnlyList<string> projectPaths)
|
||||||
|
{
|
||||||
|
if (projectPaths == null || projectPaths.Count == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var solutionName = options.ExtensionNamespace;
|
||||||
|
var slnPath = Path.Combine(solutionDir, solutionName + ".sln");
|
||||||
|
|
||||||
|
// Basic VS solution header
|
||||||
|
var lines = new List<string>();
|
||||||
|
lines.Add("Microsoft Visual Studio Solution File, Format Version 12.00");
|
||||||
|
lines.Add("# Visual Studio Version 17");
|
||||||
|
lines.Add("VisualStudioVersion = 17.0.31912.275");
|
||||||
|
lines.Add("MinimumVisualStudioVersion = 10.0.40219.1");
|
||||||
|
|
||||||
|
// C# project type GUID
|
||||||
|
const string csProjTypeGuid = "{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}";
|
||||||
|
|
||||||
|
// Collect project GUIDs
|
||||||
|
var projectEntries = new List<Tuple<string, string, string>>();
|
||||||
|
// (projGuid, projName, relativePath)
|
||||||
|
|
||||||
|
foreach (var projPath in projectPaths)
|
||||||
|
{
|
||||||
|
var projName = Path.GetFileNameWithoutExtension(projPath);
|
||||||
|
var relativePath = GetRelativePath(solutionDir, projPath);
|
||||||
|
var projGuid = "{" + Guid.NewGuid().ToString().ToUpperInvariant() + "}";
|
||||||
|
|
||||||
|
projectEntries.Add(Tuple.Create(projGuid, projName, relativePath));
|
||||||
|
|
||||||
|
lines.Add(string.Format(
|
||||||
|
"Project(\"{0}\") = \"{1}\", \"{2}\", \"{3}\"",
|
||||||
|
csProjTypeGuid,
|
||||||
|
projName,
|
||||||
|
relativePath,
|
||||||
|
projGuid));
|
||||||
|
lines.Add("EndProject");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Global section (configs + project configs)
|
||||||
|
lines.Add("Global");
|
||||||
|
lines.Add("\tGlobalSection(SolutionConfigurationPlatforms) = preSolution");
|
||||||
|
lines.Add("\t\tDebug|Any CPU = Debug|Any CPU");
|
||||||
|
lines.Add("\t\tRelease|Any CPU = Release|Any CPU");
|
||||||
|
lines.Add("\tEndGlobalSection");
|
||||||
|
|
||||||
|
lines.Add("\tGlobalSection(ProjectConfigurationPlatforms) = postSolution");
|
||||||
|
foreach (var entry in projectEntries)
|
||||||
|
{
|
||||||
|
var guid = entry.Item1;
|
||||||
|
lines.Add(string.Format("\t\t{0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU", guid));
|
||||||
|
lines.Add(string.Format("\t\t{0}.Debug|Any CPU.Build.0 = Debug|Any CPU", guid));
|
||||||
|
lines.Add(string.Format("\t\t{0}.Release|Any CPU.ActiveCfg = Release|Any CPU", guid));
|
||||||
|
lines.Add(string.Format("\t\t{0}.Release|Any CPU.Build.0 = Release|Any CPU", guid));
|
||||||
|
}
|
||||||
|
lines.Add("\tEndGlobalSection");
|
||||||
|
|
||||||
|
lines.Add("\tGlobalSection(SolutionProperties) = preSolution");
|
||||||
|
lines.Add("\t\tHideSolutionNode = FALSE");
|
||||||
|
lines.Add("\tEndGlobalSection");
|
||||||
|
|
||||||
|
lines.Add("EndGlobal");
|
||||||
|
|
||||||
|
File.WriteAllLines(slnPath, lines);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Simple helper to get relative path from one folder to a file.
|
||||||
|
/// </summary>
|
||||||
|
private static string GetRelativePath(string basePath, string fullPath)
|
||||||
|
{
|
||||||
|
var baseUri = new Uri(AppendDirectorySeparatorChar(basePath));
|
||||||
|
var fullUri = new Uri(fullPath);
|
||||||
|
var relative = baseUri.MakeRelativeUri(fullUri).ToString();
|
||||||
|
|
||||||
|
return relative.Replace('/', Path.DirectorySeparatorChar);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string AppendDirectorySeparatorChar(string path)
|
||||||
|
{
|
||||||
|
return !path.EndsWith(Path.DirectorySeparatorChar.ToString()) ? path + Path.DirectorySeparatorChar : path;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
using Matrix42.Extensions.Scaffolder.Core.Project;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace Matrix42.Extensions.Scaffolder.Core
|
||||||
|
{
|
||||||
|
public sealed class ExtensionScaffoldingOptions
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Absolute path where scaffolding should be created.
|
||||||
|
/// Typically solution directory from VS or some folder from CLI.
|
||||||
|
/// </summary>
|
||||||
|
public string ExtensionPath { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Extension id (Guid) – used in package.json or other metadata.
|
||||||
|
/// </summary>
|
||||||
|
public Guid ExtensionId { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Root namespace, e.g. "Matrix42.MyAwesomeExtension".
|
||||||
|
/// </summary>
|
||||||
|
public string ExtensionNamespace { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Projects to create.
|
||||||
|
/// </summary>
|
||||||
|
public IReadOnlyList<ProjectDefinition> Projects { get; set; } = Array.Empty<ProjectDefinition>();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
using Matrix42.Extensions.Scaffolder.Core.Project;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace Matrix42.Extensions.Scaffolder.Core.Functionality
|
||||||
|
{
|
||||||
|
public interface IProjectFunctionalityDefinition
|
||||||
|
{
|
||||||
|
ProjectFunctionality Kind { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Files to create for this functionality (relative paths, template content).
|
||||||
|
/// </summary>
|
||||||
|
IEnumerable<TemplateFile> GetFiles(ExtensionScaffoldingOptions options, ProjectDefinition project);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// References to add to the csproj.
|
||||||
|
/// </summary>
|
||||||
|
IEnumerable<ProjectReferenceDefinition> GetReferences(ExtensionScaffoldingOptions options, ProjectDefinition project);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,65 @@
|
|||||||
|
using Matrix42.Extensions.Scaffolder.Core.Project;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace Matrix42.Extensions.Scaffolder.Core.Functionality
|
||||||
|
{
|
||||||
|
public sealed class WebApiFunctionalityDefinition : IProjectFunctionalityDefinition
|
||||||
|
{
|
||||||
|
public ProjectFunctionality Kind => ProjectFunctionality.WebApi;
|
||||||
|
|
||||||
|
public IEnumerable<TemplateFile> GetFiles(
|
||||||
|
ExtensionScaffoldingOptions options,
|
||||||
|
ProjectDefinition project)
|
||||||
|
{
|
||||||
|
var ns = options.ExtensionNamespace;
|
||||||
|
|
||||||
|
yield return new TemplateFile
|
||||||
|
{
|
||||||
|
RelativePath = @"Controllers\TestController.cs",
|
||||||
|
Content = WebApi_TestControllerTemplate.Replace("{ns}", ns),
|
||||||
|
CreateIfMissingOnly = true
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public IEnumerable<ProjectReferenceDefinition> GetReferences(ExtensionScaffoldingOptions options, ProjectDefinition project)
|
||||||
|
{
|
||||||
|
yield return new ProjectReferenceDefinition
|
||||||
|
{
|
||||||
|
Include = "Matrix42.WebApi.Contracts",
|
||||||
|
HintPath = @"..\..\..\..\Root\bin\Matrix42.WebApi.Contracts.dll"
|
||||||
|
};
|
||||||
|
|
||||||
|
yield return new ProjectReferenceDefinition
|
||||||
|
{
|
||||||
|
Include = "Matrix42.Hosting.Contracts",
|
||||||
|
HintPath = @"..\..\..\..\Root\bin\Matrix42.Hosting.Contracts.dll"
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private const string WebApi_TestControllerTemplate =
|
||||||
|
@"
|
||||||
|
using Matrix42.WebApi.Contracts;
|
||||||
|
using Matrix42.Hosting.Contracts;
|
||||||
|
|
||||||
|
namespace {ns}.Services
|
||||||
|
{
|
||||||
|
[RoutePrefix(""api/test"")]
|
||||||
|
public class TestController : ApiController
|
||||||
|
{
|
||||||
|
private readonly IDependencyResolver _resolver;
|
||||||
|
|
||||||
|
public TestController(IDependencyResolver resolver)
|
||||||
|
{
|
||||||
|
_resolver = resolver;
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpPost, Route(""test"")]
|
||||||
|
public string TestMethod()
|
||||||
|
{
|
||||||
|
// TODO: implement your test method logic
|
||||||
|
return ""OK"";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}";
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace Matrix42.Extensions.Scaffolder.Core;
|
||||||
|
|
||||||
|
public interface IExtensionScaffolder
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Generates all files/folders according to options and returns the list of generated csproj paths.
|
||||||
|
/// </summary>
|
||||||
|
IReadOnlyList<string> Generate(ExtensionScaffoldingOptions options);
|
||||||
|
}
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>netstandard2.0</TargetFramework>
|
||||||
|
<LangVersion>11.0</LangVersion>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<EmbeddedResource Include="Extension.Assemblies.targets" />
|
||||||
|
<EmbeddedResource Include="azure-pipelines-ci.yaml" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
||||||
@@ -0,0 +1,54 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace Matrix42.Extensions.Scaffolder.Core.Project;
|
||||||
|
|
||||||
|
public class ProjectDefinition
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// E.g. "Services", "BizLogic", etc.
|
||||||
|
/// If empty, project name will be equal to ExtensionNamespace.
|
||||||
|
/// </summary>
|
||||||
|
public string Prefix { get; set; } = string.Empty;
|
||||||
|
|
||||||
|
public RuntimeTargets Runtimes { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Combination of functionality flags: WebApi, Engine, Behavior, Connector, Custom.
|
||||||
|
/// </summary>
|
||||||
|
public ProjectFunctionality Functionality { get; set; } = ProjectFunctionality.None;
|
||||||
|
|
||||||
|
public string Display => $"Prefix: {Prefix} - Runtimes: {Runtimes} - Functionality: {Functionality}";
|
||||||
|
|
||||||
|
public string GetProjectName(string extensionNamespace)
|
||||||
|
{
|
||||||
|
var pfx = Prefix?.Trim();
|
||||||
|
return string.IsNullOrWhiteSpace(pfx)
|
||||||
|
? extensionNamespace
|
||||||
|
: $"{extensionNamespace}.{pfx}";
|
||||||
|
}
|
||||||
|
|
||||||
|
public string GetNamespace(string extensionNamespace) => GetProjectName(extensionNamespace);
|
||||||
|
|
||||||
|
public bool DoesSupportAllRuntimes() => Runtimes.HasFlag(RuntimeTargets.All);
|
||||||
|
|
||||||
|
public string GetRuntimeIdentifiers()
|
||||||
|
{
|
||||||
|
if (DoesSupportAllRuntimes())
|
||||||
|
{
|
||||||
|
return "netstandard2.0";
|
||||||
|
}
|
||||||
|
|
||||||
|
var list = new List<string>();
|
||||||
|
if (Runtimes.HasFlag(RuntimeTargets.Win) || Runtimes.HasFlag(RuntimeTargets.WinCore))
|
||||||
|
{
|
||||||
|
list.Add("win-x64");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Runtimes.HasFlag(RuntimeTargets.LinuxCore))
|
||||||
|
{
|
||||||
|
list.Add("linux-x64");
|
||||||
|
}
|
||||||
|
|
||||||
|
return string.Join(";", list);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace Matrix42.Extensions.Scaffolder.Core.Project;
|
||||||
|
|
||||||
|
[Flags]
|
||||||
|
public enum ProjectFunctionality
|
||||||
|
{
|
||||||
|
None = 0,
|
||||||
|
WebApi = 1,
|
||||||
|
Engine = 2,
|
||||||
|
Behavior = 4,
|
||||||
|
Connector = 8,
|
||||||
|
Custom = 16
|
||||||
|
}
|
||||||
|
|
||||||
|
[Flags]
|
||||||
|
public enum RuntimeTargets
|
||||||
|
{
|
||||||
|
Win = 1,
|
||||||
|
WinCore = 2,
|
||||||
|
LinuxCore = 4,
|
||||||
|
All = 8
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
namespace Matrix42.Extensions.Scaffolder.Core.Project
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Describes a single extra reference to put in the csproj.
|
||||||
|
/// </summary>
|
||||||
|
public sealed class ProjectReferenceDefinition
|
||||||
|
{
|
||||||
|
public string Include { get; set; }
|
||||||
|
public string HintPath { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,200 @@
|
|||||||
|
using Matrix42.Extensions.Scaffolder.Core.Functionality;
|
||||||
|
using Matrix42.Extensions.Scaffolder.Core.Project;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace Matrix42.Extensions.Scaffolder.Core.ProjectGenerators
|
||||||
|
{
|
||||||
|
internal class DefaultProjectGenerator
|
||||||
|
{
|
||||||
|
private readonly IReadOnlyList<IProjectFunctionalityDefinition> _functionalityDefinitions;
|
||||||
|
|
||||||
|
public DefaultProjectGenerator()
|
||||||
|
{
|
||||||
|
_functionalityDefinitions = new IProjectFunctionalityDefinition[]
|
||||||
|
{
|
||||||
|
new WebApiFunctionalityDefinition(),
|
||||||
|
// new EngineFunctionalityDefinition(),
|
||||||
|
// new BehaviorFunctionalityDefinition(),
|
||||||
|
// new ConnectorFunctionalityDefinition(),
|
||||||
|
// new CustomFunctionalityDefinition(),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public string GenerateProject(ExtensionScaffoldingOptions options, ProjectDefinition def)
|
||||||
|
{
|
||||||
|
var ns = options.ExtensionNamespace;
|
||||||
|
var projectName = def.GetProjectName(ns); // e.g. Matrix42.MyExt.Services
|
||||||
|
|
||||||
|
var solutionDir = Path.Combine(options.ExtensionPath, "Solutions", options.ExtensionNamespace);
|
||||||
|
Directory.CreateDirectory(solutionDir);
|
||||||
|
|
||||||
|
var projectDir = Path.Combine(solutionDir, projectName);
|
||||||
|
Directory.CreateDirectory(projectDir);
|
||||||
|
|
||||||
|
var csprojPath = Path.Combine(projectDir, $"{projectName}.csproj");
|
||||||
|
|
||||||
|
GenerateCsproj(csprojPath, def, options, projectName, ns, CollectFunctionalityReferences(options, def));
|
||||||
|
GenerateHostFile(projectDir, projectName);
|
||||||
|
GenerateFiles(projectDir, CollectFunctionalityFiles(options, def));
|
||||||
|
|
||||||
|
return csprojPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
#region Csproj / Host
|
||||||
|
|
||||||
|
protected virtual void GenerateCsproj(
|
||||||
|
string csprojPath,
|
||||||
|
ProjectDefinition def,
|
||||||
|
ExtensionScaffoldingOptions options,
|
||||||
|
string projectName,
|
||||||
|
string rootNamespace,
|
||||||
|
IReadOnlyList<ProjectReferenceDefinition> extraReferences)
|
||||||
|
{
|
||||||
|
var allRuntimes = def.DoesSupportAllRuntimes();
|
||||||
|
|
||||||
|
var tfm = allRuntimes ? def.GetRuntimeIdentifiers() : "net8.0"; // Todo: dynamic based on runtimes
|
||||||
|
var runtimeIds = def.GetRuntimeIdentifiers();
|
||||||
|
|
||||||
|
var anyRids = !allRuntimes && !string.IsNullOrWhiteSpace(runtimeIds);
|
||||||
|
var ridBlock = anyRids ? $"<RuntimeIdentifiers>{runtimeIds}</RuntimeIdentifiers>{Environment.NewLine}" : string.Empty;
|
||||||
|
|
||||||
|
var referencesXml = BuildReferencesXml(extraReferences);
|
||||||
|
|
||||||
|
var content =
|
||||||
|
$@"<Project Sdk=""Microsoft.NET.Sdk"">
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>{tfm}</TargetFramework>
|
||||||
|
<OutputType>Library</OutputType>
|
||||||
|
<RootNamespace>{rootNamespace}</RootNamespace>
|
||||||
|
{ridBlock}
|
||||||
|
<AppendRuntimeIdentifierToOutputPath>true</AppendRuntimeIdentifierToOutputPath>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
<LangVersion>latestmajor</LangVersion>
|
||||||
|
<BasePackageAssembliesDir>$(MSBuildProjectDirectory)\..\..\..\BasePackage\Assemblies\</BasePackageAssembliesDir>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
{referencesXml}
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<M42ExtensionId>{options.ExtensionId}</M42ExtensionId>
|
||||||
|
<M42AssemblyPattern>$(MSBuildProjectName)*.*</M42AssemblyPattern>
|
||||||
|
<M42EnableRidBuild>{anyRids.ToString().ToLowerInvariant()}</M42EnableRidBuild>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<Import Project=""..\..\..\Extension.Assemblies.targets"" Condition=""Exists('..\..\..\Extension.Assemblies.targets')"" />
|
||||||
|
</Project>
|
||||||
|
";
|
||||||
|
|
||||||
|
File.WriteAllText(csprojPath, content);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected virtual void GenerateHostFile(string projectDir, string projectName)
|
||||||
|
{
|
||||||
|
var hostFileName = $"{projectName}.dll.host";
|
||||||
|
var hostPath = Path.Combine(projectDir, hostFileName);
|
||||||
|
|
||||||
|
if (!File.Exists(hostPath))
|
||||||
|
{
|
||||||
|
File.WriteAllText(hostPath, Templates.DefaultHostFileContent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string BuildReferencesXml(IEnumerable<ProjectReferenceDefinition> refs)
|
||||||
|
{
|
||||||
|
var list = refs?.ToList() ?? new List<ProjectReferenceDefinition>();
|
||||||
|
if (list.Count == 0)
|
||||||
|
return string.Empty;
|
||||||
|
|
||||||
|
var sb = new StringBuilder();
|
||||||
|
sb.AppendLine(" <ItemGroup>");
|
||||||
|
|
||||||
|
foreach (var r in list)
|
||||||
|
{
|
||||||
|
sb.AppendLine($@" <Reference Include=""{r.Include}"">");
|
||||||
|
if (!string.IsNullOrWhiteSpace(r.HintPath))
|
||||||
|
{
|
||||||
|
sb.AppendLine($@" <HintPath>{r.HintPath}</HintPath>");
|
||||||
|
}
|
||||||
|
sb.AppendLine(" </Reference>");
|
||||||
|
}
|
||||||
|
|
||||||
|
sb.AppendLine(" </ItemGroup>");
|
||||||
|
return sb.ToString();
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Functionality integration (files + references)
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Collects files to generate from all enabled functionalities.
|
||||||
|
/// </summary>
|
||||||
|
protected virtual IReadOnlyList<TemplateFile> CollectFunctionalityFiles(
|
||||||
|
ExtensionScaffoldingOptions options, ProjectDefinition def)
|
||||||
|
{
|
||||||
|
var result = new List<TemplateFile>();
|
||||||
|
var flags = def.Functionality;
|
||||||
|
|
||||||
|
foreach (var defn in _functionalityDefinitions)
|
||||||
|
{
|
||||||
|
if (!flags.HasFlag(defn.Kind))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
result.AddRange(defn.GetFiles(options, def));
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Collects references to add to csproj from all enabled functionalities.
|
||||||
|
/// </summary>
|
||||||
|
protected virtual IReadOnlyList<ProjectReferenceDefinition> CollectFunctionalityReferences(
|
||||||
|
ExtensionScaffoldingOptions options, ProjectDefinition def)
|
||||||
|
{
|
||||||
|
var result = new List<ProjectReferenceDefinition>();
|
||||||
|
var flags = def.Functionality;
|
||||||
|
|
||||||
|
foreach (var defn in _functionalityDefinitions)
|
||||||
|
{
|
||||||
|
if (!flags.HasFlag(defn.Kind))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
result.AddRange(defn.GetReferences(options, def));
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected virtual void GenerateFiles(string projectDir, IReadOnlyList<TemplateFile> files)
|
||||||
|
{
|
||||||
|
foreach (var file in files)
|
||||||
|
{
|
||||||
|
var targetPath = Path.Combine(projectDir, file.RelativePath);
|
||||||
|
var targetDir = Path.GetDirectoryName(targetPath);
|
||||||
|
if (!string.IsNullOrEmpty(targetDir))
|
||||||
|
{
|
||||||
|
Directory.CreateDirectory(targetDir);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (file.CreateIfMissingOnly && File.Exists(targetPath))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
File.WriteAllText(targetPath, file.Content);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
using Matrix42.Extensions.Scaffolder.Core.Project;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace Matrix42.Extensions.Scaffolder.Core.ProjectGenerators;
|
||||||
|
|
||||||
|
internal interface IProjectGenerator
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Generates the project and returns the path to the created .csproj file.
|
||||||
|
/// </summary>
|
||||||
|
string GenerateProject(ExtensionScaffoldingOptions options, ProjectDefinition def);
|
||||||
|
}
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
namespace Matrix42.Extensions.Scaffolder.Core
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Describes a single file to generate from a template.
|
||||||
|
/// </summary>
|
||||||
|
public sealed class TemplateFile
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Path relative to project folder (for project files)
|
||||||
|
/// or ExtensionPath (for root-level files).
|
||||||
|
/// Example: "Controllers\\TestController.cs" or "BuildEvent.cmd".
|
||||||
|
/// </summary>
|
||||||
|
public string RelativePath { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Template content (with tokens like {ns}, {projectName} etc.).
|
||||||
|
/// </summary>
|
||||||
|
public string Content { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// If true, file is only created if it doesn't exist.
|
||||||
|
/// If false, it will be overwritten.
|
||||||
|
/// </summary>
|
||||||
|
public bool CreateIfMissingOnly { get; set; } = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,91 @@
|
|||||||
|
using System.IO;
|
||||||
|
|
||||||
|
namespace Matrix42.Extensions.Scaffolder.Core
|
||||||
|
{
|
||||||
|
internal static class Templates
|
||||||
|
{
|
||||||
|
public const string Gitignore = @"
|
||||||
|
.idea/
|
||||||
|
.vs/
|
||||||
|
.vscode/
|
||||||
|
node_modules/
|
||||||
|
dist/
|
||||||
|
|
||||||
|
package-lock.json
|
||||||
|
workspace.json
|
||||||
|
|
||||||
|
.vs/
|
||||||
|
.libs/
|
||||||
|
.build/
|
||||||
|
|
||||||
|
bin/
|
||||||
|
obj/
|
||||||
|
|
||||||
|
*.user
|
||||||
|
|
||||||
|
/**/AssemblyInfoProduct.cs
|
||||||
|
/**/_Resharper.Caches
|
||||||
|
/Solutions/*.sln.DotSettings.user
|
||||||
|
/Solutions/**/*.csproj.user
|
||||||
|
/Solutions/**/packages/*.*
|
||||||
|
/Solutions/**/**/AssemblyInfoProduct.cs
|
||||||
|
/Solutions/TestResult/*.*
|
||||||
|
|
||||||
|
BasePackage/Assemblies/
|
||||||
|
";
|
||||||
|
|
||||||
|
public const string PrepareVeracodeScanCmd = @"set arch=""C:\Program Files\7-Zip\7z.exe""
|
||||||
|
echo [*] Building backend archive...
|
||||||
|
%arch% a -tzip -mx5 -x!*.config %Build_ArtifactStagingDirectory%\{ns}.zip %BaseDir%\Solutions\{ns}\.build\*.*
|
||||||
|
";
|
||||||
|
|
||||||
|
public const string DefaultHostFileContent =
|
||||||
|
@"<?xml version=""1.0"" encoding=""utf-8"" ?>
|
||||||
|
<host xmlns=""urn:m42/host.config"">
|
||||||
|
<modules></modules>
|
||||||
|
<sections></sections>
|
||||||
|
</host>
|
||||||
|
";
|
||||||
|
|
||||||
|
public const string BuildEventCmdTemplate =
|
||||||
|
@"call %~dps0..\..\TeamBuildEvent.cmd %1 %2 %3 ""/Solutions/{ns}""";
|
||||||
|
|
||||||
|
internal static string GetMatrix42AssembliesTargets()
|
||||||
|
{
|
||||||
|
var asm = typeof(Templates).Assembly;
|
||||||
|
const string resourceName = "Matrix42.Extensions.Scaffolder.Core.Extension.Assemblies.targets";
|
||||||
|
|
||||||
|
using (var stream = asm.GetManifestResourceStream(resourceName))
|
||||||
|
{
|
||||||
|
if (stream == null)
|
||||||
|
{
|
||||||
|
throw new FileNotFoundException($"Embedded resource '{resourceName}' not found in assembly '{asm.FullName}'.");
|
||||||
|
}
|
||||||
|
|
||||||
|
using (var reader = new StreamReader(stream))
|
||||||
|
{
|
||||||
|
return reader.ReadToEnd();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static string GetAzurePiplineCi()
|
||||||
|
{
|
||||||
|
var asm = typeof(Templates).Assembly;
|
||||||
|
const string resourceName = "Matrix42.Extensions.Scaffolder.Core.azure-pipelines-ci.yaml";
|
||||||
|
|
||||||
|
using (var stream = asm.GetManifestResourceStream(resourceName))
|
||||||
|
{
|
||||||
|
if (stream == null)
|
||||||
|
{
|
||||||
|
throw new FileNotFoundException($"Embedded resource '{resourceName}' not found in assembly '{asm.FullName}'.");
|
||||||
|
}
|
||||||
|
|
||||||
|
using (var reader = new StreamReader(stream))
|
||||||
|
{
|
||||||
|
return reader.ReadToEnd();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,123 @@
|
|||||||
|
# azure-pipelines.yml
|
||||||
|
pr: none
|
||||||
|
|
||||||
|
trigger:
|
||||||
|
branches:
|
||||||
|
include:
|
||||||
|
- release_26_1_0
|
||||||
|
paths:
|
||||||
|
include:
|
||||||
|
- 'Solutions/**'
|
||||||
|
|
||||||
|
parameters:
|
||||||
|
- name: BaseDir
|
||||||
|
type: string
|
||||||
|
default: $(Build.SourcesDirectory)
|
||||||
|
|
||||||
|
- name: SuiteRarShare
|
||||||
|
type: string
|
||||||
|
default: '\\m42-sto-ffm01.matrix42.de\ServiceStore\Builds\TitanLinux Continuous'
|
||||||
|
|
||||||
|
- name: RepoName
|
||||||
|
type: string
|
||||||
|
default: '{repoName}'
|
||||||
|
|
||||||
|
- name: SolutionName
|
||||||
|
type: string
|
||||||
|
default: '{ns}'
|
||||||
|
|
||||||
|
variables:
|
||||||
|
- name: BaseDir
|
||||||
|
value: ${{ parameters.BaseDir }}
|
||||||
|
|
||||||
|
- name: ExtensionTarget
|
||||||
|
value: ${{ parameters.BaseDir }}/${{ parameters.RepoName }}
|
||||||
|
|
||||||
|
- name: SolutionDir
|
||||||
|
value: $(ExtensionTarget)/Solutions/{ns}
|
||||||
|
|
||||||
|
- name: SolutionPath
|
||||||
|
value: $(SolutionDir)/{ns}.sln
|
||||||
|
|
||||||
|
# Tests
|
||||||
|
- name: TestsDir
|
||||||
|
value: $(SolutionDir)
|
||||||
|
- name: TestProject
|
||||||
|
value: '{ns}.Tests/{ns}.Tests.csproj'
|
||||||
|
|
||||||
|
stages:
|
||||||
|
- stage: Build
|
||||||
|
displayName: 'Build ${{ parameters.RepoName }}'
|
||||||
|
jobs:
|
||||||
|
- job: Build_Backend
|
||||||
|
displayName: 'Build, Test, Package'
|
||||||
|
pool:
|
||||||
|
name: M42BPM
|
||||||
|
demands:
|
||||||
|
- DotNetFramework
|
||||||
|
- vstest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- task: CopyFiles@2
|
||||||
|
displayName: 'Copy extension $(ExtensionTarget) source files'
|
||||||
|
inputs:
|
||||||
|
SourceFolder: '${{ parameters.BaseDir }}'
|
||||||
|
Contents: '**'
|
||||||
|
TargetFolder: '$(ExtensionTarget)'
|
||||||
|
|
||||||
|
- task: CopyFiles@2
|
||||||
|
displayName: 'Copy suite.rar'
|
||||||
|
inputs:
|
||||||
|
SourceFolder: '${{ parameters.SuiteRarShare }}'
|
||||||
|
Contents: 'suite.rar'
|
||||||
|
TargetFolder: '${{ parameters.BaseDir }}'
|
||||||
|
OverWrite: true
|
||||||
|
|
||||||
|
- task: ExtractFiles@1
|
||||||
|
displayName: 'Extract suite.rar'
|
||||||
|
inputs:
|
||||||
|
archiveFilePatterns: '${{ parameters.BaseDir }}/suite.rar'
|
||||||
|
destinationFolder: '${{ parameters.BaseDir }}'
|
||||||
|
cleanDestinationFolder: false
|
||||||
|
overwriteExistingFiles: true
|
||||||
|
|
||||||
|
- task: DotNetCoreCLI@2
|
||||||
|
displayName: 'Restore $(ExtensionTarget) solution'
|
||||||
|
inputs:
|
||||||
|
command: 'restore'
|
||||||
|
projects: '$(SolutionPath)'
|
||||||
|
|
||||||
|
# Optional: override default RIDs globally if needed: -p:M42DefaultRids=win-x64;linux-x64
|
||||||
|
- task: DotNetCoreCLI@2
|
||||||
|
displayName: 'Build {ns} solution'
|
||||||
|
inputs:
|
||||||
|
command: 'build'
|
||||||
|
projects: '$(SolutionPath)'
|
||||||
|
arguments: >
|
||||||
|
-c Release
|
||||||
|
--no-restore
|
||||||
|
-p:SolutionDir=$(SolutionDir)\
|
||||||
|
-p:M42BuildAllRidsOnCI=true
|
||||||
|
|
||||||
|
- task: DotNetCoreCLI@2
|
||||||
|
displayName: 'Test (net8.0)'
|
||||||
|
inputs:
|
||||||
|
command: 'test'
|
||||||
|
projects: '$(TestsDir)/$(TestProject)'
|
||||||
|
arguments: '-c Release -f net8.0 --no-build'
|
||||||
|
|
||||||
|
- task: ArchiveFiles@2
|
||||||
|
displayName: 'Zip $(ExtensionTarget) BasePackage'
|
||||||
|
inputs:
|
||||||
|
rootFolderOrFile: '$(ExtensionTarget)/BasePackage'
|
||||||
|
includeRootFolder: false
|
||||||
|
archiveType: 'zip'
|
||||||
|
sevenZipCompression: 'normal'
|
||||||
|
archiveFile: '$(Build.ArtifactStagingDirectory)/${{ parameters.RepoName }}_1.0.zip'
|
||||||
|
replaceExistingArchive: true
|
||||||
|
|
||||||
|
- task: PublishPipelineArtifact@1
|
||||||
|
displayName: 'Publish ${{ parameters.RepoName }}_1.0.zip'
|
||||||
|
inputs:
|
||||||
|
targetPath: '$(Build.ArtifactStagingDirectory)/${{ parameters.RepoName }}_1.0.zip'
|
||||||
|
artifact: '${{ parameters.RepoName }}'
|
||||||
@@ -0,0 +1,91 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project ToolsVersion="15.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
|
<PropertyGroup>
|
||||||
|
<MinimumVisualStudioVersion>17.0</MinimumVisualStudioVersion>
|
||||||
|
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
|
||||||
|
</PropertyGroup>
|
||||||
|
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||||
|
<PropertyGroup>
|
||||||
|
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||||
|
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||||
|
<SchemaVersion>2.0</SchemaVersion>
|
||||||
|
<ProjectTypeGuids>{82b43b9b-a64c-4715-b499-d71e9ca2bd60};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
|
||||||
|
<ProjectGuid>{50F8DCAA-48B9-47D5-ABB8-F8D33BEF1BD1}</ProjectGuid>
|
||||||
|
<OutputType>Library</OutputType>
|
||||||
|
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||||
|
<RootNamespace>Matrix42.Extensions.Scaffolder.Vsix</RootNamespace>
|
||||||
|
<AssemblyName>Matrix42.Extensions.Scaffolder.Vsix</AssemblyName>
|
||||||
|
<TargetFrameworkVersion>v4.7.2</TargetFrameworkVersion>
|
||||||
|
<GeneratePkgDefFile>true</GeneratePkgDefFile>
|
||||||
|
<UseCodebase>true</UseCodebase>
|
||||||
|
<IncludeAssemblyInVSIXContainer>true</IncludeAssemblyInVSIXContainer>
|
||||||
|
<IncludeDebugSymbolsInVSIXContainer>false</IncludeDebugSymbolsInVSIXContainer>
|
||||||
|
<IncludeDebugSymbolsInLocalVSIXDeployment>false</IncludeDebugSymbolsInLocalVSIXDeployment>
|
||||||
|
<CopyBuildOutputToOutputDirectory>true</CopyBuildOutputToOutputDirectory>
|
||||||
|
<CopyOutputSymbolsToOutputDirectory>true</CopyOutputSymbolsToOutputDirectory>
|
||||||
|
<StartAction>Program</StartAction>
|
||||||
|
<StartProgram Condition="'$(DevEnvDir)' != ''">$(DevEnvDir)devenv.exe</StartProgram>
|
||||||
|
<StartArguments>/rootsuffix Exp</StartArguments>
|
||||||
|
<GeneratePkgDefFile>false</GeneratePkgDefFile>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||||
|
<DebugSymbols>true</DebugSymbols>
|
||||||
|
<DebugType>full</DebugType>
|
||||||
|
<Optimize>false</Optimize>
|
||||||
|
<OutputPath>bin\Debug\</OutputPath>
|
||||||
|
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||||
|
<ErrorReport>prompt</ErrorReport>
|
||||||
|
<WarningLevel>4</WarningLevel>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||||
|
<DebugType>pdbonly</DebugType>
|
||||||
|
<Optimize>true</Optimize>
|
||||||
|
<OutputPath>bin\Release\</OutputPath>
|
||||||
|
<DefineConstants>TRACE</DefineConstants>
|
||||||
|
<ErrorReport>prompt</ErrorReport>
|
||||||
|
<WarningLevel>4</WarningLevel>
|
||||||
|
</PropertyGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||||
|
<Compile Include="Wizard\ExtensionProjectsWizard.cs" />
|
||||||
|
<Compile Include="Wizard\ProjectDefinition.cs" />
|
||||||
|
<Compile Include="Wizard\RuntimeTargets.cs" />
|
||||||
|
<Compile Include="Wizard\WizardForm.cs">
|
||||||
|
<SubType>Form</SubType>
|
||||||
|
</Compile>
|
||||||
|
<Compile Include="Wizard\WizardForm.Designer.cs">
|
||||||
|
<DependentUpon>WizardForm.cs</DependentUpon>
|
||||||
|
</Compile>
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<None Include="ProjectTemplates\Directory.Build.props.template" />
|
||||||
|
<None Include="ProjectTemplates\Placeholder.csproj" />
|
||||||
|
<None Include="source.extension.vsixmanifest">
|
||||||
|
<SubType>Designer</SubType>
|
||||||
|
</None>
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Reference Include="System" />
|
||||||
|
<Reference Include="System.Drawing" />
|
||||||
|
<Reference Include="System.Windows.Forms" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Microsoft.VisualStudio.SDK" Version="17.0.32112.339" ExcludeAssets="runtime" NoWarn="NU1604" />
|
||||||
|
<PackageReference Include="Microsoft.VisualStudio.TemplateWizardInterface">
|
||||||
|
<Version>17.10.40170</Version>
|
||||||
|
</PackageReference>
|
||||||
|
<PackageReference Include="Microsoft.VSSDK.BuildTools" Version="17.14.2096" NoWarn="NU1604" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Content Include="ProjectTemplates\ExtensionSolution.vstemplate" />
|
||||||
|
</ItemGroup>
|
||||||
|
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||||
|
<Import Project="$(VSToolsPath)\VSSDK\Microsoft.VsSDK.targets" Condition="'$(VSToolsPath)' != ''" />
|
||||||
|
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||||
|
Other similar extension points exist, see Microsoft.Common.targets.
|
||||||
|
<Target Name="BeforeBuild">
|
||||||
|
</Target>
|
||||||
|
<Target Name="AfterBuild">
|
||||||
|
</Target>
|
||||||
|
-->
|
||||||
|
</Project>
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
|
||||||
|
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||||
|
# Visual Studio Version 17
|
||||||
|
VisualStudioVersion = 17.14.36310.24 d17.14
|
||||||
|
MinimumVisualStudioVersion = 10.0.40219.1
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Matrix42.Extensions.Scaffolder.Vsix", "Matrix42.Extensions.Scaffolder.Vsix.csproj", "{50F8DCAA-48B9-47D5-ABB8-F8D33BEF1BD1}"
|
||||||
|
EndProject
|
||||||
|
Global
|
||||||
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
|
Debug|Any CPU = Debug|Any CPU
|
||||||
|
Debug|arm64 = Debug|arm64
|
||||||
|
Debug|x86 = Debug|x86
|
||||||
|
Release|Any CPU = Release|Any CPU
|
||||||
|
Release|arm64 = Release|arm64
|
||||||
|
Release|x86 = Release|x86
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||||
|
{50F8DCAA-48B9-47D5-ABB8-F8D33BEF1BD1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{50F8DCAA-48B9-47D5-ABB8-F8D33BEF1BD1}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{50F8DCAA-48B9-47D5-ABB8-F8D33BEF1BD1}.Debug|arm64.ActiveCfg = Debug|arm64
|
||||||
|
{50F8DCAA-48B9-47D5-ABB8-F8D33BEF1BD1}.Debug|arm64.Build.0 = Debug|arm64
|
||||||
|
{50F8DCAA-48B9-47D5-ABB8-F8D33BEF1BD1}.Debug|x86.ActiveCfg = Debug|x86
|
||||||
|
{50F8DCAA-48B9-47D5-ABB8-F8D33BEF1BD1}.Debug|x86.Build.0 = Debug|x86
|
||||||
|
{50F8DCAA-48B9-47D5-ABB8-F8D33BEF1BD1}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{50F8DCAA-48B9-47D5-ABB8-F8D33BEF1BD1}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{50F8DCAA-48B9-47D5-ABB8-F8D33BEF1BD1}.Release|arm64.ActiveCfg = Release|arm64
|
||||||
|
{50F8DCAA-48B9-47D5-ABB8-F8D33BEF1BD1}.Release|arm64.Build.0 = Release|arm64
|
||||||
|
{50F8DCAA-48B9-47D5-ABB8-F8D33BEF1BD1}.Release|x86.ActiveCfg = Release|x86
|
||||||
|
{50F8DCAA-48B9-47D5-ABB8-F8D33BEF1BD1}.Release|x86.Build.0 = Release|x86
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
|
HideSolutionNode = FALSE
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||||
|
SolutionGuid = {ECBF8D8B-3FBE-4CDA-BE52-C37D76054B09}
|
||||||
|
EndGlobalSection
|
||||||
|
EndGlobal
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
<Project>
|
||||||
|
<PropertyGroup>
|
||||||
|
<LangVersion>latest</LangVersion>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
</PropertyGroup>
|
||||||
|
</Project>
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
<VSTemplate Version="3.0.0" Type="Project">
|
||||||
|
<TemplateData>
|
||||||
|
<Name>Matrix42 Extension Solution</Name>
|
||||||
|
<Description>Create a new Matrix42 extension solution (WebApi / Contracts / BizLogic / Custom) using Matrix42.Extensions.SDK.</Description>
|
||||||
|
<ProjectType>CSharp</ProjectType>
|
||||||
|
<SortOrder>1000</SortOrder>
|
||||||
|
<DefaultName>Matrix42.Extension</DefaultName>
|
||||||
|
<CreateNewFolder>true</CreateNewFolder>
|
||||||
|
<ProvideDefaultName>true</ProvideDefaultName>
|
||||||
|
<LocationField>Enabled</LocationField>
|
||||||
|
</TemplateData>
|
||||||
|
|
||||||
|
<TemplateContent>
|
||||||
|
<Project File="Placeholder.csproj" ReplaceParameters="true" TargetFileName="$safeprojectname$.csproj" />
|
||||||
|
</TemplateContent>
|
||||||
|
|
||||||
|
<WizardExtension>
|
||||||
|
<Assembly>Matrix42.Extensions.Scaffolder.Vsix, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null</Assembly>
|
||||||
|
<FullClassName>Matrix42.Extensions.Scaffolder.Wizard.ExtensionProjectsWizard</FullClassName>
|
||||||
|
</WizardExtension>
|
||||||
|
</VSTemplate>
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
|
<OutputType>Library</OutputType>
|
||||||
|
</PropertyGroup>
|
||||||
|
</Project>
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
using System.Reflection;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
// General Information about an assembly is controlled through the following
|
||||||
|
// set of attributes. Change these attribute values to modify the information
|
||||||
|
// associated with an assembly.
|
||||||
|
[assembly: AssemblyTitle("Matrix42.Extensions.Scaffolder.Vsix")]
|
||||||
|
[assembly: AssemblyDescription("")]
|
||||||
|
[assembly: AssemblyConfiguration("")]
|
||||||
|
[assembly: AssemblyCompany("")]
|
||||||
|
[assembly: AssemblyProduct("Matrix42.Extensions.Scaffolder.Vsix")]
|
||||||
|
[assembly: AssemblyCopyright("")]
|
||||||
|
[assembly: AssemblyTrademark("")]
|
||||||
|
[assembly: AssemblyCulture("")]
|
||||||
|
|
||||||
|
// Setting ComVisible to false makes the types in this assembly not visible
|
||||||
|
// to COM components. If you need to access a type in this assembly from
|
||||||
|
// COM, set the ComVisible attribute to true on that type.
|
||||||
|
[assembly: ComVisible(false)]
|
||||||
|
|
||||||
|
// Version information for an assembly consists of the following four values:
|
||||||
|
//
|
||||||
|
// Major Version
|
||||||
|
// Minor Version
|
||||||
|
// Build Number
|
||||||
|
// Revision
|
||||||
|
//
|
||||||
|
// You can specify all the values or you can default the Build and Revision Numbers
|
||||||
|
// by using the '*' as shown below:
|
||||||
|
// [assembly: AssemblyVersion("1.0.*")]
|
||||||
|
[assembly: AssemblyVersion("1.0.0.0")]
|
||||||
|
[assembly: AssemblyFileVersion("1.0.0.0")]
|
||||||
@@ -0,0 +1,231 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using EnvDTE;
|
||||||
|
using EnvDTE80;
|
||||||
|
using Microsoft.VisualStudio.TemplateWizard;
|
||||||
|
|
||||||
|
namespace Matrix42.Extensions.Scaffolder.Wizard
|
||||||
|
{
|
||||||
|
public class ExtensionProjectsWizard : IWizard
|
||||||
|
{
|
||||||
|
private DTE2 _dte;
|
||||||
|
private Project _placeholderProject;
|
||||||
|
private string _extensionNamespace = string.Empty;
|
||||||
|
private List<ProjectDefinition> _projects = new List<ProjectDefinition>();
|
||||||
|
private string _solutionDirectory = string.Empty;
|
||||||
|
|
||||||
|
public void RunStarted(
|
||||||
|
object automationObject,
|
||||||
|
Dictionary<string, string> replacementsDictionary,
|
||||||
|
WizardRunKind runKind,
|
||||||
|
object[] customParams)
|
||||||
|
{
|
||||||
|
_dte = automationObject as DTE2
|
||||||
|
?? throw new InvalidOperationException("DTE2 not available.");
|
||||||
|
|
||||||
|
using (var form = new WizardForm())
|
||||||
|
{
|
||||||
|
var result = form.ShowDialog();
|
||||||
|
if (result != System.Windows.Forms.DialogResult.OK)
|
||||||
|
throw new WizardBackoutException();
|
||||||
|
|
||||||
|
_extensionNamespace = form.ExtensionNamespace;
|
||||||
|
_projects = new List<ProjectDefinition>(form.Projects);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 🔹 This is the method that was missing
|
||||||
|
public void BeforeOpeningFile(ProjectItem projectItem)
|
||||||
|
{
|
||||||
|
// We don't need to do anything before a file is opened.
|
||||||
|
// Leave empty on purpose.
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ProjectFinishedGenerating(Project project)
|
||||||
|
{
|
||||||
|
_placeholderProject = project;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ProjectItemFinishedGenerating(ProjectItem projectItem)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public void RunFinished()
|
||||||
|
{
|
||||||
|
var solution = _dte.Solution;
|
||||||
|
_solutionDirectory = Path.GetDirectoryName(solution.FullName);
|
||||||
|
|
||||||
|
if (string.IsNullOrEmpty(_solutionDirectory))
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Remove placeholder project from solution and disk
|
||||||
|
if (_placeholderProject != null)
|
||||||
|
{
|
||||||
|
var placeholderPath = _placeholderProject.FullName;
|
||||||
|
solution.Remove(_placeholderProject);
|
||||||
|
TryDeleteDirectorySafe(Path.GetDirectoryName(placeholderPath));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Drop Directory.Build.props
|
||||||
|
var propsTemplatePath = Path.Combine(
|
||||||
|
GetExtensionInstallPath(),
|
||||||
|
"ProjectTemplates",
|
||||||
|
"Directory.Build.props.template");
|
||||||
|
|
||||||
|
if (File.Exists(propsTemplatePath))
|
||||||
|
{
|
||||||
|
var destProps = Path.Combine(_solutionDirectory, "Directory.Build.props");
|
||||||
|
if (!File.Exists(destProps))
|
||||||
|
File.Copy(propsTemplatePath, destProps, overwrite: false);
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var proj in _projects)
|
||||||
|
{
|
||||||
|
CreateProjectFromDefinition(solution, proj);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool ShouldAddProjectItem(string filePath) => true;
|
||||||
|
|
||||||
|
private void CreateProjectFromDefinition(Solution solution, ProjectDefinition def)
|
||||||
|
{
|
||||||
|
var projectName = def.GetProjectName(_extensionNamespace);
|
||||||
|
var projectNamespace = def.GetNamespace(_extensionNamespace);
|
||||||
|
var projectDir = Path.Combine(_solutionDirectory, projectName);
|
||||||
|
|
||||||
|
Directory.CreateDirectory(projectDir);
|
||||||
|
|
||||||
|
var csprojPath = Path.Combine(projectDir, projectName + ".csproj");
|
||||||
|
var runtimeIds = def.GetRuntimeIdentifiers();
|
||||||
|
var tfm = "net8.0"; // default target framework
|
||||||
|
|
||||||
|
var csprojContent = GenerateCsproj(def.Type, tfm, runtimeIds, projectNamespace);
|
||||||
|
File.WriteAllText(csprojPath, csprojContent);
|
||||||
|
|
||||||
|
var codeFilePath = Path.Combine(
|
||||||
|
projectDir,
|
||||||
|
def.Type == ProjectType.WebApi ? "Program.cs" : "Class1.cs");
|
||||||
|
|
||||||
|
var codeContent = GenerateCodeFile(def.Type, projectNamespace);
|
||||||
|
File.WriteAllText(codeFilePath, codeContent);
|
||||||
|
|
||||||
|
solution.AddFromFile(csprojPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
private string GenerateCsproj(
|
||||||
|
ProjectType type,
|
||||||
|
string tfm,
|
||||||
|
string runtimeIds,
|
||||||
|
string rootNamespace)
|
||||||
|
{
|
||||||
|
var outputType = type == ProjectType.WebApi ? "Exe" : "Library";
|
||||||
|
var sdk = type == ProjectType.WebApi ? "Microsoft.NET.Sdk.Web" : "Microsoft.NET.Sdk";
|
||||||
|
|
||||||
|
var ridBlock = string.IsNullOrWhiteSpace(runtimeIds)
|
||||||
|
? string.Empty
|
||||||
|
: $" <RuntimeIdentifiers>{runtimeIds}</RuntimeIdentifiers>{Environment.NewLine}";
|
||||||
|
|
||||||
|
return
|
||||||
|
$@"<Project Sdk=""{sdk}"">
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>{tfm}</TargetFramework>
|
||||||
|
<OutputType>{outputType}</OutputType>
|
||||||
|
<RootNamespace>{rootNamespace}</RootNamespace>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
{ridBlock} </PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include=""Matrix42.Extensions.SDK"" Version=""1.0.0"" />
|
||||||
|
</ItemGroup>
|
||||||
|
</Project>
|
||||||
|
";
|
||||||
|
}
|
||||||
|
|
||||||
|
private string GenerateCodeFile(ProjectType type, string ns)
|
||||||
|
{
|
||||||
|
switch (type)
|
||||||
|
{
|
||||||
|
case ProjectType.WebApi:
|
||||||
|
return
|
||||||
|
$@"using Microsoft.AspNetCore.Builder;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
using Microsoft.Extensions.Hosting;
|
||||||
|
using Matrix42.Extensions.SDK;
|
||||||
|
|
||||||
|
namespace {ns}
|
||||||
|
{{
|
||||||
|
public class Program
|
||||||
|
{{
|
||||||
|
public static void Main(string[] args)
|
||||||
|
{{
|
||||||
|
var builder = WebApplication.CreateBuilder(args);
|
||||||
|
|
||||||
|
builder.Services.AddControllers();
|
||||||
|
// TODO: configure Matrix42.Extensions.SDK services
|
||||||
|
|
||||||
|
var app = builder.Build();
|
||||||
|
app.MapControllers();
|
||||||
|
|
||||||
|
app.Run();
|
||||||
|
}}
|
||||||
|
}}
|
||||||
|
}}";
|
||||||
|
case ProjectType.Contracts:
|
||||||
|
return
|
||||||
|
$@"namespace {ns}
|
||||||
|
{{
|
||||||
|
// Place your contracts (DTOs, interfaces) here
|
||||||
|
public class SampleContract
|
||||||
|
{{
|
||||||
|
public string Id {{ get; set; }} = string.Empty;
|
||||||
|
}}
|
||||||
|
}}";
|
||||||
|
case ProjectType.BizLogic:
|
||||||
|
return
|
||||||
|
$@"using Matrix42.Extensions.SDK;
|
||||||
|
|
||||||
|
namespace {ns}
|
||||||
|
{{
|
||||||
|
// Place your business logic services here
|
||||||
|
public class SampleService
|
||||||
|
{{
|
||||||
|
public string SayHello() => ""Hello from {ns}"";
|
||||||
|
}}
|
||||||
|
}}";
|
||||||
|
case ProjectType.Custom:
|
||||||
|
default:
|
||||||
|
return
|
||||||
|
$@"namespace {ns}
|
||||||
|
{{
|
||||||
|
// Custom project for your extension
|
||||||
|
public class CustomEntry
|
||||||
|
{{
|
||||||
|
public string Name {{ get; set; }} = ""Custom"";
|
||||||
|
}}
|
||||||
|
}}";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private string GetExtensionInstallPath()
|
||||||
|
{
|
||||||
|
var asmPath = typeof(ExtensionProjectsWizard).Assembly.Location;
|
||||||
|
return Path.GetDirectoryName(asmPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void TryDeleteDirectorySafe(string path)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (!string.IsNullOrWhiteSpace(path) && Directory.Exists(path))
|
||||||
|
Directory.Delete(path, recursive: true);
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
// ignore
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,66 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace Matrix42.Extensions.Scaffolder.Wizard
|
||||||
|
{
|
||||||
|
public enum ProjectType
|
||||||
|
{
|
||||||
|
WebApi,
|
||||||
|
Contracts,
|
||||||
|
BizLogic,
|
||||||
|
Custom
|
||||||
|
}
|
||||||
|
|
||||||
|
public class ProjectDefinition
|
||||||
|
{
|
||||||
|
public ProjectType Type { get; set; }
|
||||||
|
public string Prefix { get; set; } = string.Empty; // custom for Custom type, otherwise derived
|
||||||
|
public RuntimeTargets Runtimes { get; set; }
|
||||||
|
|
||||||
|
public string EffectivePrefix
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (Type == ProjectType.Custom)
|
||||||
|
return Prefix;
|
||||||
|
|
||||||
|
switch (Type)
|
||||||
|
{
|
||||||
|
case ProjectType.WebApi:
|
||||||
|
return string.IsNullOrWhiteSpace(Prefix) ? "Services" : Prefix;
|
||||||
|
case ProjectType.Contracts:
|
||||||
|
return string.IsNullOrWhiteSpace(Prefix) ? "Contracts" : Prefix;
|
||||||
|
case ProjectType.BizLogic:
|
||||||
|
return string.IsNullOrWhiteSpace(Prefix) ? "BizLogic" : Prefix;
|
||||||
|
default:
|
||||||
|
return Prefix;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public string Display => $"{Type} - Prefix: {EffectivePrefix} - Runtimes: {Runtimes}";
|
||||||
|
|
||||||
|
public string GetProjectName(string extensionNamespace)
|
||||||
|
{
|
||||||
|
var pfx = EffectivePrefix?.Trim();
|
||||||
|
return string.IsNullOrWhiteSpace(pfx)
|
||||||
|
? extensionNamespace
|
||||||
|
: $"{extensionNamespace}.{pfx}";
|
||||||
|
}
|
||||||
|
|
||||||
|
public string GetNamespace(string extensionNamespace) => GetProjectName(extensionNamespace);
|
||||||
|
|
||||||
|
public string GetRuntimeIdentifiers()
|
||||||
|
{
|
||||||
|
if (Runtimes.HasFlag(RuntimeTargets.All))
|
||||||
|
return "win-x64;linux-x64";
|
||||||
|
|
||||||
|
var list = new List<string>();
|
||||||
|
if (Runtimes.HasFlag(RuntimeTargets.Win) || Runtimes.HasFlag(RuntimeTargets.WinCore))
|
||||||
|
list.Add("win-x64");
|
||||||
|
if (Runtimes.HasFlag(RuntimeTargets.LinuxCore))
|
||||||
|
list.Add("linux-x64");
|
||||||
|
|
||||||
|
return string.Join(";", list);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
namespace Matrix42.Extensions.Scaffolder.Wizard
|
||||||
|
{
|
||||||
|
[System.Flags]
|
||||||
|
public enum RuntimeTargets
|
||||||
|
{
|
||||||
|
None = 0,
|
||||||
|
Win = 1,
|
||||||
|
WinCore = 2,
|
||||||
|
LinuxCore = 4,
|
||||||
|
All = 8
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,236 @@
|
|||||||
|
namespace Matrix42.Extensions.Scaffolder.Wizard
|
||||||
|
{
|
||||||
|
partial class WizardForm
|
||||||
|
{
|
||||||
|
private System.ComponentModel.IContainer components = null;
|
||||||
|
|
||||||
|
private System.Windows.Forms.Label lblTitle;
|
||||||
|
private System.Windows.Forms.Label lblExtensionNamespace;
|
||||||
|
private System.Windows.Forms.TextBox txtExtensionNamespace;
|
||||||
|
private System.Windows.Forms.Label lblHint;
|
||||||
|
private System.Windows.Forms.Label lblAddProjects;
|
||||||
|
private System.Windows.Forms.Label lblProjectType;
|
||||||
|
private System.Windows.Forms.ComboBox cboProjectType;
|
||||||
|
private System.Windows.Forms.Label lblProjectPrefix;
|
||||||
|
private System.Windows.Forms.TextBox txtProjectPrefix;
|
||||||
|
private System.Windows.Forms.Label lblRuntimes;
|
||||||
|
private System.Windows.Forms.CheckedListBox clbRuntimes;
|
||||||
|
private System.Windows.Forms.Button btnAddProject;
|
||||||
|
private System.Windows.Forms.ListBox lstProjects;
|
||||||
|
private System.Windows.Forms.Button btnRemoveSelected;
|
||||||
|
private System.Windows.Forms.Button btnOK;
|
||||||
|
private System.Windows.Forms.Button btnCancel;
|
||||||
|
|
||||||
|
protected override void Dispose(bool disposing)
|
||||||
|
{
|
||||||
|
if (disposing && (components != null))
|
||||||
|
components.Dispose();
|
||||||
|
base.Dispose(disposing);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void InitializeComponent()
|
||||||
|
{
|
||||||
|
this.lblTitle = new System.Windows.Forms.Label();
|
||||||
|
this.lblExtensionNamespace = new System.Windows.Forms.Label();
|
||||||
|
this.txtExtensionNamespace = new System.Windows.Forms.TextBox();
|
||||||
|
this.lblHint = new System.Windows.Forms.Label();
|
||||||
|
this.lblAddProjects = new System.Windows.Forms.Label();
|
||||||
|
this.lblProjectType = new System.Windows.Forms.Label();
|
||||||
|
this.cboProjectType = new System.Windows.Forms.ComboBox();
|
||||||
|
this.lblProjectPrefix = new System.Windows.Forms.Label();
|
||||||
|
this.txtProjectPrefix = new System.Windows.Forms.TextBox();
|
||||||
|
this.lblRuntimes = new System.Windows.Forms.Label();
|
||||||
|
this.clbRuntimes = new System.Windows.Forms.CheckedListBox();
|
||||||
|
this.btnAddProject = new System.Windows.Forms.Button();
|
||||||
|
this.lstProjects = new System.Windows.Forms.ListBox();
|
||||||
|
this.btnRemoveSelected = new System.Windows.Forms.Button();
|
||||||
|
this.btnOK = new System.Windows.Forms.Button();
|
||||||
|
this.btnCancel = new System.Windows.Forms.Button();
|
||||||
|
this.SuspendLayout();
|
||||||
|
//
|
||||||
|
// lblTitle
|
||||||
|
//
|
||||||
|
this.lblTitle.AutoSize = true;
|
||||||
|
this.lblTitle.Font = new System.Drawing.Font("Segoe UI", 11F, System.Drawing.FontStyle.Bold);
|
||||||
|
this.lblTitle.Location = new System.Drawing.Point(12, 9);
|
||||||
|
this.lblTitle.Name = "lblTitle";
|
||||||
|
this.lblTitle.Size = new System.Drawing.Size(120, 20);
|
||||||
|
this.lblTitle.TabIndex = 0;
|
||||||
|
this.lblTitle.Text = "Projects Wizard";
|
||||||
|
//
|
||||||
|
// lblExtensionNamespace
|
||||||
|
//
|
||||||
|
this.lblExtensionNamespace.AutoSize = true;
|
||||||
|
this.lblExtensionNamespace.Location = new System.Drawing.Point(13, 44);
|
||||||
|
this.lblExtensionNamespace.Name = "lblExtensionNamespace";
|
||||||
|
this.lblExtensionNamespace.Size = new System.Drawing.Size(113, 15);
|
||||||
|
this.lblExtensionNamespace.TabIndex = 1;
|
||||||
|
this.lblExtensionNamespace.Text = "Extension Namespace";
|
||||||
|
//
|
||||||
|
// txtExtensionNamespace
|
||||||
|
//
|
||||||
|
this.txtExtensionNamespace.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
|
||||||
|
| System.Windows.Forms.AnchorStyles.Right)));
|
||||||
|
this.txtExtensionNamespace.Location = new System.Drawing.Point(16, 62);
|
||||||
|
this.txtExtensionNamespace.Name = "txtExtensionNamespace";
|
||||||
|
this.txtExtensionNamespace.Size = new System.Drawing.Size(444, 23);
|
||||||
|
this.txtExtensionNamespace.TabIndex = 2;
|
||||||
|
//
|
||||||
|
// lblHint
|
||||||
|
//
|
||||||
|
this.lblHint.AutoSize = true;
|
||||||
|
this.lblHint.Location = new System.Drawing.Point(466, 65);
|
||||||
|
this.lblHint.Name = "lblHint";
|
||||||
|
this.lblHint.Size = new System.Drawing.Size(121, 15);
|
||||||
|
this.lblHint.TabIndex = 3;
|
||||||
|
this.lblHint.Text = "aka Matrix42.MyExtension";
|
||||||
|
//
|
||||||
|
// lblAddProjects
|
||||||
|
//
|
||||||
|
this.lblAddProjects.AutoSize = true;
|
||||||
|
this.lblAddProjects.Location = new System.Drawing.Point(13, 103);
|
||||||
|
this.lblAddProjects.Name = "lblAddProjects";
|
||||||
|
this.lblAddProjects.Size = new System.Drawing.Size(71, 15);
|
||||||
|
this.lblAddProjects.TabIndex = 4;
|
||||||
|
this.lblAddProjects.Text = "Add Projects";
|
||||||
|
//
|
||||||
|
// lblProjectType
|
||||||
|
//
|
||||||
|
this.lblProjectType.AutoSize = true;
|
||||||
|
this.lblProjectType.Location = new System.Drawing.Point(13, 129);
|
||||||
|
this.lblProjectType.Name = "lblProjectType";
|
||||||
|
this.lblProjectType.Size = new System.Drawing.Size(70, 15);
|
||||||
|
this.lblProjectType.TabIndex = 5;
|
||||||
|
this.lblProjectType.Text = "Project Type";
|
||||||
|
//
|
||||||
|
// cboProjectType
|
||||||
|
//
|
||||||
|
this.cboProjectType.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
|
||||||
|
this.cboProjectType.FormattingEnabled = true;
|
||||||
|
this.cboProjectType.Location = new System.Drawing.Point(16, 147);
|
||||||
|
this.cboProjectType.Name = "cboProjectType";
|
||||||
|
this.cboProjectType.Size = new System.Drawing.Size(150, 23);
|
||||||
|
this.cboProjectType.TabIndex = 6;
|
||||||
|
//
|
||||||
|
// lblProjectPrefix
|
||||||
|
//
|
||||||
|
this.lblProjectPrefix.AutoSize = true;
|
||||||
|
this.lblProjectPrefix.Location = new System.Drawing.Point(179, 129);
|
||||||
|
this.lblProjectPrefix.Name = "lblProjectPrefix";
|
||||||
|
this.lblProjectPrefix.Size = new System.Drawing.Size(75, 15);
|
||||||
|
this.lblProjectPrefix.TabIndex = 7;
|
||||||
|
this.lblProjectPrefix.Text = "Project Prefix";
|
||||||
|
//
|
||||||
|
// txtProjectPrefix
|
||||||
|
//
|
||||||
|
this.txtProjectPrefix.Location = new System.Drawing.Point(182, 147);
|
||||||
|
this.txtProjectPrefix.Name = "txtProjectPrefix";
|
||||||
|
this.txtProjectPrefix.Size = new System.Drawing.Size(150, 23);
|
||||||
|
this.txtProjectPrefix.TabIndex = 8;
|
||||||
|
//
|
||||||
|
// lblRuntimes
|
||||||
|
//
|
||||||
|
this.lblRuntimes.AutoSize = true;
|
||||||
|
this.lblRuntimes.Location = new System.Drawing.Point(345, 129);
|
||||||
|
this.lblRuntimes.Name = "lblRuntimes";
|
||||||
|
this.lblRuntimes.Size = new System.Drawing.Size(121, 15);
|
||||||
|
this.lblRuntimes.TabIndex = 9;
|
||||||
|
this.lblRuntimes.Text = "Runtimes (multiselect)";
|
||||||
|
//
|
||||||
|
// clbRuntimes
|
||||||
|
//
|
||||||
|
this.clbRuntimes.CheckOnClick = true;
|
||||||
|
this.clbRuntimes.FormattingEnabled = true;
|
||||||
|
this.clbRuntimes.Location = new System.Drawing.Point(348, 147);
|
||||||
|
this.clbRuntimes.Name = "clbRuntimes";
|
||||||
|
this.clbRuntimes.Size = new System.Drawing.Size(150, 76);
|
||||||
|
this.clbRuntimes.TabIndex = 10;
|
||||||
|
//
|
||||||
|
// btnAddProject
|
||||||
|
//
|
||||||
|
this.btnAddProject.Location = new System.Drawing.Point(504, 147);
|
||||||
|
this.btnAddProject.Name = "btnAddProject";
|
||||||
|
this.btnAddProject.Size = new System.Drawing.Size(75, 23);
|
||||||
|
this.btnAddProject.TabIndex = 11;
|
||||||
|
this.btnAddProject.Text = "Add";
|
||||||
|
this.btnAddProject.UseVisualStyleBackColor = true;
|
||||||
|
this.btnAddProject.Click += new System.EventHandler(this.btnAddProject_Click);
|
||||||
|
//
|
||||||
|
// lstProjects
|
||||||
|
//
|
||||||
|
this.lstProjects.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
|
||||||
|
| System.Windows.Forms.AnchorStyles.Left)
|
||||||
|
| System.Windows.Forms.AnchorStyles.Right)));
|
||||||
|
this.lstProjects.FormattingEnabled = true;
|
||||||
|
this.lstProjects.ItemHeight = 15;
|
||||||
|
this.lstProjects.Location = new System.Drawing.Point(16, 236);
|
||||||
|
this.lstProjects.Name = "lstProjects";
|
||||||
|
this.lstProjects.Size = new System.Drawing.Size(563, 139);
|
||||||
|
this.lstProjects.TabIndex = 12;
|
||||||
|
//
|
||||||
|
// btnRemoveSelected
|
||||||
|
//
|
||||||
|
this.btnRemoveSelected.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
|
||||||
|
this.btnRemoveSelected.Location = new System.Drawing.Point(16, 385);
|
||||||
|
this.btnRemoveSelected.Name = "btnRemoveSelected";
|
||||||
|
this.btnRemoveSelected.Size = new System.Drawing.Size(120, 23);
|
||||||
|
this.btnRemoveSelected.TabIndex = 13;
|
||||||
|
this.btnRemoveSelected.Text = "Remove selected";
|
||||||
|
this.btnRemoveSelected.UseVisualStyleBackColor = true;
|
||||||
|
this.btnRemoveSelected.Click += new System.EventHandler(this.btnRemoveSelected_Click);
|
||||||
|
//
|
||||||
|
// btnOK
|
||||||
|
//
|
||||||
|
this.btnOK.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
|
||||||
|
this.btnOK.Location = new System.Drawing.Point(423, 385);
|
||||||
|
this.btnOK.Name = "btnOK";
|
||||||
|
this.btnOK.Size = new System.Drawing.Size(75, 23);
|
||||||
|
this.btnOK.TabIndex = 14;
|
||||||
|
this.btnOK.Text = "Create";
|
||||||
|
this.btnOK.UseVisualStyleBackColor = true;
|
||||||
|
this.btnOK.Click += new System.EventHandler(this.btnOK_Click);
|
||||||
|
//
|
||||||
|
// btnCancel
|
||||||
|
//
|
||||||
|
this.btnCancel.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
|
||||||
|
this.btnCancel.Location = new System.Drawing.Point(504, 385);
|
||||||
|
this.btnCancel.Name = "btnCancel";
|
||||||
|
this.btnCancel.Size = new System.Drawing.Size(75, 23);
|
||||||
|
this.btnCancel.TabIndex = 15;
|
||||||
|
this.btnCancel.Text = "Cancel";
|
||||||
|
this.btnCancel.UseVisualStyleBackColor = true;
|
||||||
|
this.btnCancel.Click += new System.EventHandler(this.btnCancel_Click);
|
||||||
|
//
|
||||||
|
// WizardForm
|
||||||
|
//
|
||||||
|
this.AutoScaleDimensions = new System.Drawing.SizeF(7F, 15F);
|
||||||
|
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||||
|
this.ClientSize = new System.Drawing.Size(592, 420);
|
||||||
|
this.Controls.Add(this.btnCancel);
|
||||||
|
this.Controls.Add(this.btnOK);
|
||||||
|
this.Controls.Add(this.btnRemoveSelected);
|
||||||
|
this.Controls.Add(this.lstProjects);
|
||||||
|
this.Controls.Add(this.btnAddProject);
|
||||||
|
this.Controls.Add(this.clbRuntimes);
|
||||||
|
this.Controls.Add(this.lblRuntimes);
|
||||||
|
this.Controls.Add(this.txtProjectPrefix);
|
||||||
|
this.Controls.Add(this.lblProjectPrefix);
|
||||||
|
this.Controls.Add(this.cboProjectType);
|
||||||
|
this.Controls.Add(this.lblProjectType);
|
||||||
|
this.Controls.Add(this.lblAddProjects);
|
||||||
|
this.Controls.Add(this.lblHint);
|
||||||
|
this.Controls.Add(this.txtExtensionNamespace);
|
||||||
|
this.Controls.Add(this.lblExtensionNamespace);
|
||||||
|
this.Controls.Add(this.lblTitle);
|
||||||
|
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog;
|
||||||
|
this.MaximizeBox = false;
|
||||||
|
this.MinimizeBox = false;
|
||||||
|
this.Name = "WizardForm";
|
||||||
|
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
|
||||||
|
this.Text = "Matrix42 Extension Solution Wizard";
|
||||||
|
this.Load += new System.EventHandler(this.WizardForm_Load);
|
||||||
|
this.ResumeLayout(false);
|
||||||
|
this.PerformLayout();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,164 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Windows.Forms;
|
||||||
|
|
||||||
|
namespace Matrix42.Extensions.Scaffolder.Wizard
|
||||||
|
{
|
||||||
|
public partial class WizardForm : Form
|
||||||
|
{
|
||||||
|
private readonly List<ProjectDefinition> _projects = new List<ProjectDefinition>();
|
||||||
|
|
||||||
|
public string ExtensionNamespace => txtExtensionNamespace.Text.Trim();
|
||||||
|
public IReadOnlyList<ProjectDefinition> Projects => _projects;
|
||||||
|
|
||||||
|
public WizardForm()
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
|
||||||
|
cboProjectType.DataSource = Enum.GetValues(typeof(ProjectType));
|
||||||
|
|
||||||
|
clbRuntimes.Items.Add("Win");
|
||||||
|
clbRuntimes.Items.Add("WinCore");
|
||||||
|
clbRuntimes.Items.Add("LinuxCore");
|
||||||
|
clbRuntimes.Items.Add("ALL");
|
||||||
|
|
||||||
|
cboProjectType.SelectedIndexChanged += CboProjectType_SelectedIndexChanged;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void WizardForm_Load(object sender, EventArgs e)
|
||||||
|
{
|
||||||
|
lblHint.Text = "aka Matrix42.MyExtension";
|
||||||
|
}
|
||||||
|
|
||||||
|
private void CboProjectType_SelectedIndexChanged(object sender, EventArgs e)
|
||||||
|
{
|
||||||
|
var type = (ProjectType)cboProjectType.SelectedItem;
|
||||||
|
switch (type)
|
||||||
|
{
|
||||||
|
case ProjectType.WebApi:
|
||||||
|
txtProjectPrefix.Text = "Services";
|
||||||
|
txtProjectPrefix.ReadOnly = false;
|
||||||
|
break;
|
||||||
|
case ProjectType.Contracts:
|
||||||
|
txtProjectPrefix.Text = "Contracts";
|
||||||
|
txtProjectPrefix.ReadOnly = false;
|
||||||
|
break;
|
||||||
|
case ProjectType.BizLogic:
|
||||||
|
txtProjectPrefix.Text = "BizLogic";
|
||||||
|
txtProjectPrefix.ReadOnly = false;
|
||||||
|
break;
|
||||||
|
case ProjectType.Custom:
|
||||||
|
txtProjectPrefix.Text = string.Empty;
|
||||||
|
txtProjectPrefix.ReadOnly = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void btnAddProject_Click(object sender, EventArgs e)
|
||||||
|
{
|
||||||
|
if (!ValidateProjectInputs())
|
||||||
|
return;
|
||||||
|
|
||||||
|
var def = new ProjectDefinition
|
||||||
|
{
|
||||||
|
Type = (ProjectType)cboProjectType.SelectedItem,
|
||||||
|
Prefix = txtProjectPrefix.Text.Trim(),
|
||||||
|
Runtimes = GetSelectedRuntimes()
|
||||||
|
};
|
||||||
|
|
||||||
|
_projects.Add(def);
|
||||||
|
lstProjects.Items.Add(def.Display);
|
||||||
|
|
||||||
|
txtProjectPrefix.Clear();
|
||||||
|
for (int i = 0; i < clbRuntimes.Items.Count; i++)
|
||||||
|
clbRuntimes.SetItemChecked(i, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
private RuntimeTargets GetSelectedRuntimes()
|
||||||
|
{
|
||||||
|
RuntimeTargets result = RuntimeTargets.None;
|
||||||
|
|
||||||
|
foreach (var item in clbRuntimes.CheckedItems)
|
||||||
|
{
|
||||||
|
switch (item.ToString())
|
||||||
|
{
|
||||||
|
case "Win":
|
||||||
|
result |= RuntimeTargets.Win;
|
||||||
|
break;
|
||||||
|
case "WinCore":
|
||||||
|
result |= RuntimeTargets.WinCore;
|
||||||
|
break;
|
||||||
|
case "LinuxCore":
|
||||||
|
result |= RuntimeTargets.LinuxCore;
|
||||||
|
break;
|
||||||
|
case "ALL":
|
||||||
|
result |= RuntimeTargets.All;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool ValidateProjectInputs()
|
||||||
|
{
|
||||||
|
if (cboProjectType.SelectedItem == null)
|
||||||
|
{
|
||||||
|
MessageBox.Show("Please select project type.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
var type = (ProjectType)cboProjectType.SelectedItem;
|
||||||
|
if (string.IsNullOrWhiteSpace(txtProjectPrefix.Text))
|
||||||
|
{
|
||||||
|
if (type == ProjectType.Custom)
|
||||||
|
{
|
||||||
|
MessageBox.Show("Project prefix is required for Custom project type.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (clbRuntimes.CheckedItems.Count == 0)
|
||||||
|
{
|
||||||
|
MessageBox.Show("Please select at least one runtime.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void btnRemoveSelected_Click(object sender, EventArgs e)
|
||||||
|
{
|
||||||
|
int idx = lstProjects.SelectedIndex;
|
||||||
|
if (idx < 0 || idx >= _projects.Count)
|
||||||
|
return;
|
||||||
|
|
||||||
|
_projects.RemoveAt(idx);
|
||||||
|
lstProjects.Items.RemoveAt(idx);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void btnOK_Click(object sender, EventArgs e)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrWhiteSpace(ExtensionNamespace))
|
||||||
|
{
|
||||||
|
MessageBox.Show("Extension Namespace is required.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_projects.Count == 0)
|
||||||
|
{
|
||||||
|
MessageBox.Show("Please add at least one project.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
DialogResult = DialogResult.OK;
|
||||||
|
Close();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void btnCancel_Click(object sender, EventArgs e)
|
||||||
|
{
|
||||||
|
DialogResult = DialogResult.Cancel;
|
||||||
|
Close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<PackageManifest Version="2.0.0" xmlns="http://schemas.microsoft.com/developer/vsx-schema/2011" xmlns:d="http://schemas.microsoft.com/developer/vsx-schema-design/2011">
|
||||||
|
<Metadata>
|
||||||
|
<Identity Id="Matrix42.Extensions.Scaffolder.Vsix.7c0f30ed-547f-4e1d-a046-8120ae21fc8b" Version="1.0" Language="en-US" Publisher="Matrix42" />
|
||||||
|
<DisplayName>Matrix42.Extensions.Scaffolder.Vsix</DisplayName>
|
||||||
|
<Description xml:space="preserve">Creates a new Matrix42 extension solution with multiple projects based on Matrix42.Extensions.SDK.</Description>
|
||||||
|
</Metadata>
|
||||||
|
<Installation>
|
||||||
|
<InstallationTarget Id="Microsoft.VisualStudio.Community" Version="[17.0, 18.0)">
|
||||||
|
<ProductArchitecture>amd64</ProductArchitecture>
|
||||||
|
</InstallationTarget>
|
||||||
|
</Installation>
|
||||||
|
<Dependencies>
|
||||||
|
<Dependency Id="Microsoft.Framework.NDP" DisplayName="Microsoft .NET Framework" d:Source="Manual" Version="[4.7,)" />
|
||||||
|
</Dependencies>
|
||||||
|
<Prerequisites>
|
||||||
|
<Prerequisite Id="Microsoft.VisualStudio.Component.CoreEditor" Version="[17.0,18.0)" DisplayName="Visual Studio core editor" />
|
||||||
|
</Prerequisites>
|
||||||
|
<Assets>
|
||||||
|
<Asset Type="Microsoft.VisualStudio.ProjectTemplate" Path="ProjectTemplates\ExtensionSolution.vstemplate" />
|
||||||
|
</Assets>
|
||||||
|
</PackageManifest>
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
|
||||||
|
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||||
|
# Visual Studio Version 17
|
||||||
|
VisualStudioVersion = 17.14.36310.24
|
||||||
|
MinimumVisualStudioVersion = 10.0.40219.1
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Matrix42.Extensions.Scaffolder.Core", "Matrix42.Extensions.Scaffolder.Core\Matrix42.Extensions.Scaffolder.Core.csproj", "{43E82070-2941-4589-8BF5-1FD1D427BDAE}"
|
||||||
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Matrix42.Extensions.Scaffolder.Console", "Matrix42.Extensions.Scaffolder.Console\Matrix42.Extensions.Scaffolder.Console.csproj", "{F7979A70-0D89-46B7-814C-1E7D0B0DF441}"
|
||||||
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Matrix42.Extensions.Scaffolder.Vsix", "Matrix42.Extensions.Scaffolder.Vsix\Matrix42.Extensions.Scaffolder.Vsix.csproj", "{50F8DCAA-48B9-47D5-ABB8-F8D33BEF1BD1}"
|
||||||
|
EndProject
|
||||||
|
Global
|
||||||
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
|
Debug|Any CPU = Debug|Any CPU
|
||||||
|
Release|Any CPU = Release|Any CPU
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||||
|
{43E82070-2941-4589-8BF5-1FD1D427BDAE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{43E82070-2941-4589-8BF5-1FD1D427BDAE}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{43E82070-2941-4589-8BF5-1FD1D427BDAE}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{43E82070-2941-4589-8BF5-1FD1D427BDAE}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{F7979A70-0D89-46B7-814C-1E7D0B0DF441}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{F7979A70-0D89-46B7-814C-1E7D0B0DF441}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{F7979A70-0D89-46B7-814C-1E7D0B0DF441}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{F7979A70-0D89-46B7-814C-1E7D0B0DF441}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{50F8DCAA-48B9-47D5-ABB8-F8D33BEF1BD1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{50F8DCAA-48B9-47D5-ABB8-F8D33BEF1BD1}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{50F8DCAA-48B9-47D5-ABB8-F8D33BEF1BD1}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{50F8DCAA-48B9-47D5-ABB8-F8D33BEF1BD1}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
|
HideSolutionNode = FALSE
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||||
|
SolutionGuid = {3329054A-94A3-4953-8650-68C9B450515A}
|
||||||
|
EndGlobalSection
|
||||||
|
EndGlobal
|
||||||
17
F4SDM42WebApi/M42ExtensionScaffolder/service-info.yml
Normal file
17
F4SDM42WebApi/M42ExtensionScaffolder/service-info.yml
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
product: "M42 Enterprise" # The project or platform this service belongs to
|
||||||
|
service_name: "Extensions Scaffolder" # Name of the service
|
||||||
|
description: "Template project acting as an extension scaffolder. Automatically generate extension structure including provided projects and runtimes" # A brief description of the service
|
||||||
|
|
||||||
|
owner:
|
||||||
|
name: "Titan" # Owner of the service (could be an individual or team)
|
||||||
|
email: "dmytro.romanii@matrix42.com" # Contact email for the owner
|
||||||
|
|
||||||
|
pipelines:
|
||||||
|
pull_request_pipeline: "N/A" # URL to the pipeline that runs for pull requests
|
||||||
|
ci_pipeline: "N/A" # URL to the continuous integration (CI) pipeline
|
||||||
|
cd_pipeline: "N/A" # URL to the continuous delivery (CD) pipeline
|
||||||
|
|
||||||
|
links:
|
||||||
|
repository: "https://dev.azure.com/matrix42/DWP/_git/M42ExtensionScaffolder"
|
||||||
|
documentation: "https://dev.azure.com/matrix42/DWP/_git/M42ExtensionScaffolder?path=/README.md"
|
||||||
|
backlog: "https://dev.azure.com/matrix42/BPM/_backlogs/backlog/Titan"
|
||||||
BIN
F4SDM42WebApi/M42Libraries/26.1/AdminUI.AppManFoundation.dll
Normal file
BIN
F4SDM42WebApi/M42Libraries/26.1/AdminUI.AppManFoundation.dll
Normal file
Binary file not shown.
BIN
F4SDM42WebApi/M42Libraries/26.1/AdminUI.DcmObjectWrapper.dll
Normal file
BIN
F4SDM42WebApi/M42Libraries/26.1/AdminUI.DcmObjectWrapper.dll
Normal file
Binary file not shown.
BIN
F4SDM42WebApi/M42Libraries/26.1/AdminUI.WqlQueryEngine.dll
Normal file
BIN
F4SDM42WebApi/M42Libraries/26.1/AdminUI.WqlQueryEngine.dll
Normal file
Binary file not shown.
BIN
F4SDM42WebApi/M42Libraries/26.1/Ajax.dll
Normal file
BIN
F4SDM42WebApi/M42Libraries/26.1/Ajax.dll
Normal file
Binary file not shown.
BIN
F4SDM42WebApi/M42Libraries/26.1/AjaxControlToolkit.dll
Normal file
BIN
F4SDM42WebApi/M42Libraries/26.1/AjaxControlToolkit.dll
Normal file
Binary file not shown.
BIN
F4SDM42WebApi/M42Libraries/26.1/AngleSharp.dll
Normal file
BIN
F4SDM42WebApi/M42Libraries/26.1/AngleSharp.dll
Normal file
Binary file not shown.
BIN
F4SDM42WebApi/M42Libraries/26.1/AntiXSSLibrary.dll
Normal file
BIN
F4SDM42WebApi/M42Libraries/26.1/AntiXSSLibrary.dll
Normal file
Binary file not shown.
BIN
F4SDM42WebApi/M42Libraries/26.1/AutoMapper.dll
Normal file
BIN
F4SDM42WebApi/M42Libraries/26.1/AutoMapper.dll
Normal file
Binary file not shown.
BIN
F4SDM42WebApi/M42Libraries/26.1/Azure.Core.dll
Normal file
BIN
F4SDM42WebApi/M42Libraries/26.1/Azure.Core.dll
Normal file
Binary file not shown.
BIN
F4SDM42WebApi/M42Libraries/26.1/Azure.Identity.dll
Normal file
BIN
F4SDM42WebApi/M42Libraries/26.1/Azure.Identity.dll
Normal file
Binary file not shown.
BIN
F4SDM42WebApi/M42Libraries/26.1/BouncyCastle.Crypto.dll
Normal file
BIN
F4SDM42WebApi/M42Libraries/26.1/BouncyCastle.Crypto.dll
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
F4SDM42WebApi/M42Libraries/26.1/CsvHelper.dll
Normal file
BIN
F4SDM42WebApi/M42Libraries/26.1/CsvHelper.dll
Normal file
Binary file not shown.
BIN
F4SDM42WebApi/M42Libraries/26.1/DcmObjectModel.dll
Normal file
BIN
F4SDM42WebApi/M42Libraries/26.1/DcmObjectModel.dll
Normal file
Binary file not shown.
BIN
F4SDM42WebApi/M42Libraries/26.1/EPPlus.dll
Normal file
BIN
F4SDM42WebApi/M42Libraries/26.1/EPPlus.dll
Normal file
Binary file not shown.
BIN
F4SDM42WebApi/M42Libraries/26.1/EntityFramework.SqlServer.dll
Normal file
BIN
F4SDM42WebApi/M42Libraries/26.1/EntityFramework.SqlServer.dll
Normal file
Binary file not shown.
BIN
F4SDM42WebApi/M42Libraries/26.1/EntityFramework.dll
Normal file
BIN
F4SDM42WebApi/M42Libraries/26.1/EntityFramework.dll
Normal file
Binary file not shown.
Binary file not shown.
BIN
F4SDM42WebApi/M42Libraries/26.1/Google.Apis.Auth.dll
Normal file
BIN
F4SDM42WebApi/M42Libraries/26.1/Google.Apis.Auth.dll
Normal file
Binary file not shown.
BIN
F4SDM42WebApi/M42Libraries/26.1/Google.Apis.Core.dll
Normal file
BIN
F4SDM42WebApi/M42Libraries/26.1/Google.Apis.Core.dll
Normal file
Binary file not shown.
BIN
F4SDM42WebApi/M42Libraries/26.1/Google.Apis.Gmail.v1.dll
Normal file
BIN
F4SDM42WebApi/M42Libraries/26.1/Google.Apis.Gmail.v1.dll
Normal file
Binary file not shown.
BIN
F4SDM42WebApi/M42Libraries/26.1/Google.Apis.PlatformServices.dll
Normal file
BIN
F4SDM42WebApi/M42Libraries/26.1/Google.Apis.PlatformServices.dll
Normal file
Binary file not shown.
BIN
F4SDM42WebApi/M42Libraries/26.1/Google.Apis.dll
Normal file
BIN
F4SDM42WebApi/M42Libraries/26.1/Google.Apis.dll
Normal file
Binary file not shown.
BIN
F4SDM42WebApi/M42Libraries/26.1/HtmlAgilityPack.dll
Normal file
BIN
F4SDM42WebApi/M42Libraries/26.1/HtmlAgilityPack.dll
Normal file
Binary file not shown.
BIN
F4SDM42WebApi/M42Libraries/26.1/ICSharpCode.SharpZipLib.dll
Normal file
BIN
F4SDM42WebApi/M42Libraries/26.1/ICSharpCode.SharpZipLib.dll
Normal file
Binary file not shown.
BIN
F4SDM42WebApi/M42Libraries/26.1/Interop.ActiveDs.dll
Normal file
BIN
F4SDM42WebApi/M42Libraries/26.1/Interop.ActiveDs.dll
Normal file
Binary file not shown.
BIN
F4SDM42WebApi/M42Libraries/26.1/Interop.DTS.dll
Normal file
BIN
F4SDM42WebApi/M42Libraries/26.1/Interop.DTS.dll
Normal file
Binary file not shown.
BIN
F4SDM42WebApi/M42Libraries/26.1/Interop.WindowsInstaller.dll
Normal file
BIN
F4SDM42WebApi/M42Libraries/26.1/Interop.WindowsInstaller.dll
Normal file
Binary file not shown.
BIN
F4SDM42WebApi/M42Libraries/26.1/Ionic.Zip.dll
Normal file
BIN
F4SDM42WebApi/M42Libraries/26.1/Ionic.Zip.dll
Normal file
Binary file not shown.
BIN
F4SDM42WebApi/M42Libraries/26.1/MailBee.NET.dll
Normal file
BIN
F4SDM42WebApi/M42Libraries/26.1/MailBee.NET.dll
Normal file
Binary file not shown.
BIN
F4SDM42WebApi/M42Libraries/26.1/MailKit.dll
Normal file
BIN
F4SDM42WebApi/M42Libraries/26.1/MailKit.dll
Normal file
Binary file not shown.
BIN
F4SDM42WebApi/M42Libraries/26.1/Matrix42.AI.Contracts.dll
Normal file
BIN
F4SDM42WebApi/M42Libraries/26.1/Matrix42.AI.Contracts.dll
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
F4SDM42WebApi/M42Libraries/26.1/Matrix42.Api.Contracts.dll
Normal file
BIN
F4SDM42WebApi/M42Libraries/26.1/Matrix42.Api.Contracts.dll
Normal file
Binary file not shown.
BIN
F4SDM42WebApi/M42Libraries/26.1/Matrix42.Api.DbClient.dll
Normal file
BIN
F4SDM42WebApi/M42Libraries/26.1/Matrix42.Api.DbClient.dll
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
F4SDM42WebApi/M42Libraries/26.1/Matrix42.Auth.BizLogic.dll
Normal file
BIN
F4SDM42WebApi/M42Libraries/26.1/Matrix42.Auth.BizLogic.dll
Normal file
Binary file not shown.
BIN
F4SDM42WebApi/M42Libraries/26.1/Matrix42.Auth.Contracts.dll
Normal file
BIN
F4SDM42WebApi/M42Libraries/26.1/Matrix42.Auth.Contracts.dll
Normal file
Binary file not shown.
BIN
F4SDM42WebApi/M42Libraries/26.1/Matrix42.Auth.Engines.dll
Normal file
BIN
F4SDM42WebApi/M42Libraries/26.1/Matrix42.Auth.Engines.dll
Normal file
Binary file not shown.
BIN
F4SDM42WebApi/M42Libraries/26.1/Matrix42.Auth.STS.dll
Normal file
BIN
F4SDM42WebApi/M42Libraries/26.1/Matrix42.Auth.STS.dll
Normal file
Binary file not shown.
BIN
F4SDM42WebApi/M42Libraries/26.1/Matrix42.Auth.Services.dll
Normal file
BIN
F4SDM42WebApi/M42Libraries/26.1/Matrix42.Auth.Services.dll
Normal file
Binary file not shown.
Binary file not shown.
BIN
F4SDM42WebApi/M42Libraries/26.1/Matrix42.Behaviors.Contracts.dll
Normal file
BIN
F4SDM42WebApi/M42Libraries/26.1/Matrix42.Behaviors.Contracts.dll
Normal file
Binary file not shown.
BIN
F4SDM42WebApi/M42Libraries/26.1/Matrix42.BizLogic.Client.dll
Normal file
BIN
F4SDM42WebApi/M42Libraries/26.1/Matrix42.BizLogic.Client.dll
Normal file
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user