Skip to content

Commit 17796fb

Browse files
committed
Add basic database listing for server
1 parent 04f56ff commit 17796fb

File tree

13 files changed

+255
-23
lines changed

13 files changed

+255
-23
lines changed
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
<?php
2+
3+
namespace Pterodactyl\Http\Controllers\Api\Client\Servers;
4+
5+
use Pterodactyl\Models\Server;
6+
use Pterodactyl\Transformers\Api\Client\DatabaseTransformer;
7+
use Pterodactyl\Http\Controllers\Api\Client\ClientApiController;
8+
use Pterodactyl\Contracts\Repository\DatabaseRepositoryInterface;
9+
use Pterodactyl\Http\Requests\Api\Client\Servers\GetDatabasesRequest;
10+
11+
class DatabaseController extends ClientApiController
12+
{
13+
/**
14+
* @var \Pterodactyl\Contracts\Repository\DatabaseRepositoryInterface
15+
*/
16+
private $repository;
17+
18+
/**
19+
* DatabaseController constructor.
20+
*
21+
* @param \Pterodactyl\Contracts\Repository\DatabaseRepositoryInterface $repository
22+
*/
23+
public function __construct(DatabaseRepositoryInterface $repository)
24+
{
25+
parent::__construct();
26+
27+
$this->repository = $repository;
28+
}
29+
30+
/**
31+
* @param \Pterodactyl\Http\Requests\Api\Client\Servers\GetDatabasesRequest $request
32+
* @return array
33+
*/
34+
public function index(GetDatabasesRequest $request): array
35+
{
36+
$databases = $this->repository->getDatabasesForServer($request->getModel(Server::class)->id);
37+
38+
return $this->fractal->collection($databases)
39+
->transformWith($this->getTransformer(DatabaseTransformer::class))
40+
->toArray();
41+
}
42+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
<?php
2+
3+
namespace Pterodactyl\Http\Requests\Api\Client\Servers;
4+
5+
use Pterodactyl\Models\Server;
6+
use Pterodactyl\Http\Requests\Api\Client\ClientApiRequest;
7+
8+
class GetDatabasesRequest extends ClientApiRequest
9+
{
10+
/**
11+
* Determine if this user has permission to view all of the databases available
12+
* to this server.
13+
*
14+
* @return bool
15+
*/
16+
public function authorize(): bool
17+
{
18+
return $this->user()->can('view-databases', $this->getModel(Server::class));
19+
}
20+
}

app/Repositories/Eloquent/DatabaseRepository.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ public function getConnection(): string
7676
*/
7777
public function getDatabasesForServer(int $server): Collection
7878
{
79-
return $this->getBuilder()->where('server_id', $server)->get($this->getColumns());
79+
return $this->getBuilder()->with('host')->where('server_id', $server)->get($this->getColumns());
8080
}
8181

8282
/**
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
<?php
2+
3+
namespace Pterodactyl\Transformers\Api\Client;
4+
5+
use Pterodactyl\Models\Database;
6+
use League\Fractal\Resource\Item;
7+
use Illuminate\Contracts\Encryption\Encrypter;
8+
9+
class DatabaseTransformer extends BaseClientTransformer
10+
{
11+
protected $availableIncludes = ['password'];
12+
13+
/**
14+
* @var \Illuminate\Contracts\Encryption\Encrypter
15+
*/
16+
private $encrypter;
17+
18+
/**
19+
* Handle dependency injection.
20+
*
21+
* @param \Illuminate\Contracts\Encryption\Encrypter $encrypter
22+
*/
23+
public function handle(Encrypter $encrypter)
24+
{
25+
$this->encrypter = $encrypter;
26+
}
27+
28+
/**
29+
* @return string
30+
*/
31+
public function getResourceName(): string
32+
{
33+
return Database::RESOURCE_NAME;
34+
}
35+
36+
/**
37+
* @param \Pterodactyl\Models\Database $model
38+
* @return array
39+
*/
40+
public function transform(Database $model): array
41+
{
42+
$model->loadMissing('host');
43+
44+
return [
45+
'host' => [
46+
'address' => $model->getRelation('host')->host,
47+
'port' => $model->getRelation('host')->port,
48+
],
49+
'name' => $model->database,
50+
'username' => $model->username,
51+
'connections_from' => $model->remote,
52+
];
53+
}
54+
55+
/**
56+
* Include the database password in the request.
57+
*
58+
* @param \Pterodactyl\Models\Database $model
59+
* @return \League\Fractal\Resource\Item
60+
*/
61+
public function includePassword(Database $model): Item
62+
{
63+
return $this->item($model, function (Database $model) {
64+
return [
65+
'password' => $this->encrypter->decrypt($model->password),
66+
];
67+
}, 'database_password');
68+
}
69+
}

resources/assets/scripts/components/server/Server.vue

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -51,9 +51,7 @@
5151
</div>
5252
</div>
5353
-->
54-
<div class="bg-white p-6 rounded border border-grey-light">
55-
<router-view></router-view>
56-
</div>
54+
<router-view></router-view>
5755
</div>
5856
</div>
5957
</div>

