Skip to content

FOUR-24651: Enable and disable custom packages / enterprise packages per tenant #8327

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 12 commits into
base: poc/FOUR-22888-Multitenancy
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
use Illuminate\Support\Facades\Artisan;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Storage;
use ProcessMaker\Multitenancy\Tenant;

class ProcessMakerLicenseUpdate extends Command
{
Expand Down
109 changes: 109 additions & 0 deletions ProcessMaker/Console/Commands/TenantsAddScheduleTask.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
<?php

namespace ProcessMaker\Console\Commands;

use Illuminate\Console\Command;
use ProcessMaker\Multitenancy\Tenant;

class TenantsAddScheduleTask extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'tenants:add-schedule-task
{--tenant= : The ID of the tenant}
{--command= : The command to schedule}
{--frequency=daily : The frequency to run the command (e.g., everyMinute, hourly, daily, weekly, monthly, custom)}
{--cron= : Custom cron expression (required if frequency is custom)}
{--options= : Comma-separated list of options (withoutOverlapping, onOneServer)}';

/**
* The console command description.
*
* @var string
*/
protected $description = 'Add a scheduled task to a tenant configuration';

/**
* Execute the console command.
*
* @return int
*/
public function handle()
{
$tenantId = $this->option('tenant');
$command = $this->option('command');
$frequency = $this->option('frequency');
$cron = $this->option('cron');
$optionsString = $this->option('options');

// Validate required parameters
if (!$tenantId) {
$this->error('Tenant ID is required.');

return 1;
}

if (!$command) {
$this->error('Command is required.');

return 1;
}

if ($frequency === 'custom' && !$cron) {
$this->error('Cron expression is required when frequency is custom.');

return 1;
}

// Find the tenant
$tenant = Tenant::find($tenantId);
if (!$tenant) {
$this->error("Tenant with ID {$tenantId} not found.");

return 1;
}

// Get current config or initialize empty array
$config = $tenant->config ?? [];

// Initialize schedule config if not exists
if (!isset($config['schedule'])) {
$config['schedule'] = [];
}

// Set up the task configuration
$taskConfig = [
'frequency' => $frequency,
];

// Add cron expression if using custom frequency
if ($frequency === 'custom') {
$taskConfig['cron'] = $cron;
}

// Process options
if ($optionsString) {
$options = explode(',', $optionsString);
foreach ($options as $option) {
$option = trim($option);
if ($option === 'withoutOverlapping' || $option === 'onOneServer') {
$taskConfig[$option] = true;
}
}
}

// Add or update the command in the tenant's schedule config
$config['schedule'][$command] = $taskConfig;

// Save the updated configuration
$tenant->config = $config;
$tenant->save();

$this->info("Scheduled task '{$command}' added to tenant {$tenantId} with frequency '{$frequency}'.");

return 0;
}
}
90 changes: 90 additions & 0 deletions ProcessMaker/Console/Commands/TenantsListScheduleTasks.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
<?php

namespace ProcessMaker\Console\Commands;

use Illuminate\Console\Command;
use ProcessMaker\Multitenancy\Tenant;

class TenantsListScheduleTasks extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'tenants:list-schedule-tasks {--tenant= : The ID of the tenant}';

/**
* The console command description.
*
* @var string
*/
protected $description = 'List all scheduled tasks for a tenant';

/**
* Execute the console command.
*
* @return int
*/
public function handle()
{
$tenantId = $this->option('tenant');

// Validate tenant ID
if (!$tenantId) {
$this->error('Tenant ID is required.');

return 1;
}

// Find the tenant
$tenant = Tenant::find($tenantId);
if (!$tenant) {
$this->error("Tenant with ID {$tenantId} not found.");

return 1;
}

// Get tenant configuration
$config = $tenant->config ?? [];

// Check if schedule configuration exists
if (!isset($config['schedule']) || empty($config['schedule'])) {
$this->info("No scheduled tasks found for tenant {$tenantId}.");

return 0;
}

// Prepare data for table
$tasks = [];
foreach ($config['schedule'] as $command => $settings) {
$frequency = $settings['frequency'];
if ($frequency === 'custom') {
$frequency .= " ({$settings['cron']})";
}

$options = [];
if (isset($settings['withoutOverlapping']) && $settings['withoutOverlapping']) {
$options[] = 'withoutOverlapping';
}
if (isset($settings['onOneServer']) && $settings['onOneServer']) {
$options[] = 'onOneServer';
}

$tasks[] = [
'command' => $command,
'frequency' => $frequency,
'options' => implode(', ', $options),
];
}

// Display tasks in a table
$this->info("Scheduled tasks for tenant {$tenantId}:");
$this->table(
['Command', 'Frequency', 'Options'],
$tasks
);

return 0;
}
}
83 changes: 83 additions & 0 deletions ProcessMaker/Console/Commands/TenantsRemoveScheduleTask.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
<?php

