Files
server-manager/src/Controllers/AdminController.php
Agent 136eebc4c3 feat: Firebase Cloud Messaging push notifications
Backend:
- New user_fcm_tokens table (migration 010) for storing device tokens
- FCMService sends push via Firebase HTTP legacy API (server key from .env)
- POST /api/fcm/register endpoint for Android to register its FCM token
- AdminController::sendNotification() triggers FCM push after DB insert
- FCM config added to config.php

Android:
- Firebase Cloud Messaging service (ServerManagerFirebaseService)
  receives push notifications and shows them via NotificationHelper
- FCM token registered with backend on new token and on login
- google-services.json template (must be replaced with real Firebase config)
- firebase-setup.sh script with configuration instructions
- FCM dependency + google-services plugin added to Gradle
- Bump to v1.8.0 (versionCode 12)
2026-06-13 12:37:40 -04:00

303 lines
9.5 KiB
PHP
Executable File

<?php
declare(strict_types=1);
namespace ServerManager\Controllers;
use ServerManager\Core\App;
use ServerManager\Core\Database;
use ServerManager\Core\Session;
use ServerManager\Core\Validator;
use ServerManager\Models\Notification;
use ServerManager\Models\User;
use ServerManager\Services\AuditService;
use ServerManager\Services\FCMService;
class AdminController
{
private \ServerManager\Core\View $view;
private User $userModel;
private AuditService $auditService;
public function __construct()
{
$this->view = App::getInstance()->getView();
$this->userModel = new User();
$this->auditService = new AuditService();
}
private function requireSuperAdmin(): void
{
if (Session::get('user_role') !== 'super_admin') {
Session::setFlash('error', 'You do not have permission to access this page.');
$this->view->redirect('/dashboard');
}
}
public function users(): void
{
$this->requireSuperAdmin();
$page = (int) ($_GET['page'] ?? 1);
$users = $this->userModel->getAll($page, 20);
$this->view->display('admin.users', [
'title' => 'User Management - ServerManager',
'users' => $users,
]);
}
public function createUser(): void
{
if (Session::get('user_role') !== 'super_admin') {
$this->view->json(['success' => false, 'message' => 'Forbidden'], 403);
}
$validator = new Validator();
$rules = [
'username' => 'required|min:3|max:50|alphaNum',
'email' => 'required|email',
'password' => 'required|min:8',
'role' => 'required|in:super_admin,admin,operator',
];
if (!$validator->validate($_POST, $rules)) {
$this->view->json(['success' => false, 'message' => $validator->getFirstError()]);
}
$existingUser = $this->userModel->findByUsername($_POST['username']);
if ($existingUser) {
$this->view->json(['success' => false, 'message' => 'Username already exists.']);
}
$existingEmail = $this->userModel->findByEmail($_POST['email']);
if ($existingEmail) {
$this->view->json(['success' => false, 'message' => 'Email already exists.']);
}
$id = $this->userModel->create([
'username' => $_POST['username'],
'email' => $_POST['email'],
'password' => $_POST['password'],
'role' => $_POST['role'] ?? 'admin',
'is_active' => 1,
]);
$this->auditService->logUserManagement($id, 'user_created');
$this->view->json([
'success' => true,
'message' => 'User created successfully.',
'user_id' => $id,
]);
}
public function updateUser(int $id): void
{
if (Session::get('user_role') !== 'super_admin') {
$this->view->json(['success' => false, 'message' => 'Forbidden'], 403);
}
$user = $this->userModel->findById($id);
if (!$user) {
$this->view->json(['success' => false, 'message' => 'User not found'], 404);
}
$updateData = [];
if (!empty($_POST['email'])) {
$updateData['email'] = $_POST['email'];
}
if (!empty($_POST['role'])) {
$updateData['role'] = $_POST['role'];
}
if (!empty($_POST['password'])) {
$updateData['password'] = $_POST['password'];
}
if (isset($_POST['is_active'])) {
$updateData['is_active'] = (int) $_POST['is_active'];
}
if (empty($updateData)) {
$this->view->json(['success' => false, 'message' => 'No data to update.']);
}
$this->userModel->update($id, $updateData);
$this->auditService->logUserManagement($id, 'user_updated');
$this->view->json([
'success' => true,
'message' => 'User updated successfully.',
]);
}
public function deleteUser(int $id): void
{
if (Session::get('user_role') !== 'super_admin') {
$this->view->json(['success' => false, 'message' => 'Forbidden'], 403);
}
$user = $this->userModel->findById($id);
if (!$user) {
$this->view->json(['success' => false, 'message' => 'User not found'], 404);
}
if ($user['id'] === Session::get('user_id')) {
$this->view->json(['success' => false, 'message' => 'You cannot delete your own account.']);
}
$this->userModel->delete($id);
$this->auditService->logUserManagement($id, 'user_deleted');
$this->view->json([
'success' => true,
'message' => 'User deleted successfully.',
]);
}
public function auditLogs(): void
{
if (Session::get('user_role') !== 'super_admin') {
Session::setFlash('error', 'You do not have permission to access this page.');
$this->view->redirect('/dashboard');
}
$page = (int) ($_GET['page'] ?? 1);
$action = $_GET['action'] ?? '';
$username = $_GET['username'] ?? '';
$ipAddress = $_GET['ip_address'] ?? '';
$entityType = $_GET['entity_type'] ?? '';
$details = $_GET['details'] ?? '';
$dateFrom = $_GET['date_from'] ?? '';
$dateTo = $_GET['date_to'] ?? '';
$filters = [];
if ($action !== '') $filters['action'] = $action;
if ($username !== '') $filters['username'] = $username;
if ($ipAddress !== '') $filters['ip_address'] = $ipAddress;
if ($entityType !== '') $filters['entity_type'] = $entityType;
if ($details !== '') $filters['details'] = $details;
if ($dateFrom !== '') $filters['date_from'] = $dateFrom;
if ($dateTo !== '') $filters['date_to'] = $dateTo;
$logs = $this->auditService->getAuditLogs($page, 25, $filters);
$this->view->display('admin.audit', [
'title' => 'Audit Logs - ServerManager',
'logs' => $logs,
'action' => $action,
'username' => $username,
'ipAddress' => $ipAddress,
'entityType' => $entityType,
'details' => $details,
'dateFrom' => $dateFrom,
'dateTo' => $dateTo,
]);
}
public function securitySettings(): void
{
if (Session::get('user_role') !== 'super_admin') {
Session::setFlash('error', 'You do not have permission to access this page.');
$this->view->redirect('/dashboard');
}
$this->view->display('admin.security', [
'title' => 'Security Settings - ServerManager',
]);
}
public function appVersion(): void
{
$this->requireSuperAdmin();
$db = Database::getInstance();
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$fields = ['app_version', 'apk_url', 'force_update', 'release_notes'];
foreach ($fields as $field) {
if (isset($_POST[$field])) {
$db->update('app_config', ['value' => $_POST[$field]], '`key` = ?', [$field]);
}
}
$this->auditService->log('app_version_updated', 'config', null, ['details' => 'App version config updated']);
Session::setFlash('success', 'App version updated successfully.');
$this->view->redirect('/admin/app-version');
return;
}
$configs = $db->fetchAll('SELECT * FROM app_config');
$config = [];
foreach ($configs as $row) {
$config[$row['key']] = $row['value'];
}
$this->view->display('admin.app_version', [
'title' => 'App Version - ServerManager',
'config' => $config,
]);
}
public function notifications(): void
{
$this->requireSuperAdmin();
$notificationModel = new Notification();
$page = (int) ($_GET['page'] ?? 1);
$allNotifications = $notificationModel->getAll($page, 20);
$userModel = new User();
$users = $userModel->getAll(1, 200);
$totalActiveUsers = $notificationModel->getTotalActiveUsers();
$this->view->display('admin.notifications', [
'title' => 'Notifications - ServerManager',
'notifications' => $allNotifications,
'users' => $users,
'totalActiveUsers' => $totalActiveUsers,
]);
}
public function sendNotification(): void
{
$this->requireSuperAdmin();
$title = $_POST['title'] ?? '';
$message = $_POST['message'] ?? '';
$type = $_POST['type'] ?? 'info';
$userId = !empty($_POST['user_id']) ? (int) $_POST['user_id'] : null;
if (empty($title) || empty($message)) {
$this->view->json(['success' => false, 'message' => 'Title and message are required.']);
return;
}
$notificationModel = new Notification();
$noteId = $notificationModel->create([
'user_id' => $userId,
'title' => $title,
'message' => $message,
'type' => $type,
]);
$fcm = new FCMService();
if ($userId) {
$fcm->sendToUser($userId, $title, $message, $type, $noteId);
} else {
$fcm->sendToAll($title, $message, $type, $noteId);
}
$this->auditService->log('notification_sent', 'notification', null, ['title' => $title, 'target' => $userId ? "user #{$userId}" : 'all users']);
$this->view->json(['success' => true, 'message' => 'Notification sent successfully.']);
}
}