Bahn: aisupport, Analyse-O2C-C2S, awesome-bahn-mcp-servers, beam-mcp,
Confluence_Bot, db-planet-mcp-server, O2C-Harness, project-audit,
Projekt-KIQ-HP, teamlandkarte-mcp
Dhive: Jury-Voting
Privat: CV, NoteGraph (NOTE: NoteGraph needs complete redo after consolidation)
Shared: AI-Orchestrator, OrgMyLife, power_skills_and_more
Shared/references: symphony (read-only)
Bahn repos remain available as independent remotes - this monorepo
pulls them in via subtree, the originals are untouched.
161 lines
6.4 KiB
PowerShell
161 lines
6.4 KiB
PowerShell
# Shared Confluence API functions
|
|
# Source this file in other scripts: . "$PSScriptRoot/lib/confluence-api.ps1"
|
|
|
|
function Invoke-ConfluenceApi {
|
|
param([string]$Endpoint, [hashtable]$Params = @{}, [string]$Method = "Get", [string]$Body = $null)
|
|
$QS = ($Params.GetEnumerator() | ForEach-Object {
|
|
"$($_.Key)=$([Uri]::EscapeDataString($_.Value))"
|
|
}) -join "&"
|
|
$Uri = "$ApiBase$Endpoint"
|
|
if ($QS) { $Uri = "$Uri`?$QS" }
|
|
try {
|
|
if ($Body) {
|
|
$Resp = Invoke-WebRequest -Uri $Uri -Method $Method -Headers $Headers -Body ([System.Text.Encoding]::UTF8.GetBytes($Body)) -UseBasicParsing -ErrorAction Stop
|
|
} else {
|
|
$Resp = Invoke-WebRequest -Uri $Uri -Method $Method -Headers $Headers -UseBasicParsing -ErrorAction Stop
|
|
}
|
|
return ($Resp.Content | ConvertFrom-Json)
|
|
} catch {
|
|
Write-Host " ERROR at $Uri : $($_.Exception.Message)" -ForegroundColor Red
|
|
return $null
|
|
}
|
|
}
|
|
|
|
function Get-ChildPages {
|
|
param([string]$PageId)
|
|
$AllChildren = @()
|
|
$Start = 0
|
|
do {
|
|
$Result = Invoke-ConfluenceApi -Endpoint "/content/$PageId/child/page" -Params @{
|
|
start = "$Start"
|
|
limit = "$PerPage"
|
|
expand = "version"
|
|
}
|
|
if ($null -eq $Result) { break }
|
|
$Pages = $Result.results
|
|
if ($null -eq $Pages -or $Pages.Count -eq 0) { break }
|
|
$AllChildren += $Pages
|
|
$Start += $PerPage
|
|
$Size = 0
|
|
if ($Result.size) { $Size = $Result.size }
|
|
} while ($Size -ge $PerPage)
|
|
return $AllChildren
|
|
}
|
|
|
|
function Get-PageContent {
|
|
param([string]$PageId)
|
|
return Invoke-ConfluenceApi -Endpoint "/content/$PageId" -Params @{
|
|
expand = "body.storage,version,ancestors,metadata.labels,space"
|
|
}
|
|
}
|
|
|
|
function Convert-HtmlToText($html) {
|
|
if ($null -eq $html) { return "" }
|
|
$text = $html -replace '<br\s*/?>', "`n"
|
|
$text = $text -replace '<p[^>]*>', "`n"
|
|
$text = $text -replace '</p>', ""
|
|
$text = $text -replace '<li[^>]*>', "`n- "
|
|
$text = $text -replace '<h[1-6][^>]*>', "`n## "
|
|
$text = $text -replace '</h[1-6]>', "`n"
|
|
$text = $text -replace '<tr[^>]*>', "`n| "
|
|
$text = $text -replace '<td[^>]*>', " | "
|
|
$text = $text -replace '<th[^>]*>', " | "
|
|
$text = $text -replace '<[^>]+>', ''
|
|
Add-Type -AssemblyName System.Web -ErrorAction SilentlyContinue
|
|
try { $text = [System.Web.HttpUtility]::HtmlDecode($text) } catch {}
|
|
return $text.Trim()
|
|
}
|
|
|
|
function Create-Or-Update-Page {
|
|
param([string]$Title, [string]$HtmlBody, [string]$ParentId)
|
|
|
|
$SearchUri = "$ApiBase/content?spaceKey=$SpaceKey&title=$([Uri]::EscapeDataString($Title))&type=page"
|
|
try {
|
|
$SearchResp = Invoke-WebRequest -Uri $SearchUri -Headers $Headers -UseBasicParsing -ErrorAction Stop
|
|
$SearchData = $SearchResp.Content | ConvertFrom-Json
|
|
} catch {
|
|
Write-Host " ERROR searching: $($_.Exception.Message)" -ForegroundColor Red
|
|
return $null
|
|
}
|
|
|
|
if ($SearchData.results -and $SearchData.results.Count -gt 0) {
|
|
$PageId = $SearchData.results[0].id
|
|
try {
|
|
$VerResp = Invoke-WebRequest -Uri "$ApiBase/content/$PageId`?expand=version,body.storage" -Headers $Headers -UseBasicParsing -ErrorAction Stop
|
|
$VerData = $VerResp.Content | ConvertFrom-Json
|
|
$Version = $VerData.version.number + 1
|
|
$CurrentBody = ""
|
|
if ($VerData.body -and $VerData.body.storage) { $CurrentBody = $VerData.body.storage.value }
|
|
$NormCurrent = ($CurrentBody -replace '<[^>]+>' -replace '&\w+;' -replace '\s+', ' ').Trim()
|
|
$NormNew = ($HtmlBody -replace '<[^>]+>' -replace '&\w+;' -replace '\s+', ' ').Trim()
|
|
if ($NormCurrent -eq $NormNew) {
|
|
Write-Host " No changes (ID: $PageId)" -ForegroundColor DarkGray
|
|
return $PageId
|
|
}
|
|
} catch {
|
|
$Version = $SearchData.results[0].version.number + 1
|
|
}
|
|
|
|
Write-Host " Updating (ID: $PageId, v$Version)..." -NoNewline
|
|
$Body = @{
|
|
version = @{ number = $Version }
|
|
title = $Title
|
|
type = "page"
|
|
body = @{ storage = @{ value = $HtmlBody; representation = "storage" } }
|
|
} | ConvertTo-Json -Depth 10
|
|
|
|
try {
|
|
$Resp = Invoke-WebRequest -Uri "$ApiBase/content/$PageId" -Method Put -Headers $Headers -Body ([System.Text.Encoding]::UTF8.GetBytes($Body)) -UseBasicParsing -ErrorAction Stop
|
|
Write-Host " OK" -ForegroundColor Green
|
|
return ($Resp.Content | ConvertFrom-Json).id
|
|
} catch {
|
|
Write-Host " ERROR: $($_.Exception.Message)" -ForegroundColor Red
|
|
return $null
|
|
}
|
|
} else {
|
|
Write-Host " Creating new page..." -NoNewline
|
|
$Body = @{
|
|
type = "page"
|
|
title = $Title
|
|
space = @{ key = $SpaceKey }
|
|
ancestors = @(@{ id = $ParentId })
|
|
body = @{ storage = @{ value = $HtmlBody; representation = "storage" } }
|
|
} | ConvertTo-Json -Depth 10
|
|
|
|
try {
|
|
$Resp = Invoke-WebRequest -Uri "$ApiBase/content" -Method Post -Headers $Headers -Body ([System.Text.Encoding]::UTF8.GetBytes($Body)) -UseBasicParsing -ErrorAction Stop
|
|
Write-Host " OK" -ForegroundColor Green
|
|
return ($Resp.Content | ConvertFrom-Json).id
|
|
} catch {
|
|
Write-Host " ERROR: $($_.Exception.Message)" -ForegroundColor Red
|
|
return $null
|
|
}
|
|
}
|
|
}
|
|
|
|
function Move-Page($PageId, $NewParentId) {
|
|
$Page = Invoke-ConfluenceApi -Endpoint "/content/$PageId" -Params @{ expand = "version,ancestors" }
|
|
if (-not $Page) { return $false }
|
|
if ($Page.ancestors -and $Page.ancestors.Count -gt 0) {
|
|
if ($Page.ancestors[-1].id -eq $NewParentId) { return $true }
|
|
}
|
|
$Version = $Page.version.number + 1
|
|
$Json = @{
|
|
type = "page"; title = $Page.title
|
|
version = @{ number = $Version }
|
|
ancestors = @(@{ id = $NewParentId })
|
|
} | ConvertTo-Json -Depth 10
|
|
$Result = Invoke-ConfluenceApi -Endpoint "/content/$PageId" -Method "Put" -Body $Json
|
|
return ($null -ne $Result)
|
|
}
|
|
|
|
function Delete-Page($PageId) {
|
|
try {
|
|
Invoke-WebRequest -Uri "$ApiBase/content/$PageId" -Method Delete -Headers $Headers -UseBasicParsing -ErrorAction Stop
|
|
return $true
|
|
} catch {
|
|
Write-Host " ERROR deleting $PageId : $($_.Exception.Message)" -ForegroundColor Red
|
|
return $false
|
|
}
|
|
}
|