# 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 '', "`n" $text = $text -replace ']*>', "`n" $text = $text -replace '

', "" $text = $text -replace ']*>', "`n- " $text = $text -replace ']*>', "`n## " $text = $text -replace '', "`n" $text = $text -replace ']*>', "`n| " $text = $text -replace ']*>', " | " $text = $text -replace ']*>', " | " $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 } }