mirror of
				https://github.com/pelican-dev/panel.git
				synced 2025-10-31 08:36:52 +01:00 
			
		
		
		
	Add database notifications (#817)
* add database notifications to all panels * add successful param to Installed event * add listener for Installed event * create event for subuser creation * add listener for SubUserAdded event * always send Installed event * create event for subuser removal * add listener for SubUserRemoved event * add prefix to server name * remove view action from SubUserRemoved notification
This commit is contained in:
		
							parent
							
								
									eb819032bc
								
							
						
					
					
						commit
						d09227659e
					
				| @ -13,5 +13,5 @@ class Installed extends Event | |||||||
|     /** |     /** | ||||||
|      * Create a new event instance. |      * Create a new event instance. | ||||||
|      */ |      */ | ||||||
|     public function __construct(public Server $server) {} |     public function __construct(public Server $server, public bool $successful, public bool $initialInstall) {} | ||||||
| } | } | ||||||
|  | |||||||
							
								
								
									
										17
									
								
								app/Events/Server/SubUserAdded.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								app/Events/Server/SubUserAdded.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,17 @@ | |||||||
|  | <?php | ||||||
|  | 
 | ||||||
|  | namespace App\Events\Server; | ||||||
|  | 
 | ||||||
|  | use App\Events\Event; | ||||||
|  | use App\Models\Subuser; | ||||||
|  | use Illuminate\Queue\SerializesModels; | ||||||
|  | 
 | ||||||
|  | class SubUserAdded extends Event | ||||||
|  | { | ||||||
|  |     use SerializesModels; | ||||||
|  | 
 | ||||||
|  |     /** | ||||||
|  |      * Create a new event instance. | ||||||
|  |      */ | ||||||
|  |     public function __construct(public Subuser $subuser) {} | ||||||
|  | } | ||||||
							
								
								
									
										18
									
								
								app/Events/Server/SubUserRemoved.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								app/Events/Server/SubUserRemoved.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,18 @@ | |||||||
|  | <?php | ||||||
|  | 
 | ||||||
|  | namespace App\Events\Server; | ||||||
|  | 
 | ||||||
|  | use App\Events\Event; | ||||||
|  | use App\Models\Server; | ||||||
|  | use App\Models\User; | ||||||
|  | use Illuminate\Queue\SerializesModels; | ||||||
|  | 
 | ||||||
