More model updates to more places than I anticipated.

This probably broke a lot of things.
This commit is contained in:
Dane Everitt 2017-02-09 17:43:54 -05:00
parent 0d61417814
commit 4f61637284
No known key found for this signature in database
GPG key ID: EEA66103B3D71F53
21 changed files with 339 additions and 433 deletions

View file

@ -97,7 +97,7 @@ class LocationsController extends Controller
{ {
try { try {
$location = new LocationRepository; $location = new LocationRepository;
$id = $location->create($request->only(['long', 'short'])); $location->create($request->only(['long', 'short']));
Alert::success('New location successfully added.')->flash(); Alert::success('New location successfully added.')->flash();
return redirect()->route('admin.locations'); return redirect()->route('admin.locations');

View file

@ -47,63 +47,8 @@ class ServersController extends Controller
public function getIndex(Request $request) public function getIndex(Request $request)
{ {
$query = Models\Server::withTrashed()->select(
'servers.*',
'nodes.name as a_nodeName',
'users.email as a_ownerEmail',
'allocations.ip',
'allocations.port',
'allocations.ip_alias'
)->join('nodes', 'servers.node_id', '=', 'nodes.id')
->join('users', 'servers.owner_id', '=', 'users.id')
->join('allocations', 'servers.allocation_id', '=', 'allocations.id');
if ($request->input('filter') && ! is_null($request->input('filter'))) {
preg_match_all('/[^\s"\']+|"([^"]*)"|\'([^\']*)\'/', urldecode($request->input('filter')), $matches);
foreach ($matches[0] as $match) {
$match = str_replace('"', '', $match);
if (strpos($match, ':')) {
list($field, $term) = explode(':', $match);
if ($field === 'node') {
$field = 'nodes.name';
} elseif ($field === 'owner') {
$field = 'users.email';
} elseif (! strpos($field, '.')) {
$field = 'servers.' . $field;
}
$query->orWhere($field, 'LIKE', '%' . $term . '%');
} else {
$query->where('servers.name', 'LIKE', '%' . $match . '%');
$query->orWhere([
['servers.username', 'LIKE', '%' . $match . '%'],
['users.email', 'LIKE', '%' . $match . '%'],
['allocations.port', 'LIKE', '%' . $match . '%'],
['allocations.ip', 'LIKE', '%' . $match . '%'],
]);
}
}
}
try {
$servers = $query->paginate(20);
} catch (\Exception $ex) {
Alert::warning('There was an error with the search parameters provided.');
$servers = Models\Server::withTrashed()->select(
'servers.*',
'nodes.name as a_nodeName',
'users.email as a_ownerEmail',
'allocations.ip',
'allocations.port',
'allocations.ip_alias'
)->join('nodes', 'servers.node_id', '=', 'nodes.id')
->join('users', 'servers.owner_id', '=', 'users.id')
->join('allocations', 'servers.allocation_id', '=', 'allocations.id')
->paginate(20);
}
return view('admin.servers.index', [ return view('admin.servers.index', [
'servers' => $servers, 'servers' => Models\Server::withTrashed()->with('node', 'user')->paginate(25),
]); ]);
} }
@ -117,47 +62,22 @@ class ServersController extends Controller
public function getView(Request $request, $id) public function getView(Request $request, $id)
{ {
$server = Models\Server::withTrashed()->select(
'servers.*',
'users.email as a_ownerEmail',
'services.name as a_serviceName',
DB::raw('IFNULL(service_options.executable, services.executable) as a_serviceExecutable'),
'service_options.docker_image',
'service_options.name as a_servceOptionName',
'allocations.ip',
'allocations.port',
'allocations.ip_alias'
)->join('nodes', 'servers.node_id', '=', 'nodes.id')
->join('users', 'servers.owner_id', '=', 'users.id')
->join('services', 'servers.service_id', '=', 'services.id')
->join('service_options', 'servers.option_id', '=', 'service_options.id')
->join('allocations', 'servers.allocation_id', '=', 'allocations.id')
->where('servers.id', $id)
->first();
if (! $server) { $server = Models\Server::withTrashed()->with(
return abort(404); 'user', 'option.variables', 'variables',
} 'node.allocations', 'databases.host'
)->findOrFail($id);
$server->option->variables->transform(function ($item, $key) use ($server) {
$item->server_value = $server->variables->where('variable_id', $item->id)->pluck('variable_value')->first();
return $item;
});
return view('admin.servers.view', [ return view('admin.servers.view', [
'server' => $server, 'server' => $server,
'node' => Models\Node::select( 'assigned' => $server->node->allocations->where('server_id', $server->id)->sortBy('port')->sortBy('ip'),
'nodes.*', 'unassigned' => $server->node->allocations->where('server_id', null)->sortBy('port')->sortBy('ip'),
'locations.long as a_locationName'
)->join('locations', 'nodes.location', '=', 'locations.id')
->where('nodes.id', $server->node_id)
->first(),
'assigned' => Models\Allocation::where('assigned_to', $id)->orderBy('ip', 'asc')->orderBy('port', 'asc')->get(),
'unassigned' => Models\Allocation::where('node', $server->node_id)->whereNull('assigned_to')->orderBy('ip', 'asc')->orderBy('port', 'asc')->get(),
'startup' => Models\ServiceVariables::select('service_variables.*', 'server_variables.variable_value as a_serverValue')
->join('server_variables', 'server_variables.variable_id', '=', 'service_variables.id')
->where('service_variables.option_id', $server->option_id)
->where('server_variables.server_id', $server->id)
->get(),
'databases' => Models\Database::select('databases.*', 'database_servers.host as a_host', 'database_servers.port as a_port')
->where('server_id', $server->id)
->join('database_servers', 'database_servers.id', '=', 'databases.db_server')
->get(),
'db_servers' => Models\DatabaseServer::all(), 'db_servers' => Models\DatabaseServer::all(),
]); ]);
} }
@ -166,7 +86,14 @@ class ServersController extends Controller
{ {
try { try {
$server = new ServerRepository; $server = new ServerRepository;
$response = $server->create($request->all()); $response = $server->create($request->only([
'owner', 'name', 'memory', 'swap',
'node', 'ip', 'port', 'allocation',
'cpu', 'disk', 'service',
'option', 'location', 'pack',
'startup', 'custom_image_name',
'auto_deploy', 'custom_id',
]));
return redirect()->route('admin.servers.view', ['id' => $response]); return redirect()->route('admin.servers.view', ['id' => $response]);
} catch (DisplayValidationException $ex) { } catch (DisplayValidationException $ex) {
@ -261,18 +188,15 @@ class ServersController extends Controller
], 500); ], 500);
} }
$option = Models\ServiceOptions::select( $option = Models\ServiceOptions::with('variables', ['packs' => function ($query) {
DB::raw('COALESCE(service_options.executable, services.executable) as executable'), $query->where('selectable', true);
DB::raw('COALESCE(service_options.startup, services.startup) as startup') }])->findOrFail($request->input('option'));
)->leftJoin('services', 'services.id', '=', 'service_options.service_id')
->where('service_options.id', $request->input('option'))
->first();
return response()->json([ return response()->json([
'packs' => Models\ServicePack::select('id', 'name', 'version')->where('option', $request->input('option'))->where('selectable', true)->get(), 'packs' => $option->packs,
'variables' => Models\ServiceVariables::where('option_id', $request->input('option'))->get(), 'variables' => $option->variables,
'exec' => $option->executable, 'exec' => $option->display_executable,
'startup' => $option->startup, 'startup' => $option->display_startup,
]); ]);
} }
@ -309,9 +233,7 @@ class ServersController extends Controller
{ {
try { try {
$server = new ServerRepository; $server = new ServerRepository;
$server->updateContainer($id, [ $server->updateContainer($id, ['image' => $request->input('docker_image')]);
'image' => $request->input('docker_image'),
]);
Alert::success('Successfully updated this server\'s docker image.')->flash(); Alert::success('Successfully updated this server\'s docker image.')->flash();
} catch (DisplayValidationException $ex) { } catch (DisplayValidationException $ex) {
return redirect()->route('admin.servers.view', [ return redirect()->route('admin.servers.view', [
@ -333,17 +255,13 @@ class ServersController extends Controller
public function postUpdateServerToggleBuild(Request $request, $id) public function postUpdateServerToggleBuild(Request $request, $id)
{ {
$server = Models\Server::findOrFail($id); $server = Models\Server::with('node')->findOrFail($id);
$node = Models\Node::findOrFail($server->node_id);
$client = Models\Node::guzzleRequest($server->node_id);
try { try {
$res = $client->request('POST', '/server/rebuild', [ $res = $server->node->guzzleClient([
'headers' => [
'X-Access-Server' => $server->uuid, 'X-Access-Server' => $server->uuid,
'X-Access-Token' => $node->daemonSecret, 'X-Access-Token' => $node->daemonSecret,
], ])->request('POST', '/server/rebuild');
]);
Alert::success('A rebuild has been queued successfully. It will run the next time this server is booted.')->flash(); Alert::success('A rebuild has been queued successfully. It will run the next time this server is booted.')->flash();
} catch (\GuzzleHttp\Exception\TransferException $ex) { } catch (\GuzzleHttp\Exception\TransferException $ex) {
Log::warning($ex); Log::warning($ex);
@ -360,15 +278,15 @@ class ServersController extends Controller
{ {
try { try {
$server = new ServerRepository; $server = new ServerRepository;
$server->changeBuild($id, [ $server->changeBuild($id, $request->only([
'default' => $request->input('default'), 'default',
'add_additional' => $request->input('add_additional'), 'add_additional',
'remove_additional' => $request->input('remove_additional'), 'remove_additional',
'memory' => $request->input('memory'), 'memory',
'swap' => $request->input('swap'), 'swap',
'io' => $request->input('io'), 'io',
'cpu' => $request->input('cpu'), 'cpu',
]); ]));
Alert::success('Server details were successfully updated.')->flash(); Alert::success('Server details were successfully updated.')->flash();
} catch (DisplayValidationException $ex) { } catch (DisplayValidationException $ex) {
return redirect()->route('admin.servers.view', [ return redirect()->route('admin.servers.view', [
@ -458,8 +376,10 @@ class ServersController extends Controller
{ {
try { try {
$repo = new DatabaseRepository; $repo = new DatabaseRepository;
$repo->create($id, $request->except([ $repo->create($id, $request->only([
'_token', 'db_server',
'database',
'remote',
])); ]));
Alert::success('Added new database to this server.')->flash(); Alert::success('Added new database to this server.')->flash();
} catch (DisplayValidationException $ex) { } catch (DisplayValidationException $ex) {

View file

@ -45,35 +45,11 @@ class UserController extends Controller
// //
} }
// @TODO: implement nicolaslopezj/searchable to clean up this disaster.
public function getIndex(Request $request) public function getIndex(Request $request)
{ {
$query = User::select('users.*');
if ($request->input('filter') && ! is_null($request->input('filter'))) {
preg_match_all('/[^\s"\']+|"([^"]*)"|\'([^\']*)\'/', urldecode($request->input('filter')), $matches);
foreach ($matches[0] as $match) {
$match = str_replace('"', '', $match);
if (strpos($match, ':')) {
list($field, $term) = explode(':', $match);
$query->orWhere($field, 'LIKE', '%' . $term . '%');
} else {
$query->where('email', 'LIKE', '%' . $match . '%');
$query->orWhere([
['uuid', 'LIKE', '%' . $match . '%'],
['root_admin', 'LIKE', '%' . $match . '%'],
]);
}
}
}
try {
$users = $query->paginate(20);
} catch (\Exception $ex) {
Alert::warning('There was an error with the search parameters provided.');
$users = User::all()->paginate(20);
}
return view('admin.users.index', [ return view('admin.users.index', [
'users' => $users, 'users' => User::paginate(25),
]); ]);
} }
@ -85,12 +61,7 @@ class UserController extends Controller
public function getView(Request $request, $id) public function getView(Request $request, $id)
{ {
return view('admin.users.view', [ return view('admin.users.view', [
'user' => User::findOrFail($id), 'user' => User::with('servers.node')->findOrFail($id),
'servers' => Server::select('servers.*', 'nodes.name as nodeName', 'locations.long as location')
->join('nodes', 'servers.node_id', '=', 'nodes.id')
->join('locations', 'nodes.location', '=', 'locations.id')
->where('owner', $id)
->get(),
]); ]);
} }
@ -162,10 +133,6 @@ class UserController extends Controller
public function getJson(Request $request) public function getJson(Request $request)
{ {
foreach (User::select('email')->get() as $user) { return User::select('email')->get()->pluck('email');
$resp[] = $user->email;
}
return $resp;
} }
} }

View file

@ -156,14 +156,14 @@ class SubuserController extends Controller
try { try {
$repo = new SubuserRepository; $repo = new SubuserRepository;
$id = $repo->create($server->id, $request->except([ $subuser = $repo->create($server->id, $request->only([
'_token', 'permissions', 'email',
])); ]));
Alert::success('Successfully created new subuser.')->flash(); Alert::success('Successfully created new subuser.')->flash();
return redirect()->route('server.subusers.view', [ return redirect()->route('server.subusers.view', [
'uuid' => $uuid, 'uuid' => $uuid,
'id' => md5($id), 'id' => md5($subuser->id),
]); ]);
} catch (DisplayValidationException $ex) { } catch (DisplayValidationException $ex) {
return redirect()->route('server.subusers.new', $uuid)->withErrors(json_decode($ex->getMessage()))->withInput(); return redirect()->route('server.subusers.new', $uuid)->withErrors(json_decode($ex->getMessage()))->withInput();

View file

@ -63,4 +63,15 @@ class Allocation extends Model
{ {
return (is_null($this->ip_alias)) ? $this->ip : $this->ip_alias; return (is_null($this->ip_alias)) ? $this->ip : $this->ip_alias;
} }
/**
* Accessor to quickly determine if this allocation has an alias.
*
* @param null|string $value
* @return boolean
*/
public function getHasAliasAttribute($value)
{
return (! is_null($this->ip_alias));
}
} }

View file

@ -69,4 +69,14 @@ class DatabaseServer extends Model
{ {
return $this->belongsTo(Node::class, 'linked_node'); return $this->belongsTo(Node::class, 'linked_node');
} }
/**
* Gets the databases assocaited with this host.
*
* @return \Illuminate\Database\Eloquent\Relations\HasMany
*/
public function databases()
{
return $this->hasMany(Database::class, 'db_server');
}
} }

View file

@ -122,6 +122,7 @@ class Node extends Model
/** /**
* Return an instance of the Guzzle client for this specific node. * Return an instance of the Guzzle client for this specific node.
* *
* @param array $headers
* @return \GuzzleHttp\Client * @return \GuzzleHttp\Client
*/ */
public function guzzleClient($headers = []) public function guzzleClient($headers = [])

View file

@ -276,4 +276,14 @@ class Server extends Model
{ {
return $this->hasMany(Task::class, 'server', 'id'); return $this->hasMany(Task::class, 'server', 'id');
} }
/**
* Gets all databases associated with a server.
*
* @return \Illuminate\Database\Eloquent\Relations\HasMany
*/
public function databases()
{
return $this->hasMany(Database::class);
}
} }

View file

@ -51,4 +51,14 @@ class ServerVariables extends Model
'server_id' => 'integer', 'server_id' => 'integer',
'variable_id' => 'integer', 'variable_id' => 'integer',
]; ];
/**
* Returns information about a given variables parent.
*
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
*/
public function variable()
{
return $this->belongsTo(ServiceVariables::class, 'variable_id');
}
} }

View file

@ -51,6 +51,28 @@ class ServiceOptions extends Model
'service_id' => 'integer', 'service_id' => 'integer',
]; ];
/**
* Returns the display executable for the option and will use the parent
* service one if the option does not have one defined.
*
* @return string
*/
public function getDisplayExecutableAttribute($value)
{
return (is_null($this->executable)) ? $this->service->executable : $this->executable;
}
/**
* Returns the display startup string for the option and will use the parent
* service one if the option does not have one defined.
*
* @return string
*/
public function getDisplayStartupAttribute($value)
{
return (is_null($this->startup)) ? $this->service->startup : $this->startup;
}
/** /**
* Gets service associated with a service option. * Gets service associated with a service option.
* *

View file

@ -59,4 +59,24 @@ class Subuser extends Model
'user_id' => 'integer', 'user_id' => 'integer',
'server_id' => 'integer', 'server_id' => 'integer',
]; ];
/**
* Gets the server associated with a subuser.
*
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
*/
public function server()
{
return $this->belongsTo(Server::class);
}
/**
* Gets the user associated with a subuser.
*
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
*/
public function user()
{
return $this->belongsTo(User::class);
}
} }

View file

@ -167,16 +167,6 @@ class User extends Model implements AuthenticatableContract, AuthorizableContrac
return $subuser->daemonSecret; return $subuser->daemonSecret;
} }
/**
* Returns all permissions that a user has.
*
* @return \Illuminate\Database\Eloquent\Relations\HasMany
*/
public function permissions()
{
return $this->hasMany(Permission::class);
}
/** /**
* Returns an array of all servers a user is able to access. * Returns an array of all servers a user is able to access.
* Note: does not account for user admin status. * Note: does not account for user admin status.
@ -205,4 +195,24 @@ class User extends Model implements AuthenticatableContract, AuthorizableContrac
return (is_numeric($paginate)) ? $query->paginate($paginate) : $query->get(); return (is_numeric($paginate)) ? $query->paginate($paginate) : $query->get();
} }
/**
* Returns all permissions that a user has.
*
* @return \Illuminate\Database\Eloquent\Relations\HasMany
*/
public function permissions()
{
return $this->hasMany(Permission::class);
}
/**
* Returns all servers that a user owns.
*
* @return \Illuminate\Database\Eloquent\Relations\HasMany
*/
public function servers()
{
return $this->hasMany(Server::class, 'owner_id');
}
} }

View file

@ -114,28 +114,27 @@ class DatabaseRepository
/** /**
* Updates the password for a given database. * Updates the password for a given database.
* @param int $database The ID of the database to modify. * @param int $id The ID of the database to modify.
* @param string $password The new password to use for the database. * @param string $password The new password to use for the database.
* @return bool * @return bool
*/ */
public function modifyPassword($database, $password) public function modifyPassword($id, $password)
{ {
$db = Models\Database::findOrFail($database); $database = Models\Database::with('host')->findOrFail($id);
$dbr = Models\DatabaseServer::findOrFail($db->db_server);
DB::beginTransaction(); DB::beginTransaction();
try { try {
$db->password = Crypt::encrypt($password); $database->password = Crypt::encrypt($password);
$db->save(); $database->save();
$capsule = new Capsule; $capsule = new Capsule;
$capsule->addConnection([ $capsule->addConnection([
'driver' => 'mysql', 'driver' => 'mysql',
'host' => $dbr->host, 'host' => $database->host->host,
'port' => $dbr->port, 'port' => $database->host->port,
'database' => 'mysql', 'database' => 'mysql',
'username' => $dbr->username, 'username' => $database->host->username,
'password' => Crypt::decrypt($dbr->password), 'password' => Crypt::decrypt($database->host->password),
'charset' => 'utf8', 'charset' => 'utf8',
'collation' => 'utf8_unicode_ci', 'collation' => 'utf8_unicode_ci',
'prefix' => '', 'prefix' => '',
@ -147,8 +146,8 @@ class DatabaseRepository
$capsule->setAsGlobal(); $capsule->setAsGlobal();
Capsule::statement(sprintf( Capsule::statement(sprintf(
'SET PASSWORD FOR `%s`@`%s` = PASSWORD(\'%s\')', 'SET PASSWORD FOR `%s`@`%s` = PASSWORD(\'%s\')',
$db->username, $database->username,
$db->remote, $database->remote,
$password $password
)); ));
@ -161,13 +160,12 @@ class DatabaseRepository
/** /**
* Drops a database from the associated MySQL Server. * Drops a database from the associated MySQL Server.
* @param int $database The ID of the database to drop. * @param int $id The ID of the database to drop.
* @return bool * @return bool
*/ */
public function drop($database) public function drop($id)
{ {
$db = Models\Database::findOrFail($database); $database = Models\Database::with('host')->findOrFail($id);
$dbr = Models\DatabaseServer::findOrFail($db->db_server);
DB::beginTransaction(); DB::beginTransaction();
@ -175,11 +173,11 @@ class DatabaseRepository
$capsule = new Capsule; $capsule = new Capsule;
$capsule->addConnection([ $capsule->addConnection([
'driver' => 'mysql', 'driver' => 'mysql',
'host' => $dbr->host, 'host' => $database->host->host,
'port' => $dbr->port, 'port' => $database->host->port,
'database' => 'mysql', 'database' => 'mysql',
'username' => $dbr->username, 'username' => $database->host->username,
'password' => Crypt::decrypt($dbr->password), 'password' => Crypt::decrypt($database->host->password),
'charset' => 'utf8', 'charset' => 'utf8',
'collation' => 'utf8_unicode_ci', 'collation' => 'utf8_unicode_ci',
'prefix' => '', 'prefix' => '',
@ -190,10 +188,10 @@ class DatabaseRepository
$capsule->setAsGlobal(); $capsule->setAsGlobal();
Capsule::statement('DROP USER `' . $db->username . '`@`' . $db->remote . '`'); Capsule::statement('DROP USER `' . $database->username . '`@`' . $database->remote . '`');
Capsule::statement('DROP DATABASE `' . $db->database . '`'); Capsule::statement('DROP DATABASE `' . $database->database . '`');
$db->delete(); $database->delete();
DB::commit(); DB::commit();
@ -206,19 +204,19 @@ class DatabaseRepository
/** /**
* Deletes a database server from the system if it is empty. * Deletes a database server from the system if it is empty.
*
* @param int $server The ID of the Database Server. * @param int $server The ID of the Database Server.
* @return * @return
*/ */
public function delete($server) public function delete($server)
{ {
$dbh = Models\DatabaseServer::findOrFail($server); $host = Models\DatabaseServer::withCount('databases')->findOrFail($server);
$databases = Models\Database::where('db_server', $dbh->id)->count();
if ($databases > 0) { if ($host->databases_count > 0) {
throw new DisplayException('You cannot delete a database server that has active databases attached to it.'); throw new DisplayException('You cannot delete a database server that has active databases attached to it.');
} }
return $dbh->delete(); return $host->delete();
} }
/** /**
@ -268,8 +266,7 @@ class DatabaseRepository
// Allows us to check that we can connect to things. // Allows us to check that we can connect to things.
Capsule::select('SELECT 1 FROM dual'); Capsule::select('SELECT 1 FROM dual');
$dbh = new Models\DatabaseServer; Models\DatabaseServer::create([
$dbh->fill([
'name' => $data['name'], 'name' => $data['name'],
'host' => $data['host'], 'host' => $data['host'],
'port' => $data['port'], 'port' => $data['port'],
@ -278,7 +275,6 @@ class DatabaseRepository
'max_databases' => null, 'max_databases' => null,
'linked_node' => (! empty($data['linked_node']) && $data['linked_node'] > 0) ? $data['linked_node'] : null, 'linked_node' => (! empty($data['linked_node']) && $data['linked_node'] > 0) ? $data['linked_node'] : null,
]); ]);
$dbh->save();
DB::commit(); DB::commit();
} catch (\Exception $ex) { } catch (\Exception $ex) {

View file

@ -37,9 +37,10 @@ class LocationRepository
/** /**
* Creates a new location on the system. * Creates a new location on the system.
*
* @param array $data * @param array $data
* @throws Pterodactyl\Exceptions\DisplayValidationException * @throws \Pterodactyl\Exceptions\DisplayValidationException
* @return int * @return \Pterodactyl\Models\Location
*/ */
public function create(array $data) public function create(array $data)
{ {
@ -54,14 +55,12 @@ class LocationRepository
throw new DisplayValidationException($validator->errors()); throw new DisplayValidationException($validator->errors());
} }
$location = new Models\Location; $location = Models\Location::create([
$location->fill([
'long' => $data['long'], 'long' => $data['long'],
'short' => $data['short'], 'short' => $data['short'],
]); ]);
$location->save();
return $location->id; return $location;
} }
/** /**

View file

@ -81,12 +81,7 @@ class NodeRepository
$uuid = new UuidService; $uuid = new UuidService;
$data['daemonSecret'] = (string) $uuid->generate('nodes', 'daemonSecret'); $data['daemonSecret'] = (string) $uuid->generate('nodes', 'daemonSecret');
// Store the Data return Models\Node::create($data);
$node = new Models\Node;
$node->fill($data);
$node->save();
return $node;
} }
public function update($id, array $data) public function update($id, array $data)
@ -260,8 +255,8 @@ class NodeRepository
public function delete($id) public function delete($id)
{ {
$node = Models\Node::findOrFail($id); $node = Models\Node::withCount('servers')->findOrFail($id);
if (Models\Server::where('node', $id)->count() > 0) { if ($node->servers_count > 0) {
throw new DisplayException('You cannot delete a node with servers currently attached to it.'); throw new DisplayException('You cannot delete a node with servers currently attached to it.');
} }

View file

@ -30,6 +30,7 @@ use Crypt;
use Validator; use Validator;
use Pterodactyl\Models; use Pterodactyl\Models;
use Pterodactyl\Services\UuidService; use Pterodactyl\Services\UuidService;
use GuzzleHttp\Exception\TransferException;
use Pterodactyl\Services\DeploymentService; use Pterodactyl\Services\DeploymentService;
use Pterodactyl\Exceptions\DisplayException; use Pterodactyl\Exceptions\DisplayException;
use Pterodactyl\Exceptions\DisplayValidationException; use Pterodactyl\Exceptions\DisplayValidationException;
@ -121,12 +122,7 @@ class ServerRepository
throw new DisplayValidationException($validator->errors()); throw new DisplayValidationException($validator->errors());
} }
if (is_int($data['owner'])) { $user = Models\User::select('id', 'email')->where((is_int($data['owner'])) ? 'id' : 'email', $data['owner'])->first();
$user = Models\User::select('id', 'email')->where('id', $data['owner'])->first();
} else {
$user = Models\User::select('id', 'email')->where('email', $data['owner'])->first();
}
if (! $user) { if (! $user) {
throw new DisplayException('The user id or email passed to the function was not found on the system.'); throw new DisplayException('The user id or email passed to the function was not found on the system.');
} }
@ -141,7 +137,7 @@ class ServerRepository
$node = DeploymentService::smartRandomNode($data['memory'], $data['disk'], $data['location']); $node = DeploymentService::smartRandomNode($data['memory'], $data['disk'], $data['location']);
$allocation = DeploymentService::randomAllocation($node->id); $allocation = DeploymentService::randomAllocation($node->id);
} else { } else {
$node = Models\Node::getByID($data['node']); $node = Models\Node::findOrFail($data['node']);
} }
// Verify IP & Port are a.) free and b.) assigned to the node. // Verify IP & Port are a.) free and b.) assigned to the node.
@ -299,11 +295,7 @@ class ServerRepository
]); ]);
} }
$client = Models\Node::guzzleRequest($node->id); $node->guzzleClient(['X-Access-Token' => $node->daemonSecret])->request('POST', '/servers', [
$client->request('POST', '/servers', [
'headers' => [
'X-Access-Token' => $node->daemonSecret,
],
'json' => [ 'json' => [
'uuid' => (string) $server->uuid, 'uuid' => (string) $server->uuid,
'user' => $server->username, 'user' => $server->username,
@ -338,7 +330,7 @@ class ServerRepository
DB::commit(); DB::commit();
return $server->id; return $server->id;
} catch (\GuzzleHttp\Exception\TransferException $ex) { } catch (TransferException $ex) {
DB::rollBack(); DB::rollBack();
throw new DisplayException('There was an error while attempting to connect to the daemon to add this server.', $ex); throw new DisplayException('There was an error while attempting to connect to the daemon to add this server.', $ex);
} catch (\Exception $ex) { } catch (\Exception $ex) {
@ -373,11 +365,10 @@ class ServerRepository
DB::beginTransaction(); DB::beginTransaction();
try { try {
$server = Models\Server::findOrFail($id); $server = Models\Server::with('user')->findOrFail($id);
$owner = Models\User::findOrFail($server->owner_id);
// Update daemon secret if it was passed. // Update daemon secret if it was passed.
if ((isset($data['reset_token']) && $data['reset_token'] === true) || (isset($data['owner']) && $data['owner'] !== $owner->email)) { if ((isset($data['reset_token']) && $data['reset_token'] === true) || (isset($data['owner']) && $data['owner'] !== $server->user->email)) {
$oldDaemonKey = $server->daemonSecret; $oldDaemonKey = $server->daemonSecret;
$server->daemonSecret = $uuid->generate('servers', 'daemonSecret'); $server->daemonSecret = $uuid->generate('servers', 'daemonSecret');
$resetDaemonKey = true; $resetDaemonKey = true;
@ -404,15 +395,10 @@ class ServerRepository
return true; return true;
} }
// If we need to update do it here. $res = $server->node->guzzleClient([
$node = Models\Node::getByID($server->node_id);
$client = Models\Node::guzzleRequest($server->node_id);
$res = $client->request('PATCH', '/server', [
'headers' => [
'X-Access-Server' => $server->uuid, 'X-Access-Server' => $server->uuid,
'X-Access-Token' => $node->daemonSecret, 'X-Access-Token' => $server->node->daemonSecret,
], ])->request('PATCH', '/server', [
'exceptions' => false, 'exceptions' => false,
'json' => [ 'json' => [
'keys' => [ 'keys' => [
@ -461,14 +447,10 @@ class ServerRepository
$server->image = $data['image']; $server->image = $data['image'];
$server->save(); $server->save();
$node = Models\Node::getByID($server->node_id); $server->node->guzzleClient([
$client = Models\Node::guzzleRequest($server->node_id);
$client->request('PATCH', '/server', [
'headers' => [
'X-Access-Server' => $server->uuid, 'X-Access-Server' => $server->uuid,
'X-Access-Token' => $node->daemonSecret, 'X-Access-Token' => $server->node->daemonSecret,
], ])->request('PATCH', '/server', [
'json' => [ 'json' => [
'build' => [ 'build' => [
'image' => $server->image, 'image' => $server->image,
@ -479,7 +461,7 @@ class ServerRepository
DB::commit(); DB::commit();
return true; return true;
} catch (\GuzzleHttp\Exception\TransferException $ex) { } catch (TransferException $ex) {
DB::rollBack(); DB::rollBack();
throw new DisplayException('An error occured while attempting to update the container image.', $ex); throw new DisplayException('An error occured while attempting to update the container image.', $ex);
} catch (\Exception $ex) { } catch (\Exception $ex) {
@ -519,15 +501,13 @@ class ServerRepository
DB::beginTransaction(); DB::beginTransaction();
try { try {
$server = Models\Server::findOrFail($id); $server = Models\Server::with('allocation', 'allocations')->findOrFail($id);
$allocation = Models\Allocation::findOrFail($server->allocation_id);
$newBuild = []; $newBuild = [];
if (isset($data['default'])) { if (isset($data['default'])) {
list($ip, $port) = explode(':', $data['default']); list($ip, $port) = explode(':', $data['default']);
if ($ip !== $allocation->ip || (int) $port !== $allocation->port) { if ($ip !== $server->allocation->ip || (int) $port !== $server->allocation->port) {
$selection = Models\Allocation::where('ip', $ip)->where('port', $port)->where('assigned_to', $server->id)->first(); $selection = $server->allocations->where('ip', $ip)->where('port', $port)->first();
if (! $selection) { if (! $selection) {
throw new DisplayException('The requested default connection (' . $ip . ':' . $port . ') is not allocated to this server.'); throw new DisplayException('The requested default connection (' . $ip . ':' . $port . ') is not allocated to this server.');
} }
@ -539,7 +519,7 @@ class ServerRepository
]; ];
// Re-Run to keep updated for rest of function // Re-Run to keep updated for rest of function
$allocation = Models\Allocation::findOrFail($server->allocation_id); $server->load('allocation');
} }
} }
@ -554,15 +534,17 @@ class ServerRepository
} }
// Can't remove the assigned IP/Port combo // Can't remove the assigned IP/Port combo
if ($ip === $allocation->ip && (int) $port === (int) $allocation->port) { if ($ip === $server->allocation->ip && (int) $port === (int) $server->allocation->port) {
break; break;
} }
$newPorts = true; $newPorts = true;
Models\Allocation::where('ip', $ip)->where('port', $port)->where('assigned_to', $server->id)->update([ $server->allocations->where('ip', $ip)->where('port', $port)->update([
'assigned_to' => null, 'assigned_to' => null,
]); ]);
} }
$server->load('allocations');
} }
// Add Assignments // Add Assignments
@ -575,7 +557,7 @@ class ServerRepository
} }
// Don't allow double port assignments // Don't allow double port assignments
if (Models\Allocation::where('port', $port)->where('assigned_to', $server->id)->count() !== 0) { if ($server->allocations->where('port', $port)->count() !== 0) {
break; break;
} }
@ -584,12 +566,13 @@ class ServerRepository
'assigned_to' => $server->id, 'assigned_to' => $server->id,
]); ]);
} }
$server->load('allocations');
} }
// Loop All Assignments // Loop All Assignments
$additionalAssignments = []; $additionalAssignments = [];
$assignments = Models\Allocation::where('assigned_to', $server->id)->get(); foreach ($server->allocations as &$assignment) {
foreach ($assignments as &$assignment) {
if (array_key_exists((string) $assignment->ip, $additionalAssignments)) { if (array_key_exists((string) $assignment->ip, $additionalAssignments)) {
array_push($additionalAssignments[(string) $assignment->ip], (int) $assignment->port); array_push($additionalAssignments[(string) $assignment->ip], (int) $assignment->port);
} else { } else {
@ -635,14 +618,10 @@ class ServerRepository
$server->save(); $server->save();
if (! empty($newBuild)) { if (! empty($newBuild)) {
$node = Models\Node::getByID($server->node_id); $server->node->guzzleClient([
$client = Models\Node::guzzleRequest($server->node_id);
$client->request('PATCH', '/server', [
'headers' => [
'X-Access-Server' => $server->uuid, 'X-Access-Server' => $server->uuid,
'X-Access-Token' => $node->daemonSecret, 'X-Access-Token' => $server->node->daemonSecret,
], ])->request('PATCH', '/server', [
'json' => [ 'json' => [
'build' => $newBuild, 'build' => $newBuild,
], ],
@ -652,7 +631,7 @@ class ServerRepository
DB::commit(); DB::commit();
return true; return true;
} catch (\GuzzleHttp\Exception\TransferException $ex) { } catch (TransferException $ex) {
DB::rollBack(); DB::rollBack();
throw new DisplayException('An error occured while attempting to update the configuration.', $ex); throw new DisplayException('An error occured while attempting to update the configuration.', $ex);
} catch (\Exception $ex) { } catch (\Exception $ex) {
@ -663,7 +642,7 @@ class ServerRepository
public function updateStartup($id, array $data, $admin = false) public function updateStartup($id, array $data, $admin = false)
{ {
$server = Models\Server::findOrFail($id); $server = Models\Server::with('variables', 'option.variables')->findOrFail($id);
DB::beginTransaction(); DB::beginTransaction();
@ -675,22 +654,22 @@ class ServerRepository
} }
// Check those Variables // Check those Variables
$variables = Models\ServiceVariables::select( $server->option->variables->transform(function ($item, $key) use ($server) {
'service_variables.*', $displayValue = $server->variables->where('variable_id', $item->id)->pluck('variable_value')->first();
DB::raw('COALESCE(server_variables.variable_value, service_variables.default_value) as a_currentValue') $item->server_value = (! is_null($displayValue)) ? $displayValue : $item->default_value;
)->leftJoin('server_variables', 'server_variables.variable_id', '=', 'service_variables.id')
->where('option_id', $server->option_id) return $item;
->get(); });
$variableList = []; $variableList = [];
if ($variables) { if ($server->option->variables) {
foreach ($variables as &$variable) { foreach ($server->option->variables as &$variable) {
// Move on if the new data wasn't even sent // Move on if the new data wasn't even sent
if (! isset($data[$variable->env_variable])) { if (! isset($data[$variable->env_variable])) {
$variableList[] = [ $variableList[] = [
'id' => $variable->id, 'id' => $variable->id,
'env' => $variable->env_variable, 'env' => $variable->env_variable,
'val' => $variable->a_currentValue, 'val' => $variable->server_value,
]; ];
continue; continue;
} }
@ -708,13 +687,13 @@ class ServerRepository
// Is the variable required? // Is the variable required?
// @TODO: is this even logical to perform this check? // @TODO: is this even logical to perform this check?
if (isset($data[$variable->env_variable]) && empty($data[$variable->env_variable])) { if (isset($data[$variable->env_variable]) && empty($data[$variable->env_variable])) {
if ($variable->required === 1) { if ($variable->required) {
throw new DisplayException('A required service option variable field (' . $variable->env_variable . ') was included in this request but was left blank.'); throw new DisplayException('A required service option variable field (' . $variable->env_variable . ') was included in this request but was left blank.');
} }
} }
// Variable hidden and/or not user editable // Variable hidden and/or not user editable
if (($variable->user_viewable === 0 || $variable->user_editable === 0) && ! $admin) { if ((! $variable->user_viewable || ! $variable->user_editable) && ! $admin) {
throw new DisplayException('A service option variable field (' . $variable->env_variable . ') does not exist or you do not have permission to edit it.'); throw new DisplayException('A service option variable field (' . $variable->env_variable . ') does not exist or you do not have permission to edit it.');
} }
@ -747,14 +726,10 @@ class ServerRepository
$model->save(); $model->save();
} }
$node = Models\Node::getByID($server->node_id); $server->node->guzzleClient([
$client = Models\Node::guzzleRequest($server->node_id);
$client->request('PATCH', '/server', [
'headers' => [
'X-Access-Server' => $server->uuid, 'X-Access-Server' => $server->uuid,
'X-Access-Token' => $node->daemonSecret, 'X-Access-Token' => $server->node->daemonSecret,
], ])->request('PATCH', '/server', [
'json' => [ 'json' => [
'build' => [ 'build' => [
'env|overwrite' => $environmentVariables, 'env|overwrite' => $environmentVariables,
@ -765,7 +740,7 @@ class ServerRepository
DB::commit(); DB::commit();
return true; return true;
} catch (\GuzzleHttp\Exception\TransferException $ex) { } catch (TransferException $ex) {
DB::rollBack(); DB::rollBack();
throw new DisplayException('An error occured while attempting to update the server configuration.', $ex); throw new DisplayException('An error occured while attempting to update the server configuration.', $ex);
} catch (\Exception $ex) { } catch (\Exception $ex) {
@ -780,7 +755,7 @@ class ServerRepository
DB::beginTransaction(); DB::beginTransaction();
try { try {
if ($force === 'force' || $force === true) { if ($force === 'force' || $force) {
$server->installed = 3; $server->installed = 3;
$server->save(); $server->save();
} }
@ -796,8 +771,7 @@ class ServerRepository
public function deleteNow($id, $force = false) public function deleteNow($id, $force = false)
{ {
$server = Models\Server::withTrashed()->findOrFail($id); $server = Models\Server::withTrashed()->with('node')->findOrFail($id);
$node = Models\Node::findOrFail($server->node_id);
// Handle server being restored previously or // Handle server being restored previously or
// an accidental queue. // an accidental queue.
@ -835,17 +809,14 @@ class ServerRepository
$repository->drop($database->id); $repository->drop($database->id);
} }
$client = Models\Node::guzzleRequest($server->node_id); $server->node->guzzleRequest([
$client->request('DELETE', '/servers', [ 'X-Access-Token' => $server->node->daemonSecret,
'headers' => [
'X-Access-Token' => $node->daemonSecret,
'X-Access-Server' => $server->uuid, 'X-Access-Server' => $server->uuid,
], ])->request('DELETE', '/servers');
]);
$server->forceDelete(); $server->forceDelete();
DB::commit(); DB::commit();
} catch (\GuzzleHttp\Exception\TransferException $ex) { } catch (TransferException $ex) {
// Set installed is set to 3 when force deleting. // Set installed is set to 3 when force deleting.
if ($server->installed === 3 || $force) { if ($server->installed === 3 || $force) {
$server->forceDelete(); $server->forceDelete();
@ -875,7 +846,7 @@ class ServerRepository
if ($server->installed === 2) { if ($server->installed === 2) {
throw new DisplayException('This server was marked as having a failed install, you cannot override this.'); throw new DisplayException('This server was marked as having a failed install, you cannot override this.');
} }
$server->installed = ($server->installed === 1) ? 0 : 1; $server->installed = ($server->installed) ? 0 : 1;
return $server->save(); return $server->save();
} }
@ -887,31 +858,27 @@ class ServerRepository
*/ */
public function suspend($id, $deleted = false) public function suspend($id, $deleted = false)
{ {
$server = ($deleted) ? Models\Server::withTrashed()->findOrFail($id) : Models\Server::findOrFail($id); $server = Models\Server::withTrashed()->with('node')->findOrFail($id);
$node = Models\Node::findOrFail($server->node_id);
DB::beginTransaction(); DB::beginTransaction();
try { try {
// Already suspended, no need to make more requests. // Already suspended, no need to make more requests.
if ($server->suspended === 1) { if ($server->suspended) {
return true; return true;
} }
$server->suspended = 1; $server->suspended = 1;
$server->save(); $server->save();
$client = Models\Node::guzzleRequest($server->node_id); $server->node->guzzleClient([
$client->request('POST', '/server/suspend', [ 'X-Access-Token' => $server->node->daemonSecret,
'headers' => [
'X-Access-Token' => $node->daemonSecret,
'X-Access-Server' => $server->uuid, 'X-Access-Server' => $server->uuid,
], ])->request('POST', '/server/suspend');
]);
return DB::commit(); return DB::commit();
} catch (\GuzzleHttp\Exception\TransferException $ex) { } catch (TransferException $ex) {
DB::rollBack(); DB::rollBack();
throw new DisplayException('An error occured while attempting to contact the remote daemon to suspend this server.', $ex); throw new DisplayException('An error occured while attempting to contact the remote daemon to suspend this server.', $ex);
} catch (\Exception $ex) { } catch (\Exception $ex) {
@ -927,8 +894,7 @@ class ServerRepository
*/ */
public function unsuspend($id) public function unsuspend($id)
{ {
$server = Models\Server::findOrFail($id); $server = Models\Server::with('node')->findOrFail($id);
$node = Models\Node::findOrFail($server->node_id);
DB::beginTransaction(); DB::beginTransaction();
@ -942,16 +908,13 @@ class ServerRepository
$server->suspended = 0; $server->suspended = 0;
$server->save(); $server->save();
$client = Models\Node::guzzleRequest($server->node_id); $server->node->guzzleClient([
$client->request('POST', '/server/unsuspend', [ 'X-Access-Token' => $server->node->daemonSecret,
'headers' => [
'X-Access-Token' => $node->daemonSecret,
'X-Access-Server' => $server->uuid, 'X-Access-Server' => $server->uuid,
], ])->request('POST', '/server/unsuspend');
]);
return DB::commit(); return DB::commit();
} catch (\GuzzleHttp\Exception\TransferException $ex) { } catch (TransferException $ex) {
DB::rollBack(); DB::rollBack();
throw new DisplayException('An error occured while attempting to contact the remote daemon to un-suspend this server.', $ex); throw new DisplayException('An error occured while attempting to contact the remote daemon to un-suspend this server.', $ex);
} catch (\Exception $ex) { } catch (\Exception $ex) {
@ -962,12 +925,9 @@ class ServerRepository
public function updateSFTPPassword($id, $password) public function updateSFTPPassword($id, $password)
{ {
$server = Models\Server::findOrFail($id); $server = Models\Server::with('node')->findOrFail($id);
$node = Models\Node::findOrFail($server->node_id);
$validator = Validator::make([ $validator = Validator::make(['password' => $password], [
'password' => $password,
], [
'password' => 'required|regex:/^((?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{8,})$/', 'password' => 'required|regex:/^((?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{8,})$/',
]); ]);
@ -981,21 +941,17 @@ class ServerRepository
try { try {
$server->save(); $server->save();
$client = Models\Node::guzzleRequest($server->node_id); $server->node->guzzleClient([
$client->request('POST', '/server/password', [ 'X-Access-Token' => $server->node->daemonSecret,
'headers' => [
'X-Access-Token' => $node->daemonSecret,
'X-Access-Server' => $server->uuid, 'X-Access-Server' => $server->uuid,
], ])->request('POST', '/server/password', [
'json' => [ 'json' => ['password' => $password],
'password' => $password,
],
]); ]);
DB::commit(); DB::commit();
return true; return true;
} catch (\GuzzleHttp\Exception\TransferException $ex) { } catch (TransferException $ex) {
DB::rollBack(); DB::rollBack();
throw new DisplayException('There was an error while attmping to contact the remote service to change the password.', $ex); throw new DisplayException('There was an error while attmping to contact the remote service to change the password.', $ex);
} catch (\Exception $ex) { } catch (\Exception $ex) {

View file

@ -112,11 +112,11 @@ class SubuserRepository
* @param array $data * @param array $data
* @throws DisplayValidationException * @throws DisplayValidationException
* @throws DisplayException * @throws DisplayException
* @return int Returns the ID of the newly created subuser. * @return \Pterodactyl\Models\Subuser
*/ */
public function create($sid, array $data) public function create($sid, array $data)
{ {
$server = Models\Server::findOrFail($sid); $server = Models\Server::with('node')->findOrFail($sid);
$validator = Validator::make($data, [ $validator = Validator::make($data, [
'permissions' => 'required|array', 'permissions' => 'required|array',
@ -135,14 +135,13 @@ class SubuserRepository
if (! $user) { if (! $user) {
try { try {
$repo = new UserRepository; $repo = new UserRepository;
$uid = $repo->create([ $user = $repo->create([
'email' => $data['email'], 'email' => $data['email'],
'username' => substr(str_replace('@', '', $data['email']), 0, 8), 'username' => str_random(8),
'name_first' => 'John', 'name_first' => 'Unassigned',
'name_last' => 'Doe', 'name_last' => 'Name',
'root_admin' => false, 'root_admin' => false,
]); ]);
$user = Models\User::findOrFail($uid);
} catch (\Exception $ex) { } catch (\Exception $ex) {
throw $ex; throw $ex;
} }
@ -153,14 +152,11 @@ class SubuserRepository
} }
$uuid = new UuidService; $uuid = new UuidService;
$subuser = Models\Subuser::create([
$subuser = new Models\Subuser;
$subuser->fill([
'user_id' => $user->id, 'user_id' => $user->id,
'server_id' => $server->id, 'server_id' => $server->id,
'daemonSecret' => (string) $uuid->generate('servers', 'uuid'), 'daemonSecret' => (string) $uuid->generate('servers', 'uuid'),
]); ]);
$subuser->save();
$daemonPermissions = $this->coreDaemonPermissions; $daemonPermissions = $this->coreDaemonPermissions;
foreach ($data['permissions'] as $permission) { foreach ($data['permissions'] as $permission) {
@ -170,13 +166,11 @@ class SubuserRepository
array_push($daemonPermissions, $this->permissions[$permission]); array_push($daemonPermissions, $this->permissions[$permission]);
} }
$model = new Models\Permission; Models\Permission::create([
$model->fill([
'user_id' => $user->id, 'user_id' => $user->id,
'server_id' => $server->id, 'server_id' => $server->id,
'permission' => $permission, 'permission' => $permission,
]); ]);
$model->save();
} }
} }
@ -184,14 +178,10 @@ class SubuserRepository
// We contact even if they don't have any daemon permissions to overwrite // We contact even if they don't have any daemon permissions to overwrite
// if they did have them previously. // if they did have them previously.
$node = Models\Node::getByID($server->node_id); $server->node->guzzleClient([
$client = Models\Node::guzzleRequest($server->node_id);
$res = $client->request('PATCH', '/server', [
'headers' => [
'X-Access-Server' => $server->uuid, 'X-Access-Server' => $server->uuid,
'X-Access-Token' => $node->daemonSecret, 'X-Access-Token' => $node->daemonSecret,
], ])->request('PATCH', '/server', [
'json' => [ 'json' => [
'keys' => [ 'keys' => [
$subuser->daemonSecret => $daemonPermissions, $subuser->daemonSecret => $daemonPermissions,
@ -199,18 +189,9 @@ class SubuserRepository
], ],
]); ]);
$email = $data['email'];
Mail::queue('emails.added-subuser', [
'serverName' => $server->name,
'url' => route('server.index', $server->uuidShort),
], function ($message) use ($email) {
$message->to($email);
$message->from(Settings::get('email_from', env('MAIL_FROM')), Settings::get('email_sender_name', env('MAIL_FROM_NAME', 'Pterodactyl Panel')));
$message->subject(Settings::get('company') . ' - Added to Server');
});
DB::commit(); DB::commit();
return $subuser->id; return $subuser;
} catch (\GuzzleHttp\Exception\TransferException $ex) { } catch (\GuzzleHttp\Exception\TransferException $ex) {
DB::rollBack(); DB::rollBack();
throw new DisplayException('There was an error attempting to connect to the daemon to add this user.', $ex); throw new DisplayException('There was an error attempting to connect to the daemon to add this user.', $ex);
@ -232,22 +213,18 @@ class SubuserRepository
*/ */
public function delete($id) public function delete($id)
{ {
$subuser = Models\Subuser::findOrFail($id); $subuser = Models\Subuser::with('server.node', 'permissions')->findOrFail($id);
$server = Models\Server::findOrFail($subuser->server_id); $server = $subuser->server;
DB::beginTransaction(); DB::beginTransaction();
try { try {
Models\Permission::where('user_id', $subuser->user_id)->where('server_id', $subuser->server_id)->delete(); Models\Permission::where('user_id', $subuser->user_id)->where('server_id', $subuser->server_id)->delete();
$node = Models\Node::getByID($server->node_id); $server->node->guzzleClient([
$client = Models\Node::guzzleRequest($server->node_id);
$res = $client->request('PATCH', '/server', [
'headers' => [
'X-Access-Server' => $server->uuid, 'X-Access-Server' => $server->uuid,
'X-Access-Token' => $node->daemonSecret, 'X-Access-Token' => $server->node->daemonSecret,
], ])->request('PATCH', '/server', [
'json' => [ 'json' => [
'keys' => [ 'keys' => [
$subuser->daemonSecret => [], $subuser->daemonSecret => [],
@ -290,8 +267,8 @@ class SubuserRepository
throw new DisplayValidationException(json_encode($validator->all())); throw new DisplayValidationException(json_encode($validator->all()));
} }
$subuser = Models\Subuser::findOrFail($id); $subuser = Models\Subuser::with('server.node')->findOrFail($id);
$server = Models\Server::findOrFail($data['server']); $server = $subuser->server;
DB::beginTransaction(); DB::beginTransaction();
@ -318,14 +295,10 @@ class SubuserRepository
// Contact Daemon // Contact Daemon
// We contact even if they don't have any daemon permissions to overwrite // We contact even if they don't have any daemon permissions to overwrite
// if they did have them previously. // if they did have them previously.
$node = Models\Node::getByID($server->node_id); $server->node->guzzleClient([
$client = Models\Node::guzzleRequest($server->node_id);
$res = $client->request('PATCH', '/server', [
'headers' => [
'X-Access-Server' => $server->uuid, 'X-Access-Server' => $server->uuid,
'X-Access-Token' => $node->daemonSecret, 'X-Access-Token' => $server->node->daemonSecret,
], ])->request('PATCH', '/server', [
'json' => [ 'json' => [
'keys' => [ 'keys' => [
$subuser->daemonSecret => $daemonPermissions, $subuser->daemonSecret => $daemonPermissions,

View file

@ -111,7 +111,7 @@ class UserRepository
DB::commit(); DB::commit();
return $user->id; return $user;
} catch (\Exception $ex) { } catch (\Exception $ex) {
DB::rollBack(); DB::rollBack();
throw $ex; throw $ex;

View file

@ -32,7 +32,7 @@
<h3>All Servers</h3><hr /> <h3>All Servers</h3><hr />
<form method="GET" style="margin-bottom:20px;"> <form method="GET" style="margin-bottom:20px;">
<div class="input-group"> <div class="input-group">
<input type="text" name="filter" class="form-control" value="{{ urldecode(Input::get('filter')) }}" placeholder="search term" /> <input type="text" name="filter" class="form-control" value="{{ urldecode(request()->filter) }}" placeholder="search term" />
<div class="input-group-btn"> <div class="input-group-btn">
<button type="submit" class="btn btn-sm btn-primary">Filter Servers</button> <button type="submit" class="btn btn-sm btn-primary">Filter Servers</button>
</div> </div>
@ -64,8 +64,8 @@
<span class="label label-danger">Pending Deletion</span> <span class="label label-danger">Pending Deletion</span>
@endif @endif
</td> </td>
<td><a href="/admin/users/view/{{ $server->owner_id }}">{{ $server->a_ownerEmail }}</a></td> <td><a href="/admin/users/view/{{ $server->user->id }}">{{ $server->user->email }}</a></td>
<td><a href="/admin/nodes/view/{{ $server->node_id }}">{{ $server->a_nodeName }}</a></td> <td><a href="/admin/nodes/view/{{ $server->node->id }}">{{ $server->node->name }}</a></td>
<td class="hidden-xs"><code>{{ $server->username }}</code></td> <td class="hidden-xs"><code>{{ $server->username }}</code></td>
</tr> </tr>
@endforeach @endforeach

View file

@ -89,19 +89,19 @@
</tr> </tr>
<tr> <tr>
<td>Owner</td> <td>Owner</td>
<td><a href="{{ route('admin.users.view', $server->owner_id) }}">{{ $server->a_ownerEmail }}</a></td> <td><a href="{{ route('admin.users.view', $server->owner_id) }}">{{ $server->user->email }}</a></td>
</tr> </tr>
<tr> <tr>
<td>Location</td> <td>Location</td>
<td><a href="{{ route('admin.locations') }}">{{ $node->a_locationName }}</a></td> <td><a href="{{ route('admin.locations') }}">{{ $server->node->location->short }}</a></td>
</tr> </tr>
<tr> <tr>
<td>Node</td> <td>Node</td>
<td><a href="{{ route('admin.nodes.view', $server->node_id) }}">{{ $node->name }}</a></td> <td><a href="{{ route('admin.nodes.view', $server->node_id) }}">{{ $server->node->name }}</a></td>
</tr> </tr>
<tr> <tr>
<td>Service</td> <td>Service</td>
<td>{{ $server->a_serviceName }} :: {{ $server->a_servceOptionName }}</td> <td>{{ $server->option->service->name }} :: {{ $server->option->name }}</td>
</tr> </tr>
<tr> <tr>
<td>Name</td> <td>Name</td>
@ -129,13 +129,13 @@
</tr> </tr>
<tr> <tr>
<td>Default Connection</td> <td>Default Connection</td>
<td><code>{{ $server->ip }}:{{ $server->port }}</code></td> <td><code>{{ $server->allocation->ip }}:{{ $server->allocation->port }}</code></td>
</tr> </tr>
<tr> <tr>
<td>Connection Alias</td> <td>Connection Alias</td>
<td> <td>
@if(!is_null($server->ip_alias)) @if($server->allocation->alias !== $server->allocation->ip)
<code>{{ $server->ip_alias }}:{{ $server->port }}</code> <code>{{ $server->allocation->alias }}:{{ $server->allocation->port }}</code>
@else @else
<span class="label label-default">No Alias Assigned</span> <span class="label label-default">No Alias Assigned</span>
@endif @endif
@ -170,7 +170,7 @@
<div class="form-group {{ $errors->has('owner') ? 'has-error' : '' }}"> <div class="form-group {{ $errors->has('owner') ? 'has-error' : '' }}">
<label for="name" class="control-label">Server Owner</label> <label for="name" class="control-label">Server Owner</label>
<div> <div>
<input type="text" name="owner" value="{{ old('owner', $server->a_ownerEmail) }}" class="form-control" /> <input type="text" name="owner" value="{{ old('owner', $server->user->email) }}" class="form-control" />
<p class="text-muted"><small>You can change the owner of this server by changing this field to an email matching another use on this system. If you do this a new daemon security token will be generated automatically.</small></p> <p class="text-muted"><small>You can change the owner of this server by changing this field to an email matching another use on this system. If you do this a new daemon security token will be generated automatically.</small></p>
</div> </div>
</div> </div>
@ -278,9 +278,15 @@
@foreach ($assigned as $assignment) @foreach ($assigned as $assignment)
<div class="input-group" style="margin:5px auto;"> <div class="input-group" style="margin:5px auto;">
<span class="input-group-addon"> <span class="input-group-addon">
<input type="radio" @if($assignment->ip == $server->ip && $assignment->port == $server->port) checked="checked" @endif name="default" value="{{ $assignment->ip }}:{{ $assignment->port }}"/> <input type="radio"
@if($assignment->id === $server->allocation_id) checked="checked" @endif
name="default" value="{{ $assignment->ip }}:{{ $assignment->port }}"/>
</span> </span>
<input type="text" class="form-control" value="@if(!is_null($assignment->ip_alias)){{ $assignment->ip_alias }}@else{{ $assignment->ip }}@endif:{{ $assignment->port }} @if(!is_null($assignment->ip_alias))(alias of {{ $assignment->ip }})@endif" readonly /> <input type="text" class="form-control" value="{{ $assignment->alias }}:{{ $assignment->port }}"
@if($assignment->has_alias)
data-toggle="tooltip" data-placement="left" title="{{ $assignment->ip }}:{{ $assignment->port }}"
@endif
/>
</div> </div>
@endforeach @endforeach
</div> </div>
@ -291,7 +297,7 @@
<div> <div>
<select name="add_additional[]" class="form-control" multiple> <select name="add_additional[]" class="form-control" multiple>
@foreach ($unassigned as $assignment) @foreach ($unassigned as $assignment)
<option value="{{ $assignment->ip }}:{{ $assignment->port }}">@if(!is_null($assignment->ip_alias)){{ $assignment->ip_alias }}@else{{ $assignment->ip }}@endif:{{ $assignment->port }} @if(!is_null($assignment->ip_alias))(alias of {{ $assignment->ip }})@endif</option> <option value="{{ $assignment->ip }}:{{ $assignment->port }}">{{ $assignment->alias }}:{{ $assignment->port }}</option>
@endforeach @endforeach
</select> </select>
</div> </div>
@ -304,7 +310,7 @@
<div> <div>
<select name="remove_additional[]" class="form-control" multiple> <select name="remove_additional[]" class="form-control" multiple>
@foreach ($assigned as $assignment) @foreach ($assigned as $assignment)
<option value="{{ $assignment->ip }}:{{ $assignment->port }}" @if($server->allocation_id === $assignment->id)disabled @endif>@if(!is_null($assignment->ip_alias)){{ $assignment->ip_alias }}@else{{ $assignment->ip }}@endif:{{ $assignment->port }} @if(!is_null($assignment->ip_alias))(alias of {{ $assignment->ip }})@endif</option> <option value="{{ $assignment->ip }}:{{ $assignment->port }}" @if($server->allocation_id === $assignment->id)disabled @endif>{{ $assignment->alias }}:{{ $assignment->port }}</option>
@endforeach @endforeach
</select> </select>
</div> </div>
@ -333,7 +339,7 @@
<div class="alert alert-info">Changing any of the values below will require a restart for them to take effect.</div> <div class="alert alert-info">Changing any of the values below will require a restart for them to take effect.</div>
<label class="control-label">Server Startup Command</label> <label class="control-label">Server Startup Command</label>
<div class="input-group"> <div class="input-group">
<span class="input-group-addon">{{ $server->a_serviceExecutable }}</span> <span class="input-group-addon">{{ $server->option->display_executable }}</span>
<input type="text" class="form-control" name="startup" value="{{ old('startup', $server->startup) }}" /> <input type="text" class="form-control" name="startup" value="{{ old('startup', $server->startup) }}" />
</div> </div>
<p class="text-muted"><small>The following data replacers are avaliable for the startup command: <code>@{{SERVER_MEMORY}}</code>, <code>@{{SERVER_IP}}</code>, and <code>@{{SERVER_PORT}}</code>. They will be replaced with the allocated memory, server ip, and server port respectively.</small></p> <p class="text-muted"><small>The following data replacers are avaliable for the startup command: <code>@{{SERVER_MEMORY}}</code>, <code>@{{SERVER_IP}}</code>, and <code>@{{SERVER_PORT}}</code>. They will be replaced with the allocated memory, server ip, and server port respectively.</small></p>
@ -343,18 +349,18 @@
<div class="panel-heading" style="border-top: 1px solid #ddd;"></div> <div class="panel-heading" style="border-top: 1px solid #ddd;"></div>
<div class="panel-body"> <div class="panel-body">
<div class="row"> <div class="row">
@foreach($startup as $item) @foreach($server->option->variables as $variable)
<div class="form-group col-md-6"> <div class="form-group col-md-6">
<label class="control-label"> <label class="control-label">
@if($item->required === 1)<span class="label label-primary">Required</span> @endif @if($variable->required)<span class="label label-primary">Required</span> @endif
@if($item->user_viewable === 0)<span data-toggle="tooltip" data-placement="top" title="Not Visible to Users" class="label label-danger"><i class="fa fa-eye-slash"></i></span> @endif @if(! $variable->user_viewable)<span data-toggle="tooltip" data-placement="top" title="Not Visible to Users" class="label label-danger"><i class="fa fa-eye-slash"></i></span> @endif
@if($item->user_editable === 0)<span data-toggle="tooltip" data-placement="top" title="Not Editable by Users" class="label label-danger"><i class="fa fa-edit"></i></span> @endif @if(! $variable->user_editable)<span data-toggle="tooltip" data-placement="top" title="Not Editable by Users" class="label label-danger"><i class="fa fa-edit"></i></span> @endif
{{ $item->name }} {{ $variable->name }}
</label> </label>
<div> <div>
<input type="text" name="{{ $item->env_variable }}" class="form-control" value="{{ old($item->env_variable, $item->a_serverValue) }}" data-action="matchRegex" data-regex="{{ $item->regex }}" /> <input type="text" name="{{ $variable->env_variable }}" class="form-control" value="{{ old($variable->env_variable, (! $variable->server_value) ? $variable->default_value : $variable->server_value) }}" data-action="matchRegex" data-regex="{{ $variable->regex }}" />
</div> </div>
<p class="text-muted"><small>{!! $item->description !!}<br />Regex: <code>{{ $item->regex }}</code><br />Access as: <code>&#123;&#123;{{$item->env_variable}}&#125;&#125;</code></small></p> <p class="text-muted"><small>{!! $variable->description !!}<br />Regex: <code>{{ $variable->regex }}</code><br />Access as: <code>&#123;&#123;{{ $variable->env_variable }}&#125;&#125;</code></small></p>
</div> </div>
@endforeach @endforeach
</div> </div>
@ -412,7 +418,7 @@
</div> </div>
</form> </form>
</div> </div>
@if(count($databases) > 0) @if(count($server->databases) > 0)
<div class="panel-heading" style="border-top: 1px solid #ddd;"></div> <div class="panel-heading" style="border-top: 1px solid #ddd;"></div>
<div class="panel-body"> <div class="panel-body">
<table class="table table-bordered table-hover"> <table class="table table-bordered table-hover">
@ -426,12 +432,12 @@
</th> </th>
</thead> </thead>
<tbody> <tbody>
@foreach($databases as $database) @foreach($server->databases as $database)
<tr> <tr>
<td>{{ $database->database }}</td> <td>{{ $database->database }}</td>
<td>{{ $database->username }} ({{ $database->remote }})</td> <td>{{ $database->username }} ({{ $database->remote }})</td>
<td><code>{{ Crypt::decrypt($database->password) }}</code> <a href="#" data-action="reset-database-password" data-id="{{ $database->id }}"><i class="fa fa-refresh pull-right"></i></a></td> <td><code>{{ Crypt::decrypt($database->password) }}</code> <a href="#" data-action="reset-database-password" data-id="{{ $database->id }}"><i class="fa fa-refresh pull-right"></i></a></td>
<td><code>{{ $database->a_host }}:{{ $database->a_port }}</code></td> <td><code>{{ $database->host->host }}:{{ $database->host->port }}</code></td>
<td class="text-center"><a href="#delete" data-action="delete_database" data-database="{{ $database->id }}" class="text-danger"><i class="fa fa-trash-o"></i></a></td> <td class="text-center"><a href="#delete" data-action="delete_database" data-database="{{ $database->id }}" class="text-danger"><i class="fa fa-trash-o"></i></a></td>
</tr> </tr>
@endforeach @endforeach
@ -568,7 +574,7 @@ $(document).ready(function () {
'X-Access-Token': '{{ $server->daemonSecret }}', 'X-Access-Token': '{{ $server->daemonSecret }}',
'X-Access-Server': '{{ $server->uuid }}' 'X-Access-Server': '{{ $server->uuid }}'
}, },
url: '{{ $node->scheme }}://{{ $node->fqdn }}:{{ $node->daemonListen }}/server', url: '{{ $server->node->scheme }}://{{ $server->node->fqdn }}:{{ $server->node->daemonListen }}/server',
dataType: 'json', dataType: 'json',
timeout: 5000, timeout: 5000,
}).done(function (data) { }).done(function (data) {

View file

@ -39,7 +39,7 @@
<div class="col-md-6"> <div class="col-md-6">
<fieldset> <fieldset>
<div class="form-group"> <div class="form-group">
<label for="email" class="control-label">{{ trans('strings.email') }}</label> <label for="email" class="control-label">Email</label>
<div> <div>
<input type="text" name="email" value="{{ $user->email }}" class="form-control"> <input type="text" name="email" value="{{ $user->email }}" class="form-control">
</div> </div>
@ -64,7 +64,7 @@
</div> </div>
<div class="form-group"> <div class="form-group">
{!! csrf_field() !!} {!! csrf_field() !!}
<input type="submit" value="{{ trans('base.account.update_user') }}" class="btn btn-primary btn-sm"> <input type="submit" value="Update User" class="btn btn-primary btn-sm">
</div> </div>
</fieldset> </fieldset>
</div> </div>
@ -72,7 +72,7 @@
<div class="well" style="padding-bottom: 0;"> <div class="well" style="padding-bottom: 0;">
<div class="alert alert-success" style="display:none;margin-bottom:10px;" id="gen_pass"></div> <div class="alert alert-success" style="display:none;margin-bottom:10px;" id="gen_pass"></div>
<div class="form-group"> <div class="form-group">
<label for="password" class="control-label">{{ trans('strings.password') }}</label> <label for="password" class="control-label">Password</label>
<div> <div>
<input type="password" id="password" name="password" class="form-control"> <input type="password" id="password" name="password" class="form-control">
</div> </div>
@ -83,7 +83,7 @@
</div> </div>
<div class="well" style="padding-bottom: 0;"> <div class="well" style="padding-bottom: 0;">
<div class="form-group"> <div class="form-group">
<label for="root_admin" class="control-label">{{ trans('strings.root_administrator') }}</label> <label for="root_admin" class="control-label">Administrator</label>
<div> <div>
<select name="root_admin" class="form-control"> <select name="root_admin" class="form-control">
<option value="0">{{ trans('strings.no') }}</option> <option value="0">{{ trans('strings.no') }}</option>
@ -99,7 +99,7 @@
<div class="row"> <div class="row">
<div class="col-md-12"> <div class="col-md-12">
<h3>Associated Servers</h3><hr> <h3>Associated Servers</h3><hr>
@if($servers) @if($user->servers)
<table class="table table-striped table-bordered table-hover"> <table class="table table-striped table-bordered table-hover">
<thead> <thead>
<tr> <tr>
@ -112,12 +112,12 @@
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
@foreach($servers as $server) @foreach($user->servers as $server)
<tr> <tr>
<td><a href="/server/{{ $server->uuidShort }}/"><i class="fa fa-tachometer"></i></a></td> <td><a href="/server/{{ $server->uuidShort }}/"><i class="fa fa-tachometer"></i></a></td>
<td><code>{{ $server->uuidShort }}</code></td> <td><code>{{ $server->uuidShort }}</code></td>
<td><a href="/admin/servers/view/{{ $server->id }}">{{ $server->name }}</a></td> <td><a href="/admin/servers/view/{{ $server->id }}">{{ $server->name }}</a></td>
<td>{{ $server->node_idName }}</td> <td>{{ $server->node->name }}</td>
<td><code>{{ $server->username }}</code></td> <td><code>{{ $server->username }}</code></td>
<td class="centered">@if($server->suspended === 0)<span class="label muted muted-hover label-success">Active</span>@else<span class="label label-warning">Suspended</span>@endif</td> <td class="centered">@if($server->suspended === 0)<span class="label muted muted-hover label-success">Active</span>@else<span class="label label-warning">Suspended</span>@endif</td>
</td> </td>
@ -127,7 +127,7 @@
@else @else
<div class="alert alert-info">There are no servers associated with this account.</div> <div class="alert alert-info">There are no servers associated with this account.</div>
@endif @endif
<a href="/admin/servers/new?email={{ $user->email }}"><button type="button" class="btn btn-success btn-sm">{{ trans('server.index.add_new') }}</button></a> <a href="/admin/servers/new?email={{ $user->email }}"><button type="button" class="btn btn-success btn-sm">Add New Server</button></a>
</div> </div>
</div> </div>
<div class="row"> <div class="row">