namespace ProcessMaker\Console\Commands;

use Illuminate\Console\Command;
use ProcessMaker\Multitenancy\Tenant;

class TenantsRemoveScheduleTask extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'tenants:remove-schedule-task
{--tenant= : The ID of the tenant}
{--command= : The command to remove from schedule}';

/**
* The console command description.
*
* @var string
*/
protected $description = 'Remove a scheduled task from a tenant configuration';

/**
* Execute the console command.
*
* @return int
*/
public function handle()
{
$tenantId = $this->option('tenant');
$command = $this->option('command');

// Validate required parameters
if (!$tenantId) {
$this->error('Tenant ID is required.');

return 1;
}

if (!$command) {
$this->error('Command is required.');

return 1;
}

// Find the tenant
$tenant = Tenant::find($tenantId);
if (!$tenant) {
$this->error("Tenant with ID {$tenantId} not found.");

return 1;
}

// Get current config
$config = $tenant->config ?? [];

// Check if schedule and command exist
if (!isset($config['schedule']) || !isset($config['schedule'][$command])) {
$this->error("Command '{$command}' not found in tenant {$tenantId}'s schedule configuration.");

return 1;
}

// Remove the command from the schedule
unset($config['schedule'][$command]);

// If schedule is empty, remove it
if (empty($config['schedule'])) {
unset($config['schedule']);
}

// Save the updated configuration
$tenant->config = $config;
$tenant->save();

$this->info("Scheduled task '{$command}' removed from tenant {$tenantId}.");

return 0;
}
}
104 changes: 104 additions & 0 deletions ProcessMaker/Console/Commands/TenantsRunScheduler.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
<?php

namespace ProcessMaker\Console\Commands;

use Illuminate\Console\Command;
use Illuminate\Console\Scheduling\Schedule;
use ProcessMaker\Multitenancy\Services\TenantSchedulingService;
use ProcessMaker\Multitenancy\Tenant;

class TenantsRunScheduler extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'tenants:run-scheduler {--tenant= : The ID of the tenant}';

/**
* The console command description.
*
* @var string
*/
protected $description = 'Run tenant-specific scheduler for testing purposes';

/**
* The schedule instance.
*
* @var Schedule
*/
protected $schedule;

/**
* The tenant schedule manager.
*
* @var TenantSchedulingService
*/
protected $service;

/**
* Create a new command instance.
*
* @param Schedule $schedule
* @param TenantSchedulingService $service
* @return void
*/
public function __construct(Schedule $schedule, TenantSchedulingService $service)
{
parent::__construct();

$this->schedule = $schedule;
$this->service = $service;
}

/**
* Execute the console command.
*
* @return int
*/
public function handle()
{
$tenantId = $this->option('tenant');

if (!$tenantId) {
$this->error('Tenant ID is required.');

return 1;
}

$tenant = Tenant::find($tenantId);
if (!$tenant) {
$this->error("Tenant with ID {$tenantId} not found.");

return 1;
}

$this->info("Registering scheduled tasks for tenant {$tenantId}...");

// Register tenant-specific schedule
$this->service->registerScheduledTasksForTenant($this->schedule, $tenant);

// Get due events
$dueEvents = $this->schedule->dueEvents(app());

if (empty($dueEvents)) {
$this->info("No due events found for tenant {$tenantId} at this time.");

return 0;
}

$this->info('The following events are due to run:');

foreach ($dueEvents as $event) {
$this->info(' - ' . $event->command);

if ($this->confirm('Do you want to run this command now?')) {
$this->info('Running: ' . $event->command);
$event->run(app());
}
}

return 0;
}
}
Loading
Loading