Compare commits
2
Commits
dev
...
dc93ea0813
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
dc93ea0813 | ||
|
|
1aa2adac08 |
+16
@@ -4,17 +4,22 @@ obj/
|
||||
out/
|
||||
publish/
|
||||
artifacts/
|
||||
buildcheck/
|
||||
*.nupkg
|
||||
*.snupkg
|
||||
|
||||
# Visual Studio / Rider / VS Code
|
||||
.vs/
|
||||
.idea/
|
||||
.vscode/.ropeproject
|
||||
.vscode/.ionide/
|
||||
*.user
|
||||
*.suo
|
||||
*.rsuser
|
||||
*.sln.docstates
|
||||
*.csproj.user
|
||||
*.csproj.lscache
|
||||
*.sln.DotSettings.user
|
||||
|
||||
# .NET / test artifacts
|
||||
TestResults/
|
||||
@@ -32,6 +37,8 @@ coverage.cobertura.xml
|
||||
*.cache
|
||||
*.bak
|
||||
*.orig
|
||||
*.pid
|
||||
*.pid.lock
|
||||
|
||||
# Local configuration / secrets
|
||||
appsettings.Local.json
|
||||
@@ -39,9 +46,12 @@ appsettings.*.local.json
|
||||
appsettings.*.Local.json
|
||||
*.secrets.json
|
||||
secrets.json
|
||||
*.kdbx
|
||||
*.key
|
||||
|
||||
# EF / local tooling noise
|
||||
.ef/
|
||||
efbundle.exe
|
||||
|
||||
# OS files
|
||||
.DS_Store
|
||||
@@ -58,3 +68,9 @@ npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
pnpm-debug.log*
|
||||
|
||||
# Keep source artifacts versioned:
|
||||
# - Context/DemoData*.cs
|
||||
# - Migrations/*.cs
|
||||
# - .tests/*.ps1
|
||||
# - Docs/**/*.md
|
||||
|
||||
@@ -0,0 +1,310 @@
|
||||
param(
|
||||
[string]$ApiBaseUrl = 'http://localhost:5286/api',
|
||||
|
||||
[string]$DeploymentBatchId = '80000000-0000-0000-0000-000000000101',
|
||||
|
||||
[int]$ApiTimeoutSec = 30,
|
||||
|
||||
[bool]$UseDefaultCredentials = $true,
|
||||
|
||||
[System.Management.Automation.PSCredential]$Credential
|
||||
)
|
||||
|
||||
$ErrorActionPreference = 'Stop'
|
||||
|
||||
function Invoke-TestMergeApiJson {
|
||||
param(
|
||||
[ValidateSet('GET', 'POST', 'PUT', 'DELETE')]
|
||||
[string]$Method,
|
||||
|
||||
[string]$Path
|
||||
)
|
||||
|
||||
$uri = ('{0}/{1}' -f $ApiBaseUrl.TrimEnd('/'), $Path.TrimStart('/'))
|
||||
$parameters = @{
|
||||
Method = $Method
|
||||
Uri = $uri
|
||||
TimeoutSec = $ApiTimeoutSec
|
||||
ErrorAction = 'Stop'
|
||||
}
|
||||
|
||||
if ($Credential) {
|
||||
$parameters.Credential = $Credential
|
||||
}
|
||||
elseif ($UseDefaultCredentials) {
|
||||
$parameters.UseDefaultCredentials = $true
|
||||
}
|
||||
|
||||
try {
|
||||
Invoke-RestMethod @parameters
|
||||
}
|
||||
catch {
|
||||
$responseBody = '<empty response body>'
|
||||
if ($_.Exception.Response) {
|
||||
try {
|
||||
$stream = $_.Exception.Response.GetResponseStream()
|
||||
if ($stream) {
|
||||
$reader = [System.IO.StreamReader]::new($stream)
|
||||
$text = $reader.ReadToEnd()
|
||||
if (-not [string]::IsNullOrWhiteSpace($text)) {
|
||||
$responseBody = $text
|
||||
}
|
||||
}
|
||||
}
|
||||
catch {
|
||||
$responseBody = '<could not read response body>'
|
||||
}
|
||||
}
|
||||
|
||||
throw "API request failed. Method=[$Method], Uri=[$uri], Response=[$responseBody]. $($_.Exception.Message)"
|
||||
}
|
||||
}
|
||||
|
||||
function ConvertFrom-TestJson {
|
||||
param([string]$Json)
|
||||
|
||||
$Json | ConvertFrom-Json
|
||||
}
|
||||
|
||||
function Get-TestDefinition {
|
||||
param(
|
||||
[object[]]$Definitions,
|
||||
[string]$RevisionId,
|
||||
[string]$Kind,
|
||||
[string]$Name
|
||||
)
|
||||
|
||||
@($Definitions | Where-Object {
|
||||
[string]$_.templateRevisionId -eq $RevisionId -and
|
||||
$_.kind -eq $Kind -and
|
||||
$_.name -eq $Name
|
||||
})[0]
|
||||
}
|
||||
|
||||
function Get-TestFirst {
|
||||
param([object[]]$Items)
|
||||
|
||||
@($Items | Select-Object -First 1)[0]
|
||||
}
|
||||
|
||||
function Get-TestSelectionByRole {
|
||||
param(
|
||||
[object]$Composition,
|
||||
[string]$Role
|
||||
)
|
||||
|
||||
Get-TestFirst -Items @($Composition.templateSelections | Where-Object { $_.templateRole -eq $Role })
|
||||
}
|
||||
|
||||
function Get-TestRevisionDefinitions {
|
||||
param([object]$Selection)
|
||||
|
||||
$templateId = [string]$Selection.templateVersion.templateId
|
||||
$versionId = [string]$Selection.templateVersionId
|
||||
$revisionId = [string]$Selection.templateRevisionId
|
||||
|
||||
@(Invoke-TestMergeApiJson -Method GET -Path "Template/$templateId/Versions/$versionId/Revisions/$revisionId/Definitions")
|
||||
}
|
||||
|
||||
function Assert-TestApiIsReachable {
|
||||
try {
|
||||
Invoke-TestMergeApiJson -Method GET -Path "deployment-batches/$DeploymentBatchId/composition" | Out-Null
|
||||
}
|
||||
catch {
|
||||
if ($_.Exception.Message -match '401|Nicht autorisiert|Unauthorized') {
|
||||
throw @"
|
||||
API authentication failed for [$ApiBaseUrl].
|
||||
Start the API with Windows authentication enabled and run the test from a session that can authenticate to it.
|
||||
You can also pass explicit credentials:
|
||||
Invoke-Pester -Script @{ Path = '.Net\Microsoft.SelfService.Portal.Core.API\.tests\Api.Tests.ps1'; Parameters = @{ Credential = (Get-Credential) } }
|
||||
|
||||
$($_.Exception.Message)
|
||||
"@
|
||||
}
|
||||
|
||||
throw
|
||||
}
|
||||
}
|
||||
|
||||
Describe ' API DemoData composition' {
|
||||
BeforeAll {
|
||||
Assert-TestApiIsReachable
|
||||
|
||||
$script:expectedTemplateAliases = @(
|
||||
'Environment-Test'
|
||||
'Domain-Contoso'
|
||||
'Service-SharePoint-Contoso'
|
||||
'Stage-Install'
|
||||
)
|
||||
|
||||
$script:expectedTemplateRoles = @(
|
||||
'Environment'
|
||||
'Domain'
|
||||
'Service'
|
||||
'Stage'
|
||||
)
|
||||
|
||||
$script:expectedTemplateRevisionIds = @(
|
||||
'72000000-0000-0000-0000-000000000101'
|
||||
'72000000-0000-0000-0000-000000000102'
|
||||
'72000000-0000-0000-0000-000000000103'
|
||||
'72000000-0000-0000-0000-000000000104'
|
||||
)
|
||||
|
||||
$script:apiComposition = Invoke-TestMergeApiJson -Method GET -Path "deployment-batches/$DeploymentBatchId/composition"
|
||||
$script:environmentSelection = Get-TestSelectionByRole -Composition $script:apiComposition -Role 'Environment'
|
||||
$script:domainSelection = Get-TestSelectionByRole -Composition $script:apiComposition -Role 'Domain'
|
||||
$script:sharePointSelection = Get-TestSelectionByRole -Composition $script:apiComposition -Role 'Service'
|
||||
$script:stageSelection = Get-TestSelectionByRole -Composition $script:apiComposition -Role 'Stage'
|
||||
$script:environmentRevisionId = [string]$script:environmentSelection.templateRevisionId
|
||||
$script:domainRevisionId = [string]$script:domainSelection.templateRevisionId
|
||||
$script:sharePointRevisionId = [string]$script:sharePointSelection.templateRevisionId
|
||||
$script:environmentDefinitions = Get-TestRevisionDefinitions -Selection $script:environmentSelection
|
||||
$script:domainDefinitions = Get-TestRevisionDefinitions -Selection $script:domainSelection
|
||||
$script:sharePointDefinitions = Get-TestRevisionDefinitions -Selection $script:sharePointSelection
|
||||
$script:stageDefinitions = Get-TestRevisionDefinitions -Selection $script:stageSelection
|
||||
$script:deploymentArtifacts = @(Invoke-TestMergeApiJson -Method GET -Path "deployment-artifacts?deploymentGroupId=$DeploymentBatchId")
|
||||
$script:credentialSecrets = @(Invoke-TestMergeApiJson -Method GET -Path 'credential-secrets')
|
||||
$script:configurationDefinitions = @(Invoke-TestMergeApiJson -Method GET -Path 'configuration-definitions')
|
||||
$script:parameterDefinitions = @(Invoke-TestMergeApiJson -Method GET -Path 'configuration-definitions?kind=Parameter')
|
||||
$script:variableDefinitions = @(Invoke-TestMergeApiJson -Method GET -Path 'configuration-definitions?kind=Variable')
|
||||
$script:configurationValues = @(Invoke-TestMergeApiJson -Method GET -Path 'configuration-values')
|
||||
}
|
||||
|
||||
It 'loads the seeded deployment composition from the API' {
|
||||
$script:apiComposition.deploymentBatchId | Should Be $DeploymentBatchId
|
||||
@($script:apiComposition.templateSelections).Count | Should Be 4
|
||||
@($script:apiComposition.targetAssignments).Count | Should Be 3
|
||||
}
|
||||
|
||||
It 'keeps the template selection order from the seeded deployment' {
|
||||
$aliases = @($script:apiComposition.templateSelections | Sort-Object sortOrder | ForEach-Object { $_.alias })
|
||||
$roles = @($script:apiComposition.templateSelections | Sort-Object sortOrder | ForEach-Object { $_.templateRole })
|
||||
|
||||
($aliases -join '|') | Should Be ($script:expectedTemplateAliases -join '|')
|
||||
($roles -join '|') | Should Be ($script:expectedTemplateRoles -join '|')
|
||||
}
|
||||
|
||||
It 'pins every template selection to an immutable template revision' {
|
||||
$revisionIds = @($script:apiComposition.templateSelections | Sort-Object sortOrder | ForEach-Object { [string]$_.templateRevisionId })
|
||||
|
||||
($revisionIds -join '|') | Should Be ($script:expectedTemplateRevisionIds -join '|')
|
||||
@($revisionIds | Where-Object { [string]::IsNullOrWhiteSpace($_) }).Count | Should Be 0
|
||||
}
|
||||
|
||||
It 'loads each pinned template revision and its definitions from the API' {
|
||||
foreach ($selection in @($script:apiComposition.templateSelections | Sort-Object sortOrder)) {
|
||||
$templateId = [string]$selection.templateVersion.templateId
|
||||
$versionId = [string]$selection.templateVersionId
|
||||
$revisionId = [string]$selection.templateRevisionId
|
||||
|
||||
$revision = Invoke-TestMergeApiJson -Method GET -Path "Template/$templateId/Versions/$versionId/Revisions/$revisionId"
|
||||
$definitions = @(Invoke-TestMergeApiJson -Method GET -Path "Template/$templateId/Versions/$versionId/Revisions/$revisionId/Definitions")
|
||||
|
||||
$revision.id | Should Be $revisionId
|
||||
$revision.templateVersionId | Should Be $versionId
|
||||
$revision.revisionNumber | Should Be 1
|
||||
$revision.isCurrent | Should Be $true
|
||||
$revision.isPublished | Should Be $true
|
||||
|
||||
if ($selection.templateRole -ne 'Stage') {
|
||||
@($definitions).Count | Should BeGreaterThan 0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
It 'exposes deployment artifact and credential store API surfaces' {
|
||||
@($script:deploymentArtifacts).Count | Should Be 1
|
||||
$script:deploymentArtifacts[0].deploymentGroupId | Should Be $DeploymentBatchId
|
||||
$script:deploymentArtifacts[0].artifactType | Should Be 'ResolvedConfigurationData'
|
||||
$script:deploymentArtifacts[0].isStale | Should Be $false
|
||||
|
||||
$secretNames = @($script:credentialSecrets | ForEach-Object { $_.name } | Sort-Object)
|
||||
$secretNames -contains 'Windows/SharePoint/SetupAccount' | Should Be $true
|
||||
$secretNames -contains 'Windows/SharePoint/FarmAccount' | Should Be $true
|
||||
$secretNames -contains 'Windows/SharePoint/FarmPassphrase' | Should Be $true
|
||||
$secretNames -contains 'Windows/SharePoint/DefaultServiceAccount' | Should Be $true
|
||||
$secretNames -contains 'Windows/SharePoint/SearchAccount' | Should Be $true
|
||||
}
|
||||
|
||||
It 'returns resolved deployment artifact values without reading local PSD1 files' {
|
||||
$deploymentJson = ConvertFrom-TestJson -Json $script:deploymentArtifacts[0].deploymentJson
|
||||
|
||||
$deploymentJson.variables.DatabasePrefix | Should Be 'SharePoint_Contoso_Test'
|
||||
$deploymentJson.variables.ServiceDbPrefix | Should Be 'SharePoint_Contoso_Test_Services'
|
||||
$deploymentJson.variables.ConfigDbName | Should Be 'SharePoint_Contoso_Test_Farm_Config'
|
||||
$deploymentJson.resources.NonNodeData.LocalConfigurationManager.ConfigurationMode | Should Be 'ApplyOnly'
|
||||
@($deploymentJson.resources.AllNodes).Count | Should Be 3
|
||||
$deploymentJson.resources.AllNodes[0].NodeName | Should Be 'CLD-SHP-01'
|
||||
$deploymentJson.resources.AllNodes[0].RunCentralAdministration | Should Be $true
|
||||
}
|
||||
|
||||
It 'seeds parameter and variable definitions in the Configuration Definition API' {
|
||||
@($script:configurationDefinitions).Count | Should BeGreaterThan 0
|
||||
@($script:parameterDefinitions).Count | Should BeGreaterThan 0
|
||||
@($script:variableDefinitions).Count | Should BeGreaterThan 0
|
||||
|
||||
$landscape = Get-TestDefinition -Definitions $script:environmentDefinitions -RevisionId $script:environmentRevisionId -Kind 'Parameter' -Name 'Landscape'
|
||||
$domainFqdn = Get-TestDefinition -Definitions $script:domainDefinitions -RevisionId $script:domainRevisionId -Kind 'Parameter' -Name 'DomainFQDN'
|
||||
$databasePrefix = Get-TestDefinition -Definitions $script:sharePointDefinitions -RevisionId $script:sharePointRevisionId -Kind 'Parameter' -Name 'DatabasePrefix'
|
||||
$configDbName = Get-TestDefinition -Definitions $script:environmentDefinitions -RevisionId $script:environmentRevisionId -Kind 'Variable' -Name 'ConfigDbName'
|
||||
|
||||
$landscape.id | Should Not BeNullOrEmpty
|
||||
$domainFqdn.id | Should Not BeNullOrEmpty
|
||||
$databasePrefix.id | Should Not BeNullOrEmpty
|
||||
$configDbName.id | Should Not BeNullOrEmpty
|
||||
|
||||
(ConvertFrom-TestJson -Json $landscape.propertiesJson).AllowedValues -contains 'Test' | Should Be $true
|
||||
(ConvertFrom-TestJson -Json $databasePrefix.propertiesJson).DefaultValue | Should Be 'SharePoint'
|
||||
(ConvertFrom-TestJson -Json $configDbName.propertiesJson).Expression | Should Match 'joinNotEmpty'
|
||||
}
|
||||
|
||||
It 'exposes configuration definitions through the standalone API and keeps revision definitions typed' {
|
||||
$environmentDefinitions = @(Invoke-TestMergeApiJson -Method GET -Path "configuration-definitions?templateRevisionId=$($script:environmentRevisionId)")
|
||||
$environmentVariables = @($script:environmentDefinitions | Where-Object { $_.kind -eq 'Variable' })
|
||||
|
||||
@($environmentDefinitions).Count | Should BeGreaterThan 0
|
||||
@($environmentVariables).Count | Should BeGreaterThan 0
|
||||
@($environmentVariables | Where-Object { $_.kind -ne 'Variable' }).Count | Should Be 0
|
||||
|
||||
$environmentDefinitionNames = @($script:environmentDefinitions | ForEach-Object { $_.name })
|
||||
$environmentVariableNames = @($environmentVariables | ForEach-Object { $_.name })
|
||||
$environmentDefinitionNames -contains 'Landscape' | Should Be $true
|
||||
$environmentVariableNames -contains 'ConfigDbName' | Should Be $true
|
||||
}
|
||||
|
||||
It 'seeds configuration values for parameters and variables' {
|
||||
@($script:configurationValues).Count | Should BeGreaterThan 0
|
||||
|
||||
$landscape = Get-TestDefinition -Definitions $script:environmentDefinitions -RevisionId $script:environmentRevisionId -Kind 'Parameter' -Name 'Landscape'
|
||||
$domainFqdn = Get-TestDefinition -Definitions $script:domainDefinitions -RevisionId $script:domainRevisionId -Kind 'Parameter' -Name 'DomainFQDN'
|
||||
$configDbName = Get-TestDefinition -Definitions $script:environmentDefinitions -RevisionId $script:environmentRevisionId -Kind 'Variable' -Name 'ConfigDbName'
|
||||
|
||||
$landscapeValues = @(Invoke-TestMergeApiJson -Method GET -Path "configuration-definitions/$($landscape.id)/values")
|
||||
$domainFqdnValues = @(Invoke-TestMergeApiJson -Method GET -Path "configuration-values?definitionId=$($domainFqdn.id)")
|
||||
$configDbNameValues = @(Invoke-TestMergeApiJson -Method GET -Path "configuration-values?definitionId=$($configDbName.id)")
|
||||
|
||||
@($landscapeValues).Count | Should Be 1
|
||||
@($domainFqdnValues).Count | Should Be 1
|
||||
@($configDbNameValues).Count | Should Be 1
|
||||
|
||||
(ConvertFrom-TestJson -Json $landscapeValues[0].valueJson).value | Should Be 'Test'
|
||||
(ConvertFrom-TestJson -Json $domainFqdnValues[0].valueJson).value | Should Be 'contoso.local'
|
||||
(ConvertFrom-TestJson -Json $configDbNameValues[0].valueJson).expression | Should Match 'joinNotEmpty'
|
||||
|
||||
$landscapeValues[0].scopeType | Should Be 'TemplateRevision'
|
||||
[string]$landscapeValues[0].scopeId | Should Be $script:environmentRevisionId
|
||||
$configDbNameValues[0].valueSourceType | Should Be 'Expression'
|
||||
}
|
||||
|
||||
It 'marks sensitive parameter values as secret references' {
|
||||
$setupCredential = Get-TestDefinition -Definitions $script:sharePointDefinitions -RevisionId $script:sharePointRevisionId -Kind 'Parameter' -Name 'SetupCredential'
|
||||
$setupCredentialValues = @(Invoke-TestMergeApiJson -Method GET -Path "configuration-values?definitionId=$($setupCredential.id)")
|
||||
$setupValue = ConvertFrom-TestJson -Json $setupCredentialValues[0].valueJson
|
||||
|
||||
@($setupCredentialValues).Count | Should Be 1
|
||||
$setupCredentialValues[0].valueSourceType | Should Be 'SecretReference'
|
||||
$setupValue.value.Provider | Should Be 'SecretManagement'
|
||||
$setupValue.value.Name | Should Be 'Windows/SharePoint/SetupAccount'
|
||||
}
|
||||
}
|
||||
@@ -1,421 +0,0 @@
|
||||
param(
|
||||
[string]$ApiBaseUrl = 'http://localhost:5286/api',
|
||||
|
||||
[string]$BgwRoot = ('F:\Kunden Auftr' + [char]0x00E4 + 'ge\BGW'),
|
||||
|
||||
[string]$DeploymentBatchId = '80000000-0000-0000-0000-000000000101',
|
||||
|
||||
[string]$MergeModulePath = 'F:\Projekte\Coding\PowerShell\Merge-DSCConfigurationData\Merge-DSCConfigurationData.psd1',
|
||||
|
||||
[string]$ResolveModulePath = 'F:\Projekte\Coding\PowerShell\Resolve-DSCConfigurationData\Resolve-DSCConfigurationData.psd1',
|
||||
|
||||
[int]$ApiTimeoutSec = 30,
|
||||
|
||||
[bool]$UseDefaultCredentials = $true
|
||||
)
|
||||
|
||||
$ErrorActionPreference = 'Stop'
|
||||
|
||||
function Invoke-TestBgwMergeApiJson {
|
||||
param(
|
||||
[ValidateSet('GET', 'POST', 'PUT', 'DELETE')]
|
||||
[string]$Method,
|
||||
|
||||
[string]$Path
|
||||
)
|
||||
|
||||
$uri = ('{0}/{1}' -f $ApiBaseUrl.TrimEnd('/'), $Path.TrimStart('/'))
|
||||
$parameters = @{
|
||||
Method = $Method
|
||||
Uri = $uri
|
||||
TimeoutSec = $ApiTimeoutSec
|
||||
ErrorAction = 'Stop'
|
||||
}
|
||||
|
||||
if ($UseDefaultCredentials) {
|
||||
$parameters.UseDefaultCredentials = $true
|
||||
}
|
||||
|
||||
try {
|
||||
Invoke-RestMethod @parameters
|
||||
}
|
||||
catch {
|
||||
$responseBody = '<empty response body>'
|
||||
if ($_.Exception.Response) {
|
||||
try {
|
||||
$stream = $_.Exception.Response.GetResponseStream()
|
||||
if ($stream) {
|
||||
$reader = [System.IO.StreamReader]::new($stream)
|
||||
$text = $reader.ReadToEnd()
|
||||
if (-not [string]::IsNullOrWhiteSpace($text)) {
|
||||
$responseBody = $text
|
||||
}
|
||||
}
|
||||
}
|
||||
catch {
|
||||
$responseBody = '<could not read response body>'
|
||||
}
|
||||
}
|
||||
|
||||
throw "API request failed. Method=[$Method], Uri=[$uri], Response=[$responseBody]. $($_.Exception.Message)"
|
||||
}
|
||||
}
|
||||
|
||||
function ConvertTo-TestBgwMergeConfigurationValue {
|
||||
param([object]$Value)
|
||||
|
||||
if ($null -eq $Value) {
|
||||
return $null
|
||||
}
|
||||
|
||||
if ($Value -is [string] -or $Value -is [bool] -or $Value -is [int] -or $Value -is [long] -or $Value -is [double] -or $Value -is [decimal]) {
|
||||
return $Value
|
||||
}
|
||||
|
||||
if ($Value -is [System.Collections.IDictionary]) {
|
||||
$result = [ordered]@{}
|
||||
foreach ($key in $Value.Keys) {
|
||||
$result[[string]$key] = ConvertTo-TestBgwMergeConfigurationValue -Value $Value[$key]
|
||||
}
|
||||
|
||||
Write-Output -NoEnumerate $result
|
||||
return
|
||||
}
|
||||
|
||||
if ($Value -is [pscustomobject]) {
|
||||
$result = [ordered]@{}
|
||||
foreach ($property in $Value.PSObject.Properties) {
|
||||
$result[$property.Name] = ConvertTo-TestBgwMergeConfigurationValue -Value $property.Value
|
||||
}
|
||||
|
||||
Write-Output -NoEnumerate $result
|
||||
return
|
||||
}
|
||||
|
||||
if ($Value -is [System.Collections.IEnumerable] -and $Value -isnot [string]) {
|
||||
$items = New-Object System.Collections.Generic.List[object]
|
||||
foreach ($item in $Value) {
|
||||
$items.Add((ConvertTo-TestBgwMergeConfigurationValue -Value $item))
|
||||
}
|
||||
|
||||
Write-Output -NoEnumerate $items.ToArray()
|
||||
return
|
||||
}
|
||||
|
||||
return $Value
|
||||
}
|
||||
|
||||
function ConvertFrom-TestBgwMergeTemplateJson {
|
||||
param([string]$JsonData)
|
||||
|
||||
$document = $JsonData | ConvertFrom-Json
|
||||
$metadata = ConvertTo-TestBgwMergeConfigurationValue -Value $document.metadata
|
||||
if ($null -eq $metadata) {
|
||||
$metadata = [ordered]@{}
|
||||
}
|
||||
|
||||
if (-not $metadata.Contains('TemplateType')) {
|
||||
$metadata['TemplateType'] = $document.templateType
|
||||
}
|
||||
|
||||
[ordered]@{
|
||||
Metadata = $metadata
|
||||
Parameters = ConvertTo-TestBgwMergeConfigurationValue -Value $document.parameters
|
||||
Variables = ConvertTo-TestBgwMergeConfigurationValue -Value $document.variables
|
||||
Resources = ConvertTo-TestBgwMergeConfigurationValue -Value $document.resources
|
||||
}
|
||||
}
|
||||
|
||||
function ConvertFrom-TestBgwMergeTargetAssignments {
|
||||
param([object[]]$TargetAssignments)
|
||||
|
||||
@($TargetAssignments | Sort-Object sortOrder | ForEach-Object {
|
||||
$nodeData = ConvertTo-TestBgwMergeConfigurationValue -Value ($_.nodeDataJson | ConvertFrom-Json)
|
||||
$node = @{}
|
||||
|
||||
foreach ($key in $nodeData.Keys) {
|
||||
if ($key -eq 'nodeName') {
|
||||
$node.NodeName = $nodeData[$key]
|
||||
}
|
||||
else {
|
||||
$node[$key] = $nodeData[$key]
|
||||
}
|
||||
}
|
||||
|
||||
$node
|
||||
})
|
||||
}
|
||||
|
||||
function ConvertTo-TestBgwMergeStableValue {
|
||||
param([object]$Value)
|
||||
|
||||
if ($null -eq $Value) {
|
||||
return $null
|
||||
}
|
||||
|
||||
if ($Value -is [string] -or $Value -is [bool] -or $Value -is [int] -or $Value -is [long] -or $Value -is [double] -or $Value -is [decimal]) {
|
||||
return $Value
|
||||
}
|
||||
|
||||
if ($Value -is [System.Collections.IDictionary]) {
|
||||
$result = [ordered]@{}
|
||||
foreach ($key in @($Value.Keys | Sort-Object)) {
|
||||
$result[[string]$key] = ConvertTo-TestBgwMergeStableValue -Value $Value[$key]
|
||||
}
|
||||
|
||||
Write-Output -NoEnumerate $result
|
||||
return
|
||||
}
|
||||
|
||||
if ($Value -is [pscustomobject]) {
|
||||
$result = [ordered]@{}
|
||||
foreach ($property in @($Value.PSObject.Properties | Sort-Object Name)) {
|
||||
$result[$property.Name] = ConvertTo-TestBgwMergeStableValue -Value $property.Value
|
||||
}
|
||||
|
||||
Write-Output -NoEnumerate $result
|
||||
return
|
||||
}
|
||||
|
||||
if ($Value -is [System.Collections.IEnumerable] -and $Value -isnot [string]) {
|
||||
$items = New-Object System.Collections.Generic.List[object]
|
||||
foreach ($item in $Value) {
|
||||
$items.Add((ConvertTo-TestBgwMergeStableValue -Value $item))
|
||||
}
|
||||
|
||||
Write-Output -NoEnumerate $items.ToArray()
|
||||
return
|
||||
}
|
||||
|
||||
return $Value
|
||||
}
|
||||
|
||||
function ConvertTo-TestBgwMergeStableJson {
|
||||
param([object]$Value)
|
||||
|
||||
(ConvertTo-TestBgwMergeStableValue -Value $Value) | ConvertTo-Json -Depth 100 -Compress
|
||||
}
|
||||
|
||||
function Invoke-TestBgwMergeSnapshotScript {
|
||||
param([string]$Script)
|
||||
|
||||
$encodedCommand = [Convert]::ToBase64String([System.Text.Encoding]::Unicode.GetBytes($Script))
|
||||
$output = & powershell.exe -NoProfile -ExecutionPolicy Bypass -EncodedCommand $encodedCommand
|
||||
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
throw "Snapshot PowerShell process failed with exit code [$LASTEXITCODE]. Output: $($output -join [Environment]::NewLine)"
|
||||
}
|
||||
|
||||
$json = ($output | Where-Object { -not [string]::IsNullOrWhiteSpace($_) }) -join [Environment]::NewLine
|
||||
if ([string]::IsNullOrWhiteSpace($json)) {
|
||||
throw 'Snapshot PowerShell process returned no JSON output.'
|
||||
}
|
||||
|
||||
$json | ConvertFrom-Json
|
||||
}
|
||||
|
||||
function New-TestBgwMergeSnapshotScript {
|
||||
param(
|
||||
[string]$ConfigurationDataPath,
|
||||
[switch]$BuildLocalBaseline
|
||||
)
|
||||
|
||||
$escapedBgwRoot = $BgwRoot.Replace("'", "''")
|
||||
$escapedMergeModulePath = $MergeModulePath.Replace("'", "''")
|
||||
$escapedResolveModulePath = $ResolveModulePath.Replace("'", "''")
|
||||
$escapedConfigurationDataPath = if ($ConfigurationDataPath) { $ConfigurationDataPath.Replace("'", "''") } else { '' }
|
||||
$buildLocalBaselineText = if ($BuildLocalBaseline) { 'True' } else { 'False' }
|
||||
|
||||
@"
|
||||
`$ErrorActionPreference = 'Stop'
|
||||
`$ProgressPreference = 'SilentlyContinue'
|
||||
Import-Module '$escapedMergeModulePath' -Force
|
||||
Import-Module '$escapedResolveModulePath' -Force
|
||||
|
||||
function ConvertTo-SnapshotStableValue {
|
||||
param([object]`$Value)
|
||||
|
||||
if (`$null -eq `$Value) { return `$null }
|
||||
if (`$Value -is [string] -or `$Value -is [bool] -or `$Value -is [int] -or `$Value -is [long] -or `$Value -is [double] -or `$Value -is [decimal]) { return `$Value }
|
||||
|
||||
if (`$Value -is [System.Collections.IDictionary]) {
|
||||
`$result = [ordered]@{}
|
||||
foreach (`$key in @(`$Value.Keys | Sort-Object)) {
|
||||
`$result[[string]`$key] = ConvertTo-SnapshotStableValue -Value `$Value[`$key]
|
||||
}
|
||||
Write-Output -NoEnumerate `$result
|
||||
return
|
||||
}
|
||||
|
||||
if (`$Value -is [pscustomobject]) {
|
||||
`$result = [ordered]@{}
|
||||
foreach (`$property in @(`$Value.PSObject.Properties | Sort-Object Name)) {
|
||||
`$result[`$property.Name] = ConvertTo-SnapshotStableValue -Value `$property.Value
|
||||
}
|
||||
Write-Output -NoEnumerate `$result
|
||||
return
|
||||
}
|
||||
|
||||
if (`$Value -is [System.Collections.IEnumerable] -and `$Value -isnot [string]) {
|
||||
`$items = New-Object System.Collections.Generic.List[object]
|
||||
foreach (`$item in `$Value) {
|
||||
`$items.Add((ConvertTo-SnapshotStableValue -Value `$item))
|
||||
}
|
||||
Write-Output -NoEnumerate `$items.ToArray()
|
||||
return
|
||||
}
|
||||
|
||||
return `$Value
|
||||
}
|
||||
|
||||
function ConvertTo-SnapshotStableJson {
|
||||
param([object]`$Value)
|
||||
(ConvertTo-SnapshotStableValue -Value `$Value) | ConvertTo-Json -Depth 100 -Compress
|
||||
}
|
||||
|
||||
if ('$buildLocalBaselineText' -eq 'True') {
|
||||
`$root = '$escapedBgwRoot'
|
||||
`$sourceTemplates = @(
|
||||
(Join-Path -Path `$root -ChildPath 'Environment\Test.psd1')
|
||||
(Join-Path -Path `$root -ChildPath 'Domain\Contoso.psd1')
|
||||
(Join-Path -Path `$root -ChildPath 'Service\SharePoint\Contoso.psd1')
|
||||
(Join-Path -Path `$root -ChildPath 'Stage\Install.psd1')
|
||||
)
|
||||
|
||||
`$allNodes = @(
|
||||
@{ NodeName = 'CLD-SHP-01'; RunCentralAdministration = `$true }
|
||||
@{ NodeName = 'CLD-SHP-02'; RunCentralAdministration = `$false }
|
||||
@{ NodeName = 'CLD-SHP-03'; RunCentralAdministration = `$false }
|
||||
)
|
||||
|
||||
`$configurationData = New-DSCConfigurationDataDeployment -Name 'Contoso-Test-SharePoint' -DeploymentId '8f6c2c1a' -SourceTemplatePath `$sourceTemplates -AllNodes `$allNodes
|
||||
}
|
||||
else {
|
||||
`$configurationData = Import-PowerShellDataFile -LiteralPath '$escapedConfigurationDataPath'
|
||||
}
|
||||
|
||||
`$resolved = Resolve-DSCConfigurationData -ConfigurationData `$configurationData -SkipSecrets
|
||||
`$snapshot = [ordered]@{
|
||||
ParametersJson = ConvertTo-SnapshotStableJson -Value `$configurationData.Parameters
|
||||
VariablesJson = ConvertTo-SnapshotStableJson -Value `$configurationData.Variables
|
||||
ResourcesJson = ConvertTo-SnapshotStableJson -Value `$configurationData.Resources
|
||||
DatabasePrefix = `$resolved.Variables.DatabasePrefix
|
||||
ServiceDbPrefix = `$resolved.Variables.ServiceDbPrefix
|
||||
ConfigDbName = `$resolved.Variables.ConfigDbName
|
||||
LcmConfigurationMode = `$resolved.Resources.NonNodeData.LocalConfigurationManager.ConfigurationMode
|
||||
AllNodes = @(`$resolved.Resources.AllNodes | Sort-Object NodeName | ForEach-Object {
|
||||
[ordered]@{
|
||||
NodeName = `$_.NodeName
|
||||
RunCentralAdministration = `$_.RunCentralAdministration
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
`$snapshot | ConvertTo-Json -Depth 100 -Compress
|
||||
"@
|
||||
}
|
||||
|
||||
function New-TestBgwMergeLocalSnapshot {
|
||||
Invoke-TestBgwMergeSnapshotScript -Script (New-TestBgwMergeSnapshotScript -BuildLocalBaseline)
|
||||
}
|
||||
|
||||
function New-TestBgwMergeSnapshotFromConfigurationData {
|
||||
param([hashtable]$ConfigurationData)
|
||||
|
||||
Import-Module $MergeModulePath -Force
|
||||
|
||||
$tempPath = Join-Path -Path ([System.IO.Path]::GetTempPath()) -ChildPath ("BgwMergeApiSnapshot-{0}.psd1" -f ([guid]::NewGuid().ToString('N')))
|
||||
try {
|
||||
Export-PowerShellDataFile -InputObject $ConfigurationData -Path $tempPath -Force
|
||||
Invoke-TestBgwMergeSnapshotScript -Script (New-TestBgwMergeSnapshotScript -ConfigurationDataPath $tempPath)
|
||||
}
|
||||
finally {
|
||||
if (Test-Path -LiteralPath $tempPath) {
|
||||
Remove-Item -LiteralPath $tempPath -Force
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function New-TestBgwMergeApiConfigurationData {
|
||||
param([object]$Composition)
|
||||
|
||||
Import-Module $MergeModulePath -Force
|
||||
|
||||
$mergedTemplateData = @{}
|
||||
|
||||
foreach ($selection in @($Composition.templateSelections | Sort-Object sortOrder)) {
|
||||
$templateData = ConvertFrom-TestBgwMergeTemplateJson -JsonData $selection.templateVersion.jsonData
|
||||
$mergedTemplateData = Merge-DSCConfigurationData -Template $mergedTemplateData -Deployment $templateData
|
||||
}
|
||||
|
||||
$deploymentData = @{
|
||||
Resources = @{
|
||||
AllNodes = ConvertFrom-TestBgwMergeTargetAssignments -TargetAssignments @($Composition.targetAssignments)
|
||||
}
|
||||
}
|
||||
|
||||
Merge-DSCConfigurationData -Template $mergedTemplateData -Deployment $deploymentData
|
||||
}
|
||||
|
||||
Describe 'BGW Test.Merge.ps1 API DemoData composition' {
|
||||
BeforeAll {
|
||||
$script:expectedTemplateAliases = @(
|
||||
'Environment-Test'
|
||||
'Domain-Contoso'
|
||||
'Service-SharePoint-Contoso'
|
||||
'Stage-Install'
|
||||
)
|
||||
|
||||
$script:expectedTemplateRoles = @(
|
||||
'Environment'
|
||||
'Domain'
|
||||
'Service'
|
||||
'Stage'
|
||||
)
|
||||
|
||||
$script:localSnapshot = New-TestBgwMergeLocalSnapshot
|
||||
$script:apiComposition = Invoke-TestBgwMergeApiJson -Method GET -Path "deployment-batches/$DeploymentBatchId/composition"
|
||||
$script:apiConfigurationData = New-TestBgwMergeApiConfigurationData -Composition $script:apiComposition
|
||||
$script:apiSnapshot = New-TestBgwMergeSnapshotFromConfigurationData -ConfigurationData $script:apiConfigurationData
|
||||
}
|
||||
|
||||
It 'loads the seeded deployment composition from the API' {
|
||||
$script:apiComposition.deploymentBatchId | Should Be $DeploymentBatchId
|
||||
@($script:apiComposition.templateSelections).Count | Should Be 4
|
||||
@($script:apiComposition.targetAssignments).Count | Should Be 3
|
||||
}
|
||||
|
||||
It 'keeps the template selection order from Test.Merge.ps1' {
|
||||
$aliases = @($script:apiComposition.templateSelections | Sort-Object sortOrder | ForEach-Object { $_.alias })
|
||||
$roles = @($script:apiComposition.templateSelections | Sort-Object sortOrder | ForEach-Object { $_.templateRole })
|
||||
|
||||
($aliases -join '|') | Should Be ($script:expectedTemplateAliases -join '|')
|
||||
($roles -join '|') | Should Be ($script:expectedTemplateRoles -join '|')
|
||||
}
|
||||
|
||||
It 'keeps the AllNodes data from Test.Merge.ps1' {
|
||||
$nodes = @($script:apiSnapshot.AllNodes | Sort-Object NodeName)
|
||||
|
||||
$nodes.Count | Should Be 3
|
||||
$nodes[0].NodeName | Should Be 'CLD-SHP-01'
|
||||
$nodes[0].RunCentralAdministration | Should Be $true
|
||||
$nodes[1].NodeName | Should Be 'CLD-SHP-02'
|
||||
$nodes[1].RunCentralAdministration | Should Be $false
|
||||
$nodes[2].NodeName | Should Be 'CLD-SHP-03'
|
||||
$nodes[2].RunCentralAdministration | Should Be $false
|
||||
}
|
||||
|
||||
It 'resolves the same core values as the local Test.Merge.ps1 baseline' {
|
||||
$script:apiSnapshot.DatabasePrefix | Should Be $script:localSnapshot.DatabasePrefix
|
||||
$script:apiSnapshot.ServiceDbPrefix | Should Be $script:localSnapshot.ServiceDbPrefix
|
||||
$script:apiSnapshot.ConfigDbName | Should Be $script:localSnapshot.ConfigDbName
|
||||
$script:apiSnapshot.LcmConfigurationMode | Should Be $script:localSnapshot.LcmConfigurationMode
|
||||
}
|
||||
|
||||
It 'matches merged Parameters, Variables and Resources' {
|
||||
$script:apiSnapshot.ParametersJson | Should Be $script:localSnapshot.ParametersJson
|
||||
$script:apiSnapshot.VariablesJson | Should Be $script:localSnapshot.VariablesJson
|
||||
$script:apiSnapshot.ResourcesJson | Should Be $script:localSnapshot.ResourcesJson
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,42 +0,0 @@
|
||||
[CmdletBinding()]
|
||||
param(
|
||||
[string]$ApiBaseUrl = 'http://localhost:5286/api',
|
||||
|
||||
[string]$BgwRoot = ('F:\Kunden Auftr' + [char]0x00E4 + 'ge\BGW'),
|
||||
|
||||
[string]$DeploymentBatchId = '80000000-0000-0000-0000-000000000101',
|
||||
|
||||
[string]$MergeModulePath = 'F:\Projekte\Coding\PowerShell\Merge-DSCConfigurationData\Merge-DSCConfigurationData.psd1',
|
||||
|
||||
[string]$ResolveModulePath = 'F:\Projekte\Coding\PowerShell\Resolve-DSCConfigurationData\Resolve-DSCConfigurationData.psd1',
|
||||
|
||||
[int]$ApiTimeoutSec = 30,
|
||||
|
||||
[switch]$UseDefaultCredentials = $true
|
||||
)
|
||||
|
||||
$ErrorActionPreference = 'Stop'
|
||||
|
||||
$testPath = Join-Path -Path $PSScriptRoot -ChildPath 'BgwMerge.Api.Tests.ps1'
|
||||
if (-not (Test-Path -LiteralPath $testPath -PathType Leaf)) {
|
||||
throw "Pester test file [$testPath] was not found."
|
||||
}
|
||||
|
||||
if (-not (Get-Command Invoke-Pester -ErrorAction SilentlyContinue)) {
|
||||
throw 'Pester is required. Install-Module Pester or run this on a machine where Pester is available.'
|
||||
}
|
||||
|
||||
$parameters = @{
|
||||
ApiBaseUrl = $ApiBaseUrl
|
||||
BgwRoot = $BgwRoot
|
||||
DeploymentBatchId = $DeploymentBatchId
|
||||
MergeModulePath = $MergeModulePath
|
||||
ResolveModulePath = $ResolveModulePath
|
||||
ApiTimeoutSec = $ApiTimeoutSec
|
||||
UseDefaultCredentials = [bool]$UseDefaultCredentials
|
||||
}
|
||||
|
||||
$result = Invoke-Pester -Script @{ Path = $testPath; Parameters = $parameters } -PassThru
|
||||
if ($result.FailedCount -gt 0) {
|
||||
throw "Pester test run failed. Passed=[$($result.PassedCount)] Failed=[$($result.FailedCount)] Skipped=[$($result.SkippedCount)]."
|
||||
}
|
||||
@@ -0,0 +1,137 @@
|
||||
param(
|
||||
[string]$ApiBaseUrl = 'http://localhost:5286/api',
|
||||
|
||||
[string]$ClientId = 'ssp-demo-worker',
|
||||
|
||||
[string]$ClientSecret = 'DemoOnly-DoNotUseInProduction!',
|
||||
|
||||
[int]$ApiTimeoutSec = 30
|
||||
)
|
||||
|
||||
$ErrorActionPreference = 'Stop'
|
||||
|
||||
function Invoke-TestApi {
|
||||
param(
|
||||
[ValidateSet('GET', 'POST', 'DELETE')]
|
||||
[string]$Method,
|
||||
|
||||
[string]$Path,
|
||||
|
||||
[object]$Body,
|
||||
|
||||
[string]$BearerToken
|
||||
)
|
||||
|
||||
$uri = ('{0}/{1}' -f $ApiBaseUrl.TrimEnd('/'), $Path.TrimStart('/'))
|
||||
$parameters = @{
|
||||
Method = $Method
|
||||
Uri = $uri
|
||||
TimeoutSec = $ApiTimeoutSec
|
||||
ErrorAction = 'Stop'
|
||||
}
|
||||
|
||||
if ($Body) {
|
||||
$parameters.Body = ($Body | ConvertTo-Json -Depth 10)
|
||||
$parameters.ContentType = 'application/json'
|
||||
}
|
||||
|
||||
if ($BearerToken) {
|
||||
$parameters.Headers = @{
|
||||
Authorization = "Bearer $BearerToken"
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
Invoke-RestMethod @parameters
|
||||
}
|
||||
catch {
|
||||
$responseBody = '<empty response body>'
|
||||
if ($_.Exception.Response) {
|
||||
try {
|
||||
$stream = $_.Exception.Response.GetResponseStream()
|
||||
if ($stream) {
|
||||
$reader = [System.IO.StreamReader]::new($stream)
|
||||
$text = $reader.ReadToEnd()
|
||||
if (-not [string]::IsNullOrWhiteSpace($text)) {
|
||||
$responseBody = $text
|
||||
}
|
||||
}
|
||||
}
|
||||
catch {
|
||||
$responseBody = '<could not read response body>'
|
||||
}
|
||||
}
|
||||
|
||||
throw "API request failed. Method=[$Method], Uri=[$uri], Response=[$responseBody]. $($_.Exception.Message)"
|
||||
}
|
||||
}
|
||||
|
||||
Describe 'On-prem client credentials API authentication' {
|
||||
It 'issues a bearer token for the seeded demo worker client' {
|
||||
$token = Invoke-TestApi -Method POST -Path 'auth/token' -Body @{
|
||||
clientId = $ClientId
|
||||
clientSecret = $ClientSecret
|
||||
scope = 'deployment.read template.read'
|
||||
}
|
||||
|
||||
$token.accessToken | Should Not BeNullOrEmpty
|
||||
$token.tokenType | Should Be 'Bearer'
|
||||
$token.expiresIn | Should BeGreaterThan 0
|
||||
$token.scope | Should Be 'deployment.read template.read'
|
||||
}
|
||||
|
||||
It 'allows bearer-token API calls without Windows authentication' {
|
||||
$token = Invoke-TestApi -Method POST -Path 'auth/token' -Body @{
|
||||
clientId = $ClientId
|
||||
clientSecret = $ClientSecret
|
||||
scope = 'deployment.read template.read'
|
||||
}
|
||||
|
||||
$definitions = @(Invoke-TestApi -Method GET -Path 'configuration-definitions?kind=Parameter' -BearerToken $token.accessToken)
|
||||
|
||||
@($definitions).Count | Should BeGreaterThan 0
|
||||
@($definitions | Where-Object { $_.kind -ne 'Parameter' }).Count | Should Be 0
|
||||
}
|
||||
|
||||
It 'creates, lists and revokes managed tokens through the token API' {
|
||||
$adminToken = Invoke-TestApi -Method POST -Path 'auth/token' -Body @{
|
||||
clientId = $ClientId
|
||||
clientSecret = $ClientSecret
|
||||
scope = 'token.manage token.admin deployment.read'
|
||||
}
|
||||
|
||||
$managedToken = Invoke-TestApi -Method POST -Path 'tokens/my' -BearerToken $adminToken.accessToken -Body @{
|
||||
name = 'Pester managed token'
|
||||
scope = 'deployment.read'
|
||||
}
|
||||
|
||||
$managedToken.id | Should Not BeNullOrEmpty
|
||||
$managedToken.accessToken | Should Not BeNullOrEmpty
|
||||
$managedToken.scope | Should Be 'deployment.read'
|
||||
|
||||
$myTokens = @(Invoke-TestApi -Method GET -Path 'tokens/my' -BearerToken $adminToken.accessToken)
|
||||
@($myTokens | Where-Object { $_.id -eq $managedToken.id }).Count | Should Be 1
|
||||
|
||||
$allTokens = @(Invoke-TestApi -Method GET -Path 'tokens/admin' -BearerToken $adminToken.accessToken)
|
||||
@($allTokens | Where-Object { $_.id -eq $managedToken.id }).Count | Should Be 1
|
||||
|
||||
$deletedToken = Invoke-TestApi -Method DELETE -Path ('tokens/my/{0}' -f $managedToken.id) -BearerToken $adminToken.accessToken
|
||||
|
||||
$deletedToken.id | Should Be $managedToken.id
|
||||
$deletedToken.revokedAt | Should Not BeNullOrEmpty
|
||||
$deletedToken.isActive | Should Be $false
|
||||
|
||||
$myTokensAfterDelete = @(Invoke-TestApi -Method GET -Path 'tokens/my' -BearerToken $adminToken.accessToken)
|
||||
$myTokenAfterDelete = $myTokensAfterDelete | Where-Object { [string]$_.id -eq [string]$managedToken.id } | Select-Object -First 1
|
||||
if ($myTokenAfterDelete) {
|
||||
$myTokenAfterDelete.isActive | Should Be $false
|
||||
}
|
||||
|
||||
$adminTokensAfterDelete = @(Invoke-TestApi -Method GET -Path 'tokens/admin' -BearerToken $adminToken.accessToken)
|
||||
$revokedToken = $adminTokensAfterDelete | Where-Object { [string]$_.id -eq [string]$managedToken.id } | Select-Object -First 1
|
||||
if ($revokedToken) {
|
||||
$revokedToken.revokedAt | Should Not BeNullOrEmpty
|
||||
$revokedToken.isActive | Should Be $false
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -19,6 +19,13 @@ namespace Microsoft.SelfService.Portal.Core.API.Context
|
||||
public DbSet<DeploymentGroupModel> DeploymentGroups { get; set; }
|
||||
public DbSet<TemplateModel> Templates { get; set; }
|
||||
public DbSet<TemplateVersionModel> TemplateVersions { get; set; }
|
||||
public DbSet<TemplateRevisionModel> TemplateRevisions { get; set; }
|
||||
public DbSet<ConfigurationDefinitionModel> ConfigurationDefinitions { get; set; }
|
||||
public DbSet<ConfigurationValueModel> ConfigurationValues { get; set; }
|
||||
public DbSet<DeploymentArtifactModel> DeploymentArtifacts { get; set; }
|
||||
public DbSet<CredentialSecretModel> CredentialSecrets { get; set; }
|
||||
public DbSet<ApiClientModel> ApiClients { get; set; }
|
||||
public DbSet<ApiTokenModel> ApiTokens { get; set; }
|
||||
public DbSet<DeploymentRuleModel> DeploymentRules { get; set; }
|
||||
public DbSet<DeploymentRuleStepModel> DeploymentRuleSteps { get; set; }
|
||||
public DbSet<DeploymentTemplateSelectionModel> DeploymentTemplateSelections { get; set; }
|
||||
@@ -148,6 +155,18 @@ namespace Microsoft.SelfService.Portal.Core.API.Context
|
||||
.WithMany(dg => dg.Deployments)
|
||||
.HasForeignKey(d => d.DeploymentGroupId);
|
||||
|
||||
modelBuilder.Entity<DeploymentModel>()
|
||||
.HasOne(deployment => deployment.TemplateRevision)
|
||||
.WithMany(revision => revision.Deployments)
|
||||
.HasForeignKey(deployment => deployment.TemplateRevisionId)
|
||||
.OnDelete(DeleteBehavior.Restrict);
|
||||
|
||||
modelBuilder.Entity<DeploymentModel>()
|
||||
.HasOne(deployment => deployment.CurrentArtifact)
|
||||
.WithMany()
|
||||
.HasForeignKey(deployment => deployment.CurrentArtifactId)
|
||||
.OnDelete(DeleteBehavior.NoAction);
|
||||
|
||||
modelBuilder.Entity<DeploymentGroupModel>()
|
||||
.HasOne(dg => dg.Template)
|
||||
.WithMany(t => t.DeploymentGroups)
|
||||
@@ -170,6 +189,12 @@ namespace Microsoft.SelfService.Portal.Core.API.Context
|
||||
.HasForeignKey(selection => selection.TemplateVersionId)
|
||||
.OnDelete(DeleteBehavior.Restrict);
|
||||
|
||||
modelBuilder.Entity<DeploymentTemplateSelectionModel>()
|
||||
.HasOne(selection => selection.TemplateRevision)
|
||||
.WithMany(revision => revision.DeploymentTemplateSelections)
|
||||
.HasForeignKey(selection => selection.TemplateRevisionId)
|
||||
.OnDelete(DeleteBehavior.Restrict);
|
||||
|
||||
modelBuilder.Entity<DeploymentTemplateSelectionModel>()
|
||||
.HasIndex(selection => new { selection.DeploymentGroupId, selection.SortOrder })
|
||||
.IsUnique();
|
||||
@@ -250,6 +275,161 @@ namespace Microsoft.SelfService.Portal.Core.API.Context
|
||||
modelBuilder.Entity<TemplateVersionModel>()
|
||||
.ToTable(table => table.HasCheckConstraint("CK_TemplateVersions_JsonData_IsJson", "ISJSON([JsonData]) = 1"));
|
||||
|
||||
modelBuilder.Entity<TemplateRevisionModel>()
|
||||
.HasOne(revision => revision.TemplateVersion)
|
||||
.WithMany(version => version.TemplateRevisions)
|
||||
.HasForeignKey(revision => revision.TemplateVersionId);
|
||||
|
||||
modelBuilder.Entity<TemplateRevisionModel>()
|
||||
.HasIndex(revision => new { revision.TemplateVersionId, revision.RevisionNumber })
|
||||
.IsUnique();
|
||||
|
||||
modelBuilder.Entity<TemplateRevisionModel>()
|
||||
.HasIndex(revision => revision.TemplateVersionId)
|
||||
.IsUnique()
|
||||
.HasFilter("[IsCurrent] = 1");
|
||||
|
||||
modelBuilder.Entity<TemplateRevisionModel>()
|
||||
.Property(revision => revision.JsonHash)
|
||||
.HasMaxLength(64);
|
||||
|
||||
modelBuilder.Entity<TemplateRevisionModel>()
|
||||
.Property(revision => revision.SchemaVersion)
|
||||
.HasMaxLength(32);
|
||||
|
||||
modelBuilder.Entity<TemplateRevisionModel>()
|
||||
.ToTable(table => table.HasCheckConstraint("CK_TemplateRevisions_JsonData_IsJson", "ISJSON([JsonData]) = 1"));
|
||||
|
||||
modelBuilder.Entity<ConfigurationDefinitionModel>()
|
||||
.HasOne(definition => definition.TemplateRevision)
|
||||
.WithMany(revision => revision.ConfigurationDefinitions)
|
||||
.HasForeignKey(definition => definition.TemplateRevisionId)
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
|
||||
modelBuilder.Entity<ConfigurationDefinitionModel>()
|
||||
.HasIndex(definition => new { definition.TemplateRevisionId, definition.Kind, definition.Name })
|
||||
.IsUnique()
|
||||
.HasFilter("[TemplateRevisionId] IS NOT NULL");
|
||||
|
||||
modelBuilder.Entity<ConfigurationDefinitionModel>()
|
||||
.Property(definition => definition.Kind)
|
||||
.HasMaxLength(32);
|
||||
|
||||
modelBuilder.Entity<ConfigurationDefinitionModel>()
|
||||
.Property(definition => definition.DefinitionHash)
|
||||
.HasMaxLength(64);
|
||||
|
||||
modelBuilder.Entity<ConfigurationDefinitionModel>()
|
||||
.ToTable(table => table.HasCheckConstraint("CK_ConfigurationDefinitions_PropertiesJson_IsJson", "ISJSON([PropertiesJson]) = 1"));
|
||||
|
||||
modelBuilder.Entity<ConfigurationValueModel>()
|
||||
.HasOne(value => value.ConfigurationDefinition)
|
||||
.WithMany(definition => definition.Values)
|
||||
.HasForeignKey(value => value.ConfigurationDefinitionId);
|
||||
|
||||
modelBuilder.Entity<ConfigurationValueModel>()
|
||||
.HasIndex(value => new { value.ConfigurationDefinitionId, value.ScopeType, value.ScopeId, value.SortOrder });
|
||||
|
||||
modelBuilder.Entity<ConfigurationValueModel>()
|
||||
.Property(value => value.ScopeType)
|
||||
.HasMaxLength(64);
|
||||
|
||||
modelBuilder.Entity<ConfigurationValueModel>()
|
||||
.Property(value => value.ValueSourceType)
|
||||
.HasMaxLength(64);
|
||||
|
||||
modelBuilder.Entity<ConfigurationValueModel>()
|
||||
.Property(value => value.ValueHash)
|
||||
.HasMaxLength(64);
|
||||
|
||||
modelBuilder.Entity<ConfigurationValueModel>()
|
||||
.ToTable(table => table.HasCheckConstraint("CK_ConfigurationValues_ValueJson_IsJson", "[ValueJson] IS NULL OR ISJSON([ValueJson]) = 1"));
|
||||
|
||||
modelBuilder.Entity<DeploymentArtifactModel>()
|
||||
.HasOne(artifact => artifact.DeploymentGroup)
|
||||
.WithMany(group => group.Artifacts)
|
||||
.HasForeignKey(artifact => artifact.DeploymentGroupId)
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
|
||||
modelBuilder.Entity<DeploymentArtifactModel>()
|
||||
.HasOne(artifact => artifact.Deployment)
|
||||
.WithMany(deployment => deployment.Artifacts)
|
||||
.HasForeignKey(artifact => new { artifact.TargetId, artifact.DeploymentGroupId })
|
||||
.HasPrincipalKey(deployment => new { deployment.TargetId, deployment.DeploymentGroupId })
|
||||
.OnDelete(DeleteBehavior.NoAction);
|
||||
|
||||
modelBuilder.Entity<DeploymentArtifactModel>()
|
||||
.HasOne(artifact => artifact.Target)
|
||||
.WithMany()
|
||||
.HasForeignKey(artifact => artifact.TargetId)
|
||||
.OnDelete(DeleteBehavior.Restrict);
|
||||
|
||||
modelBuilder.Entity<DeploymentArtifactModel>()
|
||||
.Property(artifact => artifact.ArtifactType)
|
||||
.HasMaxLength(64);
|
||||
|
||||
modelBuilder.Entity<DeploymentArtifactModel>()
|
||||
.Property(artifact => artifact.InputHash)
|
||||
.HasMaxLength(64);
|
||||
|
||||
modelBuilder.Entity<DeploymentArtifactModel>()
|
||||
.Property(artifact => artifact.OutputHash)
|
||||
.HasMaxLength(64);
|
||||
|
||||
modelBuilder.Entity<DeploymentArtifactModel>()
|
||||
.ToTable(table => table.HasCheckConstraint("CK_DeploymentArtifacts_DeploymentJson_IsJson", "ISJSON([DeploymentJson]) = 1"));
|
||||
|
||||
modelBuilder.Entity<DeploymentArtifactModel>()
|
||||
.ToTable(table => table.HasCheckConstraint("CK_DeploymentArtifacts_SourceJson_IsJson", "[SourceJson] IS NULL OR ISJSON([SourceJson]) = 1"));
|
||||
|
||||
modelBuilder.Entity<DeploymentArtifactModel>()
|
||||
.ToTable(table => table.HasCheckConstraint("CK_DeploymentArtifacts_ResolvedJson_IsJson", "[ResolvedJson] IS NULL OR ISJSON([ResolvedJson]) = 1"));
|
||||
|
||||
modelBuilder.Entity<DeploymentArtifactModel>()
|
||||
.ToTable(table => table.HasCheckConstraint("CK_DeploymentArtifacts_SourceSnapshotJson_IsJson", "[SourceSnapshotJson] IS NULL OR ISJSON([SourceSnapshotJson]) = 1"));
|
||||
|
||||
modelBuilder.Entity<CredentialSecretModel>()
|
||||
.HasIndex(secret => secret.Name)
|
||||
.IsUnique();
|
||||
|
||||
modelBuilder.Entity<CredentialSecretModel>()
|
||||
.ToTable(table => table.HasCheckConstraint("CK_CredentialSecrets_MetadataJson_IsJson", "[MetadataJson] IS NULL OR ISJSON([MetadataJson]) = 1"));
|
||||
|
||||
modelBuilder.Entity<ApiClientModel>()
|
||||
.HasIndex(client => client.ClientId)
|
||||
.IsUnique();
|
||||
|
||||
modelBuilder.Entity<ApiClientModel>()
|
||||
.Property(client => client.ClientId)
|
||||
.HasMaxLength(128);
|
||||
|
||||
modelBuilder.Entity<ApiClientModel>()
|
||||
.ToTable(table => table.HasCheckConstraint("CK_ApiClients_ScopesJson_IsJson", "ISJSON([ScopesJson]) = 1"));
|
||||
|
||||
modelBuilder.Entity<ApiTokenModel>()
|
||||
.HasOne(token => token.ApiClient)
|
||||
.WithMany()
|
||||
.HasForeignKey(token => token.ApiClientId)
|
||||
.OnDelete(DeleteBehavior.SetNull);
|
||||
|
||||
modelBuilder.Entity<ApiTokenModel>()
|
||||
.HasIndex(token => token.Jti)
|
||||
.IsUnique();
|
||||
|
||||
modelBuilder.Entity<ApiTokenModel>()
|
||||
.HasIndex(token => new { token.SubjectType, token.Subject });
|
||||
|
||||
modelBuilder.Entity<ApiTokenModel>()
|
||||
.Property(token => token.Jti)
|
||||
.HasMaxLength(64);
|
||||
|
||||
modelBuilder.Entity<ApiTokenModel>()
|
||||
.Property(token => token.SubjectType)
|
||||
.HasMaxLength(32);
|
||||
|
||||
modelBuilder.Entity<ApiTokenModel>()
|
||||
.ToTable(table => table.HasCheckConstraint("CK_ApiTokens_ScopesJson_IsJson", "ISJSON([ScopesJson]) = 1"));
|
||||
|
||||
modelBuilder.Entity<DeploymentRuleStepModel>()
|
||||
.HasOne(step => step.DeploymentRule)
|
||||
.WithMany(rule => rule.Steps)
|
||||
|
||||
+366
-10
@@ -1,5 +1,9 @@
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.SelfService.Portal.Core.API.Models;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
using System.Text.Json;
|
||||
using Microsoft.SelfService.Portal.Core.API.Services;
|
||||
|
||||
namespace Microsoft.SelfService.Portal.Core.API.Context
|
||||
{
|
||||
@@ -61,6 +65,15 @@ namespace Microsoft.SelfService.Portal.Core.API.Context
|
||||
internal static readonly Guid TemplateBgwSharePointContosoVersionId = Guid.Parse("71000000-0000-0000-0000-000000000103");
|
||||
internal static readonly Guid TemplateBgwStageInstallVersionId = Guid.Parse("71000000-0000-0000-0000-000000000104");
|
||||
|
||||
internal static readonly Guid TemplateActiveDirectoryRevisionId = Guid.Parse("72000000-0000-0000-0000-000000000001");
|
||||
internal static readonly Guid TemplateSqlServerRevisionId = Guid.Parse("72000000-0000-0000-0000-000000000002");
|
||||
internal static readonly Guid TemplateSharePointRevisionId = Guid.Parse("72000000-0000-0000-0000-000000000003");
|
||||
internal static readonly Guid TemplateTeamsRevisionId = Guid.Parse("72000000-0000-0000-0000-000000000004");
|
||||
internal static readonly Guid TemplateBgwEnvironmentTestRevisionId = Guid.Parse("72000000-0000-0000-0000-000000000101");
|
||||
internal static readonly Guid TemplateBgwDomainContosoRevisionId = Guid.Parse("72000000-0000-0000-0000-000000000102");
|
||||
internal static readonly Guid TemplateBgwSharePointContosoRevisionId = Guid.Parse("72000000-0000-0000-0000-000000000103");
|
||||
internal static readonly Guid TemplateBgwStageInstallRevisionId = Guid.Parse("72000000-0000-0000-0000-000000000104");
|
||||
|
||||
internal static readonly Guid DeploymentBatchSharePointId = Guid.Parse("80000000-0000-0000-0000-000000000001");
|
||||
internal static readonly Guid DeploymentBatchBgwMergeId = Guid.Parse("80000000-0000-0000-0000-000000000101");
|
||||
internal static readonly Guid DeploymentSp01Id = Guid.Parse("81000000-0000-0000-0000-000000000001");
|
||||
@@ -81,6 +94,15 @@ namespace Microsoft.SelfService.Portal.Core.API.Context
|
||||
internal static readonly Guid DeploymentTargetBgwSp02Id = Guid.Parse("84000000-0000-0000-0000-000000000102");
|
||||
internal static readonly Guid DeploymentTargetBgwSp03Id = Guid.Parse("84000000-0000-0000-0000-000000000103");
|
||||
|
||||
internal static readonly Guid DeploymentArtifactBgwResolvedId = Guid.Parse("85000000-0000-0000-0000-000000000101");
|
||||
|
||||
internal static readonly Guid CredentialSharePointSetupId = Guid.Parse("90000000-0000-0000-0000-000000000001");
|
||||
internal static readonly Guid CredentialSharePointFarmId = Guid.Parse("90000000-0000-0000-0000-000000000002");
|
||||
internal static readonly Guid CredentialSharePointFarmPassphraseId = Guid.Parse("90000000-0000-0000-0000-000000000003");
|
||||
internal static readonly Guid CredentialSharePointDefaultServiceId = Guid.Parse("90000000-0000-0000-0000-000000000004");
|
||||
internal static readonly Guid CredentialSharePointSearchId = Guid.Parse("90000000-0000-0000-0000-000000000005");
|
||||
internal static readonly Guid ApiClientDemoWorkerId = Guid.Parse("91000000-0000-0000-0000-000000000001");
|
||||
|
||||
internal static void Seed(ModelBuilder modelBuilder)
|
||||
{
|
||||
modelBuilder.Entity<EnvironmentModel>().HasData(Environments());
|
||||
@@ -94,11 +116,17 @@ namespace Microsoft.SelfService.Portal.Core.API.Context
|
||||
modelBuilder.Entity<DeploymentRuleStepModel>().HasData(DeploymentRuleSteps());
|
||||
modelBuilder.Entity<TemplateModel>().HasData(Templates());
|
||||
modelBuilder.Entity<TemplateVersionModel>().HasData(TemplateVersions());
|
||||
modelBuilder.Entity<TemplateRevisionModel>().HasData(TemplateRevisions());
|
||||
modelBuilder.Entity<ConfigurationDefinitionModel>().HasData(ConfigurationDefinitions());
|
||||
modelBuilder.Entity<ConfigurationValueModel>().HasData(ConfigurationValues());
|
||||
modelBuilder.Entity<DeploymentGroupModel>().HasData(DeploymentBatches());
|
||||
modelBuilder.Entity<DeploymentModel>().HasData(Deployments());
|
||||
modelBuilder.Entity<DeploymentTemplateSelectionModel>().HasData(DeploymentTemplateSelections());
|
||||
modelBuilder.Entity<DeploymentParameterValueModel>().HasData(DeploymentParameterValues());
|
||||
modelBuilder.Entity<DeploymentTargetAssignmentModel>().HasData(DeploymentTargetAssignments());
|
||||
modelBuilder.Entity<DeploymentArtifactModel>().HasData(DeploymentArtifacts());
|
||||
modelBuilder.Entity<CredentialSecretModel>().HasData(CredentialSecrets());
|
||||
modelBuilder.Entity<ApiClientModel>().HasData(ApiClients());
|
||||
}
|
||||
|
||||
private static object[] Environments() =>
|
||||
@@ -197,6 +225,18 @@ namespace Microsoft.SelfService.Portal.Core.API.Context
|
||||
TemplateVersion(TemplateBgwStageInstallVersionId, TemplateBgwStageInstallId, BgwStageInstallTemplateJson)
|
||||
];
|
||||
|
||||
private static object[] TemplateRevisions() =>
|
||||
[
|
||||
TemplateRevision(TemplateActiveDirectoryRevisionId, TemplateActiveDirectoryVersionId, ActiveDirectoryTemplateJson),
|
||||
TemplateRevision(TemplateSqlServerRevisionId, TemplateSqlServerVersionId, SqlServerTemplateJson),
|
||||
TemplateRevision(TemplateSharePointRevisionId, TemplateSharePointVersionId, SharePointTemplateJson),
|
||||
TemplateRevision(TemplateTeamsRevisionId, TemplateTeamsVersionId, TeamsTemplateJson),
|
||||
TemplateRevision(TemplateBgwEnvironmentTestRevisionId, TemplateBgwEnvironmentTestVersionId, BgwEnvironmentTestTemplateJson),
|
||||
TemplateRevision(TemplateBgwDomainContosoRevisionId, TemplateBgwDomainContosoVersionId, BgwDomainContosoTemplateJson),
|
||||
TemplateRevision(TemplateBgwSharePointContosoRevisionId, TemplateBgwSharePointContosoVersionId, BgwSharePointContosoTemplateJson),
|
||||
TemplateRevision(TemplateBgwStageInstallRevisionId, TemplateBgwStageInstallVersionId, BgwStageInstallTemplateJson)
|
||||
];
|
||||
|
||||
private static object[] DeploymentBatches() =>
|
||||
[
|
||||
Base(new DeploymentGroupModel { Id = DeploymentBatchSharePointId, TemplateId = TemplateSharePointId, DeploymentRuleId = RuleStandardId, Status = QueueJobStatus.Pending }),
|
||||
@@ -205,20 +245,20 @@ namespace Microsoft.SelfService.Portal.Core.API.Context
|
||||
|
||||
private static object[] Deployments() =>
|
||||
[
|
||||
Base(new DeploymentModel { Id = DeploymentSp01Id, DeploymentGroupId = DeploymentBatchSharePointId, TargetId = VmSp01Id, Status = QueueJobStatus.Pending, JSONData = "{\"role\":\"WebFrontEnd\"}" }),
|
||||
Base(new DeploymentModel { Id = DeploymentSp02Id, DeploymentGroupId = DeploymentBatchSharePointId, TargetId = VmSp02Id, Status = QueueJobStatus.Pending, JSONData = "{\"role\":\"Application\"}" }),
|
||||
Base(new DeploymentModel { Id = DeploymentBgwSp01Id, DeploymentGroupId = DeploymentBatchBgwMergeId, TargetId = TargetBgwSp01Id, Status = QueueJobStatus.Pending, JSONData = "{\"role\":\"Node\"}" }),
|
||||
Base(new DeploymentModel { Id = DeploymentBgwSp02Id, DeploymentGroupId = DeploymentBatchBgwMergeId, TargetId = TargetBgwSp02Id, Status = QueueJobStatus.Pending, JSONData = "{\"role\":\"Node\"}" }),
|
||||
Base(new DeploymentModel { Id = DeploymentBgwSp03Id, DeploymentGroupId = DeploymentBatchBgwMergeId, TargetId = TargetBgwSp03Id, Status = QueueJobStatus.Pending, JSONData = "{\"role\":\"Node\"}" })
|
||||
Base(new DeploymentModel { Id = DeploymentSp01Id, DeploymentGroupId = DeploymentBatchSharePointId, TargetId = VmSp01Id, TemplateRevisionId = TemplateSharePointRevisionId, Status = QueueJobStatus.Pending, JSONData = "{\"role\":\"WebFrontEnd\"}" }),
|
||||
Base(new DeploymentModel { Id = DeploymentSp02Id, DeploymentGroupId = DeploymentBatchSharePointId, TargetId = VmSp02Id, TemplateRevisionId = TemplateSharePointRevisionId, Status = QueueJobStatus.Pending, JSONData = "{\"role\":\"Application\"}" }),
|
||||
Base(new DeploymentModel { Id = DeploymentBgwSp01Id, DeploymentGroupId = DeploymentBatchBgwMergeId, TargetId = TargetBgwSp01Id, TemplateRevisionId = TemplateBgwSharePointContosoRevisionId, Status = QueueJobStatus.Pending, JSONData = "{\"role\":\"Node\"}" }),
|
||||
Base(new DeploymentModel { Id = DeploymentBgwSp02Id, DeploymentGroupId = DeploymentBatchBgwMergeId, TargetId = TargetBgwSp02Id, TemplateRevisionId = TemplateBgwSharePointContosoRevisionId, Status = QueueJobStatus.Pending, JSONData = "{\"role\":\"Node\"}" }),
|
||||
Base(new DeploymentModel { Id = DeploymentBgwSp03Id, DeploymentGroupId = DeploymentBatchBgwMergeId, TargetId = TargetBgwSp03Id, TemplateRevisionId = TemplateBgwSharePointContosoRevisionId, Status = QueueJobStatus.Pending, JSONData = "{\"role\":\"Node\"}" })
|
||||
];
|
||||
|
||||
private static object[] DeploymentTemplateSelections() =>
|
||||
[
|
||||
Base(new DeploymentTemplateSelectionModel { Id = DeploymentSharePointTemplateSelectionId, DeploymentGroupId = DeploymentBatchSharePointId, TemplateVersionId = TemplateSharePointVersionId, TemplateRole = "Service", SortOrder = 10, Alias = "SharePoint" }),
|
||||
Base(new DeploymentTemplateSelectionModel { Id = DeploymentBgwEnvironmentSelectionId, DeploymentGroupId = DeploymentBatchBgwMergeId, TemplateVersionId = TemplateBgwEnvironmentTestVersionId, TemplateRole = "Environment", SortOrder = 10, Alias = "Environment-Test" }),
|
||||
Base(new DeploymentTemplateSelectionModel { Id = DeploymentBgwDomainSelectionId, DeploymentGroupId = DeploymentBatchBgwMergeId, TemplateVersionId = TemplateBgwDomainContosoVersionId, TemplateRole = "Domain", SortOrder = 20, Alias = "Domain-Contoso" }),
|
||||
Base(new DeploymentTemplateSelectionModel { Id = DeploymentBgwSharePointSelectionId, DeploymentGroupId = DeploymentBatchBgwMergeId, TemplateVersionId = TemplateBgwSharePointContosoVersionId, TemplateRole = "Service", SortOrder = 30, Alias = "Service-SharePoint-Contoso" }),
|
||||
Base(new DeploymentTemplateSelectionModel { Id = DeploymentBgwStageSelectionId, DeploymentGroupId = DeploymentBatchBgwMergeId, TemplateVersionId = TemplateBgwStageInstallVersionId, TemplateRole = "Stage", SortOrder = 40, Alias = "Stage-Install" })
|
||||
Base(new DeploymentTemplateSelectionModel { Id = DeploymentSharePointTemplateSelectionId, DeploymentGroupId = DeploymentBatchSharePointId, TemplateVersionId = TemplateSharePointVersionId, TemplateRevisionId = TemplateSharePointRevisionId, TemplateRole = "Service", SortOrder = 10, Alias = "SharePoint" }),
|
||||
Base(new DeploymentTemplateSelectionModel { Id = DeploymentBgwEnvironmentSelectionId, DeploymentGroupId = DeploymentBatchBgwMergeId, TemplateVersionId = TemplateBgwEnvironmentTestVersionId, TemplateRevisionId = TemplateBgwEnvironmentTestRevisionId, TemplateRole = "Environment", SortOrder = 10, Alias = "Environment-Test" }),
|
||||
Base(new DeploymentTemplateSelectionModel { Id = DeploymentBgwDomainSelectionId, DeploymentGroupId = DeploymentBatchBgwMergeId, TemplateVersionId = TemplateBgwDomainContosoVersionId, TemplateRevisionId = TemplateBgwDomainContosoRevisionId, TemplateRole = "Domain", SortOrder = 20, Alias = "Domain-Contoso" }),
|
||||
Base(new DeploymentTemplateSelectionModel { Id = DeploymentBgwSharePointSelectionId, DeploymentGroupId = DeploymentBatchBgwMergeId, TemplateVersionId = TemplateBgwSharePointContosoVersionId, TemplateRevisionId = TemplateBgwSharePointContosoRevisionId, TemplateRole = "Service", SortOrder = 30, Alias = "Service-SharePoint-Contoso" }),
|
||||
Base(new DeploymentTemplateSelectionModel { Id = DeploymentBgwStageSelectionId, DeploymentGroupId = DeploymentBatchBgwMergeId, TemplateVersionId = TemplateBgwStageInstallVersionId, TemplateRevisionId = TemplateBgwStageInstallRevisionId, TemplateRole = "Stage", SortOrder = 40, Alias = "Stage-Install" })
|
||||
];
|
||||
|
||||
private static object[] DeploymentParameterValues() =>
|
||||
@@ -236,6 +276,99 @@ namespace Microsoft.SelfService.Portal.Core.API.Context
|
||||
Base(new DeploymentTargetAssignmentModel { Id = DeploymentTargetBgwSp03Id, DeploymentGroupId = DeploymentBatchBgwMergeId, TargetId = TargetBgwSp03Id, RoleKey = "Node", SortOrder = 30, NodeDataJson = "{\"nodeName\":\"CLD-SHP-03\",\"RunCentralAdministration\":false}" })
|
||||
];
|
||||
|
||||
private static object[] ConfigurationDefinitions()
|
||||
{
|
||||
return TemplateRevisionJsonDocuments()
|
||||
.SelectMany(template => ExtractConfigurationDefinitions(template.RevisionId, template.JsonData))
|
||||
.Select(definition => Base(definition))
|
||||
.Cast<object>()
|
||||
.ToArray();
|
||||
}
|
||||
|
||||
private static object[] ConfigurationValues()
|
||||
{
|
||||
return TemplateRevisionJsonDocuments()
|
||||
.SelectMany(template => ExtractConfigurationValues(template.RevisionId, template.JsonData))
|
||||
.Select(value => Base(value))
|
||||
.Cast<object>()
|
||||
.ToArray();
|
||||
}
|
||||
|
||||
private static object[] DeploymentArtifacts()
|
||||
{
|
||||
var deploymentJson = """
|
||||
{
|
||||
"metadata": {
|
||||
"name": "Contoso-Test-SharePoint",
|
||||
"deploymentId": "8f6c2c1a",
|
||||
"source": "DemoData"
|
||||
},
|
||||
"parameters": {
|
||||
"DatabasePrefix": "SharePoint_Contoso_Test"
|
||||
},
|
||||
"variables": {
|
||||
"DatabasePrefix": "SharePoint_Contoso_Test",
|
||||
"ServiceDbPrefix": "SharePoint_Contoso_Test_Services",
|
||||
"ConfigDbName": "SharePoint_Contoso_Test_Farm_Config"
|
||||
},
|
||||
"resources": {
|
||||
"AllNodes": [
|
||||
{ "NodeName": "CLD-SHP-01", "RunCentralAdministration": true },
|
||||
{ "NodeName": "CLD-SHP-02", "RunCentralAdministration": false },
|
||||
{ "NodeName": "CLD-SHP-03", "RunCentralAdministration": false }
|
||||
],
|
||||
"NonNodeData": {
|
||||
"LocalConfigurationManager": {
|
||||
"ConfigurationMode": "ApplyOnly"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
""";
|
||||
|
||||
var sourceSnapshotJson = BgwMergeSourceSnapshotJson();
|
||||
|
||||
return
|
||||
[
|
||||
Base(new DeploymentArtifactModel
|
||||
{
|
||||
Id = DeploymentArtifactBgwResolvedId,
|
||||
DeploymentGroupId = DeploymentBatchBgwMergeId,
|
||||
ArtifactType = DeploymentArtifactTypes.ResolvedConfigurationData,
|
||||
Status = QueueJobStatus.Pending,
|
||||
DeploymentJson = deploymentJson,
|
||||
SourceJson = "{\"source\":\"DemoData\",\"composition\":\"Test.Merge.ps1\"}",
|
||||
ResolvedJson = deploymentJson,
|
||||
SourceSnapshotJson = sourceSnapshotJson,
|
||||
InputHash = TemplateVersionModel.ComputeSha256(sourceSnapshotJson),
|
||||
OutputHash = TemplateVersionModel.ComputeSha256(deploymentJson),
|
||||
IsStale = false
|
||||
})
|
||||
];
|
||||
}
|
||||
|
||||
private static object[] CredentialSecrets() =>
|
||||
[
|
||||
CredentialSecret(CredentialSharePointSetupId, "Windows/SharePoint/SetupAccount", "CONTOSO\\svc_sp_setup"),
|
||||
CredentialSecret(CredentialSharePointFarmId, "Windows/SharePoint/FarmAccount", "CONTOSO\\svc_sp_farm"),
|
||||
CredentialSecret(CredentialSharePointFarmPassphraseId, "Windows/SharePoint/FarmPassphrase", null, "Secret"),
|
||||
CredentialSecret(CredentialSharePointDefaultServiceId, "Windows/SharePoint/DefaultServiceAccount", "CONTOSO\\svc_sp_service"),
|
||||
CredentialSecret(CredentialSharePointSearchId, "Windows/SharePoint/SearchAccount", "CONTOSO\\svc_sp_search")
|
||||
];
|
||||
|
||||
private static object[] ApiClients() =>
|
||||
[
|
||||
Base(new ApiClientModel
|
||||
{
|
||||
Id = ApiClientDemoWorkerId,
|
||||
ClientId = "ssp-demo-worker",
|
||||
Name = "Demo Worker Client",
|
||||
SecretHash = ApiClientSecretHasher.HashSecretForDemoData("DemoOnly-DoNotUseInProduction!", "ssp-demo-worker"),
|
||||
ScopesJson = "[\"deployment.read\",\"deployment.write\",\"queue.process\",\"template.read\",\"credential.resolve\",\"token.manage\",\"token.admin\"]",
|
||||
IsEnabled = true
|
||||
})
|
||||
];
|
||||
|
||||
private static TemplateVersionModel TemplateVersion(Guid id, Guid templateId, string jsonData)
|
||||
{
|
||||
return Base(new TemplateVersionModel
|
||||
@@ -252,6 +385,229 @@ namespace Microsoft.SelfService.Portal.Core.API.Context
|
||||
});
|
||||
}
|
||||
|
||||
private static TemplateRevisionModel TemplateRevision(Guid id, Guid templateVersionId, string jsonData)
|
||||
{
|
||||
return Base(new TemplateRevisionModel
|
||||
{
|
||||
Id = id,
|
||||
TemplateVersionId = templateVersionId,
|
||||
RevisionNumber = 1,
|
||||
JsonData = jsonData,
|
||||
JsonHash = TemplateVersionModel.ComputeSha256(jsonData),
|
||||
SchemaVersion = "1.0",
|
||||
IsCurrent = true,
|
||||
IsPublished = true,
|
||||
PublishedAt = Timestamp,
|
||||
PublishedBy = Owner
|
||||
});
|
||||
}
|
||||
|
||||
private static CredentialSecretModel CredentialSecret(Guid id, string name, string? userName, string secretType = "Credential")
|
||||
{
|
||||
return Base(new CredentialSecretModel
|
||||
{
|
||||
Id = id,
|
||||
Name = name,
|
||||
UserName = userName,
|
||||
SecretValue = "DemoOnly-DoNotUseInProduction!",
|
||||
SecretType = secretType,
|
||||
MetadataJson = "{\"environment\":\"Demo\",\"plaintext\":true}",
|
||||
IsEnabled = true
|
||||
});
|
||||
}
|
||||
|
||||
private static IEnumerable<(Guid RevisionId, string JsonData)> TemplateRevisionJsonDocuments()
|
||||
{
|
||||
yield return (TemplateActiveDirectoryRevisionId, ActiveDirectoryTemplateJson);
|
||||
yield return (TemplateSqlServerRevisionId, SqlServerTemplateJson);
|
||||
yield return (TemplateSharePointRevisionId, SharePointTemplateJson);
|
||||
yield return (TemplateTeamsRevisionId, TeamsTemplateJson);
|
||||
yield return (TemplateBgwEnvironmentTestRevisionId, BgwEnvironmentTestTemplateJson);
|
||||
yield return (TemplateBgwDomainContosoRevisionId, BgwDomainContosoTemplateJson);
|
||||
yield return (TemplateBgwSharePointContosoRevisionId, BgwSharePointContosoTemplateJson);
|
||||
yield return (TemplateBgwStageInstallRevisionId, BgwStageInstallTemplateJson);
|
||||
}
|
||||
|
||||
private static IEnumerable<ConfigurationDefinitionModel> ExtractConfigurationDefinitions(Guid revisionId, string jsonData)
|
||||
{
|
||||
using var document = JsonDocument.Parse(jsonData);
|
||||
var root = document.RootElement;
|
||||
|
||||
foreach (var definition in ExtractConfigurationDefinitions(revisionId, root, "parameters", ConfigurationDefinitionKinds.Parameter))
|
||||
yield return definition;
|
||||
|
||||
foreach (var definition in ExtractConfigurationDefinitions(revisionId, root, "variables", ConfigurationDefinitionKinds.Variable))
|
||||
yield return definition;
|
||||
}
|
||||
|
||||
private static IEnumerable<ConfigurationDefinitionModel> ExtractConfigurationDefinitions(Guid revisionId, JsonElement root, string propertyName, string kind)
|
||||
{
|
||||
if (!root.TryGetProperty(propertyName, out var definitions) || definitions.ValueKind != JsonValueKind.Object)
|
||||
yield break;
|
||||
|
||||
foreach (var property in definitions.EnumerateObject())
|
||||
{
|
||||
var propertiesJson = kind == ConfigurationDefinitionKinds.Variable
|
||||
? $$"""{"Expression":{{property.Value.GetRawText()}}}"""
|
||||
: property.Value.GetRawText();
|
||||
yield return new ConfigurationDefinitionModel
|
||||
{
|
||||
Id = ConfigurationDefinitionId(revisionId, kind, property.Name),
|
||||
TemplateRevisionId = revisionId,
|
||||
Kind = kind,
|
||||
Name = property.Name,
|
||||
PropertiesJson = propertiesJson,
|
||||
DefinitionHash = TemplateVersionModel.ComputeSha256(propertiesJson)
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
private static IEnumerable<ConfigurationValueModel> ExtractConfigurationValues(Guid revisionId, string jsonData)
|
||||
{
|
||||
using var document = JsonDocument.Parse(jsonData);
|
||||
var root = document.RootElement;
|
||||
|
||||
foreach (var value in ExtractParameterValues(revisionId, root))
|
||||
yield return value;
|
||||
|
||||
foreach (var value in ExtractVariableValues(revisionId, root))
|
||||
yield return value;
|
||||
}
|
||||
|
||||
private static IEnumerable<ConfigurationValueModel> ExtractParameterValues(Guid revisionId, JsonElement root)
|
||||
{
|
||||
if (!root.TryGetProperty("parameters", out var parameters) || parameters.ValueKind != JsonValueKind.Object)
|
||||
yield break;
|
||||
|
||||
var sortOrder = 0;
|
||||
foreach (var parameter in parameters.EnumerateObject())
|
||||
{
|
||||
sortOrder += 10;
|
||||
|
||||
var valueSourceType = ConfigurationValueSourceTypes.Static;
|
||||
var valueJson = "{}";
|
||||
|
||||
if (parameter.Value.ValueKind == JsonValueKind.Object && parameter.Value.TryGetProperty("Value", out var explicitValue))
|
||||
{
|
||||
valueJson = $$"""{"value":{{explicitValue.GetRawText()}}}""";
|
||||
}
|
||||
else if (parameter.Value.ValueKind == JsonValueKind.Object && parameter.Value.TryGetProperty("DefaultValue", out var defaultValue))
|
||||
{
|
||||
valueJson = $$"""{"value":{{defaultValue.GetRawText()}}}""";
|
||||
}
|
||||
|
||||
if (parameter.Value.ValueKind == JsonValueKind.Object
|
||||
&& parameter.Value.TryGetProperty("Sensitive", out var sensitive)
|
||||
&& sensitive.ValueKind == JsonValueKind.True)
|
||||
{
|
||||
valueSourceType = ConfigurationValueSourceTypes.SecretReference;
|
||||
}
|
||||
|
||||
yield return ConfigurationValue(
|
||||
revisionId,
|
||||
ConfigurationDefinitionKinds.Parameter,
|
||||
parameter.Name,
|
||||
valueSourceType,
|
||||
valueJson,
|
||||
sortOrder);
|
||||
}
|
||||
}
|
||||
|
||||
private static IEnumerable<ConfigurationValueModel> ExtractVariableValues(Guid revisionId, JsonElement root)
|
||||
{
|
||||
if (!root.TryGetProperty("variables", out var variables) || variables.ValueKind != JsonValueKind.Object)
|
||||
yield break;
|
||||
|
||||
var sortOrder = 0;
|
||||
foreach (var variable in variables.EnumerateObject())
|
||||
{
|
||||
sortOrder += 10;
|
||||
var valueJson = $$"""{"expression":{{variable.Value.GetRawText()}}}""";
|
||||
|
||||
yield return ConfigurationValue(
|
||||
revisionId,
|
||||
ConfigurationDefinitionKinds.Variable,
|
||||
variable.Name,
|
||||
ConfigurationValueSourceTypes.Expression,
|
||||
valueJson,
|
||||
sortOrder);
|
||||
}
|
||||
}
|
||||
|
||||
private static ConfigurationValueModel ConfigurationValue(Guid revisionId, string kind, string name, string valueSourceType, string valueJson, int sortOrder)
|
||||
{
|
||||
return new ConfigurationValueModel
|
||||
{
|
||||
Id = ConfigurationValueId(revisionId, kind, name),
|
||||
ConfigurationDefinitionId = ConfigurationDefinitionId(revisionId, kind, name),
|
||||
ScopeType = ConfigurationValueScopeTypes.TemplateRevision,
|
||||
ScopeId = revisionId,
|
||||
ValueSourceType = valueSourceType,
|
||||
ValueJson = valueJson,
|
||||
ValueHash = TemplateVersionModel.ComputeSha256(valueJson),
|
||||
SortOrder = sortOrder
|
||||
};
|
||||
}
|
||||
|
||||
private static Guid ConfigurationDefinitionId(Guid revisionId, string kind, string name)
|
||||
{
|
||||
return DeterministicGuid($"ConfigurationDefinition:{revisionId:N}:{kind}:{name}");
|
||||
}
|
||||
|
||||
private static Guid ConfigurationValueId(Guid revisionId, string kind, string name)
|
||||
{
|
||||
return DeterministicGuid($"ConfigurationValue:{revisionId:N}:{kind}:{name}");
|
||||
}
|
||||
|
||||
private static Guid DeterministicGuid(string value)
|
||||
{
|
||||
var hash = MD5.HashData(Encoding.UTF8.GetBytes(value));
|
||||
return new Guid(hash);
|
||||
}
|
||||
|
||||
private static string BgwMergeSourceSnapshotJson()
|
||||
{
|
||||
return $$"""
|
||||
{
|
||||
"templateRevisions": [
|
||||
{
|
||||
"id": "{{TemplateBgwEnvironmentTestRevisionId}}",
|
||||
"templateVersionId": "{{TemplateBgwEnvironmentTestVersionId}}",
|
||||
"role": "Environment",
|
||||
"alias": "Environment-Test",
|
||||
"hash": "{{TemplateVersionModel.ComputeSha256(BgwEnvironmentTestTemplateJson)}}"
|
||||
},
|
||||
{
|
||||
"id": "{{TemplateBgwDomainContosoRevisionId}}",
|
||||
"templateVersionId": "{{TemplateBgwDomainContosoVersionId}}",
|
||||
"role": "Domain",
|
||||
"alias": "Domain-Contoso",
|
||||
"hash": "{{TemplateVersionModel.ComputeSha256(BgwDomainContosoTemplateJson)}}"
|
||||
},
|
||||
{
|
||||
"id": "{{TemplateBgwSharePointContosoRevisionId}}",
|
||||
"templateVersionId": "{{TemplateBgwSharePointContosoVersionId}}",
|
||||
"role": "Service",
|
||||
"alias": "Service-SharePoint-Contoso",
|
||||
"hash": "{{TemplateVersionModel.ComputeSha256(BgwSharePointContosoTemplateJson)}}"
|
||||
},
|
||||
{
|
||||
"id": "{{TemplateBgwStageInstallRevisionId}}",
|
||||
"templateVersionId": "{{TemplateBgwStageInstallVersionId}}",
|
||||
"role": "Stage",
|
||||
"alias": "Stage-Install",
|
||||
"hash": "{{TemplateVersionModel.ComputeSha256(BgwStageInstallTemplateJson)}}"
|
||||
}
|
||||
],
|
||||
"targets": [
|
||||
{ "id": "{{TargetBgwSp01Id}}", "nodeName": "CLD-SHP-01" },
|
||||
{ "id": "{{TargetBgwSp02Id}}", "nodeName": "CLD-SHP-02" },
|
||||
{ "id": "{{TargetBgwSp03Id}}", "nodeName": "CLD-SHP-03" }
|
||||
]
|
||||
}
|
||||
""";
|
||||
}
|
||||
|
||||
private static T Base<T>(T model)
|
||||
where T : BaseModel
|
||||
{
|
||||
|
||||
@@ -0,0 +1,221 @@
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.SelfService.Portal.Core.API.Context;
|
||||
using Microsoft.SelfService.Portal.Core.API.Dto.Auth;
|
||||
using Microsoft.SelfService.Portal.Core.API.Models;
|
||||
using Microsoft.SelfService.Portal.Core.API.Services;
|
||||
using System.Security.Claims;
|
||||
using System.Text.Json;
|
||||
|
||||
namespace Microsoft.SelfService.Portal.Core.API.Controllers
|
||||
{
|
||||
[Route("api/tokens")]
|
||||
[ApiController]
|
||||
public class ApiTokenController : Controller
|
||||
{
|
||||
private readonly DataContext _context;
|
||||
private readonly ApiTokenService _tokenService;
|
||||
|
||||
public ApiTokenController(DataContext context, ApiTokenService tokenService)
|
||||
{
|
||||
_context = context;
|
||||
_tokenService = tokenService;
|
||||
}
|
||||
|
||||
[HttpGet("my")]
|
||||
[Authorize(Policy = "TokenManage")]
|
||||
[ProducesResponseType(200, Type = typeof(IEnumerable<GetManagedTokenDto>))]
|
||||
public IActionResult GetMyTokens()
|
||||
{
|
||||
var subject = GetCurrentSubject();
|
||||
var subjectType = GetCurrentSubjectType();
|
||||
|
||||
var tokens = _context.ApiTokens
|
||||
.Include(token => token.ApiClient)
|
||||
.Where(token => token.Subject == subject && token.SubjectType == subjectType)
|
||||
.OrderByDescending(token => token.IssuedAt)
|
||||
.ToList();
|
||||
|
||||
return Ok(tokens.Select(ToDto));
|
||||
}
|
||||
|
||||
[HttpPost("my")]
|
||||
[Authorize(Policy = "TokenManage")]
|
||||
[ProducesResponseType(200, Type = typeof(CreateManagedTokenResponseDto))]
|
||||
[ProducesResponseType(400)]
|
||||
public IActionResult CreateMyToken([FromBody] CreateManagedTokenRequestDto request)
|
||||
{
|
||||
if (request == null || string.IsNullOrWhiteSpace(request.Scope))
|
||||
{
|
||||
return BadRequest(new { message = "Scope is required." });
|
||||
}
|
||||
|
||||
IReadOnlyCollection<string> scopes;
|
||||
try
|
||||
{
|
||||
scopes = _tokenService.ResolveRequestedUserScopes(request.Scope);
|
||||
}
|
||||
catch (InvalidOperationException ex)
|
||||
{
|
||||
return BadRequest(new { message = ex.Message });
|
||||
}
|
||||
|
||||
var subject = GetCurrentSubject();
|
||||
var subjectType = GetCurrentSubjectType();
|
||||
var name = string.IsNullOrWhiteSpace(request.Name)
|
||||
? $"Token for {subject}"
|
||||
: request.Name.Trim();
|
||||
|
||||
var token = _tokenService.CreateAccessToken(
|
||||
subject,
|
||||
subjectType == "ApiClient" ? subject : null,
|
||||
scopes);
|
||||
var now = DateTime.UtcNow;
|
||||
var expiresAt = request.ExpiresAt.HasValue && request.ExpiresAt.Value < token.ExpiresAt
|
||||
? request.ExpiresAt.Value
|
||||
: token.ExpiresAt;
|
||||
|
||||
if (expiresAt <= now)
|
||||
{
|
||||
return BadRequest(new { message = "ExpiresAt must be in the future." });
|
||||
}
|
||||
|
||||
var model = new ApiTokenModel
|
||||
{
|
||||
Id = Guid.NewGuid(),
|
||||
Jti = token.Jti,
|
||||
Subject = subject,
|
||||
SubjectType = subjectType,
|
||||
Name = name,
|
||||
ScopesJson = JsonSerializer.Serialize(scopes),
|
||||
IssuedAt = token.IssuedAt,
|
||||
ExpiresAt = expiresAt,
|
||||
Created = now,
|
||||
CreatedBy = subject,
|
||||
Modified = now,
|
||||
ModifiedBy = subject
|
||||
};
|
||||
|
||||
_context.ApiTokens.Add(model);
|
||||
_context.SaveChanges();
|
||||
|
||||
return Ok(new CreateManagedTokenResponseDto
|
||||
{
|
||||
Id = model.Id,
|
||||
AccessToken = token.AccessToken,
|
||||
ExpiresIn = Math.Max(0, Convert.ToInt32((expiresAt - now).TotalSeconds)),
|
||||
ExpiresAt = expiresAt,
|
||||
Scope = string.Join(' ', scopes)
|
||||
});
|
||||
}
|
||||
|
||||
[HttpDelete("my/{id}")]
|
||||
[Authorize(Policy = "TokenManage")]
|
||||
[ProducesResponseType(200, Type = typeof(GetManagedTokenDto))]
|
||||
[ProducesResponseType(404)]
|
||||
public IActionResult RevokeMyToken(Guid id)
|
||||
{
|
||||
var subject = GetCurrentSubject();
|
||||
var subjectType = GetCurrentSubjectType();
|
||||
var token = _context.ApiTokens.FirstOrDefault(existing =>
|
||||
existing.Id == id
|
||||
&& existing.Subject == subject
|
||||
&& existing.SubjectType == subjectType);
|
||||
|
||||
if (token == null)
|
||||
{
|
||||
return NotFound();
|
||||
}
|
||||
|
||||
RevokeToken(token, subject);
|
||||
_context.SaveChanges();
|
||||
|
||||
return Ok(ToDto(token));
|
||||
}
|
||||
|
||||
[HttpGet("admin")]
|
||||
[Authorize(Policy = "TokenAdmin")]
|
||||
[ProducesResponseType(200, Type = typeof(IEnumerable<GetManagedTokenDto>))]
|
||||
public IActionResult GetAllTokens()
|
||||
{
|
||||
var tokens = _context.ApiTokens
|
||||
.Include(token => token.ApiClient)
|
||||
.OrderByDescending(token => token.IssuedAt)
|
||||
.ToList();
|
||||
|
||||
return Ok(tokens.Select(ToDto));
|
||||
}
|
||||
|
||||
[HttpDelete("admin/{id}")]
|
||||
[Authorize(Policy = "TokenAdmin")]
|
||||
[ProducesResponseType(200, Type = typeof(GetManagedTokenDto))]
|
||||
[ProducesResponseType(404)]
|
||||
public IActionResult RevokeTokenAsAdmin(Guid id)
|
||||
{
|
||||
var token = _context.ApiTokens.FirstOrDefault(existing => existing.Id == id);
|
||||
if (token == null)
|
||||
{
|
||||
return NotFound();
|
||||
}
|
||||
|
||||
RevokeToken(token, GetCurrentSubject());
|
||||
_context.SaveChanges();
|
||||
|
||||
return Ok(ToDto(token));
|
||||
}
|
||||
|
||||
[HttpGet("scopes")]
|
||||
[Authorize(Policy = "TokenManage")]
|
||||
[ProducesResponseType(200, Type = typeof(IEnumerable<string>))]
|
||||
public IActionResult GetAllowedScopes()
|
||||
{
|
||||
return Ok(_tokenService.ReadAllowedTokenScopes());
|
||||
}
|
||||
|
||||
private string GetCurrentSubject()
|
||||
{
|
||||
return User.FindFirstValue("client_id")
|
||||
?? User.FindFirstValue(ClaimTypes.Name)
|
||||
?? User.Identity?.Name
|
||||
?? "Unknown";
|
||||
}
|
||||
|
||||
private string GetCurrentSubjectType()
|
||||
{
|
||||
return User.HasClaim(claim => claim.Type == "client_id") ? "ApiClient" : "User";
|
||||
}
|
||||
|
||||
private static void RevokeToken(ApiTokenModel token, string revokedBy)
|
||||
{
|
||||
if (!token.RevokedAt.HasValue)
|
||||
{
|
||||
token.RevokedAt = DateTime.UtcNow;
|
||||
token.RevokedBy = revokedBy;
|
||||
token.Modified = DateTime.UtcNow;
|
||||
token.ModifiedBy = revokedBy;
|
||||
}
|
||||
}
|
||||
|
||||
private static GetManagedTokenDto ToDto(ApiTokenModel token)
|
||||
{
|
||||
var scopes = JsonSerializer.Deserialize<string[]>(token.ScopesJson) ?? Array.Empty<string>();
|
||||
|
||||
return new GetManagedTokenDto
|
||||
{
|
||||
Id = token.Id,
|
||||
Subject = token.Subject,
|
||||
SubjectType = token.SubjectType,
|
||||
ClientId = token.ApiClient?.ClientId,
|
||||
Name = token.Name,
|
||||
Scope = string.Join(' ', scopes),
|
||||
IssuedAt = token.IssuedAt,
|
||||
ExpiresAt = token.ExpiresAt,
|
||||
RevokedAt = token.RevokedAt,
|
||||
RevokedBy = token.RevokedBy,
|
||||
LastUsedAt = token.LastUsedAt,
|
||||
IsActive = !token.RevokedAt.HasValue && token.ExpiresAt > DateTime.UtcNow
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.SelfService.Portal.Core.API.Context;
|
||||
using Microsoft.SelfService.Portal.Core.API.Dto.Auth;
|
||||
using Microsoft.SelfService.Portal.Core.API.Models;
|
||||
using Microsoft.SelfService.Portal.Core.API.Services;
|
||||
using System.Text.Json;
|
||||
|
||||
namespace Microsoft.SelfService.Portal.Core.API.Controllers
|
||||
{
|
||||
[Route("api/auth")]
|
||||
[ApiController]
|
||||
public class AuthController : Controller
|
||||
{
|
||||
private readonly DataContext _context;
|
||||
private readonly ApiTokenService _tokenService;
|
||||
|
||||
public AuthController(DataContext context, ApiTokenService tokenService)
|
||||
{
|
||||
_context = context;
|
||||
_tokenService = tokenService;
|
||||
}
|
||||
|
||||
[HttpPost("token")]
|
||||
[AllowAnonymous]
|
||||
[ProducesResponseType(200, Type = typeof(TokenResponseDto))]
|
||||
[ProducesResponseType(400)]
|
||||
[ProducesResponseType(401)]
|
||||
public IActionResult CreateToken([FromBody] TokenRequestDto request)
|
||||
{
|
||||
if (request == null
|
||||
|| string.IsNullOrWhiteSpace(request.ClientId)
|
||||
|| string.IsNullOrWhiteSpace(request.ClientSecret))
|
||||
{
|
||||
return BadRequest(new { message = "ClientId and ClientSecret are required." });
|
||||
}
|
||||
|
||||
var client = _context.ApiClients
|
||||
.FirstOrDefault(existing => existing.ClientId == request.ClientId);
|
||||
|
||||
if (client == null
|
||||
|| !client.IsEnabled
|
||||
|| (client.ExpiresAt.HasValue && client.ExpiresAt.Value <= DateTime.UtcNow)
|
||||
|| !ApiClientSecretHasher.VerifySecret(request.ClientSecret, client.SecretHash))
|
||||
{
|
||||
return Unauthorized(new { message = "Invalid client credentials." });
|
||||
}
|
||||
|
||||
IReadOnlyCollection<string> scopes;
|
||||
try
|
||||
{
|
||||
scopes = _tokenService.ResolveRequestedScopes(client, request.Scope);
|
||||
}
|
||||
catch (InvalidOperationException ex)
|
||||
{
|
||||
return Unauthorized(new { message = ex.Message });
|
||||
}
|
||||
|
||||
var token = _tokenService.CreateAccessToken(client, scopes);
|
||||
var now = DateTime.UtcNow;
|
||||
|
||||
client.LastUsedAt = now;
|
||||
client.Modified = now;
|
||||
client.ModifiedBy = client.ClientId;
|
||||
|
||||
_context.ApiTokens.Add(new ApiTokenModel
|
||||
{
|
||||
Id = Guid.NewGuid(),
|
||||
Jti = token.Jti,
|
||||
Subject = client.ClientId,
|
||||
SubjectType = "ApiClient",
|
||||
ApiClientId = client.Id,
|
||||
Name = $"Client credentials token for {client.Name}",
|
||||
ScopesJson = JsonSerializer.Serialize(scopes),
|
||||
IssuedAt = token.IssuedAt,
|
||||
ExpiresAt = token.ExpiresAt,
|
||||
Created = now,
|
||||
CreatedBy = client.ClientId,
|
||||
Modified = now,
|
||||
ModifiedBy = client.ClientId
|
||||
});
|
||||
|
||||
_context.SaveChanges();
|
||||
|
||||
return Ok(new TokenResponseDto
|
||||
{
|
||||
AccessToken = token.AccessToken,
|
||||
ExpiresIn = _tokenService.TokenLifetimeSeconds,
|
||||
Scope = string.Join(' ', scopes)
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,266 @@
|
||||
using AutoMapper;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.SelfService.Portal.Core.API.Context;
|
||||
using Microsoft.SelfService.Portal.Core.API.Dto.ConfigurationDefinition.Add;
|
||||
using Microsoft.SelfService.Portal.Core.API.Dto.ConfigurationDefinition.Edit;
|
||||
using Microsoft.SelfService.Portal.Core.API.Dto.ConfigurationDefinition.Get;
|
||||
using Microsoft.SelfService.Portal.Core.API.Dto.ConfigurationValue.Get;
|
||||
using Microsoft.SelfService.Portal.Core.API.JsonDocuments;
|
||||
using Microsoft.SelfService.Portal.Core.API.Models;
|
||||
|
||||
namespace Microsoft.SelfService.Portal.Core.API.Controllers
|
||||
{
|
||||
[Route("api/configuration-definitions")]
|
||||
[ApiController]
|
||||
public class ConfigurationDefinitionController : Controller
|
||||
{
|
||||
private readonly DataContext _context;
|
||||
private readonly IMapper _mapper;
|
||||
|
||||
public ConfigurationDefinitionController(DataContext context, IMapper mapper)
|
||||
{
|
||||
_context = context;
|
||||
_mapper = mapper;
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
[ProducesResponseType(200, Type = typeof(IEnumerable<GetConfigurationDefinitionDto>))]
|
||||
public IActionResult GetConfigurationDefinitions([FromQuery] Guid? templateRevisionId, [FromQuery] string? kind, [FromQuery] string? name)
|
||||
{
|
||||
var query = _context.ConfigurationDefinitions
|
||||
.AsNoTracking()
|
||||
.AsQueryable();
|
||||
|
||||
if (templateRevisionId.HasValue)
|
||||
query = query.Where(definition => definition.TemplateRevisionId == templateRevisionId.Value);
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(kind))
|
||||
query = query.Where(definition => definition.Kind == kind);
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(name))
|
||||
query = query.Where(definition => definition.Name == name);
|
||||
|
||||
var definitions = query
|
||||
.OrderBy(definition => definition.TemplateRevisionId)
|
||||
.ThenBy(definition => definition.Kind)
|
||||
.ThenBy(definition => definition.Name)
|
||||
.ToList();
|
||||
|
||||
return Ok(_mapper.Map<List<GetConfigurationDefinitionDto>>(definitions));
|
||||
}
|
||||
|
||||
[HttpGet("{id}")]
|
||||
[ProducesResponseType(200, Type = typeof(GetConfigurationDefinitionDto))]
|
||||
[ProducesResponseType(404)]
|
||||
public IActionResult GetConfigurationDefinitionById(Guid id)
|
||||
{
|
||||
var definition = _context.ConfigurationDefinitions
|
||||
.AsNoTracking()
|
||||
.FirstOrDefault(existing => existing.Id == id);
|
||||
|
||||
if (definition == null)
|
||||
return NotFound();
|
||||
|
||||
return Ok(_mapper.Map<GetConfigurationDefinitionDto>(definition));
|
||||
}
|
||||
|
||||
[HttpGet("{id}/values")]
|
||||
[ProducesResponseType(200, Type = typeof(IEnumerable<GetConfigurationValueDto>))]
|
||||
[ProducesResponseType(404)]
|
||||
public IActionResult GetConfigurationDefinitionValues(Guid id)
|
||||
{
|
||||
if (!_context.ConfigurationDefinitions.Any(definition => definition.Id == id))
|
||||
return NotFound();
|
||||
|
||||
var values = _context.ConfigurationValues
|
||||
.AsNoTracking()
|
||||
.Where(value => value.ConfigurationDefinitionId == id)
|
||||
.OrderBy(value => value.ScopeType)
|
||||
.ThenBy(value => value.SortOrder)
|
||||
.ToList();
|
||||
|
||||
return Ok(_mapper.Map<List<GetConfigurationValueDto>>(values));
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
[ProducesResponseType(200, Type = typeof(Guid))]
|
||||
[ProducesResponseType(400)]
|
||||
[ProducesResponseType(422)]
|
||||
public IActionResult AddConfigurationDefinition([FromBody] AddConfigurationDefinitionDto configurationDefinition)
|
||||
{
|
||||
if (configurationDefinition == null)
|
||||
return BadRequest(ModelState);
|
||||
|
||||
if (!TryPrepareConfigurationDefinition(
|
||||
configurationDefinition.TemplateRevisionId,
|
||||
configurationDefinition.Kind,
|
||||
configurationDefinition.Name,
|
||||
configurationDefinition.PropertiesJson,
|
||||
null,
|
||||
out var propertiesJson,
|
||||
out var errorField,
|
||||
out var errorMessage))
|
||||
{
|
||||
ModelState.AddModelError(errorField, errorMessage);
|
||||
return BadRequest(ModelState);
|
||||
}
|
||||
|
||||
if (ConfigurationDefinitionExists(configurationDefinition.TemplateRevisionId, configurationDefinition.Kind, configurationDefinition.Name, null))
|
||||
{
|
||||
ModelState.AddModelError(nameof(configurationDefinition.Name), "Configuration definition already exists for this scope, kind and name.");
|
||||
return StatusCode(422, ModelState);
|
||||
}
|
||||
|
||||
var model = _mapper.Map<ConfigurationDefinitionModel>(configurationDefinition);
|
||||
model.Id = Guid.NewGuid();
|
||||
model.PropertiesJson = propertiesJson;
|
||||
model.DefinitionHash = TemplateVersionModel.ComputeSha256(model.PropertiesJson);
|
||||
model.CreatedBy = User?.Identity?.Name ?? "System";
|
||||
model.ModifiedBy = model.CreatedBy;
|
||||
|
||||
_context.ConfigurationDefinitions.Add(model);
|
||||
_context.SaveChanges();
|
||||
|
||||
return Ok(model.Id);
|
||||
}
|
||||
|
||||
[HttpPut("{id}")]
|
||||
[ProducesResponseType(204)]
|
||||
[ProducesResponseType(400)]
|
||||
[ProducesResponseType(404)]
|
||||
[ProducesResponseType(422)]
|
||||
public IActionResult UpdateConfigurationDefinition(Guid id, [FromBody] EditConfigurationDefinitionDto configurationDefinition)
|
||||
{
|
||||
if (configurationDefinition == null)
|
||||
return BadRequest(ModelState);
|
||||
|
||||
var existing = _context.ConfigurationDefinitions.FirstOrDefault(definition => definition.Id == id);
|
||||
if (existing == null)
|
||||
return NotFound();
|
||||
|
||||
if (!TryPrepareConfigurationDefinition(
|
||||
configurationDefinition.TemplateRevisionId,
|
||||
configurationDefinition.Kind,
|
||||
configurationDefinition.Name,
|
||||
configurationDefinition.PropertiesJson,
|
||||
id,
|
||||
out var propertiesJson,
|
||||
out var errorField,
|
||||
out var errorMessage))
|
||||
{
|
||||
ModelState.AddModelError(errorField, errorMessage);
|
||||
return BadRequest(ModelState);
|
||||
}
|
||||
|
||||
if (ConfigurationDefinitionExists(configurationDefinition.TemplateRevisionId, configurationDefinition.Kind, configurationDefinition.Name, id))
|
||||
{
|
||||
ModelState.AddModelError(nameof(configurationDefinition.Name), "Configuration definition already exists for this scope, kind and name.");
|
||||
return StatusCode(422, ModelState);
|
||||
}
|
||||
|
||||
existing.TemplateRevisionId = configurationDefinition.TemplateRevisionId;
|
||||
existing.Kind = configurationDefinition.Kind;
|
||||
existing.Name = configurationDefinition.Name;
|
||||
existing.PropertiesJson = propertiesJson;
|
||||
existing.DefinitionHash = TemplateVersionModel.ComputeSha256(propertiesJson);
|
||||
existing.Modified = DateTime.UtcNow;
|
||||
existing.ModifiedBy = User?.Identity?.Name ?? "System";
|
||||
|
||||
_context.SaveChanges();
|
||||
|
||||
return NoContent();
|
||||
}
|
||||
|
||||
[HttpDelete("{id}")]
|
||||
[ProducesResponseType(204)]
|
||||
[ProducesResponseType(404)]
|
||||
[ProducesResponseType(409)]
|
||||
public IActionResult DeleteConfigurationDefinition(Guid id)
|
||||
{
|
||||
var definition = _context.ConfigurationDefinitions
|
||||
.Include(existing => existing.Values)
|
||||
.FirstOrDefault(existing => existing.Id == id);
|
||||
|
||||
if (definition == null)
|
||||
return NotFound();
|
||||
|
||||
if (definition.Values.Any())
|
||||
{
|
||||
ModelState.AddModelError(nameof(id), "Configuration definition cannot be deleted while configuration values reference it.");
|
||||
return StatusCode(409, ModelState);
|
||||
}
|
||||
|
||||
_context.ConfigurationDefinitions.Remove(definition);
|
||||
_context.SaveChanges();
|
||||
|
||||
return NoContent();
|
||||
}
|
||||
|
||||
private bool TryPrepareConfigurationDefinition(
|
||||
Guid? templateRevisionId,
|
||||
string kind,
|
||||
string name,
|
||||
string propertiesJson,
|
||||
Guid? existingId,
|
||||
out string normalizedPropertiesJson,
|
||||
out string errorField,
|
||||
out string errorMessage)
|
||||
{
|
||||
normalizedPropertiesJson = "{}";
|
||||
errorField = string.Empty;
|
||||
errorMessage = string.Empty;
|
||||
|
||||
if (templateRevisionId.HasValue && !_context.TemplateRevisions.Any(revision => revision.Id == templateRevisionId.Value))
|
||||
{
|
||||
errorField = nameof(templateRevisionId);
|
||||
errorMessage = "Template revision was not found.";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!string.Equals(kind, ConfigurationDefinitionKinds.Parameter, StringComparison.OrdinalIgnoreCase)
|
||||
&& !string.Equals(kind, ConfigurationDefinitionKinds.Variable, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
errorField = nameof(kind);
|
||||
errorMessage = $"Configuration definition kind must be [{ConfigurationDefinitionKinds.Parameter}] or [{ConfigurationDefinitionKinds.Variable}].";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (string.IsNullOrWhiteSpace(name))
|
||||
{
|
||||
errorField = nameof(name);
|
||||
errorMessage = "Configuration definition name is required.";
|
||||
return false;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
normalizedPropertiesJson = ConfigurationDocumentValidator.NormalizeAndValidate(
|
||||
propertiesJson,
|
||||
ConfigurationDocumentKind.Metadata).JsonData;
|
||||
}
|
||||
catch (ConfigurationDocumentValidationException ex)
|
||||
{
|
||||
errorField = nameof(propertiesJson);
|
||||
errorMessage = ex.Message;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private bool ConfigurationDefinitionExists(Guid? templateRevisionId, string kind, string name, Guid? excludeId)
|
||||
{
|
||||
var query = _context.ConfigurationDefinitions.AsQueryable();
|
||||
|
||||
if (excludeId.HasValue)
|
||||
query = query.Where(definition => definition.Id != excludeId.Value);
|
||||
|
||||
query = templateRevisionId.HasValue
|
||||
? query.Where(definition => definition.TemplateRevisionId == templateRevisionId.Value)
|
||||
: query.Where(definition => definition.TemplateRevisionId == null);
|
||||
|
||||
return query.Any(definition => definition.Kind == kind && definition.Name == name);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,106 @@
|
||||
using AutoMapper;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.SelfService.Portal.Core.API.Context;
|
||||
using Microsoft.SelfService.Portal.Core.API.Dto.ConfigurationValue.Add;
|
||||
using Microsoft.SelfService.Portal.Core.API.Dto.ConfigurationValue.Get;
|
||||
using Microsoft.SelfService.Portal.Core.API.JsonDocuments;
|
||||
using Microsoft.SelfService.Portal.Core.API.Models;
|
||||
|
||||
namespace Microsoft.SelfService.Portal.Core.API.Controllers
|
||||
{
|
||||
[Route("api/configuration-values")]
|
||||
[ApiController]
|
||||
public class ConfigurationValueController : Controller
|
||||
{
|
||||
private readonly DataContext _context;
|
||||
private readonly IMapper _mapper;
|
||||
|
||||
public ConfigurationValueController(DataContext context, IMapper mapper)
|
||||
{
|
||||
_context = context;
|
||||
_mapper = mapper;
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
[ProducesResponseType(200, Type = typeof(IEnumerable<GetConfigurationValueDto>))]
|
||||
public IActionResult GetConfigurationValues([FromQuery] Guid? definitionId, [FromQuery] string? scopeType, [FromQuery] Guid? scopeId)
|
||||
{
|
||||
var query = _context.ConfigurationValues
|
||||
.AsNoTracking()
|
||||
.Include(value => value.ConfigurationDefinition)
|
||||
.AsQueryable();
|
||||
|
||||
if (definitionId.HasValue)
|
||||
query = query.Where(value => value.ConfigurationDefinitionId == definitionId.Value);
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(scopeType))
|
||||
query = query.Where(value => value.ScopeType == scopeType);
|
||||
|
||||
if (scopeId.HasValue)
|
||||
query = query.Where(value => value.ScopeId == scopeId.Value);
|
||||
|
||||
var values = query
|
||||
.OrderBy(value => value.ScopeType)
|
||||
.ThenBy(value => value.SortOrder)
|
||||
.ThenBy(value => value.ConfigurationDefinition.Name)
|
||||
.ToList();
|
||||
|
||||
return Ok(_mapper.Map<List<GetConfigurationValueDto>>(values));
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
[ProducesResponseType(200, Type = typeof(Guid))]
|
||||
[ProducesResponseType(400)]
|
||||
public IActionResult AddConfigurationValue([FromBody] AddConfigurationValueDto configurationValue)
|
||||
{
|
||||
if (configurationValue == null)
|
||||
return BadRequest(ModelState);
|
||||
|
||||
if (!_context.ConfigurationDefinitions.Any(definition => definition.Id == configurationValue.ConfigurationDefinitionId))
|
||||
{
|
||||
ModelState.AddModelError(nameof(configurationValue.ConfigurationDefinitionId), "Configuration definition was not found.");
|
||||
return BadRequest(ModelState);
|
||||
}
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(configurationValue.ValueJson))
|
||||
{
|
||||
try
|
||||
{
|
||||
configurationValue.ValueJson = ConfigurationDocumentValidator.NormalizeAndValidate(
|
||||
configurationValue.ValueJson,
|
||||
ConfigurationDocumentKind.Metadata).JsonData;
|
||||
}
|
||||
catch (ConfigurationDocumentValidationException ex)
|
||||
{
|
||||
ModelState.AddModelError(nameof(configurationValue.ValueJson), ex.Message);
|
||||
return BadRequest(ModelState);
|
||||
}
|
||||
}
|
||||
|
||||
var model = _mapper.Map<ConfigurationValueModel>(configurationValue);
|
||||
model.Id = Guid.NewGuid();
|
||||
model.ValueHash = TemplateVersionModel.ComputeSha256(model.ValueJson ?? model.SourcePath ?? string.Empty);
|
||||
|
||||
_context.ConfigurationValues.Add(model);
|
||||
_context.SaveChanges();
|
||||
|
||||
return Ok(model.Id);
|
||||
}
|
||||
|
||||
[HttpDelete("{id}")]
|
||||
[ProducesResponseType(204)]
|
||||
[ProducesResponseType(404)]
|
||||
public IActionResult DeleteConfigurationValue(Guid id)
|
||||
{
|
||||
var value = _context.ConfigurationValues.FirstOrDefault(existing => existing.Id == id);
|
||||
if (value == null)
|
||||
return NotFound();
|
||||
|
||||
_context.ConfigurationValues.Remove(value);
|
||||
_context.SaveChanges();
|
||||
|
||||
return NoContent();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,143 @@
|
||||
using AutoMapper;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.SelfService.Portal.Core.API.Context;
|
||||
using Microsoft.SelfService.Portal.Core.API.Dto.CredentialSecret.Add;
|
||||
using Microsoft.SelfService.Portal.Core.API.Dto.CredentialSecret.Get;
|
||||
using Microsoft.SelfService.Portal.Core.API.JsonDocuments;
|
||||
using Microsoft.SelfService.Portal.Core.API.Models;
|
||||
|
||||
namespace Microsoft.SelfService.Portal.Core.API.Controllers
|
||||
{
|
||||
[Route("api/credential-secrets")]
|
||||
[ApiController]
|
||||
public class CredentialSecretController : Controller
|
||||
{
|
||||
private readonly DataContext _context;
|
||||
private readonly IMapper _mapper;
|
||||
|
||||
public CredentialSecretController(DataContext context, IMapper mapper)
|
||||
{
|
||||
_context = context;
|
||||
_mapper = mapper;
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
[ProducesResponseType(200, Type = typeof(IEnumerable<GetCredentialSecretDto>))]
|
||||
public IActionResult GetCredentialSecrets()
|
||||
{
|
||||
var secrets = _context.CredentialSecrets
|
||||
.AsNoTracking()
|
||||
.OrderBy(secret => secret.Name)
|
||||
.ToList();
|
||||
|
||||
return Ok(_mapper.Map<List<GetCredentialSecretDto>>(secrets));
|
||||
}
|
||||
|
||||
[HttpGet("{id}")]
|
||||
[ProducesResponseType(200, Type = typeof(GetCredentialSecretDto))]
|
||||
[ProducesResponseType(404)]
|
||||
public IActionResult GetCredentialSecretById(Guid id)
|
||||
{
|
||||
var secret = _context.CredentialSecrets
|
||||
.AsNoTracking()
|
||||
.FirstOrDefault(existing => existing.Id == id);
|
||||
|
||||
if (secret == null)
|
||||
return NotFound();
|
||||
|
||||
return Ok(_mapper.Map<GetCredentialSecretDto>(secret));
|
||||
}
|
||||
|
||||
[HttpGet("resolve")]
|
||||
[ProducesResponseType(200, Type = typeof(GetCredentialSecretValueDto))]
|
||||
[ProducesResponseType(404)]
|
||||
public IActionResult ResolveCredentialSecret([FromQuery] string name)
|
||||
{
|
||||
var secret = _context.CredentialSecrets
|
||||
.AsNoTracking()
|
||||
.FirstOrDefault(existing => existing.Name == name && existing.IsEnabled);
|
||||
|
||||
if (secret == null)
|
||||
return NotFound();
|
||||
|
||||
return Ok(_mapper.Map<GetCredentialSecretValueDto>(secret));
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
[ProducesResponseType(200, Type = typeof(Guid))]
|
||||
[ProducesResponseType(400)]
|
||||
public IActionResult AddCredentialSecret([FromBody] AddCredentialSecretDto credentialSecret)
|
||||
{
|
||||
if (credentialSecret == null)
|
||||
return BadRequest(ModelState);
|
||||
|
||||
if (_context.CredentialSecrets.Any(existing => existing.Name == credentialSecret.Name))
|
||||
{
|
||||
ModelState.AddModelError(nameof(credentialSecret.Name), "Credential secret already exists.");
|
||||
return StatusCode(422, ModelState);
|
||||
}
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(credentialSecret.MetadataJson))
|
||||
{
|
||||
try
|
||||
{
|
||||
credentialSecret.MetadataJson = ConfigurationDocumentValidator.NormalizeAndValidate(
|
||||
credentialSecret.MetadataJson,
|
||||
ConfigurationDocumentKind.Metadata).JsonData;
|
||||
}
|
||||
catch (ConfigurationDocumentValidationException ex)
|
||||
{
|
||||
ModelState.AddModelError(nameof(credentialSecret.MetadataJson), ex.Message);
|
||||
return BadRequest(ModelState);
|
||||
}
|
||||
}
|
||||
|
||||
var model = _mapper.Map<CredentialSecretModel>(credentialSecret);
|
||||
model.Id = Guid.NewGuid();
|
||||
|
||||
_context.CredentialSecrets.Add(model);
|
||||
_context.SaveChanges();
|
||||
|
||||
return Ok(model.Id);
|
||||
}
|
||||
|
||||
[HttpPut("{id}")]
|
||||
[ProducesResponseType(204)]
|
||||
[ProducesResponseType(404)]
|
||||
public IActionResult UpdateCredentialSecret(Guid id, [FromBody] AddCredentialSecretDto credentialSecret)
|
||||
{
|
||||
var existing = _context.CredentialSecrets.FirstOrDefault(secret => secret.Id == id);
|
||||
if (existing == null)
|
||||
return NotFound();
|
||||
|
||||
existing.Name = credentialSecret.Name;
|
||||
existing.UserName = credentialSecret.UserName;
|
||||
existing.SecretValue = credentialSecret.SecretValue;
|
||||
existing.SecretType = credentialSecret.SecretType;
|
||||
existing.MetadataJson = credentialSecret.MetadataJson;
|
||||
existing.IsEnabled = credentialSecret.IsEnabled;
|
||||
existing.Modified = DateTime.UtcNow;
|
||||
existing.ModifiedBy = User?.Identity?.Name ?? "System";
|
||||
|
||||
_context.SaveChanges();
|
||||
|
||||
return NoContent();
|
||||
}
|
||||
|
||||
[HttpDelete("{id}")]
|
||||
[ProducesResponseType(204)]
|
||||
[ProducesResponseType(404)]
|
||||
public IActionResult DeleteCredentialSecret(Guid id)
|
||||
{
|
||||
var secret = _context.CredentialSecrets.FirstOrDefault(existing => existing.Id == id);
|
||||
if (secret == null)
|
||||
return NotFound();
|
||||
|
||||
_context.CredentialSecrets.Remove(secret);
|
||||
_context.SaveChanges();
|
||||
|
||||
return NoContent();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,198 @@
|
||||
using AutoMapper;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.SelfService.Portal.Core.API.Context;
|
||||
using Microsoft.SelfService.Portal.Core.API.Dto.DeploymentArtifact.Add;
|
||||
using Microsoft.SelfService.Portal.Core.API.Dto.DeploymentArtifact.Get;
|
||||
using Microsoft.SelfService.Portal.Core.API.JsonDocuments;
|
||||
using Microsoft.SelfService.Portal.Core.API.Models;
|
||||
using System.Text.Json;
|
||||
|
||||
namespace Microsoft.SelfService.Portal.Core.API.Controllers
|
||||
{
|
||||
[Route("api/deployment-artifacts")]
|
||||
[ApiController]
|
||||
public class DeploymentArtifactController : Controller
|
||||
{
|
||||
private readonly DataContext _context;
|
||||
private readonly IMapper _mapper;
|
||||
|
||||
public DeploymentArtifactController(DataContext context, IMapper mapper)
|
||||
{
|
||||
_context = context;
|
||||
_mapper = mapper;
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
[ProducesResponseType(200, Type = typeof(IEnumerable<GetDeploymentArtifactDto>))]
|
||||
public IActionResult GetDeploymentArtifacts([FromQuery] Guid? deploymentGroupId, [FromQuery] Guid? targetId)
|
||||
{
|
||||
var query = _context.DeploymentArtifacts
|
||||
.AsNoTracking()
|
||||
.AsQueryable();
|
||||
|
||||
if (deploymentGroupId.HasValue)
|
||||
query = query.Where(artifact => artifact.DeploymentGroupId == deploymentGroupId.Value);
|
||||
|
||||
if (targetId.HasValue)
|
||||
query = query.Where(artifact => artifact.TargetId == targetId.Value);
|
||||
|
||||
var artifacts = query
|
||||
.OrderByDescending(artifact => artifact.Created)
|
||||
.ToList();
|
||||
|
||||
return Ok(_mapper.Map<List<GetDeploymentArtifactDto>>(artifacts));
|
||||
}
|
||||
|
||||
[HttpGet("{id}")]
|
||||
[ProducesResponseType(200, Type = typeof(GetDeploymentArtifactDto))]
|
||||
[ProducesResponseType(404)]
|
||||
public IActionResult GetDeploymentArtifactById(Guid id)
|
||||
{
|
||||
var artifact = _context.DeploymentArtifacts
|
||||
.AsNoTracking()
|
||||
.FirstOrDefault(existing => existing.Id == id);
|
||||
|
||||
if (artifact == null)
|
||||
return NotFound();
|
||||
|
||||
return Ok(_mapper.Map<GetDeploymentArtifactDto>(artifact));
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
[ProducesResponseType(200, Type = typeof(Guid))]
|
||||
[ProducesResponseType(400)]
|
||||
public IActionResult AddDeploymentArtifact([FromBody] AddDeploymentArtifactDto deploymentArtifact)
|
||||
{
|
||||
if (deploymentArtifact == null)
|
||||
return BadRequest(ModelState);
|
||||
|
||||
if (!_context.DeploymentGroups.Any(group => group.Id == deploymentArtifact.DeploymentGroupId))
|
||||
{
|
||||
ModelState.AddModelError(nameof(deploymentArtifact.DeploymentGroupId), "Deployment group was not found.");
|
||||
return BadRequest(ModelState);
|
||||
}
|
||||
|
||||
if (deploymentArtifact.TargetId.HasValue && !_context.Targets.Any(target => target.Id == deploymentArtifact.TargetId.Value))
|
||||
{
|
||||
ModelState.AddModelError(nameof(deploymentArtifact.TargetId), "Target was not found.");
|
||||
return BadRequest(ModelState);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
deploymentArtifact.DeploymentJson = NormalizeJson(deploymentArtifact.DeploymentJson);
|
||||
deploymentArtifact.SourceJson = NormalizeOptionalJson(deploymentArtifact.SourceJson);
|
||||
deploymentArtifact.ResolvedJson = NormalizeOptionalJson(deploymentArtifact.ResolvedJson);
|
||||
deploymentArtifact.SourceSnapshotJson = NormalizeOptionalJson(deploymentArtifact.SourceSnapshotJson);
|
||||
}
|
||||
catch (ConfigurationDocumentValidationException ex)
|
||||
{
|
||||
ModelState.AddModelError(nameof(deploymentArtifact.DeploymentJson), ex.Message);
|
||||
return BadRequest(ModelState);
|
||||
}
|
||||
|
||||
var model = _mapper.Map<DeploymentArtifactModel>(deploymentArtifact);
|
||||
model.Id = Guid.NewGuid();
|
||||
model.InputHash = TemplateVersionModel.ComputeSha256(model.SourceJson ?? model.DeploymentJson);
|
||||
model.OutputHash = TemplateVersionModel.ComputeSha256(model.ResolvedJson ?? model.DeploymentJson);
|
||||
model.IsStale = false;
|
||||
|
||||
_context.DeploymentArtifacts.Add(model);
|
||||
|
||||
if (model.TargetId.HasValue)
|
||||
{
|
||||
var deployment = _context.Deployments.FirstOrDefault(existing =>
|
||||
existing.DeploymentGroupId == model.DeploymentGroupId
|
||||
&& existing.TargetId == model.TargetId.Value);
|
||||
|
||||
if (deployment != null)
|
||||
{
|
||||
deployment.CurrentArtifactId = model.Id;
|
||||
deployment.SourceJson = model.SourceJson;
|
||||
deployment.JSONData = model.DeploymentJson;
|
||||
}
|
||||
}
|
||||
|
||||
_context.SaveChanges();
|
||||
|
||||
return Ok(model.Id);
|
||||
}
|
||||
|
||||
[HttpPost("{id}/stale-check")]
|
||||
[ProducesResponseType(200, Type = typeof(GetDeploymentArtifactDto))]
|
||||
[ProducesResponseType(404)]
|
||||
public IActionResult CheckDeploymentArtifactStale(Guid id)
|
||||
{
|
||||
var artifact = _context.DeploymentArtifacts.FirstOrDefault(existing => existing.Id == id);
|
||||
if (artifact == null)
|
||||
return NotFound();
|
||||
|
||||
var staleReasons = BuildStaleReasons(artifact);
|
||||
artifact.IsStale = staleReasons.Count > 0;
|
||||
artifact.StaleReasonJson = staleReasons.Count > 0
|
||||
? JsonSerializer.Serialize(staleReasons)
|
||||
: null;
|
||||
|
||||
_context.SaveChanges();
|
||||
|
||||
return Ok(_mapper.Map<GetDeploymentArtifactDto>(artifact));
|
||||
}
|
||||
|
||||
private static string NormalizeJson(string json)
|
||||
{
|
||||
return ConfigurationDocumentValidator.NormalizeAndValidate(
|
||||
string.IsNullOrWhiteSpace(json) ? "{}" : json,
|
||||
ConfigurationDocumentKind.Metadata).JsonData;
|
||||
}
|
||||
|
||||
private static string? NormalizeOptionalJson(string? json)
|
||||
{
|
||||
return string.IsNullOrWhiteSpace(json) ? null : NormalizeJson(json);
|
||||
}
|
||||
|
||||
private List<object> BuildStaleReasons(DeploymentArtifactModel artifact)
|
||||
{
|
||||
var reasons = new List<object>();
|
||||
if (string.IsNullOrWhiteSpace(artifact.SourceSnapshotJson))
|
||||
{
|
||||
return reasons;
|
||||
}
|
||||
|
||||
using var snapshot = JsonDocument.Parse(artifact.SourceSnapshotJson);
|
||||
if (!snapshot.RootElement.TryGetProperty("templateRevisions", out var revisions)
|
||||
|| revisions.ValueKind != JsonValueKind.Array)
|
||||
{
|
||||
return reasons;
|
||||
}
|
||||
|
||||
foreach (var source in revisions.EnumerateArray())
|
||||
{
|
||||
if (!source.TryGetProperty("id", out var idElement)
|
||||
|| !Guid.TryParse(idElement.GetString(), out var revisionId)
|
||||
|| !source.TryGetProperty("hash", out var hashElement))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var current = _context.TemplateRevisions
|
||||
.AsNoTracking()
|
||||
.FirstOrDefault(revision => revision.Id == revisionId);
|
||||
|
||||
if (current == null)
|
||||
{
|
||||
reasons.Add(new { Type = "TemplateRevisionMissing", RevisionId = revisionId });
|
||||
continue;
|
||||
}
|
||||
|
||||
var expectedHash = hashElement.GetString();
|
||||
if (!string.Equals(current.JsonHash, expectedHash, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
reasons.Add(new { Type = "TemplateRevisionHashChanged", RevisionId = revisionId, OldHash = expectedHash, CurrentHash = current.JsonHash });
|
||||
}
|
||||
}
|
||||
|
||||
return reasons;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -190,12 +190,26 @@ namespace Microsoft.SelfService.Portal.Core.API.Controllers
|
||||
if (!_deploymentBatchInterface.CheckDeploymentBatchById(id))
|
||||
return NotFound();
|
||||
|
||||
if (!_context.TemplateVersions.Any(version => version.Id == templateSelection.TemplateVersionId))
|
||||
var templateVersion = _context.TemplateVersions
|
||||
.Include(version => version.TemplateRevisions)
|
||||
.FirstOrDefault(version => version.Id == templateSelection.TemplateVersionId);
|
||||
|
||||
if (templateVersion == null)
|
||||
{
|
||||
ModelState.AddModelError(nameof(templateSelection.TemplateVersionId), "Template version was not found.");
|
||||
return BadRequest(ModelState);
|
||||
}
|
||||
|
||||
var templateRevisionId = templateSelection.TemplateRevisionId
|
||||
?? templateVersion.TemplateRevisions.FirstOrDefault(revision => revision.IsCurrent)?.Id;
|
||||
|
||||
if (templateRevisionId.HasValue
|
||||
&& !templateVersion.TemplateRevisions.Any(revision => revision.Id == templateRevisionId.Value))
|
||||
{
|
||||
ModelState.AddModelError(nameof(templateSelection.TemplateRevisionId), "Template revision was not found in this template version.");
|
||||
return BadRequest(ModelState);
|
||||
}
|
||||
|
||||
var sortOrder = templateSelection.SortOrder > 0
|
||||
? templateSelection.SortOrder
|
||||
: GetNextTemplateSelectionSortOrder(id);
|
||||
@@ -210,6 +224,7 @@ namespace Microsoft.SelfService.Portal.Core.API.Controllers
|
||||
model.Id = Guid.NewGuid();
|
||||
model.DeploymentGroupId = id;
|
||||
model.SortOrder = sortOrder;
|
||||
model.TemplateRevisionId = templateRevisionId;
|
||||
|
||||
_context.DeploymentTemplateSelections.Add(model);
|
||||
_context.SaveChanges();
|
||||
|
||||
@@ -108,7 +108,8 @@ namespace Microsoft.SelfService.Portal.Core.API.Controllers
|
||||
var queueJobId = _queueJobService.EnqueueDeploymentRequest(
|
||||
request.DeploymentGroupId,
|
||||
request.TargetIds,
|
||||
request.JsonData);
|
||||
request.JsonData,
|
||||
request.DeploymentArtifactId);
|
||||
|
||||
return Ok(queueJobId);
|
||||
}
|
||||
|
||||
@@ -3,6 +3,9 @@ using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.SelfService.Portal.Core.API.Dto.Template.Add;
|
||||
using Microsoft.SelfService.Portal.Core.API.Dto.Template.Edit;
|
||||
using Microsoft.SelfService.Portal.Core.API.Dto.Template.Get;
|
||||
using Microsoft.SelfService.Portal.Core.API.Dto.ConfigurationDefinition.Get;
|
||||
using Microsoft.SelfService.Portal.Core.API.Dto.TemplateRevision.Add;
|
||||
using Microsoft.SelfService.Portal.Core.API.Dto.TemplateRevision.Get;
|
||||
using Microsoft.SelfService.Portal.Core.API.Dto.TemplateVersion.Add;
|
||||
using Microsoft.SelfService.Portal.Core.API.Dto.TemplateVersion.Get;
|
||||
using Microsoft.SelfService.Portal.Core.API.Interfaces;
|
||||
@@ -223,6 +226,77 @@ namespace Microsoft.SelfService.Portal.Core.API.Controllers
|
||||
return Ok(version.Id);
|
||||
}
|
||||
|
||||
[HttpGet("{Id}/Versions/{VersionId}/Revisions")]
|
||||
[ProducesResponseType(200, Type = typeof(IEnumerable<GetTemplateRevisionDto>))]
|
||||
[ProducesResponseType(404)]
|
||||
public IActionResult GetTemplateRevisions(Guid Id, Guid VersionId)
|
||||
{
|
||||
if (!_templateInterface.CheckTemplateVersionById(Id, VersionId))
|
||||
return NotFound();
|
||||
|
||||
return Ok(_mapper.Map<List<GetTemplateRevisionDto>>(_templateInterface.GetTemplateRevisions(Id, VersionId)));
|
||||
}
|
||||
|
||||
[HttpGet("{Id}/Versions/{VersionId}/Revisions/{RevisionId}")]
|
||||
[ProducesResponseType(200, Type = typeof(GetTemplateRevisionDto))]
|
||||
[ProducesResponseType(404)]
|
||||
public IActionResult GetTemplateRevisionById(Guid Id, Guid VersionId, Guid RevisionId)
|
||||
{
|
||||
var revision = _templateInterface.GetTemplateRevisionById(Id, VersionId, RevisionId);
|
||||
if (revision == null)
|
||||
return NotFound();
|
||||
|
||||
return Ok(_mapper.Map<GetTemplateRevisionDto>(revision));
|
||||
}
|
||||
|
||||
[HttpGet("{Id}/Versions/{VersionId}/Revisions/{RevisionId}/Definitions")]
|
||||
[ProducesResponseType(200, Type = typeof(IEnumerable<GetConfigurationDefinitionDto>))]
|
||||
[ProducesResponseType(404)]
|
||||
public IActionResult GetTemplateRevisionDefinitions(Guid Id, Guid VersionId, Guid RevisionId)
|
||||
{
|
||||
var revision = _templateInterface.GetTemplateRevisionById(Id, VersionId, RevisionId);
|
||||
if (revision == null)
|
||||
return NotFound();
|
||||
|
||||
return Ok(_mapper.Map<List<GetConfigurationDefinitionDto>>(revision.ConfigurationDefinitions));
|
||||
}
|
||||
|
||||
[HttpPost("{Id}/Versions/{VersionId}/Revisions")]
|
||||
[ProducesResponseType(200, Type = typeof(Guid))]
|
||||
[ProducesResponseType(400)]
|
||||
[ProducesResponseType(404)]
|
||||
public IActionResult AddTemplateRevision(Guid Id, Guid VersionId, [FromBody] AddTemplateRevisionDto templateRevision)
|
||||
{
|
||||
if (templateRevision == null)
|
||||
return BadRequest(ModelState);
|
||||
|
||||
if (!_templateInterface.CheckTemplateVersionById(Id, VersionId))
|
||||
return NotFound();
|
||||
|
||||
if (!ModelState.IsValid)
|
||||
return BadRequest(ModelState);
|
||||
|
||||
var revision = _mapper.Map<TemplateRevisionModel>(templateRevision);
|
||||
revision.PublishedBy = templateRevision.PublishedBy ?? User?.Identity?.Name ?? "System";
|
||||
|
||||
try
|
||||
{
|
||||
if (!_templateInterface.AddTemplateRevision(Id, VersionId, revision, templateRevision.Publish))
|
||||
{
|
||||
ModelState.AddModelError("", "Something went wrong while saving template revision");
|
||||
return StatusCode(500, ModelState);
|
||||
}
|
||||
}
|
||||
catch (ConfigurationDocumentValidationException ex)
|
||||
{
|
||||
ModelState.AddModelError(nameof(templateRevision.JsonData), ex.Message);
|
||||
return BadRequest(ModelState);
|
||||
}
|
||||
|
||||
var savedRevision = _templateInterface.GetCurrentTemplateRevision(VersionId);
|
||||
return Ok(savedRevision?.Id ?? revision.Id);
|
||||
}
|
||||
|
||||
[HttpPost("{Id}/Versions/{VersionId}/Publish")]
|
||||
[ProducesResponseType(204)]
|
||||
[ProducesResponseType(404)]
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
namespace Microsoft.SelfService.Portal.Core.API.Dto.Auth
|
||||
{
|
||||
public class CreateManagedTokenRequestDto
|
||||
{
|
||||
public string Name { get; set; } = string.Empty;
|
||||
|
||||
public string Scope { get; set; } = string.Empty;
|
||||
|
||||
public DateTime? ExpiresAt { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
namespace Microsoft.SelfService.Portal.Core.API.Dto.Auth
|
||||
{
|
||||
public class CreateManagedTokenResponseDto
|
||||
{
|
||||
public Guid Id { get; set; }
|
||||
|
||||
public string AccessToken { get; set; } = string.Empty;
|
||||
|
||||
public string TokenType { get; set; } = "Bearer";
|
||||
|
||||
public int ExpiresIn { get; set; }
|
||||
|
||||
public DateTime ExpiresAt { get; set; }
|
||||
|
||||
public string Scope { get; set; } = string.Empty;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
namespace Microsoft.SelfService.Portal.Core.API.Dto.Auth
|
||||
{
|
||||
public class GetManagedTokenDto
|
||||
{
|
||||
public Guid Id { get; set; }
|
||||
|
||||
public string Subject { get; set; } = string.Empty;
|
||||
|
||||
public string SubjectType { get; set; } = string.Empty;
|
||||
|
||||
public string? ClientId { get; set; }
|
||||
|
||||
public string Name { get; set; } = string.Empty;
|
||||
|
||||
public string Scope { get; set; } = string.Empty;
|
||||
|
||||
public DateTime IssuedAt { get; set; }
|
||||
|
||||
public DateTime ExpiresAt { get; set; }
|
||||
|
||||
public DateTime? RevokedAt { get; set; }
|
||||
|
||||
public string? RevokedBy { get; set; }
|
||||
|
||||
public DateTime? LastUsedAt { get; set; }
|
||||
|
||||
public bool IsActive { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
namespace Microsoft.SelfService.Portal.Core.API.Dto.Auth
|
||||
{
|
||||
public class TokenRequestDto
|
||||
{
|
||||
public string ClientId { get; set; } = string.Empty;
|
||||
public string ClientSecret { get; set; } = string.Empty;
|
||||
public string? Scope { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
namespace Microsoft.SelfService.Portal.Core.API.Dto.Auth
|
||||
{
|
||||
public class TokenResponseDto
|
||||
{
|
||||
public string AccessToken { get; set; } = string.Empty;
|
||||
public string TokenType { get; set; } = "Bearer";
|
||||
public int ExpiresIn { get; set; }
|
||||
public string Scope { get; set; } = string.Empty;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
namespace Microsoft.SelfService.Portal.Core.API.Dto.ConfigurationDefinition.Add
|
||||
{
|
||||
public class AddConfigurationDefinitionDto
|
||||
{
|
||||
public Guid? TemplateRevisionId { get; set; }
|
||||
public string Kind { get; set; } = string.Empty;
|
||||
public string Name { get; set; } = string.Empty;
|
||||
public string PropertiesJson { get; set; } = "{}";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
namespace Microsoft.SelfService.Portal.Core.API.Dto.ConfigurationDefinition.Edit
|
||||
{
|
||||
public class EditConfigurationDefinitionDto
|
||||
{
|
||||
public Guid? TemplateRevisionId { get; set; }
|
||||
public string Kind { get; set; } = string.Empty;
|
||||
public string Name { get; set; } = string.Empty;
|
||||
public string PropertiesJson { get; set; } = "{}";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
using Microsoft.SelfService.Portal.Core.API.Dto;
|
||||
|
||||
namespace Microsoft.SelfService.Portal.Core.API.Dto.ConfigurationDefinition.Get
|
||||
{
|
||||
public class GetConfigurationDefinitionDto : BaseDetailsDto
|
||||
{
|
||||
public Guid? TemplateRevisionId { get; set; }
|
||||
public string Kind { get; set; } = string.Empty;
|
||||
public string Name { get; set; } = string.Empty;
|
||||
public string PropertiesJson { get; set; } = "{}";
|
||||
public string DefinitionHash { get; set; } = string.Empty;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
namespace Microsoft.SelfService.Portal.Core.API.Dto.ConfigurationValue.Add
|
||||
{
|
||||
public class AddConfigurationValueDto
|
||||
{
|
||||
public Guid ConfigurationDefinitionId { get; set; }
|
||||
public string ScopeType { get; set; } = "TemplateRevision";
|
||||
public Guid ScopeId { get; set; }
|
||||
public string ValueSourceType { get; set; } = "Static";
|
||||
public string? SourcePath { get; set; }
|
||||
public string? ValueJson { get; set; }
|
||||
public int SortOrder { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
using Microsoft.SelfService.Portal.Core.API.Dto;
|
||||
|
||||
namespace Microsoft.SelfService.Portal.Core.API.Dto.ConfigurationValue.Get
|
||||
{
|
||||
public class GetConfigurationValueDto : BaseDetailsDto
|
||||
{
|
||||
public Guid ConfigurationDefinitionId { get; set; }
|
||||
public string ScopeType { get; set; } = string.Empty;
|
||||
public Guid ScopeId { get; set; }
|
||||
public string ValueSourceType { get; set; } = string.Empty;
|
||||
public string? SourcePath { get; set; }
|
||||
public string? ValueJson { get; set; }
|
||||
public string ValueHash { get; set; } = string.Empty;
|
||||
public int SortOrder { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
namespace Microsoft.SelfService.Portal.Core.API.Dto.CredentialSecret.Add
|
||||
{
|
||||
public class AddCredentialSecretDto
|
||||
{
|
||||
public string Name { get; set; } = string.Empty;
|
||||
public string? UserName { get; set; }
|
||||
public string SecretValue { get; set; } = string.Empty;
|
||||
public string SecretType { get; set; } = "Credential";
|
||||
public string? MetadataJson { get; set; }
|
||||
public bool IsEnabled { get; set; } = true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
using Microsoft.SelfService.Portal.Core.API.Dto;
|
||||
|
||||
namespace Microsoft.SelfService.Portal.Core.API.Dto.CredentialSecret.Get
|
||||
{
|
||||
public class GetCredentialSecretDto : BaseDetailsDto
|
||||
{
|
||||
public string Name { get; set; } = string.Empty;
|
||||
public string? UserName { get; set; }
|
||||
public string SecretType { get; set; } = "Credential";
|
||||
public string? MetadataJson { get; set; }
|
||||
public bool IsEnabled { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
namespace Microsoft.SelfService.Portal.Core.API.Dto.CredentialSecret.Get
|
||||
{
|
||||
public class GetCredentialSecretValueDto
|
||||
{
|
||||
public string Name { get; set; } = string.Empty;
|
||||
public string? UserName { get; set; }
|
||||
public string SecretValue { get; set; } = string.Empty;
|
||||
public string SecretType { get; set; } = "Credential";
|
||||
public string? MetadataJson { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,7 @@
|
||||
public class AddDeploymentRequestDto
|
||||
{
|
||||
public Guid DeploymentGroupId { get; set; }
|
||||
public Guid? DeploymentArtifactId { get; set; }
|
||||
public ICollection<Guid> TargetIds { get; set; } = new List<Guid>();
|
||||
public string JsonData { get; set; } = "{}";
|
||||
}
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
namespace Microsoft.SelfService.Portal.Core.API.Dto.DeploymentArtifact.Add
|
||||
{
|
||||
public class AddDeploymentArtifactDto
|
||||
{
|
||||
public Guid DeploymentGroupId { get; set; }
|
||||
public Guid? TargetId { get; set; }
|
||||
public string ArtifactType { get; set; } = "ResolvedConfigurationData";
|
||||
public string Status { get; set; } = "Pending";
|
||||
public string DeploymentJson { get; set; } = "{}";
|
||||
public string? SourceJson { get; set; }
|
||||
public string? ResolvedJson { get; set; }
|
||||
public string? SourceSnapshotJson { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
using Microsoft.SelfService.Portal.Core.API.Dto;
|
||||
|
||||
namespace Microsoft.SelfService.Portal.Core.API.Dto.DeploymentArtifact.Get
|
||||
{
|
||||
public class GetDeploymentArtifactDto : BaseDetailsDto
|
||||
{
|
||||
public Guid DeploymentGroupId { get; set; }
|
||||
public Guid? TargetId { get; set; }
|
||||
public string ArtifactType { get; set; } = string.Empty;
|
||||
public string Status { get; set; } = string.Empty;
|
||||
public string DeploymentJson { get; set; } = "{}";
|
||||
public string? SourceJson { get; set; }
|
||||
public string? ResolvedJson { get; set; }
|
||||
public string? SourceSnapshotJson { get; set; }
|
||||
public string InputHash { get; set; } = string.Empty;
|
||||
public string OutputHash { get; set; } = string.Empty;
|
||||
public bool IsStale { get; set; }
|
||||
public string? StaleReasonJson { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,7 @@
|
||||
public class AddDeploymentTemplateSelectionDto
|
||||
{
|
||||
public Guid TemplateVersionId { get; set; }
|
||||
public Guid? TemplateRevisionId { get; set; }
|
||||
public string TemplateRole { get; set; } = "Service";
|
||||
public int SortOrder { get; set; }
|
||||
public string? Alias { get; set; }
|
||||
|
||||
@@ -6,6 +6,7 @@ namespace Microsoft.SelfService.Portal.Core.API.Dto.DeploymentComposition.Get
|
||||
{
|
||||
public Guid DeploymentGroupId { get; set; }
|
||||
public Guid TemplateVersionId { get; set; }
|
||||
public Guid? TemplateRevisionId { get; set; }
|
||||
public string TemplateRole { get; set; } = string.Empty;
|
||||
public int SortOrder { get; set; }
|
||||
public string? Alias { get; set; }
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
namespace Microsoft.SelfService.Portal.Core.API.Dto.TemplateRevision.Add
|
||||
{
|
||||
public class AddTemplateRevisionDto
|
||||
{
|
||||
public string JsonData { get; set; } = "{}";
|
||||
public string SchemaVersion { get; set; } = "1.0";
|
||||
public bool Publish { get; set; }
|
||||
public string? PublishedBy { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
using Microsoft.SelfService.Portal.Core.API.Dto;
|
||||
|
||||
namespace Microsoft.SelfService.Portal.Core.API.Dto.TemplateRevision.Get
|
||||
{
|
||||
public class GetTemplateRevisionDto : BaseDetailsDto
|
||||
{
|
||||
public Guid TemplateVersionId { get; set; }
|
||||
public int RevisionNumber { get; set; }
|
||||
public string JsonData { get; set; } = "{}";
|
||||
public string JsonHash { get; set; } = string.Empty;
|
||||
public string SchemaVersion { get; set; } = "1.0";
|
||||
public bool IsCurrent { get; set; }
|
||||
public bool IsPublished { get; set; }
|
||||
public DateTime? PublishedAt { get; set; }
|
||||
public string? PublishedBy { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -23,6 +23,17 @@ using Microsoft.SelfService.Portal.Core.API.Dto.Template.Add;
|
||||
using Microsoft.SelfService.Portal.Core.API.Dto.Template.Edit;
|
||||
using Microsoft.SelfService.Portal.Core.API.Dto.TemplateVersion.Add;
|
||||
using Microsoft.SelfService.Portal.Core.API.Dto.TemplateVersion.Get;
|
||||
using Microsoft.SelfService.Portal.Core.API.Dto.TemplateRevision.Add;
|
||||
using Microsoft.SelfService.Portal.Core.API.Dto.TemplateRevision.Get;
|
||||
using Microsoft.SelfService.Portal.Core.API.Dto.ConfigurationDefinition.Add;
|
||||
using Microsoft.SelfService.Portal.Core.API.Dto.ConfigurationDefinition.Edit;
|
||||
using Microsoft.SelfService.Portal.Core.API.Dto.ConfigurationDefinition.Get;
|
||||
using Microsoft.SelfService.Portal.Core.API.Dto.ConfigurationValue.Add;
|
||||
using Microsoft.SelfService.Portal.Core.API.Dto.ConfigurationValue.Get;
|
||||
using Microsoft.SelfService.Portal.Core.API.Dto.DeploymentArtifact.Add;
|
||||
using Microsoft.SelfService.Portal.Core.API.Dto.DeploymentArtifact.Get;
|
||||
using Microsoft.SelfService.Portal.Core.API.Dto.CredentialSecret.Add;
|
||||
using Microsoft.SelfService.Portal.Core.API.Dto.CredentialSecret.Get;
|
||||
using Microsoft.SelfService.Portal.Core.API.Dto.Service.Get;
|
||||
using Microsoft.SelfService.Portal.Core.API.Dto.Service.Add;
|
||||
using Microsoft.SelfService.Portal.Core.API.Dto.Service.Edit;
|
||||
@@ -131,6 +142,26 @@ namespace Microsoft.SelfService.Portal.Core.API.Helper
|
||||
CreateMap<TemplateVersionModel, AddTemplateVersionDto>();
|
||||
CreateMap<AddTemplateVersionDto, TemplateVersionModel>();
|
||||
|
||||
/** Template Revision Model **/
|
||||
CreateMap<TemplateRevisionModel, GetTemplateRevisionDto>();
|
||||
CreateMap<GetTemplateRevisionDto, TemplateRevisionModel>();
|
||||
CreateMap<AddTemplateRevisionDto, TemplateRevisionModel>();
|
||||
|
||||
/** Configuration Data Model **/
|
||||
CreateMap<ConfigurationDefinitionModel, GetConfigurationDefinitionDto>();
|
||||
CreateMap<AddConfigurationDefinitionDto, ConfigurationDefinitionModel>();
|
||||
CreateMap<EditConfigurationDefinitionDto, ConfigurationDefinitionModel>();
|
||||
CreateMap<ConfigurationValueModel, GetConfigurationValueDto>();
|
||||
CreateMap<AddConfigurationValueDto, ConfigurationValueModel>();
|
||||
|
||||
/** Deployment Artifact Model **/
|
||||
CreateMap<DeploymentArtifactModel, GetDeploymentArtifactDto>();
|
||||
CreateMap<AddDeploymentArtifactDto, DeploymentArtifactModel>();
|
||||
|
||||
/** Credential Secret Model **/
|
||||
CreateMap<CredentialSecretModel, GetCredentialSecretDto>();
|
||||
CreateMap<AddCredentialSecretDto, CredentialSecretModel>();
|
||||
|
||||
/** Service Model **/
|
||||
CreateMap<ServiceModel, GetServiceDto>();
|
||||
CreateMap<GetServiceDto, ServiceModel>();
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
public interface IQueueJobService
|
||||
{
|
||||
Guid EnqueueTemplateJsonChanged(Guid templateId, string oldJsonData, string newJsonData);
|
||||
Guid EnqueueDeploymentRequest(Guid deploymentGroupId, ICollection<Guid> targetIds, string jsonData);
|
||||
Guid EnqueueDeploymentRequest(Guid deploymentGroupId, ICollection<Guid> targetIds, string jsonData, Guid? deploymentArtifactId = null);
|
||||
bool RetryQueueJob(Guid queueJobId);
|
||||
bool ApproveQueueJobStep(Guid queueJobStepId, string approvedBy, string? comment);
|
||||
bool RejectQueueJobStep(Guid queueJobStepId, string approvedBy, string? comment);
|
||||
|
||||
@@ -18,6 +18,10 @@ namespace Microsoft.SelfService.Portal.Core.API.Interfaces
|
||||
ICollection<TemplateVersionModel> GetTemplateVersions(Guid templateId);
|
||||
TemplateVersionModel? GetTemplateVersionById(Guid templateId, Guid versionId);
|
||||
TemplateVersionModel? GetPublishedTemplateVersion(Guid templateId);
|
||||
ICollection<TemplateRevisionModel> GetTemplateRevisions(Guid templateId, Guid versionId);
|
||||
TemplateRevisionModel? GetTemplateRevisionById(Guid templateId, Guid versionId, Guid revisionId);
|
||||
TemplateRevisionModel? GetCurrentTemplateRevision(Guid versionId);
|
||||
bool AddTemplateRevision(Guid templateId, Guid versionId, TemplateRevisionModel revision, bool publish);
|
||||
bool AddTemplateVersion(Guid templateId, TemplateVersionModel version, bool publish);
|
||||
bool PublishTemplateVersion(Guid templateId, Guid versionId, string? publishedBy);
|
||||
bool CheckTemplateVersionById(Guid templateId, Guid versionId);
|
||||
|
||||
@@ -5,10 +5,12 @@
|
||||
<Nullable>enable</Nullable>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<UserSecretsId>9c90fee1-4576-4f20-be83-715728173b96</UserSecretsId>
|
||||
<DefaultItemExcludes>$(DefaultItemExcludes);buildcheck\**</DefaultItemExcludes>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="AutoMapper" Version="16.1.1" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="10.0.8" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Authentication.Negotiate" Version="10.0.8" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="10.0.8" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="10.0.8" />
|
||||
|
||||
@@ -1,604 +0,0 @@
|
||||
version=1
|
||||
|
||||
# This file caches language service data to improve the performance of C# Dev Kit.
|
||||
# It is not intended for manual editing. It can safely be deleted and will be
|
||||
# regenerated automatically. For more information, see https://aka.ms/lscache
|
||||
#
|
||||
# To control where cache files are stored, use the following VS Code setting:
|
||||
# "dotnet.projectsystem.cacheInProjectFolder": true
|
||||
|
||||
[project]
|
||||
language=C#
|
||||
primary
|
||||
lastDtbSucceeded
|
||||
|
||||
[properties]
|
||||
AssemblyName=Microsoft.SelfService.Portal.Core.API
|
||||
CommandLineArgsForDesignTimeEvaluation=-langversion:14.0 -define:TRACE
|
||||
CompilerGeneratedFilesOutputPath=
|
||||
MaxSupportedLangVersion=14.0
|
||||
ProjectAssetsFile=<PATH>obj/project.assets.json
|
||||
RootNamespace=Microsoft.SelfService.Portal.Core.API
|
||||
RunAnalyzers=
|
||||
RunAnalyzersDuringLiveAnalysis=
|
||||
SolutionPath=<PATH>../../Coding.sln
|
||||
TargetFrameworkIdentifier=.NETCoreApp
|
||||
TargetPath=<PATH>bin/Debug/net10.0/Microsoft.SelfService.Portal.Core.API.dll
|
||||
TargetRefPath=<PATH>obj/Debug/net10.0/ref/Microsoft.SelfService.Portal.Core.API.dll
|
||||
TemporaryDependencyNodeTargetIdentifier=net10.0
|
||||
|
||||
[commandLineArguments]
|
||||
/noconfig
|
||||
/unsafe-
|
||||
/checked-
|
||||
/nowarn:1701,1702,1701,1702,8002
|
||||
/fullpaths
|
||||
/nostdlib+
|
||||
/errorreport:prompt
|
||||
/warn:10
|
||||
/define:TRACE;DEBUG;NET;NET10_0;NETCOREAPP;NET5_0_OR_GREATER;NET6_0_OR_GREATER;NET7_0_OR_GREATER;NET8_0_OR_GREATER;NET9_0_OR_GREATER;NET10_0_OR_GREATER;NETCOREAPP1_0_OR_GREATER;NETCOREAPP1_1_OR_GREATER;NETCOREAPP2_0_OR_GREATER;NETCOREAPP2_1_OR_GREATER;NETCOREAPP2_2_OR_GREATER;NETCOREAPP3_0_OR_GREATER;NETCOREAPP3_1_OR_GREATER
|
||||
/highentropyva+
|
||||
/nullable:enable
|
||||
/features:"InterceptorsNamespaces=;Microsoft.AspNetCore.OpenApi.Generated;;Microsoft.Extensions.Validation.Generated"
|
||||
/debug+
|
||||
/debug:portable
|
||||
/filealign:512
|
||||
/optimize-
|
||||
/out:obj\Debug\net10.0\Microsoft.SelfService.Portal.Core.API.dll
|
||||
/refout:obj\Debug\net10.0\refint\Microsoft.SelfService.Portal.Core.API.dll
|
||||
/target:exe
|
||||
/warnaserror-
|
||||
/utf8output
|
||||
/deterministic+
|
||||
/langversion:14.0
|
||||
/features:use-roslyn-tokenizer=true
|
||||
/warnaserror+:NU1605,SYSLIB0011
|
||||
|
||||
[sourceFiles]
|
||||
Context/DataContext.cs
|
||||
Controllers/
|
||||
AbstractController.cs
|
||||
DeploymentController.cs
|
||||
DeploymentGroupController.cs
|
||||
DomainController.cs
|
||||
EnvironmentController.cs
|
||||
RunbookController.cs
|
||||
ServiceController.cs
|
||||
TemplateCategoryController.cs
|
||||
TemplateController.cs
|
||||
VirtualMachineController.cs
|
||||
Dto/
|
||||
AddEnvironmentDomainDto.cs
|
||||
BaseDetailsDto.cs
|
||||
BaseDto.cs
|
||||
Deployment/Add/
|
||||
AddDeploymentDto.cs
|
||||
AddDeploymentRequestDto.cs
|
||||
Deployment/
|
||||
Edit/EditDeploymentDto.cs
|
||||
Get/
|
||||
GetDeploymentDetailsDto.cs
|
||||
GetDeploymentDto.cs
|
||||
GetQueueJobDetailsDto.cs
|
||||
GetQueueJobDto.cs
|
||||
GetQueueJobTargetDto.cs
|
||||
DeploymentGroup/
|
||||
Add/AddDeploymentGroupDto.cs
|
||||
Edit/EditDeploymentGroupDto.cs
|
||||
Get/
|
||||
GetDeploymentGroupDetailsDto.cs
|
||||
GetDeploymentGroupDto.cs
|
||||
Domain/
|
||||
Add/AddDomainDto.cs
|
||||
Edit/EditDomainDto.cs
|
||||
Get/
|
||||
GetDomainDetailsDto.cs
|
||||
GetDomainDto.cs
|
||||
GetDomainEnvironmentDetailsDto.cs
|
||||
GetDomainEnvironmentDto.cs
|
||||
GetDomainVirtualMachineDetailsDto.cs
|
||||
Environment/
|
||||
Add/AddEnvironmentDto.cs
|
||||
Edit/EditEnvironmentDto.cs
|
||||
Get/
|
||||
GetEnvironmentDetailsDto.cs
|
||||
GetEnvironmentDomainDetailsDto.cs
|
||||
GetEnvironmentDomainDto.cs
|
||||
GetEnvironmentDto.cs
|
||||
Runbook/
|
||||
Add/AddRunbookDto.cs
|
||||
Get/
|
||||
GetRunbookDetailsDto.cs
|
||||
GetRunbookDto.cs
|
||||
Service/
|
||||
Add/AddServiceDto.cs
|
||||
Edit/EditServiceDto.cs
|
||||
Get/
|
||||
GetServiceDetailsDto.cs
|
||||
GetServiceDto.cs
|
||||
RoleDefinition/
|
||||
AddServiceRoleDefinitionDto.cs
|
||||
EditServiceRoleDefinitionDto.cs
|
||||
Template/
|
||||
Add/AddTemplateDto.cs
|
||||
Edit/EditTemplateDto.cs
|
||||
Get/
|
||||
GetTemplateDetailsDto.cs
|
||||
GetTemplateDto.cs
|
||||
TemplateCategory/
|
||||
Add/AddTemplateCategoryDto.cs
|
||||
Edit/EditTemplateCategoryDto.cs
|
||||
Get/
|
||||
GetTemplateCategoryDetailsDto.cs
|
||||
GetTemplateCategoryDto.cs
|
||||
VirtualMachine/
|
||||
Add/AddVirtualMachineDto.cs
|
||||
Edit/EditVirtualMachineDto.cs
|
||||
Get/
|
||||
GetVirtualMachineDetailsDto.cs
|
||||
GetVirtualMachineDto.cs
|
||||
Events/
|
||||
AbstractEventHandler.cs
|
||||
Interfaces/IEventHandlerInterface.cs
|
||||
Extensions/Dataannotations/DefaultValueSqlAttribute.cs
|
||||
Handlers/DomainEditedHandler.cs
|
||||
Helper/
|
||||
APIHelper.cs
|
||||
MappingProfilesHelper.cs
|
||||
Interfaces/
|
||||
IAbstractInterface.cs
|
||||
IDeploymentGroupInterface.cs
|
||||
IDeploymentInterface.cs
|
||||
IDomainInterface.cs
|
||||
IEnvironmentInterface.cs
|
||||
IJobInterface.cs
|
||||
IQueueJobService.cs
|
||||
IRunbookInterface.cs
|
||||
IServiceInterface.cs
|
||||
ITemplateCategoryInterface.cs
|
||||
ITemplateInterface.cs
|
||||
IVirtualMachineInterface.cs
|
||||
Migrations/
|
||||
20231020093825_Initial.cs
|
||||
20231020093825_Initial.Designer.cs
|
||||
20260514210821_AddQueueJobs.cs
|
||||
20260514210821_AddQueueJobs.Designer.cs
|
||||
20260514210842_AddQueueJobModelSnapshotFix.cs
|
||||
20260514210842_AddQueueJobModelSnapshotFix.Designer.cs
|
||||
20260515195005_AddEnvironmentAndTargetProviderModel.cs
|
||||
20260515195005_AddEnvironmentAndTargetProviderModel.Designer.cs
|
||||
20260515195742_RemoveCloudEnabledFromEnvironment.cs
|
||||
20260515195742_RemoveCloudEnabledFromEnvironment.Designer.cs
|
||||
20260515204426_RemoveVirtualMachineTargetAndProvider.cs
|
||||
20260515204426_RemoveVirtualMachineTargetAndProvider.Designer.cs
|
||||
20260515205512_MakeVirtualMachineDomainOptionalAndAddLinkUnlinkFlow.cs
|
||||
20260515205512_MakeVirtualMachineDomainOptionalAndAddLinkUnlinkFlow.Designer.cs
|
||||
20260515214839_AddServiceCloudFlagAndRoleDefinitions.cs
|
||||
20260515214839_AddServiceCloudFlagAndRoleDefinitions.Designer.cs
|
||||
DataContextModelSnapshot.cs
|
||||
Models/
|
||||
BaseJunctionModel.cs
|
||||
BaseModel.cs
|
||||
DeploymentGroupModel.cs
|
||||
DeploymentModel.cs
|
||||
DomainModel.cs
|
||||
EnvironmentDomainsModel.cs
|
||||
EnvironmentModel.cs
|
||||
EnvironmentTypes.cs
|
||||
EventModel.cs
|
||||
JobModel.cs
|
||||
OptionCategoryModel.cs
|
||||
OptionModel.cs
|
||||
QueueJobModel.cs
|
||||
QueueJobStatus.cs
|
||||
QueueJobTargetModel.cs
|
||||
QueueJobType.cs
|
||||
RunbookModel.cs
|
||||
ServiceModel.cs
|
||||
ServiceRoleDefinitionModel.cs
|
||||
TemplateCategoryModel.cs
|
||||
TemplateModel.cs
|
||||
TemplateOptionModel.cs
|
||||
VirtualMachineModel.cs
|
||||
obj/Debug/net10.0/
|
||||
.NETCoreApp,Version=v10.0.AssemblyAttributes.cs
|
||||
Microsoft.SelfService.Portal.Core.API.AssemblyInfo.cs
|
||||
Microsoft.SelfService.Portal.Core.API.GlobalUsings.g.cs
|
||||
Program.cs
|
||||
Repository/
|
||||
DeploymentGroupRepository.cs
|
||||
DeploymentRepository.cs
|
||||
DomainRepository.cs
|
||||
EnvironmentRepository.cs
|
||||
JobRepository.cs
|
||||
RunbookRepository.cs
|
||||
ServiceRepository.cs
|
||||
TemplateCategoryRepository.cs
|
||||
TemplateRepository.cs
|
||||
VirtualMachineRepository.cs
|
||||
Services/QueueJobService.cs
|
||||
|
||||
[metadataReferences]
|
||||
<DOTNET>/packs/Microsoft.AspNetCore.App.Ref/10.0.8/ref/net10.0/
|
||||
Microsoft.AspNetCore.Antiforgery.dll
|
||||
Microsoft.AspNetCore.Authentication.Abstractions.dll
|
||||
Microsoft.AspNetCore.Authentication.BearerToken.dll
|
||||
Microsoft.AspNetCore.Authentication.Cookies.dll
|
||||
Microsoft.AspNetCore.Authentication.Core.dll
|
||||
Microsoft.AspNetCore.Authentication.dll
|
||||
Microsoft.AspNetCore.Authentication.OAuth.dll
|
||||
Microsoft.AspNetCore.Authorization.dll
|
||||
Microsoft.AspNetCore.Authorization.Policy.dll
|
||||
Microsoft.AspNetCore.Components.Authorization.dll
|
||||
Microsoft.AspNetCore.Components.dll
|
||||
Microsoft.AspNetCore.Components.Endpoints.dll
|
||||
Microsoft.AspNetCore.Components.Forms.dll
|
||||
Microsoft.AspNetCore.Components.Server.dll
|
||||
Microsoft.AspNetCore.Components.Web.dll
|
||||
Microsoft.AspNetCore.Connections.Abstractions.dll
|
||||
Microsoft.AspNetCore.CookiePolicy.dll
|
||||
Microsoft.AspNetCore.Cors.dll
|
||||
Microsoft.AspNetCore.Cryptography.Internal.dll
|
||||
Microsoft.AspNetCore.Cryptography.KeyDerivation.dll
|
||||
Microsoft.AspNetCore.DataProtection.Abstractions.dll
|
||||
Microsoft.AspNetCore.DataProtection.dll
|
||||
Microsoft.AspNetCore.DataProtection.Extensions.dll
|
||||
Microsoft.AspNetCore.Diagnostics.Abstractions.dll
|
||||
Microsoft.AspNetCore.Diagnostics.dll
|
||||
Microsoft.AspNetCore.Diagnostics.HealthChecks.dll
|
||||
Microsoft.AspNetCore.dll
|
||||
Microsoft.AspNetCore.HostFiltering.dll
|
||||
Microsoft.AspNetCore.Hosting.Abstractions.dll
|
||||
Microsoft.AspNetCore.Hosting.dll
|
||||
Microsoft.AspNetCore.Hosting.Server.Abstractions.dll
|
||||
Microsoft.AspNetCore.Html.Abstractions.dll
|
||||
Microsoft.AspNetCore.Http.Abstractions.dll
|
||||
Microsoft.AspNetCore.Http.Connections.Common.dll
|
||||
Microsoft.AspNetCore.Http.Connections.dll
|
||||
Microsoft.AspNetCore.Http.dll
|
||||
Microsoft.AspNetCore.Http.Extensions.dll
|
||||
Microsoft.AspNetCore.Http.Features.dll
|
||||
Microsoft.AspNetCore.Http.Results.dll
|
||||
Microsoft.AspNetCore.HttpLogging.dll
|
||||
Microsoft.AspNetCore.HttpOverrides.dll
|
||||
Microsoft.AspNetCore.HttpsPolicy.dll
|
||||
Microsoft.AspNetCore.Identity.dll
|
||||
Microsoft.AspNetCore.Localization.dll
|
||||
Microsoft.AspNetCore.Localization.Routing.dll
|
||||
Microsoft.AspNetCore.Metadata.dll
|
||||
Microsoft.AspNetCore.Mvc.Abstractions.dll
|
||||
Microsoft.AspNetCore.Mvc.ApiExplorer.dll
|
||||
Microsoft.AspNetCore.Mvc.Core.dll
|
||||
Microsoft.AspNetCore.Mvc.Cors.dll
|
||||
Microsoft.AspNetCore.Mvc.DataAnnotations.dll
|
||||
Microsoft.AspNetCore.Mvc.dll
|
||||
Microsoft.AspNetCore.Mvc.Formatters.Json.dll
|
||||
Microsoft.AspNetCore.Mvc.Formatters.Xml.dll
|
||||
Microsoft.AspNetCore.Mvc.Localization.dll
|
||||
Microsoft.AspNetCore.Mvc.Razor.dll
|
||||
Microsoft.AspNetCore.Mvc.RazorPages.dll
|
||||
Microsoft.AspNetCore.Mvc.TagHelpers.dll
|
||||
Microsoft.AspNetCore.Mvc.ViewFeatures.dll
|
||||
Microsoft.AspNetCore.OutputCaching.dll
|
||||
Microsoft.AspNetCore.RateLimiting.dll
|
||||
Microsoft.AspNetCore.Razor.dll
|
||||
Microsoft.AspNetCore.Razor.Runtime.dll
|
||||
Microsoft.AspNetCore.RequestDecompression.dll
|
||||
Microsoft.AspNetCore.ResponseCaching.Abstractions.dll
|
||||
Microsoft.AspNetCore.ResponseCaching.dll
|
||||
Microsoft.AspNetCore.ResponseCompression.dll
|
||||
Microsoft.AspNetCore.Rewrite.dll
|
||||
Microsoft.AspNetCore.Routing.Abstractions.dll
|
||||
Microsoft.AspNetCore.Routing.dll
|
||||
Microsoft.AspNetCore.Server.HttpSys.dll
|
||||
Microsoft.AspNetCore.Server.IIS.dll
|
||||
Microsoft.AspNetCore.Server.IISIntegration.dll
|
||||
Microsoft.AspNetCore.Server.Kestrel.Core.dll
|
||||
Microsoft.AspNetCore.Server.Kestrel.dll
|
||||
Microsoft.AspNetCore.Server.Kestrel.Transport.NamedPipes.dll
|
||||
Microsoft.AspNetCore.Server.Kestrel.Transport.Quic.dll
|
||||
Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets.dll
|
||||
Microsoft.AspNetCore.Session.dll
|
||||
Microsoft.AspNetCore.SignalR.Common.dll
|
||||
Microsoft.AspNetCore.SignalR.Core.dll
|
||||
Microsoft.AspNetCore.SignalR.dll
|
||||
Microsoft.AspNetCore.SignalR.Protocols.Json.dll
|
||||
Microsoft.AspNetCore.StaticAssets.dll
|
||||
Microsoft.AspNetCore.StaticFiles.dll
|
||||
Microsoft.AspNetCore.WebSockets.dll
|
||||
Microsoft.AspNetCore.WebUtilities.dll
|
||||
Microsoft.Extensions.Caching.Abstractions.dll
|
||||
Microsoft.Extensions.Caching.Memory.dll
|
||||
Microsoft.Extensions.Configuration.Abstractions.dll
|
||||
Microsoft.Extensions.Configuration.Binder.dll
|
||||
Microsoft.Extensions.Configuration.CommandLine.dll
|
||||
Microsoft.Extensions.Configuration.dll
|
||||
Microsoft.Extensions.Configuration.EnvironmentVariables.dll
|
||||
Microsoft.Extensions.Configuration.FileExtensions.dll
|
||||
Microsoft.Extensions.Configuration.Ini.dll
|
||||
Microsoft.Extensions.Configuration.Json.dll
|
||||
Microsoft.Extensions.Configuration.KeyPerFile.dll
|
||||
Microsoft.Extensions.Configuration.UserSecrets.dll
|
||||
Microsoft.Extensions.Configuration.Xml.dll
|
||||
Microsoft.Extensions.DependencyInjection.Abstractions.dll
|
||||
Microsoft.Extensions.DependencyInjection.dll
|
||||
Microsoft.Extensions.Diagnostics.Abstractions.dll
|
||||
Microsoft.Extensions.Diagnostics.dll
|
||||
Microsoft.Extensions.Diagnostics.HealthChecks.Abstractions.dll
|
||||
Microsoft.Extensions.Diagnostics.HealthChecks.dll
|
||||
Microsoft.Extensions.Features.dll
|
||||
Microsoft.Extensions.FileProviders.Abstractions.dll
|
||||
Microsoft.Extensions.FileProviders.Composite.dll
|
||||
Microsoft.Extensions.FileProviders.Embedded.dll
|
||||
Microsoft.Extensions.FileProviders.Physical.dll
|
||||
Microsoft.Extensions.FileSystemGlobbing.dll
|
||||
Microsoft.Extensions.Hosting.Abstractions.dll
|
||||
Microsoft.Extensions.Hosting.dll
|
||||
Microsoft.Extensions.Http.dll
|
||||
Microsoft.Extensions.Identity.Core.dll
|
||||
Microsoft.Extensions.Identity.Stores.dll
|
||||
Microsoft.Extensions.Localization.Abstractions.dll
|
||||
Microsoft.Extensions.Localization.dll
|
||||
Microsoft.Extensions.Logging.Abstractions.dll
|
||||
Microsoft.Extensions.Logging.Configuration.dll
|
||||
Microsoft.Extensions.Logging.Console.dll
|
||||
Microsoft.Extensions.Logging.Debug.dll
|
||||
Microsoft.Extensions.Logging.dll
|
||||
Microsoft.Extensions.Logging.EventLog.dll
|
||||
Microsoft.Extensions.Logging.EventSource.dll
|
||||
Microsoft.Extensions.Logging.TraceSource.dll
|
||||
Microsoft.Extensions.ObjectPool.dll
|
||||
Microsoft.Extensions.Options.ConfigurationExtensions.dll
|
||||
Microsoft.Extensions.Options.DataAnnotations.dll
|
||||
Microsoft.Extensions.Options.dll
|
||||
Microsoft.Extensions.Primitives.dll
|
||||
Microsoft.Extensions.Validation.dll
|
||||
Microsoft.Extensions.WebEncoders.dll
|
||||
Microsoft.JSInterop.dll
|
||||
Microsoft.Net.Http.Headers.dll
|
||||
System.Diagnostics.EventLog.dll
|
||||
System.Formats.Cbor.dll
|
||||
System.Security.Cryptography.Xml.dll
|
||||
System.Threading.RateLimiting.dll
|
||||
<DOTNET>/packs/Microsoft.NETCore.App.Ref/10.0.8/ref/net10.0/
|
||||
Microsoft.CSharp.dll
|
||||
Microsoft.VisualBasic.Core.dll
|
||||
Microsoft.VisualBasic.dll
|
||||
Microsoft.Win32.Primitives.dll
|
||||
Microsoft.Win32.Registry.dll
|
||||
mscorlib.dll
|
||||
netstandard.dll
|
||||
System.AppContext.dll
|
||||
System.Buffers.dll
|
||||
System.Collections.Concurrent.dll
|
||||
System.Collections.dll
|
||||
System.Collections.Immutable.dll
|
||||
System.Collections.NonGeneric.dll
|
||||
System.Collections.Specialized.dll
|
||||
System.ComponentModel.Annotations.dll
|
||||
System.ComponentModel.DataAnnotations.dll
|
||||
System.ComponentModel.dll
|
||||
System.ComponentModel.EventBasedAsync.dll
|
||||
System.ComponentModel.Primitives.dll
|
||||
System.ComponentModel.TypeConverter.dll
|
||||
System.Configuration.dll
|
||||
System.Console.dll
|
||||
System.Core.dll
|
||||
System.Data.Common.dll
|
||||
System.Data.DataSetExtensions.dll
|
||||
System.Data.dll
|
||||
System.Diagnostics.Contracts.dll
|
||||
System.Diagnostics.Debug.dll
|
||||
System.Diagnostics.DiagnosticSource.dll
|
||||
System.Diagnostics.FileVersionInfo.dll
|
||||
System.Diagnostics.Process.dll
|
||||
System.Diagnostics.StackTrace.dll
|
||||
System.Diagnostics.TextWriterTraceListener.dll
|
||||
System.Diagnostics.Tools.dll
|
||||
System.Diagnostics.TraceSource.dll
|
||||
System.Diagnostics.Tracing.dll
|
||||
System.dll
|
||||
System.Drawing.dll
|
||||
System.Drawing.Primitives.dll
|
||||
System.Dynamic.Runtime.dll
|
||||
System.Formats.Asn1.dll
|
||||
System.Formats.Tar.dll
|
||||
System.Globalization.Calendars.dll
|
||||
System.Globalization.dll
|
||||
System.Globalization.Extensions.dll
|
||||
System.IO.Compression.Brotli.dll
|
||||
System.IO.Compression.dll
|
||||
System.IO.Compression.FileSystem.dll
|
||||
System.IO.Compression.ZipFile.dll
|
||||
System.IO.dll
|
||||
System.IO.FileSystem.AccessControl.dll
|
||||
System.IO.FileSystem.dll
|
||||
System.IO.FileSystem.DriveInfo.dll
|
||||
System.IO.FileSystem.Primitives.dll
|
||||
System.IO.FileSystem.Watcher.dll
|
||||
System.IO.IsolatedStorage.dll
|
||||
System.IO.MemoryMappedFiles.dll
|
||||
System.IO.Pipelines.dll
|
||||
System.IO.Pipes.AccessControl.dll
|
||||
System.IO.Pipes.dll
|
||||
System.IO.UnmanagedMemoryStream.dll
|
||||
System.Linq.AsyncEnumerable.dll
|
||||
System.Linq.dll
|
||||
System.Linq.Expressions.dll
|
||||
System.Linq.Parallel.dll
|
||||
System.Linq.Queryable.dll
|
||||
System.Memory.dll
|
||||
System.Net.dll
|
||||
System.Net.Http.dll
|
||||
System.Net.Http.Json.dll
|
||||
System.Net.HttpListener.dll
|
||||
System.Net.Mail.dll
|
||||
System.Net.NameResolution.dll
|
||||
System.Net.NetworkInformation.dll
|
||||
System.Net.Ping.dll
|
||||
System.Net.Primitives.dll
|
||||
System.Net.Quic.dll
|
||||
System.Net.Requests.dll
|
||||
System.Net.Security.dll
|
||||
System.Net.ServerSentEvents.dll
|
||||
System.Net.ServicePoint.dll
|
||||
System.Net.Sockets.dll
|
||||
System.Net.WebClient.dll
|
||||
System.Net.WebHeaderCollection.dll
|
||||
System.Net.WebProxy.dll
|
||||
System.Net.WebSockets.Client.dll
|
||||
System.Net.WebSockets.dll
|
||||
System.Numerics.dll
|
||||
System.Numerics.Vectors.dll
|
||||
System.ObjectModel.dll
|
||||
System.Reflection.DispatchProxy.dll
|
||||
System.Reflection.dll
|
||||
System.Reflection.Emit.dll
|
||||
System.Reflection.Emit.ILGeneration.dll
|
||||
System.Reflection.Emit.Lightweight.dll
|
||||
System.Reflection.Extensions.dll
|
||||
System.Reflection.Metadata.dll
|
||||
System.Reflection.Primitives.dll
|
||||
System.Reflection.TypeExtensions.dll
|
||||
System.Resources.Reader.dll
|
||||
System.Resources.ResourceManager.dll
|
||||
System.Resources.Writer.dll
|
||||
System.Runtime.CompilerServices.Unsafe.dll
|
||||
System.Runtime.CompilerServices.VisualC.dll
|
||||
System.Runtime.dll
|
||||
System.Runtime.Extensions.dll
|
||||
System.Runtime.Handles.dll
|
||||
System.Runtime.InteropServices.dll
|
||||
System.Runtime.InteropServices.JavaScript.dll
|
||||
System.Runtime.InteropServices.RuntimeInformation.dll
|
||||
System.Runtime.Intrinsics.dll
|
||||
System.Runtime.Loader.dll
|
||||
System.Runtime.Numerics.dll
|
||||
System.Runtime.Serialization.dll
|
||||
System.Runtime.Serialization.Formatters.dll
|
||||
System.Runtime.Serialization.Json.dll
|
||||
System.Runtime.Serialization.Primitives.dll
|
||||
System.Runtime.Serialization.Xml.dll
|
||||
System.Security.AccessControl.dll
|
||||
System.Security.Claims.dll
|
||||
System.Security.Cryptography.Algorithms.dll
|
||||
System.Security.Cryptography.Cng.dll
|
||||
System.Security.Cryptography.Csp.dll
|
||||
System.Security.Cryptography.dll
|
||||
System.Security.Cryptography.Encoding.dll
|
||||
System.Security.Cryptography.OpenSsl.dll
|
||||
System.Security.Cryptography.Primitives.dll
|
||||
System.Security.Cryptography.X509Certificates.dll
|
||||
System.Security.dll
|
||||
System.Security.Principal.dll
|
||||
System.Security.Principal.Windows.dll
|
||||
System.Security.SecureString.dll
|
||||
System.ServiceModel.Web.dll
|
||||
System.ServiceProcess.dll
|
||||
System.Text.Encoding.CodePages.dll
|
||||
System.Text.Encoding.dll
|
||||
System.Text.Encoding.Extensions.dll
|
||||
System.Text.Encodings.Web.dll
|
||||
System.Text.Json.dll
|
||||
System.Text.RegularExpressions.dll
|
||||
System.Threading.AccessControl.dll
|
||||
System.Threading.Channels.dll
|
||||
System.Threading.dll
|
||||
System.Threading.Overlapped.dll
|
||||
System.Threading.Tasks.Dataflow.dll
|
||||
System.Threading.Tasks.dll
|
||||
System.Threading.Tasks.Extensions.dll
|
||||
System.Threading.Tasks.Parallel.dll
|
||||
System.Threading.Thread.dll
|
||||
System.Threading.ThreadPool.dll
|
||||
System.Threading.Timer.dll
|
||||
System.Transactions.dll
|
||||
System.Transactions.Local.dll
|
||||
System.ValueTuple.dll
|
||||
System.Web.dll
|
||||
System.Web.HttpUtility.dll
|
||||
System.Windows.dll
|
||||
System.Xml.dll
|
||||
System.Xml.Linq.dll
|
||||
System.Xml.ReaderWriter.dll
|
||||
System.Xml.Serialization.dll
|
||||
System.Xml.XDocument.dll
|
||||
System.Xml.XmlDocument.dll
|
||||
System.Xml.XmlSerializer.dll
|
||||
System.Xml.XPath.dll
|
||||
System.Xml.XPath.XDocument.dll
|
||||
WindowsBase.dll
|
||||
<NUGET>/
|
||||
automapper/16.1.1/lib/net10.0/AutoMapper.dll
|
||||
azure.core/1.47.1/lib/net8.0/Azure.Core.dll
|
||||
azure.identity/1.14.2/lib/net8.0/Azure.Identity.dll
|
||||
microsoft.aspnetcore.authentication.negotiate/10.0.8/lib/net10.0/Microsoft.AspNetCore.Authentication.Negotiate.dll
|
||||
microsoft.aspnetcore.jsonpatch/10.0.8/lib/net10.0/Microsoft.AspNetCore.JsonPatch.dll
|
||||
microsoft.aspnetcore.mvc.newtonsoftjson/10.0.8/lib/net10.0/Microsoft.AspNetCore.Mvc.NewtonsoftJson.dll
|
||||
microsoft.aspnetcore.openapi/10.0.8/lib/net10.0/Microsoft.AspNetCore.OpenApi.dll
|
||||
microsoft.bcl.asyncinterfaces/8.0.0/lib/netstandard2.1/Microsoft.Bcl.AsyncInterfaces.dll
|
||||
microsoft.bcl.cryptography/9.0.4/lib/net9.0/Microsoft.Bcl.Cryptography.dll
|
||||
microsoft.data.sqlclient/6.1.1/ref/net9.0/Microsoft.Data.SqlClient.dll
|
||||
microsoft.entityframeworkcore.abstractions/10.0.8/lib/net10.0/Microsoft.EntityFrameworkCore.Abstractions.dll
|
||||
microsoft.entityframeworkcore.relational/10.0.8/lib/net10.0/Microsoft.EntityFrameworkCore.Relational.dll
|
||||
microsoft.entityframeworkcore.sqlserver/10.0.8/lib/net10.0/Microsoft.EntityFrameworkCore.SqlServer.dll
|
||||
microsoft.entityframeworkcore/10.0.8/lib/net10.0/Microsoft.EntityFrameworkCore.dll
|
||||
microsoft.identity.client.extensions.msal/4.73.1/lib/net8.0/Microsoft.Identity.Client.Extensions.Msal.dll
|
||||
microsoft.identity.client/4.73.1/lib/net8.0/Microsoft.Identity.Client.dll
|
||||
microsoft.identitymodel.abstractions/8.14.0/lib/net9.0/Microsoft.IdentityModel.Abstractions.dll
|
||||
microsoft.identitymodel.jsonwebtokens/8.14.0/lib/net9.0/Microsoft.IdentityModel.JsonWebTokens.dll
|
||||
microsoft.identitymodel.logging/8.14.0/lib/net9.0/Microsoft.IdentityModel.Logging.dll
|
||||
microsoft.identitymodel.protocols.openidconnect/7.7.1/lib/net8.0/Microsoft.IdentityModel.Protocols.OpenIdConnect.dll
|
||||
microsoft.identitymodel.protocols/7.7.1/lib/net8.0/Microsoft.IdentityModel.Protocols.dll
|
||||
microsoft.identitymodel.tokens/8.14.0/lib/net9.0/Microsoft.IdentityModel.Tokens.dll
|
||||
microsoft.openapi/2.4.1/lib/net8.0/Microsoft.OpenApi.dll
|
||||
microsoft.sqlserver.server/1.0.0/lib/netstandard2.0/Microsoft.SqlServer.Server.dll
|
||||
newtonsoft.json.bson/1.0.2/lib/netstandard2.0/Newtonsoft.Json.Bson.dll
|
||||
newtonsoft.json/13.0.3/lib/net6.0/Newtonsoft.Json.dll
|
||||
swashbuckle.aspnetcore.swagger/10.1.7/lib/net10.0/Swashbuckle.AspNetCore.Swagger.dll
|
||||
swashbuckle.aspnetcore.swaggergen/10.1.7/lib/net10.0/Swashbuckle.AspNetCore.SwaggerGen.dll
|
||||
swashbuckle.aspnetcore.swaggerui/10.1.7/lib/net10.0/Swashbuckle.AspNetCore.SwaggerUI.dll
|
||||
system.clientmodel/1.5.1/lib/net8.0/System.ClientModel.dll
|
||||
system.directoryservices.protocols/10.0.8/lib/net10.0/System.DirectoryServices.Protocols.dll
|
||||
system.identitymodel.tokens.jwt/7.7.1/lib/net8.0/System.IdentityModel.Tokens.Jwt.dll
|
||||
system.memory.data/8.0.1/lib/net8.0/System.Memory.Data.dll
|
||||
system.security.cryptography.pkcs/9.0.4/lib/net9.0/System.Security.Cryptography.Pkcs.dll
|
||||
system.security.cryptography.protecteddata/9.0.4/lib/net9.0/System.Security.Cryptography.ProtectedData.dll
|
||||
|
||||
[analyzerReferences]
|
||||
<DOTNET>/packs/Microsoft.AspNetCore.App.Ref/10.0.8/analyzers/dotnet/cs/
|
||||
Microsoft.AspNetCore.App.Analyzers.dll
|
||||
Microsoft.AspNetCore.App.CodeFixes.dll
|
||||
Microsoft.AspNetCore.App.SourceGenerators.dll
|
||||
Microsoft.AspNetCore.Components.Analyzers.dll
|
||||
Microsoft.Extensions.Logging.Generators.dll
|
||||
Microsoft.Extensions.Options.SourceGeneration.dll
|
||||
Microsoft.Extensions.Validation.ValidationsGenerator.dll
|
||||
<DOTNET>/packs/Microsoft.NETCore.App.Ref/10.0.8/analyzers/dotnet/cs/
|
||||
Microsoft.Interop.ComInterfaceGenerator.dll
|
||||
Microsoft.Interop.JavaScript.JSImportGenerator.dll
|
||||
Microsoft.Interop.LibraryImportGenerator.dll
|
||||
Microsoft.Interop.SourceGeneration.dll
|
||||
System.Text.Json.SourceGeneration.dll
|
||||
System.Text.RegularExpressions.Generator.dll
|
||||
<DOTNET>/sdk/10.0.300/Sdks/Microsoft.NET.Sdk.Razor/source-generators/
|
||||
Microsoft.AspNetCore.Razor.Utilities.Shared.dll
|
||||
Microsoft.CodeAnalysis.Razor.Compiler.dll
|
||||
Microsoft.Extensions.ObjectPool.dll
|
||||
<DOTNET>/sdk/10.0.300/Sdks/Microsoft.NET.Sdk.Web/analyzers/cs/
|
||||
Microsoft.AspNetCore.Analyzers.dll
|
||||
Microsoft.AspNetCore.Mvc.Analyzers.dll
|
||||
<DOTNET>/sdk/10.0.300/Sdks/Microsoft.NET.Sdk/analyzers/
|
||||
Microsoft.CodeAnalysis.CSharp.NetAnalyzers.dll
|
||||
Microsoft.CodeAnalysis.NetAnalyzers.dll
|
||||
<NUGET>/
|
||||
microsoft.aspnetcore.openapi/10.0.8/analyzers/dotnet/cs/Microsoft.AspNetCore.OpenApi.SourceGenerators.dll
|
||||
microsoft.codeanalysis.analyzers/3.11.0/analyzers/dotnet/cs/
|
||||
Microsoft.CodeAnalysis.Analyzers.dll
|
||||
Microsoft.CodeAnalysis.CSharp.Analyzers.dll
|
||||
microsoft.entityframeworkcore.analyzers/10.0.8/analyzers/dotnet/cs/Microsoft.EntityFrameworkCore.Analyzers.dll
|
||||
system.clientmodel/1.5.1/analyzers/dotnet/cs/System.ClientModel.SourceGeneration.dll
|
||||
|
||||
[analyzerConfigFiles]
|
||||
<DOTNET>/sdk/10.0.300/Sdks/Microsoft.NET.Sdk/analyzers/build/config/analysislevel_10_default.globalconfig
|
||||
obj/Debug/net10.0/Microsoft.SelfService.Portal.Core.API.GeneratedMSBuildEditorConfig.editorconfig
|
||||
@@ -1,20 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<ActiveDebugProfile>https</ActiveDebugProfile>
|
||||
<Controller_SelectedScaffolderID>ApiControllerWithActionsScaffolder</Controller_SelectedScaffolderID>
|
||||
<Controller_SelectedScaffolderCategoryPath>root/Common/Api</Controller_SelectedScaffolderCategoryPath>
|
||||
<WebStackScaffolding_ControllerDialogWidth>650</WebStackScaffolding_ControllerDialogWidth>
|
||||
<WebStackScaffolding_DbContextDialogWidth>650</WebStackScaffolding_DbContextDialogWidth>
|
||||
<WebStackScaffolding_IsLayoutPageSelected>True</WebStackScaffolding_IsLayoutPageSelected>
|
||||
<WebStackScaffolding_IsPartialViewSelected>False</WebStackScaffolding_IsPartialViewSelected>
|
||||
<WebStackScaffolding_IsReferencingScriptLibrariesSelected>True</WebStackScaffolding_IsReferencingScriptLibrariesSelected>
|
||||
<WebStackScaffolding_LayoutPageFile />
|
||||
<WebStackScaffolding_DbContextTypeFullName>Microsoft.SelfService.Portal.Core.API.Data.Context</WebStackScaffolding_DbContextTypeFullName>
|
||||
<WebStackScaffolding_IsAsyncSelected>False</WebStackScaffolding_IsAsyncSelected>
|
||||
<NameOfLastUsedPublishProfile>C:\Users\ASA_Administrator.CCIS-P01S01-CM\source\repos\Microsoft.SelfService.Portal\Microsoft.SelfService.Portal.Core.API\Properties\PublishProfiles\FolderProfile.pubxml</NameOfLastUsedPublishProfile>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
|
||||
<DebuggerFlavor>ProjectDebugger</DebuggerFlavor>
|
||||
</PropertyGroup>
|
||||
</Project>
|
||||
+3390
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+3481
File diff suppressed because one or more lines are too long
@@ -0,0 +1,68 @@
|
||||
using System;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
#nullable disable
|
||||
|
||||
#pragma warning disable CA1814 // Prefer jagged arrays over multidimensional
|
||||
|
||||
namespace Microsoft.SelfService.Portal.Core.API.Migrations
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public partial class SeedCredentialSecretsAndDeploymentArtifacts : Migration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.InsertData(
|
||||
table: "CredentialSecrets",
|
||||
columns: new[] { "Id", "Created", "CreatedBy", "IsEnabled", "MetadataJson", "Modified", "ModifiedBy", "Name", "SecretType", "SecretValue", "UserName" },
|
||||
values: new object[,]
|
||||
{
|
||||
{ new Guid("90000000-0000-0000-0000-000000000001"), new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), "DemoSeed", true, "{\"environment\":\"Demo\",\"plaintext\":true}", new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), "DemoSeed", "Windows/SharePoint/SetupAccount", "Credential", "DemoOnly-DoNotUseInProduction!", "CONTOSO\\svc_sp_setup" },
|
||||
{ new Guid("90000000-0000-0000-0000-000000000002"), new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), "DemoSeed", true, "{\"environment\":\"Demo\",\"plaintext\":true}", new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), "DemoSeed", "Windows/SharePoint/FarmAccount", "Credential", "DemoOnly-DoNotUseInProduction!", "CONTOSO\\svc_sp_farm" },
|
||||
{ new Guid("90000000-0000-0000-0000-000000000003"), new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), "DemoSeed", true, "{\"environment\":\"Demo\",\"plaintext\":true}", new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), "DemoSeed", "Windows/SharePoint/FarmPassphrase", "Secret", "DemoOnly-DoNotUseInProduction!", null },
|
||||
{ new Guid("90000000-0000-0000-0000-000000000004"), new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), "DemoSeed", true, "{\"environment\":\"Demo\",\"plaintext\":true}", new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), "DemoSeed", "Windows/SharePoint/DefaultServiceAccount", "Credential", "DemoOnly-DoNotUseInProduction!", "CONTOSO\\svc_sp_service" },
|
||||
{ new Guid("90000000-0000-0000-0000-000000000005"), new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), "DemoSeed", true, "{\"environment\":\"Demo\",\"plaintext\":true}", new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), "DemoSeed", "Windows/SharePoint/SearchAccount", "Credential", "DemoOnly-DoNotUseInProduction!", "CONTOSO\\svc_sp_search" }
|
||||
});
|
||||
|
||||
migrationBuilder.InsertData(
|
||||
table: "DeploymentArtifacts",
|
||||
columns: new[] { "Id", "ArtifactType", "Created", "CreatedBy", "DeploymentGroupId", "DeploymentJson", "DeploymentTargetId", "InputHash", "IsStale", "Modified", "ModifiedBy", "OutputHash", "ResolvedJson", "SourceJson", "SourceSnapshotJson", "StaleReasonJson", "Status", "TargetId" },
|
||||
values: new object[] { new Guid("85000000-0000-0000-0000-000000000101"), "ResolvedConfigurationData", new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), "DemoSeed", new Guid("80000000-0000-0000-0000-000000000101"), "{\n \"metadata\": {\n \"name\": \"Contoso-Test-SharePoint\",\n \"deploymentId\": \"8f6c2c1a\",\n \"source\": \"DemoData\"\n },\n \"parameters\": {\n \"DatabasePrefix\": \"SharePoint_Contoso_Test\"\n },\n \"variables\": {\n \"DatabasePrefix\": \"SharePoint_Contoso_Test\",\n \"ServiceDbPrefix\": \"SharePoint_Contoso_Test_Services\",\n \"ConfigDbName\": \"SharePoint_Contoso_Test_Farm_Config\"\n },\n \"resources\": {\n \"AllNodes\": [\n { \"NodeName\": \"CLD-SHP-01\", \"RunCentralAdministration\": true },\n { \"NodeName\": \"CLD-SHP-02\", \"RunCentralAdministration\": false },\n { \"NodeName\": \"CLD-SHP-03\", \"RunCentralAdministration\": false }\n ],\n \"NonNodeData\": {\n \"LocalConfigurationManager\": {\n \"ConfigurationMode\": \"ApplyOnly\"\n }\n }\n }\n}", null, "F081B9BACB21534D9673317615B990CC3836D68416CD6C94E06045E524640020", false, new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), "DemoSeed", "8A49E86D9D571FDE9FE243849A5399A73750798F165B0D9DCE1318B8561CEF01", "{\n \"metadata\": {\n \"name\": \"Contoso-Test-SharePoint\",\n \"deploymentId\": \"8f6c2c1a\",\n \"source\": \"DemoData\"\n },\n \"parameters\": {\n \"DatabasePrefix\": \"SharePoint_Contoso_Test\"\n },\n \"variables\": {\n \"DatabasePrefix\": \"SharePoint_Contoso_Test\",\n \"ServiceDbPrefix\": \"SharePoint_Contoso_Test_Services\",\n \"ConfigDbName\": \"SharePoint_Contoso_Test_Farm_Config\"\n },\n \"resources\": {\n \"AllNodes\": [\n { \"NodeName\": \"CLD-SHP-01\", \"RunCentralAdministration\": true },\n { \"NodeName\": \"CLD-SHP-02\", \"RunCentralAdministration\": false },\n { \"NodeName\": \"CLD-SHP-03\", \"RunCentralAdministration\": false }\n ],\n \"NonNodeData\": {\n \"LocalConfigurationManager\": {\n \"ConfigurationMode\": \"ApplyOnly\"\n }\n }\n }\n}", "{\"source\":\"DemoData\",\"composition\":\"Test.Merge.ps1\"}", "{\n \"templateRevisions\": [\n {\n \"id\": \"72000000-0000-0000-0000-000000000101\",\n \"templateVersionId\": \"71000000-0000-0000-0000-000000000101\",\n \"role\": \"Environment\",\n \"alias\": \"Environment-Test\",\n \"hash\": \"58553C7A4E902B5E39D30272754FEF9EF805A7F36363D8316A9B37540C6D4646\"\n },\n {\n \"id\": \"72000000-0000-0000-0000-000000000102\",\n \"templateVersionId\": \"71000000-0000-0000-0000-000000000102\",\n \"role\": \"Domain\",\n \"alias\": \"Domain-Contoso\",\n \"hash\": \"B265C4D542826423BAAF50BF939F026CC67FF631FEC19F708067516BCE4C7667\"\n },\n {\n \"id\": \"72000000-0000-0000-0000-000000000103\",\n \"templateVersionId\": \"71000000-0000-0000-0000-000000000103\",\n \"role\": \"Service\",\n \"alias\": \"Service-SharePoint-Contoso\",\n \"hash\": \"E3B0E2A8E0C85CCD92AEA521ECD243E61E34C61D7078D6715E6317F5669A1D69\"\n },\n {\n \"id\": \"72000000-0000-0000-0000-000000000104\",\n \"templateVersionId\": \"71000000-0000-0000-0000-000000000104\",\n \"role\": \"Stage\",\n \"alias\": \"Stage-Install\",\n \"hash\": \"ACA23E44C9F625F080D2653646555A9DE5546D8DE7BB2166324E775BCF47F3C1\"\n }\n ],\n \"targets\": [\n { \"id\": \"30000000-0000-0000-0000-000000000101\", \"nodeName\": \"CLD-SHP-01\" },\n { \"id\": \"30000000-0000-0000-0000-000000000102\", \"nodeName\": \"CLD-SHP-02\" },\n { \"id\": \"30000000-0000-0000-0000-000000000103\", \"nodeName\": \"CLD-SHP-03\" }\n ]\n}", null, "Pending", null });
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DeleteData(
|
||||
table: "CredentialSecrets",
|
||||
keyColumn: "Id",
|
||||
keyValue: new Guid("90000000-0000-0000-0000-000000000001"));
|
||||
|
||||
migrationBuilder.DeleteData(
|
||||
table: "CredentialSecrets",
|
||||
keyColumn: "Id",
|
||||
keyValue: new Guid("90000000-0000-0000-0000-000000000002"));
|
||||
|
||||
migrationBuilder.DeleteData(
|
||||
table: "CredentialSecrets",
|
||||
keyColumn: "Id",
|
||||
keyValue: new Guid("90000000-0000-0000-0000-000000000003"));
|
||||
|
||||
migrationBuilder.DeleteData(
|
||||
table: "CredentialSecrets",
|
||||
keyColumn: "Id",
|
||||
keyValue: new Guid("90000000-0000-0000-0000-000000000004"));
|
||||
|
||||
migrationBuilder.DeleteData(
|
||||
table: "CredentialSecrets",
|
||||
keyColumn: "Id",
|
||||
keyValue: new Guid("90000000-0000-0000-0000-000000000005"));
|
||||
|
||||
migrationBuilder.DeleteData(
|
||||
table: "DeploymentArtifacts",
|
||||
keyColumn: "Id",
|
||||
keyValue: new Guid("85000000-0000-0000-0000-000000000101"));
|
||||
}
|
||||
}
|
||||
}
|
||||
+4689
File diff suppressed because one or more lines are too long
@@ -0,0 +1,551 @@
|
||||
using System;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
#nullable disable
|
||||
|
||||
#pragma warning disable CA1814 // Prefer jagged arrays over multidimensional
|
||||
|
||||
namespace Microsoft.SelfService.Portal.Core.API.Migrations
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public partial class SeedConfigurationDefinitionsAndValues : Migration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.InsertData(
|
||||
table: "ConfigurationDefinitions",
|
||||
columns: new[] { "Id", "Created", "CreatedBy", "DefinitionHash", "Kind", "Modified", "ModifiedBy", "Name", "PropertiesJson", "TemplateRevisionId" },
|
||||
values: new object[,]
|
||||
{
|
||||
{ new Guid("04091788-4a0a-7911-b11d-b70335ad378a"), new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), "DemoSeed", "66CA01A01EE073BAD5B77E2ECC9F3CB54967A3F4AE820E317C24C35DB6AF5ED2", "Variable", new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), "DemoSeed", "ServiceDbPrefix", "{\"Expression\":\"[joinNotEmpty(\\u0027_\\u0027, variables(\\u0027DatabasePrefix\\u0027), parameters(\\u0027ServiceDatabaseSegment\\u0027))]\"}", new Guid("72000000-0000-0000-0000-000000000103") },
|
||||
{ new Guid("07333ab1-de72-442d-d91a-0bb2dd969443"), new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), "DemoSeed", "81D3F97A03D7745EEB15174781144CD222A27E71F28A08F0C7F03496B74A0C87", "Variable", new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), "DemoSeed", "ContentDbPrefix", "{\"Expression\":\"[joinNotEmpty(\\u0027_\\u0027, variables(\\u0027DatabasePrefix\\u0027), parameters(\\u0027ContentDatabaseSegment\\u0027))]\"}", new Guid("72000000-0000-0000-0000-000000000101") },
|
||||
{ new Guid("13f4b031-f8b8-1ef4-21b0-ab825dc54aee"), new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), "DemoSeed", "16F0D197D56D4E12B3BEB98AEA78A9D9C16DB35C1B09F3FA2298620504820B73", "Parameter", new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), "DemoSeed", "SearchServiceApplicationPoolAccount", "{\r\n \"Metadata\": {\r\n \"Description\": {\r\n \"de-DE\": \"Kontoname fuer den Search-Application-Pool der SharePoint-Serviceanwendungen.\",\r\n \"en-US\": \"Account name used by the search application pool for SharePoint service applications.\"\r\n }\r\n },\r\n \"Sensitive\": true,\r\n \"Value\": {\r\n \"Provider\": \"SecretManagement\",\r\n \"Vault\": \"Test\",\r\n \"Name\": \"Windows/SharePoint/SearchAccount\"\r\n },\r\n \"Type\": \"credential\",\r\n \"Required\": true\r\n }", new Guid("72000000-0000-0000-0000-000000000103") },
|
||||
{ new Guid("14bcd250-6d40-e1a6-5aed-e563c7a2d589"), new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), "DemoSeed", "B020AA02247152F414B03ACFB1281A6A955D4F48CA3CB26A5B42EB3A3169113A", "Variable", new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), "DemoSeed", "ConfigDbName", "{\"Expression\":\"[joinNotEmpty(\\u0027_\\u0027, variables(\\u0027DatabasePrefix\\u0027), \\u0027Farm_Config\\u0027)]\"}", new Guid("72000000-0000-0000-0000-000000000101") },
|
||||
{ new Guid("16fa79cc-52be-7ba0-56ad-051ce1879851"), new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), "DemoSeed", "8F7A22AEDBCA0CCC09451FBE6B969687E56042826C989B85CD3F02569837B761", "Parameter", new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), "DemoSeed", "WebApplicationPoolDefault", "{\r\n \"DefaultValue\": \"SharePoint Web Applications\",\r\n \"Type\": \"string\",\r\n \"Metadata\": {\r\n \"Description\": {\r\n \"de-DE\": \"Anzeigename des Standard-Application-Pools fuer SharePoint-Webanwendungen.\",\r\n \"en-US\": \"Display name of the default application pool for SharePoint web applications.\"\r\n }\r\n }\r\n }", new Guid("72000000-0000-0000-0000-000000000103") },
|
||||
{ new Guid("1e409601-2e11-453e-09bc-ccc0e61a2eaf"), new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), "DemoSeed", "BCDC01B9105DB0D42D6E8CD49092E10713CF4CBB42178218F5B2450CCB1A359A", "Parameter", new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), "DemoSeed", "DatabaseServerName", "{\r\n \"DefaultValue\": \"SQL_Server\",\r\n \"Type\": \"string\",\r\n \"Value\": \"CL-SQL-01\"\r\n }", new Guid("72000000-0000-0000-0000-000000000103") },
|
||||
{ new Guid("1ee4b631-fc15-85dc-3057-a1ca26da7ba9"), new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), "DemoSeed", "48BB0B2F36F4CA5BA7A2326F64B19AFA55D58345E675540A806877A78F61F97D", "Parameter", new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), "DemoSeed", "Landscape", "{\r\n \"DefaultValue\": \"Prod\",\r\n \"Value\": \"Test\",\r\n \"Type\": \"string\",\r\n \"AllowedValues\": [\r\n \"Prod\",\r\n \"QA\",\r\n \"Test\"\r\n ]\r\n }", new Guid("72000000-0000-0000-0000-000000000101") },
|
||||
{ new Guid("1fc14a66-5b69-00da-e92c-a38e6d674b50"), new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), "DemoSeed", "50EDDD3C7853B59491CA782C3A45A9E33EE6709FF4B964D6E42FB2DC4D6D546D", "Parameter", new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), "DemoSeed", "CentralAdminPort", "{\r\n \"DefaultValue\": 443,\r\n \"Type\": \"int\",\r\n \"Value\": 4000\r\n }", new Guid("72000000-0000-0000-0000-000000000103") },
|
||||
{ new Guid("2b7b2531-54ed-e778-e547-f0b696591d0c"), new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), "DemoSeed", "8FF8AE6C17C434DEC71C889173C0AD3E1759B94F99C0ACAFECB657D3327708BA", "Variable", new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), "DemoSeed", "ConfigDbName", "{\"Expression\":\"[concat(parameters('DatabasePrefix'), '_Farm_Config')]\"}", new Guid("72000000-0000-0000-0000-000000000003") },
|
||||
{ new Guid("3bdcaa78-354c-487f-b0c5-6a3e0b20f8a1"), new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), "DemoSeed", "AB14380C5D597E9B70A8F42F768BF86A71118D86A8B9E28237B70952CE0BEBBD", "Variable", new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), "DemoSeed", "AdminDbName", "{\"Expression\":\"[joinNotEmpty(\\u0027_\\u0027, variables(\\u0027DatabasePrefix\\u0027), \\u0027Farm_AdminContent\\u0027)]\"}", new Guid("72000000-0000-0000-0000-000000000103") },
|
||||
{ new Guid("4b3283a0-f2df-1edd-fa3f-a90cacf2a7f1"), new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), "DemoSeed", "071CCD19384E43C652F0CF2E633702F12BBC1CE8A46472DCF1B7EBB9A500795E", "Parameter", new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), "DemoSeed", "DefaultServiceApplicationPoolAccount", "{\r\n \"Metadata\": {\r\n \"Description\": {\r\n \"de-DE\": \"Kontoname fuer den Standard-Application-Pool der SharePoint-Serviceanwendungen.\",\r\n \"en-US\": \"Account name used by the default application pool for SharePoint service applications.\"\r\n }\r\n },\r\n \"Sensitive\": true,\r\n \"Value\": {\r\n \"Provider\": \"SecretManagement\",\r\n \"Vault\": \"Test\",\r\n \"Name\": \"Windows/SharePoint/DefaultServiceAccount\"\r\n },\r\n \"Type\": \"credential\",\r\n \"Required\": true\r\n }", new Guid("72000000-0000-0000-0000-000000000103") },
|
||||
{ new Guid("50f73169-1bda-2644-6963-b7cfad914a6a"), new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), "DemoSeed", "00139B0DB8374A47087A5AE9114E53200D7B2FEF79163BC3E2D627159986141A", "Variable", new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), "DemoSeed", "AdminContentDbName", "{\"Expression\":\"[concat(parameters('DatabasePrefix'), '_AdminContent')]\"}", new Guid("72000000-0000-0000-0000-000000000003") },
|
||||
{ new Guid("57fe8654-dbf4-c6c1-3a99-ac68fe393731"), new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), "DemoSeed", "81D3F97A03D7745EEB15174781144CD222A27E71F28A08F0C7F03496B74A0C87", "Variable", new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), "DemoSeed", "ContentDbPrefix", "{\"Expression\":\"[joinNotEmpty(\\u0027_\\u0027, variables(\\u0027DatabasePrefix\\u0027), parameters(\\u0027ContentDatabaseSegment\\u0027))]\"}", new Guid("72000000-0000-0000-0000-000000000103") },
|
||||
{ new Guid("5d326698-5daf-cf78-b44d-2bbe6625d506"), new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), "DemoSeed", "66CA01A01EE073BAD5B77E2ECC9F3CB54967A3F4AE820E317C24C35DB6AF5ED2", "Variable", new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), "DemoSeed", "ServiceDbPrefix", "{\"Expression\":\"[joinNotEmpty(\\u0027_\\u0027, variables(\\u0027DatabasePrefix\\u0027), parameters(\\u0027ServiceDatabaseSegment\\u0027))]\"}", new Guid("72000000-0000-0000-0000-000000000101") },
|
||||
{ new Guid("62443ac9-c783-01b8-0cf4-21dc6bd57e44"), new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), "DemoSeed", "4F3A9ED930F155C1D23ACD9FD640C0D2253B250467200E68020E1BA9FF25CA15", "Variable", new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), "DemoSeed", "DatabasePrefix", "{\"Expression\":\"[joinNotEmpty(\\u0027_\\u0027, parameters(\\u0027DatabasePrefix\\u0027), parameters(\\u0027DomainLabel\\u0027), if(equals(parameters(\\u0027Landscape\\u0027), \\u0027Test\\u0027), \\u0027Test\\u0027, \\u0027\\u0027))]\"}", new Guid("72000000-0000-0000-0000-000000000101") },
|
||||
{ new Guid("64767ffc-812e-b48e-db29-f295a287258b"), new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), "DemoSeed", "5469237A902DBDD5D1D5365F83BC4369D466C6283B618D5EFFF18037B954D206", "Parameter", new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), "DemoSeed", "MeetingPolicyName", "{ \"type\": \"string\", \"defaultValue\": \"Contoso-Standard-Meetings\" }", new Guid("72000000-0000-0000-0000-000000000004") },
|
||||
{ new Guid("67ca0430-31c6-553d-1553-60401cf4015c"), new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), "DemoSeed", "5A4F2C381DC5EBA68A416A739E7DCF0179EA6FF84D884BAF3A554D488DA9F5CE", "Parameter", new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), "DemoSeed", "DomainName", "{ \"type\": \"string\", \"defaultValue\": \"corp.contoso.com\" }", new Guid("72000000-0000-0000-0000-000000000001") },
|
||||
{ new Guid("68c57a16-e728-4c39-f245-8a41d77d0aa7"), new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), "DemoSeed", "62DE452BEBAE7CC7332895F461CD648707B5434F1EC4D55FA01E6B10A0FC4F74", "Parameter", new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), "DemoSeed", "DomainNetBIOS", "{\r\n \"Type\": \"string\",\r\n \"MaxLength\": 15,\r\n \"Value\": \"CONTOSO\",\r\n \"DefaultValue\": \"\",\r\n \"Pattern\": \"^[A-Za-z0-9_-]+$\",\r\n \"MinLength\": 1,\r\n \"Required\": true\r\n }", new Guid("72000000-0000-0000-0000-000000000102") },
|
||||
{ new Guid("7232ce0f-9f3e-e10b-9370-7aec1c610ecc"), new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), "DemoSeed", "4F3A9ED930F155C1D23ACD9FD640C0D2253B250467200E68020E1BA9FF25CA15", "Variable", new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), "DemoSeed", "DatabasePrefix", "{\"Expression\":\"[joinNotEmpty(\\u0027_\\u0027, parameters(\\u0027DatabasePrefix\\u0027), parameters(\\u0027DomainLabel\\u0027), if(equals(parameters(\\u0027Landscape\\u0027), \\u0027Test\\u0027), \\u0027Test\\u0027, \\u0027\\u0027))]\"}", new Guid("72000000-0000-0000-0000-000000000103") },
|
||||
{ new Guid("72fbe523-8aba-6aed-0918-d3e96f12254f"), new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), "DemoSeed", "112452BFA4BC12A22D96FE3095743046C3BDFBEB7DDC17E473BB2D54E6134AF6", "Parameter", new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), "DemoSeed", "InstanceName", "{ \"type\": \"string\", \"defaultValue\": \"MSSQLSERVER\" }", new Guid("72000000-0000-0000-0000-000000000002") },
|
||||
{ new Guid("73be057e-cd31-1658-186b-bcf4695a48f7"), new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), "DemoSeed", "B020AA02247152F414B03ACFB1281A6A955D4F48CA3CB26A5B42EB3A3169113A", "Variable", new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), "DemoSeed", "ConfigDbName", "{\"Expression\":\"[joinNotEmpty(\\u0027_\\u0027, variables(\\u0027DatabasePrefix\\u0027), \\u0027Farm_Config\\u0027)]\"}", new Guid("72000000-0000-0000-0000-000000000103") },
|
||||
{ new Guid("753acf7d-8ef6-69ef-b710-d430bfef3a98"), new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), "DemoSeed", "F45D71DEA1E2C611B54BD9077A92D438B2DBA2866781ABF397AFA20C2E985E07", "Parameter", new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), "DemoSeed", "ServiceApplicationPoolDefault", "{\r\n \"DefaultValue\": \"SharePoint Service Applications\",\r\n \"Type\": \"string\",\r\n \"Metadata\": {\r\n \"Description\": {\r\n \"de-DE\": \"Anzeigename des Standard-Application-Pools fuer SharePoint-Serviceanwendungen.\",\r\n \"en-US\": \"Display name of the default application pool for SharePoint service applications.\"\r\n }\r\n }\r\n }", new Guid("72000000-0000-0000-0000-000000000103") },
|
||||
{ new Guid("75c6a433-0dfe-1e3e-d324-322a2fad0d71"), new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), "DemoSeed", "FE5E0E49AA2D785B2ECA765C15A57889372826684A465793C1A69B528406D7AB", "Parameter", new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), "DemoSeed", "DomainFQDN", "{\r\n \"DefaultValue\": \"\",\r\n \"Pattern\": \"^[A-Za-z0-9.-]+$\",\r\n \"Type\": \"string\",\r\n \"Value\": \"contoso.local\",\r\n \"Required\": true\r\n }", new Guid("72000000-0000-0000-0000-000000000102") },
|
||||
{ new Guid("80733c50-d68a-d8f9-bb5f-fb6fce6f66a1"), new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), "DemoSeed", "161F0B7F00446101C1C6CBFFAACC28EFE56418E7636DCCEC2C4EE57538ACC182", "Parameter", new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), "DemoSeed", "ServiceDatabaseSegment", "{\r\n \"DefaultValue\": \"Services\",\r\n \"Type\": \"string\",\r\n \"Metadata\": {\r\n \"Description\": {\r\n \"de-DE\": \"Namenssegment fuer SharePoint-Service-Datenbanken innerhalb des Datenbanknamens.\",\r\n \"en-US\": \"Name segment used for SharePoint service databases within the database name.\"\r\n }\r\n }\r\n }", new Guid("72000000-0000-0000-0000-000000000103") },
|
||||
{ new Guid("8e334e04-0465-ca82-b4f0-fd01561cdb4a"), new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), "DemoSeed", "75224F964656A4CFD8BBB38F26767A098A327F35A986F0E63247B75B0CD0C834", "Parameter", new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), "DemoSeed", "FarmAccount", "{ \"type\": \"credential\", \"metadata\": { \"description\": \"Farm account resolved by the credential provider.\" } }", new Guid("72000000-0000-0000-0000-000000000003") },
|
||||
{ new Guid("971fc778-2e79-6408-aec3-1beeaf7fce8e"), new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), "DemoSeed", "DB3469AE0FFB2D1669BD5E8B3078C3FA04FF8DB4FA67998C9610BE9C1C96FB53", "Parameter", new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), "DemoSeed", "NetBIOSName", "{ \"type\": \"string\", \"defaultValue\": \"CONTOSO\" }", new Guid("72000000-0000-0000-0000-000000000001") },
|
||||
{ new Guid("9c60f6a6-a0c8-9f27-d31e-030403f78cd9"), new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), "DemoSeed", "8BAB062E6AAAE0E29902434B02DDFEC4A79908E307530CC3177F081F587317BD", "Parameter", new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), "DemoSeed", "CallingPolicyName", "{ \"type\": \"string\", \"defaultValue\": \"Contoso-Standard-Calling\" }", new Guid("72000000-0000-0000-0000-000000000004") },
|
||||
{ new Guid("a1bbb850-c83a-f3ee-474c-dc9484456e2a"), new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), "DemoSeed", "21654CC3E82D2DE59E438E554C32F074BA88894F1F6825BC0154D6B127CDCDD8", "Parameter", new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), "DemoSeed", "WebApplicationPoolDefaultAccount", "{\r\n \"DefaultValue\": \"SVC_SHP_WAP\",\r\n \"Type\": \"string\",\r\n \"Metadata\": {\r\n \"Description\": {\r\n \"de-DE\": \"Kontoname fuer den Standard-Application-Pool der SharePoint-Webanwendungen.\",\r\n \"en-US\": \"Account name used by the default application pool for SharePoint web applications.\"\r\n }\r\n }\r\n }", new Guid("72000000-0000-0000-0000-000000000103") },
|
||||
{ new Guid("a7cc8607-ab28-8765-6fb3-87222c485f65"), new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), "DemoSeed", "2BFD19F4E9E81007EBA8B7EDE220316E042FF6B1471CF1C33AD47E8FEE083121", "Parameter", new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), "DemoSeed", "DatabaseInstanceName", "{\r\n \"DefaultValue\": \"SQL_Server\",\r\n \"Type\": \"string\",\r\n \"Value\": \"SQLServer\"\r\n }", new Guid("72000000-0000-0000-0000-000000000103") },
|
||||
{ new Guid("a9be4c68-f2c0-279f-6a98-92b5ac3c0e80"), new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), "DemoSeed", "AB14380C5D597E9B70A8F42F768BF86A71118D86A8B9E28237B70952CE0BEBBD", "Variable", new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), "DemoSeed", "AdminDbName", "{\"Expression\":\"[joinNotEmpty(\\u0027_\\u0027, variables(\\u0027DatabasePrefix\\u0027), \\u0027Farm_AdminContent\\u0027)]\"}", new Guid("72000000-0000-0000-0000-000000000101") },
|
||||
{ new Guid("afa8d0b4-7fc7-d419-7f01-6fb1fd59be4d"), new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), "DemoSeed", "E61970B4774DA1EABE34D93AE56C4647008872A0E01B9F1862D67B7049E02CDB", "Variable", new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), "DemoSeed", "ConfigDatabase", "{\"Expression\":\"[concat(parameters('DatabasePrefix'), '_Config')]\"}", new Guid("72000000-0000-0000-0000-000000000002") },
|
||||
{ new Guid("b5f3de9e-251e-ebb1-c6cc-b4a1a2afc987"), new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), "DemoSeed", "C16A8CDDCD81BAA020E26C1EC06AB229A4483E095A9259E1C471CC7322CCF011", "Parameter", new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), "DemoSeed", "ProductKey", "{\r\n \"DefaultValue\": \"0000-0000-0000-0000-0000\",\r\n \"Type\": \"string\",\r\n \"Metadata\": {\r\n \"Description\": {\r\n \"de-DE\": \"SharePoint-Produktlizenzschluessel.\",\r\n \"en-US\": \"SharePoint product license key.\"\r\n }\r\n }\r\n }", new Guid("72000000-0000-0000-0000-000000000103") },
|
||||
{ new Guid("c32f0de1-59a8-ffb2-a421-92209185de89"), new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), "DemoSeed", "28AF3E6D01302114A9A83652445875D944E00AE5291CDC76F34BE5D412328B4D", "Parameter", new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), "DemoSeed", "ContentDatabaseSegment", "{\r\n \"DefaultValue\": \"Content\",\r\n \"Type\": \"string\",\r\n \"Metadata\": {\r\n \"Description\": {\r\n \"de-DE\": \"Namenssegment fuer SharePoint-Content-Datenbanken innerhalb des Datenbanknamens.\",\r\n \"en-US\": \"Name segment used for SharePoint content databases within the database name.\"\r\n }\r\n }\r\n }", new Guid("72000000-0000-0000-0000-000000000103") },
|
||||
{ new Guid("d0fbeeb9-628d-fa56-c106-6f54e3080b11"), new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), "DemoSeed", "4BE38B4AB1097AB42C79DA38FE0E6B6F4399319E22B23CCE5461BF7D1D1E586E", "Parameter", new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), "DemoSeed", "DatabasePrefix", "{\r\n \"DefaultValue\": \"SharePoint\",\r\n \"Type\": \"string\",\r\n \"Value\": \"SharePoint\"\r\n }", new Guid("72000000-0000-0000-0000-000000000103") },
|
||||
{ new Guid("d7d653e4-d29b-b9be-d701-b4eae2b34d2e"), new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), "DemoSeed", "B259744A1EB2E69B9D7B2A4BA1B0A9B1930AD837872C7D4F4ABDEEFA2F61A868", "Parameter", new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), "DemoSeed", "DatabasePrefix", "{ \"type\": \"string\", \"defaultValue\": \"SharePoint_Contoso_Test\" }", new Guid("72000000-0000-0000-0000-000000000003") },
|
||||
{ new Guid("dc4af326-9a3d-c4a6-9462-669bcf16103a"), new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), "DemoSeed", "DDC6599447376095A217761107BAB8795DBDB6CD0D7418A8B1A2E49684E1EFB8", "Variable", new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), "DemoSeed", "DefaultSiteName", "{\"Expression\":\"[concat(parameters('DomainName'), '-DefaultSite')]\"}", new Guid("72000000-0000-0000-0000-000000000001") },
|
||||
{ new Guid("dc6781e4-7ca7-7307-bf91-42078ba9dea1"), new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), "DemoSeed", "DED3F6C00C32BA6888DEFA172C837415D118388478A160D872AEA098B38C9298", "Parameter", new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), "DemoSeed", "DatabaseTcpPort", "{\r\n \"DefaultValue\": 1433,\r\n \"Type\": \"int\",\r\n \"Value\": 1433\r\n }", new Guid("72000000-0000-0000-0000-000000000103") },
|
||||
{ new Guid("de747816-08b8-faf8-d4ee-57b47222a7f4"), new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), "DemoSeed", "1E280B017D410A45BBF262CBED384ADA7AE42FB0D1390BDFF68909FD4389043A", "Parameter", new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), "DemoSeed", "FarmPassphrase", "{\r\n \"Sensitive\": true,\r\n \"Value\": {\r\n \"Provider\": \"SecretManagement\",\r\n \"Vault\": \"Test\",\r\n \"Name\": \"Windows/SharePoint/FarmPassphrase\"\r\n },\r\n \"Type\": \"credential\",\r\n \"Required\": true\r\n }", new Guid("72000000-0000-0000-0000-000000000103") },
|
||||
{ new Guid("dfb00c19-363f-7518-47be-1ba0ec16abd7"), new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), "DemoSeed", "ECF2FC72BEF5492B23764A1316ABEE9652F23D5C02A569A6FF59D35AAB4DE603", "Parameter", new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), "DemoSeed", "DomainLabel", "{\r\n \"Type\": \"string\",\r\n \"MaxLength\": 32,\r\n \"Value\": \"Contoso\",\r\n \"DefaultValue\": \"\",\r\n \"Pattern\": \"^[A-Za-z][A-Za-z0-9_-]*$\",\r\n \"MinLength\": 2,\r\n \"Required\": false\r\n }", new Guid("72000000-0000-0000-0000-000000000102") },
|
||||
{ new Guid("e9a93051-120a-00c2-c69d-794d3d3c6c86"), new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), "DemoSeed", "4A1AAAAA8D012E87FDFCB9C7B45C490E35B4FDD1341A6D8682591E25DE782A1F", "Parameter", new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), "DemoSeed", "SetupCredential", "{\r\n \"Sensitive\": true,\r\n \"Value\": {\r\n \"Provider\": \"SecretManagement\",\r\n \"Vault\": \"Test\",\r\n \"Name\": \"Windows/SharePoint/SetupAccount\"\r\n },\r\n \"Type\": \"credential\",\r\n \"Required\": true\r\n }", new Guid("72000000-0000-0000-0000-000000000103") },
|
||||
{ new Guid("eb2d6268-83d4-ecc7-1696-eff819ac5db5"), new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), "DemoSeed", "0975CC4EB86BE0F5D26FF2E44A7663ECDC550671F88270DE44E402AA36793609", "Parameter", new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), "DemoSeed", "DatabasePrefix", "{ \"type\": \"string\", \"defaultValue\": \"Contoso\" }", new Guid("72000000-0000-0000-0000-000000000002") },
|
||||
{ new Guid("efbb9cc6-ed11-105b-91e4-0d925c214e32"), new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), "DemoSeed", "8EF099B36AF59BC20F3FBB9D9CBBFAC9F1E32D52521A890F9510216D862DCDA2", "Parameter", new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), "DemoSeed", "FarmCredential", "{\r\n \"Sensitive\": true,\r\n \"Value\": {\r\n \"Provider\": \"SecretManagement\",\r\n \"Vault\": \"Test\",\r\n \"Name\": \"Windows/SharePoint/FarmAccount\"\r\n },\r\n \"Type\": \"credential\",\r\n \"Required\": true\r\n }", new Guid("72000000-0000-0000-0000-000000000103") },
|
||||
{ new Guid("f7ea1bce-9cf1-ddc4-320f-e26ef51a6108"), new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), "DemoSeed", "3932CF99DA0C5583F34A16C94762F0EA1E94A2D197E4E56D5F2226863686577E", "Parameter", new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), "DemoSeed", "ServiceApplicationPoolSearch", "{\r\n \"DefaultValue\": \"SharePoint Search Service Applications\",\r\n \"Type\": \"string\",\r\n \"Metadata\": {\r\n \"Description\": {\r\n \"de-DE\": \"Anzeigename des Application-Pools fuer SharePoint Search-Serviceanwendungen.\",\r\n \"en-US\": \"Display name of the application pool for SharePoint Search service applications.\"\r\n }\r\n }\r\n }", new Guid("72000000-0000-0000-0000-000000000103") }
|
||||
});
|
||||
|
||||
migrationBuilder.InsertData(
|
||||
table: "ConfigurationValues",
|
||||
columns: new[] { "Id", "ConfigurationDefinitionId", "Created", "CreatedBy", "Modified", "ModifiedBy", "ScopeId", "ScopeType", "SortOrder", "SourcePath", "ValueHash", "ValueJson", "ValueSourceType" },
|
||||
values: new object[,]
|
||||
{
|
||||
{ new Guid("0d47df0b-4ae8-e379-42f7-660dbf80cff1"), new Guid("73be057e-cd31-1658-186b-bcf4695a48f7"), new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), "DemoSeed", new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), "DemoSeed", new Guid("72000000-0000-0000-0000-000000000103"), "TemplateRevision", 50, null, "261FCBE546960FDBA45B615045DC04AE5B717633C4368C87A25A81B31339BE96", "{\"expression\":\"[joinNotEmpty(\\u0027_\\u0027, variables(\\u0027DatabasePrefix\\u0027), \\u0027Farm_Config\\u0027)]\"}", "Expression" },
|
||||
{ new Guid("146d60ab-37ba-8fbf-83f1-89a0976b70c7"), new Guid("d7d653e4-d29b-b9be-d701-b4eae2b34d2e"), new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), "DemoSeed", new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), "DemoSeed", new Guid("72000000-0000-0000-0000-000000000003"), "TemplateRevision", 10, null, "44136FA355B3678A1146AD16F7E8649E94FB4FC21FE77E8310C060F61CAAFF8A", "{}", "Static" },
|
||||
{ new Guid("1a37be2a-89b9-4784-e89e-604946b4a2a0"), new Guid("e9a93051-120a-00c2-c69d-794d3d3c6c86"), new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), "DemoSeed", new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), "DemoSeed", new Guid("72000000-0000-0000-0000-000000000103"), "TemplateRevision", 130, null, "178FED388ECABE98936E5F474887112583588BF34C39241AC452A48A3E1CEA11", "{\"value\":{\r\n \"Provider\": \"SecretManagement\",\r\n \"Vault\": \"Test\",\r\n \"Name\": \"Windows/SharePoint/SetupAccount\"\r\n }}", "SecretReference" },
|
||||
{ new Guid("27a2b22c-871b-a5e9-fda1-a862c1238f03"), new Guid("80733c50-d68a-d8f9-bb5f-fb6fce6f66a1"), new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), "DemoSeed", new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), "DemoSeed", new Guid("72000000-0000-0000-0000-000000000103"), "TemplateRevision", 70, null, "2E39290C9FFD6829B4EFE9004DF7D8236A17E02EE49D03EA79A0DAA936A1F249", "{\"value\":\"Services\"}", "Static" },
|
||||
{ new Guid("2e2fe570-7204-6b79-d073-b62171e5c5ea"), new Guid("dc6781e4-7ca7-7307-bf91-42078ba9dea1"), new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), "DemoSeed", new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), "DemoSeed", new Guid("72000000-0000-0000-0000-000000000103"), "TemplateRevision", 100, null, "635B61BE7E1B2CF8197647383A166882478C6632F878068D383D1307C2678EC4", "{\"value\":1433}", "Static" },
|
||||
{ new Guid("42f554e8-2d02-ce15-b5eb-e9344b3af1de"), new Guid("a9be4c68-f2c0-279f-6a98-92b5ac3c0e80"), new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), "DemoSeed", new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), "DemoSeed", new Guid("72000000-0000-0000-0000-000000000101"), "TemplateRevision", 10, null, "F1D875A6571735F22CA408E51F3793292BD9051C28443A107D3D3AE3E67CC18F", "{\"expression\":\"[joinNotEmpty(\\u0027_\\u0027, variables(\\u0027DatabasePrefix\\u0027), \\u0027Farm_AdminContent\\u0027)]\"}", "Expression" },
|
||||
{ new Guid("49c62e61-ae10-259f-188c-618cd50e22a4"), new Guid("9c60f6a6-a0c8-9f27-d31e-030403f78cd9"), new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), "DemoSeed", new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), "DemoSeed", new Guid("72000000-0000-0000-0000-000000000004"), "TemplateRevision", 10, null, "44136FA355B3678A1146AD16F7E8649E94FB4FC21FE77E8310C060F61CAAFF8A", "{}", "Static" },
|
||||
{ new Guid("4a01be5c-e40f-5a3e-e2af-548739f4d0ae"), new Guid("68c57a16-e728-4c39-f245-8a41d77d0aa7"), new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), "DemoSeed", new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), "DemoSeed", new Guid("72000000-0000-0000-0000-000000000102"), "TemplateRevision", 30, null, "41D77AE0AA9812940953F0E186514FBC3AF0E59F19573213C33A206FBE74C903", "{\"value\":\"CONTOSO\"}", "Static" },
|
||||
{ new Guid("4a2c7cf6-41f3-b20f-de61-6efaf96444f9"), new Guid("67ca0430-31c6-553d-1553-60401cf4015c"), new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), "DemoSeed", new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), "DemoSeed", new Guid("72000000-0000-0000-0000-000000000001"), "TemplateRevision", 10, null, "44136FA355B3678A1146AD16F7E8649E94FB4FC21FE77E8310C060F61CAAFF8A", "{}", "Static" },
|
||||
{ new Guid("4d9d3f0a-dd2e-7f7a-4bbd-8e33526dcbce"), new Guid("3bdcaa78-354c-487f-b0c5-6a3e0b20f8a1"), new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), "DemoSeed", new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), "DemoSeed", new Guid("72000000-0000-0000-0000-000000000103"), "TemplateRevision", 10, null, "F1D875A6571735F22CA408E51F3793292BD9051C28443A107D3D3AE3E67CC18F", "{\"expression\":\"[joinNotEmpty(\\u0027_\\u0027, variables(\\u0027DatabasePrefix\\u0027), \\u0027Farm_AdminContent\\u0027)]\"}", "Expression" },
|
||||
{ new Guid("534db414-821b-59d3-b082-3c57efff2bff"), new Guid("dfb00c19-363f-7518-47be-1ba0ec16abd7"), new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), "DemoSeed", new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), "DemoSeed", new Guid("72000000-0000-0000-0000-000000000102"), "TemplateRevision", 20, null, "03289E6E378FD3D96F2565E9A7B802E0D8AB301F7CAE63F1853CB4080B19EEDF", "{\"value\":\"Contoso\"}", "Static" },
|
||||
{ new Guid("57913480-45b6-f13d-504d-b05d239a2366"), new Guid("72fbe523-8aba-6aed-0918-d3e96f12254f"), new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), "DemoSeed", new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), "DemoSeed", new Guid("72000000-0000-0000-0000-000000000002"), "TemplateRevision", 10, null, "44136FA355B3678A1146AD16F7E8649E94FB4FC21FE77E8310C060F61CAAFF8A", "{}", "Static" },
|
||||
{ new Guid("651d7a24-db44-f18e-2607-1da3a1afbd9c"), new Guid("eb2d6268-83d4-ecc7-1696-eff819ac5db5"), new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), "DemoSeed", new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), "DemoSeed", new Guid("72000000-0000-0000-0000-000000000002"), "TemplateRevision", 20, null, "44136FA355B3678A1146AD16F7E8649E94FB4FC21FE77E8310C060F61CAAFF8A", "{}", "Static" },
|
||||
{ new Guid("665a2e6b-80a7-f64d-85b8-7386c9366549"), new Guid("de747816-08b8-faf8-d4ee-57b47222a7f4"), new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), "DemoSeed", new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), "DemoSeed", new Guid("72000000-0000-0000-0000-000000000103"), "TemplateRevision", 80, null, "ED585C568AA8DAB5EEBB883F90FB02B5B31C614A290A806CFD44E451EC8303ED", "{\"value\":{\r\n \"Provider\": \"SecretManagement\",\r\n \"Vault\": \"Test\",\r\n \"Name\": \"Windows/SharePoint/FarmPassphrase\"\r\n }}", "SecretReference" },
|
||||
{ new Guid("67204f36-a09b-233d-c022-9b4c713f40e1"), new Guid("13f4b031-f8b8-1ef4-21b0-ab825dc54aee"), new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), "DemoSeed", new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), "DemoSeed", new Guid("72000000-0000-0000-0000-000000000103"), "TemplateRevision", 150, null, "5B90965D61E7AD5163813A169214CA5CF9F2297487CEEBFE591487661CBFEBE1", "{\"value\":{\r\n \"Provider\": \"SecretManagement\",\r\n \"Vault\": \"Test\",\r\n \"Name\": \"Windows/SharePoint/SearchAccount\"\r\n }}", "SecretReference" },
|
||||
{ new Guid("680f4dac-c18b-0646-f036-478caf967a7a"), new Guid("1fc14a66-5b69-00da-e92c-a38e6d674b50"), new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), "DemoSeed", new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), "DemoSeed", new Guid("72000000-0000-0000-0000-000000000103"), "TemplateRevision", 160, null, "80473B1B926C839E59F1D74E99D16E1BBC9E57E96B87545421BA23E9BF9E2536", "{\"value\":4000}", "Static" },
|
||||
{ new Guid("6c056e2d-4714-80d0-905a-f49c62ea8d31"), new Guid("64767ffc-812e-b48e-db29-f295a287258b"), new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), "DemoSeed", new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), "DemoSeed", new Guid("72000000-0000-0000-0000-000000000004"), "TemplateRevision", 20, null, "44136FA355B3678A1146AD16F7E8649E94FB4FC21FE77E8310C060F61CAAFF8A", "{}", "Static" },
|
||||
{ new Guid("7ac33a52-7ee3-6b42-78fb-c125f218fa2b"), new Guid("62443ac9-c783-01b8-0cf4-21dc6bd57e44"), new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), "DemoSeed", new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), "DemoSeed", new Guid("72000000-0000-0000-0000-000000000101"), "TemplateRevision", 40, null, "7EB8E130BDEA0111303714519A04B078E07970AEBD2C51EC0244F90D3E3DFC98", "{\"expression\":\"[joinNotEmpty(\\u0027_\\u0027, parameters(\\u0027DatabasePrefix\\u0027), parameters(\\u0027DomainLabel\\u0027), if(equals(parameters(\\u0027Landscape\\u0027), \\u0027Test\\u0027), \\u0027Test\\u0027, \\u0027\\u0027))]\"}", "Expression" },
|
||||
{ new Guid("7e85c8b9-3fd6-fef6-eea5-d8789601e7de"), new Guid("8e334e04-0465-ca82-b4f0-fd01561cdb4a"), new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), "DemoSeed", new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), "DemoSeed", new Guid("72000000-0000-0000-0000-000000000003"), "TemplateRevision", 20, null, "44136FA355B3678A1146AD16F7E8649E94FB4FC21FE77E8310C060F61CAAFF8A", "{}", "Static" },
|
||||
{ new Guid("8175dee7-8e0a-c7e7-8e66-d4f12a4eb42c"), new Guid("c32f0de1-59a8-ffb2-a421-92209185de89"), new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), "DemoSeed", new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), "DemoSeed", new Guid("72000000-0000-0000-0000-000000000103"), "TemplateRevision", 20, null, "425625B9EBF4642A17AAEA773F1304A83FC7AA89A00BD4C934B7B63434AA605C", "{\"value\":\"Content\"}", "Static" },
|
||||
{ new Guid("834efeb6-4b29-efa5-9856-465663c13458"), new Guid("75c6a433-0dfe-1e3e-d324-322a2fad0d71"), new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), "DemoSeed", new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), "DemoSeed", new Guid("72000000-0000-0000-0000-000000000102"), "TemplateRevision", 10, null, "9EA8921C32C58E37F911E22432BEC6E68686DE6D3B4732B3B08029D606F09FA5", "{\"value\":\"contoso.local\"}", "Static" },
|
||||
{ new Guid("851ce8ed-dc94-d437-4947-f1fbe53e5469"), new Guid("753acf7d-8ef6-69ef-b710-d430bfef3a98"), new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), "DemoSeed", new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), "DemoSeed", new Guid("72000000-0000-0000-0000-000000000103"), "TemplateRevision", 30, null, "6B1F221C6266934F56A72E241B1D8D3426B59088F46B12BF78291F75CDC8008C", "{\"value\":\"SharePoint Service Applications\"}", "Static" },
|
||||
{ new Guid("93bcf261-facd-49b5-376a-fdbb046e46a3"), new Guid("f7ea1bce-9cf1-ddc4-320f-e26ef51a6108"), new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), "DemoSeed", new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), "DemoSeed", new Guid("72000000-0000-0000-0000-000000000103"), "TemplateRevision", 170, null, "7A32645CBAED087EDCAF78976456E695575F839D30D6F09986DDFA3B59E0AA75", "{\"value\":\"SharePoint Search Service Applications\"}", "Static" },
|
||||
{ new Guid("9550114f-755b-9512-b430-603954351fed"), new Guid("afa8d0b4-7fc7-d419-7f01-6fb1fd59be4d"), new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), "DemoSeed", new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), "DemoSeed", new Guid("72000000-0000-0000-0000-000000000002"), "TemplateRevision", 10, null, "6ED96528075B87998FDAF609CB1E2A95224A347D109435B05E4C40A0A2F5FC44", "{\"expression\":\"[concat(parameters('DatabasePrefix'), '_Config')]\"}", "Expression" },
|
||||
{ new Guid("a1c445b1-e063-e267-8721-54c0cdb6b36c"), new Guid("16fa79cc-52be-7ba0-56ad-051ce1879851"), new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), "DemoSeed", new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), "DemoSeed", new Guid("72000000-0000-0000-0000-000000000103"), "TemplateRevision", 40, null, "0370D254CED4857D0DEEBF1E9E8D1061DB1503E1E3E12B7393EE534BBD5AF783", "{\"value\":\"SharePoint Web Applications\"}", "Static" },
|
||||
{ new Guid("a2c1e504-20be-aff3-bde2-bcd9ba98bbba"), new Guid("4b3283a0-f2df-1edd-fa3f-a90cacf2a7f1"), new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), "DemoSeed", new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), "DemoSeed", new Guid("72000000-0000-0000-0000-000000000103"), "TemplateRevision", 110, null, "1843C3695744571EDFEA9C4765EAC5AE430FC8C704AFE1FFDE02FF6E68D8BE45", "{\"value\":{\r\n \"Provider\": \"SecretManagement\",\r\n \"Vault\": \"Test\",\r\n \"Name\": \"Windows/SharePoint/DefaultServiceAccount\"\r\n }}", "SecretReference" },
|
||||
{ new Guid("ab4a8935-6d46-f6da-d17f-0e2abed7b413"), new Guid("14bcd250-6d40-e1a6-5aed-e563c7a2d589"), new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), "DemoSeed", new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), "DemoSeed", new Guid("72000000-0000-0000-0000-000000000101"), "TemplateRevision", 50, null, "261FCBE546960FDBA45B615045DC04AE5B717633C4368C87A25A81B31339BE96", "{\"expression\":\"[joinNotEmpty(\\u0027_\\u0027, variables(\\u0027DatabasePrefix\\u0027), \\u0027Farm_Config\\u0027)]\"}", "Expression" },
|
||||
{ new Guid("aed99da4-e113-0a05-287e-5cca3abc1c7c"), new Guid("d0fbeeb9-628d-fa56-c106-6f54e3080b11"), new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), "DemoSeed", new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), "DemoSeed", new Guid("72000000-0000-0000-0000-000000000103"), "TemplateRevision", 140, null, "E062DA6C7583AEC7061A78C9650B5B9CE023DD629C9E6FC3184CF8D0EFCF5755", "{\"value\":\"SharePoint\"}", "Static" },
|
||||
{ new Guid("b08bf2a8-6bd3-1ed9-bf9b-a4f20738a6eb"), new Guid("1e409601-2e11-453e-09bc-ccc0e61a2eaf"), new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), "DemoSeed", new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), "DemoSeed", new Guid("72000000-0000-0000-0000-000000000103"), "TemplateRevision", 50, null, "E3D4EFD336BE54EA0E9E1BFC14536244717CCCDF5291FAB78721936BA47673C4", "{\"value\":\"CL-SQL-01\"}", "Static" },
|
||||
{ new Guid("b21cf5c3-284f-eca7-cf39-dd7451002ea4"), new Guid("971fc778-2e79-6408-aec3-1beeaf7fce8e"), new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), "DemoSeed", new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), "DemoSeed", new Guid("72000000-0000-0000-0000-000000000001"), "TemplateRevision", 20, null, "44136FA355B3678A1146AD16F7E8649E94FB4FC21FE77E8310C060F61CAAFF8A", "{}", "Static" },
|
||||
{ new Guid("bf6abd6f-d02c-55f4-a27d-b89c19bc9c35"), new Guid("5d326698-5daf-cf78-b44d-2bbe6625d506"), new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), "DemoSeed", new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), "DemoSeed", new Guid("72000000-0000-0000-0000-000000000101"), "TemplateRevision", 30, null, "4D54C78468AB68A528415889AC8B50B89E2F5AFD0B0C36D3F6B060036422009E", "{\"expression\":\"[joinNotEmpty(\\u0027_\\u0027, variables(\\u0027DatabasePrefix\\u0027), parameters(\\u0027ServiceDatabaseSegment\\u0027))]\"}", "Expression" },
|
||||
{ new Guid("bfc73c02-2df3-916e-7f54-f432bab37613"), new Guid("07333ab1-de72-442d-d91a-0bb2dd969443"), new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), "DemoSeed", new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), "DemoSeed", new Guid("72000000-0000-0000-0000-000000000101"), "TemplateRevision", 20, null, "B00E74A711838E3C2D4D3779ED0DEAECCF66172565F88F8F9ACE644EEBFBCD91", "{\"expression\":\"[joinNotEmpty(\\u0027_\\u0027, variables(\\u0027DatabasePrefix\\u0027), parameters(\\u0027ContentDatabaseSegment\\u0027))]\"}", "Expression" },
|
||||
{ new Guid("cd120ede-010a-7433-d59c-13f90301b9e2"), new Guid("b5f3de9e-251e-ebb1-c6cc-b4a1a2afc987"), new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), "DemoSeed", new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), "DemoSeed", new Guid("72000000-0000-0000-0000-000000000103"), "TemplateRevision", 120, null, "09773BB7E26265A65AB115E500C4CD051F10FEAA92C43C4260004F920BFDFAA5", "{\"value\":\"0000-0000-0000-0000-0000\"}", "Static" },
|
||||
{ new Guid("cd9e8e80-1975-10d8-8272-d95ba8275299"), new Guid("a1bbb850-c83a-f3ee-474c-dc9484456e2a"), new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), "DemoSeed", new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), "DemoSeed", new Guid("72000000-0000-0000-0000-000000000103"), "TemplateRevision", 60, null, "16EC9E2621F1BA6E974D9005EECC34771B1D6303EE73DCC86214BAD2F5E4CA81", "{\"value\":\"SVC_SHP_WAP\"}", "Static" },
|
||||
{ new Guid("d336f688-57f4-4df1-a992-27e775a48440"), new Guid("04091788-4a0a-7911-b11d-b70335ad378a"), new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), "DemoSeed", new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), "DemoSeed", new Guid("72000000-0000-0000-0000-000000000103"), "TemplateRevision", 30, null, "4D54C78468AB68A528415889AC8B50B89E2F5AFD0B0C36D3F6B060036422009E", "{\"expression\":\"[joinNotEmpty(\\u0027_\\u0027, variables(\\u0027DatabasePrefix\\u0027), parameters(\\u0027ServiceDatabaseSegment\\u0027))]\"}", "Expression" },
|
||||
{ new Guid("d746cb22-0a95-7464-d693-aa5af56ae901"), new Guid("efbb9cc6-ed11-105b-91e4-0d925c214e32"), new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), "DemoSeed", new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), "DemoSeed", new Guid("72000000-0000-0000-0000-000000000103"), "TemplateRevision", 10, null, "D6BBF1B384A92232566CF22E32A5D99FC9AC6F92E70D86EC00BF1FD5876F6FFB", "{\"value\":{\r\n \"Provider\": \"SecretManagement\",\r\n \"Vault\": \"Test\",\r\n \"Name\": \"Windows/SharePoint/FarmAccount\"\r\n }}", "SecretReference" },
|
||||
{ new Guid("e5c9e96a-c891-0854-60b0-b2246870d0c0"), new Guid("2b7b2531-54ed-e778-e547-f0b696591d0c"), new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), "DemoSeed", new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), "DemoSeed", new Guid("72000000-0000-0000-0000-000000000003"), "TemplateRevision", 10, null, "AB48409D8EC6C4009EFCDEE399B7DEED9BC132543EE5C2CF518A9201B6BEF41D", "{\"expression\":\"[concat(parameters('DatabasePrefix'), '_Farm_Config')]\"}", "Expression" },
|
||||
{ new Guid("e69c4719-077b-8ebc-bf06-708bbbca4052"), new Guid("a7cc8607-ab28-8765-6fb3-87222c485f65"), new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), "DemoSeed", new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), "DemoSeed", new Guid("72000000-0000-0000-0000-000000000103"), "TemplateRevision", 90, null, "794D1C1505B58390120A1BE2139A2056C5ED852D4653730DFD4A206060DD3155", "{\"value\":\"SQLServer\"}", "Static" },
|
||||
{ new Guid("e79ccc48-28ec-72d3-1331-6c825dc1b7c0"), new Guid("50f73169-1bda-2644-6963-b7cfad914a6a"), new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), "DemoSeed", new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), "DemoSeed", new Guid("72000000-0000-0000-0000-000000000003"), "TemplateRevision", 20, null, "7B7FA4E9CF1492587605741B7CEE29F579EC357030B794ED646A19C4474907A6", "{\"expression\":\"[concat(parameters('DatabasePrefix'), '_AdminContent')]\"}", "Expression" },
|
||||
{ new Guid("ea4bdba4-397b-d93a-fc6d-03ff3826d2c1"), new Guid("1ee4b631-fc15-85dc-3057-a1ca26da7ba9"), new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), "DemoSeed", new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), "DemoSeed", new Guid("72000000-0000-0000-0000-000000000101"), "TemplateRevision", 10, null, "94FA03DA6461D6142CFA6448B23D207BC7AFCC89E3CC4B9A507ADA54864A6B6F", "{\"value\":\"Test\"}", "Static" },
|
||||
{ new Guid("eb107c2a-335d-5148-aecf-33ffd3ba51bc"), new Guid("dc4af326-9a3d-c4a6-9462-669bcf16103a"), new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), "DemoSeed", new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), "DemoSeed", new Guid("72000000-0000-0000-0000-000000000001"), "TemplateRevision", 10, null, "C02CA81E91040D74400B8E4D152614D790E8D741A993754383057E87A581AF09", "{\"expression\":\"[concat(parameters('DomainName'), '-DefaultSite')]\"}", "Expression" },
|
||||
{ new Guid("f1520907-d5c3-3e33-1daa-0fbdec706c57"), new Guid("57fe8654-dbf4-c6c1-3a99-ac68fe393731"), new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), "DemoSeed", new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), "DemoSeed", new Guid("72000000-0000-0000-0000-000000000103"), "TemplateRevision", 20, null, "B00E74A711838E3C2D4D3779ED0DEAECCF66172565F88F8F9ACE644EEBFBCD91", "{\"expression\":\"[joinNotEmpty(\\u0027_\\u0027, variables(\\u0027DatabasePrefix\\u0027), parameters(\\u0027ContentDatabaseSegment\\u0027))]\"}", "Expression" },
|
||||
{ new Guid("fc6347da-d00e-db4c-5b5b-5a5e80c568ab"), new Guid("7232ce0f-9f3e-e10b-9370-7aec1c610ecc"), new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), "DemoSeed", new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), "DemoSeed", new Guid("72000000-0000-0000-0000-000000000103"), "TemplateRevision", 40, null, "7EB8E130BDEA0111303714519A04B078E07970AEBD2C51EC0244F90D3E3DFC98", "{\"expression\":\"[joinNotEmpty(\\u0027_\\u0027, parameters(\\u0027DatabasePrefix\\u0027), parameters(\\u0027DomainLabel\\u0027), if(equals(parameters(\\u0027Landscape\\u0027), \\u0027Test\\u0027), \\u0027Test\\u0027, \\u0027\\u0027))]\"}", "Expression" }
|
||||
});
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DeleteData(
|
||||
table: "ConfigurationValues",
|
||||
keyColumn: "Id",
|
||||
keyValue: new Guid("0d47df0b-4ae8-e379-42f7-660dbf80cff1"));
|
||||
|
||||
migrationBuilder.DeleteData(
|
||||
table: "ConfigurationValues",
|
||||
keyColumn: "Id",
|
||||
keyValue: new Guid("146d60ab-37ba-8fbf-83f1-89a0976b70c7"));
|
||||
|
||||
migrationBuilder.DeleteData(
|
||||
table: "ConfigurationValues",
|
||||
keyColumn: "Id",
|
||||
keyValue: new Guid("1a37be2a-89b9-4784-e89e-604946b4a2a0"));
|
||||
|
||||
migrationBuilder.DeleteData(
|
||||
table: "ConfigurationValues",
|
||||
keyColumn: "Id",
|
||||
keyValue: new Guid("27a2b22c-871b-a5e9-fda1-a862c1238f03"));
|
||||
|
||||
migrationBuilder.DeleteData(
|
||||
table: "ConfigurationValues",
|
||||
keyColumn: "Id",
|
||||
keyValue: new Guid("2e2fe570-7204-6b79-d073-b62171e5c5ea"));
|
||||
|
||||
migrationBuilder.DeleteData(
|
||||
table: "ConfigurationValues",
|
||||
keyColumn: "Id",
|
||||
keyValue: new Guid("42f554e8-2d02-ce15-b5eb-e9344b3af1de"));
|
||||
|
||||
migrationBuilder.DeleteData(
|
||||
table: "ConfigurationValues",
|
||||
keyColumn: "Id",
|
||||
keyValue: new Guid("49c62e61-ae10-259f-188c-618cd50e22a4"));
|
||||
|
||||
migrationBuilder.DeleteData(
|
||||
table: "ConfigurationValues",
|
||||
keyColumn: "Id",
|
||||
keyValue: new Guid("4a01be5c-e40f-5a3e-e2af-548739f4d0ae"));
|
||||
|
||||
migrationBuilder.DeleteData(
|
||||
table: "ConfigurationValues",
|
||||
keyColumn: "Id",
|
||||
keyValue: new Guid("4a2c7cf6-41f3-b20f-de61-6efaf96444f9"));
|
||||
|
||||
migrationBuilder.DeleteData(
|
||||
table: "ConfigurationValues",
|
||||
keyColumn: "Id",
|
||||
keyValue: new Guid("4d9d3f0a-dd2e-7f7a-4bbd-8e33526dcbce"));
|
||||
|
||||
migrationBuilder.DeleteData(
|
||||
table: "ConfigurationValues",
|
||||
keyColumn: "Id",
|
||||
keyValue: new Guid("534db414-821b-59d3-b082-3c57efff2bff"));
|
||||
|
||||
migrationBuilder.DeleteData(
|
||||
table: "ConfigurationValues",
|
||||
keyColumn: "Id",
|
||||
keyValue: new Guid("57913480-45b6-f13d-504d-b05d239a2366"));
|
||||
|
||||
migrationBuilder.DeleteData(
|
||||
table: "ConfigurationValues",
|
||||
keyColumn: "Id",
|
||||
keyValue: new Guid("651d7a24-db44-f18e-2607-1da3a1afbd9c"));
|
||||
|
||||
migrationBuilder.DeleteData(
|
||||
table: "ConfigurationValues",
|
||||
keyColumn: "Id",
|
||||
keyValue: new Guid("665a2e6b-80a7-f64d-85b8-7386c9366549"));
|
||||
|
||||
migrationBuilder.DeleteData(
|
||||
table: "ConfigurationValues",
|
||||
keyColumn: "Id",
|
||||
keyValue: new Guid("67204f36-a09b-233d-c022-9b4c713f40e1"));
|
||||
|
||||
migrationBuilder.DeleteData(
|
||||
table: "ConfigurationValues",
|
||||
keyColumn: "Id",
|
||||
keyValue: new Guid("680f4dac-c18b-0646-f036-478caf967a7a"));
|
||||
|
||||
migrationBuilder.DeleteData(
|
||||
table: "ConfigurationValues",
|
||||
keyColumn: "Id",
|
||||
keyValue: new Guid("6c056e2d-4714-80d0-905a-f49c62ea8d31"));
|
||||
|
||||
migrationBuilder.DeleteData(
|
||||
table: "ConfigurationValues",
|
||||
keyColumn: "Id",
|
||||
keyValue: new Guid("7ac33a52-7ee3-6b42-78fb-c125f218fa2b"));
|
||||
|
||||
migrationBuilder.DeleteData(
|
||||
table: "ConfigurationValues",
|
||||
keyColumn: "Id",
|
||||
keyValue: new Guid("7e85c8b9-3fd6-fef6-eea5-d8789601e7de"));
|
||||
|
||||
migrationBuilder.DeleteData(
|
||||
table: "ConfigurationValues",
|
||||
keyColumn: "Id",
|
||||
keyValue: new Guid("8175dee7-8e0a-c7e7-8e66-d4f12a4eb42c"));
|
||||
|
||||
migrationBuilder.DeleteData(
|
||||
table: "ConfigurationValues",
|
||||
keyColumn: "Id",
|
||||
keyValue: new Guid("834efeb6-4b29-efa5-9856-465663c13458"));
|
||||
|
||||
migrationBuilder.DeleteData(
|
||||
table: "ConfigurationValues",
|
||||
keyColumn: "Id",
|
||||
keyValue: new Guid("851ce8ed-dc94-d437-4947-f1fbe53e5469"));
|
||||
|
||||
migrationBuilder.DeleteData(
|
||||
table: "ConfigurationValues",
|
||||
keyColumn: "Id",
|
||||
keyValue: new Guid("93bcf261-facd-49b5-376a-fdbb046e46a3"));
|
||||
|
||||
migrationBuilder.DeleteData(
|
||||
table: "ConfigurationValues",
|
||||
keyColumn: "Id",
|
||||
keyValue: new Guid("9550114f-755b-9512-b430-603954351fed"));
|
||||
|
||||
migrationBuilder.DeleteData(
|
||||
table: "ConfigurationValues",
|
||||
keyColumn: "Id",
|
||||
keyValue: new Guid("a1c445b1-e063-e267-8721-54c0cdb6b36c"));
|
||||
|
||||
migrationBuilder.DeleteData(
|
||||
table: "ConfigurationValues",
|
||||
keyColumn: "Id",
|
||||
keyValue: new Guid("a2c1e504-20be-aff3-bde2-bcd9ba98bbba"));
|
||||
|
||||
migrationBuilder.DeleteData(
|
||||
table: "ConfigurationValues",
|
||||
keyColumn: "Id",
|
||||
keyValue: new Guid("ab4a8935-6d46-f6da-d17f-0e2abed7b413"));
|
||||
|
||||
migrationBuilder.DeleteData(
|
||||
table: "ConfigurationValues",
|
||||
keyColumn: "Id",
|
||||
keyValue: new Guid("aed99da4-e113-0a05-287e-5cca3abc1c7c"));
|
||||
|
||||
migrationBuilder.DeleteData(
|
||||
table: "ConfigurationValues",
|
||||
keyColumn: "Id",
|
||||
keyValue: new Guid("b08bf2a8-6bd3-1ed9-bf9b-a4f20738a6eb"));
|
||||
|
||||
migrationBuilder.DeleteData(
|
||||
table: "ConfigurationValues",
|
||||
keyColumn: "Id",
|
||||
keyValue: new Guid("b21cf5c3-284f-eca7-cf39-dd7451002ea4"));
|
||||
|
||||
migrationBuilder.DeleteData(
|
||||
table: "ConfigurationValues",
|
||||
keyColumn: "Id",
|
||||
keyValue: new Guid("bf6abd6f-d02c-55f4-a27d-b89c19bc9c35"));
|
||||
|
||||
migrationBuilder.DeleteData(
|
||||
table: "ConfigurationValues",
|
||||
keyColumn: "Id",
|
||||
keyValue: new Guid("bfc73c02-2df3-916e-7f54-f432bab37613"));
|
||||
|
||||
migrationBuilder.DeleteData(
|
||||
table: "ConfigurationValues",
|
||||
keyColumn: "Id",
|
||||
keyValue: new Guid("cd120ede-010a-7433-d59c-13f90301b9e2"));
|
||||
|
||||
migrationBuilder.DeleteData(
|
||||
table: "ConfigurationValues",
|
||||
keyColumn: "Id",
|
||||
keyValue: new Guid("cd9e8e80-1975-10d8-8272-d95ba8275299"));
|
||||
|
||||
migrationBuilder.DeleteData(
|
||||
table: "ConfigurationValues",
|
||||
keyColumn: "Id",
|
||||
keyValue: new Guid("d336f688-57f4-4df1-a992-27e775a48440"));
|
||||
|
||||
migrationBuilder.DeleteData(
|
||||
table: "ConfigurationValues",
|
||||
keyColumn: "Id",
|
||||
keyValue: new Guid("d746cb22-0a95-7464-d693-aa5af56ae901"));
|
||||
|
||||
migrationBuilder.DeleteData(
|
||||
table: "ConfigurationValues",
|
||||
keyColumn: "Id",
|
||||
keyValue: new Guid("e5c9e96a-c891-0854-60b0-b2246870d0c0"));
|
||||
|
||||
migrationBuilder.DeleteData(
|
||||
table: "ConfigurationValues",
|
||||
keyColumn: "Id",
|
||||
keyValue: new Guid("e69c4719-077b-8ebc-bf06-708bbbca4052"));
|
||||
|
||||
migrationBuilder.DeleteData(
|
||||
table: "ConfigurationValues",
|
||||
keyColumn: "Id",
|
||||
keyValue: new Guid("e79ccc48-28ec-72d3-1331-6c825dc1b7c0"));
|
||||
|
||||
migrationBuilder.DeleteData(
|
||||
table: "ConfigurationValues",
|
||||
keyColumn: "Id",
|
||||
keyValue: new Guid("ea4bdba4-397b-d93a-fc6d-03ff3826d2c1"));
|
||||
|
||||
migrationBuilder.DeleteData(
|
||||
table: "ConfigurationValues",
|
||||
keyColumn: "Id",
|
||||
keyValue: new Guid("eb107c2a-335d-5148-aecf-33ffd3ba51bc"));
|
||||
|
||||
migrationBuilder.DeleteData(
|
||||
table: "ConfigurationValues",
|
||||
keyColumn: "Id",
|
||||
keyValue: new Guid("f1520907-d5c3-3e33-1daa-0fbdec706c57"));
|
||||
|
||||
migrationBuilder.DeleteData(
|
||||
table: "ConfigurationValues",
|
||||
keyColumn: "Id",
|
||||
keyValue: new Guid("fc6347da-d00e-db4c-5b5b-5a5e80c568ab"));
|
||||
|
||||
migrationBuilder.DeleteData(
|
||||
table: "ConfigurationDefinitions",
|
||||
keyColumn: "Id",
|
||||
keyValue: new Guid("04091788-4a0a-7911-b11d-b70335ad378a"));
|
||||
|
||||
migrationBuilder.DeleteData(
|
||||
table: "ConfigurationDefinitions",
|
||||
keyColumn: "Id",
|
||||
keyValue: new Guid("07333ab1-de72-442d-d91a-0bb2dd969443"));
|
||||
|
||||
migrationBuilder.DeleteData(
|
||||
table: "ConfigurationDefinitions",
|
||||
keyColumn: "Id",
|
||||
keyValue: new Guid("13f4b031-f8b8-1ef4-21b0-ab825dc54aee"));
|
||||
|
||||
migrationBuilder.DeleteData(
|
||||
table: "ConfigurationDefinitions",
|
||||
keyColumn: "Id",
|
||||
keyValue: new Guid("14bcd250-6d40-e1a6-5aed-e563c7a2d589"));
|
||||
|
||||
migrationBuilder.DeleteData(
|
||||
table: "ConfigurationDefinitions",
|
||||
keyColumn: "Id",
|
||||
keyValue: new Guid("16fa79cc-52be-7ba0-56ad-051ce1879851"));
|
||||
|
||||
migrationBuilder.DeleteData(
|
||||
table: "ConfigurationDefinitions",
|
||||
keyColumn: "Id",
|
||||
keyValue: new Guid("1e409601-2e11-453e-09bc-ccc0e61a2eaf"));
|
||||
|
||||
migrationBuilder.DeleteData(
|
||||
table: "ConfigurationDefinitions",
|
||||
keyColumn: "Id",
|
||||
keyValue: new Guid("1ee4b631-fc15-85dc-3057-a1ca26da7ba9"));
|
||||
|
||||
migrationBuilder.DeleteData(
|
||||
table: "ConfigurationDefinitions",
|
||||
keyColumn: "Id",
|
||||
keyValue: new Guid("1fc14a66-5b69-00da-e92c-a38e6d674b50"));
|
||||
|
||||
migrationBuilder.DeleteData(
|
||||
table: "ConfigurationDefinitions",
|
||||
keyColumn: "Id",
|
||||
keyValue: new Guid("2b7b2531-54ed-e778-e547-f0b696591d0c"));
|
||||
|
||||
migrationBuilder.DeleteData(
|
||||
table: "ConfigurationDefinitions",
|
||||
keyColumn: "Id",
|
||||
keyValue: new Guid("3bdcaa78-354c-487f-b0c5-6a3e0b20f8a1"));
|
||||
|
||||
migrationBuilder.DeleteData(
|
||||
table: "ConfigurationDefinitions",
|
||||
keyColumn: "Id",
|
||||
keyValue: new Guid("4b3283a0-f2df-1edd-fa3f-a90cacf2a7f1"));
|
||||
|
||||
migrationBuilder.DeleteData(
|
||||
table: "ConfigurationDefinitions",
|
||||
keyColumn: "Id",
|
||||
keyValue: new Guid("50f73169-1bda-2644-6963-b7cfad914a6a"));
|
||||
|
||||
migrationBuilder.DeleteData(
|
||||
table: "ConfigurationDefinitions",
|
||||
keyColumn: "Id",
|
||||
keyValue: new Guid("57fe8654-dbf4-c6c1-3a99-ac68fe393731"));
|
||||
|
||||
migrationBuilder.DeleteData(
|
||||
table: "ConfigurationDefinitions",
|
||||
keyColumn: "Id",
|
||||
keyValue: new Guid("5d326698-5daf-cf78-b44d-2bbe6625d506"));
|
||||
|
||||
migrationBuilder.DeleteData(
|
||||
table: "ConfigurationDefinitions",
|
||||
keyColumn: "Id",
|
||||
keyValue: new Guid("62443ac9-c783-01b8-0cf4-21dc6bd57e44"));
|
||||
|
||||
migrationBuilder.DeleteData(
|
||||
table: "ConfigurationDefinitions",
|
||||
keyColumn: "Id",
|
||||
keyValue: new Guid("64767ffc-812e-b48e-db29-f295a287258b"));
|
||||
|
||||
migrationBuilder.DeleteData(
|
||||
table: "ConfigurationDefinitions",
|
||||
keyColumn: "Id",
|
||||
keyValue: new Guid("67ca0430-31c6-553d-1553-60401cf4015c"));
|
||||
|
||||
migrationBuilder.DeleteData(
|
||||
table: "ConfigurationDefinitions",
|
||||
keyColumn: "Id",
|
||||
keyValue: new Guid("68c57a16-e728-4c39-f245-8a41d77d0aa7"));
|
||||
|
||||
migrationBuilder.DeleteData(
|
||||
table: "ConfigurationDefinitions",
|
||||
keyColumn: "Id",
|
||||
keyValue: new Guid("7232ce0f-9f3e-e10b-9370-7aec1c610ecc"));
|
||||
|
||||
migrationBuilder.DeleteData(
|
||||
table: "ConfigurationDefinitions",
|
||||
keyColumn: "Id",
|
||||
keyValue: new Guid("72fbe523-8aba-6aed-0918-d3e96f12254f"));
|
||||
|
||||
migrationBuilder.DeleteData(
|
||||
table: "ConfigurationDefinitions",
|
||||
keyColumn: "Id",
|
||||
keyValue: new Guid("73be057e-cd31-1658-186b-bcf4695a48f7"));
|
||||
|
||||
migrationBuilder.DeleteData(
|
||||
table: "ConfigurationDefinitions",
|
||||
keyColumn: "Id",
|
||||
keyValue: new Guid("753acf7d-8ef6-69ef-b710-d430bfef3a98"));
|
||||
|
||||
migrationBuilder.DeleteData(
|
||||
table: "ConfigurationDefinitions",
|
||||
keyColumn: "Id",
|
||||
keyValue: new Guid("75c6a433-0dfe-1e3e-d324-322a2fad0d71"));
|
||||
|
||||
migrationBuilder.DeleteData(
|
||||
table: "ConfigurationDefinitions",
|
||||
keyColumn: "Id",
|
||||
keyValue: new Guid("80733c50-d68a-d8f9-bb5f-fb6fce6f66a1"));
|
||||
|
||||
migrationBuilder.DeleteData(
|
||||
table: "ConfigurationDefinitions",
|
||||
keyColumn: "Id",
|
||||
keyValue: new Guid("8e334e04-0465-ca82-b4f0-fd01561cdb4a"));
|
||||
|
||||
migrationBuilder.DeleteData(
|
||||
table: "ConfigurationDefinitions",
|
||||
keyColumn: "Id",
|
||||
keyValue: new Guid("971fc778-2e79-6408-aec3-1beeaf7fce8e"));
|
||||
|
||||
migrationBuilder.DeleteData(
|
||||
table: "ConfigurationDefinitions",
|
||||
keyColumn: "Id",
|
||||
keyValue: new Guid("9c60f6a6-a0c8-9f27-d31e-030403f78cd9"));
|
||||
|
||||
migrationBuilder.DeleteData(
|
||||
table: "ConfigurationDefinitions",
|
||||
keyColumn: "Id",
|
||||
keyValue: new Guid("a1bbb850-c83a-f3ee-474c-dc9484456e2a"));
|
||||
|
||||
migrationBuilder.DeleteData(
|
||||
table: "ConfigurationDefinitions",
|
||||
keyColumn: "Id",
|
||||
keyValue: new Guid("a7cc8607-ab28-8765-6fb3-87222c485f65"));
|
||||
|
||||
migrationBuilder.DeleteData(
|
||||
table: "ConfigurationDefinitions",
|
||||
keyColumn: "Id",
|
||||
keyValue: new Guid("a9be4c68-f2c0-279f-6a98-92b5ac3c0e80"));
|
||||
|
||||
migrationBuilder.DeleteData(
|
||||
table: "ConfigurationDefinitions",
|
||||
keyColumn: "Id",
|
||||
keyValue: new Guid("afa8d0b4-7fc7-d419-7f01-6fb1fd59be4d"));
|
||||
|
||||
migrationBuilder.DeleteData(
|
||||
table: "ConfigurationDefinitions",
|
||||
keyColumn: "Id",
|
||||
keyValue: new Guid("b5f3de9e-251e-ebb1-c6cc-b4a1a2afc987"));
|
||||
|
||||
migrationBuilder.DeleteData(
|
||||
table: "ConfigurationDefinitions",
|
||||
keyColumn: "Id",
|
||||
keyValue: new Guid("c32f0de1-59a8-ffb2-a421-92209185de89"));
|
||||
|
||||
migrationBuilder.DeleteData(
|
||||
table: "ConfigurationDefinitions",
|
||||
keyColumn: "Id",
|
||||
keyValue: new Guid("d0fbeeb9-628d-fa56-c106-6f54e3080b11"));
|
||||
|
||||
migrationBuilder.DeleteData(
|
||||
table: "ConfigurationDefinitions",
|
||||
keyColumn: "Id",
|
||||
keyValue: new Guid("d7d653e4-d29b-b9be-d701-b4eae2b34d2e"));
|
||||
|
||||
migrationBuilder.DeleteData(
|
||||
table: "ConfigurationDefinitions",
|
||||
keyColumn: "Id",
|
||||
keyValue: new Guid("dc4af326-9a3d-c4a6-9462-669bcf16103a"));
|
||||
|
||||
migrationBuilder.DeleteData(
|
||||
table: "ConfigurationDefinitions",
|
||||
keyColumn: "Id",
|
||||
keyValue: new Guid("dc6781e4-7ca7-7307-bf91-42078ba9dea1"));
|
||||
|
||||
migrationBuilder.DeleteData(
|
||||
table: "ConfigurationDefinitions",
|
||||
keyColumn: "Id",
|
||||
keyValue: new Guid("de747816-08b8-faf8-d4ee-57b47222a7f4"));
|
||||
|
||||
migrationBuilder.DeleteData(
|
||||
table: "ConfigurationDefinitions",
|
||||
keyColumn: "Id",
|
||||
keyValue: new Guid("dfb00c19-363f-7518-47be-1ba0ec16abd7"));
|
||||
|
||||
migrationBuilder.DeleteData(
|
||||
table: "ConfigurationDefinitions",
|
||||
keyColumn: "Id",
|
||||
keyValue: new Guid("e9a93051-120a-00c2-c69d-794d3d3c6c86"));
|
||||
|
||||
migrationBuilder.DeleteData(
|
||||
table: "ConfigurationDefinitions",
|
||||
keyColumn: "Id",
|
||||
keyValue: new Guid("eb2d6268-83d4-ecc7-1696-eff819ac5db5"));
|
||||
|
||||
migrationBuilder.DeleteData(
|
||||
table: "ConfigurationDefinitions",
|
||||
keyColumn: "Id",
|
||||
keyValue: new Guid("efbb9cc6-ed11-105b-91e4-0d925c214e32"));
|
||||
|
||||
migrationBuilder.DeleteData(
|
||||
table: "ConfigurationDefinitions",
|
||||
keyColumn: "Id",
|
||||
keyValue: new Guid("f7ea1bce-9cf1-ddc4-320f-e26ef51a6108"));
|
||||
}
|
||||
}
|
||||
}
|
||||
+4778
File diff suppressed because one or more lines are too long
@@ -0,0 +1,56 @@
|
||||
using System;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace Microsoft.SelfService.Portal.Core.API.Migrations
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public partial class AddOnPremApiClients : Migration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.CreateTable(
|
||||
name: "ApiClients",
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<Guid>(type: "uniqueidentifier", nullable: false, defaultValueSql: "NEWID()"),
|
||||
ClientId = table.Column<string>(type: "nvarchar(128)", maxLength: 128, nullable: false),
|
||||
Name = table.Column<string>(type: "nvarchar(max)", nullable: false),
|
||||
SecretHash = table.Column<string>(type: "nvarchar(max)", nullable: false),
|
||||
ScopesJson = table.Column<string>(type: "nvarchar(max)", nullable: false),
|
||||
IsEnabled = table.Column<bool>(type: "bit", nullable: false),
|
||||
ExpiresAt = table.Column<DateTime>(type: "datetime2", nullable: true),
|
||||
LastUsedAt = table.Column<DateTime>(type: "datetime2", nullable: true),
|
||||
Modified = table.Column<DateTime>(type: "datetime2", nullable: false, defaultValueSql: "GETDATE()"),
|
||||
ModifiedBy = table.Column<string>(type: "nvarchar(max)", nullable: false),
|
||||
Created = table.Column<DateTime>(type: "datetime2", nullable: false, defaultValueSql: "GETDATE()"),
|
||||
CreatedBy = table.Column<string>(type: "nvarchar(max)", nullable: false)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_ApiClients", x => x.Id);
|
||||
table.CheckConstraint("CK_ApiClients_ScopesJson_IsJson", "ISJSON([ScopesJson]) = 1");
|
||||
});
|
||||
|
||||
migrationBuilder.InsertData(
|
||||
table: "ApiClients",
|
||||
columns: new[] { "Id", "ClientId", "Created", "CreatedBy", "ExpiresAt", "IsEnabled", "LastUsedAt", "Modified", "ModifiedBy", "Name", "ScopesJson", "SecretHash" },
|
||||
values: new object[] { new Guid("91000000-0000-0000-0000-000000000001"), "ssp-demo-worker", new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), "DemoSeed", null, true, null, new DateTime(2026, 7, 7, 0, 0, 0, 0, DateTimeKind.Utc), "DemoSeed", "Demo Worker Client", "[\"deployment.read\",\"deployment.write\",\"queue.process\",\"template.read\",\"credential.resolve\"]", "PBKDF2-SHA256.100000.c3NwLWRlbW8td29ya2VyAA==.xQxe7BHCn9pdkqHozdyspEmKnz95uCUuxVvU2vgCEbo=" });
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_ApiClients_ClientId",
|
||||
table: "ApiClients",
|
||||
column: "ClientId",
|
||||
unique: true);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropTable(
|
||||
name: "ApiClients");
|
||||
}
|
||||
}
|
||||
}
|
||||
+4884
File diff suppressed because one or more lines are too long
@@ -0,0 +1,71 @@
|
||||
using System;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace Microsoft.SelfService.Portal.Core.API.Migrations
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public partial class AddApiTokenManagement : Migration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.CreateTable(
|
||||
name: "ApiTokens",
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<Guid>(type: "uniqueidentifier", nullable: false, defaultValueSql: "NEWID()"),
|
||||
Jti = table.Column<string>(type: "nvarchar(64)", maxLength: 64, nullable: false),
|
||||
Subject = table.Column<string>(type: "nvarchar(450)", nullable: false),
|
||||
SubjectType = table.Column<string>(type: "nvarchar(32)", maxLength: 32, nullable: false),
|
||||
ApiClientId = table.Column<Guid>(type: "uniqueidentifier", nullable: true),
|
||||
Name = table.Column<string>(type: "nvarchar(max)", nullable: false),
|
||||
ScopesJson = table.Column<string>(type: "nvarchar(max)", nullable: false),
|
||||
IssuedAt = table.Column<DateTime>(type: "datetime2", nullable: false),
|
||||
ExpiresAt = table.Column<DateTime>(type: "datetime2", nullable: false),
|
||||
RevokedAt = table.Column<DateTime>(type: "datetime2", nullable: true),
|
||||
RevokedBy = table.Column<string>(type: "nvarchar(max)", nullable: true),
|
||||
LastUsedAt = table.Column<DateTime>(type: "datetime2", nullable: true),
|
||||
Modified = table.Column<DateTime>(type: "datetime2", nullable: false, defaultValueSql: "GETDATE()"),
|
||||
ModifiedBy = table.Column<string>(type: "nvarchar(max)", nullable: false),
|
||||
Created = table.Column<DateTime>(type: "datetime2", nullable: false, defaultValueSql: "GETDATE()"),
|
||||
CreatedBy = table.Column<string>(type: "nvarchar(max)", nullable: false)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_ApiTokens", x => x.Id);
|
||||
table.CheckConstraint("CK_ApiTokens_ScopesJson_IsJson", "ISJSON([ScopesJson]) = 1");
|
||||
table.ForeignKey(
|
||||
name: "FK_ApiTokens_ApiClients_ApiClientId",
|
||||
column: x => x.ApiClientId,
|
||||
principalTable: "ApiClients",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.SetNull);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_ApiTokens_ApiClientId",
|
||||
table: "ApiTokens",
|
||||
column: "ApiClientId");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_ApiTokens_Jti",
|
||||
table: "ApiTokens",
|
||||
column: "Jti",
|
||||
unique: true);
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_ApiTokens_SubjectType_Subject",
|
||||
table: "ApiTokens",
|
||||
columns: new[] { "SubjectType", "Subject" });
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropTable(
|
||||
name: "ApiTokens");
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,33 @@
|
||||
using System;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace Microsoft.SelfService.Portal.Core.API.Migrations
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public partial class AddDemoApiClientTokenScopes : Migration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.UpdateData(
|
||||
table: "ApiClients",
|
||||
keyColumn: "Id",
|
||||
keyValue: new Guid("91000000-0000-0000-0000-000000000001"),
|
||||
column: "ScopesJson",
|
||||
value: "[\"deployment.read\",\"deployment.write\",\"queue.process\",\"template.read\",\"credential.resolve\",\"token.manage\",\"token.admin\"]");
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.UpdateData(
|
||||
table: "ApiClients",
|
||||
keyColumn: "Id",
|
||||
keyValue: new Guid("91000000-0000-0000-0000-000000000001"),
|
||||
column: "ScopesJson",
|
||||
value: "[\"deployment.read\",\"deployment.write\",\"queue.process\",\"template.read\",\"credential.resolve\"]");
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,28 @@
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
|
||||
namespace Microsoft.SelfService.Portal.Core.API.Models
|
||||
{
|
||||
public class ApiClientModel : BaseModel
|
||||
{
|
||||
[Column(Order = 1)]
|
||||
public string ClientId { get; set; } = string.Empty;
|
||||
|
||||
[Column(Order = 2)]
|
||||
public string Name { get; set; } = string.Empty;
|
||||
|
||||
[Column(Order = 3)]
|
||||
public string SecretHash { get; set; } = string.Empty;
|
||||
|
||||
[Column(Order = 4)]
|
||||
public string ScopesJson { get; set; } = "[]";
|
||||
|
||||
[Column(Order = 5)]
|
||||
public bool IsEnabled { get; set; } = true;
|
||||
|
||||
[Column(Order = 6)]
|
||||
public DateTime? ExpiresAt { get; set; }
|
||||
|
||||
[Column(Order = 7)]
|
||||
public DateTime? LastUsedAt { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
|
||||
namespace Microsoft.SelfService.Portal.Core.API.Models
|
||||
{
|
||||
public class ApiTokenModel : BaseModel
|
||||
{
|
||||
[Column(Order = 1)]
|
||||
public string Jti { get; set; } = string.Empty;
|
||||
|
||||
[Column(Order = 2)]
|
||||
public string Subject { get; set; } = string.Empty;
|
||||
|
||||
[Column(Order = 3)]
|
||||
public string SubjectType { get; set; } = "User";
|
||||
|
||||
[Column(Order = 4)]
|
||||
public Guid? ApiClientId { get; set; }
|
||||
|
||||
[Column(Order = 5)]
|
||||
public string Name { get; set; } = string.Empty;
|
||||
|
||||
[Column(Order = 6)]
|
||||
public string ScopesJson { get; set; } = "[]";
|
||||
|
||||
[Column(Order = 7)]
|
||||
public DateTime IssuedAt { get; set; } = DateTime.UtcNow;
|
||||
|
||||
[Column(Order = 8)]
|
||||
public DateTime ExpiresAt { get; set; }
|
||||
|
||||
[Column(Order = 9)]
|
||||
public DateTime? RevokedAt { get; set; }
|
||||
|
||||
[Column(Order = 10)]
|
||||
public string? RevokedBy { get; set; }
|
||||
|
||||
[Column(Order = 11)]
|
||||
public DateTime? LastUsedAt { get; set; }
|
||||
|
||||
public ApiClientModel? ApiClient { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
|
||||
namespace Microsoft.SelfService.Portal.Core.API.Models
|
||||
{
|
||||
public static class ConfigurationDefinitionKinds
|
||||
{
|
||||
public const string Parameter = "Parameter";
|
||||
public const string Variable = "Variable";
|
||||
}
|
||||
|
||||
public class ConfigurationDefinitionModel : BaseModel
|
||||
{
|
||||
[Column(Order = 1)]
|
||||
public Guid? TemplateRevisionId { get; set; }
|
||||
|
||||
[Column(Order = 2)]
|
||||
public string Kind { get; set; } = ConfigurationDefinitionKinds.Parameter;
|
||||
|
||||
[Column(Order = 3)]
|
||||
public string Name { get; set; } = string.Empty;
|
||||
|
||||
[Column(Order = 4)]
|
||||
public string PropertiesJson { get; set; } = "{}";
|
||||
|
||||
[Column(Order = 5)]
|
||||
public string DefinitionHash { get; set; } = string.Empty;
|
||||
|
||||
public TemplateRevisionModel? TemplateRevision { get; set; }
|
||||
public ICollection<ConfigurationValueModel> Values { get; set; } = new List<ConfigurationValueModel>();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
|
||||
namespace Microsoft.SelfService.Portal.Core.API.Models
|
||||
{
|
||||
public static class ConfigurationValueSourceTypes
|
||||
{
|
||||
public const string Static = "Static";
|
||||
public const string ScopeProperty = "ScopeProperty";
|
||||
public const string Expression = "Expression";
|
||||
public const string SecretReference = "SecretReference";
|
||||
}
|
||||
|
||||
public static class ConfigurationValueScopeTypes
|
||||
{
|
||||
public const string TemplateRevision = "TemplateRevision";
|
||||
public const string Environment = "Environment";
|
||||
public const string Domain = "Domain";
|
||||
public const string Target = "Target";
|
||||
public const string DeploymentGroup = "DeploymentGroup";
|
||||
public const string Deployment = "Deployment";
|
||||
public const string TemplateSelection = "TemplateSelection";
|
||||
}
|
||||
|
||||
public class ConfigurationValueModel : BaseModel
|
||||
{
|
||||
[Column(Order = 1)]
|
||||
public Guid ConfigurationDefinitionId { get; set; }
|
||||
|
||||
[Column(Order = 2)]
|
||||
public string ScopeType { get; set; } = ConfigurationValueScopeTypes.TemplateRevision;
|
||||
|
||||
[Column(Order = 3)]
|
||||
public Guid ScopeId { get; set; }
|
||||
|
||||
[Column(Order = 4)]
|
||||
public string ValueSourceType { get; set; } = ConfigurationValueSourceTypes.Static;
|
||||
|
||||
[Column(Order = 5)]
|
||||
public string? SourcePath { get; set; }
|
||||
|
||||
[Column(Order = 6)]
|
||||
public string? ValueJson { get; set; }
|
||||
|
||||
[Column(Order = 7)]
|
||||
public string ValueHash { get; set; } = string.Empty;
|
||||
|
||||
[Column(Order = 8)]
|
||||
public int SortOrder { get; set; }
|
||||
|
||||
public ConfigurationDefinitionModel ConfigurationDefinition { get; set; } = null!;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
|
||||
namespace Microsoft.SelfService.Portal.Core.API.Models
|
||||
{
|
||||
public class CredentialSecretModel : BaseModel
|
||||
{
|
||||
[Column(Order = 1)]
|
||||
public string Name { get; set; } = string.Empty;
|
||||
|
||||
[Column(Order = 2)]
|
||||
public string? UserName { get; set; }
|
||||
|
||||
[Column(Order = 3)]
|
||||
public string SecretValue { get; set; } = string.Empty;
|
||||
|
||||
[Column(Order = 4)]
|
||||
public string SecretType { get; set; } = "Credential";
|
||||
|
||||
[Column(Order = 5)]
|
||||
public string? MetadataJson { get; set; }
|
||||
|
||||
[Column(Order = 6)]
|
||||
public bool IsEnabled { get; set; } = true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
|
||||
namespace Microsoft.SelfService.Portal.Core.API.Models
|
||||
{
|
||||
public static class DeploymentArtifactTypes
|
||||
{
|
||||
public const string Preview = "Preview";
|
||||
public const string ResolvedConfigurationData = "ResolvedConfigurationData";
|
||||
public const string Mof = "Mof";
|
||||
public const string PullServerPackage = "PullServerPackage";
|
||||
}
|
||||
|
||||
public class DeploymentArtifactModel : BaseModel
|
||||
{
|
||||
[Column(Order = 1)]
|
||||
public Guid DeploymentGroupId { get; set; }
|
||||
|
||||
[Column(Order = 2)]
|
||||
public Guid? DeploymentTargetId { get; set; }
|
||||
|
||||
[Column(Order = 3)]
|
||||
public Guid? TargetId { get; set; }
|
||||
|
||||
[Column(Order = 4)]
|
||||
public string ArtifactType { get; set; } = DeploymentArtifactTypes.ResolvedConfigurationData;
|
||||
|
||||
[Column(Order = 5)]
|
||||
public string Status { get; set; } = QueueJobStatus.Pending;
|
||||
|
||||
[Column(Order = 6)]
|
||||
public string DeploymentJson { get; set; } = "{}";
|
||||
|
||||
[Column(Order = 7)]
|
||||
public string? SourceJson { get; set; }
|
||||
|
||||
[Column(Order = 8)]
|
||||
public string? ResolvedJson { get; set; }
|
||||
|
||||
[Column(Order = 9)]
|
||||
public string? SourceSnapshotJson { get; set; }
|
||||
|
||||
[Column(Order = 10)]
|
||||
public string InputHash { get; set; } = string.Empty;
|
||||
|
||||
[Column(Order = 11)]
|
||||
public string OutputHash { get; set; } = string.Empty;
|
||||
|
||||
[Column(Order = 12)]
|
||||
public bool IsStale { get; set; }
|
||||
|
||||
[Column(Order = 13)]
|
||||
public string? StaleReasonJson { get; set; }
|
||||
|
||||
public DeploymentGroupModel DeploymentGroup { get; set; } = null!;
|
||||
public DeploymentModel? Deployment { get; set; }
|
||||
public TargetModel? Target { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -22,6 +22,7 @@ namespace Microsoft.SelfService.Portal.Core.API.Models
|
||||
public ICollection<DeploymentTemplateSelectionModel> TemplateSelections { get; set; } = new List<DeploymentTemplateSelectionModel>();
|
||||
public ICollection<DeploymentParameterValueModel> ParameterValues { get; set; } = new List<DeploymentParameterValueModel>();
|
||||
public ICollection<DeploymentTargetAssignmentModel> TargetAssignments { get; set; } = new List<DeploymentTargetAssignmentModel>();
|
||||
public ICollection<DeploymentArtifactModel> Artifacts { get; set; } = new List<DeploymentArtifactModel>();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -9,12 +9,23 @@ namespace Microsoft.SelfService.Portal.Core.API.Models
|
||||
[Column(Order = 3)]
|
||||
public Guid TargetId { get; set; }
|
||||
[Column(Order = 4)]
|
||||
public string Status { get; set; }
|
||||
public Guid? TemplateRevisionId { get; set; }
|
||||
[Column(Order = 5)]
|
||||
public Guid? CurrentArtifactId { get; set; }
|
||||
[Column(Order = 6)]
|
||||
public string Status { get; set; }
|
||||
[Column(Order = 7)]
|
||||
public string JSONData { get; set; }
|
||||
[Column(Order = 8)]
|
||||
public string? OverridesJson { get; set; }
|
||||
[Column(Order = 9)]
|
||||
public string? SourceJson { get; set; }
|
||||
|
||||
public DeploymentGroupModel DeploymentGroup { get; set; }
|
||||
public TargetModel Target { get; set; }
|
||||
public TemplateRevisionModel? TemplateRevision { get; set; }
|
||||
public DeploymentArtifactModel? CurrentArtifact { get; set; }
|
||||
public ICollection<DeploymentArtifactModel> Artifacts { get; set; } = new List<DeploymentArtifactModel>();
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,16 +11,20 @@ namespace Microsoft.SelfService.Portal.Core.API.Models
|
||||
public Guid TemplateVersionId { get; set; }
|
||||
|
||||
[Column(Order = 3)]
|
||||
public string TemplateRole { get; set; } = "Service";
|
||||
public Guid? TemplateRevisionId { get; set; }
|
||||
|
||||
[Column(Order = 4)]
|
||||
public int SortOrder { get; set; }
|
||||
public string TemplateRole { get; set; } = "Service";
|
||||
|
||||
[Column(Order = 5)]
|
||||
public int SortOrder { get; set; }
|
||||
|
||||
[Column(Order = 6)]
|
||||
public string? Alias { get; set; }
|
||||
|
||||
public DeploymentGroupModel DeploymentGroup { get; set; } = null!;
|
||||
public TemplateVersionModel TemplateVersion { get; set; } = null!;
|
||||
public TemplateRevisionModel? TemplateRevision { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
|
||||
namespace Microsoft.SelfService.Portal.Core.API.Models
|
||||
{
|
||||
public class TemplateRevisionModel : BaseModel
|
||||
{
|
||||
[Column(Order = 1)]
|
||||
public Guid TemplateVersionId { get; set; }
|
||||
|
||||
[Column(Order = 2)]
|
||||
public int RevisionNumber { get; set; }
|
||||
|
||||
[Column(Order = 3)]
|
||||
public string JsonData { get; set; } = "{}";
|
||||
|
||||
[Column(Order = 4)]
|
||||
public string JsonHash { get; set; } = string.Empty;
|
||||
|
||||
[Column(Order = 5)]
|
||||
public string SchemaVersion { get; set; } = "1.0";
|
||||
|
||||
[Column(Order = 6)]
|
||||
public bool IsCurrent { get; set; }
|
||||
|
||||
[Column(Order = 7)]
|
||||
public bool IsPublished { get; set; }
|
||||
|
||||
[Column(Order = 8)]
|
||||
public DateTime? PublishedAt { get; set; }
|
||||
|
||||
[Column(Order = 9)]
|
||||
public string? PublishedBy { get; set; }
|
||||
|
||||
public TemplateVersionModel TemplateVersion { get; set; } = null!;
|
||||
public ICollection<ConfigurationDefinitionModel> ConfigurationDefinitions { get; set; } = new List<ConfigurationDefinitionModel>();
|
||||
public ICollection<DeploymentTemplateSelectionModel> DeploymentTemplateSelections { get; set; } = new List<DeploymentTemplateSelectionModel>();
|
||||
public ICollection<DeploymentModel> Deployments { get; set; } = new List<DeploymentModel>();
|
||||
|
||||
public void SetJsonData(string jsonData)
|
||||
{
|
||||
JsonData = string.IsNullOrWhiteSpace(jsonData) ? "{}" : jsonData;
|
||||
JsonHash = TemplateVersionModel.ComputeSha256(JsonData);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -31,6 +31,7 @@ namespace Microsoft.SelfService.Portal.Core.API.Models
|
||||
public string? PublishedBy { get; set; }
|
||||
|
||||
public TemplateModel Template { get; set; } = null!;
|
||||
public ICollection<TemplateRevisionModel> TemplateRevisions { get; set; } = new List<TemplateRevisionModel>();
|
||||
|
||||
public void SetJsonData(string jsonData)
|
||||
{
|
||||
|
||||
+82
-3
@@ -1,11 +1,14 @@
|
||||
using Microsoft.AspNetCore.Authentication.Negotiate;
|
||||
using Microsoft.AspNetCore.Authentication.JwtBearer;
|
||||
using Microsoft.AspNetCore.Authentication.Negotiate;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.IdentityModel.Tokens;
|
||||
using Microsoft.SelfService.Portal.Core.API.Context;
|
||||
using Microsoft.SelfService.Portal.Core.API.Interfaces;
|
||||
using Microsoft.SelfService.Portal.Core.API.Repository;
|
||||
using Microsoft.SelfService.Portal.Core.API.Services;
|
||||
using Microsoft.Extensions.FileProviders;
|
||||
|
||||
using System.IdentityModel.Tokens.Jwt;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
|
||||
@@ -27,6 +30,7 @@ builder.Services.AddScoped<IDeploymentInterface, DeploymentRepository>();
|
||||
builder.Services.AddScoped<ITemplateInterface, TemplateRepository>();
|
||||
builder.Services.AddScoped<ITemplateCategoryInterface, TemplateCategoryRepository>();
|
||||
builder.Services.AddScoped<IQueueJobService, QueueJobService>();
|
||||
builder.Services.AddScoped<ApiTokenService>();
|
||||
|
||||
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
|
||||
builder.Services.AddEndpointsApiExplorer();
|
||||
@@ -36,8 +40,72 @@ builder.Services.AddAutoMapper(_ => { }, AppDomain.CurrentDomain.GetAssemblies()
|
||||
builder.Services.AddDbContext<DataContext>(options =>
|
||||
options.UseSqlServer(builder.Configuration.GetConnectionString("Context") ?? throw new InvalidOperationException("Connection string 'Context' not found.")));
|
||||
|
||||
builder.Services.AddAuthentication(NegotiateDefaults.AuthenticationScheme)
|
||||
.AddNegotiate();
|
||||
var tokenService = new ApiTokenService(builder.Configuration);
|
||||
|
||||
builder.Services.AddAuthentication(options =>
|
||||
{
|
||||
options.DefaultScheme = "Smart";
|
||||
options.DefaultChallengeScheme = "Smart";
|
||||
})
|
||||
.AddPolicyScheme("Smart", "Negotiate or Bearer", options =>
|
||||
{
|
||||
options.ForwardDefaultSelector = context =>
|
||||
{
|
||||
var authorization = context.Request.Headers.Authorization.ToString();
|
||||
return authorization.StartsWith("Bearer ", StringComparison.OrdinalIgnoreCase)
|
||||
? JwtBearerDefaults.AuthenticationScheme
|
||||
: NegotiateDefaults.AuthenticationScheme;
|
||||
};
|
||||
})
|
||||
.AddNegotiate()
|
||||
.AddJwtBearer(options =>
|
||||
{
|
||||
options.TokenValidationParameters = new TokenValidationParameters
|
||||
{
|
||||
ValidateIssuer = true,
|
||||
ValidIssuer = tokenService.Issuer,
|
||||
ValidateAudience = true,
|
||||
ValidAudience = tokenService.Audience,
|
||||
ValidateIssuerSigningKey = true,
|
||||
IssuerSigningKey = tokenService.GetSigningKey(),
|
||||
ValidateLifetime = true,
|
||||
ClockSkew = TimeSpan.FromMinutes(2)
|
||||
};
|
||||
|
||||
options.Events = new JwtBearerEvents
|
||||
{
|
||||
OnTokenValidated = context =>
|
||||
{
|
||||
var jti = context.Principal?.FindFirst(JwtRegisteredClaimNames.Jti)?.Value;
|
||||
if (string.IsNullOrWhiteSpace(jti))
|
||||
{
|
||||
context.Fail("Token does not contain a token id.");
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
var dataContext = context.HttpContext.RequestServices.GetRequiredService<DataContext>();
|
||||
var token = dataContext.ApiTokens.FirstOrDefault(existing => existing.Jti == jti);
|
||||
if (token == null)
|
||||
{
|
||||
context.Fail("Token is not registered.");
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
if (token.RevokedAt.HasValue || token.ExpiresAt <= DateTime.UtcNow)
|
||||
{
|
||||
context.Fail("Token is revoked or expired.");
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
token.LastUsedAt = DateTime.UtcNow;
|
||||
token.Modified = DateTime.UtcNow;
|
||||
token.ModifiedBy = "BearerToken";
|
||||
dataContext.SaveChanges();
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
builder.Services.AddHttpContextAccessor();
|
||||
|
||||
@@ -45,6 +113,15 @@ builder.Services.AddAuthorization(options =>
|
||||
{
|
||||
// By default, all incoming requests will be authorized according to the default policy.
|
||||
options.FallbackPolicy = options.DefaultPolicy;
|
||||
options.AddPolicy("QueueProcess", policy => policy.RequireClaim("scope", "queue.process"));
|
||||
options.AddPolicy("DeploymentRead", policy => policy.RequireClaim("scope", "deployment.read"));
|
||||
options.AddPolicy("CredentialResolve", policy => policy.RequireClaim("scope", "credential.resolve"));
|
||||
options.AddPolicy("TokenManage", policy => policy.RequireAssertion(context =>
|
||||
context.User.HasClaim("scope", "token.manage")
|
||||
|| context.User.Identity?.AuthenticationType == NegotiateDefaults.AuthenticationScheme));
|
||||
options.AddPolicy("TokenAdmin", policy => policy.RequireAssertion(context =>
|
||||
context.User.HasClaim("scope", "token.admin")
|
||||
|| context.User.Identity?.AuthenticationType == NegotiateDefaults.AuthenticationScheme));
|
||||
});
|
||||
|
||||
var app = builder.Build();
|
||||
@@ -101,3 +178,5 @@ if (Directory.Exists(frontendDistPath))
|
||||
|
||||
app.Run();
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -55,6 +55,7 @@ namespace Microsoft.SelfService.Portal.Core.API.Repository
|
||||
|
||||
var templateVersion = requestedTemplateVersionId.HasValue
|
||||
? _context.TemplateVersions
|
||||
.Include(version => version.TemplateRevisions)
|
||||
.Include(version => version.Template)
|
||||
.ThenInclude(template => template.TemplateCategory)
|
||||
.ThenInclude(category => category.Service)
|
||||
@@ -66,6 +67,7 @@ namespace Microsoft.SelfService.Portal.Core.API.Repository
|
||||
.Include(existing => existing.TemplateCategory)
|
||||
.ThenInclude(existing => existing.Service)
|
||||
.Include(existing => existing.TemplateVersions)
|
||||
.ThenInclude(version => version.TemplateRevisions)
|
||||
.FirstOrDefault(existing => existing.Id == deploymentBatch.TemplateId);
|
||||
|
||||
if (template == null)
|
||||
@@ -128,11 +130,32 @@ namespace Microsoft.SelfService.Portal.Core.API.Repository
|
||||
Id = Guid.NewGuid(),
|
||||
DeploymentGroupId = deploymentBatch.Id,
|
||||
TemplateVersionId = templateVersion.Id,
|
||||
TemplateRevisionId = templateVersion.TemplateRevisions?.FirstOrDefault(revision => revision.IsCurrent)?.Id,
|
||||
TemplateRole = "Service",
|
||||
SortOrder = 10,
|
||||
Alias = template.Name
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (var selection in deploymentBatch.TemplateSelections)
|
||||
{
|
||||
if (selection.TemplateRevisionId.HasValue)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var selectedVersion = selection.TemplateVersionId == templateVersion?.Id
|
||||
? templateVersion
|
||||
: _context.TemplateVersions
|
||||
.Include(version => version.TemplateRevisions)
|
||||
.FirstOrDefault(version => version.Id == selection.TemplateVersionId);
|
||||
|
||||
selection.TemplateRevisionId = selectedVersion?.TemplateRevisions
|
||||
?.FirstOrDefault(revision => revision.IsCurrent)
|
||||
?.Id;
|
||||
}
|
||||
}
|
||||
|
||||
if (deploymentBatch.TargetAssignments.Count == 0)
|
||||
{
|
||||
@@ -170,6 +193,10 @@ namespace Microsoft.SelfService.Portal.Core.API.Repository
|
||||
{
|
||||
DeploymentGroupId = deploymentBatch.Id,
|
||||
TargetId = targetId,
|
||||
TemplateRevisionId = deploymentBatch.TemplateSelections
|
||||
.OrderBy(selection => selection.SortOrder)
|
||||
.Select(selection => selection.TemplateRevisionId)
|
||||
.FirstOrDefault(),
|
||||
Status = QueueJobStatus.Pending,
|
||||
JSONData = "{}"
|
||||
});
|
||||
|
||||
@@ -3,6 +3,7 @@ using Microsoft.SelfService.Portal.Core.API.Context;
|
||||
using Microsoft.SelfService.Portal.Core.API.Interfaces;
|
||||
using Microsoft.SelfService.Portal.Core.API.JsonDocuments;
|
||||
using Microsoft.SelfService.Portal.Core.API.Models;
|
||||
using System.Text.Json;
|
||||
|
||||
namespace Microsoft.SelfService.Portal.Core.API.Repository
|
||||
{
|
||||
@@ -67,6 +68,7 @@ namespace Microsoft.SelfService.Portal.Core.API.Repository
|
||||
PublishedBy = template.CreatedBy
|
||||
};
|
||||
version.SetJsonData(document.JsonData);
|
||||
version.TemplateRevisions.Add(CreateTemplateRevision(version.Id, document.JsonData, document.SchemaVersion, true, template.CreatedBy));
|
||||
|
||||
template.TemplateVersions.Add(version);
|
||||
_context.Add(template);
|
||||
@@ -87,7 +89,8 @@ namespace Microsoft.SelfService.Portal.Core.API.Repository
|
||||
var document = ConfigurationDocumentValidator.NormalizeAndValidate(template.JSONData, ConfigurationDocumentKind.Template);
|
||||
var jsonData = document.JsonData;
|
||||
var publishedVersion = existingTemplate.TemplateVersions.FirstOrDefault(version => version.IsPublished);
|
||||
var jsonChanged = publishedVersion == null || !string.Equals(publishedVersion.JsonData, jsonData, StringComparison.Ordinal);
|
||||
var currentRevision = publishedVersion == null ? null : GetCurrentTemplateRevision(publishedVersion.Id);
|
||||
var jsonChanged = currentRevision == null || !string.Equals(currentRevision.JsonData, jsonData, StringComparison.Ordinal);
|
||||
|
||||
existingTemplate.Name = template.Name;
|
||||
existingTemplate.Version = template.Version;
|
||||
@@ -99,12 +102,15 @@ namespace Microsoft.SelfService.Portal.Core.API.Repository
|
||||
existingTemplate.ModifiedBy = template.ModifiedBy;
|
||||
|
||||
if (jsonChanged)
|
||||
{
|
||||
var version = publishedVersion;
|
||||
if (version == null || !string.Equals(version.Version, template.Version, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
var versionName = GetUniqueVersionName(
|
||||
existingTemplate.Id,
|
||||
string.IsNullOrWhiteSpace(template.Version) ? DateTime.UtcNow.ToString("yyyyMMddHHmmss") : template.Version);
|
||||
|
||||
var version = new TemplateVersionModel
|
||||
version = new TemplateVersionModel
|
||||
{
|
||||
Id = Guid.NewGuid(),
|
||||
TemplateId = existingTemplate.Id,
|
||||
@@ -114,14 +120,22 @@ namespace Microsoft.SelfService.Portal.Core.API.Repository
|
||||
PublishedAt = DateTime.UtcNow,
|
||||
PublishedBy = template.ModifiedBy
|
||||
};
|
||||
version.SetJsonData(jsonData);
|
||||
existingTemplate.TemplateVersions.Add(version);
|
||||
}
|
||||
|
||||
foreach (var existingVersion in existingTemplate.TemplateVersions)
|
||||
version.SetJsonData(jsonData);
|
||||
version.SchemaVersion = document.SchemaVersion;
|
||||
version.IsPublished = true;
|
||||
version.PublishedAt = DateTime.UtcNow;
|
||||
version.PublishedBy = template.ModifiedBy;
|
||||
|
||||
foreach (var existingVersion in existingTemplate.TemplateVersions.Where(existing => existing.Id != version.Id))
|
||||
{
|
||||
existingVersion.IsPublished = false;
|
||||
}
|
||||
|
||||
existingTemplate.TemplateVersions.Add(version);
|
||||
var revision = CreateTemplateRevision(version.Id, jsonData, document.SchemaVersion, true, template.ModifiedBy);
|
||||
_context.TemplateRevisions.Add(revision);
|
||||
}
|
||||
|
||||
return SaveChanges();
|
||||
@@ -157,6 +171,7 @@ namespace Microsoft.SelfService.Portal.Core.API.Repository
|
||||
{
|
||||
return _context.TemplateVersions
|
||||
.AsNoTracking()
|
||||
.Include(version => version.TemplateRevisions)
|
||||
.Where(version => version.TemplateId == templateId)
|
||||
.OrderByDescending(version => version.Created)
|
||||
.ToList();
|
||||
@@ -166,6 +181,7 @@ namespace Microsoft.SelfService.Portal.Core.API.Repository
|
||||
{
|
||||
return _context.TemplateVersions
|
||||
.AsNoTracking()
|
||||
.Include(version => version.TemplateRevisions)
|
||||
.FirstOrDefault(version => version.TemplateId == templateId && version.Id == versionId);
|
||||
}
|
||||
|
||||
@@ -173,9 +189,45 @@ namespace Microsoft.SelfService.Portal.Core.API.Repository
|
||||
{
|
||||
return _context.TemplateVersions
|
||||
.AsNoTracking()
|
||||
.Include(version => version.TemplateRevisions)
|
||||
.FirstOrDefault(version => version.TemplateId == templateId && version.IsPublished);
|
||||
}
|
||||
|
||||
public ICollection<TemplateRevisionModel> GetTemplateRevisions(Guid templateId, Guid versionId)
|
||||
{
|
||||
if (!_context.TemplateVersions.Any(version => version.TemplateId == templateId && version.Id == versionId))
|
||||
{
|
||||
return new List<TemplateRevisionModel>();
|
||||
}
|
||||
|
||||
return _context.TemplateRevisions
|
||||
.AsNoTracking()
|
||||
.Include(revision => revision.ConfigurationDefinitions)
|
||||
.Where(revision => revision.TemplateVersionId == versionId)
|
||||
.OrderByDescending(revision => revision.RevisionNumber)
|
||||
.ToList();
|
||||
}
|
||||
|
||||
public TemplateRevisionModel? GetTemplateRevisionById(Guid templateId, Guid versionId, Guid revisionId)
|
||||
{
|
||||
if (!_context.TemplateVersions.Any(version => version.TemplateId == templateId && version.Id == versionId))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return _context.TemplateRevisions
|
||||
.AsNoTracking()
|
||||
.Include(revision => revision.ConfigurationDefinitions)
|
||||
.FirstOrDefault(revision => revision.TemplateVersionId == versionId && revision.Id == revisionId);
|
||||
}
|
||||
|
||||
public TemplateRevisionModel? GetCurrentTemplateRevision(Guid versionId)
|
||||
{
|
||||
return _context.TemplateRevisions
|
||||
.AsNoTracking()
|
||||
.FirstOrDefault(revision => revision.TemplateVersionId == versionId && revision.IsCurrent);
|
||||
}
|
||||
|
||||
public bool AddTemplateVersion(Guid templateId, TemplateVersionModel version, bool publish)
|
||||
{
|
||||
if (!_context.Templates.Any(template => template.Id == templateId))
|
||||
@@ -192,6 +244,7 @@ namespace Microsoft.SelfService.Portal.Core.API.Repository
|
||||
version.SchemaVersion);
|
||||
version.SchemaVersion = document.SchemaVersion;
|
||||
version.SetJsonData(document.JsonData);
|
||||
version.TemplateRevisions.Add(CreateTemplateRevision(version.Id, document.JsonData, document.SchemaVersion, publish, version.PublishedBy));
|
||||
|
||||
if (publish)
|
||||
{
|
||||
@@ -208,6 +261,42 @@ namespace Microsoft.SelfService.Portal.Core.API.Repository
|
||||
return SaveChanges();
|
||||
}
|
||||
|
||||
public bool AddTemplateRevision(Guid templateId, Guid versionId, TemplateRevisionModel revision, bool publish)
|
||||
{
|
||||
var version = _context.TemplateVersions
|
||||
.Include(existing => existing.TemplateRevisions)
|
||||
.FirstOrDefault(existing => existing.TemplateId == templateId && existing.Id == versionId);
|
||||
|
||||
if (version == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var document = ConfigurationDocumentValidator.NormalizeAndValidate(
|
||||
revision.JsonData,
|
||||
ConfigurationDocumentKind.Template,
|
||||
revision.SchemaVersion);
|
||||
|
||||
revision = CreateTemplateRevision(versionId, document.JsonData, document.SchemaVersion, publish, revision.PublishedBy);
|
||||
|
||||
if (publish)
|
||||
{
|
||||
foreach (var existingRevision in _context.TemplateRevisions.Where(existing => existing.TemplateVersionId == versionId && existing.IsCurrent))
|
||||
{
|
||||
existingRevision.IsCurrent = false;
|
||||
existingRevision.IsPublished = false;
|
||||
}
|
||||
|
||||
version.SetJsonData(document.JsonData);
|
||||
version.SchemaVersion = document.SchemaVersion;
|
||||
version.PublishedAt = DateTime.UtcNow;
|
||||
version.PublishedBy = revision.PublishedBy;
|
||||
}
|
||||
|
||||
_context.TemplateRevisions.Add(revision);
|
||||
return SaveChanges();
|
||||
}
|
||||
|
||||
public bool PublishTemplateVersion(Guid templateId, Guid versionId, string? publishedBy)
|
||||
{
|
||||
var version = _context.TemplateVersions
|
||||
@@ -226,6 +315,13 @@ namespace Microsoft.SelfService.Portal.Core.API.Repository
|
||||
version.IsPublished = true;
|
||||
version.PublishedAt = DateTime.UtcNow;
|
||||
version.PublishedBy = string.IsNullOrWhiteSpace(publishedBy) ? "System" : publishedBy;
|
||||
var currentRevision = _context.TemplateRevisions.FirstOrDefault(revision => revision.TemplateVersionId == version.Id && revision.IsCurrent);
|
||||
if (currentRevision != null)
|
||||
{
|
||||
currentRevision.IsPublished = true;
|
||||
currentRevision.PublishedAt = DateTime.UtcNow;
|
||||
currentRevision.PublishedBy = version.PublishedBy;
|
||||
}
|
||||
|
||||
var template = _context.Templates.FirstOrDefault(existing => existing.Id == templateId);
|
||||
if (template != null)
|
||||
@@ -266,7 +362,82 @@ namespace Microsoft.SelfService.Portal.Core.API.Repository
|
||||
}
|
||||
|
||||
template.Version = publishedVersion.Version;
|
||||
template.JSONData = publishedVersion.JsonData;
|
||||
var currentRevision = publishedVersion.TemplateRevisions?.FirstOrDefault(revision => revision.IsCurrent);
|
||||
template.JSONData = currentRevision?.JsonData ?? publishedVersion.JsonData;
|
||||
}
|
||||
|
||||
private TemplateRevisionModel CreateTemplateRevision(Guid templateVersionId, string jsonData, string schemaVersion, bool publish, string? publishedBy)
|
||||
{
|
||||
var revision = new TemplateRevisionModel
|
||||
{
|
||||
Id = Guid.NewGuid(),
|
||||
TemplateVersionId = templateVersionId,
|
||||
RevisionNumber = GetNextRevisionNumber(templateVersionId),
|
||||
SchemaVersion = schemaVersion,
|
||||
IsCurrent = true,
|
||||
IsPublished = publish,
|
||||
PublishedAt = publish ? DateTime.UtcNow : null,
|
||||
PublishedBy = publishedBy ?? "System"
|
||||
};
|
||||
revision.SetJsonData(jsonData);
|
||||
|
||||
foreach (var existingRevision in _context.TemplateRevisions.Where(existing => existing.TemplateVersionId == templateVersionId && existing.IsCurrent))
|
||||
{
|
||||
existingRevision.IsCurrent = false;
|
||||
}
|
||||
|
||||
foreach (var definition in ExtractConfigurationDefinitions(revision.Id, jsonData))
|
||||
{
|
||||
revision.ConfigurationDefinitions.Add(definition);
|
||||
}
|
||||
|
||||
return revision;
|
||||
}
|
||||
|
||||
private int GetNextRevisionNumber(Guid templateVersionId)
|
||||
{
|
||||
return (_context.TemplateRevisions
|
||||
.Where(revision => revision.TemplateVersionId == templateVersionId)
|
||||
.Select(revision => (int?)revision.RevisionNumber)
|
||||
.Max() ?? 0) + 1;
|
||||
}
|
||||
|
||||
private static IEnumerable<ConfigurationDefinitionModel> ExtractConfigurationDefinitions(Guid revisionId, string jsonData)
|
||||
{
|
||||
using var document = JsonDocument.Parse(jsonData);
|
||||
var root = document.RootElement;
|
||||
|
||||
foreach (var definition in ExtractConfigurationDefinitions(revisionId, root, "parameters", ConfigurationDefinitionKinds.Parameter))
|
||||
{
|
||||
yield return definition;
|
||||
}
|
||||
|
||||
foreach (var definition in ExtractConfigurationDefinitions(revisionId, root, "variables", ConfigurationDefinitionKinds.Variable))
|
||||
{
|
||||
yield return definition;
|
||||
}
|
||||
}
|
||||
|
||||
private static IEnumerable<ConfigurationDefinitionModel> ExtractConfigurationDefinitions(Guid revisionId, JsonElement root, string propertyName, string kind)
|
||||
{
|
||||
if (!root.TryGetProperty(propertyName, out var definitions) || definitions.ValueKind != JsonValueKind.Object)
|
||||
{
|
||||
yield break;
|
||||
}
|
||||
|
||||
foreach (var property in definitions.EnumerateObject())
|
||||
{
|
||||
var propertiesJson = property.Value.GetRawText();
|
||||
yield return new ConfigurationDefinitionModel
|
||||
{
|
||||
Id = Guid.NewGuid(),
|
||||
TemplateRevisionId = revisionId,
|
||||
Kind = kind,
|
||||
Name = property.Name,
|
||||
PropertiesJson = propertiesJson,
|
||||
DefinitionHash = TemplateVersionModel.ComputeSha256(propertiesJson)
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
private string GetUniqueVersionName(Guid templateId, string version)
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
using System.Security.Cryptography;
|
||||
|
||||
namespace Microsoft.SelfService.Portal.Core.API.Services
|
||||
{
|
||||
public static class ApiClientSecretHasher
|
||||
{
|
||||
private const int SaltSize = 16;
|
||||
private const int KeySize = 32;
|
||||
private const int DefaultIterations = 100_000;
|
||||
|
||||
public static string HashSecret(string secret)
|
||||
{
|
||||
var salt = RandomNumberGenerator.GetBytes(SaltSize);
|
||||
var hash = Rfc2898DeriveBytes.Pbkdf2(secret, salt, DefaultIterations, HashAlgorithmName.SHA256, KeySize);
|
||||
|
||||
return string.Join(
|
||||
'.',
|
||||
"PBKDF2-SHA256",
|
||||
DefaultIterations.ToString(),
|
||||
Convert.ToBase64String(salt),
|
||||
Convert.ToBase64String(hash));
|
||||
}
|
||||
|
||||
public static bool VerifySecret(string secret, string storedHash)
|
||||
{
|
||||
var parts = storedHash.Split('.');
|
||||
if (parts.Length != 4 || parts[0] != "PBKDF2-SHA256")
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!int.TryParse(parts[1], out var iterations))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var salt = Convert.FromBase64String(parts[2]);
|
||||
var expectedHash = Convert.FromBase64String(parts[3]);
|
||||
var actualHash = Rfc2898DeriveBytes.Pbkdf2(secret, salt, iterations, HashAlgorithmName.SHA256, expectedHash.Length);
|
||||
|
||||
return CryptographicOperations.FixedTimeEquals(actualHash, expectedHash);
|
||||
}
|
||||
|
||||
internal static string HashSecretForDemoData(string secret, string saltText)
|
||||
{
|
||||
var salt = System.Text.Encoding.UTF8.GetBytes(saltText);
|
||||
Array.Resize(ref salt, SaltSize);
|
||||
var hash = Rfc2898DeriveBytes.Pbkdf2(secret, salt, DefaultIterations, HashAlgorithmName.SHA256, KeySize);
|
||||
|
||||
return string.Join(
|
||||
'.',
|
||||
"PBKDF2-SHA256",
|
||||
DefaultIterations.ToString(),
|
||||
Convert.ToBase64String(salt),
|
||||
Convert.ToBase64String(hash));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
namespace Microsoft.SelfService.Portal.Core.API.Services
|
||||
{
|
||||
public class ApiTokenCreateResult
|
||||
{
|
||||
public string AccessToken { get; set; } = string.Empty;
|
||||
|
||||
public string Jti { get; set; } = string.Empty;
|
||||
|
||||
public DateTime IssuedAt { get; set; }
|
||||
|
||||
public DateTime ExpiresAt { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,162 @@
|
||||
using System.IdentityModel.Tokens.Jwt;
|
||||
using System.Security.Claims;
|
||||
using System.Text;
|
||||
using System.Text.Json;
|
||||
using Microsoft.IdentityModel.Tokens;
|
||||
using Microsoft.SelfService.Portal.Core.API.Models;
|
||||
|
||||
namespace Microsoft.SelfService.Portal.Core.API.Services
|
||||
{
|
||||
public class ApiTokenService
|
||||
{
|
||||
private readonly IConfiguration _configuration;
|
||||
|
||||
public ApiTokenService(IConfiguration configuration)
|
||||
{
|
||||
_configuration = configuration;
|
||||
}
|
||||
|
||||
public int TokenLifetimeSeconds =>
|
||||
_configuration.GetValue<int?>("Authentication:OnPremClientCredentials:TokenLifetimeSeconds") ?? 3600;
|
||||
|
||||
public string Issuer =>
|
||||
_configuration["Authentication:OnPremClientCredentials:Issuer"] ?? "Microsoft.SelfService.Portal.Core.API";
|
||||
|
||||
public string Audience =>
|
||||
_configuration["Authentication:OnPremClientCredentials:Audience"] ?? "Microsoft.SelfService.Portal.Core.API";
|
||||
|
||||
public ApiTokenCreateResult CreateAccessToken(ApiClientModel client, IReadOnlyCollection<string> scopes)
|
||||
{
|
||||
return CreateAccessToken(client.ClientId, client.ClientId, scopes);
|
||||
}
|
||||
|
||||
public ApiTokenCreateResult CreateAccessToken(string subject, string? clientId, IReadOnlyCollection<string> scopes)
|
||||
{
|
||||
var signingKey = GetSigningKey();
|
||||
var credentials = new SigningCredentials(signingKey, SecurityAlgorithms.HmacSha256);
|
||||
var now = DateTime.UtcNow;
|
||||
var jti = Guid.NewGuid().ToString("N");
|
||||
var expiresAt = now.AddSeconds(TokenLifetimeSeconds);
|
||||
|
||||
var claims = new List<Claim>
|
||||
{
|
||||
new(JwtRegisteredClaimNames.Sub, subject),
|
||||
new(JwtRegisteredClaimNames.Jti, jti)
|
||||
};
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(clientId))
|
||||
{
|
||||
claims.Add(new Claim("client_id", clientId));
|
||||
}
|
||||
|
||||
foreach (var scope in scopes)
|
||||
{
|
||||
claims.Add(new Claim("scope", scope));
|
||||
}
|
||||
|
||||
var token = new JwtSecurityToken(
|
||||
issuer: Issuer,
|
||||
audience: Audience,
|
||||
claims: claims,
|
||||
notBefore: now,
|
||||
expires: expiresAt,
|
||||
signingCredentials: credentials);
|
||||
|
||||
return new ApiTokenCreateResult
|
||||
{
|
||||
AccessToken = new JwtSecurityTokenHandler().WriteToken(token),
|
||||
Jti = jti,
|
||||
IssuedAt = now,
|
||||
ExpiresAt = expiresAt
|
||||
};
|
||||
}
|
||||
|
||||
public IReadOnlyCollection<string> ReadClientScopes(ApiClientModel client)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(client.ScopesJson))
|
||||
{
|
||||
return Array.Empty<string>();
|
||||
}
|
||||
|
||||
return JsonSerializer.Deserialize<string[]>(client.ScopesJson) ?? Array.Empty<string>();
|
||||
}
|
||||
|
||||
public IReadOnlyCollection<string> ResolveRequestedScopes(ApiClientModel client, string? requestedScope)
|
||||
{
|
||||
var allowedScopes = ReadClientScopes(client);
|
||||
if (string.IsNullOrWhiteSpace(requestedScope))
|
||||
{
|
||||
return allowedScopes;
|
||||
}
|
||||
|
||||
var requestedScopes = requestedScope
|
||||
.Split(' ', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries)
|
||||
.Distinct(StringComparer.OrdinalIgnoreCase)
|
||||
.ToArray();
|
||||
|
||||
if (requestedScopes.Any(scope => !allowedScopes.Contains(scope, StringComparer.OrdinalIgnoreCase)))
|
||||
{
|
||||
throw new InvalidOperationException("Requested scope is not allowed for this client.");
|
||||
}
|
||||
|
||||
return requestedScopes;
|
||||
}
|
||||
|
||||
public IReadOnlyCollection<string> ResolveRequestedUserScopes(string? requestedScope)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(requestedScope))
|
||||
{
|
||||
throw new InvalidOperationException("At least one scope is required.");
|
||||
}
|
||||
|
||||
var allowedScopes = ReadAllowedTokenScopes();
|
||||
var requestedScopes = requestedScope
|
||||
.Split(' ', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries)
|
||||
.Distinct(StringComparer.OrdinalIgnoreCase)
|
||||
.ToArray();
|
||||
|
||||
if (requestedScopes.Length == 0)
|
||||
{
|
||||
throw new InvalidOperationException("At least one scope is required.");
|
||||
}
|
||||
|
||||
if (requestedScopes.Any(scope => !allowedScopes.Contains(scope, StringComparer.OrdinalIgnoreCase)))
|
||||
{
|
||||
throw new InvalidOperationException("Requested scope is not allowed.");
|
||||
}
|
||||
|
||||
return requestedScopes;
|
||||
}
|
||||
|
||||
public IReadOnlyCollection<string> ReadAllowedTokenScopes()
|
||||
{
|
||||
var configuredScopes = _configuration.GetSection("Authentication:OnPremClientCredentials:AllowedTokenScopes").Get<string[]>();
|
||||
if (configuredScopes != null && configuredScopes.Length > 0)
|
||||
{
|
||||
return configuredScopes;
|
||||
}
|
||||
|
||||
return
|
||||
[
|
||||
"deployment.read",
|
||||
"deployment.write",
|
||||
"queue.process",
|
||||
"template.read",
|
||||
"credential.resolve",
|
||||
"token.manage",
|
||||
"token.admin"
|
||||
];
|
||||
}
|
||||
|
||||
public SymmetricSecurityKey GetSigningKey()
|
||||
{
|
||||
var signingKey = _configuration["Authentication:OnPremClientCredentials:SigningKey"];
|
||||
if (string.IsNullOrWhiteSpace(signingKey))
|
||||
{
|
||||
signingKey = "DevelopmentOnly-OnPremClientCredentials-SigningKey-ChangeMe";
|
||||
}
|
||||
|
||||
return new SymmetricSecurityKey(Encoding.UTF8.GetBytes(signingKey));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -55,13 +55,8 @@ namespace Microsoft.SelfService.Portal.Core.API.Services
|
||||
return queueJob.Id;
|
||||
}
|
||||
|
||||
public Guid EnqueueDeploymentRequest(Guid deploymentGroupId, ICollection<Guid> targetIds, string jsonData)
|
||||
public Guid EnqueueDeploymentRequest(Guid deploymentGroupId, ICollection<Guid> targetIds, string jsonData, Guid? deploymentArtifactId = null)
|
||||
{
|
||||
var deploymentDocument = ConfigurationDocumentValidator.NormalizeAndValidate(
|
||||
jsonData,
|
||||
ConfigurationDocumentKind.DeploymentOverride);
|
||||
jsonData = deploymentDocument.JsonData;
|
||||
|
||||
var deploymentGroup = _context.DeploymentGroups
|
||||
.AsNoTracking()
|
||||
.Include(group => group.Template)
|
||||
@@ -80,6 +75,39 @@ namespace Microsoft.SelfService.Portal.Core.API.Services
|
||||
throw new InvalidOperationException("DeploymentGroup does not exist.");
|
||||
}
|
||||
|
||||
var currentArtifact = deploymentArtifactId.HasValue
|
||||
? _context.DeploymentArtifacts
|
||||
.AsNoTracking()
|
||||
.FirstOrDefault(artifact =>
|
||||
artifact.Id == deploymentArtifactId.Value
|
||||
&& artifact.DeploymentGroupId == deploymentGroupId
|
||||
&& !artifact.IsStale)
|
||||
: _context.DeploymentArtifacts
|
||||
.AsNoTracking()
|
||||
.Where(artifact =>
|
||||
artifact.DeploymentGroupId == deploymentGroupId
|
||||
&& artifact.ArtifactType == DeploymentArtifactTypes.ResolvedConfigurationData
|
||||
&& !artifact.IsStale)
|
||||
.OrderByDescending(artifact => artifact.Created)
|
||||
.FirstOrDefault();
|
||||
|
||||
if (deploymentArtifactId.HasValue && currentArtifact == null)
|
||||
{
|
||||
throw new InvalidOperationException("Deployment artifact does not exist or is stale.");
|
||||
}
|
||||
|
||||
if (currentArtifact != null)
|
||||
{
|
||||
jsonData = currentArtifact.DeploymentJson;
|
||||
}
|
||||
else
|
||||
{
|
||||
var deploymentDocument = ConfigurationDocumentValidator.NormalizeAndValidate(
|
||||
jsonData,
|
||||
ConfigurationDocumentKind.DeploymentOverride);
|
||||
jsonData = deploymentDocument.JsonData;
|
||||
}
|
||||
|
||||
var primaryTemplateSelection = deploymentGroup.TemplateSelections
|
||||
.OrderBy(selection => selection.SortOrder)
|
||||
.FirstOrDefault();
|
||||
@@ -156,6 +184,7 @@ namespace Microsoft.SelfService.Portal.Core.API.Services
|
||||
{
|
||||
selection.Id,
|
||||
selection.TemplateVersionId,
|
||||
selection.TemplateRevisionId,
|
||||
TemplateId = selection.TemplateVersion.TemplateId,
|
||||
TemplateName = selection.TemplateVersion.Template.Name,
|
||||
selection.TemplateVersion.Version,
|
||||
@@ -176,6 +205,8 @@ namespace Microsoft.SelfService.Portal.Core.API.Services
|
||||
assignment.NodeDataJson
|
||||
}),
|
||||
TargetIds = resolvedTargetIds,
|
||||
DeploymentArtifactId = currentArtifact?.Id,
|
||||
DeploymentJson = currentArtifact?.DeploymentJson,
|
||||
JsonData = jsonData,
|
||||
TargetCount = resolvedTargetIds.Count,
|
||||
Created = DateTime.UtcNow
|
||||
|
||||
@@ -6,6 +6,23 @@
|
||||
}
|
||||
},
|
||||
"AllowedHosts": "*",
|
||||
"Authentication": {
|
||||
"OnPremClientCredentials": {
|
||||
"Issuer": "Microsoft.SelfService.Portal.Core.API",
|
||||
"Audience": "Microsoft.SelfService.Portal.Core.API",
|
||||
"SigningKey": "DevelopmentOnly-OnPremClientCredentials-SigningKey-ChangeMe",
|
||||
"TokenLifetimeSeconds": 3600,
|
||||
"AllowedTokenScopes": [
|
||||
"deployment.read",
|
||||
"deployment.write",
|
||||
"queue.process",
|
||||
"template.read",
|
||||
"credential.resolve",
|
||||
"token.manage",
|
||||
"token.admin"
|
||||
]
|
||||
}
|
||||
},
|
||||
"ConnectionStrings": {
|
||||
"Context": "Server=.;Database=SSP;TrustServerCertificate=True;Encrypt=False;Trusted_Connection=True"
|
||||
}
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
Binary file not shown.
-68
@@ -1,68 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<configuration>
|
||||
<startup>
|
||||
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.7.2" />
|
||||
</startup>
|
||||
<runtime>
|
||||
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="Microsoft.Build" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-15.1.0.0" newVersion="15.1.0.0" />
|
||||
</dependentAssembly>
|
||||
</assemblyBinding>
|
||||
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="Microsoft.Build.Framework" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-15.1.0.0" newVersion="15.1.0.0" />
|
||||
</dependentAssembly>
|
||||
</assemblyBinding>
|
||||
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="Microsoft.Build.Utilities.Core" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-15.1.0.0" newVersion="15.1.0.0" />
|
||||
</dependentAssembly>
|
||||
</assemblyBinding>
|
||||
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="Microsoft.Build.Tasks.Core" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-15.1.0.0" newVersion="15.1.0.0" />
|
||||
</dependentAssembly>
|
||||
</assemblyBinding>
|
||||
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="Microsoft.IO.Redist" publicKeyToken="cc7b13ffcd2ddd51" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-6.1.0.0" newVersion="6.1.0.0" />
|
||||
</dependentAssembly>
|
||||
</assemblyBinding>
|
||||
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="System.Buffers" publicKeyToken="cc7b13ffcd2ddd51" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-4.0.4.0" newVersion="4.0.4.0" />
|
||||
</dependentAssembly>
|
||||
</assemblyBinding>
|
||||
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="System.Collections.Immutable" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-9.0.0.0" newVersion="9.0.0.0" />
|
||||
</dependentAssembly>
|
||||
</assemblyBinding>
|
||||
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="System.Memory" publicKeyToken="cc7b13ffcd2ddd51" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-4.0.2.0" newVersion="4.0.2.0" />
|
||||
</dependentAssembly>
|
||||
</assemblyBinding>
|
||||
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="System.Runtime.CompilerServices.Unsafe" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-6.0.1.0" newVersion="6.0.1.0" />
|
||||
</dependentAssembly>
|
||||
</assemblyBinding>
|
||||
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="System.Threading.Tasks.Extensions" publicKeyToken="cc7b13ffcd2ddd51" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-4.2.1.0" newVersion="4.2.1.0" />
|
||||
</dependentAssembly>
|
||||
</assemblyBinding>
|
||||
</runtime>
|
||||
</configuration>
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
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