|  | class SubUserRemoved extends Event | ||||||
|  | { | ||||||
|  |     use SerializesModels; | ||||||
|  | 
 | ||||||
|  |     /** | ||||||
|  |      * Create a new event instance. | ||||||
|  |      */ | ||||||
|  |     public function __construct(public Server $server, public User $user) {} | ||||||
|  | } | ||||||
| @ -35,13 +35,11 @@ class ServerInstallController extends Controller | |||||||
|     { |     { | ||||||
|         $status = null; |         $status = null; | ||||||
| 
 | 
 | ||||||
|         // Make sure the type of failure is accurate
 |         $successful = $request->boolean('successful'); | ||||||
|         if (!$request->boolean('successful')) { |  | ||||||
|             $status = ServerState::InstallFailed; |  | ||||||
| 
 | 
 | ||||||
|             if ($request->boolean('reinstall')) { |         // Make sure the type of failure is accurate
 | ||||||
|                 $status = ServerState::ReinstallFailed; |         if (!$successful) { | ||||||
|             } |             $status = $request->boolean('reinstall') ? ServerState::ReinstallFailed : ServerState::InstallFailed; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         // Keep the server suspended if it's already suspended
 |         // Keep the server suspended if it's already suspended
 | ||||||
| @ -55,16 +53,8 @@ class ServerInstallController extends Controller | |||||||
|         $server->installed_at = now(); |         $server->installed_at = now(); | ||||||
|         $server->save(); |         $server->save(); | ||||||
| 
 | 
 | ||||||
|         // If the server successfully installed, fire installed event.
 |  | ||||||
|         // This logic allows individually disabling install and reinstall notifications separately.
 |  | ||||||
|         $isInitialInstall = is_null($previouslyInstalledAt); |         $isInitialInstall = is_null($previouslyInstalledAt); | ||||||
|         if ($isInitialInstall && config()->get('panel.email.send_install_notification', true)) { |         event(new ServerInstalled($server, $successful, $isInitialInstall)); | ||||||
|             event(new ServerInstalled($server)); |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         if (!$isInitialInstall && config()->get('panel.email.send_reinstall_notification', true)) { |  | ||||||
|             event(new ServerInstalled($server)); |  | ||||||
|         } |  | ||||||
| 
 | 
 | ||||||
|         return new JsonResponse([], Response::HTTP_NO_CONTENT); |         return new JsonResponse([], Response::HTTP_NO_CONTENT); | ||||||
|     } |     } | ||||||
|  | |||||||
							
								
								
									
										29
									
								
								app/Listeners/Server/ServerInstalledListener.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								app/Listeners/Server/ServerInstalledListener.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,29 @@ | |||||||
|  | <?php | ||||||
|  | 
 | ||||||
|  | namespace App\Listeners\Server; | ||||||
|  | 
 | ||||||
|  | use App\Events\Server\Installed; | ||||||
|  | use App\Filament\Server\Pages\Console; | ||||||
|  | use Filament\Notifications\Actions\Action; | ||||||
|  | use Filament\Notifications\Notification; | ||||||
|  | 
 | ||||||
|  | class ServerInstalledListener | ||||||
|  | { | ||||||
|  |     public function handle(Installed $event): void | ||||||
|  |     { | ||||||
|  |         $event->server->loadMissing('user'); | ||||||
|  | 
 | ||||||
|  |         Notification::make() | ||||||
|  |             ->status($event->successful ? 'success' : 'danger') | ||||||
|  |             ->title('Server ' . ($event->initialInstall ? 'Installation' : 'Reinstallation') . ' ' . ($event->successful ? 'completed' : 'failed')) | ||||||
|  |             ->body('Server Name: ' . $event->server->name) | ||||||
|  |             ->actions([ | ||||||
|  |                 Action::make('view') | ||||||
|  |                     ->button() | ||||||
|  |                     ->label('Open Server') | ||||||
|  |                     ->markAsRead() | ||||||
|  |                     ->url(fn () => Console::getUrl(panel: 'server', tenant: $event->server)), | ||||||
|  |             ]) | ||||||
|  |             ->sendToDatabase($event->server->user); | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										29
									
								
								app/Listeners/Server/SubUserAddedListener.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								app/Listeners/Server/SubUserAddedListener.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,29 @@ | |||||||
|  | <?php | ||||||
|  | 
 | ||||||
|  | namespace App\Listeners\Server; | ||||||
|  | 
 | ||||||
|  | use App\Events\Server\SubUserAdded; | ||||||
|  | use App\Filament\Server\Pages\Console; | ||||||
|  | use Filament\Notifications\Actions\Action; | ||||||
|  | use Filament\Notifications\Notification; | ||||||
|  | 
 | ||||||
|  | class SubUserAddedListener | ||||||
|  | { | ||||||
|  |     public function handle(SubUserAdded $event): void | ||||||
|  |     { | ||||||
|  |         $event->subuser->loadMissing('server'); | ||||||
|  |         $event->subuser->loadMissing('user'); | ||||||
|  | 
 | ||||||
|  |         Notification::make() | ||||||
|  |             ->title('Added to Server') | ||||||
|  |             ->body('You have been added as a subuser to ' . $event->subuser->server->name . '.') | ||||||
|  |             ->actions([ | ||||||
|  |                 Action::make('view') | ||||||
|  |                     ->button() | ||||||
|  |                     ->label('Open Server') | ||||||
|  |                     ->markAsRead() | ||||||
|  |                     ->url(fn () => Console::getUrl(panel: 'server', tenant: $event->subuser->server)), | ||||||
|  |             ]) | ||||||
|  |             ->sendToDatabase($event->subuser->user); | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										17
									
								
								app/Listeners/Server/SubUserRemovedListener.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								app/Listeners/Server/SubUserRemovedListener.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,17 @@ | |||||||
|  | <?php | ||||||
|  | 
 | ||||||
|  | namespace App\Listeners\Server; | ||||||
|  | 
 | ||||||
|  | use App\Events\Server\SubUserRemoved; | ||||||
|  | use Filament\Notifications\Notification; | ||||||
|  | 
 | ||||||
|  | class SubUserRemovedListener | ||||||
|  | { | ||||||
|  |     public function handle(SubUserRemoved $event): void | ||||||
|  |     { | ||||||
|  |         Notification::make() | ||||||
|  |             ->title('Removed from Server') | ||||||
|  |             ->body('You have been removed as a subuser from ' . $event->server->name . '.') | ||||||
|  |             ->sendToDatabase($event->user); | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -2,7 +2,12 @@ | |||||||
| 
 | 
 | ||||||
| namespace App\Notifications; | namespace App\Notifications; | ||||||
| 
 | 
 | ||||||
|  | use App\Events\Server\SubUserAdded; | ||||||
|  | use App\Models\Server; | ||||||
|  | use App\Models\User; | ||||||
| use Illuminate\Bus\Queueable; | use Illuminate\Bus\Queueable; | ||||||
|  | use Illuminate\Container\Container; | ||||||
|  | use Illuminate\Contracts\Notifications\Dispatcher; | ||||||
| use Illuminate\Notifications\Notification; | use Illuminate\Notifications\Notification; | ||||||
| use Illuminate\Contracts\Queue\ShouldQueue; | use Illuminate\Contracts\Queue\ShouldQueue; | ||||||
| use Illuminate\Notifications\Messages\MailMessage; | use Illuminate\Notifications\Messages\MailMessage; | ||||||
| @ -11,14 +16,22 @@ class AddedToServer extends Notification implements ShouldQueue | |||||||
| { | { | ||||||
|     use Queueable; |     use Queueable; | ||||||
| 
 | 
 | ||||||
|     public object $server; |     public Server $server; | ||||||
|  | 
 | ||||||
|  |     public User $user; | ||||||
| 
 | 
 | ||||||
|     /** |     /** | ||||||
|      * Create a new notification instance. |      * Handle a direct call to this notification from the subuser added event. This is configured | ||||||
|  |      * in the event service provider. | ||||||
|      */ |      */ | ||||||
|     public function __construct(array $server) |     public function handle(SubUserAdded $event): void | ||||||
|     { |     { | ||||||
|         $this->server = (object) $server; |         $this->server = $event->subuser->server; | ||||||
|  |         $this->user = $event->subuser->user; | ||||||
|  | 
 | ||||||
|  |         // Since we are calling this notification directly from an event listener we need to fire off the dispatcher
 | ||||||
|  |         // to send the email now. Don't use send() or you'll end up firing off two different events.
 | ||||||
|  |         Container::getInstance()->make(Dispatcher::class)->sendNow($this->user, $this); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /** |     /** | ||||||
| @ -35,7 +48,7 @@ class AddedToServer extends Notification implements ShouldQueue | |||||||
|     public function toMail(): MailMessage |     public function toMail(): MailMessage | ||||||
|     { |     { | ||||||
|         return (new MailMessage()) |         return (new MailMessage()) | ||||||
|             ->greeting('Hello ' . $this->server->user . '!') |             ->greeting('Hello ' . $this->user->username . '!') | ||||||
|             ->line('You have been added as a subuser for the following server, allowing you certain control over the server.') |             ->line('You have been added as a subuser for the following server, allowing you certain control over the server.') | ||||||
|             ->line('Server Name: ' . $this->server->name) |             ->line('Server Name: ' . $this->server->name) | ||||||
|             ->action('Visit Server', url('/server/' . $this->server->uuid_short)); |             ->action('Visit Server', url('/server/' . $this->server->uuid_short)); | ||||||
|  | |||||||
| @ -2,7 +2,12 @@ | |||||||
| 
 | 
 | ||||||
| namespace App\Notifications; | namespace App\Notifications; | ||||||
| 
 | 
 | ||||||
|  | use App\Events\Server\SubUserRemoved; | ||||||
|  | use App\Models\Server; | ||||||
|  | use App\Models\User; | ||||||
| use Illuminate\Bus\Queueable; | use Illuminate\Bus\Queueable; | ||||||
|  | use Illuminate\Container\Container; | ||||||
|  | use Illuminate\Contracts\Notifications\Dispatcher; | ||||||
| use Illuminate\Notifications\Notification; | use Illuminate\Notifications\Notification; | ||||||
| use Illuminate\Contracts\Queue\ShouldQueue; | use Illuminate\Contracts\Queue\ShouldQueue; | ||||||
| use Illuminate\Notifications\Messages\MailMessage; | use Illuminate\Notifications\Messages\MailMessage; | ||||||
| @ -11,14 +16,22 @@ class RemovedFromServer extends Notification implements ShouldQueue | |||||||
| { | { | ||||||
|     use Queueable; |     use Queueable; | ||||||
| 
 | 
 | ||||||
|     public object $server; |     public Server $server; | ||||||
|  | 
 | ||||||
|  |     public User $user; | ||||||
| 
 | 
 | ||||||
|     /** |     /** | ||||||
|      * Create a new notification instance. |      * Handle a direct call to this notification from the subuser removed event. This is configured | ||||||
|  |      * in the event service provider. | ||||||
|      */ |      */ | ||||||
|     public function __construct(array $server) |     public function handle(SubUserRemoved $event): void | ||||||
|     { |     { | ||||||
|         $this->server = (object) $server; |         $this->server = $event->server; | ||||||
|  |         $this->user = $event->user; | ||||||
|  | 
 | ||||||
|  |         // Since we are calling this notification directly from an event listener we need to fire off the dispatcher
 | ||||||
|  |         // to send the email now. Don't use send() or you'll end up firing off two different events.
 | ||||||
|  |         Container::getInstance()->make(Dispatcher::class)->sendNow($this->user, $this); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /** |     /** | ||||||
| @ -36,7 +49,7 @@ class RemovedFromServer extends Notification implements ShouldQueue | |||||||
|     { |     { | ||||||
|         return (new MailMessage()) |         return (new MailMessage()) | ||||||
|             ->error() |             ->error() | ||||||
|             ->greeting('Hello ' . $this->server->user . '.') |             ->greeting('Hello ' . $this->user->username . '.') | ||||||
|             ->line('You have been removed as a subuser for the following server.') |             ->line('You have been removed as a subuser for the following server.') | ||||||
|             ->line('Server Name: ' . $this->server->name) |             ->line('Server Name: ' . $this->server->name) | ||||||
|             ->action('Visit Panel', route('index')); |             ->action('Visit Panel', route('index')); | ||||||
|  | |||||||
| @ -4,7 +4,6 @@ namespace App\Notifications; | |||||||
| 
 | 
 | ||||||
| use App\Models\User; | use App\Models\User; | ||||||
| use Illuminate\Bus\Queueable; | use Illuminate\Bus\Queueable; | ||||||
| use App\Events\Event; |  | ||||||
| use App\Models\Server; | use App\Models\Server; | ||||||
| use Illuminate\Container\Container; | use Illuminate\Container\Container; | ||||||
| use App\Events\Server\Installed; | use App\Events\Server\Installed; | ||||||
| @ -27,14 +26,24 @@ class ServerInstalled extends Notification implements ShouldQueue | |||||||
|      */ |      */ | ||||||
|     public function handle(Installed $event): void |     public function handle(Installed $event): void | ||||||
|     { |     { | ||||||
|         $event->server->loadMissing('user'); |         if ($event->initialInstall && !config()->get('panel.email.send_install_notification', true)) { | ||||||
|  |             return; | ||||||
|  |         } | ||||||
| 
 | 
 | ||||||
|         $this->server = $event->server; |         if (!$event->initialInstall && !config()->get('panel.email.send_reinstall_notification', true)) { | ||||||
|         $this->user = $event->server->user; |             return; | ||||||
|  |         } | ||||||
| 
 | 
 | ||||||
|         // Since we are calling this notification directly from an event listener we need to fire off the dispatcher
 |         if ($event->successful) { | ||||||
|         // to send the email now. Don't use send() or you'll end up firing off two different events.
 |             $event->server->loadMissing('user'); | ||||||
|         Container::getInstance()->make(Dispatcher::class)->sendNow($this->user, $this); | 
 | ||||||
|  |             $this->server = $event->server; | ||||||
|  |             $this->user = $event->server->user; | ||||||
|  | 
 | ||||||
|  |             // Since we are calling this notification directly from an event listener we need to fire off the dispatcher
 | ||||||
|  |             // to send the email now. Don't use send() or you'll end up firing off two different events.
 | ||||||
|  |             Container::getInstance()->make(Dispatcher::class)->sendNow($this->user, $this); | ||||||
|  |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /** |     /** | ||||||
|  | |||||||
| @ -55,6 +55,7 @@ class AdminPanelProvider extends PanelProvider | |||||||
|             ->spa() |             ->spa() | ||||||
|             ->discoverResources(in: app_path('Filament/Admin/Resources'), for: 'App\\Filament\\Admin\\Resources') |             ->discoverResources(in: app_path('Filament/Admin/Resources'), for: 'App\\Filament\\Admin\\Resources') | ||||||
|             ->discoverPages(in: app_path('Filament/Admin/Pages'), for: 'App\\Filament\\Admin\\Pages') |             ->discoverPages(in: app_path('Filament/Admin/Pages'), for: 'App\\Filament\\Admin\\Pages') | ||||||
|  |             ->databaseNotifications() | ||||||
|             ->middleware([ |             ->middleware([ | ||||||
|                 EncryptCookies::class, |                 EncryptCookies::class, | ||||||
|                 AddQueuedCookiesToResponse::class, |                 AddQueuedCookiesToResponse::class, | ||||||
|  | |||||||
| @ -46,6 +46,7 @@ class AppPanelProvider extends PanelProvider | |||||||
|                     ->visible(fn (): bool => auth()->user()->canAccessPanel(Filament::getPanel('admin'))), |                     ->visible(fn (): bool => auth()->user()->canAccessPanel(Filament::getPanel('admin'))), | ||||||
|             ]) |             ]) | ||||||
|             ->discoverResources(in: app_path('Filament/App/Resources'), for: 'App\\Filament\\App\\Resources') |             ->discoverResources(in: app_path('Filament/App/Resources'), for: 'App\\Filament\\App\\Resources') | ||||||
|  |             ->databaseNotifications() | ||||||
|             ->middleware([ |             ->middleware([ | ||||||
|                 EncryptCookies::class, |                 EncryptCookies::class, | ||||||
|                 AddQueuedCookiesToResponse::class, |                 AddQueuedCookiesToResponse::class, | ||||||
|  | |||||||
| @ -65,6 +65,7 @@ class ServerPanelProvider extends PanelProvider | |||||||
|             ->discoverResources(in: app_path('Filament/Server/Resources'), for: 'App\\Filament\\Server\\Resources') |             ->discoverResources(in: app_path('Filament/Server/Resources'), for: 'App\\Filament\\Server\\Resources') | ||||||
|             ->discoverPages(in: app_path('Filament/Server/Pages'), for: 'App\\Filament\\Server\\Pages') |             ->discoverPages(in: app_path('Filament/Server/Pages'), for: 'App\\Filament\\Server\\Pages') | ||||||
|             ->discoverWidgets(in: app_path('Filament/Server/Widgets'), for: 'App\\Filament\\Server\\Widgets') |             ->discoverWidgets(in: app_path('Filament/Server/Widgets'), for: 'App\\Filament\\Server\\Widgets') | ||||||
|  |             ->databaseNotifications() | ||||||
|             ->middleware([ |             ->middleware([ | ||||||
|                 EncryptCookies::class, |                 EncryptCookies::class, | ||||||
|                 AddQueuedCookiesToResponse::class, |                 AddQueuedCookiesToResponse::class, | ||||||
|  | |||||||
| @ -2,8 +2,8 @@ | |||||||
| 
 | 
 | ||||||
| namespace App\Services\Subusers; | namespace App\Services\Subusers; | ||||||
| 
 | 
 | ||||||
|  | use App\Events\Server\SubUserAdded; | ||||||
| use App\Models\User; | use App\Models\User; | ||||||
| use App\Notifications\AddedToServer; |  | ||||||
| use Illuminate\Support\Str; | use Illuminate\Support\Str; | ||||||
| use App\Models\Server; | use App\Models\Server; | ||||||
| use App\Models\Subuser; | use App\Models\Subuser; | ||||||
| @ -63,11 +63,7 @@ class SubuserCreationService | |||||||
|                 'permissions' => array_unique($permissions), |                 'permissions' => array_unique($permissions), | ||||||
|             ]); |             ]); | ||||||
| 
 | 
 | ||||||
|             $subuser->user->notify(new AddedToServer([ |             event(new SubUserAdded($subuser)); | ||||||
|                 'user' => $subuser->user->name_first, |  | ||||||
|                 'name' => $subuser->server->name, |  | ||||||
|                 'uuid_short' => $subuser->server->uuid_short, |  | ||||||
|             ])); |  | ||||||
| 
 | 
 | ||||||
|             return $subuser; |             return $subuser; | ||||||
|         }); |         }); | ||||||
|  | |||||||
| @ -2,11 +2,11 @@ | |||||||
| 
 | 
 | ||||||
| namespace App\Services\Subusers; | namespace App\Services\Subusers; | ||||||
| 
 | 
 | ||||||
|  | use App\Events\Server\SubUserRemoved; | ||||||
| use App\Exceptions\Http\Connection\DaemonConnectionException; | use App\Exceptions\Http\Connection\DaemonConnectionException; | ||||||
| use App\Facades\Activity; | use App\Facades\Activity; | ||||||
| use App\Models\Server; | use App\Models\Server; | ||||||
| use App\Models\Subuser; | use App\Models\Subuser; | ||||||
| use App\Notifications\RemovedFromServer; |  | ||||||
| use App\Repositories\Daemon\DaemonServerRepository; | use App\Repositories\Daemon\DaemonServerRepository; | ||||||
| 
 | 
 | ||||||
| class SubuserDeletionService | class SubuserDeletionService | ||||||
| @ -25,10 +25,7 @@ class SubuserDeletionService | |||||||
|         $log->transaction(function ($instance) use ($server, $subuser) { |         $log->transaction(function ($instance) use ($server, $subuser) { | ||||||
|             $subuser->delete(); |             $subuser->delete(); | ||||||
| 
 | 
 | ||||||
|             $subuser->user->notify(new RemovedFromServer([ |             event(new SubUserRemoved($subuser->server, $subuser->user)); | ||||||
|                 'user' => $subuser->user->name_first, |  | ||||||
|                 'name' => $subuser->server->name, |  | ||||||
|             ])); |  | ||||||
| 
 | 
 | ||||||
|             try { |             try { | ||||||
|                 $this->serverRepository->setServer($server)->revokeUserJTI($subuser->user_id); |                 $this->serverRepository->setServer($server)->revokeUserJTI($subuser->user_id); | ||||||
|  | |||||||
| @ -185,7 +185,7 @@ class ProcessWebhooksTest extends TestCase | |||||||
| 
 | 
 | ||||||
|         $server = $this->createServer(); |         $server = $this->createServer(); | ||||||
| 
 | 
 | ||||||
|         event(new Installed($server)); |         event(new Installed($server, true, true)); | ||||||
| 
 | 
 | ||||||
|         $this->assertDatabaseCount(Webhook::class, 1); |         $this->assertDatabaseCount(Webhook::class, 1); | ||||||
|         $this->assertDatabaseHas(Webhook::class, [ |         $this->assertDatabaseHas(Webhook::class, [ | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 Boy132
						Boy132