Skip to content

Commit cae604e

Browse files
committed
Include egg variables in the output from the API
1 parent 3a2c60c commit cae604e

File tree

12 files changed

+204
-92
lines changed

12 files changed

+204
-92
lines changed

app/Models/EggVariable.php

Lines changed: 38 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,27 @@
22

33
namespace Pterodactyl\Models;
44

5+
/**
6+
* @property int $id
7+
* @property int $egg_id
8+
* @property string $name
9+
* @property string $description
10+
* @property string $env_variable
11+
* @property string $default_value
12+
* @property bool $user_viewable
13+
* @property bool $user_editable
14+
* @property string $rules
15+
* @property \Carbon\CarbonImmutable $created_at
16+
* @property \Carbon\CarbonImmutable $updated_at
17+
*
18+
* @property bool $required
19+
* @property \Pterodactyl\Models\Egg $egg
20+
* @property \Pterodactyl\Models\ServerVariable $serverVariable
21+
*
22+
* The "server_value" variable is only present on the object if you've loaded this model
23+
* using the server relationship.
24+
* @property string|null $server_value
25+
*/
526
class EggVariable extends Model
627
{
728
/**
@@ -17,6 +38,11 @@ class EggVariable extends Model
1738
*/
1839
const RESERVED_ENV_NAMES = 'SERVER_MEMORY,SERVER_IP,SERVER_PORT,ENV,HOME,USER,STARTUP,SERVER_UUID,UUID';
1940

41+
/**
42+
* @var bool
43+
*/
44+
protected $immutableDates = true;
45+
2046
/**
2147
* The table associated with the model.
2248
*
@@ -38,8 +64,8 @@ class EggVariable extends Model
3864
*/
3965
protected $casts = [
4066
'egg_id' => 'integer',
41-
'user_viewable' => 'integer',
42-
'user_editable' => 'integer',
67+
'user_viewable' => 'bool',
68+
'user_editable' => 'bool',
4369
];
4470

4571
/**
@@ -65,12 +91,19 @@ class EggVariable extends Model
6591
];
6692

6793
/**
68-
* @param $value
6994
* @return bool
7095
*/
71-
public function getRequiredAttribute($value)
96+
public function getRequiredAttribute()
97+
{
98+
return in_array('required', explode('|', $this->rules));
99+
}
100+
101+
/**
102+
* @return \Illuminate\Database\Eloquent\Relations\HasOne
103+
*/
104+
public function egg()
72105
{
73-
return $this->rules === 'required' || str_contains($this->rules, ['required|', '|required']);
106+
return $this->hasOne(Egg::class);
74107
}
75108

76109
/**

app/Models/Server.php

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@
4545
* @property \Pterodactyl\Models\Node $node
4646
* @property \Pterodactyl\Models\Nest $nest
4747
* @property \Pterodactyl\Models\Egg $egg
48-
* @property \Pterodactyl\Models\ServerVariable[]|\Illuminate\Database\Eloquent\Collection $variables
48+
* @property \Pterodactyl\Models\EggVariable[]|\Illuminate\Database\Eloquent\Collection $variables
4949
* @property \Pterodactyl\Models\Schedule[]|\Illuminate\Database\Eloquent\Collection $schedule
5050
* @property \Pterodactyl\Models\Database[]|\Illuminate\Database\Eloquent\Collection $databases
5151
* @property \Pterodactyl\Models\Location $location
@@ -270,7 +270,9 @@ public function egg()
270270
*/
271271
public function variables()
272272
{
273-
return $this->hasMany(ServerVariable::class);
273+
return $this->hasMany(EggVariable::class, 'egg_id', 'egg_id')
274+
->select(['egg_variables.*', 'server_variables.variable_value as server_value'])
275+
->leftJoin('server_variables', 'server_variables.variable_id', '=', 'egg_variables.id');
274276
}
275277

276278
/**

app/Repositories/Eloquent/ServerRepository.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,10 @@ public function getPrimaryAllocation(Server $server, bool $refresh = false): Ser
143143
*/
144144
public function getVariablesWithValues(int $id, bool $returnAsObject = false)
145145
{
146+
$this->getBuilder()
147+
->with('variables', 'egg.variables')
148+
->findOrFail($id);
149+
146150
try {
147151
$instance = $this->getBuilder()->with('variables', 'egg.variables')->find($id, $this->getColumns());
148152
} catch (ModelNotFoundException $exception) {
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
<?php
2+
3+
namespace Pterodactyl\Services\Servers;
4+
5+
use Pterodactyl\Models\Server;
6+
7+
class StartupCommandService
8+
{
9+
/**
10+
* Generates a startup command for a given server instance.
11+
*
12+
* @param \Pterodactyl\Models\Server $server
13+
* @return string
14+
*/
15+
public function handle(Server $server): string
16+
{
17+
$find = ['{{SERVER_MEMORY}}', '{{SERVER_IP}}', '{{SERVER_PORT}}'];
18+
$replace = [$server->memory, $server->allocation->ip, $server->allocation->port];
19+
20+
foreach ($server->variables as $variable) {
21+
$find[] = '{{' . $variable->env_variable . '}}';
22+
$replace[] = $variable->user_viewable ? ($variable->server_value ?? $variable->default_value) : '[hidden]';
23+
}
24+
25+
return str_replace($find, $replace, $server->startup);
26+
}
27+
}

app/Services/Servers/StartupCommandViewService.php

Lines changed: 0 additions & 56 deletions
This file was deleted.
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
<?php
2+
3+
namespace Pterodactyl\Transformers\Api\Client;
4+
5+
use Pterodactyl\Models\EggVariable;
6+
7+
class EggVariableTransformer extends BaseClientTransformer
8+
{
9+
/**
10+
* @return string
11+
*/
12+
public function getResourceName(): string
13+
{
14+
return EggVariable::RESOURCE_NAME;
15+
}
16+
17+
/**
18+
* @param \Pterodactyl\Models\EggVariable $variable
19+
* @return array
20+
*/
21+
public function transform(EggVariable $variable)
22+
{
23+
return [
24+
'name' => $variable->name,
25+
'description' => $variable->description,
26+
'env_variable' => $variable->env_variable,
27+
'default_value' => $variable->default_value,
28+
'server_value' => $variable->server_value,
29+
'is_editable' => $variable->user_editable,
30+
'rules' => $variable->rules,
31+
];
32+
}
33+
}

app/Transformers/Api/Client/ServerTransformer.php

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,17 @@
66
use Pterodactyl\Models\Server;
77
use Pterodactyl\Models\Subuser;
88
use Pterodactyl\Models\Allocation;
9+
use Illuminate\Container\Container;
10+
use Pterodactyl\Models\EggVariable;
11+
use Pterodactyl\Services\Servers\StartupCommandService;
12+
use Pterodactyl\Transformers\Api\Client\EggVariableTransformer;
913

1014
class ServerTransformer extends BaseClientTransformer
1115
{
1216
/**
1317
* @var string[]
1418
*/
15-
protected $defaultIncludes = ['allocations'];
19+
protected $defaultIncludes = ['allocations', 'variables'];
1620

1721
/**
1822
* @var array
@@ -36,6 +40,9 @@ public function getResourceName(): string
3640
*/
3741
public function transform(Server $server): array
3842
{
43+
/** @var \Pterodactyl\Services\Servers\StartupCommandService $service */
44+
$service = Container::getInstance()->make(StartupCommandService::class);
45+
3946
return [
4047
'server_owner' => $this->getKey()->user_id === $server->owner_id,
4148
'identifier' => $server->uuidShort,
@@ -54,6 +61,7 @@ public function transform(Server $server): array
5461
'io' => $server->io,
5562
'cpu' => $server->cpu,
5663
],
64+
'invocation' => $service->handle($server),
5765
'feature_limits' => [
5866
'databases' => $server->database_limit,
5967
'allocations' => $server->allocation_limit,
@@ -80,6 +88,20 @@ public function includeAllocations(Server $server)
8088
);
8189
}
8290

91+
/**
92+
* @param \Pterodactyl\Models\Server $server
93+
* @return \League\Fractal\Resource\Collection
94+
* @throws \Pterodactyl\Exceptions\Transformer\InvalidTransformerLevelException
95+
*/
96+
public function includeVariables(Server $server)
97+
{
98+
return $this->collection(
99+
$server->variables->where('user_viewable', true),
100+
$this->makeTransformer(EggVariableTransformer::class),
101+
EggVariable::RESOURCE_NAME
102+
);
103+
}
104+
83105
/**
84106
* Returns the egg associated with this server.
85107
*

resources/scripts/api/server/getServer.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ export interface Server {
1919
ip: string;
2020
port: number;
2121
};
22+
invocation: string;
2223
description: string;
2324
allocations: Allocation[];
2425
limits: {
@@ -43,6 +44,7 @@ export const rawDataToServerObject = ({ attributes: data }: FractalResponseData)
4344
uuid: data.uuid,
4445
name: data.name,
4546
node: data.node,
47+
invocation: data.invocation,
4648
sftpDetails: {
4749
ip: data.sftp_details.ip,
4850
port: data.sftp_details.port,

resources/scripts/components/elements/PageContentBlock.tsx

Lines changed: 41 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -3,31 +3,48 @@ import ContentContainer from '@/components/elements/ContentContainer';
33
import { CSSTransition } from 'react-transition-group';
44
import tw from 'twin.macro';
55
import FlashMessageRender from '@/components/FlashMessageRender';
6+
import { Helmet } from 'react-helmet';
7+
import useServer from '@/plugins/useServer';
68

7-
const PageContentBlock: React.FC<{ showFlashKey?: string; className?: string }> = ({ children, showFlashKey, className }) => (
8-
<CSSTransition timeout={150} classNames={'fade'} appear in>
9-
<>
10-
<ContentContainer css={tw`my-10`} className={className}>
11-
{showFlashKey &&
12-
<FlashMessageRender byKey={showFlashKey} css={tw`mb-4`}/>
9+
interface Props {
10+
title?: string;
11+
className?: string;
12+
showFlashKey?: string;
13+
}
14+
15+
const PageContentBlock: React.FC<Props> = ({ title, showFlashKey, className, children }) => {
16+
const { name } = useServer();
17+
18+
return (
19+
<CSSTransition timeout={150} classNames={'fade'} appear in>
20+
<>
21+
{!!title &&
22+
<Helmet>
23+
<title>{name} | {title}</title>
24+
</Helmet>
1325
}
14-
{children}
15-
</ContentContainer>
16-
<ContentContainer css={tw`mb-4`}>
17-
<p css={tw`text-center text-neutral-500 text-xs`}>
18-
&copy; 2015 - 2020&nbsp;
19-
<a
20-
rel={'noopener nofollow noreferrer'}
21-
href={'https://pterodactyl.io'}
22-
target={'_blank'}
23-
css={tw`no-underline text-neutral-500 hover:text-neutral-300`}
24-
>
25-
Pterodactyl Software
26-
</a>
27-
</p>
28-
</ContentContainer>
29-
</>
30-
</CSSTransition>
31-
);
26+
<ContentContainer css={tw`my-10`} className={className}>
27+
{showFlashKey &&
28+
<FlashMessageRender byKey={showFlashKey} css={tw`mb-4`}/>
29+
}
30+
{children}
31+
</ContentContainer>
32+
<ContentContainer css={tw`mb-4`}>
33+
<p css={tw`text-center text-neutral-500 text-xs`}>
34+
&copy; 2015 - 2020&nbsp;
35+
<a
36+
rel={'noopener nofollow noreferrer'}
37+
href={'https://pterodactyl.io'}
38+
target={'_blank'}
39+
css={tw`no-underline text-neutral-500 hover:text-neutral-300`}
40+
>
41+
Pterodactyl Software
42+
</a>
43+
</p>
44+
</ContentContainer>
45+
</>
46+
</CSSTransition>
47+
);
48+
};
3249

3350
export default PageContentBlock;
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import React from 'react';
2+
import PageContentBlock from '@/components/elements/PageContentBlock';
3+
import TitledGreyBox from '@/components/elements/TitledGreyBox';
4+
import useServer from '@/plugins/useServer';
5+
import tw from 'twin.macro';
6+
7+
const StartupContainer = () => {
8+
const { invocation } = useServer();
9+
10+
return (
11+
<PageContentBlock title={'Startup Settings'} showFlashKey={'server:startup'}>
12+
<TitledGreyBox title={'Startup Command'}>
13+
<div css={tw`px-1 py-2`}>
14+
<p css={tw`font-mono bg-neutral-900 rounded py-2 px-4`}>
15+
{invocation}
16+
</p>
17+
</div>
18+
</TitledGreyBox>
19+
</PageContentBlock>
20+
);
21+
};
22+
23+
export default StartupContainer;

0 commit comments

Comments
 (0)