Ka-Note/ka-note/scripts/import-helpers.ps1

161 lines
5.3 KiB
PowerShell

<#
.SYNOPSIS
Shared helper functions for UpNote → Ka-Note bundle imports.
Dot-source this file in import scripts: . "$PSScriptRoot\import-helpers.ps1"
.NOTES
Bundle file formats (as of current schema):
contexts.json — array of AgendaContext:
id, name, type (meeting|project|person|company), sortOrder,
updatedAt, deletedAt, version, archivedAt, isFavorite, meta
topics.json — array of Topic:
id, contextId, title, body, sortOrder, isPinned,
deletedAt, updatedAt, version
history/<id>.meta.json — HistoryEntry (without text):
id, topicId, date (YYYY-MM-DD), sortOrder, linkedContextId,
doneAt, wiedervorlageDate, wiedervorlageResolvedAt,
updatedAt, deletedAt, version
history/<id>.md — plain text / markdown content
IMPORTANT:
- History is TOPIC-scoped (topicId), NOT context-scoped.
- History date is "YYYY-MM-DD" (no time part).
- History has no "title" field.
- Soft-deleted contexts cause 500 on upload if new topics reference them
→ always call Upsert-Context which auto-resurrects deleted contexts.
#>
# Globals set by Initialize-BundleSession
$script:WorkDir = $null
$script:Now = $null
function Initialize-BundleSession {
param([string]$WorkDir)
$script:WorkDir = $WorkDir
$script:Now = (Get-Date).ToUniversalTime().ToString("yyyy-MM-ddTHH:mm:ss.fffZ")
if (-not (Test-Path "$WorkDir\history")) { New-Item -ItemType Directory "$WorkDir\history" | Out-Null }
}
# Upsert a context: creates new OR resurrects if soft-deleted OR skips if active.
# Always bumps version and sets name/type/sortOrder if changed.
function Upsert-Context {
param(
[string]$CtxPath,
[string]$Id,
[string]$Name,
[string]$Type = 'meeting',
[int] $SortOrder = 10,
[bool] $IsFavorite = $true
)
$ctxs = Get-Content $CtxPath -Raw -Encoding UTF8 | ConvertFrom-Json
$existing = $ctxs | Where-Object { $_.id -eq $Id }
if ($existing) {
$wasDeleted = $null -ne $existing.deletedAt
$existing | Add-Member -NotePropertyName deletedAt -NotePropertyValue $null -Force
$existing | Add-Member -NotePropertyName name -NotePropertyValue $Name -Force
$existing | Add-Member -NotePropertyName updatedAt -NotePropertyValue $script:Now -Force
$existing.version++
if ($wasDeleted) {
Write-Host " [CTX] Resurrected: $Id" -ForegroundColor Green
} else {
Write-Host " [CTX] Already active, updated: $Id" -ForegroundColor DarkGray
}
} else {
$new = [PSCustomObject]@{
id = $Id
name = $Name
type = $Type
sortOrder = $SortOrder
updatedAt = $script:Now
deletedAt = $null
version = 1
archivedAt = $null
isFavorite = $IsFavorite
meta = $null
}
$ctxs = @($ctxs) + $new
Write-Host " [CTX] Created: $Id ($Name)" -ForegroundColor Green
}
$ctxs | ConvertTo-Json -Depth 10 | Set-Content $CtxPath -Encoding UTF8
}
# Soft-delete all topics for a context (cleanup orphans or old data)
function Remove-ContextTopics {
param([string]$TopicsPath, [string]$ContextId)
$tops = Get-Content $TopicsPath -Raw -Encoding UTF8 | ConvertFrom-Json
$count = 0
foreach ($t in $tops) {
if ($t.contextId -eq $ContextId -and -not $t.deletedAt) {
$t | Add-Member -NotePropertyName deletedAt -NotePropertyValue $script:Now -Force
$t | Add-Member -NotePropertyName updatedAt -NotePropertyValue $script:Now -Force
$t.version++
$count++
}
}
$tops | ConvertTo-Json -Depth 10 | Set-Content $TopicsPath -Encoding UTF8
if ($count -gt 0) { Write-Host " [TOP] Soft-deleted $count orphan topics for $ContextId" -ForegroundColor DarkGray }
}
# Add a new topic. Returns the topic ID.
function Add-Topic {
param(
[string]$TopicsPath,
[string]$ContextId,
[string]$Title,
[string]$Body = '',
[int] $SortOrder = 0,
[bool] $IsPinned = $false
)
$id = [System.Guid]::NewGuid().ToString()
$tops = Get-Content $TopicsPath -Raw -Encoding UTF8 | ConvertFrom-Json
$new = [PSCustomObject]@{
id = $id
contextId = $ContextId
title = $Title
body = $Body
sortOrder = $SortOrder
isPinned = $IsPinned
deletedAt = $null
updatedAt = $script:Now
version = 1
}
$tops = @($tops) + $new
$tops | ConvertTo-Json -Depth 10 | Set-Content $TopicsPath -Encoding UTF8
Write-Host " [TOP] + $Title" -ForegroundColor DarkGray
return $id
}
# Add a history entry (attached to a topic).
# $Date: 'YYYY-MM-DD'
# $Text: markdown string
function Add-HistoryEntry {
param(
[string]$TopicId,
[string]$Date,
[string]$Text,
[int] $SortOrder = 0
)
$id = [System.Guid]::NewGuid().ToString()
$meta = [PSCustomObject]@{
id = $id
topicId = $TopicId
date = $Date
sortOrder = $SortOrder
linkedContextId = $null
doneAt = $null
wiedervorlageDate = $null
wiedervorlageResolvedAt = $null
updatedAt = $script:Now
deletedAt = $null
version = 1
}
$meta | ConvertTo-Json -Depth 5 | Set-Content "$($script:WorkDir)\history\$id.meta.json" -Encoding UTF8
$Text | Set-Content "$($script:WorkDir)\history\$id.md" -Encoding UTF8
Write-Host " [HIS] + $Date" -ForegroundColor DarkGray
return $id
}