mirror of
				https://github.com/pelican-dev/panel.git
				synced 2025-10-31 02:26:52 +01:00 
			
		
		
		
	Refactor & Catch DatabaseManagementService (#1671)
Co-authored-by: notCharles <charles@pelican.dev>
This commit is contained in:
		
							parent
							
								
									420730ba1f
								
							
						
					
					
						commit
						2ef81eae1a
					
				| @ -687,8 +687,22 @@ class EditServer extends EditRecord | |||||||
|                                                     ->modalHeading(trans('admin/server.delete_db_heading')) |                                                     ->modalHeading(trans('admin/server.delete_db_heading')) | ||||||
|                                                     ->modalSubmitActionLabel(trans('filament-actions::delete.single.label')) |                                                     ->modalSubmitActionLabel(trans('filament-actions::delete.single.label')) | ||||||
|                                                     ->modalDescription(fn (Get $get) => trans('admin/server.delete_db', ['name' => $get('database')])) |                                                     ->modalDescription(fn (Get $get) => trans('admin/server.delete_db', ['name' => $get('database')])) | ||||||
|                                                     ->action(function (DatabaseManagementService $databaseManagementService, $record) { |                                                     ->action(function (DatabaseManagementService $service, $record) { | ||||||
|                                                         $databaseManagementService->delete($record); |                                                         try { | ||||||
|  |                                                             $service->delete($record); | ||||||
|  | 
 | ||||||
|  |                                                             Notification::make() | ||||||
|  |                                                                 ->title(trans('server/database.delete_notification', ['database' => $record->database])) | ||||||
|  |                                                                 ->success() | ||||||
|  |                                                                 ->send(); | ||||||
|  |                                                         } catch (Exception $e) { | ||||||
|  |                                                             Notification::make() | ||||||
|  |                                                                 ->title(trans('server/database.delete_notification_fail', ['database' => $record->database])) | ||||||
|  |                                                                 ->body($e->getMessage()) | ||||||
|  |                                                                 ->danger() | ||||||
|  |                                                                 ->persistent()->send(); | ||||||
|  |                                                         } | ||||||
|  | 
 | ||||||
|                                                         $this->fillForm(); |                                                         $this->fillForm(); | ||||||
|                                                     }) |                                                     }) | ||||||
|                                             ), |                                             ), | ||||||
| @ -737,21 +751,22 @@ class EditServer extends EditRecord | |||||||
|                                         ->label(fn () => DatabaseHost::query()->count() < 1 ? trans('admin/server.no_db_hosts') : trans('admin/server.create_database')) |                                         ->label(fn () => DatabaseHost::query()->count() < 1 ? trans('admin/server.no_db_hosts') : trans('admin/server.create_database')) | ||||||
|                                         ->color(fn () => DatabaseHost::query()->count() < 1 ? 'danger' : 'primary') |                                         ->color(fn () => DatabaseHost::query()->count() < 1 ? 'danger' : 'primary') | ||||||
|                                         ->modalSubmitActionLabel(trans('admin/server.create_database')) |                                         ->modalSubmitActionLabel(trans('admin/server.create_database')) | ||||||
|                                         ->action(function (array $data, DatabaseManagementService $service, Server $server, RandomWordService $randomWordService) { |                                         ->action(function (array $data, DatabaseManagementService $service, Server $server) { | ||||||
|                                             if (empty($data['database'])) { |                                             $data['database'] ??= str_random(12); | ||||||
|                                                 $data['database'] = $randomWordService->word() . random_int(1, 420); |                                             $data['remote'] ??= '%'; | ||||||
|                                             } |  | ||||||
|                                             if (empty($data['remote'])) { |  | ||||||
|                                                 $data['remote'] = '%'; |  | ||||||
|                                             } |  | ||||||
| 
 | 
 | ||||||
|                                             $data['database'] = $service->generateUniqueDatabaseName($data['database'], $server->id); |                                             $data['database'] = $service->generateUniqueDatabaseName($data['database'], $server->id); | ||||||
| 
 | 
 | ||||||
|                                             try { |                                             try { | ||||||
|                                                 $service->setValidateDatabaseLimit(false)->create($server, $data); |                                                 $service->setValidateDatabaseLimit(false)->create($server, $data); | ||||||
|  | 
 | ||||||
|  |                                                 Notification::make() | ||||||
|  |                                                     ->title(trans('server/database.create_notification', ['database' => $data['database']])) | ||||||
|  |                                                     ->success() | ||||||
|  |                                                     ->send(); | ||||||
|                                             } catch (Exception $e) { |                                             } catch (Exception $e) { | ||||||
|                                                 Notification::make() |                                                 Notification::make() | ||||||
|                                                     ->title(trans('admin/server.failed_to_create')) |                                                     ->title(trans('server/database.create_notification_fail', ['database' => $data['database']])) | ||||||
|                                                     ->body($e->getMessage()) |                                                     ->body($e->getMessage()) | ||||||
|                                                     ->danger() |                                                     ->danger() | ||||||
|                                                     ->persistent()->send(); |                                                     ->persistent()->send(); | ||||||
|  | |||||||
| @ -4,9 +4,10 @@ namespace App\Filament\Components\Forms\Actions; | |||||||
| 
 | 
 | ||||||
| use App\Facades\Activity; | use App\Facades\Activity; | ||||||
| use App\Models\Database; | use App\Models\Database; | ||||||
| use App\Services\Databases\DatabasePasswordService; | use App\Services\Databases\DatabaseManagementService; | ||||||
| use Exception; | use Exception; | ||||||
| use Filament\Actions\StaticAction; | use Filament\Actions\StaticAction; | ||||||
|  | use Filament\Facades\Filament; | ||||||
| use Filament\Forms\Components\Actions\Action; | use Filament\Forms\Components\Actions\Action; | ||||||
| use Filament\Forms\Set; | use Filament\Forms\Set; | ||||||
| use Filament\Notifications\Notification; | use Filament\Notifications\Notification; | ||||||
| @ -36,10 +37,9 @@ class RotateDatabasePasswordAction extends Action | |||||||
| 
 | 
 | ||||||
|         $this->requiresConfirmation(); |         $this->requiresConfirmation(); | ||||||
| 
 | 
 | ||||||
|         $this->action(function (DatabasePasswordService $service, Database $database, Set $set) { |         $this->action(function (DatabaseManagementService $service, Database $database, Set $set) { | ||||||
|             try { |             try { | ||||||
|                 $service->handle($database); |                 $service->rotatePassword($database); | ||||||
| 
 |  | ||||||
|                 $database->refresh(); |                 $database->refresh(); | ||||||
| 
 | 
 | ||||||
|                 $set('password', $database->password); |                 $set('password', $database->password); | ||||||
| @ -57,7 +57,7 @@ class RotateDatabasePasswordAction extends Action | |||||||
|             } catch (Exception $exception) { |             } catch (Exception $exception) { | ||||||
|                 Notification::make() |                 Notification::make() | ||||||
|                     ->title(trans('admin/databasehost.rotate_error')) |                     ->title(trans('admin/databasehost.rotate_error')) | ||||||
|                     ->body($exception->getMessage()) |                     ->body(fn () => auth()->user()->canAccessPanel(Filament::getPanel('admin')) ? $exception->getMessage() : null) | ||||||
|                     ->danger() |                     ->danger() | ||||||
|                     ->send(); |                     ->send(); | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -15,9 +15,11 @@ use App\Traits\Filament\CanCustomizeRelations; | |||||||
| use App\Traits\Filament\CanModifyForm; | use App\Traits\Filament\CanModifyForm; | ||||||
| use App\Traits\Filament\CanModifyTable; | use App\Traits\Filament\CanModifyTable; | ||||||
| use App\Traits\Filament\HasLimitBadge; | use App\Traits\Filament\HasLimitBadge; | ||||||
|  | use Exception; | ||||||
| use Filament\Facades\Filament; | use Filament\Facades\Filament; | ||||||
| use Filament\Forms\Components\TextInput; | use Filament\Forms\Components\TextInput; | ||||||
| use Filament\Forms\Form; | use Filament\Forms\Form; | ||||||
|  | use Filament\Notifications\Notification; | ||||||
| use Filament\Resources\Pages\PageRegistration; | use Filament\Resources\Pages\PageRegistration; | ||||||
| use Filament\Resources\Resource; | use Filament\Resources\Resource; | ||||||
| use Filament\Tables\Actions\DeleteAction; | use Filament\Tables\Actions\DeleteAction; | ||||||
| @ -122,7 +124,23 @@ class DatabaseResource extends Resource | |||||||
|                 ViewAction::make() |                 ViewAction::make() | ||||||
|                     ->modalHeading(fn (Database $database) => trans('server/database.viewing', ['database' => $database->database])), |                     ->modalHeading(fn (Database $database) => trans('server/database.viewing', ['database' => $database->database])), | ||||||
|                 DeleteAction::make() |                 DeleteAction::make() | ||||||
|                     ->using(fn (Database $database, DatabaseManagementService $service) => $service->delete($database)), |                     ->using(function (Database $database, DatabaseManagementService $service) { | ||||||
|  |                         try { | ||||||
|  |                             $service->delete($database); | ||||||
|  | 
 | ||||||
|  |                             Notification::make() | ||||||
|  |                                 ->title(trans('server/database.delete_notification', ['database' => $database->database])) | ||||||
|  |                                 ->success() | ||||||
|  |                                 ->send(); | ||||||
|  |                         } catch (Exception $exception) { | ||||||
|  |                             Notification::make() | ||||||
|  |                                 ->title(trans('server/database.delete_notification_fail', ['database' => $database->database])) | ||||||
|  |                                 ->danger() | ||||||
|  |                                 ->send(); | ||||||
|  | 
 | ||||||
|  |                             report($exception); | ||||||
|  |                         } | ||||||
|  |                     }), | ||||||
|             ]); |             ]); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -8,6 +8,7 @@ use App\Models\Server; | |||||||
| use App\Services\Databases\DatabaseManagementService; | use App\Services\Databases\DatabaseManagementService; | ||||||
| use App\Traits\Filament\CanCustomizeHeaderActions; | use App\Traits\Filament\CanCustomizeHeaderActions; | ||||||
| use App\Traits\Filament\CanCustomizeHeaderWidgets; | use App\Traits\Filament\CanCustomizeHeaderWidgets; | ||||||
|  | use Exception; | ||||||
| use Filament\Actions\Action; | use Filament\Actions\Action; | ||||||
| use Filament\Actions\ActionGroup; | use Filament\Actions\ActionGroup; | ||||||
| use Filament\Actions\CreateAction; | use Filament\Actions\CreateAction; | ||||||
| @ -15,6 +16,7 @@ use Filament\Facades\Filament; | |||||||
| use Filament\Forms\Components\Grid; | use Filament\Forms\Components\Grid; | ||||||
| use Filament\Forms\Components\Select; | use Filament\Forms\Components\Select; | ||||||
| use Filament\Forms\Components\TextInput; | use Filament\Forms\Components\TextInput; | ||||||
|  | use Filament\Notifications\Notification; | ||||||
| use Filament\Resources\Pages\ListRecords; | use Filament\Resources\Pages\ListRecords; | ||||||
| use Filament\Support\Enums\IconSize; | use Filament\Support\Enums\IconSize; | ||||||
| use Illuminate\Support\Str; | use Illuminate\Support\Str; | ||||||
| @ -63,12 +65,24 @@ class ListDatabases extends ListRecords | |||||||
|                         ]), |                         ]), | ||||||
|                 ]) |                 ]) | ||||||
|                 ->action(function ($data, DatabaseManagementService $service) use ($server) { |                 ->action(function ($data, DatabaseManagementService $service) use ($server) { | ||||||
|                     if (empty($data['database'])) { |                     $data['database'] ??= Str::random(12); | ||||||
|                         $data['database'] = Str::random(12); |                     $data['database'] = $service->generateUniqueDatabaseName($data['database'], $server->id); | ||||||
|                     } |  | ||||||
|                     $data['database'] = 's'. $server->id . '_' . $data['database']; |  | ||||||
| 
 | 
 | ||||||
|                     $service->create($server, $data); |                     try { | ||||||
|  |                         $service->create($server, $data); | ||||||
|  | 
 | ||||||
|  |                         Notification::make() | ||||||
|  |                             ->title(trans('server/database.create_notification', ['database' => $data['database']])) | ||||||
|  |                             ->success() | ||||||
|  |                             ->send(); | ||||||
|  |                     } catch (Exception $exception) { | ||||||
|  |                         Notification::make() | ||||||
|  |                             ->title(trans('server/database.create_notification_fail', ['database' => $data['database']])) | ||||||
|  |                             ->danger() | ||||||
|  |                             ->send(); | ||||||
|  | 
 | ||||||
|  |                         report($exception); | ||||||
|  |                     } | ||||||
|                 }), |                 }), | ||||||
|         ]; |         ]; | ||||||
|     } |     } | ||||||
|  | |||||||
| @ -6,7 +6,6 @@ use Illuminate\Http\Response; | |||||||
| use App\Models\Server; | use App\Models\Server; | ||||||
| use App\Models\Database; | use App\Models\Database; | ||||||
| use Illuminate\Http\JsonResponse; | use Illuminate\Http\JsonResponse; | ||||||
| use App\Services\Databases\DatabasePasswordService; |  | ||||||
| use App\Services\Databases\DatabaseManagementService; | use App\Services\Databases\DatabaseManagementService; | ||||||
| use App\Transformers\Api\Application\ServerDatabaseTransformer; | use App\Transformers\Api\Application\ServerDatabaseTransformer; | ||||||
| use App\Http\Controllers\Api\Application\ApplicationApiController; | use App\Http\Controllers\Api\Application\ApplicationApiController; | ||||||
| @ -24,7 +23,6 @@ class DatabaseController extends ApplicationApiController | |||||||
|      */ |      */ | ||||||
|     public function __construct( |     public function __construct( | ||||||
|         private DatabaseManagementService $databaseManagementService, |         private DatabaseManagementService $databaseManagementService, | ||||||
|         private DatabasePasswordService $databasePasswordService |  | ||||||
|     ) { |     ) { | ||||||
|         parent::__construct(); |         parent::__construct(); | ||||||
|     } |     } | ||||||
| @ -66,7 +64,7 @@ class DatabaseController extends ApplicationApiController | |||||||
|      */ |      */ | ||||||
|     public function resetPassword(ServerDatabaseWriteRequest $request, Server $server, Database $database): JsonResponse |     public function resetPassword(ServerDatabaseWriteRequest $request, Server $server, Database $database): JsonResponse | ||||||
|     { |     { | ||||||
|         $this->databasePasswordService->handle($database); |         $this->databaseManagementService->rotatePassword($database); | ||||||
| 
 | 
 | ||||||
|         return new JsonResponse([], JsonResponse::HTTP_NO_CONTENT); |         return new JsonResponse([], JsonResponse::HTTP_NO_CONTENT); | ||||||
|     } |     } | ||||||
|  | |||||||
| @ -6,7 +6,6 @@ use Illuminate\Http\Response; | |||||||
| use App\Models\Server; | use App\Models\Server; | ||||||
| use App\Models\Database; | use App\Models\Database; | ||||||
| use App\Facades\Activity; | use App\Facades\Activity; | ||||||
| use App\Services\Databases\DatabasePasswordService; |  | ||||||
| use App\Transformers\Api\Client\DatabaseTransformer; | use App\Transformers\Api\Client\DatabaseTransformer; | ||||||
| use App\Services\Databases\DatabaseManagementService; | use App\Services\Databases\DatabaseManagementService; | ||||||
| use App\Services\Databases\DeployServerDatabaseService; | use App\Services\Databases\DeployServerDatabaseService; | ||||||
| @ -26,7 +25,6 @@ class DatabaseController extends ClientApiController | |||||||
|     public function __construct( |     public function __construct( | ||||||
|         private DeployServerDatabaseService $deployDatabaseService, |         private DeployServerDatabaseService $deployDatabaseService, | ||||||
|         private DatabaseManagementService $managementService, |         private DatabaseManagementService $managementService, | ||||||
|         private DatabasePasswordService $passwordService |  | ||||||
|     ) { |     ) { | ||||||
|         parent::__construct(); |         parent::__construct(); | ||||||
|     } |     } | ||||||
| @ -83,7 +81,7 @@ class DatabaseController extends ClientApiController | |||||||
|      */ |      */ | ||||||
|     public function rotatePassword(RotatePasswordRequest $request, Server $server, Database $database): array |     public function rotatePassword(RotatePasswordRequest $request, Server $server, Database $database): array | ||||||
|     { |     { | ||||||
|         $this->passwordService->handle($database); |         $this->managementService->rotatePassword($database); | ||||||
|         $database->refresh(); |         $database->refresh(); | ||||||
| 
 | 
 | ||||||
|         Activity::event('server:database.rotate-password') |         Activity::event('server:database.rotate-password') | ||||||
|  | |||||||
| @ -8,6 +8,7 @@ use Illuminate\Database\Eloquent\Casts\Attribute; | |||||||
| use Illuminate\Database\Eloquent\Factories\HasFactory; | use Illuminate\Database\Eloquent\Factories\HasFactory; | ||||||
| use Illuminate\Database\Eloquent\Model; | use Illuminate\Database\Eloquent\Model; | ||||||
| use Illuminate\Database\Eloquent\Relations\BelongsTo; | use Illuminate\Database\Eloquent\Relations\BelongsTo; | ||||||
|  | use PDOException; | ||||||
| 
 | 
 | ||||||
| /** | /** | ||||||
|  * @property int $id |  * @property int $id | ||||||
| @ -97,71 +98,97 @@ class Database extends Model implements Validatable | |||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /** |     /** | ||||||
|  |      * @throws PDOException | ||||||
|  |      * | ||||||
|      * Run the provided statement against the database on a given connection. |      * Run the provided statement against the database on a given connection. | ||||||
|      */ |      */ | ||||||
|     private function run(string $statement): bool |     private function run(string $statement): void | ||||||
|     { |     { | ||||||
|         return $this->host->buildConnection()->statement($statement); |         $this->host->buildConnection()->statement($statement); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /** |     /** | ||||||
|  |      * @throws PDOException | ||||||
|  |      * | ||||||
|      * Create a new database on a given connection. |      * Create a new database on a given connection. | ||||||
|      */ |      */ | ||||||
|     public function createDatabase(string $database): bool |     public function createDatabase(): self | ||||||
|     { |     { | ||||||
|         return $this->run(sprintf('CREATE DATABASE IF NOT EXISTS `%s`', $database)); |         $this->run(sprintf('CREATE DATABASE IF NOT EXISTS `%s`', $this->database)); | ||||||
|  | 
 | ||||||
|  |         return $this; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /** |     /** | ||||||
|  |      * @throws PDOException | ||||||
|  |      * | ||||||
|      * Create a new database user on a given connection. |      * Create a new database user on a given connection. | ||||||
|      */ |      */ | ||||||
|     public function createUser(string $username, string $remote, string $password, ?int $max_connections): bool |     public function createUser(): self | ||||||
|     { |     { | ||||||
|         $args = [$username, $remote, $password]; |         $args = [$this->username, $this->remote, $this->password]; | ||||||
|         $command = 'CREATE USER `%s`@`%s` IDENTIFIED BY \'%s\''; |         $command = 'CREATE USER `%s`@`%s` IDENTIFIED BY \'%s\''; | ||||||
| 
 | 
 | ||||||
|         if (!empty($max_connections)) { |         if (!empty($this->max_connections)) { | ||||||
|             $args[] = $max_connections; |             $args[] = $this->max_connections; | ||||||
|             $command .= ' WITH MAX_USER_CONNECTIONS %s'; |             $command .= ' WITH MAX_USER_CONNECTIONS %s'; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         return $this->run(sprintf($command, ...$args)); |         $this->run(sprintf($command, ...$args)); | ||||||
|  | 
 | ||||||
|  |         return $this; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /** |     /** | ||||||
|  |      * @throws PDOException | ||||||
|  |      * | ||||||
|      * Give a specific user access to a given database. |      * Give a specific user access to a given database. | ||||||
|      */ |      */ | ||||||
|     public function assignUserToDatabase(string $database, string $username, string $remote): bool |     public function assignUserToDatabase(): self | ||||||
|     { |     { | ||||||
|         return $this->run(sprintf( |         $this->run(sprintf( | ||||||
|             'GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, ALTER, REFERENCES, INDEX, LOCK TABLES, CREATE ROUTINE, ALTER ROUTINE, EXECUTE, CREATE TEMPORARY TABLES, CREATE VIEW, SHOW VIEW, EVENT, TRIGGER ON `%s`.* TO `%s`@`%s`', |             'GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, ALTER, REFERENCES, INDEX, LOCK TABLES, CREATE ROUTINE, ALTER ROUTINE, EXECUTE, CREATE TEMPORARY TABLES, CREATE VIEW, SHOW VIEW, EVENT, TRIGGER ON `%s`.* TO `%s`@`%s`', | ||||||
|             $database, |             $this->database, | ||||||
|             $username, |             $this->username, | ||||||
|             $remote |             $this->remote | ||||||
|         )); |         )); | ||||||
|  | 
 | ||||||
|  |         return $this; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /** |     /** | ||||||
|  |      * @throws PDOException | ||||||
|  |      * | ||||||
|      * Flush the privileges for a given connection. |      * Flush the privileges for a given connection. | ||||||
|      */ |      */ | ||||||
|     public function flush(): bool |     public function flushPrivileges(): self | ||||||
|     { |     { | ||||||
|         return $this->run('FLUSH PRIVILEGES'); |         $this->run('FLUSH PRIVILEGES'); | ||||||
|  | 
 | ||||||
|  |         return $this; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /** |     /** | ||||||
|  |      * @throws PDOException | ||||||
|  |      * | ||||||
|      * Drop a given database on a specific connection. |      * Drop a given database on a specific connection. | ||||||
|      */ |      */ | ||||||
|     public function dropDatabase(string $database): bool |     public function dropDatabase(): self | ||||||
|     { |     { | ||||||
|         return $this->run(sprintf('DROP DATABASE IF EXISTS `%s`', $database)); |         $this->run(sprintf('DROP DATABASE IF EXISTS `%s`', $this->database)); | ||||||
|  | 
 | ||||||
|  |         return $this; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /** |     /** | ||||||
|  |      * @throws PDOException | ||||||
|  |      * | ||||||
|      * Drop a given user on a specific connection. |      * Drop a given user on a specific connection. | ||||||
|      */ |      */ | ||||||
|     public function dropUser(string $username, string $remote): bool |     public function dropUser(): self | ||||||
|     { |     { | ||||||
|         return $this->run(sprintf('DROP USER IF EXISTS `%s`@`%s`', $username, $remote)); |         $this->run(sprintf('DROP USER IF EXISTS `%s`@`%s`', $this->username, $this->remote)); | ||||||
|  | 
 | ||||||
|  |         return $this; | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | |||||||
| @ -93,15 +93,11 @@ class DatabaseManagementService | |||||||
|         return $this->connection->transaction(function () use ($data) { |         return $this->connection->transaction(function () use ($data) { | ||||||
|             $database = $this->createModel($data); |             $database = $this->createModel($data); | ||||||
| 
 | 
 | ||||||
|             $database->createDatabase($database->database); |             $database | ||||||
|             $database->createUser( |                 ->createDatabase() | ||||||
|                 $database->username, |                 ->createUser() | ||||||
|                 $database->remote, |                 ->assignUserToDatabase() | ||||||
|                 $database->password, |                 ->flushPrivileges(); | ||||||
|                 $database->max_connections |  | ||||||
|             ); |  | ||||||
|             $database->assignUserToDatabase($database->database, $database->username, $database->remote); |  | ||||||
|             $database->flush(); |  | ||||||
| 
 | 
 | ||||||
|             Activity::event('server:database.create') |             Activity::event('server:database.create') | ||||||
|                 ->subject($database) |                 ->subject($database) | ||||||
| @ -115,14 +111,15 @@ class DatabaseManagementService | |||||||
|     /** |     /** | ||||||
|      * Delete a database from the given host server. |      * Delete a database from the given host server. | ||||||
|      * |      * | ||||||
|      * @throws \Exception |      * @throws \Throwable | ||||||
|      */ |      */ | ||||||
|     public function delete(Database $database): ?bool |     public function delete(Database $database): ?bool | ||||||
|     { |     { | ||||||
|         return $this->connection->transaction(function () use ($database) { |         return $this->connection->transaction(function () use ($database) { | ||||||
|             $database->dropDatabase($database->database); |             $database | ||||||
|             $database->dropUser($database->username, $database->remote); |                 ->dropDatabase() | ||||||
|             $database->flush(); |                 ->dropUser() | ||||||
|  |                 ->flushPrivileges(); | ||||||
| 
 | 
 | ||||||
|             Activity::event('server:database.delete') |             Activity::event('server:database.delete') | ||||||
|                 ->subject($database) |                 ->subject($database) | ||||||
| @ -133,6 +130,28 @@ class DatabaseManagementService | |||||||
|         }); |         }); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     /** | ||||||
|  |      * Updates a password for a given database. | ||||||
|  |      * | ||||||
|  |      * @throws \Exception | ||||||
|  |      */ | ||||||
|  |     public function rotatePassword(Database $database): void | ||||||
|  |     { | ||||||
|  |         $password = Utilities::randomStringWithSpecialCharacters(24); | ||||||
|  | 
 | ||||||
|  |         $this->connection->transaction(function () use ($database, $password) { | ||||||
|  |             $database->update([ | ||||||
|  |                 'password' => $password, | ||||||
|  |             ]); | ||||||
|  | 
 | ||||||
|  |             $database | ||||||
|  |                 ->dropUser() | ||||||
|  |                 ->createUser() | ||||||
|  |                 ->assignUserToDatabase() | ||||||
|  |                 ->flushPrivileges(); | ||||||
|  |         }); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     /** |     /** | ||||||
|      * Create the database if there is not an identical match in the DB. While you can technically |      * Create the database if there is not an identical match in the DB. While you can technically | ||||||
|      * have the same name across multiple hosts, for the sake of keeping this logic easy to understand |      * have the same name across multiple hosts, for the sake of keeping this logic easy to understand | ||||||
|  | |||||||
| @ -1,40 +0,0 @@ | |||||||
| <?php |  | ||||||
| 
 |  | ||||||
| namespace App\Services\Databases; |  | ||||||
| 
 |  | ||||||
| use App\Models\Database; |  | ||||||
| use App\Helpers\Utilities; |  | ||||||
| use Illuminate\Database\ConnectionInterface; |  | ||||||
| 
 |  | ||||||
| class DatabasePasswordService |  | ||||||
| { |  | ||||||
|     /** |  | ||||||
|      * DatabasePasswordService constructor. |  | ||||||
|      */ |  | ||||||
|     public function __construct( |  | ||||||
|         private ConnectionInterface $connection, |  | ||||||
|     ) {} |  | ||||||
| 
 |  | ||||||
|     /** |  | ||||||
|      * Updates a password for a given database. |  | ||||||
|      */ |  | ||||||
|     public function handle(Database|int $database): void |  | ||||||
|     { |  | ||||||
|         if (is_int($database)) { |  | ||||||
|             $database = Database::query()->findOrFail($database); |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         $password = Utilities::randomStringWithSpecialCharacters(24); |  | ||||||
| 
 |  | ||||||
|         $this->connection->transaction(function () use ($database, $password) { |  | ||||||
|             $database->update([ |  | ||||||
|                 'password' => $password, |  | ||||||
|             ]); |  | ||||||
| 
 |  | ||||||
|             $database->dropUser($database->username, $database->remote); |  | ||||||
|             $database->createUser($database->username, $database->remote, $password, $database->max_connections); |  | ||||||
|             $database->assignUserToDatabase($database->database, $database->username, $database->remote); |  | ||||||
|             $database->flush(); |  | ||||||
|         }); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| @ -19,4 +19,8 @@ return [ | |||||||
|     'database_host' => 'Database Host', |     'database_host' => 'Database Host', | ||||||
|     'database_host_select' => 'Select Database Host', |     'database_host_select' => 'Select Database Host', | ||||||
|     'jdbc' => 'JDBC Connection String', |     'jdbc' => 'JDBC Connection String', | ||||||
|  |     'create_notification' => 'Created :database', | ||||||
|  |     'create_notification_fail' => 'Failed to create :database', | ||||||
|  |     'delete_notification' => 'Deleted :database', | ||||||
|  |     'delete_notification_fail' => 'Failed to delete :database', | ||||||
| ]; | ]; | ||||||
|  | |||||||
| @ -5,7 +5,6 @@ namespace App\Tests\Integration\Api\Client\Server\Database; | |||||||
| use App\Models\Subuser; | use App\Models\Subuser; | ||||||
| use App\Models\Database; | use App\Models\Database; | ||||||
| use App\Models\DatabaseHost; | use App\Models\DatabaseHost; | ||||||
| use App\Services\Databases\DatabasePasswordService; |  | ||||||
| use App\Services\Databases\DatabaseManagementService; | use App\Services\Databases\DatabaseManagementService; | ||||||
| use App\Tests\Integration\Api\Client\ClientApiIntegrationTestCase; | use App\Tests\Integration\Api\Client\ClientApiIntegrationTestCase; | ||||||
| use PHPUnit\Framework\Attributes\DataProvider; | use PHPUnit\Framework\Attributes\DataProvider; | ||||||
| @ -33,8 +32,8 @@ class DatabaseAuthorizationTest extends ClientApiIntegrationTestCase | |||||||
|         $database3 = Database::factory()->create(['server_id' => $server3->id, 'database_host_id' => $host->id]); |         $database3 = Database::factory()->create(['server_id' => $server3->id, 'database_host_id' => $host->id]); | ||||||
| 
 | 
 | ||||||
|         $this |         $this | ||||||
|             ->mock($method === 'POST' ? DatabasePasswordService::class : DatabaseManagementService::class) |             ->mock(DatabaseManagementService::class) | ||||||
|             ->expects($method === 'POST' ? 'handle' : 'delete') |             ->expects($method === 'POST' ? 'rotatePassword' : 'delete') | ||||||
|             ->andReturn($method === 'POST' ? 'foo' : null); |             ->andReturn($method === 'POST' ? 'foo' : null); | ||||||
| 
 | 
 | ||||||
|         // This is the only valid call for this test, accessing the database for the same
 |         // This is the only valid call for this test, accessing the database for the same
 | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 MartinOscar
						MartinOscar