Private/WorkspaceHelpers.ps1
|
function Get-WorkspacePath { <# .SYNOPSIS Gets the budget workspace root path. .DESCRIPTION Returns the workspace root path from preferences or the default location. Default location is %USERPROFILE%\Documents\.mybudget .OUTPUTS String - Full path to workspace root #> [CmdletBinding()] param() $preferences = Get-Preferences -ErrorAction SilentlyContinue if ($preferences -and $preferences.workspacePath) { return $preferences.workspacePath } # Default workspace location $documentsPath = [Environment]::GetFolderPath('MyDocuments') return Join-Path $documentsPath '.mybudget' } function Get-BudgetPath { <# .SYNOPSIS Resolves a budget name to its full directory path. .DESCRIPTION Takes a budget name and returns the full path to its directory. Uses the workspace path from preferences or default location. .PARAMETER BudgetName The name of the budget to resolve. .PARAMETER WorkspacePath Optional workspace path override. .OUTPUTS String - Full path to budget directory #> [CmdletBinding()] param( [Parameter(Mandatory)] [string]$BudgetName, [Parameter()] [string]$WorkspacePath ) if (-not $WorkspacePath) { $WorkspacePath = Get-WorkspacePath } return Join-Path (Join-Path $WorkspacePath 'budgets') $BudgetName } function Get-Preferences { <# .SYNOPSIS Loads user preferences from preferences.json. .DESCRIPTION Reads and deserializes the preferences.json file from the workspace root. Returns null if file doesn't exist. .PARAMETER WorkspacePath Optional workspace path override. .OUTPUTS PSCustomObject - Preferences object or $null if not found #> [CmdletBinding()] param( [Parameter()] [string]$WorkspacePath ) if (-not $WorkspacePath) { $documentsPath = [Environment]::GetFolderPath('MyDocuments') $WorkspacePath = Join-Path $documentsPath '.mybudget' } $preferencesPath = Join-Path $WorkspacePath 'preferences.json' if (-not (Test-Path $preferencesPath)) { return $null } try { $json = Get-Content -Path $preferencesPath -Raw | ConvertFrom-Json return $json } catch { Write-Error "Failed to load preferences: $_" return $null } } function Set-Preferences { <# .SYNOPSIS Saves user preferences to preferences.json. .DESCRIPTION Serializes and writes the preferences object to preferences.json. .PARAMETER Preferences The preferences object to save. .PARAMETER WorkspacePath Optional workspace path override. .OUTPUTS Boolean - True if successful #> [CmdletBinding()] param( [Parameter(Mandatory)] [PSCustomObject]$Preferences, [Parameter()] [string]$WorkspacePath ) if (-not $WorkspacePath) { $WorkspacePath = $Preferences.workspacePath if (-not $WorkspacePath) { $documentsPath = [Environment]::GetFolderPath('MyDocuments') $WorkspacePath = Join-Path $documentsPath '.mybudget' } } $preferencesPath = Join-Path $WorkspacePath 'preferences.json' # Ensure workspace directory exists if (-not (Test-Path $WorkspacePath)) { New-Item -Path $WorkspacePath -ItemType Directory -Force | Out-Null } try { $Preferences | ConvertTo-Json -Depth 10 | Set-Content -Path $preferencesPath -Encoding UTF8 return $true } catch { Write-Error "Failed to save preferences: $_" return $false } } function Test-WorkspaceInitialized { <# .SYNOPSIS Checks if the budget workspace has been initialized. .DESCRIPTION Verifies that the workspace directory and preferences.json exist. .PARAMETER WorkspacePath Optional workspace path to check. .OUTPUTS Boolean - True if workspace is initialized #> [CmdletBinding()] param( [Parameter()] [string]$WorkspacePath ) if (-not $WorkspacePath) { $WorkspacePath = Get-WorkspacePath } $preferencesPath = Join-Path $WorkspacePath 'preferences.json' $budgetsPath = Join-Path $WorkspacePath 'budgets' return (Test-Path $preferencesPath) -and (Test-Path $budgetsPath) } function Get-BudgetMetadata { <# .SYNOPSIS Loads metadata for a budget. .DESCRIPTION Reads and deserializes the metadata.json file from a budget directory. .PARAMETER BudgetName The name of the budget. .PARAMETER BudgetPath Optional direct path to budget directory. .OUTPUTS PSCustomObject - Budget metadata or $null if not found #> [CmdletBinding()] param( [Parameter()] [string]$BudgetName, [Parameter()] [string]$BudgetPath ) if (-not $BudgetPath -and $BudgetName) { $BudgetPath = Get-BudgetPath -BudgetName $BudgetName } if (-not $BudgetPath) { Write-Error "BudgetName or BudgetPath must be provided" return $null } $metadataPath = Join-Path $BudgetPath 'metadata.json' if (-not (Test-Path $metadataPath)) { return $null } try { $json = Get-Content -Path $metadataPath -Raw | ConvertFrom-Json return $json } catch { Write-Error "Failed to load budget metadata: $_" return $null } } function Set-BudgetMetadata { <# .SYNOPSIS Saves metadata for a budget. .DESCRIPTION Serializes and writes the metadata object to metadata.json in the budget directory. .PARAMETER Metadata The metadata object to save. .PARAMETER BudgetPath Path to the budget directory. .OUTPUTS Boolean - True if successful #> [CmdletBinding()] param( [Parameter(Mandatory)] [PSCustomObject]$Metadata, [Parameter(Mandatory)] [string]$BudgetPath ) $metadataPath = Join-Path $BudgetPath 'metadata.json' # Ensure budget directory exists if (-not (Test-Path $BudgetPath)) { New-Item -Path $BudgetPath -ItemType Directory -Force | Out-Null } try { $Metadata | ConvertTo-Json -Depth 10 | Set-Content -Path $metadataPath -Encoding UTF8 return $true } catch { Write-Error "Failed to save budget metadata: $_" return $false } } function Get-ActiveBudgetPath { <# .SYNOPSIS Gets the full path to the currently active budget. .DESCRIPTION Returns the directory path for the active budget from preferences. Returns null if no workspace is initialized or no active budget is set. .OUTPUTS String - Full path to active budget directory or $null #> [CmdletBinding()] param() if (-not (Test-WorkspaceInitialized)) { return $null } $preferences = Get-Preferences if (-not $preferences -or -not $preferences.activeBudget) { return $null } return Get-BudgetPath -BudgetName $preferences.activeBudget -WorkspacePath $preferences.workspacePath } function Resolve-DataPath { <# .SYNOPSIS Resolves the data path for entity storage based on context. .DESCRIPTION Determines the appropriate data path for entity storage: 1. If DataPath is explicitly provided, use it (legacy mode) 2. If Budget parameter is provided, resolve to that budget's path 3. Otherwise, use the active budget from workspace 4. Fall back to default path if no workspace initialized .PARAMETER DataPath Explicit data path (legacy parameter). .PARAMETER Budget Budget name to target. .OUTPUTS String - Resolved data path #> [CmdletBinding()] param( [Parameter()] [string]$DataPath, [Parameter()] [string]$Budget ) # Priority 1: Explicit DataPath (legacy mode) if ($DataPath) { return $DataPath } # Priority 2: Specific budget parameter if ($Budget) { if (-not (Test-WorkspaceInitialized)) { Write-Error "Budget workspace not initialized. Run Initialize-BudgetWorkspace first." return $null } $budgetPath = Get-BudgetPath -BudgetName $Budget if (-not (Test-Path $budgetPath)) { Write-Error "Budget '$Budget' not found. Use Get-Budget to see available budgets." return $null } return $budgetPath } # Priority 3: Active budget from workspace if (Test-WorkspaceInitialized) { $activePath = Get-ActiveBudgetPath if ($activePath) { return $activePath } Write-Warning "No active budget set. Use Set-ActiveBudget or provide -Budget parameter." } # Fall back to default path (backwards compatibility) return $script:DefaultDataPath } |