resources/assets/scripts/components/server/ServerDatabases.vue

Lines changed: 0 additions & 13 deletions
This file was deleted.

resources/assets/scripts/components/server/index.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
export {default as Server} from './Server';
22
export {default as ServerAllocations} from './ServerAllocations';
33
export {default as ConsolePage} from './subpages/Console';
4-
export {default as ServerDatabases} from './ServerDatabases';
4+
export {default as DatabasesPage} from './subpages/Databases';
55
export {default as FileManagerPage} from './subpages/FileManager';
66
export {default as ServerSchedules} from './ServerSchedules';
77
export {default as ServerSettings} from './ServerSettings';

resources/assets/scripts/components/server/subpages/Console.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<template>
2-
<div>
2+
<div class="bg-white p-6 rounded border border-grey-light">
33
<div class="text-xs font-mono">
44
<div class="rounded-t p-2 bg-black overflow-scroll w-full" style="min-height: 16rem;max-height:64rem;">
55
<div class="mb-2 text-grey-light" ref="terminal" v-if="connected"></div>
Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
<template>
2+
<div>
3+
<div v-if="loading">
4+
<div class="spinner spinner-xl blue"></div>
5+
</div>
6+
<div class="bg-white p-6 rounded border border-grey-light" v-else-if="!databases.length">
7+
<div class="flex items-center">
8+
<database-icon class="flex-none text-grey-darker"></database-icon>
9+
<div class="flex-1 px-4 text-grey-darker">
10+
<p>You have no databases.</p>
11+
</div>
12+
</div>
13+
</div>
14+
<div v-else>
15+
<div class="bg-white p-6 rounded border border-grey-light mb-6" v-for="database in databases" :key="database.name">
16+
<div class="flex items-center text-grey-darker">
17+
<database-icon class="flex-none text-green"></database-icon>
18+
<div class="flex-1 px-4">
19+
<p class="uppercase text-xs text-grey pb-1 select-none">Database Name</p>
20+
<p>{{database.name}}</p>
21+
</div>
22+
<div class="flex-1 px-4">
23+
<p class="uppercase text-xs text-grey pb-1 select-none">Username</p>
24+
<p>{{database.username}}</p>
25+
</div>
26+
<div class="flex-1 px-4">
27+
<p class="uppercase text-xs text-grey pb-1 select-none">Password</p>
28+
<p>
29+
<code class="text-sm cursor-pointer" v-on:click="revealPassword(database)">
30+
<span class="select-none" v-if="!database.showPassword">
31+
<lock-icon class="h-3"/> &bull;&bull;&bull;&bull;&bull;&bull;
32+
</span>
33+
<span v-else>{{database.password}}</span>
34+
</code>
35+
</p>
36+
</div>
37+
<div class="flex-1 px-4">
38+
<p class="uppercase text-xs text-grey pb-1 select-none">Server</p>
39+
<p><code class="text-sm">{{database.host.address}}:{{database.host.port}}</code></p>
40+
</div>
41+
</div>
42+
</div>
43+
</div>
44+
</div>
45+
</template>
46+
47+
<script>
48+
import { DatabaseIcon, LockIcon } from 'vue-feather-icons';
49+
import map from 'lodash/map';
50+
51+
export default {
52+
name: 'databases-page',
53+
components: { DatabaseIcon, LockIcon },
54+
55+
data: function () {
56+
return {
57+
loading: true,
58+
databases: [],
59+
};
60+
},
61+
62+
mounted: function () {
63+
this.getDatabases();
64+
},
65+
66+
methods: {
67+
/**
68+
* Get all of the databases that exist for this server.
69+
*/
70+
getDatabases: function () {
71+
this.clearFlashes();
72+
this.loading = true;
73+
74+
window.axios.get(this.route('api.client.servers.databases', {
75+
server: this.$route.params.id,
76+
include: 'password'
77+
}))
78+
.then(response => {
79+
this.databases = map(response.data.data, (object) => {
80+
const data = object.attributes;
81+
82+
data.password = data.relationships.password.attributes.password;
83+
data.showPassword = false;
84+
delete data.relationships;
85+
86+
return data;
87+
});
88+
})
89+
.catch(err => {
90+
this.error('There was an error encountered while attempting to fetch databases for this server.');
91+
console.error(err);
92+
})
93+
.then(() => {
94+
this.loading = false;
95+
});
96+
},
97+
98+
/**
99+
* Show the password for a given database object.
100+
*
101+
* @param {Object} database
102+
*/
103+
revealPassword: function (database) {
104+
this.databases.forEach((d) => {
105+
d.showPassword = d === database ? d.showPassword : false;
106+
});
107+
108+
database.showPassword = !database.showPassword;
109+
},
110+
}
111+
};
112+
</script>

resources/assets/scripts/components/server/subpages/FileManager.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<template>
2-
<div>
2+
<div class="bg-white p-6 rounded border border-grey-light">
33
<div class="filemanager-breadcrumbs">
44
/<span class="px-1">home</span><!--
55
-->/<router-link :to="{ name: 'server-files' }" class="px-1">container</router-link><!--

0 commit comments

Comments
 (0)