@fleetbase/fleetops-engine 0.6.69 → 0.6.70
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/RELEASE.md +41 -8
- package/addon/components/admin/telematics-settings.hbs +143 -0
- package/addon/components/admin/telematics-settings.js +145 -0
- package/addon/components/fuel-integration/hub.hbs +1 -1
- package/addon/components/layout/fleet-ops-sidebar.js +37 -17
- package/addon/components/map/leaflet-live-map.hbs +4 -242
- package/addon/components/map/leaflet-live-map.js +2 -1
- package/addon/components/map/marker-card/driver.hbs +57 -0
- package/addon/components/map/marker-card/driver.js +3 -0
- package/addon/components/map/marker-card/vehicle.hbs +78 -0
- package/addon/components/map/marker-card/vehicle.js +3 -0
- package/addon/components/telematic/hub.hbs +1 -1
- package/addon/components/widget/live-fleet.hbs +8 -40
- package/addon/controllers/analytics/reports/index.js +5 -0
- package/addon/controllers/connectivity/devices/index.js +4 -0
- package/addon/controllers/connectivity/fuel-providers/index.js +6 -4
- package/addon/controllers/connectivity/sensors/index.js +4 -0
- package/addon/controllers/connectivity/telematics/index.js +4 -0
- package/addon/controllers/maintenance/equipment/index.js +11 -4
- package/addon/controllers/maintenance/inspection-forms/index.js +2 -2
- package/addon/controllers/maintenance/inspection-submissions/index.js +8 -2
- package/addon/controllers/maintenance/maintenances/index.js +4 -0
- package/addon/controllers/maintenance/parts/index.js +11 -4
- package/addon/controllers/maintenance/schedules/index.js +17 -4
- package/addon/controllers/maintenance/work-orders/index.js +11 -4
- package/addon/controllers/management/contacts/index.js +4 -0
- package/addon/controllers/management/drivers/index.js +4 -0
- package/addon/controllers/management/fleets/index.js +4 -0
- package/addon/controllers/management/fuel-reports/index.js +4 -0
- package/addon/controllers/management/fuel-transactions/index.js +9 -7
- package/addon/controllers/management/issues/index.js +4 -0
- package/addon/controllers/management/places/index.js +4 -0
- package/addon/controllers/management/vehicles/index.js +4 -0
- package/addon/controllers/management/vendors/index.js +4 -0
- package/addon/controllers/operations/orders/index/details.js +30 -1
- package/addon/controllers/operations/orders/index.js +7 -0
- package/addon/controllers/operations/service-rates/index.js +3 -0
- package/addon/controllers/settings/index.js +13 -0
- package/addon/controllers/settings/telematics.js +113 -0
- package/addon/extension.js +38 -6
- package/addon/routes/analytics/index.js +14 -1
- package/addon/routes/analytics/reports/index/details.js +1 -1
- package/addon/routes/analytics/reports/index/edit.js +1 -1
- package/addon/routes/analytics/reports/index/new.js +14 -1
- package/addon/routes/analytics/reports.js +14 -1
- package/addon/routes/connectivity/devices/index/new.js +14 -1
- package/addon/routes/connectivity/devices.js +14 -1
- package/addon/routes/connectivity/events.js +14 -1
- package/addon/routes/connectivity/fuel-providers/details/transactions.js +12 -0
- package/addon/routes/connectivity/fuel-providers/details.js +9 -0
- package/addon/routes/connectivity/fuel-providers/edit.js +9 -0
- package/addon/routes/connectivity/fuel-providers/new.js +14 -1
- package/addon/routes/connectivity/fuel-providers.js +14 -1
- package/addon/routes/connectivity/sensors/index/new.js +14 -1
- package/addon/routes/connectivity/sensors.js +14 -1
- package/addon/routes/connectivity/telematics/new.js +14 -1
- package/addon/routes/connectivity/telematics.js +14 -1
- package/addon/routes/connectivity/tracking.js +14 -1
- package/addon/routes/maintenance/equipment/index/details.js +2 -2
- package/addon/routes/maintenance/equipment/index/edit.js +2 -2
- package/addon/routes/maintenance/equipment/index/new.js +14 -1
- package/addon/routes/maintenance/equipment.js +14 -1
- package/addon/routes/maintenance/index.js +14 -1
- package/addon/routes/maintenance/inspection-forms/index/details.js +10 -1
- package/addon/routes/maintenance/inspection-forms/index/edit.js +10 -1
- package/addon/routes/maintenance/inspection-forms/index/new.js +14 -1
- package/addon/routes/maintenance/inspection-forms.js +14 -1
- package/addon/routes/maintenance/inspection-submissions/index/details.js +10 -1
- package/addon/routes/maintenance/inspection-submissions/index/edit.js +10 -1
- package/addon/routes/maintenance/inspection-submissions/index/new.js +14 -1
- package/addon/routes/maintenance/inspection-submissions.js +14 -1
- package/addon/routes/maintenance/maintenances/index/details.js +2 -2
- package/addon/routes/maintenance/maintenances/index/edit.js +2 -2
- package/addon/routes/maintenance/maintenances/index/new.js +14 -1
- package/addon/routes/maintenance/maintenances.js +14 -1
- package/addon/routes/maintenance/parts/index/details.js +2 -2
- package/addon/routes/maintenance/parts/index/edit.js +2 -2
- package/addon/routes/maintenance/parts/index/new.js +14 -1
- package/addon/routes/maintenance/parts.js +14 -1
- package/addon/routes/maintenance/schedules/index/details.js +2 -2
- package/addon/routes/maintenance/schedules/index/edit.js +2 -2
- package/addon/routes/maintenance/schedules/index/new.js +15 -1
- package/addon/routes/maintenance/schedules.js +15 -1
- package/addon/routes/maintenance/work-orders/index/details.js +2 -2
- package/addon/routes/maintenance/work-orders/index/edit.js +2 -2
- package/addon/routes/maintenance/work-orders/index/new.js +14 -1
- package/addon/routes/maintenance/work-orders.js +14 -1
- package/addon/routes/management/fuel-transactions/index/details.js +9 -0
- package/addon/routes/management/fuel-transactions.js +14 -1
- package/addon/routes/management/index.js +13 -0
- package/addon/routes/management/trailers.js +16 -0
- package/addon/routes/management/vendors/integrated/details.js +14 -1
- package/addon/routes/management/vendors/integrated/edit.js +14 -1
- package/addon/routes/management/vendors/integrated/new.js +14 -1
- package/addon/routes/management/vendors/integrated.js +14 -1
- package/addon/routes/operations/orders.js +40 -1
- package/addon/routes/operations/routes/index/details.js +14 -1
- package/addon/routes/operations/routes/index/new.js +13 -0
- package/addon/routes/operations/routes.js +14 -1
- package/addon/routes/operations/service-rates/index/new.js +11 -0
- package/addon/routes/operations/service-rates.js +14 -1
- package/addon/routes/settings/avatars.js +14 -1
- package/addon/routes/settings/custom-fields.js +14 -1
- package/addon/routes/settings/map.js +14 -1
- package/addon/routes/settings/notifications.js +11 -0
- package/addon/routes/settings/orchestrator.js +1 -1
- package/addon/routes/settings/payments/index.js +1 -1
- package/addon/routes/settings/routing.js +14 -1
- package/addon/routes/settings/scheduling.js +14 -1
- package/addon/routes/settings/telematics.js +21 -0
- package/addon/routes/virtual.js +11 -0
- package/addon/routes.js +1 -0
- package/addon/templates/settings/telematics.hbs +70 -0
- package/app/components/admin/telematics-settings.js +1 -0
- package/app/components/map/marker-card/driver.js +1 -0
- package/app/components/map/marker-card/vehicle.js +1 -0
- package/app/controllers/settings/telematics.js +1 -0
- package/app/routes/settings/telematics.js +1 -0
- package/app/templates/settings/telematics.js +1 -0
- package/composer.json +2 -2
- package/docs/AFAQY.md +1 -1
- package/docs/TELEMATICS_QUEUES.md +1 -1
- package/docs/TELEMETRY_ARCHITECTURE.md +72 -1
- package/extension.json +1 -1
- package/package.json +1 -1
- package/server/config/telemetry.php +12 -0
- package/server/migrations/2026_09_23_000001_add_retention_index_to_device_events.php +40 -0
- package/server/migrations/2026_09_23_000002_add_retention_index_to_positions.php +40 -0
- package/server/migrations/2026_09_23_000003_add_retention_index_to_telematic_sync_runs.php +40 -0
- package/server/src/Auth/Schemas/FleetOps.php +104 -5
- package/server/src/Console/Commands/DrainTelematicInbox.php +3 -13
- package/server/src/Console/Commands/ProcessOperationalAlerts.php +3 -3
- package/server/src/Console/Commands/PruneTelematicsData.php +318 -0
- package/server/src/Http/Controllers/Api/v1/OrchestrationController.php +9 -0
- package/server/src/Http/Controllers/FleetOpsController.php +21 -0
- package/server/src/Http/Controllers/Internal/v1/AnalyticsController.php +11 -0
- package/server/src/Http/Controllers/Internal/v1/ContactController.php +11 -0
- package/server/src/Http/Controllers/Internal/v1/CustomerController.php +14 -0
- package/server/src/Http/Controllers/Internal/v1/DeviceController.php +13 -0
- package/server/src/Http/Controllers/Internal/v1/DeviceEventController.php +11 -0
- package/server/src/Http/Controllers/Internal/v1/DriverController.php +22 -0
- package/server/src/Http/Controllers/Internal/v1/FuelProviderConnectionController.php +13 -0
- package/server/src/Http/Controllers/Internal/v1/FuelProviderTransactionController.php +15 -0
- package/server/src/Http/Controllers/Internal/v1/FuelReportController.php +9 -3
- package/server/src/Http/Controllers/Internal/v1/InspectionFormController.php +15 -0
- package/server/src/Http/Controllers/Internal/v1/LiveController.php +16 -0
- package/server/src/Http/Controllers/Internal/v1/MaintenanceController.php +15 -0
- package/server/src/Http/Controllers/Internal/v1/MaintenanceScheduleController.php +15 -0
- package/server/src/Http/Controllers/Internal/v1/ManifestController.php +15 -0
- package/server/src/Http/Controllers/Internal/v1/MetricsController.php +11 -0
- package/server/src/Http/Controllers/Internal/v1/NavigatorController.php +42 -1
- package/server/src/Http/Controllers/Internal/v1/OrchestrationController.php +12 -0
- package/server/src/Http/Controllers/Internal/v1/OrderController.php +22 -0
- package/server/src/Http/Controllers/Internal/v1/PaymentController.php +13 -0
- package/server/src/Http/Controllers/Internal/v1/RadarController.php +19 -0
- package/server/src/Http/Controllers/Internal/v1/ServiceAreaController.php +9 -3
- package/server/src/Http/Controllers/Internal/v1/SettingController.php +465 -14
- package/server/src/Http/Controllers/Internal/v1/TelematicController.php +21 -0
- package/server/src/Http/Controllers/Internal/v1/TrailerController.php +21 -0
- package/server/src/Http/Controllers/Internal/v1/VehicleController.php +21 -0
- package/server/src/Http/Controllers/Internal/v1/VendorController.php +17 -0
- package/server/src/Http/Controllers/Internal/v1/WorkOrderController.php +11 -0
- package/server/src/Jobs/DispatchTelematicsRetentionJobs.php +70 -0
- package/server/src/Jobs/PruneTelematicsDataJob.php +74 -0
- package/server/src/Listeners/NotifyDriverOnShiftChange.php +3 -3
- package/server/src/Mail/CustomerCredentialsMail.php +1 -1
- package/server/src/Orchestration/Engines/VroomOrchestrationEngine.php +9 -1
- package/server/src/Providers/FleetOpsServiceProvider.php +3 -0
- package/server/src/Support/Analytics/LiveFleet.php +18 -2
- package/server/src/Support/Authorization.php +103 -0
- package/server/src/Support/Database/TableIndexes.php +66 -0
- package/server/src/Support/OrderTracker.php +2 -2
- package/server/src/Support/Reporting/FleetOpsReportSchema.php +476 -116
- package/server/src/Support/Telematics/Retention/RetentionPolicy.php +300 -0
- package/server/src/Support/Telematics/Retention/TelemetryActivity.php +40 -0
- package/server/src/Support/Telematics/TelematicService.php +12 -2
- package/server/src/Support/Telematics/Telemetry/Ingestor.php +4 -2
- package/server/src/Tracking/TrackingIntelligenceService.php +1 -1
- package/server/src/Tracking/TrackingOptions.php +2 -2
- package/server/src/Traits/AuthorizesMethods.php +37 -0
- package/server/src/routes.php +9 -1
- package/server/tests/AnalyticsRoutesTest.php +29 -2
- package/server/tests/Feature/Http/AfaqyRealtimeIngestionTest.php +16 -1
- package/server/tests/Feature/Http/Api/TelematicsRetentionIndexMigrationTest.php +115 -0
- package/server/tests/Feature/Http/Internal/SettingControllerHelpersTest.php +71 -0
- package/server/tests/Feature/Http/Internal/TelematicsStorageDeadlinesTest.php +119 -0
- package/server/tests/InternalImportExportControllerContractsTest.php +5 -8
- package/server/tests/NavigatorControllerContractsTest.php +36 -4
- package/server/tests/NotificationAndMailContractsTest.php +31 -0
- package/server/tests/ObserverContractsTest.php +1 -1
- package/server/tests/OrchestratorConsumableApiTest.php +42 -0
- package/server/tests/ProviderContractsTest.php +10 -0
- package/server/tests/ReportSchemaContractsTest.php +120 -6
- package/server/tests/SettingControllerContractsTest.php +429 -18
- package/server/tests/SmallControllerContractsTest.php +8 -5
- package/server/tests/Support/PruneTelematicsDataProbe.php +55 -0
- package/server/tests/Unit/Console/Commands/ProcessOperationalAlertsCommandTest.php +2 -2
- package/server/tests/Unit/Console/PruneTelematicsDataCommandTest.php +353 -0
- package/server/tests/Unit/Jobs/DispatchTelematicsRetentionJobsTest.php +114 -0
- package/server/tests/Unit/Jobs/PruneTelematicsDataJobTest.php +60 -0
- package/server/tests/Unit/Orchestration/VroomEngineTransportAndSettingsTest.php +20 -0
- package/server/tests/Unit/Support/Analytics/LiveFleetTest.php +6 -0
- package/server/tests/Unit/Support/AuthorizationTest.php +142 -0
- package/server/tests/Unit/Support/MaintainableAndOperationalAlertsTest.php +12 -1
- package/server/tests/Unit/Support/MoreQuerySeamsTest.php +11 -2
- package/server/tests/Unit/Support/Telematics/Retention/RetentionPolicyTest.php +190 -0
- package/server/tests/Unit/Support/Telematics/Retention/TelemetryActivityTest.php +68 -0
- package/server/tests/Unit/Tracking/TrackingOptionsCompanySettingsTest.php +109 -0
- package/translations/en-us.yaml +48 -0
|
@@ -2,18 +2,54 @@
|
|
|
2
2
|
|
|
3
3
|
namespace Fleetbase\FleetOps\Http\Controllers\Internal\v1;
|
|
4
4
|
|
|
5
|
+
use Fleetbase\FleetOps\Jobs\DispatchTelematicsRetentionJobs;
|
|
6
|
+
use Fleetbase\FleetOps\Support\Telematics\Retention\RetentionPolicy;
|
|
7
|
+
use Fleetbase\FleetOps\Support\Telematics\Telemetry\Queue;
|
|
5
8
|
use Fleetbase\FleetOps\Tracking\TrackingProviderRegistry;
|
|
9
|
+
use Fleetbase\FleetOps\Traits\AuthorizesMethods;
|
|
6
10
|
use Fleetbase\Http\Controllers\Controller;
|
|
7
11
|
use Fleetbase\Models\Setting;
|
|
8
12
|
use Fleetbase\Support\Auth;
|
|
9
13
|
use Fleetbase\Support\NotificationRegistry;
|
|
14
|
+
use Illuminate\Database\MySqlConnection;
|
|
15
|
+
use Illuminate\Database\QueryException;
|
|
10
16
|
use Illuminate\Http\Request;
|
|
17
|
+
use Illuminate\Support\Facades\DB;
|
|
11
18
|
|
|
12
19
|
/**
|
|
13
20
|
* Class SettingController.
|
|
14
21
|
*/
|
|
15
22
|
class SettingController extends Controller
|
|
16
23
|
{
|
|
24
|
+
use AuthorizesMethods;
|
|
25
|
+
|
|
26
|
+
public function __construct()
|
|
27
|
+
{
|
|
28
|
+
$this->authorizeMethods([
|
|
29
|
+
'saveEntityEditingSettings' => 'update navigator-settings',
|
|
30
|
+
'savedDriverOnboardSettings' => 'update navigator-settings',
|
|
31
|
+
'saveCustomerEnabledOrderConfigs' => 'update order-config',
|
|
32
|
+
'saveCustomerPortalPaymentConfig' => 'update payments',
|
|
33
|
+
'saveNotificationSettings' => 'update notification-settings',
|
|
34
|
+
'saveRoutingSettings' => 'update routing-settings',
|
|
35
|
+
'saveTrackingSettings' => 'update tracking-settings',
|
|
36
|
+
'getAdminTrackingSettings' => 'admin',
|
|
37
|
+
'saveAdminTrackingSettings' => 'admin',
|
|
38
|
+
'saveMapSettings' => 'update map-settings',
|
|
39
|
+
'getAdminMapSettings' => 'admin',
|
|
40
|
+
'saveAdminMapSettings' => 'admin',
|
|
41
|
+
'saveSchedulingSettings' => 'update scheduling-settings',
|
|
42
|
+
'saveOrchestratorSettings' => 'update routing-settings',
|
|
43
|
+
'saveOrchestratorCardFields' => 'update routing-settings',
|
|
44
|
+
'getAdminTelematicsSettings' => 'admin',
|
|
45
|
+
'saveAdminTelematicsSettings' => 'admin',
|
|
46
|
+
'getTelematicsSettings' => 'view telematics-settings',
|
|
47
|
+
'saveTelematicsSettings' => 'update telematics-settings',
|
|
48
|
+
'getTelematicsStorageUsage' => 'admin',
|
|
49
|
+
'runTelematicsRetention' => 'admin',
|
|
50
|
+
]);
|
|
51
|
+
}
|
|
52
|
+
|
|
17
53
|
/**
|
|
18
54
|
* Save entity editing settings.
|
|
19
55
|
*
|
|
@@ -21,37 +57,54 @@ class SettingController extends Controller
|
|
|
21
57
|
*/
|
|
22
58
|
public function saveEntityEditingSettings(Request $request)
|
|
23
59
|
{
|
|
24
|
-
|
|
60
|
+
// The setting is one platform-wide map keyed by order config id. Only this
|
|
61
|
+
// company's order configs may be written, and other companies' entries are kept.
|
|
62
|
+
$ownKeys = $this->companyOrderConfigKeys();
|
|
63
|
+
$incoming = array_intersect_key((array) $request->input('entityEditingSettings', []), array_flip($ownKeys));
|
|
64
|
+
$existing = (array) ($this->settingValue('fleet-ops.entity-editing-settings') ?? []);
|
|
65
|
+
$merged = array_merge(array_diff_key($existing, array_flip($ownKeys)), $incoming);
|
|
25
66
|
|
|
26
|
-
|
|
27
|
-
$this->configureSetting('fleet-ops.entity-editing-settings', $entityEditingSettings);
|
|
67
|
+
$this->configureSetting('fleet-ops.entity-editing-settings', $merged);
|
|
28
68
|
|
|
29
|
-
return response()->json(['entityEditingSettings' => $
|
|
69
|
+
return response()->json(['entityEditingSettings' => $incoming]);
|
|
30
70
|
}
|
|
31
71
|
|
|
32
72
|
/**
|
|
33
|
-
* Retrieve entity editing settings.
|
|
73
|
+
* Retrieve entity editing settings for this company's order configs.
|
|
34
74
|
*
|
|
35
75
|
* @return \Illuminate\Http\JsonResponse
|
|
36
76
|
*/
|
|
37
77
|
public function getEntityEditingSettings()
|
|
38
78
|
{
|
|
39
|
-
$entityEditingSettings
|
|
40
|
-
|
|
41
|
-
$entityEditingSettings = [];
|
|
42
|
-
}
|
|
79
|
+
$entityEditingSettings = (array) ($this->settingValue('fleet-ops.entity-editing-settings') ?? []);
|
|
80
|
+
$entityEditingSettings = array_intersect_key($entityEditingSettings, array_flip($this->companyOrderConfigKeys()));
|
|
43
81
|
|
|
44
82
|
return response()->json(['entityEditingSettings' => $entityEditingSettings]);
|
|
45
83
|
}
|
|
46
84
|
|
|
47
85
|
/**
|
|
48
|
-
*
|
|
86
|
+
* Ids (uuid and public id) of the session company's order configs.
|
|
87
|
+
*/
|
|
88
|
+
protected function companyOrderConfigKeys(): array
|
|
89
|
+
{
|
|
90
|
+
return \Fleetbase\FleetOps\Models\OrderConfig::where('company_uuid', session('company'))
|
|
91
|
+
->get(['uuid', 'public_id'])
|
|
92
|
+
->flatMap(fn ($config) => array_filter([$config->uuid, $config->public_id]))
|
|
93
|
+
->values()
|
|
94
|
+
->all();
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Retrieve driver onboard settings for the session company.
|
|
99
|
+
*
|
|
100
|
+
* The route still carries a company id for backwards compatibility, but only
|
|
101
|
+
* the session company's settings are ever returned.
|
|
49
102
|
*
|
|
50
103
|
* @return \Illuminate\Http\JsonResponse
|
|
51
104
|
*/
|
|
52
|
-
public function getDriverOnboardSettings($companyId)
|
|
105
|
+
public function getDriverOnboardSettings($companyId = null)
|
|
53
106
|
{
|
|
54
|
-
$driverOnboardSettings = $this->settingValue('fleet-ops.driver-onboard-settings.' .
|
|
107
|
+
$driverOnboardSettings = $this->settingValue('fleet-ops.driver-onboard-settings.' . session('company'));
|
|
55
108
|
if (!$driverOnboardSettings) {
|
|
56
109
|
$driverOnboardSettings = [];
|
|
57
110
|
}
|
|
@@ -66,9 +119,10 @@ class SettingController extends Controller
|
|
|
66
119
|
*/
|
|
67
120
|
public function savedDriverOnboardSettings(Request $request)
|
|
68
121
|
{
|
|
69
|
-
$driverOnboardSettings
|
|
122
|
+
$driverOnboardSettings = $request->array('driverOnboardSettings', []);
|
|
123
|
+
$driverOnboardSettings['companyId'] = session('company');
|
|
70
124
|
|
|
71
|
-
if ($driverOnboardSettings['enableDriverOnboardFromApp']
|
|
125
|
+
if (empty($driverOnboardSettings['enableDriverOnboardFromApp'])) {
|
|
72
126
|
$driverOnboardSettings['driverMustProvideOnboardDoucments'] = false;
|
|
73
127
|
$driverOnboardSettings['requiredOnboardDocuments'] = [];
|
|
74
128
|
$driverOnboardSettings['driverOnboardAppMethod'] = '';
|
|
@@ -628,6 +682,403 @@ class SettingController extends Controller
|
|
|
628
682
|
})->values()->all();
|
|
629
683
|
}
|
|
630
684
|
|
|
685
|
+
/**
|
|
686
|
+
* Retrieve customer history preferences for the current company.
|
|
687
|
+
*
|
|
688
|
+
* Company values fall back to the system defaults (admin setting over
|
|
689
|
+
* package config); the response carries both so the UI can show them.
|
|
690
|
+
*
|
|
691
|
+
* @return \Illuminate\Http\JsonResponse
|
|
692
|
+
*/
|
|
693
|
+
public function getTelematicsSettings()
|
|
694
|
+
{
|
|
695
|
+
if (!$this->currentCompany()) {
|
|
696
|
+
return response()->error('No company session.', 401);
|
|
697
|
+
}
|
|
698
|
+
|
|
699
|
+
return response()->json($this->telematicsCompanySettings((array) $this->lookupFromCompanySetting(RetentionPolicy::SETTING_KEY, [])));
|
|
700
|
+
}
|
|
701
|
+
|
|
702
|
+
/**
|
|
703
|
+
* Save customer history preferences within the administrator's policy.
|
|
704
|
+
*
|
|
705
|
+
* @return \Illuminate\Http\JsonResponse
|
|
706
|
+
*/
|
|
707
|
+
public function saveTelematicsSettings(Request $request)
|
|
708
|
+
{
|
|
709
|
+
$company = $this->currentCompany();
|
|
710
|
+
if (!$company) {
|
|
711
|
+
return response()->error('No company session.', 401);
|
|
712
|
+
}
|
|
713
|
+
|
|
714
|
+
$request->validate([
|
|
715
|
+
'event_retention_days' => ['nullable', 'integer', 'min:0', 'max:3650'],
|
|
716
|
+
'position_retention_days' => ['nullable', 'integer', 'min:0', 'max:3650'],
|
|
717
|
+
]);
|
|
718
|
+
|
|
719
|
+
$saved = $this->withTelematicsPolicyLock(function () use ($request) {
|
|
720
|
+
$preferences = RetentionPolicy::constrainCompanyPreferences($request->only(RetentionPolicy::HISTORY_KEYS), $this->telematicsDefaults());
|
|
721
|
+
|
|
722
|
+
return $this->configureCompanySetting(RetentionPolicy::SETTING_KEY, $preferences);
|
|
723
|
+
});
|
|
724
|
+
if ($saved === false) {
|
|
725
|
+
return response()->error('Unable to save telematics history preferences.', 500);
|
|
726
|
+
}
|
|
727
|
+
RetentionPolicy::flush($company->uuid);
|
|
728
|
+
|
|
729
|
+
return response()->json(array_merge($this->getTelematicsSettings()->getData(true), [
|
|
730
|
+
'status' => 'ok',
|
|
731
|
+
'message' => 'Telematics history preferences successfully saved.',
|
|
732
|
+
]));
|
|
733
|
+
}
|
|
734
|
+
|
|
735
|
+
/**
|
|
736
|
+
* Retrieve the system-wide telematics retention defaults.
|
|
737
|
+
*
|
|
738
|
+
* @return \Illuminate\Http\JsonResponse
|
|
739
|
+
*/
|
|
740
|
+
public function getAdminTelematicsSettings()
|
|
741
|
+
{
|
|
742
|
+
return response()->json(array_merge($this->telematicsDefaults(), [
|
|
743
|
+
'limits' => RetentionPolicy::LIMITS,
|
|
744
|
+
]));
|
|
745
|
+
}
|
|
746
|
+
|
|
747
|
+
/**
|
|
748
|
+
* Save the system-wide telematics retention defaults.
|
|
749
|
+
*
|
|
750
|
+
* @return \Illuminate\Http\JsonResponse
|
|
751
|
+
*/
|
|
752
|
+
public function saveAdminTelematicsSettings(Request $request)
|
|
753
|
+
{
|
|
754
|
+
$request->validate([
|
|
755
|
+
'max_event_retention_days' => ['sometimes', 'integer', 'min:0', 'max:3650'],
|
|
756
|
+
'max_position_retention_days' => ['sometimes', 'integer', 'min:0', 'max:3650'],
|
|
757
|
+
]);
|
|
758
|
+
|
|
759
|
+
try {
|
|
760
|
+
$settings = $this->withTelematicsPolicyLock(function () use ($request) {
|
|
761
|
+
$settings = RetentionPolicy::normalize($request->only(RetentionPolicy::keys()), $this->telematicsDefaults());
|
|
762
|
+
$this->configureSetting(RetentionPolicy::SETTING_KEY, $settings);
|
|
763
|
+
|
|
764
|
+
return $settings;
|
|
765
|
+
});
|
|
766
|
+
$this->reconcileTelematicsCompanyPreferences($settings);
|
|
767
|
+
} finally {
|
|
768
|
+
RetentionPolicy::flush();
|
|
769
|
+
}
|
|
770
|
+
|
|
771
|
+
return response()->json($this->getAdminTelematicsSettings()->getData(true));
|
|
772
|
+
}
|
|
773
|
+
|
|
774
|
+
/**
|
|
775
|
+
* Report system-wide telematics storage, including data without an owner.
|
|
776
|
+
*
|
|
777
|
+
* Use table statistics for MySQL/MariaDB instead of scanning every tenant's
|
|
778
|
+
* history. Oldest-row lookups and fallback counts have a database deadline.
|
|
779
|
+
*
|
|
780
|
+
* @return \Illuminate\Http\JsonResponse
|
|
781
|
+
*/
|
|
782
|
+
public function getTelematicsStorageUsage()
|
|
783
|
+
{
|
|
784
|
+
$ageColumns = [
|
|
785
|
+
'device_events' => 'created_at',
|
|
786
|
+
'positions' => 'created_at',
|
|
787
|
+
'telematic_deliveries' => 'received_at',
|
|
788
|
+
'telematic_sync_runs' => 'created_at',
|
|
789
|
+
];
|
|
790
|
+
$statistics = $this->storageTableStatistics(array_keys($ageColumns));
|
|
791
|
+
$allRows = fn ($query) => $query;
|
|
792
|
+
$tables = [];
|
|
793
|
+
foreach ($ageColumns as $table => $ageColumn) {
|
|
794
|
+
$tables[$table] = isset($statistics[$table])
|
|
795
|
+
? array_merge($statistics[$table], ['oldest' => $this->tableOldest($table, $allRows, $ageColumn)])
|
|
796
|
+
: $this->tableUsage($table, $allRows, $ageColumn);
|
|
797
|
+
}
|
|
798
|
+
|
|
799
|
+
// Payload details require reading JSON-bearing rows, so they are opt-in
|
|
800
|
+
// and omitted if they cannot be counted within the database deadline.
|
|
801
|
+
if (request()->boolean('include_payload_counts', false)) {
|
|
802
|
+
try {
|
|
803
|
+
$rawPayloadRows = $this->tableCount('device_events', fn ($query) => $query->whereNotNull('payload'));
|
|
804
|
+
$compactAfter = (int) $this->telematicsDefaults()['event_compact_after_days'];
|
|
805
|
+
$compactableRows = $compactAfter > 0
|
|
806
|
+
? $this->tableCount('device_events', fn ($query) => $query->whereNotNull('payload')->where('created_at', '<', now()->subDays($compactAfter)->toDateTimeString()))
|
|
807
|
+
: 0;
|
|
808
|
+
|
|
809
|
+
$tables['device_events']['raw_payload_rows'] = $rawPayloadRows;
|
|
810
|
+
$tables['device_events']['compactable_rows'] = $compactableRows;
|
|
811
|
+
} catch (QueryException $exception) {
|
|
812
|
+
if (!$this->isStorageUsageTimeout($exception)) {
|
|
813
|
+
throw $exception;
|
|
814
|
+
}
|
|
815
|
+
}
|
|
816
|
+
}
|
|
817
|
+
|
|
818
|
+
return response()->json([
|
|
819
|
+
'tables' => $tables,
|
|
820
|
+
'scope' => 'system',
|
|
821
|
+
'generated_at' => now()->toISOString(),
|
|
822
|
+
]);
|
|
823
|
+
}
|
|
824
|
+
|
|
825
|
+
/**
|
|
826
|
+
* Queue retention for all companies and orphaned data, independent of session company.
|
|
827
|
+
*
|
|
828
|
+
* @return \Illuminate\Http\JsonResponse
|
|
829
|
+
*/
|
|
830
|
+
public function runTelematicsRetention()
|
|
831
|
+
{
|
|
832
|
+
$connection = (string) config('queue.default', 'sync');
|
|
833
|
+
$driver = config('queue.connections.' . $connection . '.driver', $connection);
|
|
834
|
+
if (in_array($driver, ['sync', 'null'], true)) {
|
|
835
|
+
return response()->error('System-wide telematics cleanup requires an asynchronous queue connection and a running queue worker.', 503);
|
|
836
|
+
}
|
|
837
|
+
|
|
838
|
+
$this->dispatchTelematicsPrune();
|
|
839
|
+
|
|
840
|
+
return response()->json([
|
|
841
|
+
'status' => 'queued',
|
|
842
|
+
'scope' => 'system',
|
|
843
|
+
'message' => 'System-wide telematics cleanup has been queued.',
|
|
844
|
+
], 202);
|
|
845
|
+
}
|
|
846
|
+
|
|
847
|
+
/**
|
|
848
|
+
* System-wide retention defaults: package config overridden by the admin setting.
|
|
849
|
+
*/
|
|
850
|
+
protected function telematicsDefaults(): array
|
|
851
|
+
{
|
|
852
|
+
$config = array_intersect_key((array) config('telematics.telemetry', []), RetentionPolicy::FALLBACKS);
|
|
853
|
+
|
|
854
|
+
return RetentionPolicy::normalize((array) $this->lookupSetting(RetentionPolicy::SETTING_KEY, []), RetentionPolicy::normalize($config, RetentionPolicy::FALLBACKS));
|
|
855
|
+
}
|
|
856
|
+
|
|
857
|
+
/**
|
|
858
|
+
* Customer responses expose history choices and constraints, never internal
|
|
859
|
+
* ingestion, cleanup, storage or activity logging configuration.
|
|
860
|
+
*/
|
|
861
|
+
protected function telematicsCompanySettings(array $stored, ?array $defaults = null): array
|
|
862
|
+
{
|
|
863
|
+
$defaults = $defaults ?? $this->telematicsDefaults();
|
|
864
|
+
$history = array_flip(RetentionPolicy::HISTORY_KEYS);
|
|
865
|
+
$preferences = RetentionPolicy::constrainCompanyPreferences($stored, $defaults);
|
|
866
|
+
$effective = RetentionPolicy::fromCompanyPreferences($preferences, $defaults)->toArray();
|
|
867
|
+
$inherited = RetentionPolicy::fromCompanyPreferences([], $defaults)->toArray();
|
|
868
|
+
|
|
869
|
+
return array_merge(array_intersect_key($effective, $history), [
|
|
870
|
+
'preferences' => array_merge(array_fill_keys(RetentionPolicy::HISTORY_KEYS, null), $preferences),
|
|
871
|
+
'defaults' => array_intersect_key($inherited, $history),
|
|
872
|
+
'policy' => array_intersect_key($defaults, array_flip(array_values(RetentionPolicy::MAXIMUMS))),
|
|
873
|
+
'limits' => array_intersect_key(RetentionPolicy::LIMITS, $history),
|
|
874
|
+
]);
|
|
875
|
+
}
|
|
876
|
+
|
|
877
|
+
/**
|
|
878
|
+
* Serialize policy changes with a customer's policy lookup and preference
|
|
879
|
+
* write, so a request cannot save an old unlimited choice after a new cap.
|
|
880
|
+
* The empty row is only a lock anchor and keeps config fallbacks intact.
|
|
881
|
+
*/
|
|
882
|
+
protected function withTelematicsPolicyLock(\Closure $callback): mixed
|
|
883
|
+
{
|
|
884
|
+
$setting = new Setting();
|
|
885
|
+
if (!$setting->newQuery()->where('key', RetentionPolicy::SETTING_KEY)->exists()) {
|
|
886
|
+
$setting->newQuery()->insertOrIgnore(['key' => RetentionPolicy::SETTING_KEY, 'value' => '[]']);
|
|
887
|
+
}
|
|
888
|
+
|
|
889
|
+
return $setting->getConnection()->transaction(function () use ($setting, $callback) {
|
|
890
|
+
$setting->newQuery()->where('key', RetentionPolicy::SETTING_KEY)->lockForUpdate()->firstOrFail();
|
|
891
|
+
|
|
892
|
+
return $callback();
|
|
893
|
+
}, 3);
|
|
894
|
+
}
|
|
895
|
+
|
|
896
|
+
/**
|
|
897
|
+
* A newly imposed maximum replaces existing unlimited or longer explicit
|
|
898
|
+
* choices for every organization. Keep inherited preferences absent so they
|
|
899
|
+
* continue following future system defaults. Process settings in bounded
|
|
900
|
+
* batches rather than loading every organization or its telemetry history.
|
|
901
|
+
*/
|
|
902
|
+
protected function reconcileTelematicsCompanyPreferences(array $defaults): void
|
|
903
|
+
{
|
|
904
|
+
$maximums = array_intersect_key($defaults, array_flip(array_values(RetentionPolicy::MAXIMUMS)));
|
|
905
|
+
if (!array_filter($maximums, fn ($maximum) => $maximum > 0)) {
|
|
906
|
+
return;
|
|
907
|
+
}
|
|
908
|
+
|
|
909
|
+
Setting::query()
|
|
910
|
+
->where('key', 'like', 'company.%.' . RetentionPolicy::SETTING_KEY)
|
|
911
|
+
->select('id')
|
|
912
|
+
->chunkById(200, function ($settings) {
|
|
913
|
+
foreach ($settings as $setting) {
|
|
914
|
+
// Lock policy then company, as customer saves do. Reread
|
|
915
|
+
// both so a later admin change or customer preference is
|
|
916
|
+
// never overwritten using an earlier batch's snapshot.
|
|
917
|
+
$this->withTelematicsPolicyLock(function () use ($setting) {
|
|
918
|
+
$current = Setting::query()->whereKey($setting->getKey())->lockForUpdate()->first();
|
|
919
|
+
if (!$current) {
|
|
920
|
+
return;
|
|
921
|
+
}
|
|
922
|
+
|
|
923
|
+
$stored = (array) $current->value;
|
|
924
|
+
$preferences = RetentionPolicy::companyPreferences($stored);
|
|
925
|
+
$constrained = RetentionPolicy::constrainCompanyPreferences($preferences, $this->telematicsDefaults());
|
|
926
|
+
if ($preferences === $constrained) {
|
|
927
|
+
return;
|
|
928
|
+
}
|
|
929
|
+
|
|
930
|
+
$current->value = array_replace($stored, $constrained);
|
|
931
|
+
$current->save();
|
|
932
|
+
});
|
|
933
|
+
}
|
|
934
|
+
});
|
|
935
|
+
}
|
|
936
|
+
|
|
937
|
+
protected function tableUsage(string $table, \Closure $scope, string $ageColumn): array
|
|
938
|
+
{
|
|
939
|
+
if (!in_array(DB::connection()->getDriverName(), ['mysql', 'mariadb'], true)) {
|
|
940
|
+
return [
|
|
941
|
+
'rows' => $this->tableCount($table, $scope),
|
|
942
|
+
'oldest' => $this->tableOldest($table, $scope, $ageColumn),
|
|
943
|
+
];
|
|
944
|
+
}
|
|
945
|
+
|
|
946
|
+
$query = $scope(DB::table($table));
|
|
947
|
+
$query->selectRaw('COUNT(*) AS row_count, MIN(' . $query->getGrammar()->wrap($ageColumn) . ') AS oldest');
|
|
948
|
+
|
|
949
|
+
try {
|
|
950
|
+
$usage = $this->storageUsageSelect($query->toSql(), $query->getBindings())[0];
|
|
951
|
+
|
|
952
|
+
return [
|
|
953
|
+
'rows' => (int) $usage->row_count,
|
|
954
|
+
'oldest' => $usage->oldest === null ? null : (string) $usage->oldest,
|
|
955
|
+
];
|
|
956
|
+
} catch (QueryException $exception) {
|
|
957
|
+
if (!$this->isStorageUsageTimeout($exception)) {
|
|
958
|
+
throw $exception;
|
|
959
|
+
}
|
|
960
|
+
}
|
|
961
|
+
|
|
962
|
+
// EXPLAIN does not execute the history scan. The caller's scope is
|
|
963
|
+
// preserved when metadata is unavailable and a count reaches its deadline.
|
|
964
|
+
$estimate = null;
|
|
965
|
+
$query = $scope(DB::table($table))->select($ageColumn);
|
|
966
|
+
try {
|
|
967
|
+
$plan = $this->storageUsageSelect($query->toSql(), $query->getBindings(), true)[0] ?? null;
|
|
968
|
+
if (isset($plan->rows)) {
|
|
969
|
+
$estimate = max(0, (int) round((float) $plan->rows * (float) ($plan->filtered ?? 100) / 100));
|
|
970
|
+
}
|
|
971
|
+
} catch (QueryException $exception) {
|
|
972
|
+
if (!$this->isStorageUsageTimeout($exception)) {
|
|
973
|
+
throw $exception;
|
|
974
|
+
}
|
|
975
|
+
}
|
|
976
|
+
|
|
977
|
+
return ['rows' => $estimate, 'oldest' => null, 'rows_estimated' => true];
|
|
978
|
+
}
|
|
979
|
+
|
|
980
|
+
protected function tableCount(string $table, \Closure $scope): int
|
|
981
|
+
{
|
|
982
|
+
$query = $scope(DB::table($table))->selectRaw('COUNT(*) AS row_count');
|
|
983
|
+
$usage = $this->storageUsageSelect($query->toSql(), $query->getBindings())[0];
|
|
984
|
+
|
|
985
|
+
return (int) $usage->row_count;
|
|
986
|
+
}
|
|
987
|
+
|
|
988
|
+
protected function tableOldest(string $table, \Closure $scope, string $column): ?string
|
|
989
|
+
{
|
|
990
|
+
$query = $scope(DB::table($table));
|
|
991
|
+
$query->selectRaw('MIN(' . $query->getGrammar()->wrap($column) . ') AS oldest');
|
|
992
|
+
try {
|
|
993
|
+
$oldest = $this->storageUsageSelect($query->toSql(), $query->getBindings())[0]->oldest ?? null;
|
|
994
|
+
} catch (QueryException $exception) {
|
|
995
|
+
if (!$this->isStorageUsageTimeout($exception)) {
|
|
996
|
+
throw $exception;
|
|
997
|
+
}
|
|
998
|
+
|
|
999
|
+
return null;
|
|
1000
|
+
}
|
|
1001
|
+
|
|
1002
|
+
return $oldest ? (string) $oldest : null;
|
|
1003
|
+
}
|
|
1004
|
+
|
|
1005
|
+
/**
|
|
1006
|
+
* Bound each MySQL/MariaDB scan to one second without changing persistent
|
|
1007
|
+
* connection settings. A browser abort alone leaves database work running.
|
|
1008
|
+
*/
|
|
1009
|
+
protected function storageUsageSelect(string $sql, array $bindings = [], bool $explain = false): array
|
|
1010
|
+
{
|
|
1011
|
+
$connection = DB::connection();
|
|
1012
|
+
$driver = $connection->getDriverName();
|
|
1013
|
+
$isMariaDb = $driver === 'mariadb';
|
|
1014
|
+
|
|
1015
|
+
if ($connection instanceof MySqlConnection) {
|
|
1016
|
+
$isMariaDb = stripos((string) $connection->getReadPdo()->getAttribute(\PDO::ATTR_SERVER_VERSION), 'MariaDB') !== false;
|
|
1017
|
+
}
|
|
1018
|
+
|
|
1019
|
+
if ($isMariaDb) {
|
|
1020
|
+
$sql = 'SET STATEMENT max_statement_time=1 FOR ' . ($explain ? 'EXPLAIN ' : '') . $sql;
|
|
1021
|
+
} else {
|
|
1022
|
+
if ($driver === 'mysql') {
|
|
1023
|
+
$sql = preg_replace('/^select\b/i', 'SELECT /*+ MAX_EXECUTION_TIME(1000) */', $sql, 1);
|
|
1024
|
+
}
|
|
1025
|
+
if ($explain) {
|
|
1026
|
+
$sql = 'EXPLAIN ' . $sql;
|
|
1027
|
+
}
|
|
1028
|
+
}
|
|
1029
|
+
|
|
1030
|
+
return $connection->select($sql, $bindings);
|
|
1031
|
+
}
|
|
1032
|
+
|
|
1033
|
+
protected function isStorageUsageTimeout(QueryException $exception): bool
|
|
1034
|
+
{
|
|
1035
|
+
return in_array((int) ($exception->errorInfo[1] ?? 0), [3024, 1969], true);
|
|
1036
|
+
}
|
|
1037
|
+
|
|
1038
|
+
/**
|
|
1039
|
+
* Whole-table row estimates and allocated data/index bytes. Empty on other drivers.
|
|
1040
|
+
*
|
|
1041
|
+
* @return array<string, array<string, int|bool|null>>
|
|
1042
|
+
*/
|
|
1043
|
+
protected function storageTableStatistics(array $tables): array
|
|
1044
|
+
{
|
|
1045
|
+
$connection = DB::connection();
|
|
1046
|
+
if (!in_array($connection->getDriverName(), ['mysql', 'mariadb'], true)) {
|
|
1047
|
+
return [];
|
|
1048
|
+
}
|
|
1049
|
+
|
|
1050
|
+
$prefix = $connection->getTablePrefix();
|
|
1051
|
+
$placeholders = implode(', ', array_fill(0, count($tables), '?'));
|
|
1052
|
+
try {
|
|
1053
|
+
$rows = $this->storageUsageSelect(
|
|
1054
|
+
'SELECT TABLE_NAME AS name, TABLE_ROWS AS row_count, DATA_LENGTH AS data_bytes, INDEX_LENGTH AS index_bytes FROM information_schema.TABLES WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME IN (' . $placeholders . ')',
|
|
1055
|
+
array_map(fn ($table) => $prefix . $table, $tables)
|
|
1056
|
+
);
|
|
1057
|
+
} catch (QueryException $exception) {
|
|
1058
|
+
if (!$this->isStorageUsageTimeout($exception)) {
|
|
1059
|
+
throw $exception;
|
|
1060
|
+
}
|
|
1061
|
+
|
|
1062
|
+
return [];
|
|
1063
|
+
}
|
|
1064
|
+
|
|
1065
|
+
$statistics = [];
|
|
1066
|
+
foreach ($rows as $row) {
|
|
1067
|
+
$statistics[substr($row->name, strlen($prefix))] = [
|
|
1068
|
+
'rows' => $row->row_count === null ? null : (int) $row->row_count,
|
|
1069
|
+
'rows_estimated' => true,
|
|
1070
|
+
'estimated_bytes' => $row->data_bytes === null || $row->index_bytes === null ? null : (int) $row->data_bytes + (int) $row->index_bytes,
|
|
1071
|
+
];
|
|
1072
|
+
}
|
|
1073
|
+
|
|
1074
|
+
return $statistics;
|
|
1075
|
+
}
|
|
1076
|
+
|
|
1077
|
+
protected function dispatchTelematicsPrune(): void
|
|
1078
|
+
{
|
|
1079
|
+
Queue::dispatch(new DispatchTelematicsRetentionJobs());
|
|
1080
|
+
}
|
|
1081
|
+
|
|
631
1082
|
protected function configureSetting(string $key, mixed $value): mixed
|
|
632
1083
|
{
|
|
633
1084
|
return Setting::configure($key, $value);
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
namespace Fleetbase\FleetOps\Http\Controllers\Internal\v1;
|
|
4
4
|
|
|
5
|
+
use Fleetbase\Attributes\SkipAuthorizationCheck;
|
|
5
6
|
use Fleetbase\FleetOps\Exports\TelematicExport;
|
|
6
7
|
use Fleetbase\FleetOps\Http\Controllers\FleetOpsController;
|
|
7
8
|
use Fleetbase\FleetOps\Models\Telematic;
|
|
@@ -16,6 +17,20 @@ use Maatwebsite\Excel\Facades\Excel;
|
|
|
16
17
|
|
|
17
18
|
class TelematicController extends FleetOpsController
|
|
18
19
|
{
|
|
20
|
+
/**
|
|
21
|
+
* Permissions for methods AuthorizationGuard cannot map to a schema action (see FleetOpsController).
|
|
22
|
+
*
|
|
23
|
+
* @var array<string, string|string[]>
|
|
24
|
+
*/
|
|
25
|
+
protected array $methodPermissions = [
|
|
26
|
+
'testConnection' => 'update telematic',
|
|
27
|
+
'testCredentials' => 'create telematic',
|
|
28
|
+
'discover' => 'update telematic',
|
|
29
|
+
'linkDevice' => 'update telematic',
|
|
30
|
+
'telemetryWebhook' => 'update telematic',
|
|
31
|
+
'replayTelemetryDelivery' => 'update telematic',
|
|
32
|
+
];
|
|
33
|
+
|
|
19
34
|
/**
|
|
20
35
|
* The resource to query.
|
|
21
36
|
*
|
|
@@ -71,6 +86,7 @@ class TelematicController extends FleetOpsController
|
|
|
71
86
|
/**
|
|
72
87
|
* Test connection to provider.
|
|
73
88
|
*/
|
|
89
|
+
#[SkipAuthorizationCheck]
|
|
74
90
|
public function testConnection(Request $request, string $id): JsonResponse
|
|
75
91
|
{
|
|
76
92
|
$telematic = $this->findTelematic($id);
|
|
@@ -89,6 +105,7 @@ class TelematicController extends FleetOpsController
|
|
|
89
105
|
/**
|
|
90
106
|
* Test connection to provider.
|
|
91
107
|
*/
|
|
108
|
+
#[SkipAuthorizationCheck]
|
|
92
109
|
public function testCredentials(Request $request, string $key): JsonResponse
|
|
93
110
|
{
|
|
94
111
|
$credentials = $request->array('credentials', []);
|
|
@@ -120,6 +137,7 @@ class TelematicController extends FleetOpsController
|
|
|
120
137
|
/**
|
|
121
138
|
* Discover devices from provider.
|
|
122
139
|
*/
|
|
140
|
+
#[SkipAuthorizationCheck]
|
|
123
141
|
public function discover(Request $request, string $id): JsonResponse
|
|
124
142
|
{
|
|
125
143
|
$telematic = $this->findTelematic($id);
|
|
@@ -181,6 +199,7 @@ class TelematicController extends FleetOpsController
|
|
|
181
199
|
/**
|
|
182
200
|
* Link a device to a telematic.
|
|
183
201
|
*/
|
|
202
|
+
#[SkipAuthorizationCheck]
|
|
184
203
|
public function linkDevice(Request $request, string $id): JsonResponse
|
|
185
204
|
{
|
|
186
205
|
$telematic = $this->findTelematic($id);
|
|
@@ -199,6 +218,7 @@ class TelematicController extends FleetOpsController
|
|
|
199
218
|
], 201);
|
|
200
219
|
}
|
|
201
220
|
|
|
221
|
+
#[SkipAuthorizationCheck]
|
|
202
222
|
public function telemetryWebhook(Request $request, string $id): JsonResponse
|
|
203
223
|
{
|
|
204
224
|
$telematic = $this->findTelematic($id);
|
|
@@ -248,6 +268,7 @@ class TelematicController extends FleetOpsController
|
|
|
248
268
|
]);
|
|
249
269
|
}
|
|
250
270
|
|
|
271
|
+
#[SkipAuthorizationCheck]
|
|
251
272
|
public function replayTelemetryDelivery(string $id, string $delivery): JsonResponse
|
|
252
273
|
{
|
|
253
274
|
$telematic = $this->findTelematic($id);
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
namespace Fleetbase\FleetOps\Http\Controllers\Internal\v1;
|
|
4
4
|
|
|
5
|
+
use Fleetbase\Attributes\SkipAuthorizationCheck;
|
|
5
6
|
use Fleetbase\FleetOps\Exceptions\DeviceAlreadyAttachedException;
|
|
6
7
|
use Fleetbase\FleetOps\Exports\TrailerExport;
|
|
7
8
|
use Fleetbase\FleetOps\Http\Controllers\FleetOpsController;
|
|
@@ -23,6 +24,20 @@ use Maatwebsite\Excel\Facades\Excel;
|
|
|
23
24
|
|
|
24
25
|
class TrailerController extends FleetOpsController
|
|
25
26
|
{
|
|
27
|
+
/**
|
|
28
|
+
* Permissions for methods AuthorizationGuard cannot map to a schema action (see FleetOpsController).
|
|
29
|
+
*
|
|
30
|
+
* @var array<string, string|string[]>
|
|
31
|
+
*/
|
|
32
|
+
protected array $methodPermissions = [
|
|
33
|
+
'attach' => 'attach-vehicle-for trailer',
|
|
34
|
+
'detach' => 'detach-vehicle-for trailer',
|
|
35
|
+
'attachDevice' => 'attach-device-for trailer',
|
|
36
|
+
'detachDevice' => 'detach-device-for trailer',
|
|
37
|
+
'attachEquipment' => 'attach-equipment-for trailer',
|
|
38
|
+
'detachEquipment' => 'detach-equipment-for trailer',
|
|
39
|
+
];
|
|
40
|
+
|
|
26
41
|
/**
|
|
27
42
|
* The resource to query.
|
|
28
43
|
*
|
|
@@ -69,6 +84,7 @@ class TrailerController extends FleetOpsController
|
|
|
69
84
|
/**
|
|
70
85
|
* Attach the trailer to a vehicle. Re-attaching to the same vehicle is idempotent.
|
|
71
86
|
*/
|
|
87
|
+
#[SkipAuthorizationCheck]
|
|
72
88
|
public function attach(Request $request, string $id)
|
|
73
89
|
{
|
|
74
90
|
$request->validate(['vehicle' => ['required', 'string'], 'position' => ['nullable', 'integer', 'min:1']]);
|
|
@@ -134,6 +150,7 @@ class TrailerController extends FleetOpsController
|
|
|
134
150
|
/**
|
|
135
151
|
* End the active towing connection. Detaching an unattached trailer is a no-op.
|
|
136
152
|
*/
|
|
153
|
+
#[SkipAuthorizationCheck]
|
|
137
154
|
public function detach(string $id)
|
|
138
155
|
{
|
|
139
156
|
$trailer = $this->resolveTrailer($id);
|
|
@@ -157,6 +174,7 @@ class TrailerController extends FleetOpsController
|
|
|
157
174
|
]);
|
|
158
175
|
}
|
|
159
176
|
|
|
177
|
+
#[SkipAuthorizationCheck]
|
|
160
178
|
public function attachDevice(Request $request, string $id)
|
|
161
179
|
{
|
|
162
180
|
$request->validate(['device' => ['required', 'string']]);
|
|
@@ -186,6 +204,7 @@ class TrailerController extends FleetOpsController
|
|
|
186
204
|
]);
|
|
187
205
|
}
|
|
188
206
|
|
|
207
|
+
#[SkipAuthorizationCheck]
|
|
189
208
|
public function detachDevice(Request $request, string $id)
|
|
190
209
|
{
|
|
191
210
|
$request->validate(['device' => ['required', 'string']]);
|
|
@@ -215,6 +234,7 @@ class TrailerController extends FleetOpsController
|
|
|
215
234
|
]);
|
|
216
235
|
}
|
|
217
236
|
|
|
237
|
+
#[SkipAuthorizationCheck]
|
|
218
238
|
public function attachEquipment(Request $request, string $id)
|
|
219
239
|
{
|
|
220
240
|
$request->validate(['equipment' => ['required', 'string']]);
|
|
@@ -242,6 +262,7 @@ class TrailerController extends FleetOpsController
|
|
|
242
262
|
]);
|
|
243
263
|
}
|
|
244
264
|
|
|
265
|
+
#[SkipAuthorizationCheck]
|
|
245
266
|
public function detachEquipment(Request $request, string $id)
|
|
246
267
|
{
|
|
247
268
|
$request->validate(['equipment' => ['required', 'string']]);
|