Skip to content

Commit f8c89f8

Browse files
committed
Add support for seeding nests and eggs
1 parent 99aceac commit f8c89f8

21 files changed

+862
-18
lines changed

app/Http/Controllers/Admin/Nests/EggShareController.php

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,10 +69,12 @@ public function __construct(
6969
*/
7070
public function export(Egg $egg): Response
7171
{
72+
$filename = trim(preg_replace('/[^\w]/', '-', kebab_case($egg->name)), '-');
73+
7274
return response($this->exporterService->handle($egg->id), 200, [
7375
'Content-Transfer-Encoding' => 'binary',
7476
'Content-Description' => 'File Transfer',
75-
'Content-Disposition' => 'attachment; filename=egg-' . kebab_case($egg->name) . '.json',
77+
'Content-Disposition' => 'attachment; filename=egg-' . $filename . '.json',
7678
'Content-Type' => 'application/json',
7779
]);
7880
}

app/Services/Eggs/Sharing/EggImporterService.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ public function __construct(
7575
*/
7676
public function handle(UploadedFile $file, int $nest): Egg
7777
{
78-
if (! $file->isValid() || ! $file->isFile()) {
78+
if ($file->getError() !== UPLOAD_ERR_OK || ! $file->isFile()) {
7979
throw new InvalidFileUploadException(trans('exceptions.nest.importer.file_error'));
8080
}
8181

app/Services/Eggs/Sharing/EggUpdateImporterService.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ public function __construct(
5656
*/
5757
public function handle(int $egg, UploadedFile $file)
5858
{
59-
if (! $file->isValid() || ! $file->isFile()) {
59+
if ($file->getError() !== UPLOAD_ERR_OK || ! $file->isFile()) {
6060
throw new InvalidFileUploadException(trans('exceptions.nest.importer.file_error'));
6161
}
6262

database/seeds/DatabaseSeeder.php

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
<?php
22

33
use Illuminate\Database\Seeder;
4-
use Illuminate\Database\Eloquent\Model;
54

65
class DatabaseSeeder extends Seeder
76
{
@@ -10,8 +9,7 @@ class DatabaseSeeder extends Seeder
109
*/
1110
public function run()
1211
{
13-
Model::unguard();
14-
15-
Model::reguard();
12+
$this->call(NestSeeder::class);
13+
$this->call(EggSeeder::class);
1614
}
1715
}

database/seeds/EggSeeder.php

Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
<?php
2+
3+
use Pterodactyl\Models\Nest;
4+
use Illuminate\Database\Seeder;
5+
use Illuminate\Http\UploadedFile;
6+
use Illuminate\Support\Collection;
7+
use Illuminate\Filesystem\Filesystem;
8+
use Pterodactyl\Services\Eggs\Sharing\EggImporterService;
9+
use Pterodactyl\Contracts\Repository\EggRepositoryInterface;
10+
use Pterodactyl\Contracts\Repository\NestRepositoryInterface;
11+
use Pterodactyl\Exceptions\Repository\RecordNotFoundException;
12+
use Pterodactyl\Services\Eggs\Sharing\EggUpdateImporterService;
13+
14+
class EggSeeder extends Seeder
15+
{
16+
/**
17+
* @var \Illuminate\Filesystem\Filesystem
18+
*/
19+
private $filesystem;
20+
21+
/**
22+
* @var \Pterodactyl\Services\Eggs\Sharing\EggImporterService
23+
*/
24+
private $importerService;
25+
26+
/**
27+
* @var \Pterodactyl\Contracts\Repository\NestRepositoryInterface
28+
*/
29+
private $nestRepository;
30+
31+
/**
32+
* @var \Pterodactyl\Contracts\Repository\EggRepositoryInterface
33+
*/
34+
private $repository;
35+
36+
/**
37+
* @var \Pterodactyl\Services\Eggs\Sharing\EggUpdateImporterService
38+
*/
39+
private $updateImporterService;
40+
41+
/**
42+
* EggSeeder constructor.
43+
*
44+
* @param \Pterodactyl\Services\Eggs\Sharing\EggImporterService $importerService
45+
* @param \Pterodactyl\Contracts\Repository\EggRepositoryInterface $repository
46+
* @param \Pterodactyl\Services\Eggs\Sharing\EggUpdateImporterService $updateImporterService
47+
* @param \Illuminate\Filesystem\Filesystem $filesystem
48+
* @param \Pterodactyl\Contracts\Repository\NestRepositoryInterface $nestRepository
49+
*/
50+
public function __construct(
51+
EggImporterService $importerService,
52+
EggRepositoryInterface $repository,
53+
EggUpdateImporterService $updateImporterService,
54+
Filesystem $filesystem,
55+
NestRepositoryInterface $nestRepository
56+
) {
57+
$this->filesystem = $filesystem;
58+
$this->importerService = $importerService;
59+
$this->repository = $repository;
60+
$this->updateImporterService = $updateImporterService;
61+
$this->nestRepository = $nestRepository;
62+
}
63+
64+
/**
65+
* Run the egg seeder.
66+
*/
67+
public function run()
68+
{
69+
$this->getEggsToImport()->each(function ($nest) {
70+
$this->parseEggFiles($this->findMatchingNest($nest));
71+
});
72+
}
73+
74+
/**
75+
* Return a list of eggs to import.
76+
*
77+
* @return \Illuminate\Support\Collection
78+
*/
79+
protected function getEggsToImport(): Collection
80+
{
81+
return collect([
82+
'Minecraft',
83+
'Source Engine',
84+
'Voice Servers',
85+
]);
86+
}
87+
88+
/**
89+
* Find the nest that these eggs should be attached to.
90+
*
91+
* @param string $nestName
92+
* @return \Pterodactyl\Models\Nest
93+
*
94+
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
95+
*/
96+
private function findMatchingNest(string $nestName): Nest
97+
{
98+
return $this->nestRepository->findFirstWhere([
99+
['author', '=', 'support@pterodactyl.io'],
100+
['name', '=', $nestName],
101+
]);
102+
}
103+
104+
/**
105+
* Loop through the list of egg files and import them.
106+
*
107+
* @param \Pterodactyl\Models\Nest $nest
108+
*/
109+
private function parseEggFiles(Nest $nest)
110+
{
111+
$files = $this->filesystem->allFiles(database_path('seeds/eggs/' . kebab_case($nest->name)));
112+
113+
$this->command->alert('Updating Eggs for Nest: ' . $nest->name);
114+
collect($files)->each(function ($file) use ($nest) {
115+
/* @var \Symfony\Component\Finder\SplFileInfo $file */
116+
$decoded = json_decode($file->getContents());
117+
if (json_last_error() !== JSON_ERROR_NONE) {
118+
return $this->command->error('JSON decode exception for ' . $file->getFilename() . ': ' . json_last_error_msg());
119+
}
120+
121+
$file = new UploadedFile($file->getPathname(), $file->getFilename(), 'application/json', $file->getSize());
122+
123+
try {
124+
$egg = $this->repository->withColumns('id')->findFirstWhere([
125+
['author', '=', $decoded->author],
126+
['name', '=', $decoded->name],
127+
['nest_id', '=', $nest->id],
128+
]);
129+
130+
$this->updateImporterService->handle($egg->id, $file);
131+
132+
return $this->command->info('Updated ' . $decoded->name);
133+
} catch (RecordNotFoundException $exception) {
134+
$this->importerService->handle($file, $nest->id);
135+
136+
return $this->command->comment('Created ' . $decoded->name);
137+
}
138+
});
139+
140+
$this->command->line('');
141+
}
142+
}

database/seeds/NestSeeder.php

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
<?php
2+
3+
use Illuminate\Database\Seeder;
4+
use Pterodactyl\Services\Nests\NestCreationService;
5+
use Pterodactyl\Contracts\Repository\NestRepositoryInterface;
6+
7+
class NestSeeder extends Seeder
8+
{
9+
/**
10+
* @var \Pterodactyl\Services\Nests\NestCreationService
11+
*/
12+
private $creationService;
13+
14+
/**
15+
* @var \Pterodactyl\Contracts\Repository\NestRepositoryInterface
16+
*/
17+
private $repository;
18+
19+
/**
20+
* MinecraftNestSeeder constructor.
21+
*
22+
* @param \Pterodactyl\Services\Nests\NestCreationService $creationService
23+
* @param \Pterodactyl\Contracts\Repository\NestRepositoryInterface $repository
24+
*/
25+
public function __construct(
26+
NestCreationService $creationService,
27+
NestRepositoryInterface $repository
28+
) {
29+
$this->creationService = $creationService;
30+
$this->repository = $repository;
31+
}
32+
33+
/**
34+
* Run the seeder to add missing nests to the Panel.
35+
*
36+
* @throws \Pterodactyl\Exceptions\Model\DataValidationException
37+
*/
38+
public function run()
39+
{
40+
$items = $this->repository->findWhere([
41+
'author' => 'support@pterodactyl.io',
42+
])->keyBy('name')->toArray();
43+
44+
$this->createMinecraftNest(array_get($items, 'Minecraft'));
45+
$this->createSourceEngineNest(array_get($items, 'Source Engine'));
46+
$this->createVoiceServersNest(array_get($items, 'Voice Servers'));
47+
}
48+
49+
/**
50+
* Create the Minecraft nest to be used later on.
51+
*
52+
* @param array|null $nest
53+
*
54+
* @throws \Pterodactyl\Exceptions\Model\DataValidationException
55+
*/
56+
private function createMinecraftNest(array $nest = null)
57+
{
58+
if (is_null($nest)) {
59+
$this->creationService->handle([
60+
'name' => 'Minecraft',
61+
'description' => 'Minecraft - the classic game from Mojang. With support for Vanilla MC, Spigot, and many others!',
62+
]);
63+
}
64+
}
65+
66+
/**
67+
* Create the Source Engine Games nest to be used later on.
68+
*
69+
* @param array|null $nest
70+
*
71+
* @throws \Pterodactyl\Exceptions\Model\DataValidationException
72+
*/
73+
private function createSourceEngineNest(array $nest = null)
74+
{
75+
if (is_null($nest)) {
76+
$this->creationService->handle([
77+
'name' => 'Source Engine',
78+
'description' => 'Includes support for most Source Dedicated Server games.',
79+
]);
80+
}
81+
}
82+
83+
/**
84+
* Create the Source Engine Games nest to be used later on.
85+
*
86+
* @param array|null $nest
87+
*
88+
* @throws \Pterodactyl\Exceptions\Model\DataValidationException
89+
*/
90+
private function createVoiceServersNest(array $nest = null)
91+
{
92+
if (is_null($nest)) {
93+
$this->creationService->handle([
94+
'name' => 'Voice Servers',
95+
'description' => 'Voice servers such as Mumble and Teamspeak 3.',
96+
]);
97+
}
98+
}
99+
}
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
{
2+
"_comment": "DO NOT EDIT: FILE GENERATED AUTOMATICALLY BY PTERODACTYL PANEL - PTERODACTYL.IO",
3+
"meta": {
4+
"version": "PTDL_v1"
5+
},
6+
"exported_at": "2017-11-03T22:15:10-05:00",
7+
"name": "Bungeecord",
8+
"author": "support@pterodactyl.io",
9+
"description": "For a long time, Minecraft server owners have had a dream that encompasses a free, easy, and reliable way to connect multiple Minecraft servers together. BungeeCord is the answer to said dream. Whether you are a small server wishing to string multiple game-modes together, or the owner of the ShotBow Network, BungeeCord is the ideal solution for you. With the help of BungeeCord, you will be able to unlock your community's full potential.",
10+
"image": "quay.io\/pterodactyl\/core:java",
11+
"startup": "java -Xms128M -Xmx{{SERVER_MEMORY}}M -jar {{SERVER_JARFILE}}",
12+
"config": {
13+
"files": "{\r\n \"config.yml\": {\r\n \"parser\": \"yaml\",\r\n \"find\": {\r\n \"listeners[0].query_enabled\": true,\r\n \"listeners[0].query_port\": \"{{server.build.default.port}}\",\r\n \"listeners[0].host\": \"0.0.0.0:{{server.build.default.port}}\",\r\n \"servers.*.address\": {\r\n \"127.0.0.1\": \"{{config.docker.interface}}\",\r\n \"localhost\": \"{{config.docker.interface}}\"\r\n }\r\n }\r\n }\r\n}",
14+
"startup": "{\r\n \"done\": \"Listening on \",\r\n \"userInteraction\": [\r\n \"Listening on \/0.0.0.0:25577\"\r\n ]\r\n}",
15+
"logs": "{\r\n \"custom\": false,\r\n \"location\": \"proxy.log.0\"\r\n}",
16+
"stop": "end"
17+
},
18+
"scripts": {
19+
"installation": {
20+
"script": "#!\/bin\/ash\n# Bungeecord Installation Script\n#\n# Server Files: \/mnt\/server\napk update\napk add curl\n\ncd \/mnt\/server\n\nif [ -z \"${BUNGEE_VERSION}\" ] || [ \"${BUNGEE_VERSION}\" == \"latest\" ]; then\n BUNGEE_VERSION=\"lastStableBuild\"\nfi\n\ncurl -o ${SERVER_JARFILE} https:\/\/ci.md-5.net\/job\/BungeeCord\/${BUNGEE_VERSION}\/artifact\/bootstrap\/target\/BungeeCord.jar",
21+
"container": "alpine:3.4",
22+
"entrypoint": "ash"
23+
}
24+
},
25+
"variables": [
26+
{
27+
"name": "Bungeecord Version",
28+
"description": "The version of Bungeecord to download and use.",
29+
"env_variable": "BUNGEE_VERSION",
30+
"default_value": "latest",
31+
"user_viewable": 1,
32+
"user_editable": 1,
33+
"rules": "required|alpha_num|between:1,6"
34+
},
35+
{
36+
"name": "Bungeecord Jar File",
37+
"description": "The name of the Jarfile to use when running Bungeecord.",
38+
"env_variable": "SERVER_JARFILE",
39+
"default_value": "bungeecord.jar",
40+
"user_viewable": 1,
41+
"user_editable": 1,
42+
"rules": "required|regex:\/^([\\w\\d._-]+)(\\.jar)$\/"
43+
}
44+
]
45+
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
{
2+
"_comment": "DO NOT EDIT: FILE GENERATED AUTOMATICALLY BY PTERODACTYL PANEL - PTERODACTYL.IO",
3+
"meta": {
4+
"version": "PTDL_v1"
5+
},
6+
"exported_at": "2017-11-03T22:15:10-05:00",
7+
"name": "Forge Minecraft",
8+
"author": "support@pterodactyl.io",
9+
"description": "Minecraft Forge Server. Minecraft Forge is a modding API (Application Programming Interface), which makes it easier to create mods, and also make sure mods are compatible with each other.",
10+
"image": "quay.io\/pterodactyl\/core:java",
11+
"startup": "java -Xms128M -Xmx{{SERVER_MEMORY}}M -jar {{SERVER_JARFILE}}",
12+
"config": {
13+
"files": "{\r\n \"server.properties\": {\r\n \"parser\": \"properties\",\r\n \"find\": {\r\n \"server-ip\": \"0.0.0.0\",\r\n \"enable-query\": \"true\",\r\n \"server-port\": \"{{server.build.default.port}}\",\r\n \"query.port\": \"{{server.build.default.port}}\"\r\n }\r\n }\r\n}",
14+
"startup": "{\r\n \"done\": \")! For help, type \",\r\n \"userInteraction\": [\r\n \"Go to eula.txt for more info.\"\r\n ]\r\n}",
15+
"logs": "{\r\n \"custom\": false,\r\n \"location\": \"logs\/latest.log\"\r\n}",
16+
"stop": "stop"
17+
},
18+
"scripts": {
19+
"installation": {
20+
"script": "#!\/bin\/ash\n# Forge Installation Script\n#\n# Server Files: \/mnt\/server\napk update\napk add curl\n\nGET_VERSIONS=$(curl -sl http:\/\/files.minecraftforge.net\/maven\/net\/minecraftforge\/forge\/ | grep -A1 Latest | grep -o -e '[1]\\.[0-9][0-9] - [0-9][0-9]\\.[0-9][0-9]\\.[0-9]\\.[0-9][0-9][0-9][0-9]')\nLATEST_VERSION=$(echo $GET_VERSIONS | sed 's\/ \/\/g')\n\ncd \/mnt\/server\n\ncurl -sS http:\/\/files.minecraftforge.net\/maven\/net\/minecraftforge\/forge\/$LATEST_VERSION\/forge-$LATEST_VERSION-installer.jar -o installer.jar\ncurl -sS http:\/\/files.minecraftforge.net\/maven\/net\/minecraftforge\/forge\/$LATEST_VERSION\/forge-$LATEST_VERSION-universal.jar -o server.jar\n\njava -jar installer.jar --installServer\nrm -rf installer.jar",
21+
"container": "frolvlad\/alpine-oraclejdk8:cleaned",
22+
"entrypoint": "ash"
23+
}
24+
},
25+
"variables": [
26+
{
27+
"name": "Server Jar File",
28+
"description": "The name of the Jarfile to use when running Forge Mod.",
29+
"env_variable": "SERVER_JARFILE",
30+
"default_value": "server.jar",
31+
"user_viewable": 1,
32+
"user_editable": 1,
33+
"rules": "required|regex:\/^([\\w\\d._-]+)(\\.jar)$\/"
34+
}
35+
]
36+
}

0 commit comments

Comments
 (0)