@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.
Files changed (211) hide show
  1. package/.php-cs-fixer.php +29 -0
  2. package/LICENSE.md +651 -0
  3. package/README.md +122 -0
  4. package/addon/adapters/registry-bridge.js +5 -0
  5. package/addon/adapters/registry-extension-bundle.js +1 -0
  6. package/addon/adapters/registry-extension.js +1 -0
  7. package/addon/components/extension-card.hbs +12 -0
  8. package/addon/components/extension-card.js +235 -0
  9. package/addon/components/extension-form.hbs +237 -0
  10. package/addon/components/extension-form.js +123 -0
  11. package/addon/components/extension-modal-title.hbs +14 -0
  12. package/addon/components/extension-modal-title.js +20 -0
  13. package/addon/components/extension-monetize-form.hbs +56 -0
  14. package/addon/components/extension-monetize-form.js +7 -0
  15. package/addon/components/extension-pending-publish-viewer.hbs +52 -0
  16. package/addon/components/extension-pending-publish-viewer.js +37 -0
  17. package/addon/components/extension-reviewer-control.hbs +68 -0
  18. package/addon/components/extension-reviewer-control.js +68 -0
  19. package/addon/components/modals/confirm-extension-purchase.hbs +5 -0
  20. package/addon/components/modals/confirm-extension-purchase.js +3 -0
  21. package/addon/components/modals/extension-details.hbs +69 -0
  22. package/addon/components/modals/extension-details.js +33 -0
  23. package/addon/components/modals/extension-purchase-form.hbs +5 -0
  24. package/addon/components/modals/extension-purchase-form.js +3 -0
  25. package/addon/components/modals/extension-uninstall.hbs +25 -0
  26. package/addon/components/modals/extension-uninstall.js +11 -0
  27. package/addon/components/modals/select-extension-bundle.hbs +43 -0
  28. package/addon/components/modals/select-extension-bundle.js +31 -0
  29. package/addon/components/progress-bar.hbs +12 -0
  30. package/addon/components/progress-bar.js +8 -0
  31. package/addon/controllers/application.js +6 -0
  32. package/addon/controllers/developers/analytics.js +26 -0
  33. package/addon/controllers/developers/extensions/edit/bundles.js +70 -0
  34. package/addon/controllers/developers/extensions/edit/index.js +3 -0
  35. package/addon/controllers/developers/extensions/edit/monetize.js +7 -0
  36. package/addon/controllers/developers/extensions/edit.js +107 -0
  37. package/addon/controllers/developers/extensions/index.js +3 -0
  38. package/addon/controllers/developers/extensions/new.js +32 -0
  39. package/addon/controllers/developers/payments/index.js +39 -0
  40. package/addon/controllers/developers/payments/onboard.js +67 -0
  41. package/addon/controllers/explore/category.js +22 -0
  42. package/addon/controllers/explore/index.js +15 -0
  43. package/addon/controllers/installed.js +86 -0
  44. package/addon/controllers/purchased.js +18 -0
  45. package/addon/engine.js +44 -0
  46. package/addon/models/registry-extension-bundle.js +62 -0
  47. package/addon/models/registry-extension.js +215 -0
  48. package/addon/routes/application.js +12 -0
  49. package/addon/routes/developers/analytics.js +10 -0
  50. package/addon/routes/developers/credentials.js +3 -0
  51. package/addon/routes/developers/extensions/edit/bundles.js +21 -0
  52. package/addon/routes/developers/extensions/edit/details.js +3 -0
  53. package/addon/routes/developers/extensions/edit/index.js +3 -0
  54. package/addon/routes/developers/extensions/edit/monetize.js +3 -0
  55. package/addon/routes/developers/extensions/edit.js +18 -0
  56. package/addon/routes/developers/extensions/index.js +10 -0
  57. package/addon/routes/developers/extensions/new.js +3 -0
  58. package/addon/routes/developers/extensions.js +3 -0
  59. package/addon/routes/developers/payments/index.js +26 -0
  60. package/addon/routes/developers/payments/onboard.js +21 -0
  61. package/addon/routes/developers/payments.js +3 -0
  62. package/addon/routes/developers.js +3 -0
  63. package/addon/routes/explore/category.js +27 -0
  64. package/addon/routes/explore/index.js +17 -0
  65. package/addon/routes/explore.js +3 -0
  66. package/addon/routes/installed.js +10 -0
  67. package/addon/routes/purchased.js +10 -0
  68. package/addon/routes.js +28 -0
  69. package/addon/serializers/registry-extension-bundle.js +15 -0
  70. package/addon/serializers/registry-extension.js +21 -0
  71. package/addon/services/stripe.js +83 -0
  72. package/addon/styles/registry-bridge-engine.css +142 -0
  73. package/addon/templates/application.hbs +26 -0
  74. package/addon/templates/developers/analytics.hbs +83 -0
  75. package/addon/templates/developers/credentials.hbs +1 -0
  76. package/addon/templates/developers/extensions/edit/bundles.hbs +71 -0
  77. package/addon/templates/developers/extensions/edit/details.hbs +16 -0
  78. package/addon/templates/developers/extensions/edit/index.hbs +1 -0
  79. package/addon/templates/developers/extensions/edit/monetize.hbs +3 -0
  80. package/addon/templates/developers/extensions/edit.hbs +48 -0
  81. package/addon/templates/developers/extensions/index.hbs +27 -0
  82. package/addon/templates/developers/extensions/new.hbs +39 -0
  83. package/addon/templates/developers/extensions.hbs +1 -0
  84. package/addon/templates/developers/payments/index.hbs +33 -0
  85. package/addon/templates/developers/payments/onboard.hbs +48 -0
  86. package/addon/templates/developers/payments.hbs +1 -0
  87. package/addon/templates/developers.hbs +1 -0
  88. package/addon/templates/explore/category.hbs +12 -0
  89. package/addon/templates/explore/index.hbs +12 -0
  90. package/addon/templates/explore.hbs +1 -0
  91. package/addon/templates/installed.hbs +32 -0
  92. package/addon/templates/purchased.hbs +34 -0
  93. package/app/adapters/registry-bridge.js +1 -0
  94. package/app/adapters/registry-extension-bundle.js +1 -0
  95. package/app/adapters/registry-extension.js +1 -0
  96. package/app/components/extension-card.js +1 -0
  97. package/app/components/extension-form.js +1 -0
  98. package/app/components/extension-modal-title.js +1 -0
  99. package/app/components/extension-monetize-form.js +1 -0
  100. package/app/components/extension-pending-publish-viewer.js +1 -0
  101. package/app/components/extension-reviewer-control.js +1 -0
  102. package/app/components/modals/confirm-extension-purchase.js +1 -0
  103. package/app/components/modals/extension-details.js +1 -0
  104. package/app/components/modals/extension-purchase-form.js +1 -0
  105. package/app/components/modals/extension-uninstall.js +1 -0
  106. package/app/components/modals/select-extension-bundle.js +1 -0
  107. package/app/components/progress-bar.js +1 -0
  108. package/app/controllers/application.js +1 -0
  109. package/app/controllers/developers/analytics.js +1 -0
  110. package/app/controllers/developers/extensions/edit/bundles.js +1 -0
  111. package/app/controllers/developers/extensions/edit/index.js +1 -0
  112. package/app/controllers/developers/extensions/edit/monetize.js +1 -0
  113. package/app/controllers/developers/extensions/edit.js +1 -0
  114. package/app/controllers/developers/extensions/index.js +1 -0
  115. package/app/controllers/developers/extensions/new.js +1 -0
  116. package/app/controllers/developers/payments/index.js +1 -0
  117. package/app/controllers/developers/payments/onboard.js +1 -0
  118. package/app/controllers/explore/category.js +1 -0
  119. package/app/controllers/explore/index.js +1 -0
  120. package/app/controllers/installed.js +1 -0
  121. package/app/controllers/purchased.js +1 -0
  122. package/app/models/registry-extension-bundle.js +1 -0
  123. package/app/models/registry-extension.js +1 -0
  124. package/app/routes/developers/analytics.js +1 -0
  125. package/app/routes/developers/credentials.js +1 -0
  126. package/app/routes/developers/extensions/edit/bundles.js +1 -0
  127. package/app/routes/developers/extensions/edit/details.js +1 -0
  128. package/app/routes/developers/extensions/edit/index.js +1 -0
  129. package/app/routes/developers/extensions/edit/monetize.js +1 -0
  130. package/app/routes/developers/extensions/edit.js +1 -0
  131. package/app/routes/developers/extensions/index.js +1 -0
  132. package/app/routes/developers/extensions/new.js +1 -0
  133. package/app/routes/developers/extensions.js +1 -0
  134. package/app/routes/developers/payments/index.js +1 -0
  135. package/app/routes/developers/payments/onboard.js +1 -0
  136. package/app/routes/developers/payments.js +1 -0
  137. package/app/routes/developers.js +1 -0
  138. package/app/routes/explore/category.js +1 -0
  139. package/app/routes/explore/index.js +1 -0
  140. package/app/routes/explore.js +1 -0
  141. package/app/routes/installed.js +1 -0
  142. package/app/routes/purchased.js +1 -0
  143. package/app/serializers/registry-extension-bundle.js +1 -0
  144. package/app/serializers/registry-extension.js +1 -0
  145. package/app/services/stripe.js +1 -0
  146. package/app/templates/developers/analytics.js +1 -0
  147. package/app/templates/developers/credentials.js +1 -0
  148. package/app/templates/developers/extensions/edit/bundles.js +1 -0
  149. package/app/templates/developers/extensions/edit/details.js +1 -0
  150. package/app/templates/developers/extensions/edit/index.js +1 -0
  151. package/app/templates/developers/extensions/edit/monetize.js +1 -0
  152. package/app/templates/developers/extensions/edit.js +1 -0
  153. package/app/templates/developers/extensions/index.js +1 -0
  154. package/app/templates/developers/extensions/new.js +1 -0
  155. package/app/templates/developers/extensions.js +1 -0
  156. package/app/templates/developers/payments/index.js +1 -0
  157. package/app/templates/developers/payments/onboard.js +1 -0
  158. package/app/templates/developers/payments.js +1 -0
  159. package/app/templates/developers.js +1 -0
  160. package/app/templates/explore/category.js +1 -0
  161. package/app/templates/explore/index.js +1 -0
  162. package/app/templates/explore.js +1 -0
  163. package/app/templates/installed.js +1 -0
  164. package/app/templates/purchased.js +1 -0
  165. package/composer.json +95 -0
  166. package/config/environment.js +28 -0
  167. package/extension.json +10 -0
  168. package/index.js +26 -0
  169. package/package.json +129 -0
  170. package/phpstan.neon.dist +8 -0
  171. package/phpunit.xml.dist +16 -0
  172. package/server/.gitattributes +14 -0
  173. package/server/config/registry-bridge.php +32 -0
  174. package/server/migrations/2024_03_19_060627_create_registry_users_table.php +42 -0
  175. package/server/migrations/2024_03_21_051614_create_registry_extensions_table.php +76 -0
  176. package/server/migrations/2024_03_25_044537_create_registry_extension_bundles_table.php +54 -0
  177. package/server/migrations/2024_03_29_072101_registry_extension_installs.php +35 -0
  178. package/server/migrations/2024_07_16_155000_create_registry_extension_purchases.php +41 -0
  179. package/server/seeders/ExtensionsCategorySeeder.php +359 -0
  180. package/server/src/Console/Commands/Initialize.php +35 -0
  181. package/server/src/Console/Commands/PostInstallExtension.php +84 -0
  182. package/server/src/Exceptions/InstallFailedException.php +21 -0
  183. package/server/src/Expansions/CategoryExpansion.php +30 -0
  184. package/server/src/Http/Controllers/Internal/v1/ExtensionInstallerController.php +153 -0
  185. package/server/src/Http/Controllers/Internal/v1/RegistryAuthController.php +230 -0
  186. package/server/src/Http/Controllers/Internal/v1/RegistryController.php +54 -0
  187. package/server/src/Http/Controllers/Internal/v1/RegistryExtensionBundleController.php +112 -0
  188. package/server/src/Http/Controllers/Internal/v1/RegistryExtensionController.php +257 -0
  189. package/server/src/Http/Controllers/Internal/v1/RegistryPaymentsController.php +227 -0
  190. package/server/src/Http/Controllers/RegistryBridgeController.php +13 -0
  191. package/server/src/Http/Filter/RegistryExtensionFilter.php +80 -0
  192. package/server/src/Http/Requests/AddRegistryUserRequest.php +47 -0
  193. package/server/src/Http/Requests/AuthenticateRegistryUserRequest.php +47 -0
  194. package/server/src/Http/Requests/CreateRegistryExtensionBundleRequest.php +42 -0
  195. package/server/src/Http/Requests/CreateRegistryExtensionRequest.php +31 -0
  196. package/server/src/Http/Requests/InstallExtensionRequest.php +30 -0
  197. package/server/src/Http/Requests/RegistryAuthRequest.php +46 -0
  198. package/server/src/Http/Requests/RegistryExtensionActionRequest.php +30 -0
  199. package/server/src/Http/Resources/RegistryUser.php +40 -0
  200. package/server/src/Models/RegistryExtension.php +656 -0
  201. package/server/src/Models/RegistryExtensionBundle.php +1015 -0
  202. package/server/src/Models/RegistryExtensionInstall.php +76 -0
  203. package/server/src/Models/RegistryExtensionPurchase.php +87 -0
  204. package/server/src/Models/RegistryUser.php +140 -0
  205. package/server/src/Providers/RegistryBridgeServiceProvider.php +117 -0
  206. package/server/src/Support/Bridge.php +53 -0
  207. package/server/src/Support/Utils.php +19 -0
  208. package/server/src/routes.php +58 -0
  209. package/server/tests/Feature.php +5 -0
  210. package/translations/en-us.yaml +119 -0
  211. package/tsconfig.declarations.json +10 -0
