diff --git a/composer.json b/composer.json index 837c9b6..89fd4fa 100644 --- a/composer.json +++ b/composer.json @@ -1,6 +1,6 @@ { "name": "fleetbase/core-api", - "version": "1.0.3-alpha", + "version": "1.0.4-alpha", "description": "Core Framework and Resources for Fleetbase API", "keywords": [ "fleetbase", diff --git a/config/mail.mailers.php b/config/mail.mailers.php deleted file mode 100644 index a2179d2..0000000 --- a/config/mail.mailers.php +++ /dev/null @@ -1,28 +0,0 @@ - [ - 'transport' => 'ses', - 'key' => env('AWS_ACCESS_KEY_ID'), - 'secret' => env('AWS_SECRET_ACCESS_KEY'), - 'region' => env('AWS_DEFAULT_REGION'), - 'version' => '2010-12-01' - ], -]; diff --git a/config/queue.connections.php b/config/queue.connections.php deleted file mode 100644 index fb4e9e5..0000000 --- a/config/queue.connections.php +++ /dev/null @@ -1,85 +0,0 @@ - [ - 'driver' => 'sync', - ], - - 'database' => [ - 'driver' => 'database', - 'table' => 'jobs', - 'queue' => 'default', - 'retry_after' => 90, - 'after_commit' => false, - ], - - 'beanstalkd' => [ - 'driver' => 'beanstalkd', - 'host' => 'localhost', - 'queue' => 'default', - 'retry_after' => 90, - 'block_for' => 0, - 'after_commit' => false, - ], - - 'sqs' => [ - 'driver' => 'sqs', - 'key' => env('AWS_ACCESS_KEY_ID'), - 'secret' => env('AWS_SECRET_ACCESS_KEY'), - 'prefix' => $sqs_jobs_prefix, - 'queue' => $sqs_jobs_queue, - 'suffix' => env('SQS_SUFFIX'), - 'region' => env('AWS_DEFAULT_REGION', 'ap-southeast-1'), - ], - - 'events' => [ - 'driver' => 'sqs', - 'key' => env('AWS_ACCESS_KEY_ID'), - 'secret' => env('AWS_SECRET_ACCESS_KEY'), - 'prefix' => $sqs_events_prefix, - 'queue' => $sqs_events_queue, - 'suffix' => env('SQS_SUFFIX'), - 'region' => env('AWS_DEFAULT_REGION', 'ap-southeast-1'), - ], - - 'redis' => [ - 'driver' => 'redis', - 'connection' => 'default', - 'queue' => env('REDIS_QUEUE', 'default'), - 'retry_after' => 90, - 'block_for' => null, - 'after_commit' => false, - ], -]; diff --git a/src/Casts/Json.php b/src/Casts/Json.php index 089d8e0..8bf7c3c 100644 --- a/src/Casts/Json.php +++ b/src/Casts/Json.php @@ -49,11 +49,6 @@ public static function decode($json) } $json = stripslashes($json); - - if (Str::startsWith($json, '"') && Str::endsWith($json, '"')) { - $json = trim($json, '"'); - } - return json_decode($json, true); } } diff --git a/src/Events/ResourceLifecycleEvent.php b/src/Events/ResourceLifecycleEvent.php index b82508b..ea5f286 100644 --- a/src/Events/ResourceLifecycleEvent.php +++ b/src/Events/ResourceLifecycleEvent.php @@ -57,20 +57,6 @@ class ResourceLifecycleEvent implements ShouldBroadcast */ public array $data = []; - /** - * The name of the queue connection to use when broadcasting the event. - * - * @var string - */ - public string $connection = 'events'; - - /** - * The name of the queue to use when broadcasting the event. - * - * @var string - */ - public string $queue = 'events'; - /** * Create a new lifecycle event instance. * diff --git a/src/Http/Controllers/Internal/v1/FileController.php b/src/Http/Controllers/Internal/v1/FileController.php index 07fc1e6..cce35e2 100644 --- a/src/Http/Controllers/Internal/v1/FileController.php +++ b/src/Http/Controllers/Internal/v1/FileController.php @@ -28,7 +28,7 @@ class FileController extends FleetbaseController */ public function upload(UploadFileRequest $request) { - $disk = env('FILESYSTEM_DRIVER'); + $disk = $request->input('disk', config('filesystems.default')); $type = $request->input('type'); $size = $request->input('file_size', $request->file->getSize()); $path = $request->input('path', 'uploads'); @@ -87,7 +87,7 @@ public function upload(UploadFileRequest $request) */ public function uploadBase64(UploadBase64FileRequest $request) { - $disk = env('FILESYSTEM_DRIVER'); + $disk = $request->input('disk', config('filesystems.default')); $data = $request->input('data'); $path = $request->input('path', 'uploads'); $visibility = $request->input('visibility', 'public'); @@ -145,7 +145,7 @@ public function uploadBase64(UploadBase64FileRequest $request) */ public function download(?string $id, DownloadFileRequest $request) { - $disk = env('FILESYSTEM_DRIVER'); + $disk = $request->input('disk', config('filesystems.default')); $file = File::where('uuid', $id)->first(); return Storage::disk($disk)->download($file->path, $file->name); diff --git a/src/Http/Controllers/Internal/v1/SettingController.php b/src/Http/Controllers/Internal/v1/SettingController.php index 1b6406f..90c89ab 100644 --- a/src/Http/Controllers/Internal/v1/SettingController.php +++ b/src/Http/Controllers/Internal/v1/SettingController.php @@ -2,68 +2,254 @@ namespace Fleetbase\Http\Controllers\Internal\v1; -use Fleetbase\Http\Controllers\FleetbaseController; +use Fleetbase\Http\Controllers\Controller; +use Fleetbase\Models\Setting; use Illuminate\Http\Request; +use Illuminate\Support\Facades\Mail; -class SettingController extends FleetbaseController +class SettingController extends Controller { /** - * The resource to query + * Simple admin overview metrics -- v1 * - * @var string + * @return void */ - public $resource = 'setting'; + public function adminOverview() { + $metrics = []; + $metrics['total_users'] = \Fleetbase\Models\User::all()->count(); + $metrics['total_organizations'] = \Fleetbase\Models\Company::all()->count(); + $metrics['total_transactions'] = \Fleetbase\Models\Transaction::all()->count(); + + return response()->json($metrics); + } /** - * Test a MySQL database connection. + * Loads and sends the filesystem configuration. * - * This function will attempt to establish a connection to a MySQL database using either a set of - * database connection parameters (host, port, database, username, and password), or a database URL. - * It will then return a JSON response indicating whether the connection was successful or not. + * @return \Illuminate\Http\JsonResponse + */ + public function getFilesystemConfig() + { + $driver = config('filesystems.default'); + $disks = array_keys(config('filesystems.disks', [])); + + // additional configurables + $s3Bucket = config('filesystems.disks.s3.bucket'); + $s3Url = config('filesystems.disks.s3.url'); + $s3Endpoint = config('filesystems.disks.s3.endpoint'); + + return response()->json([ + 'driver' => $driver, + 'disks' => $disks, + 's3Bucket' => $s3Bucket, + 's3Url' => $s3Url, + 's3Endpoint' => $s3Endpoint, + ]); + } + + /** + * Saves filesystem configuration. * * @param \Illuminate\Http\Request $request * @return \Illuminate\Http\JsonResponse */ - public function testMysqlConnection(Request $request) + public function saveFilesystemConfig(Request $request) { - $host = $request->input('DB_HOST'); - $port = $request->input('DB_PORT'); - $database = $request->input('DB_DATABASE', 'fleetbase'); - $username = $request->input('DB_USERNAME', 'fleetbase'); - $password = $request->input('DB_PASSWORD', ''); - $databaseUrl = $request->input('DATABASE_URL'); - - if ($databaseUrl) { - $url = parse_url($databaseUrl); - $host = $url['host']; - $port = $url['port'] ?? null; // Default to null if not set - $username = $url['user']; - if (isset($url['pass'])) { - $password = $url['pass']; + $driver = $request->input('driver', 'local'); + $s3 = $request->input('s3', config('filesystems.disks.s3')); + + Setting::configure('system.filesystem.driver', $driver); + Setting::configure('system.filesystem.s3', array_merge(config('filesystems.disks.s3', []), $s3)); + + return response()->json(['status' => 'OK']); + } + + /** + * Loads and sends the mail configuration. + * + * @return \Illuminate\Http\JsonResponse + */ + public function getMailConfig() + { + $mailer = config('mail.default'); + $from = config('mail.from'); + $mailers = array_keys(config('mail.mailers', [])); + $smtpConfig = config('mail.mailers.smtp'); + + $config = [ + 'mailer' => $mailer, + 'mailers' => $mailers, + 'fromAddress' => data_get($from, 'address'), + 'fromName' => data_get($from, 'name'), + ]; + + foreach ($smtpConfig as $key => $value) { + if ($key === 'transport') { + continue; } - $database = isset($url['path']) ? substr($url['path'], 1) : $database; + + $config['smtp' . ucfirst($key)] = $value; } + return response()->json($config); + } + + /** + * Saves mail configuration. + * + * @param \Illuminate\Http\Request $request + * @return \Illuminate\Http\JsonResponse + */ + public function saveMailConfig(Request $request) + { + $mailer = $request->input('mailer', 'smtp'); + $from = $request->input('from', []); + $smtp = $request->input('smtp', []); + + Setting::configure('system.mail.mailer', $mailer); + Setting::configure('system.mail.from', $from); + Setting::configure('system.mail.smtp', array_merge(['transport' => 'smtp'], $smtp)); + + return response()->json(['status' => 'OK']); + } + + /** + * Sends a test email to the authenticated user. + * + * This function retrieves the authenticated user from the given request and sends a + * test email to the user's email address. It returns a JSON response indicating whether + * the email was sent successfully. + * + * @param \Illuminate\Http\Request $request The incoming HTTP request containing the authenticated user. + * @return \Illuminate\Http\JsonResponse Returns a JSON response with a success message and HTTP status 200. + * + * @throws \Illuminate\Database\Eloquent\ModelNotFoundException If the authenticated user is not found. + * @throws \Illuminate\Mail\MailerException If the email fails to send. + */ + public function testMailConfig(Request $request) + { + $mailer = $request->input('mailer', 'smtp'); + $from = $request->input('from', []); + $smtp = $request->input('smtp', []); + $user = $request->user(); + $message = 'Mail configuration is successful, check your inbox for the test email to confirm.'; + $status = 'success'; + + // set config values from input + config(['mail.default' => $mailer, 'mail.from' => $from, 'mail.mailers.smtp' => array_merge(['transport' => 'smtp'], $smtp)]); + try { - // Make sure the configuration works - new \PDO( - "mysql:host=$host;port=$port;dbname=$database", - $username, - $password, - [\PDO::ATTR_ERRMODE => \PDO::ERRMODE_EXCEPTION] - ); - - // If we got here, it means the connection is successful. Return a positive result - return response()->json([ - 'status' => 'success', - 'message' => 'Connection successful.' - ]); + Mail::to($user)->send(new \Fleetbase\Mail\TestEmail()); } catch (\Exception $e) { - // If we got an error, it means that the connection details were incorrect. - return response()->json([ - 'status' => 'error', - 'message' => 'Could not connect to the database. Please check your configuration. Error: ' . $e->getMessage() - ]); + $message = $e->getMessage(); + $status = 'error'; } + + return response()->json(['status' => $status, 'message' => $message]); + } + + /** + * Loads and sends the queue configuration. + * + * @return \Illuminate\Http\JsonResponse + */ + public function getQueueConfig() + { + $driver = config('queue.default'); + $connections = array_keys(config('queue.connections', [])); + + // additional configurables + $beanstalkdHost = config('queue.connections.beanstalkd.host'); + $beanstalkdQueue = config('queue.connections.beanstalkd.queue'); + $sqsPrefix = config('queue.connections.sqs.prefix'); + $sqsQueue = config('queue.connections.sqs.queue'); + $sqsSuffix = config('queue.connections.sqs.suffix'); + + return response()->json([ + 'driver' => $driver, + 'connections' => $connections, + 'beanstalkdHost' => $beanstalkdHost, + 'beanstalkdQueue' => $beanstalkdQueue, + 'sqsPrefix' => $sqsPrefix, + 'sqsQueue' => $sqsQueue, + 'sqsSuffix' => $sqsSuffix, + ]); + } + + /** + * Saves queue configuration. + * + * @param \Illuminate\Http\Request $request + * @return \Illuminate\Http\JsonResponse + */ + public function saveQueueConfig(Request $request) + { + $driver = $request->input('driver', 'sync'); + $sqs = $request->input('sqs', config('queue.connections.sqs')); + $beanstalkd = $request->input('beanstalkd', config('queue.connections.beanstalkd')); + + Setting::configure('system.queue.driver', $driver); + Setting::configure('system.queue.sqs', array_merge(config('queue.connections.sqs'), $sqs)); + Setting::configure('system.queue.beanstalkd', array_merge(config('queue.connections.beanstalkd'), $beanstalkd)); + + return response()->json(['status' => 'OK']); + } + + /** + * Loads and sends the services configuration. + * + * @return \Illuminate\Http\JsonResponse + */ + public function getServicesConfig() + { + /** aws service */ + $awsKey = config('services.aws.key', env('AWS_ACCESS_KEY_ID')); + $awsSecret = config('services.aws.secret', env('AWS_SECRET_ACCESS_KEY')); + $awsRegion = config('services.aws.region', env('AWS_DEFAULT_REGION', 'us-east-1')); + + /** ipinfo service */ + $ipinfoApiKey = config('services.ipinfo.api_key', env('IPINFO_API_KEY')); + + /** google maps service */ + $googleMapsApiKey = config('services.google_maps.api_key', env('GOOGLE_MAPS_API_KEY')); + $googleMapsLocale = config('services.google_maps.locale', env('GOOGLE_MAPS_LOCALE', 'us')); + + /** twilio service */ + $twilioSid = config('services.twilio.sid', env('TWILIO_SID')); + $twilioToken = config('services.twilio.token', env('TWILIO_TOKEN')); + $twilioFrom = config('services.twilio.from', env('TWILIO_FROM')); + + return response()->json([ + 'awsKey' => $awsKey, + 'awsSecret' => $awsSecret, + 'awsRegion' => $awsRegion, + 'ipinfoApiKey' => $ipinfoApiKey, + 'googleMapsApiKey' => $googleMapsApiKey, + 'googleMapsLocale' => $googleMapsLocale, + 'twilioSid' => $twilioSid, + 'twilioToken' => $twilioToken, + 'twilioFrom' => $twilioFrom, + ]); + } + + /** + * Saves services configuration. + * + * @param \Illuminate\Http\Request $request + * @return \Illuminate\Http\JsonResponse + */ + public function saveServicesConfig(Request $request) + { + $aws = $request->input('aws', config('services.aws')); + $ipinfo = $request->input('ipinfo', config('services.ipinfo')); + $googleMaps = $request->input('googleMaps', config('services.google_maps')); + $twilio = $request->input('twilio', config('services.twilio')); + + Setting::configure('system.services.aws', array_merge(config('services.aws', []), $aws)); + Setting::configure('system.services.ipinfo', array_merge(config('services.ipinfo', []), $ipinfo)); + Setting::configure('system.services.google_maps', array_merge(config('services.google_maps', []), $googleMaps)); + Setting::configure('system.services.twilio', array_merge(config('services.twilio', []), $twilio)); + + return response()->json(['status' => 'OK']); } } diff --git a/src/Mail/TestEmail.php b/src/Mail/TestEmail.php new file mode 100644 index 0000000..5594592 --- /dev/null +++ b/src/Mail/TestEmail.php @@ -0,0 +1,32 @@ +subject($subject) + ->html((new MailMessage) + ->greeting($subject) + ->line('Hello! This is a test email from Fleetbase to confirm that your mail configuration works.') + ->render() + ); + } +} diff --git a/src/Models/Model.php b/src/Models/Model.php index bf007c5..77733f4 100644 --- a/src/Models/Model.php +++ b/src/Models/Model.php @@ -4,7 +4,6 @@ use Illuminate\Database\Eloquent\Model as EloquentModel; use Illuminate\Database\Eloquent\SoftDeletes; -use Illuminate\Support\Facades\Schema; use Fleetbase\Traits\HasCacheableAttributes; use Fleetbase\Traits\ClearsHttpCache; use Fleetbase\Traits\Expandable; diff --git a/src/Models/Setting.php b/src/Models/Setting.php index 7ee4318..dcf64f6 100644 --- a/src/Models/Setting.php +++ b/src/Models/Setting.php @@ -3,12 +3,31 @@ namespace Fleetbase\Models; use Fleetbase\Casts\Json; -use Fleetbase\Traits\HasApiModelBehavior; +use Illuminate\Database\Eloquent\Model as EloquentModel; -class Setting extends Model +class Setting extends EloquentModel { - use HasApiModelBehavior; - + /** + * Create a new instance of the model. + * + * @param array $attributes The attributes to set on the model. + * + * @return void + */ + public function __construct(array $attributes = []) + { + parent::__construct($attributes); + + $this->connection = config('fleetbase.db.connection'); + } + + /** + * No timestamp columns. + * + * @var boolean + */ + public $timestamps = false; + /** * The database table used by the model. * @@ -62,4 +81,69 @@ class Setting extends Model protected $casts = [ 'value' => Json::class ]; + + /** + * Finds a system setting. + * + * @param string $key + * @param mixed $defaultValue + * @return mixed + */ + public static function system($key, $defaultValue = null) + { + $segments = explode('.', $key); + $settingKey = 'system.' . $key; + $queryKey = 'system.' . $segments[0] . '.' . $segments[1]; + + if (count($segments) >= 3) { + // Remove first two segments, join remaining ones + $subKey = implode('.', array_slice($segments, 2)); + + // Query the database for the main setting + $setting = static::where('key', $queryKey)->first(); + + if ($setting) { + // Get the sub value from the setting value + return data_get($setting->value, $subKey); + } + } else { + $setting = static::where('key', $settingKey)->first(); + + if ($setting) { + return $setting->value; + } + } + + return $defaultValue; + } + + /** + * Updates a system setting. + * + * @param string $key + * @param mixed $defaultValue + * @return mixed + */ + public static function configureSystem($key, $value = null) + { + return static::configure('system.' . $key, $value); + } + + /** + * Updates a system setting. + * + * @param string $key + * @param mixed $defaultValue + * @return mixed + */ + public static function configure($key, $value = null) + { + return static::updateOrCreate( + ['key' => $key], + [ + 'key' => $key, + 'value' => $value + ] + ); + } } diff --git a/src/Providers/CoreServiceProvider.php b/src/Providers/CoreServiceProvider.php index d8c81e6..d130a82 100644 --- a/src/Providers/CoreServiceProvider.php +++ b/src/Providers/CoreServiceProvider.php @@ -2,6 +2,7 @@ namespace Fleetbase\Providers; +use Fleetbase\Models\Setting; use Fleetbase\Support\Expansion; use Fleetbase\Support\Utils; use Laravel\Cashier\Cashier; @@ -72,7 +73,6 @@ public function boot() $this->mergeConfigFrom(__DIR__ . '/../../config/database.connections.php', 'database.connections'); $this->mergeConfigFrom(__DIR__ . '/../../config/database.redis.php', 'database.redis'); $this->mergeConfigFrom(__DIR__ . '/../../config/broadcasting.connections.php', 'broadcasting.connections'); - $this->mergeConfigFrom(__DIR__ . '/../../config/queue.connections.php', 'queue.connections'); $this->mergeConfigFrom(__DIR__ . '/../../config/fleetbase.php', 'fleetbase'); $this->mergeConfigFrom(__DIR__ . '/../../config/auth.php', 'auth'); $this->mergeConfigFrom(__DIR__ . '/../../config/sanctum.php', 'sanctum'); @@ -81,6 +81,74 @@ public function boot() $this->mergeConfigFrom(__DIR__ . '/../../config/permission.php', 'permission'); $this->mergeConfigFrom(__DIR__ . '/../../config/activitylog.php', 'activitylog'); $this->mergeConfigFrom(__DIR__ . '/../../config/excel.php', 'excel'); + $this->mergeConfigFromSettings(); + } + + public function mergeConfigFromSettings() + { + $putsenv = [ + 'services.aws' => ['key' => 'AWS_ACCESS_KEY_ID', 'secret' => 'AWS_SECRET_ACCESS_KEY', 'region' => 'AWS_DEFAULT_REGION'], + 'services.google_maps' => ['api_key' => 'GOOGLE_MAPS_API_KEY', 'locale' => 'GOOGLE_MAPS_LOCALE'], + 'services.twilio' => ['sid' => 'TWILIO_SID', 'token' => 'TWILIO_TOKEN', 'from' => 'TWILIO_FROM'] + ]; + + $settings = [ + ['settingsKey' => 'filesystem.driver', 'configKey' => 'filesystems.default'], + ['settingsKey' => 'filesystem.s3', 'configKey' => 'filesystems.disks.s3'], + ['settingsKey' => 'mail.mailer', 'configKey' => 'mail.default'], + ['settingsKey' => 'mail.from', 'configKey' => 'mail.from'], + ['settingsKey' => 'mail.smtp', 'configKey' => 'mail.mailers.smtp'], + ['settingsKey' => 'queue.driver', 'configKey' => 'queue.default'], + ['settingsKey' => 'queue.sqs', 'configKey' => 'queue.connections.sqs'], + ['settingsKey' => 'queue.beanstalkd', 'configKey' => 'queue.connections.beanstalkd'], + ['settingsKey' => 'services.aws', 'configKey' => 'services.aws'], + ['settingsKey' => 'services.aws.key', 'configKey' => 'queue.connections.sqs.key'], + ['settingsKey' => 'services.aws.secret', 'configKey' => 'queue.connections.sqs.secret'], + ['settingsKey' => 'services.aws.region', 'configKey' => 'queue.connections.sqs.region'], + ['settingsKey' => 'services.aws.key', 'configKey' => 'cache.stores.dynamodb.key'], + ['settingsKey' => 'services.aws.secret', 'configKey' => 'cache.stores.dynamodb.secret'], + ['settingsKey' => 'services.aws.region', 'configKey' => 'cache.stores.dynamodb.region'], + ['settingsKey' => 'services.aws.key', 'configKey' => 'filesystems.disks.s3.key'], + ['settingsKey' => 'services.aws.secret', 'configKey' => 'filesystems.disks.s3.secret'], + ['settingsKey' => 'services.aws.region', 'configKey' => 'filesystems.disks.s3.region'], + ['settingsKey' => 'services.aws.key', 'configKey' => 'mail.mailers.ses.key'], + ['settingsKey' => 'services.aws.secret', 'configKey' => 'mail.mailers.ses.secret'], + ['settingsKey' => 'services.aws.region', 'configKey' => 'mail.mailers.ses.region'], + ['settingsKey' => 'services.aws.key', 'configKey' => 'services.ses.key'], + ['settingsKey' => 'services.aws.secret', 'configKey' => 'services.ses.secret'], + ['settingsKey' => 'services.aws.region', 'configKey' => 'services.ses.region'], + ['settingsKey' => 'services.google_maps', 'configKey' => 'services.google_maps'], + ['settingsKey' => 'services.twilio', 'configKey' => 'services.twilio'], + ['settingsKey' => 'services.twilio', 'configKey' => 'twilio.connections.twilio'], + ['settingsKey' => 'services.ipinfo', 'configKey' => 'services.ipinfo'], + ['settingsKey' => 'services.ipinfo', 'configKey' => 'fleetbase.services.ipinfo'], + ]; + + foreach ($settings as $setting) { + $settingsKey = $setting['settingsKey']; + $configKey = $setting['configKey']; + $value = Setting::system($settingsKey); + + if ($value) { + // some settings should set env variables to be accessed throughout entire application + if (in_array($settingsKey, array_keys($putsenv))) { + $environmentVariables = $putsenv[$settingsKey]; + + foreach ($environmentVariables as $configEnvKey => $envKey) { + putenv($envKey . '="' . data_get($value, $configEnvKey) . '"'); + } + } + + // Fetch the current config array + $config = config()->all(); + + // Update the specific value in the config array + Arr::set($config, $configKey, $value); + + // Set the entire config array + config($config); + } + } } /** diff --git a/src/routes.php b/src/routes.php index 5021ccd..de40d15 100644 --- a/src/routes.php +++ b/src/routes.php @@ -72,7 +72,16 @@ function ($router, $controller) { $router->fleetbaseRoutes( 'settings', function ($router, $controller) { - $router->post('test-mysql-connection', $controller('testMysqlConnection')); + $router->get('overview', $controller('adminOverview')); + $router->get('filesystem-config', $controller('getFilesystemConfig')); + $router->post('filesystem-config', $controller('saveFilesystemConfig')); + $router->get('mail-config', $controller('getMailConfig')); + $router->post('mail-config', $controller('saveMailConfig')); + $router->post('test-mail-config', $controller('testMailConfig')); + $router->get('queue-config', $controller('getQueueConfig')); + $router->post('queue-config', $controller('saveQueueConfig')); + $router->get('services-config', $controller('getServicesConfig')); + $router->post('services-config', $controller('saveServicesConfig')); } ); $router->fleetbaseRoutes('api-events');