Complete MVP implementation including: - PHP 8.4 backend with Front Controller pattern (80+ API endpoints) - Multi-tenant architecture with organization_id isolation - JWT authentication (HS256, 2h access + 7d refresh tokens) - 14 controllers: Auth, Organization, Assessment, Dashboard, Risk, Incident, Policy, SupplyChain, Training, Asset, Audit, Admin - AI Service integration (Anthropic Claude API) for gap analysis, risk suggestions, policy generation, incident classification - NIS2 gap analysis questionnaire (~80 questions, 10 categories) - MySQL schema (20 tables) with NIS2 Art. 21 compliance controls - NIS2 Art. 23 incident reporting workflow (24h/72h/30d) - Frontend: login, register, dashboard, assessment wizard, org setup - Docker configuration (PHP-FPM + Nginx + MySQL) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
72 lines
2.9 KiB
PHP
72 lines
2.9 KiB
PHP
<?php
|
|
/**
|
|
* NIS2 Agile - Admin Controller
|
|
*
|
|
* Gestione piattaforma (solo super_admin).
|
|
*/
|
|
|
|
require_once __DIR__ . '/BaseController.php';
|
|
|
|
class AdminController extends BaseController
|
|
{
|
|
public function listOrganizations(): void
|
|
{
|
|
$this->requireSuperAdmin();
|
|
$pagination = $this->getPagination();
|
|
|
|
$total = Database::count('organizations', '1=1');
|
|
$orgs = Database::fetchAll(
|
|
"SELECT o.*,
|
|
(SELECT COUNT(*) FROM user_organizations WHERE organization_id = o.id) as member_count,
|
|
(SELECT overall_score FROM assessments WHERE organization_id = o.id AND status = 'completed' ORDER BY completed_at DESC LIMIT 1) as last_score
|
|
FROM organizations o
|
|
ORDER BY o.created_at DESC
|
|
LIMIT {$pagination['per_page']} OFFSET {$pagination['offset']}"
|
|
);
|
|
|
|
$this->jsonPaginated($orgs, $total, $pagination['page'], $pagination['per_page']);
|
|
}
|
|
|
|
public function listUsers(): void
|
|
{
|
|
$this->requireSuperAdmin();
|
|
$pagination = $this->getPagination();
|
|
|
|
$total = Database::count('users', '1=1');
|
|
$users = Database::fetchAll(
|
|
"SELECT u.id, u.email, u.full_name, u.role, u.is_active, u.last_login_at, u.created_at,
|
|
GROUP_CONCAT(o.name) as organizations
|
|
FROM users u
|
|
LEFT JOIN user_organizations uo ON uo.user_id = u.id
|
|
LEFT JOIN organizations o ON o.id = uo.organization_id
|
|
GROUP BY u.id
|
|
ORDER BY u.created_at DESC
|
|
LIMIT {$pagination['per_page']} OFFSET {$pagination['offset']}"
|
|
);
|
|
|
|
$this->jsonPaginated($users, $total, $pagination['page'], $pagination['per_page']);
|
|
}
|
|
|
|
public function platformStats(): void
|
|
{
|
|
$this->requireSuperAdmin();
|
|
|
|
$this->jsonSuccess([
|
|
'total_organizations' => Database::count('organizations', '1=1'),
|
|
'active_organizations' => Database::count('organizations', 'is_active = 1'),
|
|
'total_users' => Database::count('users', '1=1'),
|
|
'active_users' => Database::count('users', 'is_active = 1'),
|
|
'total_assessments' => Database::count('assessments', '1=1'),
|
|
'completed_assessments' => Database::count('assessments', 'status = "completed"'),
|
|
'total_incidents' => Database::count('incidents', '1=1'),
|
|
'open_incidents' => Database::count('incidents', 'status NOT IN ("closed", "post_mortem")'),
|
|
'total_risks' => Database::count('risks', '1=1'),
|
|
'total_policies' => Database::count('policies', '1=1'),
|
|
'ai_interactions' => Database::count('ai_interactions', '1=1'),
|
|
'plans_distribution' => Database::fetchAll(
|
|
'SELECT subscription_plan, COUNT(*) as count FROM organizations GROUP BY subscription_plan'
|
|
),
|
|
]);
|
|
}
|
|
}
|