This commit is contained in:
2026-05-23 21:31:34 +02:00
parent 51b5ddc6f2
commit 641bb10479
6155 changed files with 3775717 additions and 291 deletions

View File

@@ -0,0 +1,3 @@
Restore: Dateien nach Verzeichnis C:\Users\surov\Documents\AZA_GIT\aza\AzA march 2026 zurueckkopieren (gleiche relativen Pfade).
Geaendert: installer\aza_installer.iss, release.ps1.
Timestamp: 20260514_192048

View File

@@ -0,0 +1,156 @@
#define MyAppName "AZA"
#ifndef MyAppVersion
#define MyAppVersion "0.1.0"
#endif
#define MyAppPublisher "AZA MedWork"
#define MyAppExeName "aza_desktop.exe"
#define MyAppSourceDir SourcePath + "\..\dist\aza_desktop"
[Setup]
AppId={{B7E4C0D2-6B5D-4D39-9D7C-5B0D5E8C2A11}
AppName={#MyAppName}
AppVersion={#MyAppVersion}
AppPublisher={#MyAppPublisher}
AppPublisherURL=https://aza-medwork.ch
DefaultDirName={autopf}\AZA Desktop
DefaultGroupName=AZA Desktop
DisableProgramGroupPage=no
OutputDir={#MyAppSourceDir}\..\..\dist\installer
OutputBaseFilename=aza_desktop_setup
Compression=lzma
SolidCompression=yes
WizardStyle=modern
PrivilegesRequired=admin
ArchitecturesInstallIn64BitMode=x64
UninstallDisplayIcon={app}\logo.ico
SetupIconFile={#MyAppSourceDir}\..\..\logo.ico
SetupMutex=AZADesktopSetupMutex
CloseApplications=no
RestartApplications=no
[Languages]
Name: "german"; MessagesFile: "compiler:Languages\German.isl"
[Types]
Name: "standard"; Description: "AZA Office und AZA Chat (empfohlen)"
Name: "chatonly"; Description: "Nur AZA Chat (Empfang / MPA)"
Name: "custom"; Description: "Benutzerdefiniert"; Flags: iscustom
[Components]
Name: "office"; Description: "AZA Office — Hauptprogramm (Dokumentation, Profil, KG, Diktat, Briefe, Praxisarbeitsplatz)"; Types: standard custom; Flags: checkablealone
Name: "chat"; Description: "AZA Chat — Empfangs- und Chat-Huelle (WebView, Server-Login)"; Types: standard chatonly custom; Flags: checkablealone
[Tasks]
Name: "desktopicon_office"; Description: "Desktop-Verknuepfung: AZA Office"; GroupDescription: "Verknuepfungen:"; Components: office
Name: "desktopicon_chat"; Description: "Desktop-Verknuepfung: AZA Chat"; GroupDescription: "Verknuepfungen:"; Components: chat
[Dirs]
Name: "{app}\config"; Components: office; Permissions: users-modify
[InstallDelete]
Type: filesandordirs; Name: "{app}\_internal\*.pyd"
Type: filesandordirs; Name: "{app}\_internal\*.dll"
Type: files; Name: "{app}\_internal\*.tmp"
[Files]
; --- AZA Office ---
Source: "{#MyAppSourceDir}\{#MyAppExeName}"; DestDir: "{app}"; Components: office; Flags: ignoreversion restartreplace uninsrestartdelete
Source: "{#MyAppSourceDir}\_internal\*"; DestDir: "{app}\_internal"; Components: office; Flags: ignoreversion recursesubdirs createallsubdirs restartreplace
Source: "{#MyAppSourceDir}\_internal\backend_url.txt"; DestDir: "{app}"; Components: office; Flags: ignoreversion skipifsourcedoesntexist
Source: "{#MyAppSourceDir}\_internal\backend_token.txt"; DestDir: "{app}"; Components: office; Flags: ignoreversion skipifsourcedoesntexist
Source: "{#MyAppSourceDir}\BUILD_INFO.txt"; DestDir: "{app}"; Components: office; Flags: ignoreversion skipifsourcedoesntexist
Source: "{#MyAppSourceDir}\..\..\setup_openai_runtime.ps1"; DestDir: "{app}"; Components: office; Flags: ignoreversion
; --- Gemeinsam: Icon fuer Verknuepfungen ---
Source: "{#MyAppSourceDir}\..\..\logo.ico"; DestDir: "{app}"; Components: office chat; Flags: ignoreversion
; --- AZA Chat (Ein-Datei-WebView-Shell) ---
Source: "{#MyAppSourceDir}\AZA_EmpfangShell.exe"; DestDir: "{app}"; Components: chat; Flags: ignoreversion restartreplace uninsrestartdelete
[Icons]
Name: "{group}\AZA Office"; Filename: "{app}\{#MyAppExeName}"; IconFilename: "{app}\logo.ico"; Components: office
Name: "{autodesktop}\AZA Office"; Filename: "{app}\{#MyAppExeName}"; IconFilename: "{app}\logo.ico"; Tasks: desktopicon_office; Components: office
Name: "{group}\OpenAI Schluessel einrichten"; Filename: "powershell.exe"; Parameters: "-ExecutionPolicy Bypass -File ""{app}\setup_openai_runtime.ps1"""; Components: office
Name: "{group}\AZA Chat"; Filename: "{app}\AZA_EmpfangShell.exe"; IconFilename: "{app}\logo.ico"; Components: chat
Name: "{autodesktop}\AZA Chat"; Filename: "{app}\AZA_EmpfangShell.exe"; IconFilename: "{app}\logo.ico"; Tasks: desktopicon_chat; Components: chat
[Run]
Filename: "{app}\{#MyAppExeName}"; Description: "AZA Office starten"; Flags: nowait postinstall skipifsilent; Components: office
[UninstallRun]
Filename: "netsh.exe"; Parameters: "advfirewall firewall delete rule name=""AZA Desktop - Lokale Kommunikation"""; Flags: runhidden; RunOnceId: "DelFirewallRule"
[Code]
function NextButtonClick(CurPageID: Integer): Boolean;
begin
Result := True;
if CurPageID = wpSelectComponents then
begin
if not WizardIsComponentSelected('office') and not WizardIsComponentSelected('chat') then
begin
MsgBox('Bitte mindestens eine Komponente waehlen (AZA Office und/oder AZA Chat).', mbError, MB_OK);
Result := False;
Exit;
end;
if WizardIsComponentSelected('office') and not WizardIsComponentSelected('chat') then
begin
if MsgBox('Ohne "AZA Chat" ist der Chat-Button in AZA Office nicht nutzbar.' + #13#10 + #13#10 +
'Empfehlung: Aktivieren Sie "AZA Chat" zusaetzlich zu "AZA Office".' + #13#10 + #13#10 +
'Trotzdem fortfahren und nur AZA Office installieren?',
mbConfirmation, MB_YESNO or MB_DEFBUTTON2) = IDNO then
Result := False;
end;
end;
end;
function InitializeSetup(): Boolean;
var
R: Integer;
begin
Result := True;
Exec('taskkill.exe', '/F /IM aza_desktop.exe', '', SW_HIDE, ewWaitUntilTerminated, R);
Exec('taskkill.exe', '/F /IM AZA_EmpfangShell.exe', '', SW_HIDE, ewWaitUntilTerminated, R);
Exec('taskkill.exe', '/F /IM AZA_EmpfangChat.exe', '', SW_HIDE, ewWaitUntilTerminated, R);
Exec('taskkill.exe', '/F /IM AZA_Empfang.exe', '', SW_HIDE, ewWaitUntilTerminated, R);
Sleep(500);
end;
function PrepareToInstall(var NeedsRestart: Boolean): String;
var
R: Integer;
begin
Result := '';
Exec('taskkill.exe', '/F /IM aza_desktop.exe', '', SW_HIDE, ewWaitUntilTerminated, R);
Exec('taskkill.exe', '/F /IM AZA_EmpfangShell.exe', '', SW_HIDE, ewWaitUntilTerminated, R);
Sleep(500);
end;
procedure CurStepChanged(CurStep: TSetupStep);
var
R: Integer;
AppPath, ExePath, Cmd: String;
begin
if CurStep = ssPostInstall then
begin
AppPath := ExpandConstant('{app}');
ExePath := AddBackslash(AppPath) + 'aza_desktop.exe';
if WizardIsComponentSelected('office') and FileExists(ExePath) then
begin
Exec('netsh.exe', 'advfirewall firewall delete rule name="AZA Desktop - Lokale Kommunikation"', '', SW_HIDE, ewWaitUntilTerminated, R);
Sleep(200);
Cmd := 'advfirewall firewall add rule name="AZA Desktop - Lokale Kommunikation" dir=in action=allow program="' + ExePath + '" localport=8000 protocol=tcp remoteip=127.0.0.1';
if not Exec('netsh.exe', Cmd, '', SW_HIDE, ewWaitUntilTerminated, R) or (R <> 0) then
Log('Firewall-Regel konnte nicht angelegt werden (Code: ' + IntToStr(R) + ')');
end;
end;
end;
procedure CurUninstallStepChanged(CurUninstallStep: TUninstallStep);
var
UserDataDir: String;
begin
if CurUninstallStep = usPostUninstall then
begin
UserDataDir := ExpandConstant('{userappdata}\AZA Desktop');
Log('AZA deinstalliert. Persoenliche Daten bleiben unter "' + UserDataDir + '" erhalten (kein automatisches Loeschen).');
end;
end;

View File

@@ -0,0 +1,183 @@
# release.ps1 Verbindlicher Single-Entry-Point fuer den lokalen AZA Release-Build
#
# Reihenfolge:
# 1. build_exe.ps1 (PyInstaller + Pre-Build-Validierung)
# 2. build_installer.ps1 (Inno Setup Installer)
# 3. build_release_manifest.ps1 (version.json aus aza_version.py)
# 4. Post-Build-Verifizierung
# 5. Abschlussmeldung mit Upload-Befehlen
#
# Verbindliche Release-Artefakte:
# dist\installer\aza_desktop_setup.exe
# release\version.json
$ErrorActionPreference = "Stop"
$projectRoot = $PSScriptRoot
Write-Host ""
Write-Host "=============================================="
Write-Host " AZA Release-Build"
Write-Host "=============================================="
Write-Host ""
# --- Schritt 1: Desktop EXE bauen ---
Write-Host "[1/4] Desktop EXE bauen (build_exe.ps1)..."
Write-Host ""
& (Join-Path $projectRoot "build_exe.ps1")
if ($LASTEXITCODE -ne 0) {
Write-Error "ABBRUCH: build_exe.ps1 fehlgeschlagen."
exit 1
}
Write-Host ""
# --- Schritt 2: Installer bauen ---
Write-Host "[2/4] Installer bauen (build_installer.ps1)..."
Write-Host ""
& (Join-Path $projectRoot "build_installer.ps1")
if ($LASTEXITCODE -ne 0) {
Write-Error "ABBRUCH: build_installer.ps1 fehlgeschlagen."
exit 1
}
Write-Host ""
# --- Schritt 3: Release-Manifest aktualisieren ---
Write-Host "[3/4] Release-Manifest aktualisieren (build_release_manifest.ps1)..."
Write-Host ""
& (Join-Path $projectRoot "build_release_manifest.ps1")
if ($LASTEXITCODE -ne 0) {
Write-Error "ABBRUCH: build_release_manifest.ps1 fehlgeschlagen."
exit 1
}
Write-Host ""
# --- Schritt 4: Post-Build-Verifizierung ---
Write-Host "[4/4] Post-Build-Verifizierung..."
Write-Host ""
$internalDir = Join-Path $projectRoot "dist\aza_desktop\_internal"
$installerPath = Join-Path $projectRoot "dist\installer\aza_desktop_setup.exe"
$manifestPath = Join-Path $projectRoot "release\version.json"
$errors = @()
# 4a) backend_url.txt pruefen
$urlFile = Join-Path $internalDir "backend_url.txt"
if (-not (Test-Path $urlFile)) {
$errors += "backend_url.txt fehlt in _internal"
} else {
$urlContent = (Get-Content $urlFile -Raw).Trim()
if (-not $urlContent) {
$errors += "backend_url.txt in _internal ist leer"
} elseif ($urlContent -match "127\.0\.0\.1|localhost|0\.0\.0\.0") {
$errors += "backend_url.txt in _internal enthaelt lokale Adresse: $urlContent"
} else {
Write-Host " backend_url.txt OK: $urlContent"
}
}
# 4b) backend_token.txt pruefen
$tokenFile = Join-Path $internalDir "backend_token.txt"
if (-not (Test-Path $tokenFile)) {
$errors += "backend_token.txt fehlt in _internal"
} else {
$tokenContent = (Get-Content $tokenFile -Raw).Trim()
if (-not $tokenContent) {
$errors += "backend_token.txt in _internal ist leer"
} elseif ($tokenContent -match "CHANGE_ME") {
$errors += "backend_token.txt in _internal enthaelt Platzhalter"
} else {
Write-Host " backend_token.txt OK (Token vorhanden)"
}
}
# 4c) Verbotene Dateien duerfen NICHT in _internal liegen
$forbidden = @(".env", "license_url.txt")
foreach ($f in $forbidden) {
$fp = Join-Path $internalDir $f
if (Test-Path $fp) {
$errors += "VERBOTEN: $f liegt in _internal (darf nicht im Installer sein)"
}
}
$forbiddenDb = Join-Path $internalDir "data\stripe_webhook.sqlite"
if (Test-Path $forbiddenDb) {
$errors += "VERBOTEN: data\stripe_webhook.sqlite liegt in _internal (darf nicht im Installer sein)"
}
if ($errors.Count -eq 0) {
Write-Host " Keine verbotenen Dateien in _internal"
}
# 4f) Empfang-Web-Huelle (Shell-EXE) muss mit dem Installer gebundelt werden
$shellExeDist = Join-Path $projectRoot "dist\aza_desktop\AZA_EmpfangShell.exe"
if (-not (Test-Path $shellExeDist)) {
$errors += "AZA_EmpfangShell.exe fehlt in dist\aza_desktop (wird fuer die Empfang-Web-Huelle benoetigt)"
} else {
Write-Host " AZA_EmpfangShell.exe OK (neben aza_desktop.exe)"
}
# 4d) Installer existiert und hat Groesse > 0
if (-not (Test-Path $installerPath)) {
$errors += "Installer nicht gefunden: $installerPath"
} else {
$fileInfo = Get-Item $installerPath
if ($fileInfo.Length -eq 0) {
$errors += "Installer hat Groesse 0: $installerPath"
}
}
# 4e) version.json existiert und Version stimmt mit aza_version.py ueberein
if (-not (Test-Path $manifestPath)) {
$errors += "release\version.json nicht gefunden"
} else {
try {
$manifest = Get-Content $manifestPath -Raw | ConvertFrom-Json
$manifestVersion = $manifest.version
$azaContent = Get-Content (Join-Path $projectRoot "aza_version.py") -Raw
if ($azaContent -match 'APP_VERSION\s*=\s*"([^"]+)"') {
$codeVersion = $matches[1].Trim()
if ($manifestVersion -ne $codeVersion) {
$errors += "version.json Version ($manifestVersion) stimmt nicht mit aza_version.py ($codeVersion) ueberein"
} else {
Write-Host " version.json OK: Version $manifestVersion"
}
}
$dlUrl = $manifest.download_url
if ($dlUrl -and ($dlUrl -match "127\.0\.0\.1|localhost")) {
$errors += "version.json download_url enthaelt localhost: $dlUrl"
}
} catch {
$errors += "version.json konnte nicht gelesen werden: $_"
}
}
# Fehler auswerten
if ($errors.Count -gt 0) {
Write-Host ""
Write-Host "=============================================="
Write-Host " RELEASE-VERIFIZIERUNG FEHLGESCHLAGEN"
Write-Host "=============================================="
foreach ($e in $errors) {
Write-Host " FEHLER: $e" -ForegroundColor Red
}
Write-Host ""
Write-Error "Release-Build nicht sauber. Bitte Fehler beheben und erneut ausfuehren."
exit 1
}
# --- Abschlussmeldung ---
$instInfo = Get-Item $installerPath
$sizeMB = [math]::Round($instInfo.Length / 1MB, 2)
$sha256 = (Get-FileHash -Path $installerPath -Algorithm SHA256).Hash
Write-Host ""
Write-Host "=============================================="
Write-Host " RELEASE BEREIT FUER UPLOAD"
Write-Host "=============================================="
Write-Host ""
Write-Host " Installer: $installerPath"
Write-Host " Groesse: $sizeMB MB"
Write-Host " SHA256: $sha256"
Write-Host " Manifest: $manifestPath"
Write-Host ""
Write-Host " Upload-Befehle:"
Write-Host " scp `"$installerPath`" root@5.78.100.228:/root/aza-app/release/aza_desktop_setup.exe"
Write-Host " scp `"$manifestPath`" root@5.78.100.228:/root/aza-app/release/version.json"
Write-Host ""