Compare commits
No commits in common. "eb4b5ca7bcba02d559c728dcb2b7b9f7126c70d5" and "d318b621d51861baaceed70101fc2b7cce8160b2" have entirely different histories.
eb4b5ca7bc
...
d318b621d5
|
|
@ -603,41 +603,25 @@ if ($queryAction === 'plugin_check_page' && isset($_GET['plugin'])) {
|
||||||
|
|
||||||
// Check database tables
|
// Check database tables
|
||||||
$db = \App\App::db();
|
$db = \App\App::db();
|
||||||
$pluginOwnedTables = [];
|
$pluginTables = [];
|
||||||
$pluginReferencedTables = [];
|
if ($db instanceof PDO) {
|
||||||
if ($db && method_exists($db, 'getConnection')) {
|
$stmt = $db->query("SHOW TABLES");
|
||||||
$pdo = $db->getConnection();
|
|
||||||
$stmt = $pdo->query("SHOW TABLES");
|
|
||||||
$allTables = $stmt->fetchAll(PDO::FETCH_COLUMN, 0);
|
$allTables = $stmt->fetchAll(PDO::FETCH_COLUMN, 0);
|
||||||
|
|
||||||
if ($hasMigration) {
|
if ($hasMigration) {
|
||||||
|
// Check each migration file for table references
|
||||||
foreach ($migrationFiles as $migrationFile) {
|
foreach ($migrationFiles as $migrationFile) {
|
||||||
$migrationContent = file_get_contents($migrationFile);
|
$migrationContent = file_get_contents($migrationFile);
|
||||||
|
|
||||||
// Extract tables created by this migration (plugin-owned)
|
|
||||||
if (preg_match_all('/CREATE\s+TABLE(?:\s+IF\s+NOT\s+EXISTS)?\s+`?([a-zA-Z0-9_]+)`?/i', $migrationContent, $matches)) {
|
|
||||||
foreach ($matches[1] as $tableName) {
|
|
||||||
if (in_array($tableName, $allTables)) {
|
|
||||||
$pluginOwnedTables[] = $tableName;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Find all referenced tables (dependencies)
|
|
||||||
foreach ($allTables as $table) {
|
foreach ($allTables as $table) {
|
||||||
if (strpos($migrationContent, $table) !== false && !in_array($table, $pluginOwnedTables)) {
|
if (strpos($migrationContent, $table) !== false) {
|
||||||
$pluginReferencedTables[] = $table;
|
$pluginTables[] = $table;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$pluginOwnedTables = array_unique($pluginOwnedTables);
|
$pluginTables = array_unique($pluginTables);
|
||||||
$pluginReferencedTables = array_unique($pluginReferencedTables);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$checkResults['tables'] = [
|
$checkResults['tables'] = $pluginTables;
|
||||||
'owned' => $pluginOwnedTables,
|
|
||||||
'referenced' => $pluginReferencedTables,
|
|
||||||
];
|
|
||||||
|
|
||||||
// Check plugin functions
|
// Check plugin functions
|
||||||
$bootstrapPath = $pluginInfo['path'] . '/bootstrap.php';
|
$bootstrapPath = $pluginInfo['path'] . '/bootstrap.php';
|
||||||
|
|
|
||||||
|
|
@ -628,41 +628,25 @@ endif; ?>
|
||||||
|
|
||||||
// Check database tables
|
// Check database tables
|
||||||
$db = \App\App::db();
|
$db = \App\App::db();
|
||||||
$pluginOwnedTables = [];
|
$pluginTables = [];
|
||||||
$pluginReferencedTables = [];
|
if ($db instanceof PDO) {
|
||||||
if ($db && method_exists($db, 'getConnection')) {
|
$stmt = $db->query("SHOW TABLES");
|
||||||
$pdo = $db->getConnection();
|
|
||||||
$stmt = $pdo->query("SHOW TABLES");
|
|
||||||
$allTables = $stmt->fetchAll(PDO::FETCH_COLUMN, 0);
|
$allTables = $stmt->fetchAll(PDO::FETCH_COLUMN, 0);
|
||||||
|
|
||||||
if ($hasMigration) {
|
if ($hasMigration) {
|
||||||
|
// Check each migration file for table references
|
||||||
foreach ($migrationFiles as $migrationFile) {
|
foreach ($migrationFiles as $migrationFile) {
|
||||||
$migrationContent = file_get_contents($migrationFile);
|
$migrationContent = file_get_contents($migrationFile);
|
||||||
|
|
||||||
// Extract tables created by this migration (plugin-owned)
|
|
||||||
if (preg_match_all('/CREATE\s+TABLE(?:\s+IF\s+NOT\s+EXISTS)?\s+`?([a-zA-Z0-9_]+)`?/i', $migrationContent, $matches)) {
|
|
||||||
foreach ($matches[1] as $tableName) {
|
|
||||||
if (in_array($tableName, $allTables)) {
|
|
||||||
$pluginOwnedTables[] = $tableName;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Find all referenced tables (dependencies)
|
|
||||||
foreach ($allTables as $table) {
|
foreach ($allTables as $table) {
|
||||||
if (strpos($migrationContent, $table) !== false && !in_array($table, $pluginOwnedTables)) {
|
if (strpos($migrationContent, $table) !== false) {
|
||||||
$pluginReferencedTables[] = $table;
|
$pluginTables[] = $table;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$pluginOwnedTables = array_unique($pluginOwnedTables);
|
$pluginTables = array_unique($pluginTables);
|
||||||
$pluginReferencedTables = array_unique($pluginReferencedTables);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$checkResults['tables'] = [
|
$checkResults['tables'] = $pluginTables;
|
||||||
'owned' => $pluginOwnedTables,
|
|
||||||
'referenced' => $pluginReferencedTables,
|
|
||||||
];
|
|
||||||
|
|
||||||
// Check plugin functions and integrations
|
// Check plugin functions and integrations
|
||||||
$bootstrapPath = $plugin['path'] . '/bootstrap.php';
|
$bootstrapPath = $plugin['path'] . '/bootstrap.php';
|
||||||
|
|
@ -789,29 +773,13 @@ endif; ?>
|
||||||
<h6 class="card-title mb-0">Database Tables</h6>
|
<h6 class="card-title mb-0">Database Tables</h6>
|
||||||
</div>
|
</div>
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<?php if (!empty($checkResults['tables']['owned']) || !empty($checkResults['tables']['referenced'])): ?>
|
<?php if (!empty($checkResults['tables'])): ?>
|
||||||
<?php if (!empty($checkResults['tables']['owned'])): ?>
|
<?php foreach ($checkResults['tables'] as $table): ?>
|
||||||
<div class="mb-3">
|
<div class="d-flex justify-content-between align-items-center mb-2">
|
||||||
<strong class="text-danger">Plugin Tables (removed on purge):</strong>
|
<span><?= htmlspecialchars($table) ?></span>
|
||||||
<?php foreach ($checkResults['tables']['owned'] as $table): ?>
|
<span class="badge bg-success">Present</span>
|
||||||
<div class="d-flex justify-content-between align-items-center mb-2 mt-2">
|
|
||||||
<span><i class="fas fa-database text-danger"></i> <?= htmlspecialchars($table) ?></span>
|
|
||||||
<span class="badge bg-danger">Owned</span>
|
|
||||||
</div>
|
</div>
|
||||||
<?php endforeach; ?>
|
<?php endforeach; ?>
|
||||||
</div>
|
|
||||||
<?php endif; ?>
|
|
||||||
<?php if (!empty($checkResults['tables']['referenced'])): ?>
|
|
||||||
<div>
|
|
||||||
<strong class="text-muted">Referenced Tables (dependencies):</strong>
|
|
||||||
<?php foreach ($checkResults['tables']['referenced'] as $table): ?>
|
|
||||||
<div class="d-flex justify-content-between align-items-center mb-2 mt-2">
|
|
||||||
<span><i class="fas fa-link text-muted"></i> <?= htmlspecialchars($table) ?></span>
|
|
||||||
<span class="badge bg-secondary">Referenced</span>
|
|
||||||
</div>
|
|
||||||
<?php endforeach; ?>
|
|
||||||
</div>
|
|
||||||
<?php endif; ?>
|
|
||||||
<?php else: ?>
|
<?php else: ?>
|
||||||
<p class="text-muted mb-0">
|
<p class="text-muted mb-0">
|
||||||
<?php if ($checkResults['files']['migration']): ?>
|
<?php if ($checkResults['files']['migration']): ?>
|
||||||
|
|
|
||||||
|
|
@ -1,38 +1,13 @@
|
||||||
# Logger plugin
|
# Logger plugin
|
||||||
|
|
||||||
## Overview
|
## Overview
|
||||||
The Logger plugin (located in `plugins/logs/`) provides a modular, pluggable logging
|
The Logger plugin provides a modular, pluggable logging system for the application.
|
||||||
system for the application. It records both user and system events in the `log`
|
It logs user and system events to a MySQL table named `log`.
|
||||||
table and exposes retrieval utilities plus a built-in UI at `?page=logs`.
|
|
||||||
|
|
||||||
The plugin uses the callable dispatcher pattern with `PluginRouteRegistry` for routing
|
|
||||||
and follows the App API pattern for service access.
|
|
||||||
|
|
||||||
## Features
|
|
||||||
1. **Log entry management**
|
|
||||||
- PSR-3-style `log()` method with level + context payloads
|
|
||||||
- Core helper `app_log()` for simplified access with NullLogger fallback
|
|
||||||
2. **Filtering & pagination**
|
|
||||||
- Query by scope, user, time range, message text, or specific user IDs
|
|
||||||
- Pagination-ready result sets with newest-first sorting
|
|
||||||
3. **User awareness**
|
|
||||||
- Stores username via joins for auditing
|
|
||||||
- Captures current user IP via plugin bootstrap
|
|
||||||
4. **Auto-migration**
|
|
||||||
- `logs_ensure_tables()` function creates the `log` table on demand
|
|
||||||
- Called automatically via `logger.system_init` hook
|
|
||||||
5. **UI integration**
|
|
||||||
- Adds a "Logs" entry to the top menu
|
|
||||||
- Provides list/detail views with tabs for user vs system scopes
|
|
||||||
- Uses callable dispatcher for route handling
|
|
||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
1. Copy the `logs` folder into the project's `plugins/` directory.
|
1. Copy the entire `logger` folder into your project's `plugins/` directory.
|
||||||
2. Enable the plugin via the admin plugin management interface (stored in `settings` table).
|
2. Ensure `"enabled": true` in `plugins/logger/plugin.json`.
|
||||||
3. The plugin bootstrap automatically:
|
3. On first initialization, the plugin will create the `log` table if it does not already exist.
|
||||||
- Registers the `logs` route prefix with a callable dispatcher
|
|
||||||
- Sets up the `logs_ensure_tables()` migration function
|
|
||||||
- Initializes the logger via the `logger.system_init` hook
|
|
||||||
|
|
||||||
## Database Schema
|
## Database Schema
|
||||||
The plugin defines the following table (auto-created):
|
The plugin defines the following table (auto-created):
|
||||||
|
|
@ -49,120 +24,39 @@ CREATE TABLE IF NOT EXISTS `log` (
|
||||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_uca1400_ai_ci;
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_uca1400_ai_ci;
|
||||||
```
|
```
|
||||||
|
|
||||||
## Routing & Dispatcher
|
## Hook API
|
||||||
The plugin registers its route using `PluginRouteRegistry`:
|
Core must call:
|
||||||
```php
|
|
||||||
register_plugin_route_prefix('logs', [
|
|
||||||
'dispatcher' => function($action, array $context = []) {
|
|
||||||
require_once PLUGIN_LOGS_PATH . 'controllers/logs.php';
|
|
||||||
if (function_exists('logs_plugin_handle')) {
|
|
||||||
return logs_plugin_handle($action, $context);
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
},
|
|
||||||
'access' => 'private',
|
|
||||||
'defaults' => ['action' => 'list'],
|
|
||||||
'plugin' => 'logs',
|
|
||||||
]);
|
|
||||||
```
|
|
||||||
|
|
||||||
## Hook + Loader API
|
|
||||||
Core must fire the initialization hook after the database connection is ready:
|
|
||||||
```php
|
```php
|
||||||
|
// After DB connect:
|
||||||
do_hook('logger.system_init', ['db' => $db]);
|
do_hook('logger.system_init', ['db' => $db]);
|
||||||
```
|
```
|
||||||
The plugin listener:
|
The plugin listens on `logger.system_init`, runs auto-migration, then sets:
|
||||||
- calls `logs_ensure_tables()` to create the `log` table if needed
|
|
||||||
- resolves the current user IP
|
|
||||||
- exposes `$GLOBALS['logObject']` (`Log` instance) and `$GLOBALS['user_IP']`
|
|
||||||
|
|
||||||
When `$logObject` is not available, use `app_log($level, $message, $context)` which falls back to `NullLogger`.
|
|
||||||
|
|
||||||
## PHP API
|
|
||||||
`Log` lives in `plugins/logs/models/Log.php` and receives the database connector.
|
|
||||||
|
|
||||||
### Methods
|
|
||||||
```php
|
```php
|
||||||
Log::log(string $level, string $message, array $context = []): void
|
$GLOBALS['logObject']; // instance of Log
|
||||||
Log::readLog(int $userId, string $scope, int $offset = 0, int $itemsPerPage = 0, array $filters = []): array
|
$GLOBALS['user_IP']; // current user IP
|
||||||
```
|
```
|
||||||
|
|
||||||
### Supported log levels
|
Then in the code use:
|
||||||
`emergency`, `alert`, `critical`, `error`, `warning`, `notice`, `info`, `debug`
|
|
||||||
|
|
||||||
### Supported filters
|
|
||||||
- `from_time`: `YYYY-MM-DD` lower bound (inclusive)
|
|
||||||
- `until_time`: `YYYY-MM-DD` upper bound (inclusive)
|
|
||||||
- `message`: substring match across message text
|
|
||||||
- `id`: explicit user ID (system scope only)
|
|
||||||
|
|
||||||
### Typical usage
|
|
||||||
```php
|
```php
|
||||||
app_log('info', 'User updated profile', [
|
$logObject->insertLog($userId, 'Your message', 'user');
|
||||||
'user_id' => $userId,
|
$data = $logObject->readLog($userId, 'user', $offset, $limit, $filters);
|
||||||
'scope' => 'user',
|
|
||||||
]);
|
|
||||||
|
|
||||||
$entries = $logObject->readLog(
|
|
||||||
$userId,
|
|
||||||
$scope,
|
|
||||||
$offset,
|
|
||||||
$itemsPerPage,
|
|
||||||
['message' => 'profile']
|
|
||||||
);
|
|
||||||
```
|
```
|
||||||
|
|
||||||
## Usage guidelines
|
|
||||||
1. **When to log**
|
|
||||||
- User actions, authentication events, configuration changes
|
|
||||||
- System events, background job outcomes, and security anomalies
|
|
||||||
2. **Message hygiene**
|
|
||||||
- Keep messages concise, include essential metadata, avoid sensitive data
|
|
||||||
3. **Data integrity**
|
|
||||||
- Validate user input before logging to avoid malformed queries
|
|
||||||
- Wrap bulk insertions in transactions when necessary
|
|
||||||
4. **Performance**
|
|
||||||
- Prefer pagination for large result sets
|
|
||||||
- Index columns used by custom filters if extending the schema
|
|
||||||
5. **Retention**
|
|
||||||
- Schedule archival/log rotation via cron if the table grows quickly
|
|
||||||
|
|
||||||
## File Structure
|
## File Structure
|
||||||
```
|
```
|
||||||
plugins/logs/
|
plugins/logger/
|
||||||
├─ bootstrap.php # registers route, migration function, hooks & menu
|
├─ bootstrap.php # registers hook
|
||||||
├─ plugin.json # plugin metadata
|
├─ plugin.json # metadata & enabled flag
|
||||||
├─ README.md # this documentation
|
├─ README.md # this documentation
|
||||||
├─ controllers/
|
|
||||||
│ └─ logs.php # procedural handler functions for callable dispatcher
|
|
||||||
├─ models/
|
├─ models/
|
||||||
│ ├─ Log.php # main Log class
|
│ ├─ Log.php # main Log class
|
||||||
│ └─ LoggerFactory.php # migration + factory
|
│ └─ LoggerFactory.php# migration + factory
|
||||||
├─ helpers/
|
├─ helpers/
|
||||||
│ ├─ logs_view_helper.php
|
│ └─ logs.php # user IP helper
|
||||||
├─ helpers.php # plugin helper wrapper
|
|
||||||
└─ migrations/
|
└─ migrations/
|
||||||
└─ create_log_table.sql
|
└─ create_log_table.sql
|
||||||
```
|
```
|
||||||
|
|
||||||
## Controller Architecture
|
|
||||||
The controller uses procedural functions instead of classes:
|
|
||||||
- `logs_plugin_handle($action, $context)` - main dispatcher function
|
|
||||||
- `logs_plugin_render_list($logObject, $db, $userId, $validSession, $app_root)` - renders log list with filters and pagination
|
|
||||||
|
|
||||||
The callable dispatcher pattern provides:
|
|
||||||
- Clean separation of concerns
|
|
||||||
- Access to request context (user_id, db, app_root, valid_session)
|
|
||||||
- Consistent error handling and layout rendering
|
|
||||||
|
|
||||||
## Admin Plugin Check
|
|
||||||
The plugin provides `logs_ensure_tables()` for the admin plugin management interface:
|
|
||||||
- **Owned tables:** `log` (will be removed on purge)
|
|
||||||
- **Referenced tables:** `user` (dependency, not removed)
|
|
||||||
|
|
||||||
## Uninstall / Disable
|
## Uninstall / Disable
|
||||||
To disable the plugin:
|
- Set `"enabled": false` in `plugin.json` or delete the `plugins/logger/` folder.
|
||||||
- Use the admin plugin management interface to disable it (updates the `settings` table), or
|
- Core code will default to `NullLogger` and no logs will be written.
|
||||||
- Delete the `plugins/logs/` folder entirely
|
|
||||||
|
|
||||||
When disabled, the `app_log()` helper automatically falls back to `NullLogger`, so logging calls remain safe and won't cause errors. To remove plugin data, use the admin plugin management interface to purge the `log` table.
|
|
||||||
|
|
|
||||||
|
|
@ -1,63 +1,20 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
/**
|
// Logs plugin bootstrap
|
||||||
* Logs Plugin Bootstrap
|
|
||||||
*
|
|
||||||
* Initializes the logs plugin using the App API pattern.
|
|
||||||
*/
|
|
||||||
|
|
||||||
if (!defined('PLUGIN_LOGS_PATH')) {
|
if (!defined('PLUGIN_LOGS_PATH')) {
|
||||||
define('PLUGIN_LOGS_PATH', __DIR__ . '/');
|
define('PLUGIN_LOGS_PATH', __DIR__ . '/');
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load plugin helpers
|
// We add the plugin helpers wrapper
|
||||||
require_once PLUGIN_LOGS_PATH . 'helpers.php';
|
require_once PLUGIN_LOGS_PATH . 'helpers.php';
|
||||||
|
|
||||||
// Register route with callable dispatcher
|
// List here all the controllers in "/controllers/" that we need as pages
|
||||||
register_plugin_route_prefix('logs', [
|
$GLOBALS['plugin_controllers']['logs'] = [
|
||||||
'dispatcher' => function($action, array $context = []) {
|
'logs'
|
||||||
require_once PLUGIN_LOGS_PATH . 'controllers/logs.php';
|
];
|
||||||
if (function_exists('logs_plugin_handle')) {
|
|
||||||
return logs_plugin_handle($action, $context);
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
},
|
|
||||||
'access' => 'private',
|
|
||||||
'defaults' => ['action' => 'list'],
|
|
||||||
'plugin' => 'logs',
|
|
||||||
]);
|
|
||||||
|
|
||||||
// Migration function for admin plugin check
|
|
||||||
if (!function_exists('logs_ensure_tables')) {
|
|
||||||
function logs_ensure_tables(): void {
|
|
||||||
static $ensured = false;
|
|
||||||
if ($ensured) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
$db = \App\App::db();
|
|
||||||
if (!$db || !method_exists($db, 'getConnection')) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
$pdo = $db->getConnection();
|
|
||||||
if (!$pdo instanceof \PDO) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
$migrationFile = __DIR__ . '/migrations/create_log_table.sql';
|
|
||||||
if (is_readable($migrationFile)) {
|
|
||||||
$sql = file_get_contents($migrationFile);
|
|
||||||
if ($sql !== false && trim($sql) !== '') {
|
|
||||||
$pdo->exec($sql);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
$ensured = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Logger plugin bootstrap
|
// Logger plugin bootstrap
|
||||||
register_hook('logger.system_init', function(array $context) {
|
register_hook('logger.system_init', function(array $context) {
|
||||||
// Ensure tables exist
|
|
||||||
logs_ensure_tables();
|
|
||||||
|
|
||||||
// Load plugin-specific LoggerFactory class
|
// Load plugin-specific LoggerFactory class
|
||||||
require_once __DIR__ . '/models/LoggerFactory.php';
|
require_once __DIR__ . '/models/LoggerFactory.php';
|
||||||
[$logger, $userIP] = LoggerFactory::create($context['db']);
|
[$logger, $userIP] = LoggerFactory::create($context['db']);
|
||||||
|
|
|
||||||
|
|
@ -1,157 +1,122 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Logs Plugin Controller
|
* Logs listings
|
||||||
*
|
*
|
||||||
* Procedural handler used by the callable dispatcher of the logs plugin.
|
* This page ("logs") retrieves and displays logs within a time range
|
||||||
|
* either for a specified user or for all users.
|
||||||
|
* It supports pagination and filtering.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
// Define plugin base path if not already defined
|
||||||
|
if (!defined('PLUGIN_LOGS_PATH')) {
|
||||||
|
define('PLUGIN_LOGS_PATH', dirname(__FILE__, 2) . '/');
|
||||||
|
}
|
||||||
require_once PLUGIN_LOGS_PATH . 'models/Log.php';
|
require_once PLUGIN_LOGS_PATH . 'models/Log.php';
|
||||||
require_once PLUGIN_LOGS_PATH . 'models/LoggerFactory.php';
|
require_once PLUGIN_LOGS_PATH . 'models/LoggerFactory.php';
|
||||||
require_once APP_PATH . 'classes/user.php';
|
require_once dirname(__FILE__, 4) . '/app/classes/user.php';
|
||||||
require_once APP_PATH . 'helpers/theme.php';
|
|
||||||
|
|
||||||
function logs_plugin_handle(string $action, array $context = []): bool {
|
// Check for rights; user or system
|
||||||
$validSession = (bool)($context['valid_session'] ?? false);
|
$has_system_access = ($userObject->hasRight($userId, 'superuser') ||
|
||||||
$app_root = $context['app_root'] ?? (\App\App::get('app_root') ?? '/');
|
|
||||||
$db = $context['db'] ?? \App\App::db();
|
|
||||||
$userId = $context['user_id'] ?? null;
|
|
||||||
|
|
||||||
if (!$db || !$userId) {
|
|
||||||
\Feedback::flash('ERROR', 'DEFAULT', 'Logs service unavailable.');
|
|
||||||
header('Location: ' . $app_root);
|
|
||||||
exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get logger instance from globals (set by logger.system_init hook)
|
|
||||||
$logObject = $GLOBALS['logObject'] ?? null;
|
|
||||||
if (!$logObject) {
|
|
||||||
\Feedback::flash('ERROR', 'DEFAULT', 'Logger not initialized.');
|
|
||||||
header('Location: ' . $app_root);
|
|
||||||
exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch ($action) {
|
|
||||||
case 'list':
|
|
||||||
default:
|
|
||||||
logs_plugin_render_list($logObject, $db, $userId, $validSession, $app_root);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function logs_plugin_render_list($logObject, $db, int $userId, bool $validSession, string $app_root): void {
|
|
||||||
// Load User class for permissions check
|
|
||||||
$userObject = new \User($db);
|
|
||||||
|
|
||||||
// Check for rights; user or system
|
|
||||||
$has_system_access = ($userObject->hasRight($userId, 'superuser') ||
|
|
||||||
$userObject->hasRight($userId, 'view app logs'));
|
$userObject->hasRight($userId, 'view app logs'));
|
||||||
|
|
||||||
// Get current page for pagination
|
// Get current page for pagination
|
||||||
$currentPage = $_REQUEST['page_num'] ?? 1;
|
$currentPage = $_REQUEST['page_num'] ?? 1;
|
||||||
$currentPage = (int)$currentPage;
|
$currentPage = (int)$currentPage;
|
||||||
|
|
||||||
// Get selected tab
|
// Get selected tab
|
||||||
$selected_tab = $_REQUEST['tab'] ?? 'user';
|
$selected_tab = $_REQUEST['tab'] ?? 'user';
|
||||||
if ($selected_tab === 'system' && !$has_system_access) {
|
if ($selected_tab === 'system' && !$has_system_access) {
|
||||||
$selected_tab = 'user';
|
$selected_tab = 'user';
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set scope based on selected tab
|
// Set scope based on selected tab
|
||||||
$scope = ($selected_tab === 'system') ? 'system' : 'user';
|
$scope = ($selected_tab === 'system') ? 'system' : 'user';
|
||||||
|
|
||||||
// Specify time range
|
// specify time range
|
||||||
include APP_PATH . 'helpers/time_range.php';
|
include '../app/helpers/time_range.php';
|
||||||
|
|
||||||
// Prepare search filters
|
// Prepare search filters
|
||||||
$filters = [];
|
$filters = [];
|
||||||
if (isset($_REQUEST['from_time']) && !empty($_REQUEST['from_time'])) {
|
if (isset($_REQUEST['from_time']) && !empty($_REQUEST['from_time'])) {
|
||||||
$filters['from_time'] = $_REQUEST['from_time'];
|
$filters['from_time'] = $_REQUEST['from_time'];
|
||||||
}
|
}
|
||||||
if (isset($_REQUEST['until_time']) && !empty($_REQUEST['until_time'])) {
|
if (isset($_REQUEST['until_time']) && !empty($_REQUEST['until_time'])) {
|
||||||
$filters['until_time'] = $_REQUEST['until_time'];
|
$filters['until_time'] = $_REQUEST['until_time'];
|
||||||
}
|
}
|
||||||
if (isset($_REQUEST['message']) && !empty($_REQUEST['message'])) {
|
if (isset($_REQUEST['message']) && !empty($_REQUEST['message'])) {
|
||||||
$filters['message'] = $_REQUEST['message'];
|
$filters['message'] = $_REQUEST['message'];
|
||||||
}
|
}
|
||||||
if ($scope === 'system' && isset($_REQUEST['id']) && !empty($_REQUEST['id'])) {
|
if ($scope === 'system' && isset($_REQUEST['id']) && !empty($_REQUEST['id'])) {
|
||||||
$filters['id'] = $_REQUEST['id'];
|
$filters['id'] = $_REQUEST['id'];
|
||||||
}
|
}
|
||||||
|
|
||||||
// Pagination variables
|
// pagination variables
|
||||||
$items_per_page = 15;
|
$items_per_page = 15;
|
||||||
$offset = ($currentPage - 1) * $items_per_page;
|
$offset = ($currentPage - 1) * $items_per_page;
|
||||||
|
|
||||||
// Build params for pagination
|
// Build params for pagination
|
||||||
$params = '';
|
$params = '';
|
||||||
if (!empty($_REQUEST['from_time'])) {
|
if (!empty($_REQUEST['from_time'])) {
|
||||||
$params .= '&from_time=' . urlencode($_REQUEST['from_time']);
|
$params .= '&from_time=' . urlencode($_REQUEST['from_time']);
|
||||||
}
|
}
|
||||||
if (!empty($_REQUEST['until_time'])) {
|
if (!empty($_REQUEST['until_time'])) {
|
||||||
$params .= '&until_time=' . urlencode($_REQUEST['until_time']);
|
$params .= '&until_time=' . urlencode($_REQUEST['until_time']);
|
||||||
}
|
}
|
||||||
if (!empty($_REQUEST['message'])) {
|
if (!empty($_REQUEST['message'])) {
|
||||||
$params .= '&message=' . urlencode($_REQUEST['message']);
|
$params .= '&message=' . urlencode($_REQUEST['message']);
|
||||||
}
|
}
|
||||||
if (!empty($_REQUEST['id'])) {
|
if (!empty($_REQUEST['id'])) {
|
||||||
$params .= '&id=' . urlencode($_REQUEST['id']);
|
$params .= '&id=' . urlencode($_REQUEST['id']);
|
||||||
}
|
}
|
||||||
if (isset($_REQUEST['tab'])) {
|
if (isset($_REQUEST['tab'])) {
|
||||||
$params .= '&tab=' . urlencode($_REQUEST['tab']);
|
$params .= '&tab=' . urlencode($_REQUEST['tab']);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Prepare the result
|
// prepare the result
|
||||||
$search = $logObject->readLog($userId, $scope, $offset, $items_per_page, $filters);
|
$search = $logObject->readLog($userId, $scope, $offset, $items_per_page, $filters);
|
||||||
$search_all = $logObject->readLog($userId, $scope, 0, 0, $filters);
|
$search_all = $logObject->readLog($userId, $scope, 0, 0, $filters);
|
||||||
|
|
||||||
$logs = [];
|
if (!empty($search)) {
|
||||||
$totalPages = 0;
|
// we get total items and number of pages
|
||||||
$item_count = 0;
|
|
||||||
|
|
||||||
if (!empty($search)) {
|
|
||||||
// Get total items and number of pages
|
|
||||||
$item_count = count($search_all);
|
$item_count = count($search_all);
|
||||||
$totalPages = ceil($item_count / $items_per_page);
|
$totalPages = ceil($item_count / $items_per_page);
|
||||||
|
|
||||||
$logs = [];
|
$logs = array();
|
||||||
$logs['records'] = [];
|
$logs['records'] = array();
|
||||||
|
|
||||||
foreach ($search as $item) {
|
foreach ($search as $item) {
|
||||||
// When we show only user's logs, omit user_id column
|
// when we show only user's logs, omit user_id column
|
||||||
if ($scope === 'user') {
|
if ($scope === 'user') {
|
||||||
// assign title to the field
|
$log_record = array(
|
||||||
$log_record = [
|
// assign title to the field in the array record
|
||||||
'time' => $item['time'],
|
'time' => $item['time'],
|
||||||
'log level' => $item['level'],
|
'log level' => $item['level'],
|
||||||
'log message' => $item['message']
|
'log message' => $item['message']
|
||||||
];
|
);
|
||||||
} else {
|
} else {
|
||||||
// assign title to the field
|
$log_record = array(
|
||||||
$log_record = [
|
// assign title to the field in the array record
|
||||||
'userID' => $item['user_id'],
|
'userID' => $item['user_id'],
|
||||||
'username' => $item['username'],
|
'username' => $item['username'],
|
||||||
'time' => $item['time'],
|
'time' => $item['time'],
|
||||||
'log level' => $item['level'],
|
'log level' => $item['level'],
|
||||||
'log message' => $item['message']
|
'log message' => $item['message']
|
||||||
];
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
$logs['records'][] = $log_record;
|
// populate the result array
|
||||||
|
array_push($logs['records'], $log_record);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
$username = $userObject->getUserDetails($userId)[0]['username'];
|
|
||||||
$page = 'logs'; // For pagination template
|
|
||||||
|
|
||||||
\App\Helpers\Theme::include('page-header');
|
|
||||||
\App\Helpers\Theme::include('page-menu');
|
|
||||||
if ($validSession) {
|
|
||||||
\App\Helpers\Theme::include('page-sidebar');
|
|
||||||
}
|
|
||||||
|
|
||||||
include APP_PATH . 'helpers/feedback.php';
|
|
||||||
require_once PLUGIN_LOGS_PATH . 'helpers/logs_view_helper.php';
|
|
||||||
include PLUGIN_LOGS_PATH . 'views/logs.php';
|
|
||||||
|
|
||||||
\App\Helpers\Theme::include('page-footer');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$username = $userObject->getUserDetails($userId)[0]['username'];
|
||||||
|
|
||||||
|
// Get any new feedback messages
|
||||||
|
include_once dirname(__FILE__, 4) . '/app/helpers/feedback.php';
|
||||||
|
|
||||||
|
// Load plugin helpers
|
||||||
|
require_once PLUGIN_LOGS_PATH . 'helpers/logs_view_helper.php';
|
||||||
|
|
||||||
|
// Display messages list
|
||||||
|
include PLUGIN_LOGS_PATH . 'views/logs.php';
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
{
|
{
|
||||||
"name": "Logger Plugin",
|
"name": "Logger Plugin",
|
||||||
"version": "1.0.2",
|
"version": "1.0.1",
|
||||||
"description": "Initializes logging system via LoggerFactory"
|
"description": "Initializes logging system via LoggerFactory"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -44,55 +44,16 @@ Enable/disable registration in `totalmeet.conf.php`:
|
||||||
|
|
||||||
## Implementation
|
## Implementation
|
||||||
|
|
||||||
Uses callable dispatcher pattern with procedural handler functions:
|
Uses simple callable dispatcher pattern for single-action plugin:
|
||||||
```php
|
```php
|
||||||
register_plugin_route_prefix('register', [
|
register_plugin_route_prefix('register', [
|
||||||
'dispatcher' => function($action, array $context = []) {
|
'dispatcher' => function($context) {
|
||||||
require_once PLUGIN_REGISTER_PATH . 'controllers/register.php';
|
require_once PLUGIN_REGISTER_PATH . 'controllers/register.php';
|
||||||
if (function_exists('register_plugin_handle_register')) {
|
|
||||||
return register_plugin_handle_register($action, $context);
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
},
|
},
|
||||||
'access' => 'public',
|
'access' => 'public',
|
||||||
'defaults' => ['action' => 'register'],
|
|
||||||
'plugin' => 'register',
|
|
||||||
]);
|
]);
|
||||||
```
|
```
|
||||||
|
|
||||||
## Controller Architecture
|
|
||||||
|
|
||||||
The controller uses procedural functions:
|
|
||||||
- `register_plugin_handle_register($action, $context)` - main handler
|
|
||||||
- `register_plugin_handle_submission(...)` - processes form submission
|
|
||||||
- `register_plugin_render_form(...)` - renders registration form with layout
|
|
||||||
- `register_plugin_log_success(...)` - logs successful registration
|
|
||||||
|
|
||||||
## Database Tables
|
|
||||||
|
|
||||||
No plugin-specific tables. Uses core `user` and `user_meta` tables.
|
|
||||||
|
|
||||||
## Enable/Disable
|
|
||||||
|
|
||||||
The plugin is managed via the admin plugin management interface (stored in `settings` table).
|
|
||||||
When disabled, the registration route becomes unavailable.
|
|
||||||
|
|
||||||
## File Structure
|
|
||||||
|
|
||||||
```
|
|
||||||
plugins/register/
|
|
||||||
├── bootstrap.php # registers route with callable dispatcher
|
|
||||||
├── plugin.json # plugin metadata
|
|
||||||
├── README.md # this documentation
|
|
||||||
├── controllers/
|
|
||||||
│ └── register.php # procedural handler functions
|
|
||||||
├── models/
|
|
||||||
│ └── register.php # registration logic and validation
|
|
||||||
├── helpers.php # plugin helper wrapper
|
|
||||||
└── views/
|
|
||||||
└── form-register.php # registration form template
|
|
||||||
```
|
|
||||||
|
|
||||||
## Dependencies
|
## Dependencies
|
||||||
|
|
||||||
None - functions independently.
|
None - functions independently.
|
||||||
|
|
|
||||||
|
|
@ -12,16 +12,11 @@ if (!defined('PLUGIN_REGISTER_PATH')) {
|
||||||
}
|
}
|
||||||
|
|
||||||
require_once PLUGIN_REGISTER_PATH . 'helpers.php';
|
require_once PLUGIN_REGISTER_PATH . 'helpers.php';
|
||||||
|
require_once PLUGIN_REGISTER_PATH . 'controllers/register.php';
|
||||||
|
|
||||||
// Register route with simple callable dispatcher
|
// Register route with dispatcher class
|
||||||
register_plugin_route_prefix('register', [
|
register_plugin_route_prefix('register', [
|
||||||
'dispatcher' => function($action, array $context = []) {
|
'dispatcher' => \Plugins\Register\Controllers\RegisterController::class,
|
||||||
require_once PLUGIN_REGISTER_PATH . 'controllers/register.php';
|
|
||||||
if (function_exists('register_plugin_handle_register')) {
|
|
||||||
return register_plugin_handle_register($action, $context);
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
},
|
|
||||||
'access' => 'public',
|
'access' => 'public',
|
||||||
'defaults' => ['action' => 'register'],
|
'defaults' => ['action' => 'register'],
|
||||||
'plugin' => 'register',
|
'plugin' => 'register',
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,19 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Register Plugin Controller
|
* User Registration API Controller
|
||||||
*
|
*
|
||||||
* Procedural handler used by the callable dispatcher.
|
* Provides RESTful endpoints for user registration.
|
||||||
|
* Follows the API pattern used by other plugins.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
namespace Plugins\Register\Controllers;
|
||||||
|
|
||||||
|
use App\App;
|
||||||
|
use App\Helpers\Theme;
|
||||||
|
use Exception;
|
||||||
|
use PDO;
|
||||||
|
|
||||||
require_once APP_PATH . 'classes/feedback.php';
|
require_once APP_PATH . 'classes/feedback.php';
|
||||||
require_once APP_PATH . 'classes/user.php';
|
require_once APP_PATH . 'classes/user.php';
|
||||||
require_once APP_PATH . 'classes/validator.php';
|
require_once APP_PATH . 'classes/validator.php';
|
||||||
|
|
@ -14,36 +22,55 @@ require_once APP_PATH . 'helpers/theme.php';
|
||||||
require_once APP_PATH . 'includes/rate_limit_middleware.php';
|
require_once APP_PATH . 'includes/rate_limit_middleware.php';
|
||||||
require_once PLUGIN_REGISTER_PATH . 'models/register.php';
|
require_once PLUGIN_REGISTER_PATH . 'models/register.php';
|
||||||
|
|
||||||
function register_plugin_handle_register(string $action, array $context = []): bool {
|
class RegisterController
|
||||||
$validSession = (bool)($context['valid_session'] ?? false);
|
{
|
||||||
$app_root = $context['app_root'] ?? (\App\App::get('app_root') ?? '/');
|
private $db;
|
||||||
$config = $context['config'] ?? \App\App::config();
|
private array $config;
|
||||||
$db = $context['db'] ?? \App\App::db();
|
private string $appRoot;
|
||||||
$logger = $context['logger'] ?? \App\App::get('logger');
|
private $logger;
|
||||||
|
|
||||||
if (!$db) {
|
public function __construct()
|
||||||
|
{
|
||||||
|
$this->db = App::db();
|
||||||
|
$this->config = App::config();
|
||||||
|
$this->appRoot = App::get('app_root') ?? '/';
|
||||||
|
$this->logger = App::get('logObject');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function handle(string $action, array $context = []): bool
|
||||||
|
{
|
||||||
|
$validSession = (bool)($context['valid_session'] ?? false);
|
||||||
|
$app_root = $context['app_root'] ?? $this->appRoot;
|
||||||
|
|
||||||
|
if (!$this->db) {
|
||||||
\Feedback::flash('ERROR', 'DEFAULT', 'Registration service unavailable. Please try again later.');
|
\Feedback::flash('ERROR', 'DEFAULT', 'Registration service unavailable. Please try again later.');
|
||||||
register_plugin_render_form($validSession, $app_root, ['registrationEnabled' => false]);
|
$this->renderForm($validSession, $app_root, ['registrationEnabled' => false]);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(bool)($config['registration_enabled'] ?? false)) {
|
if (!$this->isRegistrationEnabled()) {
|
||||||
\Feedback::flash('NOTICE', 'DEFAULT', 'Registration is currently disabled.');
|
\Feedback::flash('NOTICE', 'DEFAULT', 'Registration is currently disabled.');
|
||||||
register_plugin_render_form($validSession, $app_root, ['registrationEnabled' => false]);
|
$this->renderForm($validSession, $app_root, ['registrationEnabled' => false]);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||||
register_plugin_handle_submission($validSession, $app_root, $db, $logger);
|
$this->handleSubmission($validSession, $app_root);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
register_plugin_render_form($validSession, $app_root);
|
$this->renderForm($validSession, $app_root);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
function register_plugin_handle_submission(bool $validSession, string $app_root, $db, $logger = null): void {
|
private function isRegistrationEnabled(): bool
|
||||||
checkRateLimit($db, 'register');
|
{
|
||||||
|
return (bool)($this->config['registration_enabled'] ?? false);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function handleSubmission(bool $validSession, string $app_root): void
|
||||||
|
{
|
||||||
|
checkRateLimit($this->db, 'register');
|
||||||
|
|
||||||
$security = \SecurityHelper::getInstance();
|
$security = \SecurityHelper::getInstance();
|
||||||
$formData = $security->sanitizeArray(
|
$formData = $security->sanitizeArray(
|
||||||
|
|
@ -53,7 +80,7 @@ function register_plugin_handle_submission(bool $validSession, string $app_root,
|
||||||
|
|
||||||
if (!$security->verifyCsrfToken($formData['csrf_token'] ?? '')) {
|
if (!$security->verifyCsrfToken($formData['csrf_token'] ?? '')) {
|
||||||
\Feedback::flash('ERROR', 'DEFAULT', 'Invalid security token. Please try again.');
|
\Feedback::flash('ERROR', 'DEFAULT', 'Invalid security token. Please try again.');
|
||||||
register_plugin_render_form($validSession, $app_root, [
|
$this->renderForm($validSession, $app_root, [
|
||||||
'values' => ['username' => $formData['username'] ?? ''],
|
'values' => ['username' => $formData['username'] ?? ''],
|
||||||
]);
|
]);
|
||||||
return;
|
return;
|
||||||
|
|
@ -83,7 +110,7 @@ function register_plugin_handle_submission(bool $validSession, string $app_root,
|
||||||
|
|
||||||
if (!$validator->validate($rules)) {
|
if (!$validator->validate($rules)) {
|
||||||
\Feedback::flash('ERROR', 'DEFAULT', $validator->getFirstError());
|
\Feedback::flash('ERROR', 'DEFAULT', $validator->getFirstError());
|
||||||
register_plugin_render_form($validSession, $app_root, [
|
$this->renderForm($validSession, $app_root, [
|
||||||
'values' => ['username' => $formData['username'] ?? ''],
|
'values' => ['username' => $formData['username'] ?? ''],
|
||||||
]);
|
]);
|
||||||
return;
|
return;
|
||||||
|
|
@ -92,68 +119,70 @@ function register_plugin_handle_submission(bool $validSession, string $app_root,
|
||||||
$username = trim($formData['username']);
|
$username = trim($formData['username']);
|
||||||
$password = $formData['password'];
|
$password = $formData['password'];
|
||||||
|
|
||||||
$pdo = $db instanceof \PDO ? $db : $db->getConnection();
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$register = new \Register($pdo);
|
$register = new \Register($this->db);
|
||||||
$result = $register->register($username, $password);
|
$result = $register->register($username, $password);
|
||||||
|
|
||||||
if ($result === true) {
|
if ($result === true) {
|
||||||
register_plugin_log_success($username, $db, $logger);
|
$this->logSuccessfulRegistration($username);
|
||||||
\Feedback::flash('NOTICE', 'DEFAULT', 'Registration successful. You can log in now.');
|
\Feedback::flash('NOTICE', 'DEFAULT', 'Registration successful. You can log in now.');
|
||||||
header('Location: ' . $app_root . '?page=login');
|
header('Location: ' . $app_root . '?page=login');
|
||||||
exit;
|
exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
\Feedback::flash('ERROR', 'DEFAULT', 'Registration failed: ' . $result);
|
\Feedback::flash('ERROR', 'DEFAULT', 'Registration failed: ' . $result);
|
||||||
register_plugin_render_form($validSession, $app_root, [
|
$this->renderForm($validSession, $app_root, [
|
||||||
'values' => ['username' => $username],
|
'values' => ['username' => $username],
|
||||||
]);
|
]);
|
||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
\Feedback::flash('ERROR', 'DEFAULT', 'Registration failed: ' . $e->getMessage());
|
\Feedback::flash('ERROR', 'DEFAULT', 'Registration failed: ' . $e->getMessage());
|
||||||
register_plugin_render_form($validSession, $app_root, [
|
$this->renderForm($validSession, $app_root, [
|
||||||
'values' => ['username' => $username],
|
'values' => ['username' => $username],
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function register_plugin_log_success(string $username, $db, $logger = null): void {
|
private function logSuccessfulRegistration(string $username): void
|
||||||
if (!$logger) {
|
{
|
||||||
|
if (!$this->logger) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$userModel = new \User($db);
|
$userModel = new \User($this->db);
|
||||||
$userRecord = $userModel->getUserId($username);
|
$userRecord = $userModel->getUserId($username);
|
||||||
$userId = $userRecord[0]['id'] ?? null;
|
$userId = $userRecord[0]['id'] ?? null;
|
||||||
$userIP = $_SERVER['REMOTE_ADDR'] ?? '';
|
$userIP = $_SERVER['REMOTE_ADDR'] ?? '';
|
||||||
|
|
||||||
$logger->log(
|
$this->logger->log(
|
||||||
'info',
|
'info',
|
||||||
sprintf('Registration: New user "%s" registered successfully. IP: %s', $username, $userIP),
|
sprintf('Registration: New user "%s" registered successfully. IP: %s', $username, $userIP),
|
||||||
['user_id' => $userId, 'scope' => 'user']
|
['user_id' => $userId, 'scope' => 'user']
|
||||||
);
|
);
|
||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
app_log('warning', 'Register plugin logging failed: ' . $e->getMessage(), ['scope' => 'plugin']);
|
app_log('warning', 'RegisterController logging failed: ' . $e->getMessage(), ['scope' => 'plugin']);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
function register_plugin_render_form(bool $validSession, string $app_root, array $data = []): void {
|
private function renderForm(bool $validSession, string $app_root, array $data = []): void
|
||||||
|
{
|
||||||
$formValues = $data['values'] ?? ['username' => ''];
|
$formValues = $data['values'] ?? ['username' => ''];
|
||||||
$registrationEnabled = $data['registrationEnabled'] ?? true;
|
$registrationEnabled = $data['registrationEnabled'] ?? true;
|
||||||
|
|
||||||
\App\Helpers\Theme::include('page-header');
|
Theme::include('page-header');
|
||||||
\App\Helpers\Theme::include('page-menu');
|
Theme::include('page-menu');
|
||||||
if ($validSession) {
|
if ($validSession) {
|
||||||
\App\Helpers\Theme::include('page-sidebar');
|
Theme::include('page-sidebar');
|
||||||
}
|
}
|
||||||
|
|
||||||
include APP_PATH . 'helpers/feedback.php';
|
include APP_PATH . 'helpers/feedback.php';
|
||||||
|
|
||||||
|
$app_root_value = $app_root; // align variable name for template include
|
||||||
|
$app_root = $app_root_value;
|
||||||
$values = $formValues;
|
$values = $formValues;
|
||||||
$app_root = $app_root;
|
|
||||||
|
|
||||||
include PLUGIN_REGISTER_PATH . 'views/form-register.php';
|
include PLUGIN_REGISTER_PATH . 'views/form-register.php';
|
||||||
|
|
||||||
\App\Helpers\Theme::include('page-footer');
|
Theme::include('page-footer');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
{
|
{
|
||||||
"name": "Registration Plugin",
|
"name": "Registration Plugin",
|
||||||
"version": "1.0.2",
|
"version": "1.0.1",
|
||||||
"description": "Provides registration functionality as a plugin."
|
"description": "Provides registration functionality as a plugin."
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue