Implement comprehensive improvement plan (Phases 1-6)
Security (Phase 1-2):
- Add SecurityHeadersMiddleware with CSP, X-Frame-Options, etc.
- Add RateLimitMiddleware for API rate limiting
- Add security event logging to AuditLogModel
- Add ResponseHelper for standardized API responses
- Update config.php with security constants
Database (Phase 3):
- Add migration 014 for additional indexes
- Add migration 015 for ticket dependencies
- Add migration 016 for ticket attachments
- Add migration 017 for recurring tickets
- Add migration 018 for custom fields
Features (Phase 4-5):
- Add ticket dependencies with DependencyModel and API
- Add duplicate detection with check_duplicates API
- Add file attachments with AttachmentModel and upload/download APIs
- Add @mentions with autocomplete and highlighting
- Add quick actions on dashboard rows
Collaboration (Phase 5):
- Add mention extraction in CommentModel
- Add mention autocomplete dropdown in ticket.js
- Add mention highlighting CSS styles
Admin & Export (Phase 6):
- Add StatsModel for dashboard widgets
- Add dashboard stats cards (open, critical, unassigned, etc.)
- Add CSV/JSON export via export_tickets API
- Add rich text editor toolbar in markdown.js
- Add RecurringTicketModel with cron job
- Add CustomFieldModel for per-category fields
- Add admin views: RecurringTickets, CustomFields, Workflow,
Templates, AuditLog, UserActivity
- Add admin APIs: manage_workflows, manage_templates,
manage_recurring, custom_fields, get_users
- Add admin routes in index.php
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-20 09:55:01 -05:00
|
|
|
#!/usr/bin/env php
|
|
|
|
|
<?php
|
|
|
|
|
/**
|
|
|
|
|
* Recurring Tickets Cron Job
|
|
|
|
|
*
|
|
|
|
|
* Run this script via cron to automatically create tickets from recurring schedules.
|
|
|
|
|
* Recommended: Run every 5-15 minutes
|
|
|
|
|
*
|
|
|
|
|
* Example crontab entry:
|
|
|
|
|
* */10 * * * * /usr/bin/php /path/to/cron/create_recurring_tickets.php >> /var/log/recurring_tickets.log 2>&1
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
// Change to project root directory
|
|
|
|
|
chdir(dirname(__DIR__));
|
|
|
|
|
|
|
|
|
|
// Include required files
|
|
|
|
|
require_once 'config/config.php';
|
|
|
|
|
require_once 'models/RecurringTicketModel.php';
|
|
|
|
|
require_once 'models/TicketModel.php';
|
|
|
|
|
require_once 'models/AuditLogModel.php';
|
|
|
|
|
|
|
|
|
|
// Log function
|
|
|
|
|
function logMessage($message) {
|
|
|
|
|
echo "[" . date('Y-m-d H:i:s') . "] " . $message . "\n";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
logMessage("Starting recurring tickets cron job");
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
// Create database connection
|
|
|
|
|
$conn = new mysqli(
|
|
|
|
|
$GLOBALS['config']['DB_HOST'],
|
|
|
|
|
$GLOBALS['config']['DB_USER'],
|
|
|
|
|
$GLOBALS['config']['DB_PASS'],
|
|
|
|
|
$GLOBALS['config']['DB_NAME']
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
if ($conn->connect_error) {
|
|
|
|
|
throw new Exception("Database connection failed: " . $conn->connect_error);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Initialize models
|
|
|
|
|
$recurringModel = new RecurringTicketModel($conn);
|
|
|
|
|
$ticketModel = new TicketModel($conn);
|
|
|
|
|
$auditLog = new AuditLogModel($conn);
|
|
|
|
|
|
|
|
|
|
// Get all due recurring tickets
|
|
|
|
|
$dueTickets = $recurringModel->getDueRecurringTickets();
|
|
|
|
|
logMessage("Found " . count($dueTickets) . " recurring tickets due for creation");
|
|
|
|
|
|
|
|
|
|
$created = 0;
|
|
|
|
|
$errors = 0;
|
|
|
|
|
|
|
|
|
|
foreach ($dueTickets as $recurring) {
|
|
|
|
|
logMessage("Processing recurring ticket ID: " . $recurring['recurring_id']);
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
// Prepare ticket data
|
|
|
|
|
$ticketData = [
|
|
|
|
|
'title' => processTemplate($recurring['title_template']),
|
|
|
|
|
'description' => processTemplate($recurring['description_template']),
|
|
|
|
|
'category' => $recurring['category'],
|
|
|
|
|
'type' => $recurring['type'],
|
|
|
|
|
'priority' => $recurring['priority'],
|
|
|
|
|
'status' => 'Open'
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
// Create the ticket
|
|
|
|
|
$result = $ticketModel->createTicket($ticketData, $recurring['created_by']);
|
|
|
|
|
|
|
|
|
|
if ($result['success']) {
|
|
|
|
|
$ticketId = $result['ticket_id'];
|
|
|
|
|
logMessage("Created ticket: " . $ticketId);
|
|
|
|
|
|
|
|
|
|
// Assign to user if specified
|
|
|
|
|
if ($recurring['assigned_to']) {
|
2026-01-30 14:39:13 -05:00
|
|
|
$ticketModel->assignTicket($ticketId, $recurring['assigned_to'], $recurring['created_by']);
|
Implement comprehensive improvement plan (Phases 1-6)
Security (Phase 1-2):
- Add SecurityHeadersMiddleware with CSP, X-Frame-Options, etc.
- Add RateLimitMiddleware for API rate limiting
- Add security event logging to AuditLogModel
- Add ResponseHelper for standardized API responses
- Update config.php with security constants
Database (Phase 3):
- Add migration 014 for additional indexes
- Add migration 015 for ticket dependencies
- Add migration 016 for ticket attachments
- Add migration 017 for recurring tickets
- Add migration 018 for custom fields
Features (Phase 4-5):
- Add ticket dependencies with DependencyModel and API
- Add duplicate detection with check_duplicates API
- Add file attachments with AttachmentModel and upload/download APIs
- Add @mentions with autocomplete and highlighting
- Add quick actions on dashboard rows
Collaboration (Phase 5):
- Add mention extraction in CommentModel
- Add mention autocomplete dropdown in ticket.js
- Add mention highlighting CSS styles
Admin & Export (Phase 6):
- Add StatsModel for dashboard widgets
- Add dashboard stats cards (open, critical, unassigned, etc.)
- Add CSV/JSON export via export_tickets API
- Add rich text editor toolbar in markdown.js
- Add RecurringTicketModel with cron job
- Add CustomFieldModel for per-category fields
- Add admin views: RecurringTickets, CustomFields, Workflow,
Templates, AuditLog, UserActivity
- Add admin APIs: manage_workflows, manage_templates,
manage_recurring, custom_fields, get_users
- Add admin routes in index.php
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-20 09:55:01 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Log to audit
|
|
|
|
|
$auditLog->log(
|
|
|
|
|
$recurring['created_by'],
|
|
|
|
|
'create',
|
|
|
|
|
'ticket',
|
|
|
|
|
$ticketId,
|
|
|
|
|
['source' => 'recurring', 'recurring_id' => $recurring['recurring_id']]
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
// Update the recurring ticket's next run time
|
|
|
|
|
$recurringModel->updateAfterRun($recurring['recurring_id']);
|
|
|
|
|
|
|
|
|
|
$created++;
|
|
|
|
|
} else {
|
|
|
|
|
logMessage("ERROR: Failed to create ticket - " . ($result['error'] ?? 'Unknown error'));
|
|
|
|
|
$errors++;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} catch (Exception $e) {
|
|
|
|
|
logMessage("ERROR: Exception processing recurring ticket - " . $e->getMessage());
|
|
|
|
|
$errors++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
logMessage("Completed: Created $created tickets, $errors errors");
|
|
|
|
|
|
|
|
|
|
$conn->close();
|
|
|
|
|
|
|
|
|
|
} catch (Exception $e) {
|
|
|
|
|
logMessage("FATAL ERROR: " . $e->getMessage());
|
|
|
|
|
exit(1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Process template variables
|
|
|
|
|
*/
|
|
|
|
|
function processTemplate($template) {
|
|
|
|
|
if (empty($template)) {
|
|
|
|
|
return $template;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$replacements = [
|
|
|
|
|
'{{date}}' => date('Y-m-d'),
|
|
|
|
|
'{{time}}' => date('H:i:s'),
|
|
|
|
|
'{{datetime}}' => date('Y-m-d H:i:s'),
|
|
|
|
|
'{{week}}' => date('W'),
|
|
|
|
|
'{{month}}' => date('F'),
|
|
|
|
|
'{{year}}' => date('Y'),
|
|
|
|
|
'{{day_of_week}}' => date('l'),
|
|
|
|
|
'{{day}}' => date('d'),
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
return str_replace(array_keys($replacements), array_values($replacements), $template);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
logMessage("Cron job finished");
|