@fleetbase/fleetops-engine 0.3.6 → 0.3.7
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/addon/components/admin/navigator-app.hbs +6 -3
- package/addon/controllers/management/drivers/index/edit.js +0 -26
- package/addon/engine.js +4 -4
- package/composer.json +2 -2
- package/extension.json +1 -1
- package/package.json +1 -1
- package/server/config/fleetops.php +4 -1
- package/server/src/Http/Controllers/Api/v1/DriverController.php +7 -6
- package/server/src/Http/Controllers/Internal/v1/DriverController.php +148 -0
- package/server/src/Http/Controllers/Internal/v1/NavigatorController.php +38 -0
- package/server/src/routes.php +54 -0
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
<ContentPanel @title="Navigator App" @open={{true}} @pad={{true}} @panelBodyClass="bg-white dark:bg-gray-800">
|
|
2
|
-
<InputGroup @name="URL">
|
|
3
|
-
<ClickToCopy>{{this.url}}</ClickToCopy>
|
|
2
|
+
<InputGroup @name="Instance Linking URL">
|
|
3
|
+
<ClickToCopy class="px-4 py-2 border rounded-md bg-gray-100 shadow-sm dark:bg-gray-700 border-gray-200 dark:border-gray-800" @value={{this.url}}>{{this.url}}</ClickToCopy>
|
|
4
|
+
<Attach::Tooltip @class="clean" @animation="scale" @placement="top">
|
|
5
|
+
<InputInfo>Use this URL to link the official Navigator app to this {{t "app.name"}} instance. Opening this URL on a mobile device will open the Navigator app and update it's configuration and branding.</InputInfo>
|
|
6
|
+
</Attach::Tooltip>
|
|
4
7
|
</InputGroup>
|
|
5
|
-
</ContentPanel>
|
|
8
|
+
</ContentPanel>
|
|
@@ -25,13 +25,6 @@ export default class ManagementDriversIndexEditController extends BaseController
|
|
|
25
25
|
*/
|
|
26
26
|
@tracked overlay;
|
|
27
27
|
|
|
28
|
-
/**
|
|
29
|
-
* The universe service.
|
|
30
|
-
*
|
|
31
|
-
* @memberof ManagementDriversIndexEditController
|
|
32
|
-
*/
|
|
33
|
-
@tracked universe;
|
|
34
|
-
|
|
35
28
|
/**
|
|
36
29
|
* When exiting the overlay.
|
|
37
30
|
*
|
|
@@ -115,23 +108,4 @@ export default class ManagementDriversIndexEditController extends BaseController
|
|
|
115
108
|
...options,
|
|
116
109
|
});
|
|
117
110
|
}
|
|
118
|
-
|
|
119
|
-
/**
|
|
120
|
-
* Transitions to a specified route within the '@fleetbase/fleetops-engine' engine.
|
|
121
|
-
*
|
|
122
|
-
* This action is a wrapper around the `transitionToEngineRoute` method of the `universe` service (or object),
|
|
123
|
-
* specifically targeting the '@fleetbase/fleetops-engine'. It allows for easy transitioning to routes
|
|
124
|
-
* within this engine, abstracting away the need to repeatedly specify the engine name.
|
|
125
|
-
*
|
|
126
|
-
* @param {string} route - The route within the '@fleetbase/fleetops-engine' to transition to.
|
|
127
|
-
* @param {...any} args - Additional arguments to pass to the transitionToEngineRoute method.
|
|
128
|
-
* @returns {Promise} A Promise that resolves with the result of the transitionToEngineRoute method.
|
|
129
|
-
*
|
|
130
|
-
* @example
|
|
131
|
-
* // To transition to the 'management.fleets.index.new' route within the '@fleetbase/fleetops-engine'
|
|
132
|
-
* this.transitionToRoute('management.fleets.index.new');
|
|
133
|
-
*/
|
|
134
|
-
@action _transitionToRoute(route, ...args) {
|
|
135
|
-
return this.universe.transitionToEngineRoute('@fleetbase/fleetops-engine', route, ...args);
|
|
136
|
-
}
|
|
137
111
|
}
|
package/addon/engine.js
CHANGED
|
@@ -4,7 +4,7 @@ import Resolver from 'ember-resolver';
|
|
|
4
4
|
import config from './config/environment';
|
|
5
5
|
import services from '@fleetbase/ember-core/exports/services';
|
|
6
6
|
import AdminVisibilityControlsComponent from './components/admin/visibility-controls';
|
|
7
|
-
import
|
|
7
|
+
import NavigatorAppConfigComponent from './components/admin/navigator-app';
|
|
8
8
|
|
|
9
9
|
const { modulePrefix } = config;
|
|
10
10
|
const externalRoutes = ['console', 'extensions'];
|
|
@@ -30,9 +30,9 @@ export default class FleetOpsEngine extends Engine {
|
|
|
30
30
|
component: AdminVisibilityControlsComponent,
|
|
31
31
|
},
|
|
32
32
|
{
|
|
33
|
-
title: 'Navigator
|
|
34
|
-
icon: '
|
|
35
|
-
component:
|
|
33
|
+
title: 'Navigator App',
|
|
34
|
+
icon: 'location-arrow',
|
|
35
|
+
component: NavigatorAppConfigComponent,
|
|
36
36
|
},
|
|
37
37
|
],
|
|
38
38
|
{
|
package/composer.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "fleetbase/fleetops-api",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.7",
|
|
4
4
|
"description": "Fleet & Transport Management Extension for Fleetbase",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"fleetbase-extension",
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
],
|
|
23
23
|
"require": {
|
|
24
24
|
"php": "^7.4|^8.0",
|
|
25
|
-
"fleetbase/core-api": "^1.3.
|
|
25
|
+
"fleetbase/core-api": "^1.3.4",
|
|
26
26
|
"barryvdh/laravel-dompdf": "^2.0",
|
|
27
27
|
"brick/geo": "0.7.2",
|
|
28
28
|
"cknow/laravel-money": "^7.1",
|
package/extension.json
CHANGED
package/package.json
CHANGED
|
@@ -12,7 +12,10 @@ return [
|
|
|
12
12
|
'prefix' => null,
|
|
13
13
|
'internal_prefix' => 'int'
|
|
14
14
|
]
|
|
15
|
-
],
|
|
15
|
+
],
|
|
16
|
+
'navigator' => [
|
|
17
|
+
'bypass_verification_code' => env('NAVIGATOR_BYPASS_VERIFICATION_CODE', '999000')
|
|
18
|
+
],
|
|
16
19
|
'connection' => [
|
|
17
20
|
'db' => env('DB_CONNECTION', 'mysql')
|
|
18
21
|
]
|
|
@@ -353,10 +353,10 @@ class DriverController extends Controller
|
|
|
353
353
|
return response()->error('Authentication failed using password provided.', 401);
|
|
354
354
|
}
|
|
355
355
|
|
|
356
|
-
//
|
|
356
|
+
// Get the company session for the user
|
|
357
357
|
$company = Flow::getCompanySessionForUser($user);
|
|
358
358
|
|
|
359
|
-
//
|
|
359
|
+
// Get driver record
|
|
360
360
|
$driver = Driver::firstOrCreate(
|
|
361
361
|
[
|
|
362
362
|
'user_uuid' => $user->uuid,
|
|
@@ -365,9 +365,10 @@ class DriverController extends Controller
|
|
|
365
365
|
[
|
|
366
366
|
'user_uuid' => $user->uuid,
|
|
367
367
|
'company_uuid' => $company->uuid,
|
|
368
|
-
'name' => $attrs
|
|
369
|
-
'phone' => $attrs
|
|
370
|
-
'email' => $attrs
|
|
368
|
+
'name' => data_get($attrs, 'name', $user->name),
|
|
369
|
+
'phone' => data_get($attrs, 'phone', $user->phone),
|
|
370
|
+
'email' => data_get($attrs, 'email', $user->email),
|
|
371
|
+
'location' => new Point(0, 0),
|
|
371
372
|
]
|
|
372
373
|
);
|
|
373
374
|
|
|
@@ -443,7 +444,7 @@ class DriverController extends Controller
|
|
|
443
444
|
// find and verify code
|
|
444
445
|
$verificationCode = VerificationCode::where(['subject_uuid' => $user->uuid, 'code' => $code, 'for' => $for])->exists();
|
|
445
446
|
|
|
446
|
-
if (!$verificationCode && $code !== '
|
|
447
|
+
if (!$verificationCode && $code !== config('fleetops.navigator.bypass_verification_code')) {
|
|
447
448
|
return response()->error('Invalid verification code!');
|
|
448
449
|
}
|
|
449
450
|
|
|
@@ -4,14 +4,18 @@ namespace Fleetbase\FleetOps\Http\Controllers\Internal\v1;
|
|
|
4
4
|
|
|
5
5
|
use Fleetbase\Exceptions\FleetbaseRequestValidationException;
|
|
6
6
|
use Fleetbase\FleetOps\Exports\DriverExport;
|
|
7
|
+
use Fleetbase\FleetOps\Http\Controllers\Api\v1\DriverController as ApiDriverController;
|
|
7
8
|
use Fleetbase\FleetOps\Http\Controllers\FleetOpsController;
|
|
9
|
+
use Fleetbase\FleetOps\Http\Requests\Internal\AssignOrderRequest;
|
|
8
10
|
use Fleetbase\FleetOps\Http\Requests\Internal\CreateDriverRequest;
|
|
9
11
|
use Fleetbase\FleetOps\Http\Requests\Internal\UpdateDriverRequest;
|
|
10
12
|
use Fleetbase\FleetOps\Models\Driver;
|
|
13
|
+
use Fleetbase\FleetOps\Models\Order;
|
|
11
14
|
use Fleetbase\FleetOps\Support\Utils;
|
|
12
15
|
use Fleetbase\Http\Requests\ExportRequest;
|
|
13
16
|
use Fleetbase\Models\Invite;
|
|
14
17
|
use Fleetbase\Models\User;
|
|
18
|
+
use Fleetbase\Models\VerificationCode;
|
|
15
19
|
use Fleetbase\Notifications\UserInvited;
|
|
16
20
|
use Illuminate\Http\Request;
|
|
17
21
|
use Illuminate\Support\Facades\DB;
|
|
@@ -267,4 +271,148 @@ class DriverController extends FleetOpsController
|
|
|
267
271
|
|
|
268
272
|
return Excel::download(new DriverExport(), $fileName);
|
|
269
273
|
}
|
|
274
|
+
|
|
275
|
+
/**
|
|
276
|
+
* Assigns a driver to a specified order.
|
|
277
|
+
*
|
|
278
|
+
* @param Fleetbase\FleetOps\Http\Requests\Internal\AssignOrderRequest $request
|
|
279
|
+
*
|
|
280
|
+
* @return \Illuminate\Http\Response $response
|
|
281
|
+
*/
|
|
282
|
+
public function assignOrder(AssignOrderRequest $request)
|
|
283
|
+
{
|
|
284
|
+
$driver = Driver::where('public_id', $request->driver)->first();
|
|
285
|
+
$order = Order::where('public_id', $request->order)->first();
|
|
286
|
+
|
|
287
|
+
if ($order->hasDriverAssigned) {
|
|
288
|
+
return response()->error('A driver is already assigned to this order.');
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
if ($order->isDriver($driver)) {
|
|
292
|
+
return response()->error('The driver is already assigned to this order.');
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
$order->assignDriver($driver);
|
|
296
|
+
|
|
297
|
+
return response()->json([
|
|
298
|
+
'status' => 'ok',
|
|
299
|
+
'message' => 'Driver assigned',
|
|
300
|
+
]);
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
/**
|
|
304
|
+
* Update drivers geolocation data.
|
|
305
|
+
*
|
|
306
|
+
* @return \Illuminate\Http\Response
|
|
307
|
+
*/
|
|
308
|
+
public function track(string $id, Request $request)
|
|
309
|
+
{
|
|
310
|
+
return app(ApiDriverController::class)->track($id, $request);
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
/**
|
|
314
|
+
* Query for Storefront Customer orders.
|
|
315
|
+
*
|
|
316
|
+
* @return \Fleetbase\Http\Resources\Storefront\Customer
|
|
317
|
+
*/
|
|
318
|
+
public function registerDevice(Request $request)
|
|
319
|
+
{
|
|
320
|
+
return app(ApiDriverController::class)->registerDevice($request);
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
/**
|
|
324
|
+
* Authenticates customer using login credentials and returns with auth token.
|
|
325
|
+
*
|
|
326
|
+
* @return \Fleetbase\Http\Resources\Storefront\Customer
|
|
327
|
+
*/
|
|
328
|
+
public function login(Request $request)
|
|
329
|
+
{
|
|
330
|
+
return app(ApiDriverController::class)->login($request);
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
/**
|
|
334
|
+
* Attempts authentication with phone number via SMS verification.
|
|
335
|
+
*
|
|
336
|
+
* @return \Illuminate\Http\Response
|
|
337
|
+
*/
|
|
338
|
+
public function loginWithPhone()
|
|
339
|
+
{
|
|
340
|
+
$phone = static::phone();
|
|
341
|
+
|
|
342
|
+
// Check if user exists
|
|
343
|
+
$user = User::where('phone', $phone)->whereNull('deleted_at')->withoutGlobalScopes()->first();
|
|
344
|
+
|
|
345
|
+
if (!$user) {
|
|
346
|
+
return response()->error('No driver with this phone # found.');
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
// Generate verification token
|
|
350
|
+
VerificationCode::generateSmsVerificationFor($user, 'driver_login', function ($verification) {
|
|
351
|
+
return 'Your ' . config('app.name') . ' verification code is ' . $verification->code;
|
|
352
|
+
});
|
|
353
|
+
|
|
354
|
+
return response()->json(['status' => 'OK']);
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
/**
|
|
358
|
+
* Verifys SMS code and sends auth token with driver resource.
|
|
359
|
+
*
|
|
360
|
+
* @return \Fleetbase\Http\Resources\FleetOps\Driver
|
|
361
|
+
*/
|
|
362
|
+
public function verifyCode(Request $request)
|
|
363
|
+
{
|
|
364
|
+
$identity = Utils::isEmail($request->identity) ? $request->identity : static::phone($request->identity);
|
|
365
|
+
$code = $request->input('code');
|
|
366
|
+
$for = $request->input('for', 'driver_login');
|
|
367
|
+
$attrs = $request->input(['name', 'phone', 'email']);
|
|
368
|
+
|
|
369
|
+
if ($for === 'create_driver') {
|
|
370
|
+
return app(ApiDriverController::class)->create($request);
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
// Check if user exists
|
|
374
|
+
$user = User::where('phone', $identity)->orWhere('email', $identity)->first();
|
|
375
|
+
if (!$user) {
|
|
376
|
+
return response()->error('Unable to verify code.');
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
// Find and verify code
|
|
380
|
+
$verificationCode = VerificationCode::where(['subject_uuid' => $user->uuid, 'code' => $code, 'for' => $for])->exists();
|
|
381
|
+
if (!$verificationCode && $code !== config('fleetops.navigator.bypass_verification_code')) {
|
|
382
|
+
return response()->error('Invalid verification code!');
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
// Get driver record
|
|
386
|
+
$driver = Driver::where('user_uuid', $user->uuid)->whereNull('deleted_at')->withoutGlobalScopes()->first();
|
|
387
|
+
if (!$driver) {
|
|
388
|
+
return response()->error('No driver/agent record found for login.');
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
// Generate auth token
|
|
392
|
+
try {
|
|
393
|
+
$token = $user->createToken($driver->uuid);
|
|
394
|
+
} catch (\Exception $e) {
|
|
395
|
+
return response()->error($e->getMessage());
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
$driver->token = $token->plainTextToken;
|
|
399
|
+
|
|
400
|
+
return new $this->resource($driver);
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
/**
|
|
404
|
+
* Patches phone number with international code.
|
|
405
|
+
*/
|
|
406
|
+
public static function phone(string $phone = null): string
|
|
407
|
+
{
|
|
408
|
+
if ($phone === null) {
|
|
409
|
+
$phone = request()->input('phone');
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
if (!Str::startsWith($phone, '+')) {
|
|
413
|
+
$phone = '+' . $phone;
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
return $phone;
|
|
417
|
+
}
|
|
270
418
|
}
|
|
@@ -3,8 +3,12 @@
|
|
|
3
3
|
namespace Fleetbase\FleetOps\Http\Controllers\Internal\v1;
|
|
4
4
|
|
|
5
5
|
use Fleetbase\Http\Controllers\Controller;
|
|
6
|
+
use Fleetbase\Http\Resources\Organization;
|
|
6
7
|
use Fleetbase\Models\ApiCredential;
|
|
8
|
+
use Fleetbase\Models\Company;
|
|
7
9
|
use Fleetbase\Models\User;
|
|
10
|
+
use Illuminate\Http\Request;
|
|
11
|
+
use Illuminate\Support\Str;
|
|
8
12
|
|
|
9
13
|
class NavigatorController extends Controller
|
|
10
14
|
{
|
|
@@ -38,4 +42,38 @@ class NavigatorController extends Controller
|
|
|
38
42
|
'linkUrl' => url('int/v1/fleet-ops/navigator/link-app'),
|
|
39
43
|
]);
|
|
40
44
|
}
|
|
45
|
+
|
|
46
|
+
public function getCurrentOrganization(Request $request)
|
|
47
|
+
{
|
|
48
|
+
$token = $request->bearerToken();
|
|
49
|
+
$isSecretKey = Str::startsWith($token, '$');
|
|
50
|
+
|
|
51
|
+
// Depending on API key format set the connection to find credential on
|
|
52
|
+
$connection = Str::startsWith($token, 'flb_test_') ? 'sandbox' : 'mysql';
|
|
53
|
+
|
|
54
|
+
// Find the API Credential record
|
|
55
|
+
$findApKey = ApiCredential::on($connection)
|
|
56
|
+
->where(function ($query) use ($isSecretKey, $token) {
|
|
57
|
+
if ($isSecretKey) {
|
|
58
|
+
$query->where('secret', $token);
|
|
59
|
+
} else {
|
|
60
|
+
$query->where('key', $token);
|
|
61
|
+
}
|
|
62
|
+
})
|
|
63
|
+
->with(['company.owner'])
|
|
64
|
+
->withoutGlobalScopes();
|
|
65
|
+
|
|
66
|
+
// Get the api credential model record
|
|
67
|
+
$apiCredential = $findApKey->first();
|
|
68
|
+
|
|
69
|
+
// Handle no api credential found
|
|
70
|
+
if (!$apiCredential) {
|
|
71
|
+
return response()->error('No API key found to fetch company details with.');
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// Get the organization owning the API key
|
|
75
|
+
$organization = Company::where('uuid', $apiCredential->company_uuid)->first();
|
|
76
|
+
|
|
77
|
+
return new Organization($organization);
|
|
78
|
+
}
|
|
41
79
|
}
|
package/server/src/routes.php
CHANGED
|
@@ -175,6 +175,60 @@ Route::prefix(config('fleetops.api.routing.prefix', null))->namespace('Fleetbase
|
|
|
175
175
|
});
|
|
176
176
|
});
|
|
177
177
|
|
|
178
|
+
/*
|
|
179
|
+
|--------------------------------------------------------------------------
|
|
180
|
+
| Navigator App API
|
|
181
|
+
|--------------------------------------------------------------------------
|
|
182
|
+
|
|
|
183
|
+
| Internal routes specific for instance wide authentication/use for navigator app
|
|
184
|
+
*/
|
|
185
|
+
Route::prefix('navigator/v1')
|
|
186
|
+
->group(function ($router) {
|
|
187
|
+
// driver/auth routes
|
|
188
|
+
$router->group(['prefix' => 'drivers', 'namespace' => 'Internal\v1'], function () use ($router) {
|
|
189
|
+
$router->post('login-with-sms', 'DriverController@loginWithPhone');
|
|
190
|
+
$router->post('verify-code', 'DriverController@verifyCode');
|
|
191
|
+
$router->post('login', 'DriverController@login');
|
|
192
|
+
});
|
|
193
|
+
|
|
194
|
+
// auth:sanctum
|
|
195
|
+
$router->group(['middleware' => ['fleetbase.protected', \Fleetbase\FleetOps\Http\Middleware\TransformLocationMiddleware::class]], function () use ($router) {
|
|
196
|
+
$router->group(['prefix' => 'orders'], function () use ($router) {
|
|
197
|
+
$router->post('/', 'Api\v1\OrderController@create');
|
|
198
|
+
$router->get('/', 'Api\v1\OrderController@query');
|
|
199
|
+
$router->get('{id}', 'Api\v1\OrderController@find');
|
|
200
|
+
$router->get('{id}/distance-and-time', 'Api\v1\OrderController@getDistanceMatrix');
|
|
201
|
+
$router->post('{id}/dispatch', 'Api\v1\OrderController@dispatchOrder');
|
|
202
|
+
$router->post('{id}/start', 'Api\v1\OrderController@startOrder');
|
|
203
|
+
$router->delete('{id}/cancel', 'Api\v1\OrderController@cancelOrder');
|
|
204
|
+
$router->post('{id}/update-activity', 'Api\v1\OrderController@updateActivity');
|
|
205
|
+
$router->post('{id}/complete', 'Api\v1\OrderController@completeOrder');
|
|
206
|
+
$router->get('{id}/next-activity', 'Api\v1\OrderController@getNextActivity');
|
|
207
|
+
$router->post('{id}/set-destination/{placeId}', 'Api\v1\OrderController@setDestination');
|
|
208
|
+
$router->post('{id}/capture-signature/{subjectId?}', 'Api\v1\OrderController@captureSignature');
|
|
209
|
+
$router->post('{id}/capture-qr/{subjectId?}', 'Api\v1\OrderController@captureQrScan');
|
|
210
|
+
$router->put('{id}', 'Api\v1\OrderController@update');
|
|
211
|
+
$router->delete('{id}', 'Api\v1\OrderController@delete');
|
|
212
|
+
});
|
|
213
|
+
|
|
214
|
+
$router->group(['prefix' => 'drivers'], function () use ($router) {
|
|
215
|
+
$router->post('{id}/register-device', 'Api\v1\DriverController@registerDevice');
|
|
216
|
+
$router->post('{id}/track', 'Api\v1\DriverController@track');
|
|
217
|
+
$router->post('{id}/switch-organization', 'Api\v1\DriverController@switchOrganization');
|
|
218
|
+
$router->post('/', 'Api\v1\DriverController@create');
|
|
219
|
+
$router->get('/', 'Api\v1\DriverController@query');
|
|
220
|
+
$router->get('{id}', 'Api\v1\DriverController@find');
|
|
221
|
+
$router->get('{id}/organizations', 'Api\v1\DriverController@listOrganizations');
|
|
222
|
+
$router->put('{id}', 'Api\v1\DriverController@update');
|
|
223
|
+
$router->delete('{id}', 'Api\v1\DriverController@delete');
|
|
224
|
+
});
|
|
225
|
+
|
|
226
|
+
$router->group(['prefix' => 'organizations'], function ($router) {
|
|
227
|
+
$router->get('current', 'Internal\v1\NavigatorController@getCurrentOrganization');
|
|
228
|
+
});
|
|
229
|
+
});
|
|
230
|
+
});
|
|
231
|
+
|
|
178
232
|
/*
|
|
179
233
|
|--------------------------------------------------------------------------
|
|
180
234
|
| Internal FleetOps API Routes
|