@fleetbase/registry-bridge-engine 0.0.1
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/.php-cs-fixer.php +29 -0
- package/LICENSE.md +651 -0
- package/README.md +122 -0
- package/addon/adapters/registry-bridge.js +5 -0
- package/addon/adapters/registry-extension-bundle.js +1 -0
- package/addon/adapters/registry-extension.js +1 -0
- package/addon/components/extension-card.hbs +12 -0
- package/addon/components/extension-card.js +235 -0
- package/addon/components/extension-form.hbs +237 -0
- package/addon/components/extension-form.js +123 -0
- package/addon/components/extension-modal-title.hbs +14 -0
- package/addon/components/extension-modal-title.js +20 -0
- package/addon/components/extension-monetize-form.hbs +56 -0
- package/addon/components/extension-monetize-form.js +7 -0
- package/addon/components/extension-pending-publish-viewer.hbs +52 -0
- package/addon/components/extension-pending-publish-viewer.js +37 -0
- package/addon/components/extension-reviewer-control.hbs +68 -0
- package/addon/components/extension-reviewer-control.js +68 -0
- package/addon/components/modals/confirm-extension-purchase.hbs +5 -0
- package/addon/components/modals/confirm-extension-purchase.js +3 -0
- package/addon/components/modals/extension-details.hbs +69 -0
- package/addon/components/modals/extension-details.js +33 -0
- package/addon/components/modals/extension-purchase-form.hbs +5 -0
- package/addon/components/modals/extension-purchase-form.js +3 -0
- package/addon/components/modals/extension-uninstall.hbs +25 -0
- package/addon/components/modals/extension-uninstall.js +11 -0
- package/addon/components/modals/select-extension-bundle.hbs +43 -0
- package/addon/components/modals/select-extension-bundle.js +31 -0
- package/addon/components/progress-bar.hbs +12 -0
- package/addon/components/progress-bar.js +8 -0
- package/addon/controllers/application.js +6 -0
- package/addon/controllers/developers/analytics.js +26 -0
- package/addon/controllers/developers/extensions/edit/bundles.js +70 -0
- package/addon/controllers/developers/extensions/edit/index.js +3 -0
- package/addon/controllers/developers/extensions/edit/monetize.js +7 -0
- package/addon/controllers/developers/extensions/edit.js +107 -0
- package/addon/controllers/developers/extensions/index.js +3 -0
- package/addon/controllers/developers/extensions/new.js +32 -0
- package/addon/controllers/developers/payments/index.js +39 -0
- package/addon/controllers/developers/payments/onboard.js +67 -0
- package/addon/controllers/explore/category.js +22 -0
- package/addon/controllers/explore/index.js +15 -0
- package/addon/controllers/installed.js +86 -0
- package/addon/controllers/purchased.js +18 -0
- package/addon/engine.js +44 -0
- package/addon/models/registry-extension-bundle.js +62 -0
- package/addon/models/registry-extension.js +215 -0
- package/addon/routes/application.js +12 -0
- package/addon/routes/developers/analytics.js +10 -0
- package/addon/routes/developers/credentials.js +3 -0
- package/addon/routes/developers/extensions/edit/bundles.js +21 -0
- package/addon/routes/developers/extensions/edit/details.js +3 -0
- package/addon/routes/developers/extensions/edit/index.js +3 -0
- package/addon/routes/developers/extensions/edit/monetize.js +3 -0
- package/addon/routes/developers/extensions/edit.js +18 -0
- package/addon/routes/developers/extensions/index.js +10 -0
- package/addon/routes/developers/extensions/new.js +3 -0
- package/addon/routes/developers/extensions.js +3 -0
- package/addon/routes/developers/payments/index.js +26 -0
- package/addon/routes/developers/payments/onboard.js +21 -0
- package/addon/routes/developers/payments.js +3 -0
- package/addon/routes/developers.js +3 -0
- package/addon/routes/explore/category.js +27 -0
- package/addon/routes/explore/index.js +17 -0
- package/addon/routes/explore.js +3 -0
- package/addon/routes/installed.js +10 -0
- package/addon/routes/purchased.js +10 -0
- package/addon/routes.js +28 -0
- package/addon/serializers/registry-extension-bundle.js +15 -0
- package/addon/serializers/registry-extension.js +21 -0
- package/addon/services/stripe.js +83 -0
- package/addon/styles/registry-bridge-engine.css +142 -0
- package/addon/templates/application.hbs +26 -0
- package/addon/templates/developers/analytics.hbs +83 -0
- package/addon/templates/developers/credentials.hbs +1 -0
- package/addon/templates/developers/extensions/edit/bundles.hbs +71 -0
- package/addon/templates/developers/extensions/edit/details.hbs +16 -0
- package/addon/templates/developers/extensions/edit/index.hbs +1 -0
- package/addon/templates/developers/extensions/edit/monetize.hbs +3 -0
- package/addon/templates/developers/extensions/edit.hbs +48 -0
- package/addon/templates/developers/extensions/index.hbs +27 -0
- package/addon/templates/developers/extensions/new.hbs +39 -0
- package/addon/templates/developers/extensions.hbs +1 -0
- package/addon/templates/developers/payments/index.hbs +33 -0
- package/addon/templates/developers/payments/onboard.hbs +48 -0
- package/addon/templates/developers/payments.hbs +1 -0
- package/addon/templates/developers.hbs +1 -0
- package/addon/templates/explore/category.hbs +12 -0
- package/addon/templates/explore/index.hbs +12 -0
- package/addon/templates/explore.hbs +1 -0
- package/addon/templates/installed.hbs +32 -0
- package/addon/templates/purchased.hbs +34 -0
- package/app/adapters/registry-bridge.js +1 -0
- package/app/adapters/registry-extension-bundle.js +1 -0
- package/app/adapters/registry-extension.js +1 -0
- package/app/components/extension-card.js +1 -0
- package/app/components/extension-form.js +1 -0
- package/app/components/extension-modal-title.js +1 -0
- package/app/components/extension-monetize-form.js +1 -0
- package/app/components/extension-pending-publish-viewer.js +1 -0
- package/app/components/extension-reviewer-control.js +1 -0
- package/app/components/modals/confirm-extension-purchase.js +1 -0
- package/app/components/modals/extension-details.js +1 -0
- package/app/components/modals/extension-purchase-form.js +1 -0
- package/app/components/modals/extension-uninstall.js +1 -0
- package/app/components/modals/select-extension-bundle.js +1 -0
- package/app/components/progress-bar.js +1 -0
- package/app/controllers/application.js +1 -0
- package/app/controllers/developers/analytics.js +1 -0
- package/app/controllers/developers/extensions/edit/bundles.js +1 -0
- package/app/controllers/developers/extensions/edit/index.js +1 -0
- package/app/controllers/developers/extensions/edit/monetize.js +1 -0
- package/app/controllers/developers/extensions/edit.js +1 -0
- package/app/controllers/developers/extensions/index.js +1 -0
- package/app/controllers/developers/extensions/new.js +1 -0
- package/app/controllers/developers/payments/index.js +1 -0
- package/app/controllers/developers/payments/onboard.js +1 -0
- package/app/controllers/explore/category.js +1 -0
- package/app/controllers/explore/index.js +1 -0
- package/app/controllers/installed.js +1 -0
- package/app/controllers/purchased.js +1 -0
- package/app/models/registry-extension-bundle.js +1 -0
- package/app/models/registry-extension.js +1 -0
- package/app/routes/developers/analytics.js +1 -0
- package/app/routes/developers/credentials.js +1 -0
- package/app/routes/developers/extensions/edit/bundles.js +1 -0
- package/app/routes/developers/extensions/edit/details.js +1 -0
- package/app/routes/developers/extensions/edit/index.js +1 -0
- package/app/routes/developers/extensions/edit/monetize.js +1 -0
- package/app/routes/developers/extensions/edit.js +1 -0
- package/app/routes/developers/extensions/index.js +1 -0
- package/app/routes/developers/extensions/new.js +1 -0
- package/app/routes/developers/extensions.js +1 -0
- package/app/routes/developers/payments/index.js +1 -0
- package/app/routes/developers/payments/onboard.js +1 -0
- package/app/routes/developers/payments.js +1 -0
- package/app/routes/developers.js +1 -0
- package/app/routes/explore/category.js +1 -0
- package/app/routes/explore/index.js +1 -0
- package/app/routes/explore.js +1 -0
- package/app/routes/installed.js +1 -0
- package/app/routes/purchased.js +1 -0
- package/app/serializers/registry-extension-bundle.js +1 -0
- package/app/serializers/registry-extension.js +1 -0
- package/app/services/stripe.js +1 -0
- package/app/templates/developers/analytics.js +1 -0
- package/app/templates/developers/credentials.js +1 -0
- package/app/templates/developers/extensions/edit/bundles.js +1 -0
- package/app/templates/developers/extensions/edit/details.js +1 -0
- package/app/templates/developers/extensions/edit/index.js +1 -0
- package/app/templates/developers/extensions/edit/monetize.js +1 -0
- package/app/templates/developers/extensions/edit.js +1 -0
- package/app/templates/developers/extensions/index.js +1 -0
- package/app/templates/developers/extensions/new.js +1 -0
- package/app/templates/developers/extensions.js +1 -0
- package/app/templates/developers/payments/index.js +1 -0
- package/app/templates/developers/payments/onboard.js +1 -0
- package/app/templates/developers/payments.js +1 -0
- package/app/templates/developers.js +1 -0
- package/app/templates/explore/category.js +1 -0
- package/app/templates/explore/index.js +1 -0
- package/app/templates/explore.js +1 -0
- package/app/templates/installed.js +1 -0
- package/app/templates/purchased.js +1 -0
- package/composer.json +95 -0
- package/config/environment.js +28 -0
- package/extension.json +10 -0
- package/index.js +26 -0
- package/package.json +129 -0
- package/phpstan.neon.dist +8 -0
- package/phpunit.xml.dist +16 -0
- package/server/.gitattributes +14 -0
- package/server/config/registry-bridge.php +32 -0
- package/server/migrations/2024_03_19_060627_create_registry_users_table.php +42 -0
- package/server/migrations/2024_03_21_051614_create_registry_extensions_table.php +76 -0
- package/server/migrations/2024_03_25_044537_create_registry_extension_bundles_table.php +54 -0
- package/server/migrations/2024_03_29_072101_registry_extension_installs.php +35 -0
- package/server/migrations/2024_07_16_155000_create_registry_extension_purchases.php +41 -0
- package/server/seeders/ExtensionsCategorySeeder.php +359 -0
- package/server/src/Console/Commands/Initialize.php +35 -0
- package/server/src/Console/Commands/PostInstallExtension.php +84 -0
- package/server/src/Exceptions/InstallFailedException.php +21 -0
- package/server/src/Expansions/CategoryExpansion.php +30 -0
- package/server/src/Http/Controllers/Internal/v1/ExtensionInstallerController.php +153 -0
- package/server/src/Http/Controllers/Internal/v1/RegistryAuthController.php +230 -0
- package/server/src/Http/Controllers/Internal/v1/RegistryController.php +54 -0
- package/server/src/Http/Controllers/Internal/v1/RegistryExtensionBundleController.php +112 -0
- package/server/src/Http/Controllers/Internal/v1/RegistryExtensionController.php +257 -0
- package/server/src/Http/Controllers/Internal/v1/RegistryPaymentsController.php +227 -0
- package/server/src/Http/Controllers/RegistryBridgeController.php +13 -0
- package/server/src/Http/Filter/RegistryExtensionFilter.php +80 -0
- package/server/src/Http/Requests/AddRegistryUserRequest.php +47 -0
- package/server/src/Http/Requests/AuthenticateRegistryUserRequest.php +47 -0
- package/server/src/Http/Requests/CreateRegistryExtensionBundleRequest.php +42 -0
- package/server/src/Http/Requests/CreateRegistryExtensionRequest.php +31 -0
- package/server/src/Http/Requests/InstallExtensionRequest.php +30 -0
- package/server/src/Http/Requests/RegistryAuthRequest.php +46 -0
- package/server/src/Http/Requests/RegistryExtensionActionRequest.php +30 -0
- package/server/src/Http/Resources/RegistryUser.php +40 -0
- package/server/src/Models/RegistryExtension.php +656 -0
- package/server/src/Models/RegistryExtensionBundle.php +1015 -0
- package/server/src/Models/RegistryExtensionInstall.php +76 -0
- package/server/src/Models/RegistryExtensionPurchase.php +87 -0
- package/server/src/Models/RegistryUser.php +140 -0
- package/server/src/Providers/RegistryBridgeServiceProvider.php +117 -0
- package/server/src/Support/Bridge.php +53 -0
- package/server/src/Support/Utils.php +19 -0
- package/server/src/routes.php +58 -0
- package/server/tests/Feature.php +5 -0
- package/translations/en-us.yaml +119 -0
- package/tsconfig.declarations.json +10 -0
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
<?php
|
|
2
|
+
|
|
3
|
+
namespace Fleetbase\RegistryBridge\Http\Controllers\Internal\v1;
|
|
4
|
+
|
|
5
|
+
use Fleetbase\Exceptions\FleetbaseRequestValidationException;
|
|
6
|
+
use Fleetbase\Models\File;
|
|
7
|
+
use Fleetbase\RegistryBridge\Http\Controllers\RegistryBridgeController;
|
|
8
|
+
use Fleetbase\RegistryBridge\Http\Requests\CreateRegistryExtensionBundleRequest;
|
|
9
|
+
use Fleetbase\RegistryBridge\Http\Requests\RegistryExtensionActionRequest;
|
|
10
|
+
use Fleetbase\RegistryBridge\Models\RegistryExtensionBundle;
|
|
11
|
+
use Fleetbase\Support\Utils;
|
|
12
|
+
use Illuminate\Http\Request;
|
|
13
|
+
use Illuminate\Support\Facades\Storage;
|
|
14
|
+
use Illuminate\Support\Facades\Validator;
|
|
15
|
+
|
|
16
|
+
class RegistryExtensionBundleController extends RegistryBridgeController
|
|
17
|
+
{
|
|
18
|
+
/**
|
|
19
|
+
* The resource to query.
|
|
20
|
+
*
|
|
21
|
+
* @var string
|
|
22
|
+
*/
|
|
23
|
+
public $resource = 'registry_extension_bundle';
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Creates a record with request payload.
|
|
27
|
+
*
|
|
28
|
+
* @return \Illuminate\Http\Response
|
|
29
|
+
*/
|
|
30
|
+
public function createRecord(Request $request)
|
|
31
|
+
{
|
|
32
|
+
$extensionId = $request->input('subject_uuid');
|
|
33
|
+
|
|
34
|
+
// Create validation request
|
|
35
|
+
$createRegistryExtensionBundleRequest = CreateRegistryExtensionBundleRequest::createFrom($request);
|
|
36
|
+
$rules = $createRegistryExtensionBundleRequest->rules();
|
|
37
|
+
|
|
38
|
+
// Manually validate request
|
|
39
|
+
$validator = Validator::make($request->input('registryExtensionBundle'), $rules);
|
|
40
|
+
if ($validator->fails()) {
|
|
41
|
+
return $createRegistryExtensionBundleRequest->responseWithErrors($validator);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// Extract bundle extension json for file validation
|
|
45
|
+
$bundleFile = File::where('uuid', $request->input('registryExtensionBundle.bundle_uuid'))->first();
|
|
46
|
+
if (!$bundleFile) {
|
|
47
|
+
return response()->error('Unable to find bundle file for validation.');
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// Get extension.json contents
|
|
51
|
+
$bundleData = RegistryExtensionBundle::extractBundleData($bundleFile);
|
|
52
|
+
$extensionJson = Utils::getObjectKeyValue($bundleData, 'extension.json');
|
|
53
|
+
if (!$extensionJson) {
|
|
54
|
+
return response()->error('Unable to find `extension.json` file required in bundle.');
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// Check if version is set
|
|
58
|
+
if (!isset($extensionJson->version)) {
|
|
59
|
+
return response()->error('No `version` set in the `extension.json`');
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// Check if either api or engine property is set
|
|
63
|
+
if (!isset($extensionJson->engine) && !isset($extensionJson->api)) {
|
|
64
|
+
return response()->error('No `api` or `engine` property set in the `extension.json`');
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// Set bundle number
|
|
68
|
+
$numberOfBundles = RegistryExtensionBundle::whereHas('extension', function ($query) use ($extensionId) {
|
|
69
|
+
$query->where('public_id', $extensionId);
|
|
70
|
+
})->count();
|
|
71
|
+
$extensionJson->bundle_number = ($numberOfBundles ?? 0) + 1;
|
|
72
|
+
|
|
73
|
+
try {
|
|
74
|
+
$record = $this->model->createRecordFromRequest($request);
|
|
75
|
+
|
|
76
|
+
// Update the record version from extension json
|
|
77
|
+
$record->update(['bundle_number' => $extensionJson->bundle_number, 'version' => $extensionJson->version]);
|
|
78
|
+
$record->updateMetaProperties((array) $bundleData);
|
|
79
|
+
|
|
80
|
+
return ['registryExtensionBundle' => new $this->resource($record)];
|
|
81
|
+
} catch (\Throwable $e) {
|
|
82
|
+
return response()->error($e->getMessage());
|
|
83
|
+
} catch (\Illuminate\Database\QueryException $e) {
|
|
84
|
+
return response()->error($e->getMessage());
|
|
85
|
+
} catch (FleetbaseRequestValidationException $e) {
|
|
86
|
+
return response()->error($e->getErrors());
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Handles the download request for an extension bundle.
|
|
92
|
+
*
|
|
93
|
+
* This function retrieves a specific `RegistryExtension` by its ID and attempts to download
|
|
94
|
+
* its latest bundle. If the extension exists and has an associated bundle, it returns a download response
|
|
95
|
+
* with the appropriate file. If the extension doesn't exist or doesn't have a bundle, it returns an error response.
|
|
96
|
+
*
|
|
97
|
+
* @param RegistryExtensionActionRequest $request the validated request object
|
|
98
|
+
*
|
|
99
|
+
* @return \Symfony\Component\HttpFoundation\BinaryFileResponse|\Illuminate\Http\Response
|
|
100
|
+
* Returns a download response for the bundle if successful, or an error response if not
|
|
101
|
+
*/
|
|
102
|
+
public function download(RegistryExtensionActionRequest $request)
|
|
103
|
+
{
|
|
104
|
+
$id = $request->input('id');
|
|
105
|
+
$extensionBundle = RegistryExtensionBundle::find($id);
|
|
106
|
+
if ($extensionBundle && $extensionBundle->bundle) {
|
|
107
|
+
return Storage::disk($extensionBundle->bundle->disk)->download($extensionBundle->bundle->path, $extensionBundle->bundle->name);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
return response()->error('Failed to download extension bundle');
|
|
111
|
+
}
|
|
112
|
+
}
|
|
@@ -0,0 +1,257 @@
|
|
|
1
|
+
<?php
|
|
2
|
+
|
|
3
|
+
namespace Fleetbase\RegistryBridge\Http\Controllers\Internal\v1;
|
|
4
|
+
|
|
5
|
+
use Fleetbase\Exceptions\FleetbaseRequestValidationException;
|
|
6
|
+
use Fleetbase\RegistryBridge\Http\Controllers\RegistryBridgeController;
|
|
7
|
+
use Fleetbase\RegistryBridge\Http\Requests\CreateRegistryExtensionRequest;
|
|
8
|
+
use Fleetbase\RegistryBridge\Http\Requests\RegistryExtensionActionRequest;
|
|
9
|
+
use Fleetbase\RegistryBridge\Models\RegistryExtension;
|
|
10
|
+
use Fleetbase\Support\Utils;
|
|
11
|
+
use Illuminate\Http\Request;
|
|
12
|
+
use Illuminate\Support\Facades\Storage;
|
|
13
|
+
use Illuminate\Support\Facades\Validator;
|
|
14
|
+
|
|
15
|
+
class RegistryExtensionController extends RegistryBridgeController
|
|
16
|
+
{
|
|
17
|
+
/**
|
|
18
|
+
* The resource to query.
|
|
19
|
+
*
|
|
20
|
+
* @var string
|
|
21
|
+
*/
|
|
22
|
+
public $resource = 'registry_extension';
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Creates a record with request payload.
|
|
26
|
+
*
|
|
27
|
+
* @return \Illuminate\Http\Response
|
|
28
|
+
*/
|
|
29
|
+
public function createRecord(Request $request)
|
|
30
|
+
{
|
|
31
|
+
// Create validation request
|
|
32
|
+
$createRegistryExtensionRequest = CreateRegistryExtensionRequest::createFrom($request);
|
|
33
|
+
$rules = $createRegistryExtensionRequest->rules();
|
|
34
|
+
|
|
35
|
+
// Manually validate request
|
|
36
|
+
$validator = Validator::make($request->input('registryExtension'), $rules);
|
|
37
|
+
if ($validator->fails()) {
|
|
38
|
+
return $createRegistryExtensionRequest->responseWithErrors($validator);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
try {
|
|
42
|
+
$record = $this->model->createRecordFromRequest($request);
|
|
43
|
+
|
|
44
|
+
return ['registryExtension' => new $this->resource($record)];
|
|
45
|
+
} catch (\Throwable $e) {
|
|
46
|
+
return response()->error($e->getMessage());
|
|
47
|
+
} catch (\Illuminate\Database\QueryException $e) {
|
|
48
|
+
return response()->error($e->getMessage());
|
|
49
|
+
} catch (FleetbaseRequestValidationException $e) {
|
|
50
|
+
return response()->error($e->getErrors());
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Display a list of installed extensions for the current company.
|
|
56
|
+
*
|
|
57
|
+
* This function retrieves all extensions that are installed for the company
|
|
58
|
+
* identified by the `company_uuid` stored in the session. It disables the cache
|
|
59
|
+
* for the `RegistryExtension` model to ensure fresh data is fetched from the database.
|
|
60
|
+
*
|
|
61
|
+
* The extensions are filtered based on their association with any installation
|
|
62
|
+
* record that matches the `company_uuid` from the session. The resulting collection
|
|
63
|
+
* of installed extensions is then wrapped and returned as a resource collection.
|
|
64
|
+
*
|
|
65
|
+
* @return \Illuminate\Http\Resources\Json\AnonymousResourceCollection the collection of installed extensions wrapped as a resource
|
|
66
|
+
*/
|
|
67
|
+
public function installed()
|
|
68
|
+
{
|
|
69
|
+
$installedExtensions = RegistryExtension::disableCache()->whereHas('installs', function ($query) {
|
|
70
|
+
$query->where('company_uuid', session('company'));
|
|
71
|
+
})->get();
|
|
72
|
+
|
|
73
|
+
$this->resource::wrap('registryExtensions');
|
|
74
|
+
|
|
75
|
+
return $this->resource::collection($installedExtensions);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Display a list of purchased extensions for the current company.
|
|
80
|
+
*
|
|
81
|
+
* This function retrieves all extensions that are purchased for the company
|
|
82
|
+
* identified by the `company_uuid` stored in the session. It disables the cache
|
|
83
|
+
* for the `RegistryExtension` model to ensure fresh data is fetched from the database.
|
|
84
|
+
*
|
|
85
|
+
* The extensions are filtered based on their association with any purchase
|
|
86
|
+
* record that matches the `company_uuid` from the session. The resulting collection
|
|
87
|
+
* of purchased extensions is then wrapped and returned as a resource collection.
|
|
88
|
+
*
|
|
89
|
+
* @return \Illuminate\Http\Resources\Json\AnonymousResourceCollection the collection of purchased extensions wrapped as a resource
|
|
90
|
+
*/
|
|
91
|
+
public function purchased()
|
|
92
|
+
{
|
|
93
|
+
$purchasedExtensions = RegistryExtension::disableCache()->whereHas('purchases', function ($query) {
|
|
94
|
+
$query->where('company_uuid', session('company'));
|
|
95
|
+
})->get();
|
|
96
|
+
|
|
97
|
+
$this->resource::wrap('registryExtensions');
|
|
98
|
+
|
|
99
|
+
return $this->resource::collection($purchasedExtensions);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Retrieve analytics for a specific registry extension.
|
|
104
|
+
*
|
|
105
|
+
* This method fetches analytics for a registry extension identified by
|
|
106
|
+
* the provided ID. It gathers various metrics, including the number of
|
|
107
|
+
* installs, uninstalls, purchases, and the total purchase amount. If the
|
|
108
|
+
* extension cannot be found, it returns an error response. Otherwise, it
|
|
109
|
+
* returns the collected metrics as a JSON response.
|
|
110
|
+
*
|
|
111
|
+
* @param Request $request
|
|
112
|
+
* The incoming request instance containing the extension ID
|
|
113
|
+
*
|
|
114
|
+
* @return \Illuminate\Http\JsonResponse
|
|
115
|
+
* A JSON response containing the collected analytics metrics or an error message
|
|
116
|
+
*/
|
|
117
|
+
public function analytics(Request $request)
|
|
118
|
+
{
|
|
119
|
+
$id = $request->input('id');
|
|
120
|
+
$extension = RegistryExtension::find($id);
|
|
121
|
+
if (!$extension) {
|
|
122
|
+
return response()->error('Unable to find extension to fetch analytics.');
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
$metrics = [];
|
|
126
|
+
|
|
127
|
+
// Get number of installs
|
|
128
|
+
$metrics['install_count'] = $extension->installs()->count();
|
|
129
|
+
|
|
130
|
+
// Get number of uninstalls
|
|
131
|
+
$metrics['uninstall_count'] = $extension->installs()->withoutGlobalScopes()->whereNotNull('deleted_at')->count();
|
|
132
|
+
|
|
133
|
+
// Get number of purchases
|
|
134
|
+
$metrics['purchase_count'] = $extension->purchases()->count();
|
|
135
|
+
|
|
136
|
+
// Get total amount in purchases
|
|
137
|
+
$totalPurchaseAmount = $extension->purchases()->get()->sum('locked_price');
|
|
138
|
+
$metrics['purchase_amount'] = Utils::moneyFormat($totalPurchaseAmount, $extension->currency);
|
|
139
|
+
|
|
140
|
+
// Respond with metrics
|
|
141
|
+
return response()->json($metrics);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* Approves a specific extension by its ID.
|
|
146
|
+
*
|
|
147
|
+
* This function locates a `RegistryExtension` using the provided ID and sets its status to 'approved'.
|
|
148
|
+
* If the extension is successfully found and updated, it returns the extension resource. If the extension
|
|
149
|
+
* cannot be found, it returns an error response indicating the inability to locate the extension.
|
|
150
|
+
*
|
|
151
|
+
* @param RegistryExtensionActionRequest $request the validated request object
|
|
152
|
+
*
|
|
153
|
+
* @return \Illuminate\Http\Response|array returns an array containing the extension resource if successful,
|
|
154
|
+
* or an error response if the extension cannot be found
|
|
155
|
+
*/
|
|
156
|
+
public function approve(RegistryExtensionActionRequest $request)
|
|
157
|
+
{
|
|
158
|
+
$id = $request->input('id');
|
|
159
|
+
$extension = RegistryExtension::find($id);
|
|
160
|
+
if ($extension) {
|
|
161
|
+
$extension->update(['status' => 'approved', 'current_bundle_uuid' => $extension->next_bundle_uuid]);
|
|
162
|
+
$extension->nextBundle()->update(['status' => 'approved']);
|
|
163
|
+
} else {
|
|
164
|
+
return response()->error('Unable to find extension for approval.');
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
return ['registryExtension' => new $this->resource($extension)];
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
* Rejects a specific extension by its ID.
|
|
172
|
+
*
|
|
173
|
+
* Locates a `RegistryExtension` using the provided ID and updates its status to 'rejected'. It also
|
|
174
|
+
* intends to send a rejection reason via email to the extension's author (as indicated by commented code).
|
|
175
|
+
* If the extension is found and updated, it returns the extension resource. If not found, it returns an
|
|
176
|
+
* error response indicating the extension could not be located.
|
|
177
|
+
*
|
|
178
|
+
* Note: This method assumes the rejection reason is handled separately (possibly by another request).
|
|
179
|
+
*
|
|
180
|
+
* @param RegistryExtensionActionRequest $request the validated request object
|
|
181
|
+
*
|
|
182
|
+
* @return \Illuminate\Http\Response|array returns an array containing the extension resource if successful,
|
|
183
|
+
* or an error response if the extension cannot be found
|
|
184
|
+
*/
|
|
185
|
+
public function reject(RegistryExtensionActionRequest $request)
|
|
186
|
+
{
|
|
187
|
+
$id = $request->input('id');
|
|
188
|
+
$extension = RegistryExtension::find($id);
|
|
189
|
+
if ($extension) {
|
|
190
|
+
$extension->update(['status' => 'rejected']);
|
|
191
|
+
$extension->nextBundle()->update(['status' => 'rejected']);
|
|
192
|
+
} else {
|
|
193
|
+
return response()->error('Unable to find extension for rejection.');
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
// send rejection reason via email to extension author
|
|
197
|
+
// $reason = $request->input('reason');
|
|
198
|
+
|
|
199
|
+
return ['registryExtension' => new $this->resource($extension)];
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
/**
|
|
203
|
+
* Submits an extension for review based on its ID.
|
|
204
|
+
*
|
|
205
|
+
* This method attempts to submit a `RegistryExtension` for review. It first checks
|
|
206
|
+
* if the extension is ready for submission by calling the static method
|
|
207
|
+
* `isExtensionReadyForSubmission`. If the extension is not ready, it returns an error response.
|
|
208
|
+
* If the extension is ready, it updates the extension's status to 'awaiting_review' and returns
|
|
209
|
+
* a JSON response indicating success.
|
|
210
|
+
*
|
|
211
|
+
* @param string $id the unique identifier of the extension to be submitted
|
|
212
|
+
*
|
|
213
|
+
* @return \Illuminate\Http\JsonResponse returns a JSON response indicating the outcome of the operation
|
|
214
|
+
*
|
|
215
|
+
* @throws \Illuminate\Database\Eloquent\ModelNotFoundException if no extension with the given ID is found
|
|
216
|
+
*/
|
|
217
|
+
public function submit(string $id)
|
|
218
|
+
{
|
|
219
|
+
$isReady = RegistryExtension::isExtensionReadyForSubmission($id);
|
|
220
|
+
if (!$isReady) {
|
|
221
|
+
return response()->error('Unable to submit extension for review.');
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
$extension = RegistryExtension::find($id);
|
|
225
|
+
if ($extension) {
|
|
226
|
+
$extension->update(['status' => 'awaiting_review']);
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
return ['registryExtension' => new $this->resource($extension)];
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
/**
|
|
233
|
+
* Handles the download request for an extension bundle.
|
|
234
|
+
*
|
|
235
|
+
* This function retrieves a specific `RegistryExtension` by its ID and attempts to download
|
|
236
|
+
* its latest bundle. If the extension exists and has an associated bundle, it returns a download response
|
|
237
|
+
* with the appropriate file. If the extension doesn't exist or doesn't have a bundle, it returns an error response.
|
|
238
|
+
*
|
|
239
|
+
* @param RegistryExtensionActionRequest $request the validated request object
|
|
240
|
+
*
|
|
241
|
+
* @return \Symfony\Component\HttpFoundation\BinaryFileResponse|\Illuminate\Http\Response
|
|
242
|
+
* Returns a download response for the bundle if successful, or an error response if not
|
|
243
|
+
*/
|
|
244
|
+
public function downloadBundle(RegistryExtensionActionRequest $request)
|
|
245
|
+
{
|
|
246
|
+
$id = $request->input('id');
|
|
247
|
+
$extension = RegistryExtension::find($id);
|
|
248
|
+
if ($extension && $extension->nextBundle) {
|
|
249
|
+
$bundleFile = data_get($extension, 'nextBundle.bundle');
|
|
250
|
+
if ($bundleFile) {
|
|
251
|
+
return Storage::disk($bundleFile->disk)->download($bundleFile->path, $bundleFile->name);
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
return response()->error('Failed to download extension bundle');
|
|
256
|
+
}
|
|
257
|
+
}
|
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
<?php
|
|
2
|
+
|
|
3
|
+
namespace Fleetbase\RegistryBridge\Http\Controllers\Internal\v1;
|
|
4
|
+
|
|
5
|
+
use Fleetbase\Http\Controllers\Controller;
|
|
6
|
+
use Fleetbase\Http\Resources\FleetbaseResource;
|
|
7
|
+
use Fleetbase\RegistryBridge\Models\RegistryExtension;
|
|
8
|
+
use Fleetbase\RegistryBridge\Models\RegistryExtensionPurchase;
|
|
9
|
+
use Fleetbase\RegistryBridge\Support\Utils;
|
|
10
|
+
use Fleetbase\Support\Auth;
|
|
11
|
+
use Illuminate\Http\Request;
|
|
12
|
+
use Illuminate\Support\Str;
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Handles payment processing and Stripe account management for registry extensions.
|
|
16
|
+
*
|
|
17
|
+
* This controller provides functionalities such as checking if a company has a Stripe Connect account,
|
|
18
|
+
* creating Stripe accounts, managing Stripe account sessions, and handling Stripe Checkout sessions.
|
|
19
|
+
*/
|
|
20
|
+
class RegistryPaymentsController extends Controller
|
|
21
|
+
{
|
|
22
|
+
/**
|
|
23
|
+
* Checks if the currently authenticated company has an associated Stripe Connect account.
|
|
24
|
+
*
|
|
25
|
+
* This method verifies if the authenticated company has a Stripe Connect ID that starts with 'acct_'.
|
|
26
|
+
*
|
|
27
|
+
* @return \Illuminate\Http\JsonResponse returns a JSON response indicating the presence of a Stripe Connect account
|
|
28
|
+
*/
|
|
29
|
+
public function hasStripeConnectAccount()
|
|
30
|
+
{
|
|
31
|
+
$company = Auth::getCompany();
|
|
32
|
+
if ($company) {
|
|
33
|
+
return response()->json([
|
|
34
|
+
'hasStripeConnectAccount' => !empty($company->stripe_connect_id) && Str::startsWith($company->stripe_connect_id, 'acct_'),
|
|
35
|
+
]);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
return response()->json([
|
|
39
|
+
'hasStripeConnectAccount' => false,
|
|
40
|
+
]);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Creates a new Stripe account for the currently authenticated company and stores the account ID.
|
|
45
|
+
*
|
|
46
|
+
* This method utilizes the Fleetbase utility class to create a Stripe Express account and saves the
|
|
47
|
+
* Stripe account ID to the current company's profile. In case of failure, it returns an error.
|
|
48
|
+
*
|
|
49
|
+
* @return \Illuminate\Http\JsonResponse returns the Stripe account ID or an error message in JSON format
|
|
50
|
+
*/
|
|
51
|
+
public function getStripeAccount()
|
|
52
|
+
{
|
|
53
|
+
$stripe = Utils::getStripeClient();
|
|
54
|
+
|
|
55
|
+
try {
|
|
56
|
+
$account = $stripe->accounts->create([
|
|
57
|
+
'controller' => [
|
|
58
|
+
'stripe_dashboard' => [
|
|
59
|
+
'type' => 'express',
|
|
60
|
+
],
|
|
61
|
+
'fees' => [
|
|
62
|
+
'payer' => 'application',
|
|
63
|
+
],
|
|
64
|
+
'losses' => [
|
|
65
|
+
'payments' => 'application',
|
|
66
|
+
],
|
|
67
|
+
],
|
|
68
|
+
]);
|
|
69
|
+
|
|
70
|
+
// Save account ID to current company session
|
|
71
|
+
$company = Auth::getCompany();
|
|
72
|
+
if ($company) {
|
|
73
|
+
$company->update(['stripe_connect_id' => $account->id]);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
return response()->json(['account' => $account->id]);
|
|
77
|
+
} catch (\Exception $e) {
|
|
78
|
+
return response()->error($e->getMessage());
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Creates a Stripe account session for account onboarding or management.
|
|
84
|
+
*
|
|
85
|
+
* This method creates a session for the current company's Stripe account, allowing for onboarding or management activities.
|
|
86
|
+
* It accepts an 'account' parameter from the request, defaulting to the company's stored Stripe Connect ID if not provided.
|
|
87
|
+
*
|
|
88
|
+
* @param Request $request the incoming HTTP request containing optional 'account' parameter
|
|
89
|
+
*
|
|
90
|
+
* @return \Illuminate\Http\JsonResponse returns a JSON response with the session's client secret or an error message
|
|
91
|
+
*/
|
|
92
|
+
public function getStripeAccountSession(Request $request)
|
|
93
|
+
{
|
|
94
|
+
$stripe = Utils::getStripeClient();
|
|
95
|
+
$company = Auth::getCompany();
|
|
96
|
+
|
|
97
|
+
try {
|
|
98
|
+
$accountSession = $stripe->accountSessions->create([
|
|
99
|
+
'account' => $request->input('account', $company->stripe_connect_id),
|
|
100
|
+
'components' => [
|
|
101
|
+
'account_onboarding' => [
|
|
102
|
+
'enabled' => true,
|
|
103
|
+
],
|
|
104
|
+
],
|
|
105
|
+
]);
|
|
106
|
+
|
|
107
|
+
return response()->json([
|
|
108
|
+
'clientSecret' => $accountSession->client_secret,
|
|
109
|
+
]);
|
|
110
|
+
} catch (\Exception $e) {
|
|
111
|
+
return response()->error($e->getMessage());
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Creates a Stripe Checkout session for a specified registry extension.
|
|
117
|
+
*
|
|
118
|
+
* This method initializes a checkout session for purchasing a registry extension identified by a UUID.
|
|
119
|
+
* It requires a 'uri' for redirection after the checkout and an 'extension' UUID to identify the product.
|
|
120
|
+
*
|
|
121
|
+
* @param Request $request the incoming HTTP request with 'uri' and 'extension' parameters
|
|
122
|
+
*
|
|
123
|
+
* @return \Illuminate\Http\JsonResponse returns the checkout session's client secret or an error message
|
|
124
|
+
*/
|
|
125
|
+
public function createStripeCheckoutSession(Request $request)
|
|
126
|
+
{
|
|
127
|
+
$redirectUri = $request->input('uri');
|
|
128
|
+
$extension = RegistryExtension::where('uuid', $request->input('extension'))->first();
|
|
129
|
+
if (!$extension) {
|
|
130
|
+
return response()->error('The extension you attempted to purchase does not exist.');
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
try {
|
|
134
|
+
$checkoutSession = $extension->createStripeCheckoutSession($redirectUri);
|
|
135
|
+
} catch (\Throwable $e) {
|
|
136
|
+
return response()->error($e->getMessage());
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
return response()->json(['clientSecret' => $checkoutSession->client_secret]);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* Retrieves the status of an ongoing Stripe Checkout session.
|
|
144
|
+
*
|
|
145
|
+
* This method checks the status of a Stripe Checkout session associated with a registry extension purchase.
|
|
146
|
+
* It ensures the extension exists and checks if it has already been purchased. It then retrieves and returns
|
|
147
|
+
* the checkout session status or creates a purchase record if the session is complete.
|
|
148
|
+
*
|
|
149
|
+
* @param Request $request the incoming HTTP request containing 'extension' and 'checkout_session_id'
|
|
150
|
+
*
|
|
151
|
+
* @return \Illuminate\Http\JsonResponse returns the checkout session status or an error message
|
|
152
|
+
*/
|
|
153
|
+
public function getStripeCheckoutSessionStatus(Request $request)
|
|
154
|
+
{
|
|
155
|
+
$extension = RegistryExtension::where('uuid', $request->input('extension'))->first();
|
|
156
|
+
if (!$extension) {
|
|
157
|
+
return response()->error('The extension you attempted to purchase does not exist.');
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
// Flush cache for extension
|
|
161
|
+
if (method_exists($extension, 'flushCache')) {
|
|
162
|
+
$extension->flushCache();
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
// Check if already purchased
|
|
166
|
+
$purchaseRecordExists = RegistryExtensionPurchase::where(['company_uuid' => session('company'), 'extension_uuid' => $extension->uuid])->exists();
|
|
167
|
+
if ($purchaseRecordExists) {
|
|
168
|
+
return response()->json(['status' => 'purchase_complete', 'extension' => $extension]);
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
$stripe = Utils::getStripeClient();
|
|
172
|
+
try {
|
|
173
|
+
$session = $stripe->checkout->sessions->retrieve($request->input('checkout_session_id'));
|
|
174
|
+
if (isset($session->status) && $session->status === 'complete') {
|
|
175
|
+
RegistryExtensionPurchase::firstOrCreate(
|
|
176
|
+
[
|
|
177
|
+
'company_uuid' => session('company'),
|
|
178
|
+
'extension_uuid' => $extension->uuid,
|
|
179
|
+
],
|
|
180
|
+
[
|
|
181
|
+
'stripe_checkout_session_id' => $session->id,
|
|
182
|
+
'stripe_payment_intent_id' => $session->payment_intent,
|
|
183
|
+
'locked_price' => $session->amount_total,
|
|
184
|
+
]
|
|
185
|
+
);
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
// Flush cache for extension
|
|
189
|
+
if (method_exists($extension, 'flushCache')) {
|
|
190
|
+
$extension->flushCache();
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
return response()->json(['status' => $session->status, 'extension' => $extension]);
|
|
194
|
+
} catch (\Error $e) {
|
|
195
|
+
return response()->error($e->getMessage());
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
public function getAuthorReceivedPayments(Request $request)
|
|
200
|
+
{
|
|
201
|
+
$limit = $request->input('limit', 30);
|
|
202
|
+
$query = RegistryExtensionPurchase::whereHas(
|
|
203
|
+
'extension',
|
|
204
|
+
function ($query) {
|
|
205
|
+
$query->where('company_uuid', session('company'));
|
|
206
|
+
}
|
|
207
|
+
)->with(
|
|
208
|
+
[
|
|
209
|
+
'extension' => function ($query) {
|
|
210
|
+
$query->select(['uuid', 'public_id', 'name', 'category_uuid']);
|
|
211
|
+
$query->with(['category']);
|
|
212
|
+
},
|
|
213
|
+
'company' => function ($query) {
|
|
214
|
+
$query->select(['uuid', 'name'])->withoutGlobalScopes();
|
|
215
|
+
},
|
|
216
|
+
]
|
|
217
|
+
);
|
|
218
|
+
|
|
219
|
+
// Handle sorting
|
|
220
|
+
app(RegistryExtensionPurchase::class)->applySorts($request, $query);
|
|
221
|
+
|
|
222
|
+
$payments = $query->fastPaginate($limit);
|
|
223
|
+
$totalPurchaseAmount = $query->get()->sum('locked_price');
|
|
224
|
+
|
|
225
|
+
return FleetbaseResource::collection($payments)->additional(['total_amount' => $totalPurchaseAmount]);
|
|
226
|
+
}
|
|
227
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
<?php
|
|
2
|
+
|
|
3
|
+
namespace Fleetbase\RegistryBridge\Http\Controllers;
|
|
4
|
+
|
|
5
|
+
use Fleetbase\Http\Controllers\FleetbaseController;
|
|
6
|
+
|
|
7
|
+
class RegistryBridgeController extends FleetbaseController
|
|
8
|
+
{
|
|
9
|
+
/**
|
|
10
|
+
* The package namespace used to resolve from.
|
|
11
|
+
*/
|
|
12
|
+
public string $namespace = '\\Fleetbase\\RegistryBridge';
|
|
13
|
+
}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
<?php
|
|
2
|
+
|
|
3
|
+
namespace Fleetbase\RegistryBridge\Http\Filter;
|
|
4
|
+
|
|
5
|
+
use Fleetbase\Http\Filter\Filter;
|
|
6
|
+
use Fleetbase\Support\Utils;
|
|
7
|
+
use Illuminate\Support\Str;
|
|
8
|
+
|
|
9
|
+
class RegistryExtensionFilter extends Filter
|
|
10
|
+
{
|
|
11
|
+
public function queryForInternal()
|
|
12
|
+
{
|
|
13
|
+
if ($this->request->boolean('explore')) {
|
|
14
|
+
return;
|
|
15
|
+
}
|
|
16
|
+
$this->builder->where('company_uuid', $this->session->get('company'));
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
public function queryForPublic()
|
|
20
|
+
{
|
|
21
|
+
$this->builder->where('company_uuid', $this->session->get('company'));
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
public function query(?string $searchQuery)
|
|
25
|
+
{
|
|
26
|
+
$this->builder->search($searchQuery);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
public function isAuthor()
|
|
30
|
+
{
|
|
31
|
+
$this->builder->where('company_uuid', session('company'));
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
public function explore()
|
|
35
|
+
{
|
|
36
|
+
$this->builder->where('status', 'published');
|
|
37
|
+
$this->builder->without(['current_bundle', 'next_bundle', 'category']);
|
|
38
|
+
$this->builder->with(['screenshots']);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
public function category($category)
|
|
42
|
+
{
|
|
43
|
+
if (Str::isUuid($category)) {
|
|
44
|
+
return $this->builder->where('category_uuid', $category);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
if (Utils::isPublicId($category)) {
|
|
48
|
+
return $this->builder->whereHas('category', function ($query) use ($category) {
|
|
49
|
+
$query->where('public_id', $category)->where('for', 'extension_category')->where('core_category', 1);
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// assume slug
|
|
54
|
+
return $this->builder->whereHas('category', function ($query) use ($category) {
|
|
55
|
+
$query->where('slug', $category)->where('for', 'extension_category')->where('core_category', 1);
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
public function createdAt($createdAt)
|
|
60
|
+
{
|
|
61
|
+
$createdAt = Utils::dateRange($createdAt);
|
|
62
|
+
|
|
63
|
+
if (is_array($createdAt)) {
|
|
64
|
+
$this->builder->whereBetween('created_at', $createdAt);
|
|
65
|
+
} else {
|
|
66
|
+
$this->builder->whereDate('created_at', $createdAt);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
public function updatedAt($updatedAt)
|
|
71
|
+
{
|
|
72
|
+
$updatedAt = Utils::dateRange($updatedAt);
|
|
73
|
+
|
|
74
|
+
if (is_array($updatedAt)) {
|
|
75
|
+
$this->builder->whereBetween('updated_at', $updatedAt);
|
|
76
|
+
} else {
|
|
77
|
+
$this->builder->whereDate('updated_at', $updatedAt);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|