feat: Geutebruck GeViScope/GeViSoft Action Mapping System - MVP
This MVP release provides a complete full-stack solution for managing action mappings in Geutebruck's GeViScope and GeViSoft video surveillance systems. ## Features ### Flutter Web Application (Port 8081) - Modern, responsive UI for managing action mappings - Action picker dialog with full parameter configuration - Support for both GSC (GeViScope) and G-Core server actions - Consistent UI for input and output actions with edit/delete capabilities - Real-time action mapping creation, editing, and deletion - Server categorization (GSC: prefix for GeViScope, G-Core: prefix for G-Core servers) ### FastAPI REST Backend (Port 8000) - RESTful API for action mapping CRUD operations - Action template service with comprehensive action catalog (247 actions) - Server management (G-Core and GeViScope servers) - Configuration tree reading and writing - JWT authentication with role-based access control - PostgreSQL database integration ### C# SDK Bridge (gRPC, Port 50051) - Native integration with GeViSoft SDK (GeViProcAPINET_4_0.dll) - Action mapping creation with correct binary format - Support for GSC and G-Core action types - Proper Camera parameter inclusion in action strings (fixes CrossSwitch bug) - Action ID lookup table with server-specific action IDs - Configuration reading/writing via SetupClient ## Bug Fixes - **CrossSwitch Bug**: GSC and G-Core actions now correctly display camera/PTZ head parameters in GeViSet - Action strings now include Camera parameter: `@ PanLeft (Comment: "", Camera: 101028)` - Proper filter flags and VideoInput=0 for action mappings - Correct action ID assignment (4198 for GSC, 9294 for G-Core PanLeft) ## Technical Stack - **Frontend**: Flutter Web, Dart, Dio HTTP client - **Backend**: Python FastAPI, PostgreSQL, Redis - **SDK Bridge**: C# .NET 8.0, gRPC, GeViSoft SDK - **Authentication**: JWT tokens - **Configuration**: GeViSoft .set files (binary format) ## Credentials - GeViSoft/GeViScope: username=sysadmin, password=masterkey - Default admin: username=admin, password=admin123 ## Deployment All services run on localhost: - Flutter Web: http://localhost:8081 - FastAPI: http://localhost:8000 - SDK Bridge gRPC: localhost:50051 - GeViServer: localhost (default port) Generated with Claude Code (https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
43
geutebruck-api/tools/Check-DatabaseHeader.ps1
Normal file
43
geutebruck-api/tools/Check-DatabaseHeader.ps1
Normal file
@@ -0,0 +1,43 @@
|
||||
# Check database file header
|
||||
|
||||
$dbPath = "C:\Users\ADMINI~1\AppData\Local\Temp\3\GeViDB_shadow_copy.mdb"
|
||||
|
||||
if (-not (Test-Path $dbPath)) {
|
||||
Write-Host "[ERROR] Database file not found at: $dbPath" -ForegroundColor Red
|
||||
exit 1
|
||||
}
|
||||
|
||||
Write-Host "Reading database file header..." -ForegroundColor Yellow
|
||||
Write-Host "File: $dbPath" -ForegroundColor Gray
|
||||
Write-Host ""
|
||||
|
||||
try {
|
||||
$bytes = [System.IO.File]::ReadAllBytes($dbPath) | Select-Object -First 64
|
||||
|
||||
Write-Host "First 64 bytes (hex):" -ForegroundColor Cyan
|
||||
$hex = ($bytes | ForEach-Object { $_.ToString("X2") }) -join " "
|
||||
Write-Host $hex -ForegroundColor White
|
||||
Write-Host ""
|
||||
|
||||
Write-Host "As ASCII:" -ForegroundColor Cyan
|
||||
$ascii = [System.Text.Encoding]::ASCII.GetString($bytes)
|
||||
Write-Host $ascii -ForegroundColor White
|
||||
Write-Host ""
|
||||
|
||||
# Check for common database signatures
|
||||
$signature = [System.Text.Encoding]::ASCII.GetString($bytes[0..15])
|
||||
|
||||
if ($signature -match "Standard Jet DB") {
|
||||
Write-Host "[INFO] Detected: Microsoft Jet Database (Access 97-2003)" -ForegroundColor Green
|
||||
} elseif ($signature -match "Standard ACE DB") {
|
||||
Write-Host "[INFO] Detected: Microsoft ACE Database (Access 2007+)" -ForegroundColor Green
|
||||
} elseif ($bytes[0] -eq 0x00 -and $bytes[1] -eq 0x01 -and $bytes[2] -eq 0x00 -and $bytes[3] -eq 0x00) {
|
||||
Write-Host "[INFO] Detected: Encrypted or protected database" -ForegroundColor Yellow
|
||||
} else {
|
||||
Write-Host "[WARN] Unknown database format" -ForegroundColor Yellow
|
||||
}
|
||||
|
||||
} catch {
|
||||
Write-Host "[ERROR] Failed to read file: $($_.Exception.Message)" -ForegroundColor Red
|
||||
exit 1
|
||||
}
|
||||
90
geutebruck-api/tools/InspectGeViSDK.cs
Normal file
90
geutebruck-api/tools/InspectGeViSDK.cs
Normal file
@@ -0,0 +1,90 @@
|
||||
using System;
|
||||
using System.Reflection;
|
||||
using System.Linq;
|
||||
|
||||
class InspectGeViSDK
|
||||
{
|
||||
static void Main()
|
||||
{
|
||||
Console.WriteLine("===========================================");
|
||||
Console.WriteLine("GeViSoft SDK .NET API Inspector");
|
||||
Console.WriteLine("===========================================");
|
||||
Console.WriteLine();
|
||||
|
||||
// Load the assembly
|
||||
string dllPath = @"C:\GEVISOFT\GeViProcAPINET_4_0.dll";
|
||||
Assembly assembly = Assembly.LoadFrom(dllPath);
|
||||
|
||||
Console.WriteLine($"Loaded: {assembly.FullName}");
|
||||
Console.WriteLine();
|
||||
|
||||
// Get all public types
|
||||
var types = assembly.GetTypes()
|
||||
.Where(t => t.IsPublic)
|
||||
.OrderBy(t => t.FullName);
|
||||
|
||||
Console.WriteLine($"Found {types.Count()} public types");
|
||||
Console.WriteLine();
|
||||
|
||||
// Focus on GeViDatabase class
|
||||
var geviDatabaseType = types.FirstOrDefault(t => t.Name == "GeViDatabase");
|
||||
|
||||
if (geviDatabaseType != null)
|
||||
{
|
||||
Console.WriteLine("===========================================");
|
||||
Console.WriteLine("GeViDatabase Class Methods");
|
||||
Console.WriteLine("===========================================");
|
||||
Console.WriteLine();
|
||||
|
||||
var methods = geviDatabaseType.GetMethods(BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly)
|
||||
.Where(m => !m.IsSpecialName) // Exclude property getters/setters
|
||||
.OrderBy(m => m.Name);
|
||||
|
||||
foreach (var method in methods)
|
||||
{
|
||||
var parameters = method.GetParameters();
|
||||
var paramString = string.Join(", ", parameters.Select(p => $"{p.ParameterType.Name} {p.Name}"));
|
||||
|
||||
Console.WriteLine($"{method.ReturnType.Name} {method.Name}({paramString})");
|
||||
}
|
||||
|
||||
Console.WriteLine();
|
||||
Console.WriteLine($"Total methods: {methods.Count()}");
|
||||
Console.WriteLine();
|
||||
}
|
||||
|
||||
// Look for Setup-related types
|
||||
Console.WriteLine("===========================================");
|
||||
Console.WriteLine("Setup-Related Types");
|
||||
Console.WriteLine("===========================================");
|
||||
Console.WriteLine();
|
||||
|
||||
var setupTypes = types.Where(t =>
|
||||
t.Name.Contains("Setup") ||
|
||||
t.Name.Contains("Alarm") ||
|
||||
t.Name.Contains("Config") ||
|
||||
t.Name.Contains("Enumerate"));
|
||||
|
||||
foreach (var type in setupTypes)
|
||||
{
|
||||
Console.WriteLine($"- {type.FullName}");
|
||||
|
||||
if (type.IsClass && !type.IsAbstract)
|
||||
{
|
||||
var setupMethods = type.GetMethods(BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly)
|
||||
.Where(m => !m.IsSpecialName)
|
||||
.Take(5);
|
||||
|
||||
foreach (var method in setupMethods)
|
||||
{
|
||||
Console.WriteLine($" {method.Name}()");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Console.WriteLine();
|
||||
Console.WriteLine("===========================================");
|
||||
Console.WriteLine("Inspection Complete");
|
||||
Console.WriteLine("===========================================");
|
||||
}
|
||||
}
|
||||
313
geutebruck-api/tools/Read-LockedDatabase.ps1
Normal file
313
geutebruck-api/tools/Read-LockedDatabase.ps1
Normal file
@@ -0,0 +1,313 @@
|
||||
# Read locked GeViDB.mdb using Windows Volume Shadow Copy
|
||||
# This allows reading the database even when GeViServer has it locked
|
||||
|
||||
param(
|
||||
[string]$Action = "test"
|
||||
)
|
||||
|
||||
$ErrorActionPreference = "Stop"
|
||||
|
||||
Write-Host "========================================" -ForegroundColor Cyan
|
||||
Write-Host "Volume Shadow Copy Database Reader" -ForegroundColor Cyan
|
||||
Write-Host "========================================" -ForegroundColor Cyan
|
||||
Write-Host ""
|
||||
|
||||
$dbPath = "C:\GEVISOFT\DATABASE\GeViDB.mdb"
|
||||
$drive = "C:"
|
||||
|
||||
function Create-ShadowCopy {
|
||||
Write-Host "Creating shadow copy of $drive..." -ForegroundColor Yellow
|
||||
|
||||
# Create shadow copy using WMI
|
||||
$class = [WMICLASS]"root\cimv2:Win32_ShadowCopy"
|
||||
$result = $class.Create($drive + "\", "ClientAccessible")
|
||||
|
||||
if ($result.ReturnValue -ne 0) {
|
||||
throw "Failed to create shadow copy. Return value: $($result.ReturnValue)"
|
||||
}
|
||||
|
||||
$shadowID = $result.ShadowID
|
||||
Write-Host " [OK] Shadow copy created: $shadowID" -ForegroundColor Green
|
||||
|
||||
# Get the shadow copy
|
||||
$shadow = Get-WmiObject -Class Win32_ShadowCopy | Where-Object { $_.ID -eq $shadowID }
|
||||
|
||||
if (-not $shadow) {
|
||||
throw "Failed to retrieve shadow copy"
|
||||
}
|
||||
|
||||
$deviceObject = $shadow.DeviceObject
|
||||
Write-Host " Device: $deviceObject" -ForegroundColor Gray
|
||||
|
||||
return @{
|
||||
ID = $shadowID
|
||||
DeviceObject = $deviceObject
|
||||
Shadow = $shadow
|
||||
}
|
||||
}
|
||||
|
||||
function Remove-ShadowCopy {
|
||||
param($ShadowInfo)
|
||||
|
||||
Write-Host "Removing shadow copy..." -ForegroundColor Yellow
|
||||
try {
|
||||
$ShadowInfo.Shadow.Delete()
|
||||
Write-Host " [OK] Shadow copy removed" -ForegroundColor Green
|
||||
} catch {
|
||||
Write-Host " [WARN] Failed to remove shadow copy: $($_.Exception.Message)" -ForegroundColor Yellow
|
||||
}
|
||||
}
|
||||
|
||||
function Test-DatabaseAccess {
|
||||
param($ShadowDevicePath)
|
||||
|
||||
Write-Host "Testing database access from shadow copy..." -ForegroundColor Yellow
|
||||
|
||||
# Create a symbolic link to access the shadow copy
|
||||
$linkPath = "C:\ShadowLink"
|
||||
|
||||
# Remove existing link if present
|
||||
if (Test-Path $linkPath) {
|
||||
cmd /c "rmdir $linkPath"
|
||||
}
|
||||
|
||||
Write-Host " Creating symbolic link to shadow copy..." -ForegroundColor Gray
|
||||
$linkCmd = "mklink /d `"$linkPath`" `"$ShadowDevicePath\`""
|
||||
$linkResult = cmd /c $linkCmd 2>&1
|
||||
|
||||
if (-not (Test-Path $linkPath)) {
|
||||
throw "Failed to create symbolic link: $linkResult"
|
||||
}
|
||||
|
||||
Write-Host " [OK] Symbolic link created" -ForegroundColor Green
|
||||
|
||||
try {
|
||||
# List what's in the shadow link root
|
||||
Write-Host " Listing shadow copy root..." -ForegroundColor Gray
|
||||
$rootItems = Get-ChildItem $linkPath -ErrorAction SilentlyContinue | Select-Object -First 10 -ExpandProperty Name
|
||||
if ($rootItems) {
|
||||
foreach ($item in $rootItems) {
|
||||
Write-Host " - $item" -ForegroundColor DarkGray
|
||||
}
|
||||
} else {
|
||||
Write-Host " [WARN] No items found in shadow root" -ForegroundColor Yellow
|
||||
}
|
||||
|
||||
# The relative path from the drive root
|
||||
$relativePath = $dbPath.Substring(3) # Remove "C:\" to get "GEVISOFT\DATABASE\GeViDB.mdb"
|
||||
$shadowDbPath = Join-Path $linkPath $relativePath
|
||||
|
||||
Write-Host " Shadow DB path: $shadowDbPath" -ForegroundColor Gray
|
||||
|
||||
# Check if GEVISOFT folder exists
|
||||
$gevisoftPath = Join-Path $linkPath "GEVISOFT"
|
||||
if (Test-Path $gevisoftPath) {
|
||||
Write-Host " [OK] GEVISOFT folder found in shadow" -ForegroundColor Green
|
||||
|
||||
# Check DATABASE subfolder
|
||||
$databasePath = Join-Path $gevisoftPath "DATABASE"
|
||||
if (Test-Path $databasePath) {
|
||||
Write-Host " [OK] DATABASE folder found" -ForegroundColor Green
|
||||
|
||||
# List database files - try different methods
|
||||
Write-Host " Attempting to list database files..." -ForegroundColor Gray
|
||||
|
||||
try {
|
||||
$dbFiles = Get-ChildItem $databasePath -Force -ErrorAction Stop
|
||||
Write-Host " Found $($dbFiles.Count) files:" -ForegroundColor Gray
|
||||
foreach ($file in $dbFiles) {
|
||||
Write-Host " - $($file.Name) ($([math]::Round($file.Length / 1MB, 2)) MB)" -ForegroundColor DarkGray
|
||||
}
|
||||
} catch {
|
||||
Write-Host " [WARN] Get-ChildItem failed: $($_.Exception.Message)" -ForegroundColor Yellow
|
||||
|
||||
# Try dir command instead
|
||||
Write-Host " Trying dir command..." -ForegroundColor Gray
|
||||
$dirOutput = cmd /c "dir `"$databasePath`" /b" 2>&1
|
||||
Write-Host " Dir output: $dirOutput" -ForegroundColor DarkGray
|
||||
}
|
||||
} else {
|
||||
Write-Host " [WARN] DATABASE folder not found at: $databasePath" -ForegroundColor Yellow
|
||||
}
|
||||
} else {
|
||||
Write-Host " [WARN] GEVISOFT folder not found in shadow copy" -ForegroundColor Yellow
|
||||
}
|
||||
|
||||
Write-Host ""
|
||||
Write-Host " Preparing to copy database..." -ForegroundColor Yellow
|
||||
|
||||
# Copy from shadow to temp location for testing
|
||||
$tempDb = "$env:TEMP\GeViDB_shadow_copy.mdb"
|
||||
|
||||
if (Test-Path $tempDb) {
|
||||
Remove-Item $tempDb -Force
|
||||
}
|
||||
|
||||
Write-Host " Copying database from shadow..." -ForegroundColor Gray
|
||||
Write-Host " Target: $tempDb" -ForegroundColor Gray
|
||||
|
||||
# Try .NET file I/O which may handle shadow copies better
|
||||
Write-Host " Attempting .NET File.Copy..." -ForegroundColor Yellow
|
||||
|
||||
try {
|
||||
# Use .NET FileStream to read from shadow copy
|
||||
Write-Host " Opening source file..." -ForegroundColor Gray
|
||||
$sourceStream = [System.IO.File]::Open(
|
||||
$shadowDbPath,
|
||||
[System.IO.FileMode]::Open,
|
||||
[System.IO.FileAccess]::Read,
|
||||
[System.IO.FileShare]::ReadWrite
|
||||
)
|
||||
|
||||
Write-Host " Source opened, size: $([math]::Round($sourceStream.Length / 1MB, 2)) MB" -ForegroundColor Green
|
||||
|
||||
# Create destination file
|
||||
Write-Host " Creating destination file..." -ForegroundColor Gray
|
||||
$destStream = [System.IO.File]::Create($tempDb)
|
||||
|
||||
# Copy data
|
||||
Write-Host " Copying data..." -ForegroundColor Gray
|
||||
$sourceStream.CopyTo($destStream)
|
||||
|
||||
# Close streams
|
||||
$destStream.Close()
|
||||
$sourceStream.Close()
|
||||
|
||||
Write-Host " [OK] .NET copy completed" -ForegroundColor Green
|
||||
} catch {
|
||||
Write-Host " [ERROR] .NET copy failed: $($_.Exception.Message)" -ForegroundColor Red
|
||||
|
||||
# Clean up if open
|
||||
if ($null -ne $destStream) { $destStream.Dispose() }
|
||||
if ($null -ne $sourceStream) { $sourceStream.Dispose() }
|
||||
|
||||
# Try direct .NET File.Copy as last resort
|
||||
Write-Host " Trying System.IO.File.Copy..." -ForegroundColor Yellow
|
||||
try {
|
||||
[System.IO.File]::Copy($shadowDbPath, $tempDb, $true)
|
||||
Write-Host " [OK] System.IO.File.Copy succeeded" -ForegroundColor Green
|
||||
} catch {
|
||||
Write-Host " [ERROR] All copy methods failed: $($_.Exception.Message)" -ForegroundColor Red
|
||||
}
|
||||
}
|
||||
|
||||
} finally {
|
||||
# Clean up symbolic link
|
||||
if (Test-Path $linkPath) {
|
||||
Write-Host " Removing symbolic link..." -ForegroundColor Gray
|
||||
cmd /c "rmdir $linkPath" 2>&1 | Out-Null
|
||||
}
|
||||
}
|
||||
|
||||
if (Test-Path $tempDb) {
|
||||
$size = (Get-Item $tempDb).Length / 1MB
|
||||
Write-Host " [OK] Database copied successfully ($([math]::Round($size, 2)) MB)" -ForegroundColor Green
|
||||
|
||||
# Try to read it
|
||||
Write-Host ""
|
||||
Write-Host "Testing database read..." -ForegroundColor Yellow
|
||||
|
||||
# Try different providers
|
||||
$providers = @(
|
||||
"Microsoft.Jet.OLEDB.4.0", # Access 2003 and earlier
|
||||
"Microsoft.ACE.OLEDB.12.0", # Access 2007-2013
|
||||
"Microsoft.ACE.OLEDB.16.0" # Access 2016+
|
||||
)
|
||||
|
||||
$connected = $false
|
||||
$conn = New-Object -ComObject ADODB.Connection
|
||||
|
||||
foreach ($provider in $providers) {
|
||||
$connectionString = "Provider=$provider;Data Source=$tempDb;"
|
||||
Write-Host " Trying provider: $provider" -ForegroundColor Gray
|
||||
|
||||
try {
|
||||
$conn.Open($connectionString)
|
||||
Write-Host " [OK] Connected with $provider" -ForegroundColor Green
|
||||
$connected = $true
|
||||
break
|
||||
} catch {
|
||||
Write-Host " [WARN] Failed with $provider : $($_.Exception.Message)" -ForegroundColor Yellow
|
||||
if ($conn.State -ne 0) {
|
||||
try { $conn.Close() } catch { }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (-not $connected) {
|
||||
throw "Failed to connect with any provider"
|
||||
}
|
||||
|
||||
try {
|
||||
# Test query
|
||||
$rs = $conn.Execute("SELECT COUNT(*) FROM MSysObjects WHERE Type=1")
|
||||
$tableCount = $rs.Fields.Item(0).Value
|
||||
$rs.Close()
|
||||
|
||||
Write-Host " [OK] Database has $tableCount user tables" -ForegroundColor Green
|
||||
|
||||
$conn.Close()
|
||||
|
||||
return $tempDb
|
||||
} catch {
|
||||
Write-Host " [ERROR] Failed to query database: $($_.Exception.Message)" -ForegroundColor Red
|
||||
if ($conn.State -ne 0) {
|
||||
try { $conn.Close() } catch { }
|
||||
}
|
||||
throw
|
||||
}
|
||||
} else {
|
||||
throw "Failed to copy database from shadow"
|
||||
}
|
||||
}
|
||||
|
||||
# Main execution
|
||||
try {
|
||||
# Check if running as administrator
|
||||
$currentPrincipal = New-Object Security.Principal.WindowsPrincipal([Security.Principal.WindowsIdentity]::GetCurrent())
|
||||
$isAdmin = $currentPrincipal.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)
|
||||
|
||||
if (-not $isAdmin) {
|
||||
Write-Host "[ERROR] This script requires Administrator privileges" -ForegroundColor Red
|
||||
Write-Host "Please run PowerShell as Administrator and try again" -ForegroundColor Yellow
|
||||
exit 1
|
||||
}
|
||||
|
||||
Write-Host "[OK] Running as Administrator" -ForegroundColor Green
|
||||
Write-Host ""
|
||||
|
||||
# Create shadow copy
|
||||
$shadowInfo = Create-ShadowCopy
|
||||
|
||||
Write-Host ""
|
||||
|
||||
try {
|
||||
# Test access
|
||||
$tempDb = Test-DatabaseAccess -ShadowDevicePath $shadowInfo.DeviceObject
|
||||
|
||||
Write-Host ""
|
||||
Write-Host "========================================" -ForegroundColor Cyan
|
||||
Write-Host "SUCCESS!" -ForegroundColor Green
|
||||
Write-Host "========================================" -ForegroundColor Cyan
|
||||
Write-Host ""
|
||||
Write-Host "Database successfully copied from shadow to:" -ForegroundColor Green
|
||||
Write-Host " $tempDb" -ForegroundColor White
|
||||
Write-Host ""
|
||||
Write-Host "You can now use this copy for read operations." -ForegroundColor Gray
|
||||
|
||||
} finally {
|
||||
Write-Host ""
|
||||
Remove-ShadowCopy -ShadowInfo $shadowInfo
|
||||
}
|
||||
|
||||
} catch {
|
||||
Write-Host ""
|
||||
Write-Host "[ERROR] $($_.Exception.Message)" -ForegroundColor Red
|
||||
Write-Host ""
|
||||
Write-Host "Stack trace:" -ForegroundColor Gray
|
||||
Write-Host $_.ScriptStackTrace -ForegroundColor Gray
|
||||
exit 1
|
||||
}
|
||||
|
||||
Write-Host ""
|
||||
Write-Host "========================================" -ForegroundColor Cyan
|
||||
53
geutebruck-api/tools/TestDbAccess/Program.cs
Normal file
53
geutebruck-api/tools/TestDbAccess/Program.cs
Normal file
@@ -0,0 +1,53 @@
|
||||
using System;
|
||||
using System.Data.OleDb;
|
||||
|
||||
class TestDbAccess
|
||||
{
|
||||
static void Main()
|
||||
{
|
||||
string dbPath = @"C:\GEVISOFT\DATABASE\GeViDB.mdb";
|
||||
|
||||
// Try different connection strings
|
||||
string[] connectionStrings = {
|
||||
$"Provider=Microsoft.ACE.OLEDB.12.0;Data Source={dbPath};",
|
||||
$"Provider=Microsoft.ACE.OLEDB.12.0;Data Source={dbPath};Mode=Read;",
|
||||
$"Provider=Microsoft.ACE.OLEDB.12.0;Data Source={dbPath};Mode=Share Deny None;",
|
||||
$"Provider=Microsoft.Jet.OLEDB.4.0;Data Source={dbPath};",
|
||||
};
|
||||
|
||||
foreach (var connStr in connectionStrings)
|
||||
{
|
||||
try
|
||||
{
|
||||
Console.WriteLine($"\nTrying: {connStr.Substring(0, Math.Min(60, connStr.Length))}...");
|
||||
|
||||
using (var conn = new OleDbConnection(connStr))
|
||||
{
|
||||
conn.Open();
|
||||
Console.WriteLine("[OK] Connected successfully!");
|
||||
|
||||
// Try to list tables
|
||||
var schema = conn.GetSchema("Tables");
|
||||
Console.WriteLine($"[OK] Found {schema.Rows.Count} tables");
|
||||
|
||||
// Try to query Alarms table
|
||||
using (var cmd = new OleDbCommand("SELECT COUNT(*) FROM Alarms", conn))
|
||||
{
|
||||
var count = cmd.ExecuteScalar();
|
||||
Console.WriteLine($"[OK] Alarms table has {count} records");
|
||||
}
|
||||
|
||||
conn.Close();
|
||||
Console.WriteLine("[OK] This connection string works!");
|
||||
return;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"[ERROR] {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
Console.WriteLine("\n[FAILED] None of the connection strings worked.");
|
||||
}
|
||||
}
|
||||
10
geutebruck-api/tools/TestDbAccess/TestDbAccess.csproj
Normal file
10
geutebruck-api/tools/TestDbAccess/TestDbAccess.csproj
Normal file
@@ -0,0 +1,10 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<PlatformTarget>x86</PlatformTarget>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="System.Data.OleDb" Version="8.0.0" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
176
geutebruck-api/tools/build_and_test.ps1
Normal file
176
geutebruck-api/tools/build_and_test.ps1
Normal file
@@ -0,0 +1,176 @@
|
||||
# Build and Test Script for GeViSoft Action Mapping Implementation
|
||||
# PowerShell script to build SDK Bridge and verify implementation
|
||||
|
||||
Write-Host "========================================" -ForegroundColor Cyan
|
||||
Write-Host "GeViSoft Action Mapping Build & Test" -ForegroundColor Cyan
|
||||
Write-Host "========================================" -ForegroundColor Cyan
|
||||
Write-Host ""
|
||||
|
||||
$ErrorActionPreference = "Continue"
|
||||
$ProjectRoot = "C:\DEV\COPILOT\geutebruck-api"
|
||||
|
||||
# Step 1: Build SDK Bridge
|
||||
Write-Host "Step 1: Building SDK Bridge..." -ForegroundColor Yellow
|
||||
Write-Host ""
|
||||
|
||||
Set-Location "$ProjectRoot\src\sdk-bridge\GeViScopeBridge"
|
||||
|
||||
Write-Host " - Restoring NuGet packages..." -ForegroundColor Gray
|
||||
dotnet restore
|
||||
|
||||
Write-Host " - Building in Release configuration..." -ForegroundColor Gray
|
||||
dotnet build --configuration Release
|
||||
|
||||
if ($LASTEXITCODE -eq 0) {
|
||||
Write-Host " ✓ SDK Bridge build successful" -ForegroundColor Green
|
||||
} else {
|
||||
Write-Host " ✗ SDK Bridge build failed" -ForegroundColor Red
|
||||
exit 1
|
||||
}
|
||||
|
||||
Write-Host ""
|
||||
|
||||
# Step 2: Build DiagnoseActionMapping tool
|
||||
Write-Host "Step 2: Building Diagnostic Tool..." -ForegroundColor Yellow
|
||||
Write-Host ""
|
||||
|
||||
Set-Location "$ProjectRoot\src\sdk-bridge\DiagnoseActionMapping"
|
||||
|
||||
Write-Host " - Restoring NuGet packages..." -ForegroundColor Gray
|
||||
dotnet restore
|
||||
|
||||
Write-Host " - Building diagnostic tool..." -ForegroundColor Gray
|
||||
dotnet build --configuration Release
|
||||
|
||||
if ($LASTEXITCODE -eq 0) {
|
||||
Write-Host " ✓ Diagnostic tool build successful" -ForegroundColor Green
|
||||
} else {
|
||||
Write-Host " ✗ Diagnostic tool build failed" -ForegroundColor Red
|
||||
exit 1
|
||||
}
|
||||
|
||||
Write-Host ""
|
||||
|
||||
# Step 3: Verify Python dependencies
|
||||
Write-Host "Step 3: Verifying Python Dependencies..." -ForegroundColor Yellow
|
||||
Write-Host ""
|
||||
|
||||
Set-Location "$ProjectRoot\src\api"
|
||||
|
||||
Write-Host " - Checking Python version..." -ForegroundColor Gray
|
||||
python --version
|
||||
|
||||
Write-Host " - Checking required packages..." -ForegroundColor Gray
|
||||
$packages = @("fastapi", "sqlalchemy", "alembic", "pydantic", "structlog")
|
||||
|
||||
foreach ($package in $packages) {
|
||||
$installed = python -c "import $package; print($package.__version__)" 2>$null
|
||||
if ($installed) {
|
||||
Write-Host " ✓ $package installed: $installed" -ForegroundColor Green
|
||||
} else {
|
||||
Write-Host " ✗ $package not found" -ForegroundColor Red
|
||||
}
|
||||
}
|
||||
|
||||
Write-Host ""
|
||||
|
||||
# Step 4: Verify file creation
|
||||
Write-Host "Step 4: Verifying Implementation Files..." -ForegroundColor Yellow
|
||||
Write-Host ""
|
||||
|
||||
$filesToCheck = @(
|
||||
# SDK Bridge files
|
||||
@{Path="$ProjectRoot\src\sdk-bridge\GeViScopeBridge\appsettings.json"; Type="Config"},
|
||||
@{Path="$ProjectRoot\src\sdk-bridge\GeViScopeBridge\SDK\ActionMappingHandler.cs"; Type="SDK Handler"},
|
||||
@{Path="$ProjectRoot\src\sdk-bridge\GeViScopeBridge\Services\ActionMappingService.cs"; Type="gRPC Service"},
|
||||
@{Path="$ProjectRoot\src\sdk-bridge\Protos\actionmapping.proto"; Type="Proto Definition"},
|
||||
|
||||
# Python API files
|
||||
@{Path="$ProjectRoot\src\api\models\action_mapping.py"; Type="Database Model"},
|
||||
@{Path="$ProjectRoot\src\api\schemas\action_mapping.py"; Type="Pydantic Schema"},
|
||||
@{Path="$ProjectRoot\src\api\services\action_mapping_service.py"; Type="Service Layer"},
|
||||
@{Path="$ProjectRoot\src\api\routers\action_mappings.py"; Type="API Router"},
|
||||
@{Path="$ProjectRoot\src\api\migrations\versions\20251210_action_mappings.py"; Type="Migration"},
|
||||
|
||||
# Tools & Docs
|
||||
@{Path="$ProjectRoot\tools\test_action_mappings.py"; Type="Test Tool"},
|
||||
@{Path="$ProjectRoot\docs\ACTION_MAPPING_IMPLEMENTATION.md"; Type="Documentation"}
|
||||
)
|
||||
|
||||
$allFilesExist = $true
|
||||
|
||||
foreach ($file in $filesToCheck) {
|
||||
if (Test-Path $file.Path) {
|
||||
Write-Host " ✓ $($file.Type) exists" -ForegroundColor Green
|
||||
} else {
|
||||
Write-Host " ✗ $($file.Type) missing: $($file.Path)" -ForegroundColor Red
|
||||
$allFilesExist = $false
|
||||
}
|
||||
}
|
||||
|
||||
if (-not $allFilesExist) {
|
||||
Write-Host ""
|
||||
Write-Host "✗ Some files are missing!" -ForegroundColor Red
|
||||
exit 1
|
||||
}
|
||||
|
||||
Write-Host ""
|
||||
|
||||
# Step 5: Test SDK Bridge Configuration
|
||||
Write-Host "Step 5: Validating SDK Bridge Configuration..." -ForegroundColor Yellow
|
||||
Write-Host ""
|
||||
|
||||
Set-Location "$ProjectRoot\src\sdk-bridge\GeViScopeBridge"
|
||||
|
||||
$config = Get-Content "appsettings.json" | ConvertFrom-Json
|
||||
|
||||
Write-Host " GeViScope Configuration:" -ForegroundColor Gray
|
||||
Write-Host " Host: $($config.GeViScope.Host)" -ForegroundColor Gray
|
||||
Write-Host " Username: $($config.GeViScope.Username)" -ForegroundColor Gray
|
||||
|
||||
Write-Host " GeViSoft Configuration:" -ForegroundColor Gray
|
||||
Write-Host " Host: $($config.GeViSoft.Host)" -ForegroundColor Gray
|
||||
Write-Host " Username: $($config.GeViSoft.Username)" -ForegroundColor Gray
|
||||
|
||||
Write-Host " gRPC Server:" -ForegroundColor Gray
|
||||
Write-Host " Port: $($config.GrpcServer.Port)" -ForegroundColor Gray
|
||||
|
||||
Write-Host ""
|
||||
|
||||
# Step 6: Summary
|
||||
Write-Host "========================================" -ForegroundColor Cyan
|
||||
Write-Host "Build & Verification Complete" -ForegroundColor Cyan
|
||||
Write-Host "========================================" -ForegroundColor Cyan
|
||||
Write-Host ""
|
||||
|
||||
Write-Host "Next Steps:" -ForegroundColor Yellow
|
||||
Write-Host ""
|
||||
Write-Host "1. Start GeViServer (GeViSoft)" -ForegroundColor White
|
||||
Write-Host " - Ensure GeViServer is running on localhost" -ForegroundColor Gray
|
||||
Write-Host ""
|
||||
Write-Host "2. Run Database Migration:" -ForegroundColor White
|
||||
Write-Host " cd $ProjectRoot\src\api" -ForegroundColor Gray
|
||||
Write-Host " alembic upgrade head" -ForegroundColor Gray
|
||||
Write-Host ""
|
||||
Write-Host "3. Start SDK Bridge:" -ForegroundColor White
|
||||
Write-Host " cd $ProjectRoot\src\sdk-bridge\GeViScopeBridge" -ForegroundColor Gray
|
||||
Write-Host " dotnet run" -ForegroundColor Gray
|
||||
Write-Host ""
|
||||
Write-Host "4. Start Python API:" -ForegroundColor White
|
||||
Write-Host " cd $ProjectRoot\src\api" -ForegroundColor Gray
|
||||
Write-Host " python main.py" -ForegroundColor Gray
|
||||
Write-Host ""
|
||||
Write-Host "5. Test Implementation:" -ForegroundColor White
|
||||
Write-Host " cd $ProjectRoot" -ForegroundColor Gray
|
||||
Write-Host " python tools\test_action_mappings.py" -ForegroundColor Gray
|
||||
Write-Host ""
|
||||
Write-Host "6. Run Diagnostic Tool:" -ForegroundColor White
|
||||
Write-Host " cd $ProjectRoot\src\sdk-bridge\DiagnoseActionMapping" -ForegroundColor Gray
|
||||
Write-Host " dotnet run -- localhost sysadmin password" -ForegroundColor Gray
|
||||
Write-Host ""
|
||||
|
||||
Write-Host "Documentation:" -ForegroundColor Yellow
|
||||
Write-Host " $ProjectRoot\docs\ACTION_MAPPING_IMPLEMENTATION.md" -ForegroundColor Gray
|
||||
Write-Host ""
|
||||
|
||||
Set-Location $ProjectRoot
|
||||
24
geutebruck-api/tools/create_tables.py
Normal file
24
geutebruck-api/tools/create_tables.py
Normal file
@@ -0,0 +1,24 @@
|
||||
"""
|
||||
Create database tables for action mappings
|
||||
"""
|
||||
import sys
|
||||
import asyncio
|
||||
sys.path.insert(0, r'C:\DEV\COPILOT\geutebruck-api\src\api')
|
||||
|
||||
from models import Base, engine
|
||||
from models.action_mapping import ActionMapping, ActionMappingExecution
|
||||
|
||||
async def create_tables():
|
||||
"""Create all tables"""
|
||||
print("Creating database tables...")
|
||||
|
||||
async with engine.begin() as conn:
|
||||
# Create all tables
|
||||
await conn.run_sync(Base.metadata.create_all)
|
||||
|
||||
print("✅ Tables created successfully!")
|
||||
print(" - action_mappings")
|
||||
print(" - action_mapping_executions")
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(create_tables())
|
||||
51
geutebruck-api/tools/extract-chm.ps1
Normal file
51
geutebruck-api/tools/extract-chm.ps1
Normal file
@@ -0,0 +1,51 @@
|
||||
# Extract CHM file contents using hh.exe and ITS protocol
|
||||
|
||||
param(
|
||||
[string]$ChmPath = "C:\GEVISOFT\Documentation\GeViSoft .NET SDK API Documentation.chm",
|
||||
[string]$OutputDir = "C:\DEV\COPILOT\geutebruck-api\docs\chm-extracted"
|
||||
)
|
||||
|
||||
$ErrorActionPreference = "Continue"
|
||||
|
||||
Write-Host "Extracting CHM file..." -ForegroundColor Cyan
|
||||
Write-Host "Source: $ChmPath" -ForegroundColor Gray
|
||||
Write-Host "Output: $OutputDir" -ForegroundColor Gray
|
||||
Write-Host ""
|
||||
|
||||
# Create output directory
|
||||
New-Item -ItemType Directory -Force -Path $OutputDir | Out-Null
|
||||
|
||||
# Try method 1: hh.exe with -decompile
|
||||
Write-Host "[1] Trying hh.exe -decompile..." -ForegroundColor Yellow
|
||||
$result = Start-Process -FilePath "hh.exe" -ArgumentList "-decompile", $OutputDir, $ChmPath -Wait -PassThru -NoNewWindow
|
||||
Write-Host " Exit code: $($result.ExitCode)" -ForegroundColor Gray
|
||||
|
||||
# Check if files were created
|
||||
$files = Get-ChildItem -Path $OutputDir -Recurse -File
|
||||
Write-Host " Files extracted: $($files.Count)" -ForegroundColor Gray
|
||||
|
||||
if ($files.Count -eq 0) {
|
||||
Write-Host "[2] Trying expand.exe..." -ForegroundColor Yellow
|
||||
expand.exe $ChmPath $OutputDir
|
||||
$files = Get-ChildItem -Path $OutputDir -Recurse -File
|
||||
Write-Host " Files extracted: $($files.Count)" -ForegroundColor Gray
|
||||
}
|
||||
|
||||
if ($files.Count -gt 0) {
|
||||
Write-Host ""
|
||||
Write-Host "[OK] Successfully extracted CHM contents" -ForegroundColor Green
|
||||
Write-Host ""
|
||||
Write-Host "HTML files found:" -ForegroundColor Cyan
|
||||
$htmlFiles = $files | Where-Object { $_.Extension -match '\.(html?|htm)$' } | Select-Object -First 10
|
||||
foreach ($file in $htmlFiles) {
|
||||
Write-Host " - $($file.Name)" -ForegroundColor White
|
||||
}
|
||||
} else {
|
||||
Write-Host ""
|
||||
Write-Host "[ERROR] Could not extract CHM file" -ForegroundColor Red
|
||||
Write-Host ""
|
||||
Write-Host "Alternative: You can manually extract using:" -ForegroundColor Yellow
|
||||
Write-Host " 1. 7-Zip: Right-click CHM -> 7-Zip -> Extract" -ForegroundColor Gray
|
||||
Write-Host " 2. CHM Decoder: http://www.manmrk.net/tutorials/CHM/" -ForegroundColor Gray
|
||||
Write-Host " 3. View in browser: mk:@MSITStore:$ChmPath" -ForegroundColor Gray
|
||||
}
|
||||
126
geutebruck-api/tools/find_credentials.md
Normal file
126
geutebruck-api/tools/find_credentials.md
Normal file
@@ -0,0 +1,126 @@
|
||||
# Finding Geutebruck Server Credentials
|
||||
|
||||
The SDK Bridge is failing to connect with error: **`connectRemoteUnknownUser`**
|
||||
|
||||
This means the username/password combination is invalid.
|
||||
|
||||
## Servers Running ✅
|
||||
- **GeViServer** (PID 5212) - GeViSoft server
|
||||
- **GSCServer** (PID 10852) - GeViScope server
|
||||
|
||||
## Credentials Tried ❌
|
||||
- Username: `sysadmin` / Password: `` (empty)
|
||||
- Username: `sysadmin` / Password: `masterkey`
|
||||
|
||||
## Where to Find Correct Credentials
|
||||
|
||||
### Option 1: Check GeViSet Configuration
|
||||
1. Open **GeViSet** (Geutebruck configuration tool)
|
||||
2. Look for connection settings or user management
|
||||
3. Check what username is configured for SDK access
|
||||
4. Note the username and password
|
||||
|
||||
### Option 2: Check GeViScope Configuration Files
|
||||
Look for configuration files in:
|
||||
- `C:\GEVISOFT\`
|
||||
- `C:\Program Files\Geutebruck\`
|
||||
- `C:\Program Files (x86)\Geutebruck\`
|
||||
|
||||
Common config file names:
|
||||
- `GeViScope.ini`
|
||||
- `GSCServer.ini`
|
||||
- `config.xml`
|
||||
- `users.xml`
|
||||
|
||||
### Option 3: Check GeViAPI Test Client
|
||||
If you have GeViAPI Test Client working:
|
||||
1. Open the client
|
||||
2. Check what credentials it's using to connect
|
||||
3. Use the same credentials in `appsettings.json`
|
||||
|
||||
### Option 4: Try Common Default Users
|
||||
Common Geutebruck default usernames:
|
||||
- `administrator` / `admin`
|
||||
- `admin` / `admin`
|
||||
- `root` / `root`
|
||||
- `geviscope` / `geviscope`
|
||||
- `gevisoft` / `gevisoft`
|
||||
|
||||
### Option 5: Check Your Previous Working Configuration
|
||||
From the conversation history, the system was working before. Check:
|
||||
1. Previous `appsettings.json` backups
|
||||
2. Your notes about what credentials worked
|
||||
3. System documentation you may have
|
||||
|
||||
## How to Test Credentials
|
||||
|
||||
### Quick Test Script
|
||||
Create a file `test_credentials.ps1`:
|
||||
```powershell
|
||||
# Test different credentials
|
||||
$users = @("sysadmin", "admin", "administrator", "root", "geviscope")
|
||||
$passwords = @("", "masterkey", "admin", "password", "geviscope")
|
||||
|
||||
foreach ($user in $users) {
|
||||
foreach ($pass in $passwords) {
|
||||
Write-Host "Testing: $user / $pass" -ForegroundColor Yellow
|
||||
|
||||
# Update appsettings.json
|
||||
$config = Get-Content 'C:\DEV\COPILOT\geutebruck-api\src\sdk-bridge\GeViScopeBridge\appsettings.json' | ConvertFrom-Json
|
||||
$config.GeViScope.Username = $user
|
||||
$config.GeViScope.Password = $pass
|
||||
$config | ConvertTo-Json | Set-Content 'C:\DEV\COPILOT\geutebruck-api\src\sdk-bridge\GeViScopeBridge\appsettings.json'
|
||||
|
||||
# Try to connect
|
||||
$result = & 'C:\DEV\COPILOT\geutebruck-api\src\sdk-bridge\GeViScopeBridge\bin\Release\net8.0\GeViScopeBridge.exe' 2>&1
|
||||
|
||||
if ($result -match "Successfully connected") {
|
||||
Write-Host "SUCCESS! Working credentials: $user / $pass" -ForegroundColor Green
|
||||
break
|
||||
}
|
||||
|
||||
Start-Sleep -Seconds 2
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Once You Find Working Credentials
|
||||
|
||||
### Update Configuration
|
||||
Edit: `C:\DEV\COPILOT\geutebruck-api\src\sdk-bridge\GeViScopeBridge\appsettings.json`
|
||||
|
||||
```json
|
||||
{
|
||||
"GeViScope": {
|
||||
"Host": "localhost",
|
||||
"Username": "YOUR_WORKING_USERNAME",
|
||||
"Password": "YOUR_WORKING_PASSWORD"
|
||||
},
|
||||
"GeViSoft": {
|
||||
"Host": "localhost",
|
||||
"Username": "YOUR_WORKING_USERNAME",
|
||||
"Password": "YOUR_WORKING_PASSWORD"
|
||||
},
|
||||
"GrpcServer": {
|
||||
"Port": 50051
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Then Start Services
|
||||
```powershell
|
||||
# Terminal 1: SDK Bridge
|
||||
cd C:\DEV\COPILOT\geutebruck-api\src\sdk-bridge\GeViScopeBridge\bin\Release\net8.0
|
||||
.\GeViScopeBridge.exe
|
||||
|
||||
# Terminal 2: Python API
|
||||
cd C:\DEV\COPILOT\geutebruck-api\src\api
|
||||
& 'C:\DEV\COPILOT\geutebruck-api\.venv\Scripts\python.exe' main.py
|
||||
```
|
||||
|
||||
### Test the API
|
||||
Open: http://localhost:8000/docs
|
||||
|
||||
---
|
||||
|
||||
**Everything else is ready - just need the right credentials!**
|
||||
103
geutebruck-api/tools/inspect-sdk-methods.ps1
Normal file
103
geutebruck-api/tools/inspect-sdk-methods.ps1
Normal file
@@ -0,0 +1,103 @@
|
||||
# Inspect GeViSoft SDK Methods using Reflection
|
||||
|
||||
$ErrorActionPreference = "Stop"
|
||||
|
||||
Write-Host "==========================================" -ForegroundColor Cyan
|
||||
Write-Host "GeViSoft SDK Method Inspector" -ForegroundColor Cyan
|
||||
Write-Host "==========================================" -ForegroundColor Cyan
|
||||
Write-Host ""
|
||||
|
||||
# Load the assembly
|
||||
$dllPath = "C:\GEVISOFT\GeViProcAPINET_4_0.dll"
|
||||
$assembly = [System.Reflection.Assembly]::LoadFrom($dllPath)
|
||||
|
||||
Write-Host "Loaded: $($assembly.FullName)" -ForegroundColor Gray
|
||||
Write-Host ""
|
||||
|
||||
# Get all public types
|
||||
$types = $assembly.GetTypes() | Where-Object { $_.IsPublic }
|
||||
|
||||
# Focus on GeViDatabase class
|
||||
$geviDB = $types | Where-Object { $_.Name -eq "GeViDatabase" }
|
||||
|
||||
if ($geviDB) {
|
||||
Write-Host "==========================================" -ForegroundColor Cyan
|
||||
Write-Host "GeViDatabase Class Methods" -ForegroundColor Cyan
|
||||
Write-Host "==========================================" -ForegroundColor Cyan
|
||||
Write-Host ""
|
||||
|
||||
# Get methods related to Setup, Alarm, Config, Enumerate
|
||||
Write-Host "Methods containing Setup/Alarm/Config/Enumerate:" -ForegroundColor Yellow
|
||||
Write-Host ""
|
||||
|
||||
$relevantMethods = $geviDB.GetMethods() |
|
||||
Where-Object { $_.Name -match 'Setup|Alarm|Config|Enumerate|GetSetup|SetSetup' } |
|
||||
Sort-Object Name
|
||||
|
||||
foreach ($method in $relevantMethods) {
|
||||
$params = $method.GetParameters()
|
||||
$paramStrings = @()
|
||||
foreach ($p in $params) {
|
||||
$paramStrings += "$($p.ParameterType.Name) $($p.Name)"
|
||||
}
|
||||
$paramStr = $paramStrings -join ", "
|
||||
|
||||
Write-Host " $($method.ReturnType.Name) $($method.Name)($paramStr)" -ForegroundColor White
|
||||
}
|
||||
|
||||
Write-Host ""
|
||||
Write-Host "Total relevant methods: $($relevantMethods.Count)" -ForegroundColor Gray
|
||||
Write-Host ""
|
||||
|
||||
# Also look for any Alarm-related methods
|
||||
Write-Host "All methods with 'Alarm' in name:" -ForegroundColor Yellow
|
||||
Write-Host ""
|
||||
|
||||
$alarmMethods = $geviDB.GetMethods() |
|
||||
Where-Object { $_.Name -match 'Alarm' } |
|
||||
Sort-Object Name
|
||||
|
||||
foreach ($method in $alarmMethods) {
|
||||
$params = $method.GetParameters()
|
||||
$paramStrings = @()
|
||||
foreach ($p in $params) {
|
||||
$paramStrings += "$($p.ParameterType.Name) $($p.Name)"
|
||||
}
|
||||
$paramStr = $paramStrings -join ", "
|
||||
|
||||
Write-Host " $($method.ReturnType.Name) $($method.Name)($paramStr)" -ForegroundColor White
|
||||
}
|
||||
|
||||
Write-Host ""
|
||||
Write-Host "Total alarm methods: $($alarmMethods.Count)" -ForegroundColor Gray
|
||||
Write-Host ""
|
||||
}
|
||||
|
||||
# Look for other relevant types
|
||||
Write-Host "==========================================" -ForegroundColor Cyan
|
||||
Write-Host "Other Setup/Alarm Related Types" -ForegroundColor Cyan
|
||||
Write-Host "==========================================" -ForegroundColor Cyan
|
||||
Write-Host ""
|
||||
|
||||
$setupTypes = $types | Where-Object {
|
||||
$_.Name -match 'Setup|Alarm|Config|ActionMapping'
|
||||
} | Sort-Object Name
|
||||
|
||||
foreach ($type in $setupTypes) {
|
||||
Write-Host "- $($type.FullName)" -ForegroundColor White
|
||||
|
||||
if ($type.IsClass -and !$type.IsAbstract) {
|
||||
$methods = $type.GetMethods() |
|
||||
Where-Object { !$_.IsSpecialName } |
|
||||
Select-Object -First 5
|
||||
|
||||
foreach ($m in $methods) {
|
||||
Write-Host " $($m.Name)()" -ForegroundColor Gray
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Write-Host ""
|
||||
Write-Host "==========================================" -ForegroundColor Cyan
|
||||
Write-Host "Inspection Complete" -ForegroundColor Cyan
|
||||
Write-Host "==========================================" -ForegroundColor Cyan
|
||||
256
geutebruck-api/tools/test_action_mappings.py
Normal file
256
geutebruck-api/tools/test_action_mappings.py
Normal file
@@ -0,0 +1,256 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Test script for Action Mapping API endpoints
|
||||
Tests CRUD operations and validates the implementation
|
||||
"""
|
||||
import requests
|
||||
import json
|
||||
from typing import Optional
|
||||
import sys
|
||||
|
||||
|
||||
class ActionMappingAPITester:
|
||||
"""Test harness for Action Mapping API"""
|
||||
|
||||
def __init__(self, base_url: str = "http://localhost:8000", token: Optional[str] = None):
|
||||
self.base_url = base_url
|
||||
self.token = token
|
||||
self.session = requests.Session()
|
||||
|
||||
if token:
|
||||
self.session.headers.update({
|
||||
"Authorization": f"Bearer {token}"
|
||||
})
|
||||
|
||||
def login(self, username: str = "admin", password: str = "admin123"):
|
||||
"""Login and get access token"""
|
||||
print(f"\n=== Logging in as {username} ===")
|
||||
|
||||
response = self.session.post(
|
||||
f"{self.base_url}/api/v1/auth/login",
|
||||
json={"username": username, "password": password}
|
||||
)
|
||||
|
||||
if response.status_code == 200:
|
||||
data = response.json()
|
||||
self.token = data["access_token"]
|
||||
self.session.headers.update({
|
||||
"Authorization": f"Bearer {self.token}"
|
||||
})
|
||||
print(f"✓ Login successful")
|
||||
return True
|
||||
else:
|
||||
print(f"✗ Login failed: {response.status_code} - {response.text}")
|
||||
return False
|
||||
|
||||
def list_action_mappings(self, enabled_only: bool = False):
|
||||
"""Test: List all action mappings"""
|
||||
print(f"\n=== Test: List Action Mappings (enabled_only={enabled_only}) ===")
|
||||
|
||||
params = {"enabled_only": enabled_only}
|
||||
response = self.session.get(
|
||||
f"{self.base_url}/api/v1/action-mappings",
|
||||
params=params
|
||||
)
|
||||
|
||||
print(f"Status: {response.status_code}")
|
||||
|
||||
if response.status_code == 200:
|
||||
data = response.json()
|
||||
print(f"✓ Found {data['total_count']} action mappings")
|
||||
print(f" Enabled: {data['enabled_count']}")
|
||||
print(f" Disabled: {data['disabled_count']}")
|
||||
|
||||
for mapping in data['mappings']:
|
||||
print(f"\n {mapping['name']} ({mapping['id']})")
|
||||
print(f" Input: {mapping['input_action']}")
|
||||
print(f" Outputs: {mapping['output_actions']}")
|
||||
print(f" Enabled: {mapping['enabled']}")
|
||||
print(f" Executions: {mapping['execution_count']}")
|
||||
|
||||
return data
|
||||
else:
|
||||
print(f"✗ Failed: {response.text}")
|
||||
return None
|
||||
|
||||
def create_action_mapping(self, name: str, input_action: str, output_actions: list):
|
||||
"""Test: Create new action mapping"""
|
||||
print(f"\n=== Test: Create Action Mapping '{name}' ===")
|
||||
|
||||
mapping_data = {
|
||||
"name": name,
|
||||
"description": f"Test mapping: {name}",
|
||||
"input_action": input_action,
|
||||
"output_actions": output_actions,
|
||||
"enabled": True
|
||||
}
|
||||
|
||||
print(f"Creating:")
|
||||
print(f" Input: {input_action}")
|
||||
print(f" Outputs: {output_actions}")
|
||||
|
||||
response = self.session.post(
|
||||
f"{self.base_url}/api/v1/action-mappings",
|
||||
json=mapping_data
|
||||
)
|
||||
|
||||
print(f"Status: {response.status_code}")
|
||||
|
||||
if response.status_code == 201:
|
||||
data = response.json()
|
||||
print(f"✓ Created action mapping")
|
||||
print(f" ID: {data['id']}")
|
||||
print(f" Name: {data['name']}")
|
||||
return data
|
||||
else:
|
||||
print(f"✗ Failed: {response.text}")
|
||||
return None
|
||||
|
||||
def get_action_mapping(self, mapping_id: str):
|
||||
"""Test: Get specific action mapping"""
|
||||
print(f"\n=== Test: Get Action Mapping {mapping_id} ===")
|
||||
|
||||
response = self.session.get(
|
||||
f"{self.base_url}/api/v1/action-mappings/{mapping_id}"
|
||||
)
|
||||
|
||||
print(f"Status: {response.status_code}")
|
||||
|
||||
if response.status_code == 200:
|
||||
data = response.json()
|
||||
print(f"✓ Retrieved action mapping")
|
||||
print(f" Name: {data['name']}")
|
||||
print(f" Input: {data['input_action']}")
|
||||
print(f" Outputs: {data['output_actions']}")
|
||||
return data
|
||||
else:
|
||||
print(f"✗ Failed: {response.text}")
|
||||
return None
|
||||
|
||||
def update_action_mapping(self, mapping_id: str, updates: dict):
|
||||
"""Test: Update action mapping"""
|
||||
print(f"\n=== Test: Update Action Mapping {mapping_id} ===")
|
||||
|
||||
print(f"Updates: {json.dumps(updates, indent=2)}")
|
||||
|
||||
response = self.session.put(
|
||||
f"{self.base_url}/api/v1/action-mappings/{mapping_id}",
|
||||
json=updates
|
||||
)
|
||||
|
||||
print(f"Status: {response.status_code}")
|
||||
|
||||
if response.status_code == 200:
|
||||
data = response.json()
|
||||
print(f"✓ Updated action mapping")
|
||||
print(f" Name: {data['name']}")
|
||||
print(f" Enabled: {data['enabled']}")
|
||||
return data
|
||||
else:
|
||||
print(f"✗ Failed: {response.text}")
|
||||
return None
|
||||
|
||||
def delete_action_mapping(self, mapping_id: str):
|
||||
"""Test: Delete action mapping"""
|
||||
print(f"\n=== Test: Delete Action Mapping {mapping_id} ===")
|
||||
|
||||
response = self.session.delete(
|
||||
f"{self.base_url}/api/v1/action-mappings/{mapping_id}"
|
||||
)
|
||||
|
||||
print(f"Status: {response.status_code}")
|
||||
|
||||
if response.status_code == 204:
|
||||
print(f"✓ Deleted action mapping")
|
||||
return True
|
||||
else:
|
||||
print(f"✗ Failed: {response.text}")
|
||||
return False
|
||||
|
||||
def run_full_test_suite(self):
|
||||
"""Run complete test suite"""
|
||||
print("=" * 60)
|
||||
print("Action Mapping API Test Suite")
|
||||
print("=" * 60)
|
||||
|
||||
# Login
|
||||
if not self.login():
|
||||
print("\n✗ Cannot proceed without authentication")
|
||||
return False
|
||||
|
||||
# Test 1: List initial state
|
||||
initial_list = self.list_action_mappings()
|
||||
|
||||
# Test 2: Create action mapping
|
||||
created = self.create_action_mapping(
|
||||
name="Test Motion Detection Alert",
|
||||
input_action="VMD_Start(101038)",
|
||||
output_actions=[
|
||||
"CrossSwitch(101038, 1, 0)",
|
||||
"SendMail(security@example.com, Motion Detected)"
|
||||
]
|
||||
)
|
||||
|
||||
if not created:
|
||||
print("\n✗ Cannot proceed - failed to create action mapping")
|
||||
return False
|
||||
|
||||
mapping_id = created['id']
|
||||
|
||||
# Test 3: Get the created mapping
|
||||
self.get_action_mapping(mapping_id)
|
||||
|
||||
# Test 4: Update the mapping
|
||||
self.update_action_mapping(
|
||||
mapping_id,
|
||||
{
|
||||
"enabled": False,
|
||||
"description": "Updated test description"
|
||||
}
|
||||
)
|
||||
|
||||
# Test 5: List again to see the update
|
||||
self.list_action_mappings()
|
||||
|
||||
# Test 6: Delete the mapping
|
||||
self.delete_action_mapping(mapping_id)
|
||||
|
||||
# Test 7: Verify deletion
|
||||
print(f"\n=== Test: Verify Deletion ===")
|
||||
response = self.session.get(f"{self.base_url}/api/v1/action-mappings/{mapping_id}")
|
||||
if response.status_code == 404:
|
||||
print("✓ Mapping successfully deleted (404 Not Found)")
|
||||
else:
|
||||
print(f"✗ Unexpected response: {response.status_code}")
|
||||
|
||||
print("\n" + "=" * 60)
|
||||
print("Test Suite Complete")
|
||||
print("=" * 60)
|
||||
|
||||
return True
|
||||
|
||||
|
||||
def main():
|
||||
"""Main entry point"""
|
||||
import argparse
|
||||
|
||||
parser = argparse.ArgumentParser(description="Test Action Mapping API")
|
||||
parser.add_argument("--url", default="http://localhost:8000", help="API base URL")
|
||||
parser.add_argument("--username", default="admin", help="Username for login")
|
||||
parser.add_argument("--password", default="admin123", help="Password for login")
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
tester = ActionMappingAPITester(base_url=args.url)
|
||||
|
||||
if not tester.login(args.username, args.password):
|
||||
print("Login failed - check credentials and API availability")
|
||||
sys.exit(1)
|
||||
|
||||
success = tester.run_full_test_suite()
|
||||
|
||||
sys.exit(0 if success else 1)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
97
geutebruck-api/tools/test_credentials.ps1
Normal file
97
geutebruck-api/tools/test_credentials.ps1
Normal file
@@ -0,0 +1,97 @@
|
||||
# Automated Credential Testing Script
|
||||
# Tests common Geutebruck username/password combinations
|
||||
|
||||
$ErrorActionPreference = "SilentlyContinue"
|
||||
|
||||
$users = @("sysadmin", "admin", "administrator", "root", "geviscope", "gevisoft")
|
||||
$passwords = @("", "masterkey", "admin", "password", "geviscope", "gevisoft", "123456", "geutebruck")
|
||||
|
||||
$configPath = "C:\DEV\COPILOT\geutebruck-api\src\sdk-bridge\GeViScopeBridge\appsettings.json"
|
||||
$exePath = "C:\DEV\COPILOT\geutebruck-api\src\sdk-bridge\GeViScopeBridge\bin\Release\net8.0\GeViScopeBridge.exe"
|
||||
$logPath = "C:\DEV\COPILOT\geutebruck-api\tools\credential_test.log"
|
||||
|
||||
Write-Host "========================================" -ForegroundColor Cyan
|
||||
Write-Host "Testing Geutebruck Server Credentials" -ForegroundColor Cyan
|
||||
Write-Host "========================================" -ForegroundColor Cyan
|
||||
Write-Host ""
|
||||
|
||||
$testCount = 0
|
||||
$totalTests = $users.Count * $passwords.Count
|
||||
|
||||
foreach ($user in $users) {
|
||||
foreach ($pass in $passwords) {
|
||||
$testCount++
|
||||
$passDisplay = if ($pass -eq "") { "(empty)" } else { $pass }
|
||||
Write-Host "[$testCount/$totalTests] Testing: $user / $passDisplay" -ForegroundColor Yellow
|
||||
|
||||
# Update appsettings.json
|
||||
$config = @{
|
||||
GeViScope = @{
|
||||
Host = "localhost"
|
||||
Username = $user
|
||||
Password = $pass
|
||||
}
|
||||
GeViSoft = @{
|
||||
Host = "localhost"
|
||||
Username = $user
|
||||
Password = $pass
|
||||
}
|
||||
GrpcServer = @{
|
||||
Port = 50051
|
||||
}
|
||||
Logging = @{
|
||||
LogLevel = @{
|
||||
Default = "Information"
|
||||
Microsoft = "Warning"
|
||||
Grpc = "Information"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$config | ConvertTo-Json -Depth 5 | Out-File $configPath -Encoding UTF8
|
||||
|
||||
# Run SDK Bridge with timeout
|
||||
$proc = Start-Process -FilePath $exePath -PassThru -RedirectStandardOutput $logPath -RedirectStandardError $logPath -WindowStyle Hidden
|
||||
|
||||
# Wait up to 8 seconds for connection
|
||||
Start-Sleep -Seconds 8
|
||||
|
||||
# Check output
|
||||
$output = Get-Content $logPath -Raw -ErrorAction SilentlyContinue
|
||||
|
||||
# Kill the process
|
||||
Stop-Process -Id $proc.Id -Force -ErrorAction SilentlyContinue
|
||||
|
||||
# Check for success
|
||||
if ($output -match "Successfully connected to GeViServer") {
|
||||
Write-Host ""
|
||||
Write-Host "========================================" -ForegroundColor Green
|
||||
Write-Host "SUCCESS! WORKING CREDENTIALS FOUND" -ForegroundColor Green
|
||||
Write-Host "========================================" -ForegroundColor Green
|
||||
Write-Host "Username: $user" -ForegroundColor Green
|
||||
Write-Host "Password: $passDisplay" -ForegroundColor Green
|
||||
Write-Host ""
|
||||
Write-Host "Configuration has been updated in:" -ForegroundColor Green
|
||||
Write-Host " $configPath" -ForegroundColor Green
|
||||
Write-Host ""
|
||||
Write-Host "You can now start the SDK Bridge:" -ForegroundColor Cyan
|
||||
Write-Host " cd C:\DEV\COPILOT\geutebruck-api\src\sdk-bridge\GeViScopeBridge\bin\Release\net8.0" -ForegroundColor Cyan
|
||||
Write-Host " .\GeViScopeBridge.exe" -ForegroundColor Cyan
|
||||
exit 0
|
||||
}
|
||||
|
||||
Start-Sleep -Milliseconds 500
|
||||
}
|
||||
}
|
||||
|
||||
Write-Host ""
|
||||
Write-Host "========================================" -ForegroundColor Red
|
||||
Write-Host "No working credentials found" -ForegroundColor Red
|
||||
Write-Host "========================================" -ForegroundColor Red
|
||||
Write-Host ""
|
||||
Write-Host "Please check:" -ForegroundColor Yellow
|
||||
Write-Host " 1. GeViSet configuration" -ForegroundColor Yellow
|
||||
Write-Host " 2. GeViScope/GeViSoft config files" -ForegroundColor Yellow
|
||||
Write-Host " 3. GeViAPI Test Client settings" -ForegroundColor Yellow
|
||||
Write-Host ""
|
||||
Write-Host "See: tools/find_credentials.md for more options" -ForegroundColor Cyan
|
||||
Reference in New Issue
Block a user