Skip to content

Commit a81c3b4

Browse files
authored
Add support for stripe-style identifiers on existing models with UUIDs (#5548)
This is a partial implementation to begin moving towards stripe-style identifiers for resources in the system. Any models with an existing `uuid` column can easily be updated to return an identifier in the format of `prfx_xyz` where `prfx` is a four character prefix, and `xyz` is the UUID, encoded using base-32. These are quite easy to use within the API layer because we just need to do one quick transformation to extract the UUID for those models. This PR implements that logic for servers in the `SubstituteClientBindings` logic. A future PR will need to come through and handle identifiers for models that _don't_ currently use UUIDs for reference that we want to expose to clients. In those cases it is easier to just generate base-32 encoded UUID7s that get stored in the database and indexed. They follow the same base approach, but you don't need to do any transformations in the code (other than stripping the prefix, unless we decide to store the prefix). There is also now a `PTERODACTYL_USE_SERVER_IDENTIFIERS` environment variable, that when set to true, updates the front-end and API response to use this new identifier in place of the `uuidShort` value.
1 parent 14185a9 commit a81c3b4

19 files changed

Lines changed: 183 additions & 27 deletions

File tree

.php-cs-fixer.dist.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@
4747
'var',
4848
],
4949
],
50+
'phpdoc_no_alias_tag' => false,
5051
// 'random_api_migration' => true,
5152
'ternary_to_null_coalescing' => true,
5253
'yoda_style' => [
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<?php
2+
3+
namespace Pterodactyl\Contracts\Models;
4+
5+
use Illuminate\Database\Eloquent\Builder;
6+
7+
interface Identifiable
8+
{
9+
public function scopeWhereIdentifier(Builder $builder, string $identifier): void;
10+
}

app/Http/Middleware/Api/Client/SubstituteClientBindings.php

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,13 @@ public function handle($request, \Closure $next): mixed
1515
// Override default behavior of the model binding to use a specific table
1616
// column rather than the default 'id'.
1717
$this->router->bind('server', function ($value) {
18-
return Server::query()->where(strlen($value) === 8 ? 'uuidShort' : 'uuid', $value)->firstOrFail();
18+
return Server::query()
19+
->when(
20+
str_starts_with($value, 'serv_'),
21+
fn ($builder) => $builder->whereIdentifier($value),
22+
fn ($builder) => $builder->where(strlen($value) === 8 ? 'uuidShort' : 'uuid', $value)
23+
)
24+
->firstOrFail();
1925
});
2026

2127
$this->router->bind('user', function ($value, $route) {

app/Models/ActivityLog.php

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,11 @@
77
use Pterodactyl\Events\ActivityLogged;
88
use Illuminate\Database\Eloquent\Builder;
99
use Illuminate\Database\Eloquent\MassPrunable;
10+
use Pterodactyl\Contracts\Models\Identifiable;
1011
use Illuminate\Database\Eloquent\Relations\HasOne;
1112
use Illuminate\Database\Eloquent\Relations\HasMany;
1213
use Illuminate\Database\Eloquent\Relations\MorphTo;
14+
use Pterodactyl\Models\Traits\HasRealtimeIdentifier;
1315
use Illuminate\Database\Eloquent\Model as IlluminateModel;
1416

1517
/**
@@ -48,9 +50,11 @@
4850
*
4951
* @mixin \Eloquent
5052
*/
51-
class ActivityLog extends Model
53+
#[Attributes\Identifiable('actl')]
54+
class ActivityLog extends Model implements Identifiable
5255
{
5356
use MassPrunable;
57+
use HasRealtimeIdentifier;
5458

5559
public const RESOURCE_NAME = 'activity_log';
5660

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
<?php
2+
3+
namespace Pterodactyl\Models\Attributes;
4+
5+
#[\Attribute(\Attribute::TARGET_CLASS)]
6+
readonly class Identifiable
7+
{
8+
public function __construct(public string $prefix, public string $column = 'uuid')
9+
{
10+
}
11+
}

app/Models/Backup.php

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
namespace Pterodactyl\Models;
44

55
use Illuminate\Database\Eloquent\SoftDeletes;
6+
use Pterodactyl\Contracts\Models\Identifiable;
7+
use Pterodactyl\Models\Traits\HasRealtimeIdentifier;
68
use Illuminate\Database\Eloquent\Relations\BelongsTo;
79
use Illuminate\Database\Eloquent\Factories\HasFactory;
810

@@ -25,11 +27,13 @@
2527
* @property Server $server
2628
* @property \Pterodactyl\Models\AuditLog[] $audits
2729
*/
28-
class Backup extends Model
30+
#[Attributes\Identifiable('bkup')]
31+
class Backup extends Model implements Identifiable
2932
{
3033
/** @use HasFactory<\Database\Factories\BackupFactory> */
3134
use HasFactory;
3235
use SoftDeletes;
36+
use HasRealtimeIdentifier;
3337

3438
public const RESOURCE_NAME = 'backup';
3539

app/Models/Egg.php

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,9 @@
22

33
namespace Pterodactyl\Models;
44

5+
use Pterodactyl\Contracts\Models\Identifiable;
56
use Illuminate\Database\Eloquent\Relations\HasMany;
7+
use Pterodactyl\Models\Traits\HasRealtimeIdentifier;
68
use Illuminate\Database\Eloquent\Relations\BelongsTo;
79
use Illuminate\Database\Eloquent\Factories\HasFactory;
810

@@ -47,10 +49,12 @@
4749
* @property Egg|null $scriptFrom
4850
* @property Egg|null $configFrom
4951
*/
50-
class Egg extends Model
52+
#[Attributes\Identifiable('eegg')]
53+
class Egg extends Model implements Identifiable
5154
{
5255
/** @use HasFactory<\Database\Factories\EggFactory> */
5356
use HasFactory;
57+
use HasRealtimeIdentifier;
5458

5559
/**
5660
* The resource name for this model when it is transformed into an

app/Models/Mount.php

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
namespace Pterodactyl\Models;
44

55
use Illuminate\Validation\Rules\NotIn;
6+
use Pterodactyl\Contracts\Models\Identifiable;
7+
use Pterodactyl\Models\Traits\HasRealtimeIdentifier;
68
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
79

810
/**
@@ -18,8 +20,11 @@
1820
* @property \Pterodactyl\Models\Node[]|\Illuminate\Database\Eloquent\Collection $nodes
1921
* @property \Pterodactyl\Models\Server[]|\Illuminate\Database\Eloquent\Collection $servers
2022
*/
21-
class Mount extends Model
23+
#[Attributes\Identifiable('moun')]
24+
class Mount extends Model implements Identifiable
2225
{
26+
use HasRealtimeIdentifier;
27+
2328
/**
2429
* The resource name for this model when it is transformed into an
2530
* API representation using fractal.

app/Models/Node.php

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,9 @@
77
use Illuminate\Container\Container;
88
use Illuminate\Notifications\Notifiable;
99
use Illuminate\Contracts\Encryption\Encrypter;
10+
use Pterodactyl\Contracts\Models\Identifiable;
1011
use Illuminate\Database\Eloquent\Relations\HasMany;
12+
use Pterodactyl\Models\Traits\HasRealtimeIdentifier;
1113
use Illuminate\Database\Eloquent\Relations\BelongsTo;
1214
use Illuminate\Database\Eloquent\Factories\HasFactory;
1315
use Illuminate\Database\Eloquent\Relations\HasManyThrough;
@@ -40,11 +42,13 @@
4042
* @property \Pterodactyl\Models\Server[]|\Illuminate\Database\Eloquent\Collection $servers
4143
* @property \Pterodactyl\Models\Allocation[]|\Illuminate\Database\Eloquent\Collection $allocations
4244
*/
43-
class Node extends Model
45+
#[Attributes\Identifiable('node')]
46+
class Node extends Model implements Identifiable
4447
{
4548
/** @use HasFactory<\Database\Factories\NodeFactory> */
4649
use HasFactory;
4750
use Notifiable;
51+
use HasRealtimeIdentifier;
4852

4953
/**
5054
* The resource name for this model when it is transformed into an

app/Models/Server.php

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,10 @@
55
use Illuminate\Notifications\Notifiable;
66
use Illuminate\Database\Query\JoinClause;
77
use Znck\Eloquent\Traits\BelongsToThrough;
8+
use Pterodactyl\Contracts\Models\Identifiable;
89
use Illuminate\Database\Eloquent\Relations\HasOne;
910
use Illuminate\Database\Eloquent\Relations\HasMany;
11+
use Pterodactyl\Models\Traits\HasRealtimeIdentifier;
1012
use Illuminate\Database\Eloquent\Relations\BelongsTo;
1113
use Illuminate\Database\Eloquent\Factories\HasFactory;
1214
use Illuminate\Database\Eloquent\Relations\MorphToMany;
@@ -103,19 +105,20 @@
103105
*
104106
* @mixin \Eloquent
105107
*/
106-
class Server extends Model
108+
#[Attributes\Identifiable('serv')]
109+
class Server extends Model implements Identifiable
107110
{
108111
/** @use HasFactory<\Database\Factories\ServerFactory> */
109112
use HasFactory;
110113
use BelongsToThrough;
111114
use Notifiable;
115+
use HasRealtimeIdentifier;
112116

113117
/**
114118
* The resource name for this model when it is transformed into an
115119
* API representation using fractal.
116120
*/
117121
public const RESOURCE_NAME = 'server';
118-
119122
public const STATUS_INSTALLING = 'installing';
120123
public const STATUS_INSTALL_FAILED = 'install_failed';
121124
public const STATUS_REINSTALL_FAILED = 'reinstall_failed';

0 commit comments

Comments
 (0)