@@ -0,0 +1,35 @@
1
+ <?php
2
+
3
+ namespace Fleetbase\RegistryBridge\Console\Commands;
4
+
5
+ use Fleetbase\RegistryBridge\Providers\RegistryBridgeServiceProvider;
6
+ use Illuminate\Console\Command;
7
+
8
+ class Initialize extends Command
9
+ {
10
+ /**
11
+ * The name and signature of the console command.
12
+ *
13
+ * @var string
14
+ */
15
+ protected $signature = 'registry:init';
16
+
17
+ /**
18
+ * The console command description.
19
+ *
20
+ * @var string
21
+ */
22
+ protected $description = 'Runs initialization for registry bridge.';
23
+
24
+ /**
25
+ * Execute the console command.
26
+ *
27
+ * @return int
28
+ */
29
+ public function handle()
30
+ {
31
+ RegistryBridgeServiceProvider::bootRegistryAuth(true);
32
+
33
+ return 0;
34
+ }
35
+ }
@@ -0,0 +1,84 @@
1
+ <?php
2
+
3
+ namespace Fleetbase\RegistryBridge\Console\Commands;
4
+
5
+ use Fleetbase\RegistryBridge\Models\RegistryExtension;
6
+ use Illuminate\Console\Command;
7
+ use Symfony\Component\Process\Exception\ProcessFailedException;
8
+ use Symfony\Component\Process\Process;
9
+
10
+ class PostInstallExtension extends Command
11
+ {
12
+ /**
13
+ * The name and signature of the console command.
14
+ *
15
+ * @var string
16
+ */
17
+ protected $signature = 'registry:post-install {extensionId}';
18
+
19
+ /**
20
+ * The console command description.
21
+ *
22
+ * @var string
23
+ */
24
+ protected $description = 'Post install an extension by running necessary commands';
25
+
26
+ /**
27
+ * Execute the console command.
28
+ *
29
+ * @return int
30
+ */
31
+ public function handle()
32
+ {
33
+ $extensionId = $this->argument('extensionId');
34
+ $extension = RegistryExtension::disableCache()->where('public_id', $extensionId)->first();
35
+
36
+ if ($extension) {
37
+ $this->postInstallExtension($extension);
38
+ $this->info('Post install commands executed successfully.');
39
+ } else {
40
+ $this->error('Extension not found.');
41
+ }
42
+
43
+ return 0;
44
+ }
45
+
46
+ /**
47
+ * Post install extension commands.
48
+ */
49
+ public function postInstallExtension(RegistryExtension $extension): void
50
+ {
51
+ if (isset($extension->currentBundle)) {
52
+ $composerJson = $extension->currentBundle->meta['composer.json'];
53
+ if ($composerJson) {
54
+ $extensionPath = base_path('vendor/' . $composerJson['name']);
55
+
56
+ $commands = [
57
+ 'rm -rf /fleetbase/.pnpm-store',
58
+ 'rm -rf node_modules',
59
+ 'pnpm install',
60
+ 'pnpm build',
61
+ ];
62
+
63
+ $this->info('Running post install for: ' . $extension->name);
64
+ $this->info('Extension install path: ' . $extensionPath);
65
+ foreach ($commands as $command) {
66
+ $this->info('Running extension post install command: `' . $command . '`');
67
+ $process = Process::fromShellCommandline($command, $extensionPath);
68
+ $process->run(function ($type, $buffer) {
69
+ if (Process::ERR === $type) {
70
+ $this->error($buffer);
71
+ } else {
72
+ $this->info($buffer);
73
+ }
74
+ });
75
+
76
+ // Check if the process was successful
77
+ if (!$process->isSuccessful()) {
78
+ throw new ProcessFailedException($process);
79
+ }
80
+ }
81
+ }
82
+ }
83
+ }
84
+ }
@@ -0,0 +1,21 @@
1
+ <?php
2
+
3
+ namespace Fleetbase\RegistryBridge\Exceptions;
4
+
5
+ /**
6
+ * Represents an exception thrown when a package installation fails.
7
+ */
8
+ class InstallFailedException extends \Exception
9
+ {
10
+ /**
11
+ * Constructs the InstallFailedException.
12
+ *
13
+ * @param string $message the Exception message to throw
14
+ * @param int $code the Exception code
15
+ * @param \Throwable|null $previous the previous throwable used for the exception chaining
16
+ */
17
+ public function __construct($message = '', $code = 0, ?\Throwable $previous = null)
18
+ {
19
+ parent::__construct($message, $code, $previous);
20
+ }
21
+ }
@@ -0,0 +1,30 @@
1
+ <?php
2
+
3
+ namespace Fleetbase\RegistryBridge\Expansions;
4
+
5
+ use Fleetbase\Build\Expansion;
6
+ use Fleetbase\RegistryBridge\Models\RegistryExtension;
7
+
8
+ class CategoryExpansion implements Expansion
9
+ {
10
+ /**
11
+ * Get the target class to expand.
12
+ *
13
+ * @return string|Class
14
+ */
15
+ public static function target()
16
+ {
17
+ return \Fleetbase\Models\Category::class;
18
+ }
19
+
20
+ /**
21
+ * @return \Illuminate\Database\Eloquent\Relations\HasMany
22
+ */
23
+ public static function registryExtensions()
24
+ {
25
+ return function () {
26
+ /* @var \Illuminate\Database\Eloquent\Model $this */
27
+ return $this->hasMany(RegistryExtension::class, 'category_uuid', 'uuid')->where('status', 'published');
28
+ };
29
+ }
30
+ }
@@ -0,0 +1,153 @@
1
+ <?php
2
+
3
+ namespace Fleetbase\RegistryBridge\Http\Controllers\Internal\v1;
4
+
5
+ use Fleetbase\Http\Controllers\Controller;
6
+ use Fleetbase\RegistryBridge\Http\Requests\InstallExtensionRequest;
7
+ use Fleetbase\RegistryBridge\Models\RegistryExtension;
8
+ use Fleetbase\RegistryBridge\Models\RegistryExtensionInstall;
9
+
10
+ class ExtensionInstallerController extends Controller
11
+ {
12
+ /**
13
+ * Installs a specified extension for a company.
14
+ *
15
+ * This method handles the installation process of an extension. It first looks up
16
+ * the extension in the `RegistryExtension` model using its public identifier provided
17
+ * in the request. Then, it ensures that the installation is recorded in the
18
+ * `RegistryExtensionInstall` model, linking the extension to the current company.
19
+ * If the installation record already exists, it does not create a duplicate.
20
+ *
21
+ * @param InstallExtensionRequest $request The request object containing the extension
22
+ * identifier. Expected to have an 'extension'
23
+ * field with the public ID of the extension.
24
+ *
25
+ * @return \Illuminate\Http\JsonResponse Returns a JSON response indicating the status.
26
+ * The response contains a 'status' key with the
27
+ * value 'ok' if the process is successful.
28
+ *
29
+ * @throws \Exception throws an exception if the specified extension is not found in the
30
+ * `RegistryExtension` model, leading to a potential error when
31
+ * trying to access properties of a non-object (`$extension->uuid`)
32
+ */
33
+ public function install(InstallExtensionRequest $request)
34
+ {
35
+ set_time_limit(120 * 6);
36
+ $extension = RegistryExtension::where('public_id', $request->input('extension'))->first();
37
+
38
+ // Check if already installed
39
+ $installed = RegistryExtensionInstall::disableCache()->where(['company_uuid' => session('company'), 'extension_uuid' => $extension->uuid])->exists();
40
+ if ($installed) {
41
+ return response()->error('This extension is already installed.');
42
+ }
43
+
44
+ // Check if extensions are pre-installed to system
45
+ $PREINSTALLED_EXTENSIONS = config('registry-bridge.extensions.preinstalled') === true;
46
+
47
+ // Run installers if extension needs to be installed
48
+ if ($PREINSTALLED_EXTENSIONS === false) {
49
+ // Install for Composer
50
+ try {
51
+ $extension->currentBundle->installComposerPackage();
52
+ } catch (\Throwable $e) {
53
+ return response()->error($e->getMessage());
54
+ }
55
+
56
+ // Install for Console
57
+ try {
58
+ $extension->currentBundle->installEnginePackage();
59
+ } catch (\Throwable $e) {
60
+ return response()->error($e->getMessage());
61
+ }
62
+
63
+ // Rebuild Console
64
+ try {
65
+ $extension->currentBundle->buildConsole();
66
+ } catch (\Throwable $e) {
67
+ return response()->error($e->getMessage());
68
+ }
69
+ }
70
+
71
+ // Run installer progress if preinstalled
72
+ if ($PREINSTALLED_EXTENSIONS === true) {
73
+ $extension->currentBundle->runInstallerProgress();
74
+ }
75
+
76
+ // Create install record
77
+ $install = RegistryExtensionInstall::create([
78
+ 'company_uuid' => session('company'),
79
+ 'extension_uuid' => $extension->uuid,
80
+ ]);
81
+
82
+ return response()->json(['status' => 'ok', 'install' => $install]);
83
+ }
84
+
85
+ /**
86
+ * Uninstall a specific extension for the current company.
87
+ *
88
+ * This function handles the uninstallation of an extension specified by the public ID
89
+ * provided in the request. It first checks if the extension is already uninstalled for
90
+ * the company identified by the `company_uuid` stored in the session. If the extension
91
+ * is not installed, an error response is returned.
92
+ *
93
+ * If the extension is installed, it proceeds to uninstall the extension using Composer
94
+ * and removes the corresponding installation records from the database. If any errors
95
+ * occur during the Composer uninstallation process, an error response is returned.
96
+ *
97
+ * @param InstallExtensionRequest $request the request containing the public ID of the extension to be uninstalled
98
+ *
99
+ * @return \Illuminate\Http\JsonResponse a JSON response indicating the status of the uninstallation process
100
+ */
101
+ public function uninstall(InstallExtensionRequest $request)
102
+ {
103
+ set_time_limit(120 * 6);
104
+ $extension = RegistryExtension::where('public_id', $request->input('extension'))->first();
105
+ $uninstalled = false;
106
+
107
+ // Check if already uninstalled
108
+ $uninstalled = RegistryExtensionInstall::disableCache()->where(['company_uuid' => session('company'), 'extension_uuid' => $extension->uuid])->doesntExist();
109
+ if ($uninstalled) {
110
+ return response()->error('This extension is not installed.');
111
+ }
112
+
113
+ // Check if extensions are pre-installed to system
114
+ $PREINSTALLED_EXTENSIONS = config('registry-bridge.extensions.preinstalled') === true;
115
+
116
+ // Run installers if extension needs to be installed
117
+ if ($PREINSTALLED_EXTENSIONS === false) {
118
+ // Uninstall for Composer
119
+ try {
120
+ $extension->currentBundle->uninstallComposerPackage();
121
+ } catch (\Throwable $e) {
122
+ return response()->error($e->getMessage());
123
+ }
124
+
125
+ // Unnstall for Console
126
+ try {
127
+ $extension->currentBundle->uninstallEnginePackage();
128
+ } catch (\Throwable $e) {
129
+ return response()->error($e->getMessage());
130
+ }
131
+
132
+ // Rebuild Console
133
+ try {
134
+ $extension->currentBundle->buildConsole();
135
+ } catch (\Throwable $e) {
136
+ return response()->error($e->getMessage());
137
+ }
138
+ }
139
+
140
+ // Run installer progress if preinstalled
141
+ if ($PREINSTALLED_EXTENSIONS === true) {
142
+ $extension->currentBundle->runUninstallerProgress();
143
+ }
144
+
145
+ // Remove install records
146
+ $uninstalled = RegistryExtensionInstall::where([
147
+ 'company_uuid' => session('company'),
148
+ 'extension_uuid' => $extension->uuid,
149
+ ])->delete();
150
+
151
+ return response()->json(['status' => 'ok', 'uninstalled' => $uninstalled]);
152
+ }
153
+ }
@@ -0,0 +1,230 @@
1
+ <?php
2
+
3
+ namespace Fleetbase\RegistryBridge\Http\Controllers\Internal\v1;
4
+
5
+ use Fleetbase\Http\Controllers\Controller;
6
+ use Fleetbase\Models\User;
7
+ use Fleetbase\RegistryBridge\Http\Requests\AddRegistryUserRequest;
8
+ use Fleetbase\RegistryBridge\Http\Requests\AuthenticateRegistryUserRequest;
9
+ use Fleetbase\RegistryBridge\Http\Requests\RegistryAuthRequest;
10
+ use Fleetbase\RegistryBridge\Http\Resources\RegistryUser as RegistryUserResource;
11
+ use Fleetbase\RegistryBridge\Models\RegistryExtension;
12
+ use Fleetbase\RegistryBridge\Models\RegistryUser;
13
+ use Fleetbase\RegistryBridge\Support\Bridge;
14
+ use Fleetbase\Support\Auth;
15
+
16
+ class RegistryAuthController extends Controller
17
+ {
18
+ public function test()
19
+ {
20
+ dd(Bridge::get('~/flb/extensions'));
21
+ }
22
+
23
+ /**
24
+ * Authenticates a registry user based on provided credentials.
25
+ *
26
+ * This method attempts to authenticate a user using an identity (which can be either an email or username)
27
+ * and a password. Upon successful authentication, it either retrieves an existing token associated with
28
+ * the user or generates a new one. The method returns the token and user information in JSON format.
29
+ *
30
+ * If authentication fails or a token cannot be generated or retrieved, an error response is returned.
31
+ *
32
+ * @param AuthenticateRegistryUserRequest $request the request object containing identity and password
33
+ *
34
+ * @return RegistryUserResource Returns a JSON resource representing the registry user along with groups and containing the auth token and additional user data.
35
+ * Returns an error response if authentication fails or token generation is unsuccessful.
36
+ */
37
+ public function authenticate(AuthenticateRegistryUserRequest $request)
38
+ {
39
+ $identity = $request->input('identity');
40
+ $password = $request->input('password');
41
+
42
+ // Find user by email or username
43
+ $user = User::where(function ($query) use ($identity) {
44
+ $query->where('email', $identity)->orWhere('phone', $identity)->orWhere('username', $identity);
45
+ })->first();
46
+
47
+ // Authenticate user with password
48
+ if (Auth::isInvalidPassword($password, $user->password)) {
49
+ return response()->error('Invalid credentials.', 401);
50
+ }
51
+
52
+ // Get existing token for current user
53
+ $registryUser = RegistryUser::where(['company_uuid' => $user->company_uuid, 'user_uuid' => $user->uuid])->first();
54
+ if (!$registryUser) {
55
+ // Create registry user
56
+ $registryUser = RegistryUser::create([
57
+ 'company_uuid' => $user->company_uuid,
58
+ 'user_uuid' => $user->uuid,
59
+ 'scope' => '*',
60
+ 'expires_at' => now()->addYear(),
61
+ 'name' => $user->public_id . ' developer token',
62
+ ]);
63
+ }
64
+
65
+ // If no token response with error
66
+ if (!$registryUser) {
67
+ return response()->error('Unable to authenticate.');
68
+ }
69
+
70
+ return new RegistryUserResource($registryUser);
71
+ }
72
+
73
+ /**
74
+ * Adds a new user to the registry with authentication credentials.
75
+ *
76
+ * This method creates a registry user linked to the currently active company
77
+ * of the user. It requires an identity (email or username) and password for
78
+ * authentication. After successful authentication, it generates a developer
79
+ * key for the user with a scope and expiration date.
80
+ *
81
+ * @param AddRegistryUserRequest $request the request object containing identity and password
82
+ *
83
+ * @return \Illuminate\Http\JsonResponse returns the newly created registry user data in JSON format
84
+ */
85
+ public function addUser(AddRegistryUserRequest $request)
86
+ {
87
+ $identity = $request->input('identity');
88
+ $password = $request->input('password');
89
+
90
+ // Find user by email or username
91
+ $user = User::where(function ($query) use ($identity) {
92
+ $query->where('email', $identity)->orWhere('phone', $identity)->orWhere('username', $identity);
93
+ })->first();
94
+
95
+ // Authenticate user with password
96
+ if (Auth::isInvalidPassword($password, $user->password)) {
97
+ return response()->error('Invalid credentials.', 401);
98
+ }
99
+
100
+ // Check if registry user already exists first
101
+ $registryUser = RegistryUser::where(['company_uuid' => $user->company_uuid, 'user_uuid' => $user->uuid])->first();
102
+ if (!$registryUser) {
103
+ // Create registry user
104
+ $registryUser = RegistryUser::create([
105
+ 'company_uuid' => $user->company_uuid,
106
+ 'user_uuid' => $user->uuid,
107
+ 'scope' => '*',
108
+ 'expires_at' => now()->addYear(),
109
+ 'name' => $user->public_id . ' developer token',
110
+ ]);
111
+ }
112
+
113
+ return response()->json($registryUser);
114
+ }
115
+
116
+ /**
117
+ * Checks if a user has access to the registry based on their identity.
118
+ *
119
+ * This function receives a request containing an 'identity' (which could be an email or username) and
120
+ * attempts to find a corresponding user. If the user is found and they have admin privileges, it grants access
121
+ * to the registry by returning a JSON response indicating that access is allowed. If the user doesn't have
122
+ * admin privileges or the user can't be found based on the provided identity, it returns an error response.
123
+ *
124
+ * @param RegistryAuthRequest $request the request containing the user's identity information
125
+ *
126
+ * @return \Illuminate\Http\JsonResponse|\Illuminate\Http\Response
127
+ * Returns a JSON response indicating access is allowed if the user is an admin,
128
+ * or an error response if the user is not an admin or can't be found
129
+ */
130
+ public function checkAccess(RegistryAuthRequest $request)
131
+ {
132
+ // Get identity
133
+ $identity = $request->input('identity');
134
+
135
+ // Find user by email or username
136
+ $user = User::where('email', $identity)->orWhere('username', $identity)->first();
137
+
138
+ // If user is not admin respond with error
139
+ if (!$user->isAdmin()) {
140
+ return response()->error('User is not allowed access to the registry.', 401);
141
+ }
142
+
143
+ // For now only admin users can access registry
144
+ return response()->json(['allowed' => true]);
145
+ }
146
+
147
+ /**
148
+ * Validates whether a user is allowed to publish or unpublish a specified package in the registry.
149
+ *
150
+ * This function extracts the user's identity, the package name, and the desired action ('publish' or 'unpublish')
151
+ * from the request. It then performs several checks:
152
+ * 1. Verifies that the specified package (extension) exists in the registry.
153
+ * 2. Confirms the existence of the user associated with the provided identity.
154
+ * 3. Checks if the user has administrative privileges.
155
+ * 4. Ensures that the extension's status allows the desired action (either 'approved' or 'published' for publishing,
156
+ * 'published' for unpublishing).
157
+ * If these conditions are met, the function updates the extension's status based on the action and returns a
158
+ * JSON response indicating the action is allowed. If any of these checks fail, it returns an error response.
159
+ *
160
+ * @param RegistryAuthRequest $request the request containing the user's identity, package information, and action
161
+ *
162
+ * @return \Illuminate\Http\JsonResponse|\Illuminate\Http\Response
163
+ * Returns a JSON response indicating the action is allowed if all checks pass, or
164
+ * an error response if any check fails
165
+ */
166
+ public function checkPublishAllowed(RegistryAuthRequest $request)
167
+ {
168
+ $identity = $request->input('identity');
169
+ $package = $request->input('package');
170
+ $action = $request->input('action', 'publish');
171
+ $force = $request->boolean('force');
172
+ $password = $request->input('password');
173
+
174
+ // If force publish bypass checks, authenticate by user login
175
+ if ($force === true) {
176
+ // Find user by email or username
177
+ $user = User::where(function ($query) use ($identity) {
178
+ $query->where('email', $identity)->orWhere('phone', $identity)->orWhere('username', $identity);
179
+ })->first();
180
+
181
+ // Authenticate user with password
182
+ if (Auth::isInvalidPassword($password, $user->password)) {
183
+ return response()->error('Invalid credentials, unable to force publish.', 401);
184
+ }
185
+
186
+ return response()->json(['allowed' => true]);
187
+ }
188
+
189
+ // Make sure package is provided
190
+ if (!$package) {
191
+ return response()->error('No package specified for publish.', 401);
192
+ }
193
+
194
+ // Find package
195
+ $extension = RegistryExtension::findByPackageName($package);
196
+ if (!$extension) {
197
+ return response()->error('Attempting to publish extension which has no record.', 401);
198
+ }
199
+
200
+ // Find user by email or username
201
+ $user = User::where(function ($query) use ($identity) {
202
+ $query->where('email', $identity)->orWhere('phone', $identity)->orWhere('username', $identity);
203
+ })->first();
204
+ if (!$user) {
205
+ return response()->error('Attempting to publish extension with invalid user.', 401);
206
+ }
207
+
208
+ // If user is not admin respond with error
209
+ if (!$user->isAdmin()) {
210
+ return response()->error('User is not allowed publish to the registry.', 401);
211
+ }
212
+
213
+ // Extension should be approved
214
+ if (!in_array($extension->status, ['approved', 'published'])) {
215
+ return response()->error('Attempting to publish extension which is not approved.', 401);
216
+ }
217
+
218
+ // Change status to published
219
+ if ($action === 'publish') {
220
+ $extension->update(['status' => 'published']);
221
+ $extension->currentBundle()->update(['status' => 'published']);
222
+ } elseif ($action === 'unpublish') {
223
+ $extension->update(['status' => 'unpublished']);
224
+ $extension->currentBundle()->update(['status' => 'unpublished']);
225
+ }
226
+
227
+ // Passed all checks
228
+ return response()->json(['allowed' => true]);
229
+ }
230
+ }
@@ -0,0 +1,54 @@
1
+ <?php
2
+
3
+ namespace Fleetbase\RegistryBridge\Http\Controllers\Internal\v1;
4
+
5
+ use Fleetbase\Http\Controllers\Controller;
6
+ use Fleetbase\Http\Resources\Category as CategoryResource;
7
+ use Fleetbase\Models\Category;
8
+ use Fleetbase\RegistryBridge\Models\RegistryExtension;
9
+
10
+ class RegistryController extends Controller
11
+ {
12
+ /**
13
+ * Retrieve a collection of categories that have registry extensions.
14
+ *
15
+ * This method fetches categories that have associated registry extensions
16
+ * and meet the specified criteria (core_category equals 1 and 'for' equals
17
+ * 'extension_category'). The retrieved categories are then wrapped using
18
+ * the CategoryResource and returned as a collection of CategoryResource.
19
+ *
20
+ * @return \Illuminate\Http\Resources\Json\AnonymousResourceCollection
21
+ * A collection of CategoryResource objects representing the categories
22
+ */
23
+ public function categories()
24
+ {
25
+ $categories = Category::whereHas('registryExtensions')->where(['core_category' => 1, 'for' => 'extension_category'])->get();
26
+
27
+ CategoryResource::wrap('categories');
28
+
29
+ return CategoryResource::collection($categories);
30
+ }
31
+
32
+ /**
33
+ * Retrieve a list of installed engines for the current company session.
34
+ *
35
+ * This method fetches registry extensions that have been installed by the
36
+ * company identified in the current session. It disables caching for the
37
+ * query, filters the results based on the company's UUID stored in the session,
38
+ * and maps the retrieved extensions to extract the 'package.json' metadata.
39
+ * The result is returned as a JSON response.
40
+ *
41
+ * @return \Illuminate\Http\JsonResponse
42
+ * A JSON response containing a list of installed engines with their metadata
43
+ */
44
+ public function getInstalledEngines()
45
+ {
46
+ $installedExtensions = RegistryExtension::disableCache()->whereHas('installs', function ($query) {
47
+ $query->where('company_uuid', session('company'));
48
+ })->get()->map(function ($extension) {
49
+ return $extension->currentBundle->meta['package.json'] ?? [];
50
+ });
51
+
52
+ return response()->json($installedExtensions);
53
+ }
54
+ }