Files
roa2web-service-auto/deployment/windows/scripts/Backup-TelegramDB.ps1
Marius Mutu 6b13ffa183 Initial commit: ROA2WEB - FastAPI + Vue.js + Telegram Bot
Modern ERP Reports Application with microservices architecture

Tech Stack:
- Backend: FastAPI + python-oracledb (Oracle DB integration)
- Frontend: Vue.js 3 + PrimeVue + Vite
- Telegram Bot: python-telegram-bot + SQLite
- Infrastructure: Shared database pool, JWT authentication, SSH tunnel

Features:
- FastAPI backend with async Oracle connection pool
- Vue.js 3 responsive frontend with PrimeVue components
- Telegram bot alternative interface
- Microservices architecture with shared components
- Complete deployment support (Linux Docker + Windows IIS)
- Comprehensive testing (Playwright E2E + pytest)

Repository Structure:
- reports-app/ - Main application (backend, frontend, telegram-bot)
- shared/ - Shared components (database pool, auth, utils)
- deployment/ - Deployment scripts (Linux & Windows)
- docs/ - Project documentation
- security/ - Security scanning and git hooks
2025-10-25 14:55:08 +03:00

362 lines
11 KiB
PowerShell

<#
.SYNOPSIS
Backup ROA2WEB Telegram Bot SQLite Database
.DESCRIPTION
This script creates a backup of the Telegram bot's SQLite database:
- Copies database file with timestamp
- Compresses backup (optional)
- Cleans up old backups (keeps last 30 days)
- Logs backup operations
- Can run manually or via scheduled task
.PARAMETER InstallPath
Installation path (default: C:\inetpub\wwwroot\roa2web\telegram-bot)
.PARAMETER RetentionDays
Number of days to keep backups (default: 30)
.PARAMETER Compress
Compress backup file (default: true)
.PARAMETER LogToFile
Write backup log to file (default: true)
.EXAMPLE
.\Backup-TelegramDB.ps1
Standard backup with defaults
.EXAMPLE
.\Backup-TelegramDB.ps1 -RetentionDays 60 -Compress $true
Backup with 60-day retention and compression
.EXAMPLE
.\Backup-TelegramDB.ps1 -LogToFile $false
Backup without logging to file (console only)
.NOTES
Author: ROA2WEB Team
Requires: PowerShell 5.1+
Can be run manually or via Task Scheduler
#>
[CmdletBinding()]
param(
[string]$InstallPath = "C:\inetpub\wwwroot\roa2web\telegram-bot",
[int]$RetentionDays = 30,
[bool]$Compress = $true,
[bool]$LogToFile = $true
)
$ErrorActionPreference = "Stop"
# =============================================================================
# CONFIGURATION
# =============================================================================
$script:Config = @{
InstallPath = $InstallPath
DataPath = Join-Path $InstallPath "data"
BackupPath = Join-Path $InstallPath "backups"
LogsPath = Join-Path $InstallPath "logs"
DatabaseFile = "telegram_bot.db"
RetentionDays = $RetentionDays
Compress = $Compress
}
# =============================================================================
# HELPER FUNCTIONS
# =============================================================================
function Write-Log {
param(
[string]$Message,
[string]$Level = "INFO"
)
$timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
$logMessage = "[$timestamp] [$Level] $Message"
# Console output
switch ($Level) {
"ERROR" { Write-Host $logMessage -ForegroundColor Red }
"WARN" { Write-Host $logMessage -ForegroundColor Yellow }
"SUCCESS" { Write-Host $logMessage -ForegroundColor Green }
default { Write-Host $logMessage -ForegroundColor Cyan }
}
# File output
if ($LogToFile) {
$logFile = Join-Path $Config.LogsPath "backup.log"
Add-Content -Path $logFile -Value $logMessage -Encoding UTF8
}
}
function Test-DatabaseFile {
$dbPath = Join-Path $Config.DataPath $Config.DatabaseFile
if (-not (Test-Path $dbPath)) {
Write-Log "Database file not found: $dbPath" -Level "ERROR"
return $false
}
# Check if file is accessible (not locked)
try {
$stream = [System.IO.File]::Open($dbPath, 'Open', 'Read', 'Read')
$stream.Close()
Write-Log "Database file is accessible: $dbPath" -Level "INFO"
return $true
} catch {
Write-Log "Database file is locked or inaccessible: $_" -Level "ERROR"
return $false
}
}
function Get-DatabaseSize {
$dbPath = Join-Path $Config.DataPath $Config.DatabaseFile
$size = (Get-Item $dbPath).Length / 1KB
return [math]::Round($size, 2)
}
function New-BackupDirectory {
if (-not (Test-Path $Config.BackupPath)) {
New-Item -ItemType Directory -Path $Config.BackupPath -Force | Out-Null
Write-Log "Created backup directory: $($Config.BackupPath)" -Level "INFO"
}
}
function Backup-Database {
Write-Log "Starting database backup..." -Level "INFO"
# Ensure backup directory exists
New-BackupDirectory
# Generate backup filename with timestamp
$timestamp = Get-Date -Format "yyyyMMdd-HHmmss"
$backupFileName = "telegram_bot_backup_$timestamp.db"
$backupFilePath = Join-Path $Config.BackupPath $backupFileName
# Source database path
$dbPath = Join-Path $Config.DataPath $Config.DatabaseFile
try {
# Copy database file
Copy-Item -Path $dbPath -Destination $backupFilePath -Force
Write-Log "Database backed up to: $backupFileName" -Level "SUCCESS"
# Get backup file size
$backupSize = (Get-Item $backupFilePath).Length / 1KB
Write-Log "Backup size: $([math]::Round($backupSize, 2)) KB" -Level "INFO"
# Compress if enabled
if ($Config.Compress) {
$compressedPath = Compress-Backup -BackupPath $backupFilePath
if ($compressedPath) {
# Remove uncompressed backup
Remove-Item -Path $backupFilePath -Force
Write-Log "Uncompressed backup removed" -Level "INFO"
return $compressedPath
}
}
return $backupFilePath
} catch {
Write-Log "Backup failed: $_" -Level "ERROR"
return $null
}
}
function Compress-Backup {
param([string]$BackupPath)
Write-Log "Compressing backup..." -Level "INFO"
$zipPath = "$BackupPath.zip"
try {
# Create ZIP archive
Compress-Archive -Path $BackupPath -DestinationPath $zipPath -CompressionLevel Optimal -Force
# Get compressed size
$originalSize = (Get-Item $BackupPath).Length / 1KB
$compressedSize = (Get-Item $zipPath).Length / 1KB
$ratio = [math]::Round((1 - ($compressedSize / $originalSize)) * 100, 1)
Write-Log "Backup compressed: $([math]::Round($compressedSize, 2)) KB (saved $ratio%)" -Level "SUCCESS"
return $zipPath
} catch {
Write-Log "Compression failed: $_" -Level "WARN"
return $null
}
}
function Remove-OldBackups {
Write-Log "Cleaning up old backups (keeping last $($Config.RetentionDays) days)..." -Level "INFO"
$cutoffDate = (Get-Date).AddDays(-$Config.RetentionDays)
try {
# Get all backup files (both .db and .zip)
$allBackups = Get-ChildItem -Path $Config.BackupPath -File |
Where-Object {
$_.Name -like "telegram_bot_backup_*.db" -or
$_.Name -like "telegram_bot_backup_*.db.zip"
}
$removedCount = 0
$freedSpace = 0
foreach ($backup in $allBackups) {
if ($backup.LastWriteTime -lt $cutoffDate) {
$size = $backup.Length / 1MB
Remove-Item -Path $backup.FullName -Force
$removedCount++
$freedSpace += $size
Write-Log "Removed old backup: $($backup.Name)" -Level "INFO"
}
}
if ($removedCount -gt 0) {
Write-Log "Removed $removedCount old backup(s), freed $([math]::Round($freedSpace, 2)) MB" -Level "SUCCESS"
} else {
Write-Log "No old backups to remove" -Level "INFO"
}
} catch {
Write-Log "Failed to clean up old backups: $_" -Level "WARN"
}
}
function Get-BackupStatistics {
Write-Log "Backup Statistics:" -Level "INFO"
# Count backups
$allBackups = Get-ChildItem -Path $Config.BackupPath -File |
Where-Object {
$_.Name -like "telegram_bot_backup_*.db" -or
$_.Name -like "telegram_bot_backup_*.db.zip"
}
$totalBackups = $allBackups.Count
$totalSize = ($allBackups | Measure-Object -Property Length -Sum).Sum / 1MB
Write-Log " Total backups: $totalBackups" -Level "INFO"
Write-Log " Total size: $([math]::Round($totalSize, 2)) MB" -Level "INFO"
# Latest backup
if ($totalBackups -gt 0) {
$latest = $allBackups | Sort-Object LastWriteTime -Descending | Select-Object -First 1
Write-Log " Latest backup: $($latest.Name) ($([math]::Round($latest.Length / 1KB, 2)) KB)" -Level "INFO"
Write-Log " Created: $($latest.LastWriteTime)" -Level "INFO"
}
# Oldest backup
if ($totalBackups -gt 1) {
$oldest = $allBackups | Sort-Object LastWriteTime | Select-Object -First 1
$age = (Get-Date) - $oldest.LastWriteTime
Write-Log " Oldest backup: $($oldest.Name) (Age: $([math]::Round($age.TotalDays, 1)) days)" -Level "INFO"
}
}
function Test-BackupIntegrity {
param([string]$BackupPath)
Write-Log "Testing backup integrity..." -Level "INFO"
try {
# For ZIP files, test archive
if ($BackupPath -like "*.zip") {
# Try to extract to temp location
$tempExtract = Join-Path $env:TEMP "telegram_bot_backup_test"
if (Test-Path $tempExtract) {
Remove-Item -Path $tempExtract -Recurse -Force
}
Expand-Archive -Path $BackupPath -DestinationPath $tempExtract -Force
# Check if database file exists in extracted folder
$extractedDb = Get-ChildItem -Path $tempExtract -Filter "*.db" -Recurse
if ($extractedDb) {
Write-Log "Backup integrity test PASSED (ZIP archive valid)" -Level "SUCCESS"
Remove-Item -Path $tempExtract -Recurse -Force
return $true
} else {
Write-Log "Backup integrity test FAILED (No database file in archive)" -Level "ERROR"
Remove-Item -Path $tempExtract -Recurse -Force
return $false
}
} else {
# For .db files, try to open
$stream = [System.IO.File]::Open($BackupPath, 'Open', 'Read', 'Read')
$stream.Close()
Write-Log "Backup integrity test PASSED (Database file readable)" -Level "SUCCESS"
return $true
}
} catch {
Write-Log "Backup integrity test FAILED: $_" -Level "ERROR"
return $false
}
}
# =============================================================================
# MAIN BACKUP FLOW
# =============================================================================
function Main {
Write-Host @"
====================================================================
ROA2WEB Telegram Bot - Database Backup
SQLite database backup and retention management
====================================================================
"@ -ForegroundColor Cyan
Write-Log "Backup started by: $env:USERNAME" -Level "INFO"
Write-Log "Backup script: $($MyInvocation.MyCommand.Path)" -Level "INFO"
# Check if database exists
if (-not (Test-DatabaseFile)) {
Write-Log "Backup aborted: Database file not accessible" -Level "ERROR"
exit 1
}
# Get current database size
$dbSize = Get-DatabaseSize
Write-Log "Current database size: $dbSize KB" -Level "INFO"
try {
# Perform backup
$backupPath = Backup-Database
if ($backupPath) {
# Test backup integrity
$integrityOk = Test-BackupIntegrity -BackupPath $backupPath
if ($integrityOk) {
# Cleanup old backups
Remove-OldBackups
# Show statistics
Get-BackupStatistics
Write-Log "Backup completed successfully" -Level "SUCCESS"
exit 0
} else {
Write-Log "Backup created but failed integrity test" -Level "ERROR"
exit 1
}
} else {
Write-Log "Backup failed" -Level "ERROR"
exit 1
}
} catch {
Write-Log "Backup process failed: $_" -Level "ERROR"
Write-Log $_.ScriptStackTrace -Level "ERROR"
exit 1
}
}
# Run main backup
Main