Initial release: Do Better Norge Legal Tools Hub
Five MVP tools (Ask, Search, Summarize, Timeline, Redact) with email+password auth, Azure OpenAI gateway, evidence trail panel, and process-and-forget privacy default. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
+14
@@ -0,0 +1,14 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
require_once __DIR__ . '/../includes/LegalTools.php';
|
||||
|
||||
dbnToolsRequireMethod('POST');
|
||||
dbnToolsRequireAuth();
|
||||
$input = dbnToolsJsonInput(25000);
|
||||
$language = dbnToolsNormalizeLanguage($input['language'] ?? 'en');
|
||||
|
||||
dbnToolsWithTelemetry('ask', $language, function () use ($input, $language): array {
|
||||
$question = dbnToolsString($input, 'question', 4000);
|
||||
return (new DbnLegalToolsService())->ask($question, $language);
|
||||
});
|
||||
@@ -0,0 +1,88 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
require_once __DIR__ . '/../includes/bootstrap.php';
|
||||
require_once __DIR__ . '/../includes/AzureOpenAiGateway.php';
|
||||
|
||||
dbnToolsRequireMethod('GET');
|
||||
dbnToolsRequireAuth();
|
||||
|
||||
$checks = [];
|
||||
$checks['passcode_hash'] = [
|
||||
'ok' => (bool)dbnToolsEnv('DBN_TOOLS_PASSCODE_HASH'),
|
||||
'detail' => dbnToolsEnv('DBN_TOOLS_PASSCODE_HASH') ? 'Configured' : 'Missing DBN_TOOLS_PASSCODE_HASH',
|
||||
];
|
||||
|
||||
$azure = new DbnAzureOpenAiGateway();
|
||||
$missingChat = $azure->missingChatConfig();
|
||||
$missingEmbedding = $azure->missingEmbeddingConfig();
|
||||
$checks['azure_chat_config'] = [
|
||||
'ok' => !$missingChat,
|
||||
'detail' => !$missingChat ? 'Configured' : 'Missing: ' . implode(', ', $missingChat),
|
||||
];
|
||||
$checks['azure_embedding_config'] = [
|
||||
'ok' => !$missingEmbedding,
|
||||
'detail' => !$missingEmbedding ? 'Configured' : 'Missing: ' . implode(', ', $missingEmbedding),
|
||||
];
|
||||
$checks['azure_reachability'] = [
|
||||
'ok' => false,
|
||||
'detail' => 'Not checked because chat config is incomplete',
|
||||
];
|
||||
if (!$missingChat) {
|
||||
$reachable = $azure->ping(8);
|
||||
$checks['azure_reachability'] = [
|
||||
'ok' => $reachable,
|
||||
'detail' => $reachable ? 'Azure chat deployment responded' : 'Azure chat deployment did not respond',
|
||||
];
|
||||
}
|
||||
|
||||
try {
|
||||
$db = dbnToolsDb();
|
||||
$db->query('SELECT 1');
|
||||
$checks['db_connectivity'] = ['ok' => true, 'detail' => 'CaveauAI admin DB reachable'];
|
||||
|
||||
$client = dbnToolsFetchClient($db);
|
||||
$checks['dave_jr_legal_client'] = [
|
||||
'ok' => (bool)$client,
|
||||
'detail' => $client ? 'Client id ' . $client['id'] . ' found' : 'Client slug ' . dbnToolsClientSlug() . ' not found',
|
||||
];
|
||||
|
||||
$package = dbnToolsFetchPackage('family-legal', $db);
|
||||
$checks['family_legal_package'] = [
|
||||
'ok' => (bool)$package,
|
||||
'detail' => $package ? 'Package id ' . $package['id'] . ' found' : 'family-legal package not found',
|
||||
];
|
||||
|
||||
$subOk = $client && $package && dbnToolsHasActiveSubscription((int)$client['id'], (int)$package['id'], $db);
|
||||
$checks['family_legal_subscription'] = [
|
||||
'ok' => (bool)$subOk,
|
||||
'detail' => $subOk ? 'Active subscription visible' : 'Active subscription not visible',
|
||||
];
|
||||
} catch (Throwable $e) {
|
||||
$checks['db_connectivity'] = ['ok' => false, 'detail' => $e->getMessage()];
|
||||
$checks['dave_jr_legal_client'] = ['ok' => false, 'detail' => 'Not checked'];
|
||||
$checks['family_legal_package'] = ['ok' => false, 'detail' => 'Not checked'];
|
||||
$checks['family_legal_subscription'] = ['ok' => false, 'detail' => 'Not checked'];
|
||||
}
|
||||
|
||||
$logPath = dbnToolsMetadataLogPath();
|
||||
$dir = dirname($logPath);
|
||||
$checks['metadata_log'] = [
|
||||
'ok' => is_dir($dir) && is_writable($dir),
|
||||
'detail' => is_dir($dir) && is_writable($dir) ? 'Metadata directory is writable' : 'Metadata directory is not writable',
|
||||
];
|
||||
|
||||
$ok = true;
|
||||
foreach ($checks as $check) {
|
||||
if (empty($check['ok'])) {
|
||||
$ok = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
dbnToolsRespond([
|
||||
'ok' => $ok,
|
||||
'status' => $ok ? 'ok' : 'degraded',
|
||||
'version' => DBN_TOOLS_VERSION,
|
||||
'checks' => $checks,
|
||||
], $ok ? 200 : 503);
|
||||
@@ -0,0 +1,14 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
require_once __DIR__ . '/../includes/LegalTools.php';
|
||||
|
||||
dbnToolsRequireMethod('POST');
|
||||
dbnToolsRequireAuth();
|
||||
$input = dbnToolsJsonInput(70000);
|
||||
|
||||
dbnToolsWithTelemetry('redact', '', function () use ($input): array {
|
||||
$text = dbnToolsString($input, 'text', 32000);
|
||||
$mode = (string)($input['mode'] ?? 'standard');
|
||||
return (new DbnLegalToolsService())->redact($text, $mode);
|
||||
});
|
||||
@@ -0,0 +1,15 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
require_once __DIR__ . '/../includes/LegalTools.php';
|
||||
|
||||
dbnToolsRequireMethod('POST');
|
||||
dbnToolsRequireAuth();
|
||||
$input = dbnToolsJsonInput(12000);
|
||||
$language = dbnToolsNormalizeLanguage($input['language'] ?? 'en');
|
||||
|
||||
dbnToolsWithTelemetry('search', $language, function () use ($input, $language): array {
|
||||
$query = dbnToolsString($input, 'query', 2000);
|
||||
$limit = max(1, min(10, (int)($input['limit'] ?? 6)));
|
||||
return (new DbnLegalToolsService())->search($query, $language, $limit);
|
||||
});
|
||||
@@ -0,0 +1,42 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
require_once __DIR__ . '/../includes/bootstrap.php';
|
||||
|
||||
dbnToolsRequireMethod('POST');
|
||||
$input = dbnToolsJsonInput(2048);
|
||||
|
||||
$email = strtolower(trim((string)($input['email'] ?? '')));
|
||||
$password = (string)($input['password'] ?? '');
|
||||
|
||||
if ($email === '') {
|
||||
dbnToolsError('Email is required.', 422, 'missing_email');
|
||||
}
|
||||
if ($password === '') {
|
||||
dbnToolsError('Password is required.', 422, 'missing_password');
|
||||
}
|
||||
|
||||
$configuredEmail = dbnToolsAuthEmail();
|
||||
$hash = dbnToolsAuthPasswordHash();
|
||||
|
||||
if ($configuredEmail === null || trim($configuredEmail) === '' || $hash === null || trim($hash) === '') {
|
||||
dbnToolsError('Authentication credentials are not configured.', 503, 'auth_not_configured');
|
||||
}
|
||||
|
||||
$emailMatch = hash_equals(strtolower(trim($configuredEmail)), $email);
|
||||
$passwordMatch = password_verify($password, $hash);
|
||||
|
||||
if (!$emailMatch || !$passwordMatch) {
|
||||
dbnToolsError('Email or password was not accepted.', 401, 'invalid_credentials');
|
||||
}
|
||||
|
||||
session_regenerate_id(true);
|
||||
$_SESSION['dbn_tools_authenticated'] = true;
|
||||
$_SESSION['dbn_tools_authenticated_at'] = time();
|
||||
$_SESSION['dbn_tools_anon_id'] = $_SESSION['dbn_tools_anon_id'] ?? bin2hex(random_bytes(16));
|
||||
|
||||
dbnToolsRespond([
|
||||
'ok' => true,
|
||||
'authenticated' => true,
|
||||
'session' => dbnToolsAnonymousSessionId(),
|
||||
]);
|
||||
@@ -0,0 +1,14 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
require_once __DIR__ . '/../includes/LegalTools.php';
|
||||
|
||||
dbnToolsRequireMethod('POST');
|
||||
dbnToolsRequireAuth();
|
||||
$input = dbnToolsJsonInput(70000);
|
||||
$language = dbnToolsNormalizeLanguage($input['language'] ?? 'en');
|
||||
|
||||
dbnToolsWithTelemetry('summarize', $language, function () use ($input, $language): array {
|
||||
$text = dbnToolsString($input, 'text', 32000);
|
||||
return (new DbnLegalToolsService())->summarize($text, $language);
|
||||
});
|
||||
@@ -0,0 +1,14 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
require_once __DIR__ . '/../includes/LegalTools.php';
|
||||
|
||||
dbnToolsRequireMethod('POST');
|
||||
dbnToolsRequireAuth();
|
||||
$input = dbnToolsJsonInput(70000);
|
||||
$language = dbnToolsNormalizeLanguage($input['language'] ?? 'en');
|
||||
|
||||
dbnToolsWithTelemetry('timeline', $language, function () use ($input, $language): array {
|
||||
$text = dbnToolsString($input, 'text', 32000);
|
||||
return (new DbnLegalToolsService())->timeline($text, $language);
|
||||
});
|
||||
Reference in New Issue
Block a user