2024-10-26 20:35:25 -04:00
< ? php
namespace App\Models ;
2025-09-24 13:34:19 +02:00
use App\Enums\WebhookType ;
2025-07-05 18:42:34 +02:00
use App\Jobs\ProcessWebhook ;
2024-10-26 20:35:25 -04:00
use Illuminate\Database\Eloquent\Factories\HasFactory ;
use Illuminate\Database\Eloquent\Model ;
use Illuminate\Database\Eloquent\Relations\HasMany ;
2024-10-27 05:42:08 +01:00
use Illuminate\Database\Eloquent\SoftDeletes ;
2025-09-24 13:34:19 +02:00
use Illuminate\Support\Carbon ;
2024-11-07 17:26:47 -05:00
use Illuminate\Support\Collection ;
2024-10-26 20:35:25 -04:00
use Illuminate\Support\Facades\File ;
2025-07-05 18:42:34 +02:00
use Livewire\Features\SupportEvents\HandlesEvents ;
2024-10-26 20:35:25 -04:00
2024-11-22 09:27:57 +01:00
/**
2025-07-05 18:42:34 +02:00
* @ property string | array < string , mixed >| null $payload
2024-11-22 09:27:57 +01:00
* @ property string $endpoint
* @ property string $description
2025-03-03 14:41:19 -05:00
* @ property string [] $events
2025-07-05 18:42:34 +02:00
* @ property WebhookType | string | null $type
2025-09-08 13:12:33 -04:00
* @ property Carbon | null $created_at
* @ property Carbon | null $updated_at
* @ property Carbon | null $deleted_at
2025-07-05 18:42:34 +02:00
* @ property array < string , string >| null $headers
2024-11-22 09:27:57 +01:00
*/
2024-10-26 20:35:25 -04:00
class WebhookConfiguration extends Model
{
2025-07-05 18:42:34 +02:00
use HandlesEvents , HasFactory , SoftDeletes ;
2024-10-26 20:35:25 -04:00
2025-03-03 14:41:19 -05:00
/** @var string[] */
2024-10-28 23:44:32 +01:00
protected static array $eventBlacklist = [
'eloquent.created: App\Models\Webhook' ,
];
2024-10-26 20:35:25 -04:00
protected $fillable = [
2025-07-05 18:42:34 +02:00
'type' ,
'payload' ,
2024-10-26 20:35:25 -04:00
'endpoint' ,
'description' ,
'events' ,
2025-07-05 18:42:34 +02:00
'headers' ,
];
/**
* Default values for specific fields in the database .
*/
protected $attributes = [
'type' => WebhookType :: Regular ,
'payload' => null ,
2024-10-26 20:35:25 -04:00
];
protected function casts () : array
{
return [
2025-07-05 18:42:34 +02:00
'events' => 'array' ,
'payload' => 'array' ,
'type' => WebhookType :: class ,
'headers' => 'array' ,
2024-10-26 20:35:25 -04:00
];
}
protected static function booted () : void
{
self :: saved ( static function ( self $webhookConfiguration ) : void {
$changedEvents = collect ([
2025-07-05 18:42:34 +02:00
... ( $webhookConfiguration -> events ),
2024-10-26 20:35:25 -04:00
... $webhookConfiguration -> getOriginal ( 'events' , '[]' ),
]) -> unique ();
2024-11-07 17:26:47 -05:00
self :: updateCache ( $changedEvents );
});
self :: deleted ( static function ( self $webhookConfiguration ) : void {
2025-07-05 18:42:34 +02:00
self :: updateCache ( collect ( $webhookConfiguration -> events ));
2024-11-07 17:26:47 -05:00
});
}
2024-10-26 20:35:25 -04:00
2024-11-07 17:26:47 -05:00
private static function updateCache ( Collection $eventList ) : void
{
$eventList -> each ( function ( string $event ) {
cache () -> forever ( " webhooks. $event " , WebhookConfiguration :: query () -> whereJsonContains ( 'events' , $event ) -> get ());
2024-10-26 20:35:25 -04:00
});
2024-11-07 17:26:47 -05:00
cache () -> forever ( 'watchedWebhooks' , WebhookConfiguration :: pluck ( 'events' ) -> flatten () -> unique () -> values () -> all ());
2024-10-26 20:35:25 -04:00
}
public function webhooks () : HasMany
{
return $this -> hasMany ( Webhook :: class );
}
2025-03-03 14:41:19 -05:00
/** @return string[] */
2024-10-26 20:35:25 -04:00
public static function allPossibleEvents () : array
{
2024-10-28 23:44:32 +01:00
return collect ( static :: discoverCustomEvents ())
-> merge ( static :: allModelEvents ())
-> unique ()
-> filter ( fn ( $event ) => ! in_array ( $event , static :: $eventBlacklist ))
-> all ();
2024-10-26 20:35:25 -04:00
}
2025-03-03 14:41:19 -05:00
/** @return array<string, string> */
2024-10-26 20:35:25 -04:00
public static function filamentCheckboxList () : array
{
$list = [];
$events = static :: allPossibleEvents ();
foreach ( $events as $event ) {
$list [ $event ] = static :: transformClassName ( $event );
}
return $list ;
}
public static function transformClassName ( string $event ) : string
{
return str ( $event )
-> after ( 'eloquent.' )
-> replace ( 'App\\Models\\' , '' )
-> replace ( 'App\\Events\\' , 'event: ' )
-> toString ();
}
2025-03-03 14:41:19 -05:00
/** @return string[] */
2024-10-26 20:35:25 -04:00
public static function allModelEvents () : array
{
$eventTypes = [ 'created' , 'updated' , 'deleted' ];
$models = static :: discoverModels ();
$events = [];
foreach ( $models as $model ) {
foreach ( $eventTypes as $eventType ) {
$events [] = " eloquent. $eventType : $model " ;
}
}
return $events ;
}
2025-03-03 14:41:19 -05:00
/** @return string[] */
2024-10-26 20:35:25 -04:00
public static function discoverModels () : array
{
$namespace = 'App\\Models\\' ;
$directory = app_path ( 'Models' );
$models = [];
foreach ( File :: allFiles ( $directory ) as $file ) {
$models [] = $namespace . str ( $file -> getFilename ())
-> replace ([ DIRECTORY_SEPARATOR , '.php' ], [ '\\' , '' ]);
}
return $models ;
}
2025-03-03 14:41:19 -05:00
/** @return string[] */
2024-10-26 20:35:25 -04:00
public static function discoverCustomEvents () : array
{
$directory = app_path ( 'Events' );
$events = [];
2025-01-05 19:07:01 -05:00
foreach ( File :: allFiles ( $directory ) as $file ) {
$namespace = str ( $file -> getPath ())
-> after ( base_path ())
2025-07-05 18:42:34 +02:00
-> replace ([ DIRECTORY_SEPARATOR , '\\app\\' ], [ '\\' , 'App\\' ]);
2024-10-26 20:35:25 -04:00
2025-01-05 19:07:01 -05:00
$events [] = $namespace . '\\' . str ( $file -> getFilename ())
-> replace ([ DIRECTORY_SEPARATOR , '.php' ], [ '\\' , '' ]);
2024-10-26 20:35:25 -04:00
}
return $events ;
}
2025-07-05 18:42:34 +02:00
/**
2025-11-09 15:35:00 +01:00
* @ param array < mixed , mixed >| object $replacement
2025-07-05 18:42:34 +02:00
* */
2025-11-09 15:35:00 +01:00
public function replaceVars ( array | object $replacement , string $subject ) : string
2025-07-05 18:42:34 +02:00
{
2025-11-09 15:35:00 +01:00
if ( is_object ( $replacement )) {
$replacement = $replacement -> toArray ();
}
2025-07-05 18:42:34 +02:00
return preg_replace_callback (
'/{{(.*?)}}/' ,
function ( $matches ) use ( $replacement ) {
$trimmed = trim ( $matches [ 1 ]);
2025-09-18 16:40:24 +02:00
return data_get ( $replacement , $trimmed , $trimmed );
2025-07-05 18:42:34 +02:00
},
$subject
);
}
/** @param array<mixed, mixed> $eventData */
public function run ( ? string $eventName = null , ? array $eventData = null ) : void
{
$eventName ? ? = 'eloquent.created: ' . Server :: class ;
2025-09-18 16:40:24 +02:00
$eventData ? ? = static :: getWebhookSampleData ();
2025-07-05 18:42:34 +02:00
ProcessWebhook :: dispatch ( $this , $eventName , [ $eventData ]);
}
/**
* @ return array < string , mixed >
*/
2025-09-18 16:40:24 +02:00
public static function getWebhookSampleData () : array
2025-07-05 18:42:34 +02:00
{
return [
2025-09-18 16:40:24 +02:00
'id' => 4 ,
'uuid' => '4864a058-9a3b-44a9-a6cf-c1355e89406e' ,
'uuid_short' => '4864a058' ,
2025-07-05 18:42:34 +02:00
'node_id' => 1 ,
2025-09-18 16:40:24 +02:00
'name' => 'Example Server' ,
2025-07-05 18:42:34 +02:00
'owner_id' => 1 ,
2025-09-18 16:40:24 +02:00
'memory' => 6144 ,
'swap' => 0 ,
'disk' => 20480 ,
2025-07-05 18:42:34 +02:00
'io' => 500 ,
2025-09-18 16:40:24 +02:00
'cpu' => 300 ,
'egg_id' => 1 ,
'startup' => 'java -Xms128M -XX:MaxRAMPercentage=95.0 -Dterminal.jline=false -Dterminal.ansi=true -jar {{SERVER_JARFILE}}' ,
'created_at' => '2025-09-05T01:15:43.000000Z' ,
'updated_at' => '2025-09-11T22:45:14.000000Z' ,
2025-07-05 18:42:34 +02:00
'allocation_id' => 4 ,
2025-12-09 17:53:07 -05:00
'image' => 'ghcr.io/pelican-eggs/yolks:java_21' ,
2025-09-18 16:40:24 +02:00
'description' => 'This is an example server description.' ,
'skip_scripts' => false ,
'external_id' => null ,
'database_limit' => 5 ,
2025-07-05 18:42:34 +02:00
'allocation_limit' => 5 ,
2025-09-18 16:40:24 +02:00
'threads' => null ,
'backup_limit' => 5 ,
'status' => null ,
'installed_at' => '2025-09-06T03:02:31.000000Z' ,
'oom_killer' => false ,
2025-07-05 18:42:34 +02:00
'docker_labels' => [],
2025-09-18 16:40:24 +02:00
'allocation' => [
'id' => 4 ,
'node_id' => 1 ,
'ip' => '0.0.0.0' ,
'port' => 25565 ,
'server_id' => 4 ,
'created_at' => '2025-07-01T20:12:41.000000Z' ,
'updated_at' => '2025-09-09T17:47:22.000000Z' ,
'ip_alias' => null ,
'notes' => null ,
],
'variables' => [
[
'id' => 1 ,
'egg_id' => 1 ,
'name' => 'Build Number' ,
'description' => 'The build number for the paper release.\r\n\r\nLeave at latest to always get the latest version. Invalid versions will default to latest.' ,
'env_variable' => 'BUILD_NUMBER' ,
'default_value' => 'latest' ,
'user_viewable' => true ,
'user_editable' => true ,
'rules' => [ 'required' , 'string' , 'max:20' ],
'created_at' => '2025-09-05T01:15:43.000000Z' ,
'updated_at' => '2025-09-05T01:15:43.000000Z' ,
'sort' => 4 ,
'server_value' => 'latest' ,
],
[
'id' => 2 ,
'egg_id' => 1 ,
'name' => 'Download Path' ,
'description' => 'A URL to use to download a server.jar rather than the ones in the install script. This is not user\nviewable.' ,
'env_variable' => 'DL_PATH' ,
'default_value' => '' ,
'user_viewable' => false ,
'user_editable' => false ,
'rules' => [ 'nullable' , 'string' ],
'created_at' => '2025-09-05T01:15:43.000000Z' ,
'updated_at' => '2025-09-05T01:15:43.000000Z' ,
'sort' => 3 ,
'server_value' => '' ,
],
[
'id' => 3 ,
'egg_id' => 1 ,
'name' => 'Minecraft Version' ,
'description' => 'The version of minecraft to download. \r\n\r\nLeave at latest to always get the latest version. Invalid versions will default to latest.' ,
'env_variable' => 'MINECRAFT_VERSION' ,
'default_value' => 'latest' ,
'user_viewable' => true ,
'user_editable' => true ,
'rules' => [ 'nullable' , 'string' , 'max:20' ],
'created_at' => '2025-09-05T01:15:43.000000Z' ,
'updated_at' => '2025-09-05T01:15:43.000000Z' ,
'sort' => 1 ,
'server_value' => '1.21.8' ,
],
[
'id' => 4 ,
'egg_id' => 1 ,
'name' => 'Server Jar File' ,
'description' => 'The name of the server jarfile to run the server with.' ,
'env_variable' => 'SERVER_JARFILE' ,
'default_value' => 'server.jar' ,
'user_viewable' => true ,
'user_editable' => true ,
'rules' => [ 'required' , 'regex:/^([\w\d._-]+)(\.jar)$/' ],
'created_at' => '2025-09-05T01:15:43.000000Z' ,
'updated_at' => '2025-09-05T01:15:43.000000Z' ,
'sort' => 2 ,
'server_value' => 'server.jar' ,
],
],
'server_variables' => [
'record-21' => [
'id' => 21 ,
'server_id' => 4 ,
'variable_id' => 3 ,
'variable_value' => '1.21.8' ,
'created_at' => '2025-09-06T06:00:58.000000Z' ,
'updated_at' => '2025-09-09T17:59:40.000000Z' ,
'variable' => [
'id' => 3 ,
'egg_id' => 1 ,
'name' => 'Minecraft Version' ,
'description' => 'The version of minecraft to download. \r\n\r\nLeave at latest to always get the latest version. Invalid versions will default to latest.' ,
'env_variable' => 'MINECRAFT_VERSION' ,
'default_value' => 'latest' ,
'user_viewable' => true ,
'user_editable' => true ,
'rules' => [ 'nullable' , 'string' , 'max:20' ],
'created_at' => '2025-09-05T01:15:43.000000Z' ,
'updated_at' => '2025-09-05T01:15:43.000000Z' ,
'sort' => 1 ,
],
],
'record-22' => [
'id' => 22 ,
'server_id' => 4 ,
'variable_id' => 4 ,
'variable_value' => 'server.jar' ,
'created_at' => '2025-09-06T06:00:58.000000Z' ,
'updated_at' => '2025-09-06T06:01:05.000000Z' ,
'variable' => [
'id' => 4 ,
'egg_id' => 1 ,
'name' => 'Server Jar File' ,
'description' => 'The name of the server jarfile to run the server with.' ,
'env_variable' => 'SERVER_JARFILE' ,
'default_value' => 'server.jar' ,
'user_viewable' => true ,
'user_editable' => true ,
'rules' => [ 'required' , 'regex:/^([\w\d._-]+)(\.jar)$/' ],
'created_at' => '2025-09-05T01:15:43.000000Z' ,
'updated_at' => '2025-09-05T01:15:43.000000Z' ,
'sort' => 2 ,
],
],
'record-20' => [
'id' => 20 ,
'server_id' => 4 ,
'variable_id' => 2 ,
'variable_value' => '' ,
'created_at' => '2025-09-06T06:00:58.000000Z' ,
'updated_at' => '2025-09-06T06:00:58.000000Z' ,
'variable' => [
'id' => 2 ,
'egg_id' => 1 ,
'name' => 'Download Path' ,
'description' => 'A URL to use to download a server.jar rather than the ones in the install script. This is not user\nviewable.' ,
'env_variable' => 'DL_PATH' ,
'default_value' => '' ,
'user_viewable' => false ,
'user_editable' => false ,
'rules' => [ 'nullable' , 'string' ],
'created_at' => '2025-09-05T01:15:43.000000Z' ,
'updated_at' => '2025-09-05T01:15:43.000000Z' ,
'sort' => 3 ,
],
],
'record-19' => [
'id' => 19 ,
'server_id' => 4 ,
'variable_id' => 1 ,
'variable_value' => 'latest' ,
'created_at' => '2025-09-06T06:00:58.000000Z' ,
'updated_at' => '2025-09-06T06:00:58.000000Z' ,
'variable' => [
'id' => 1 ,
'egg_id' => 1 ,
'name' => 'Build Number' ,
'description' => 'The build number for the paper release.\r\n\r\nLeave at latest to always get the latest version. Invalid versions will default to latest.' ,
'env_variable' => 'BUILD_NUMBER' ,
'default_value' => 'latest' ,
'user_viewable' => true ,
'user_editable' => true ,
'rules' => [ 'required' , 'string' , 'max:20' ],
'created_at' => '2025-09-05T01:15:43.000000Z' ,
'updated_at' => '2025-09-05T01:15:43.000000Z' ,
'sort' => 4 ,
],
],
],
'event' => 'updated: Server' ,
2025-07-05 18:42:34 +02:00
];
}
2024-10-26 20:35:25 -04:00
}