Update repository base code to be cleaner and make use of PHP 7 features

This commit is contained in:
Dane Everitt 2018-01-04 22:49:50 -06:00
parent 0ec5a4e08c
commit 60eb60013c
No known key found for this signature in database
GPG key ID: EEA66103B3D71F53
96 changed files with 1048 additions and 1785 deletions

View file

@ -1,30 +1,36 @@
<?php
/**
* Pterodactyl - Panel
* Copyright (c) 2015 - 2017 Dane Everitt <dane@daneeveritt.com>.
*
* This software is licensed under the terms of the MIT license.
* https://opensource.org/licenses/MIT
*/
namespace Pterodactyl\Repositories\Concerns;
trait Searchable
{
/**
* The term to search.
* The search term to use when filtering results.
*
* @var bool|string
* @var null|string
*/
protected $searchTerm = false;
protected $searchTerm;
/**
* Perform a search of the model using the given term.
* Set the search term.
*
* @param string $term
* @param string|null $term
* @return $this
* @deprecated
*/
public function search($term)
{
return $this->setSearchTerm($term);
}
/**
* Set the search term to use when requesting all records from
* the model.
*
* @param string|null $term
* @return $this
*/
public function setSearchTerm(string $term = null)
{
if (empty($term)) {
return $this;
@ -35,4 +41,24 @@ trait Searchable
return $clone;
}
/**
* Determine if a valid search term is set on this repository.
*
* @return bool
*/
public function hasSearchTerm(): bool
{
return ! empty($this->searchTerm);
}
/**
* Return the search term.
*
* @return string|null
*/
public function getSearchTerm()
{
return $this->searchTerm;
}
}

View file

@ -1,11 +1,4 @@
<?php
/**
* Pterodactyl - Panel
* Copyright (c) 2015 - 2017 Dane Everitt <dane@daneeveritt.com>.
*
* This software is licensed under the terms of the MIT license.
* https://opensource.org/licenses/MIT
*/
namespace Pterodactyl\Repositories\Daemon;

View file

@ -1,21 +1,17 @@
<?php
/**
* Pterodactyl - Panel
* Copyright (c) 2015 - 2017 Dane Everitt <dane@daneeveritt.com>.
*
* This software is licensed under the terms of the MIT license.
* https://opensource.org/licenses/MIT
*/
namespace Pterodactyl\Repositories\Eloquent;
use Illuminate\Support\Collection;
use Pterodactyl\Models\Allocation;
use Pterodactyl\Contracts\Repository\AllocationRepositoryInterface;
class AllocationRepository extends EloquentRepository implements AllocationRepositoryInterface
{
/**
* {@inheritdoc}
* Return the model backing this repository.
*
* @return string
*/
public function model()
{
@ -23,18 +19,25 @@ class AllocationRepository extends EloquentRepository implements AllocationRepos
}
/**
* {@inheritdoc}
* Set an array of allocation IDs to be assigned to a specific server.
*
* @param int|null $server
* @param array $ids
* @return int
*/
public function assignAllocationsToServer($server, array $ids)
public function assignAllocationsToServer(int $server = null, array $ids): int
{
return $this->getBuilder()->whereIn('id', $ids)->update(['server_id' => $server]);
}
/**
* {@inheritdoc}
* Return all of the allocations for a specific node.
*
* @param int $node
* @return \Illuminate\Support\Collection
*/
public function getAllocationsForNode($node)
public function getAllocationsForNode(int $node): Collection
{
return $this->getBuilder()->where('node_id', $node)->get();
return $this->getBuilder()->where('node_id', $node)->get($this->getColumns());
}
}

View file

@ -1,11 +1,4 @@
<?php
/**
* Pterodactyl - Panel
* Copyright (c) 2015 - 2017 Dane Everitt <dane@daneeveritt.com>.
*
* This software is licensed under the terms of the MIT license.
* https://opensource.org/licenses/MIT
*/
namespace Pterodactyl\Repositories\Eloquent;
@ -15,7 +8,9 @@ use Pterodactyl\Contracts\Repository\ApiKeyRepositoryInterface;
class ApiKeyRepository extends EloquentRepository implements ApiKeyRepositoryInterface
{
/**
* {@inheritdoc}
* Return the model backing this repository.
*
* @return string
*/
public function model()
{

View file

@ -1,11 +1,4 @@
<?php
/**
* Pterodactyl - Panel
* Copyright (c) 2015 - 2017 Dane Everitt <dane@daneeveritt.com>.
*
* This software is licensed under the terms of the MIT license.
* https://opensource.org/licenses/MIT
*/
namespace Pterodactyl\Repositories\Eloquent;
@ -15,7 +8,9 @@ use Pterodactyl\Contracts\Repository\ApiPermissionRepositoryInterface;
class ApiPermissionRepository extends EloquentRepository implements ApiPermissionRepositoryInterface
{
/**
* {@inheritdoc}
* Return the model backing this repository.
*
* @return string
*/
public function model()
{

View file

@ -1,26 +1,4 @@
<?php
/*
* Pterodactyl - Panel
* Copyright (c) 2015 - 2017 Dane Everitt <dane@daneeveritt.com>.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
namespace Pterodactyl\Repositories\Eloquent;
@ -28,13 +6,16 @@ use Pterodactyl\Models\User;
use Webmozart\Assert\Assert;
use Pterodactyl\Models\DaemonKey;
use Illuminate\Support\Collection;
use Illuminate\Database\Eloquent\ModelNotFoundException;
use Pterodactyl\Exceptions\Repository\RecordNotFoundException;
use Pterodactyl\Contracts\Repository\DaemonKeyRepositoryInterface;
class DaemonKeyRepository extends EloquentRepository implements DaemonKeyRepositoryInterface
{
/**
* {@inheritdoc}
* Return the model backing this repository.
*
* @return string
*/
public function model()
{
@ -62,28 +43,22 @@ class DaemonKeyRepository extends EloquentRepository implements DaemonKeyReposit
}
/**
* {@inheritdoc}
* Return a daemon key with the associated server relation attached.
*
* @param string $key
* @return \Pterodactyl\Models\DaemonKey
*
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
*/
public function getServerKeys($server)
public function getKeyWithServer(string $key): DaemonKey
{
Assert::integerish($server, 'First argument passed to getServerKeys must be integer, received %s.');
Assert::notEmpty($key, 'Expected non-empty string as first argument passed to ' . __METHOD__);
return $this->getBuilder()->where('server_id', $server)->get($this->getColumns());
}
/**
* {@inheritdoc}
*/
public function getKeyWithServer($key)
{
Assert::stringNotEmpty($key, 'First argument passed to getServerByKey must be string, received %s.');
$instance = $this->getBuilder()->with('server')->where('secret', '=', $key)->first();
if (is_null($instance)) {
try {
return $this->getBuilder()->with('server')->where('secret', '=', $key)->firstOrFail($this->getColumns());
} catch (ModelNotFoundException $exception) {
throw new RecordNotFoundException;
}
return $instance;
}
/**

View file

@ -1,23 +1,19 @@
<?php
/**
* Pterodactyl - Panel
* Copyright (c) 2015 - 2017 Dane Everitt <dane@daneeveritt.com>.
*
* This software is licensed under the terms of the MIT license.
* https://opensource.org/licenses/MIT
*/
namespace Pterodactyl\Repositories\Eloquent;
use Webmozart\Assert\Assert;
use Illuminate\Support\Collection;
use Pterodactyl\Models\DatabaseHost;
use Illuminate\Database\Eloquent\ModelNotFoundException;
use Pterodactyl\Exceptions\Repository\RecordNotFoundException;
use Pterodactyl\Contracts\Repository\DatabaseHostRepositoryInterface;
class DatabaseHostRepository extends EloquentRepository implements DatabaseHostRepositoryInterface
{
/**
* {@inheritdoc}
* Return the model backing this repository.
*
* @return string
*/
public function model()
{
@ -25,25 +21,31 @@ class DatabaseHostRepository extends EloquentRepository implements DatabaseHostR
}
/**
* {@inheritdoc}
* Return database hosts with a count of databases and the node
* information for which it is attached.
*
* @return \Illuminate\Support\Collection
*/
public function getWithViewDetails()
public function getWithViewDetails(): Collection
{
return $this->getBuilder()->withCount('databases')->with('node')->get();
}
/**
* {@inheritdoc}
* Return a database host with the databases and associated servers
* that are attached to said databases.
*
* @param int $id
* @return \Pterodactyl\Models\DatabaseHost
*
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
*/
public function getWithServers($id)
public function getWithServers(int $id): DatabaseHost
{
Assert::numeric($id, 'First argument passed to getWithServers must be numeric, recieved %s.');
$instance = $this->getBuilder()->with('databases.server')->find($id, $this->getColumns());
if (! $instance) {
throw new RecordNotFoundException();
try {
return $this->getBuilder()->with('databases.server')->findOrFail($id, $this->getColumns());
} catch (ModelNotFoundException $exception) {
throw new RecordNotFoundException;
}
return $instance;
}
}

View file

@ -1,11 +1,4 @@
<?php
/**
* Pterodactyl - Panel
* Copyright (c) 2015 - 2017 Dane Everitt <dane@daneeveritt.com>.
*
* This software is licensed under the terms of the MIT license.
* https://opensource.org/licenses/MIT
*/
namespace Pterodactyl\Repositories\Eloquent;
@ -34,17 +27,17 @@ class DatabaseRepository extends EloquentRepository implements DatabaseRepositor
* @param \Illuminate\Foundation\Application $application
* @param \Illuminate\Database\DatabaseManager $database
*/
public function __construct(
Application $application,
DatabaseManager $database
) {
public function __construct(Application $application, DatabaseManager $database)
{
parent::__construct($application);
$this->database = $database;
}
/**
* {@inheritdoc}
* Return the model backing this repository.
*
* @return string
*/
public function model()
{
@ -86,18 +79,24 @@ class DatabaseRepository extends EloquentRepository implements DatabaseRepositor
}
/**
* {@inheritdoc}
* @return bool|\Illuminate\Database\Eloquent\Model
* Create a new database if it does not already exist on the host with
* the provided details.
*
* @param array $data
* @return \Pterodactyl\Models\Database
*
* @throws \Pterodactyl\Exceptions\Model\DataValidationException
* @throws \Pterodactyl\Exceptions\Repository\DuplicateDatabaseNameException
*/
public function createIfNotExists(array $data)
public function createIfNotExists(array $data): Database
{
$instance = $this->getBuilder()->where([
$count = $this->getBuilder()->where([
['server_id', '=', array_get($data, 'server_id')],
['database_host_id', '=', array_get($data, 'database_host_id')],
['database', '=', array_get($data, 'database')],
])->count();
if ($instance > 0) {
if ($count > 0) {
throw new DuplicateDatabaseNameException('A database with those details already exists for the specified server.');
}
@ -105,27 +104,40 @@ class DatabaseRepository extends EloquentRepository implements DatabaseRepositor
}
/**
* {@inheritdoc}
* Create a new database on a given connection.
*
* @param string $database
* @return bool
*/
public function createDatabase($database)
public function createDatabase(string $database): bool
{
return $this->runStatement(sprintf('CREATE DATABASE IF NOT EXISTS `%s`', $database));
return $this->run(sprintf('CREATE DATABASE IF NOT EXISTS `%s`', $database));
}
/**
* {@inheritdoc}
* Create a new database user on a given connection.
*
* @param string $username
* @param string $remote
* @param string $password
* @return bool
*/
public function createUser($username, $remote, $password)
public function createUser(string $username, string $remote, string $password): bool
{
return $this->runStatement(sprintf('CREATE USER `%s`@`%s` IDENTIFIED BY \'%s\'', $username, $remote, $password));
return $this->run(sprintf('CREATE USER `%s`@`%s` IDENTIFIED BY \'%s\'', $username, $remote, $password));
}
/**
* {@inheritdoc}
* Give a specific user access to a given database.
*
* @param string $database
* @param string $username
* @param string $remote
* @return bool
*/
public function assignUserToDatabase($database, $username, $remote)
public function assignUserToDatabase(string $database, string $username, string $remote): bool
{
return $this->runStatement(sprintf(
return $this->run(sprintf(
'GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, ALTER, INDEX, EXECUTE ON `%s`.* TO `%s`@`%s`',
$database,
$username,
@ -134,27 +146,36 @@ class DatabaseRepository extends EloquentRepository implements DatabaseRepositor
}
/**
* {@inheritdoc}
* Flush the privileges for a given connection.
*
* @return bool
*/
public function flush()
public function flush(): bool
{
return $this->runStatement('FLUSH PRIVILEGES');
return $this->run('FLUSH PRIVILEGES');
}
/**
* {@inheritdoc}
* Drop a given database on a specific connection.
*
* @param string $database
* @return bool
*/
public function dropDatabase($database)
public function dropDatabase(string $database): bool
{
return $this->runStatement(sprintf('DROP DATABASE IF EXISTS `%s`', $database));
return $this->run(sprintf('DROP DATABASE IF EXISTS `%s`', $database));
}
/**
* {@inheritdoc}
* Drop a given user on a specific connection.
*
* @param string $username
* @param string $remote
* @return mixed
*/
public function dropUser($username, $remote)
public function dropUser(string $username, string $remote): bool
{
return $this->runStatement(sprintf('DROP USER IF EXISTS `%s`@`%s`', $username, $remote));
return $this->run(sprintf('DROP USER IF EXISTS `%s`@`%s`', $username, $remote));
}
/**
@ -163,7 +184,7 @@ class DatabaseRepository extends EloquentRepository implements DatabaseRepositor
* @param string $statement
* @return bool
*/
protected function runStatement($statement)
private function run(string $statement): bool
{
return $this->database->connection($this->getConnection())->statement($statement);
}

View file

@ -1,24 +1,20 @@
<?php
/**
* Pterodactyl - Panel
* Copyright (c) 2015 - 2017 Dane Everitt <dane@daneeveritt.com>.
*
* This software is licensed under the terms of the MIT license.
* https://opensource.org/licenses/MIT
*/
namespace Pterodactyl\Repositories\Eloquent;
use Pterodactyl\Models\Egg;
use Webmozart\Assert\Assert;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Database\Eloquent\ModelNotFoundException;
use Pterodactyl\Contracts\Repository\EggRepositoryInterface;
use Pterodactyl\Exceptions\Repository\RecordNotFoundException;
class EggRepository extends EloquentRepository implements EggRepositoryInterface
{
/**
* {@inheritdoc}
* Return the model backing this repository.
*
* @return string
*/
public function model()
{
@ -35,13 +31,11 @@ class EggRepository extends EloquentRepository implements EggRepositoryInterface
*/
public function getWithVariables(int $id): Egg
{
/** @var \Pterodactyl\Models\Egg $instance */
$instance = $this->getBuilder()->with('variables')->find($id, $this->getColumns());
if (! $instance) {
try {
return $this->getBuilder()->with('variables')->firstOrFail($id, $this->getColumns());
} catch (ModelNotFoundException $exception) {
throw new RecordNotFoundException;
}
return $instance;
}
/**
@ -67,13 +61,11 @@ class EggRepository extends EloquentRepository implements EggRepositoryInterface
{
Assert::true((is_digit($value) || is_string($value)), 'First argument passed to getWithCopyAttributes must be an integer or string, received %s.');
/** @var \Pterodactyl\Models\Egg $instance */
$instance = $this->getBuilder()->with('scriptFrom', 'configFrom')->where($column, '=', $value)->first($this->getColumns());
if (! $instance) {
try {
return $this->getBuilder()->with('scriptFrom', 'configFrom')->where($column, '=', $value)->firstOrFail($this->getColumns());
} catch (ModelNotFoundException $exception) {
throw new RecordNotFoundException;
}
return $instance;
}
/**
@ -86,13 +78,11 @@ class EggRepository extends EloquentRepository implements EggRepositoryInterface
*/
public function getWithExportAttributes(int $id): Egg
{
/** @var \Pterodactyl\Models\Egg $instance */
$instance = $this->getBuilder()->with('scriptFrom', 'configFrom', 'variables')->find($id, $this->getColumns());
if (! $instance) {
try {
return $this->getBuilder()->with('scriptFrom', 'configFrom', 'variables')->find($id, $this->getColumns());
} catch (ModelNotFoundException $exception) {
throw new RecordNotFoundException;
}
return $instance;
}
/**

View file

@ -1,11 +1,4 @@
<?php
/**
* Pterodactyl - Panel
* Copyright (c) 2015 - 2017 Dane Everitt <dane@daneeveritt.com>.
*
* This software is licensed under the terms of the MIT license.
* https://opensource.org/licenses/MIT
*/
namespace Pterodactyl\Repositories\Eloquent;
@ -16,7 +9,9 @@ use Pterodactyl\Contracts\Repository\EggVariableRepositoryInterface;
class EggVariableRepository extends EloquentRepository implements EggVariableRepositoryInterface
{
/**
* {@inheritdoc}
* Return the model backing this repository.
*
* @return string
*/
public function model()
{

View file

@ -1,17 +1,12 @@
<?php
/**
* Pterodactyl - Panel
* Copyright (c) 2015 - 2017 Dane Everitt <dane@daneeveritt.com>.
*
* This software is licensed under the terms of the MIT license.
* https://opensource.org/licenses/MIT
*/
namespace Pterodactyl\Repositories\Eloquent;
use Webmozart\Assert\Assert;
use Illuminate\Support\Collection;
use Pterodactyl\Repositories\Repository;
use Illuminate\Database\Query\Expression;
use Illuminate\Database\Eloquent\ModelNotFoundException;
use Pterodactyl\Contracts\Repository\RepositoryInterface;
use Pterodactyl\Exceptions\Model\DataValidationException;
use Pterodactyl\Exceptions\Repository\RecordNotFoundException;
@ -20,7 +15,19 @@ use Pterodactyl\Contracts\Repository\Attributes\SearchableInterface;
abstract class EloquentRepository extends Repository implements RepositoryInterface
{
/**
* {@inheritdoc}
* Return an instance of the eloquent model bound to this
* repository instance.
*
* @return \Illuminate\Database\Eloquent\Model
*/
public function getModel()
{
return $this->model;
}
/**
* Return an instance of the builder to use for this repository.
*
* @return \Illuminate\Database\Eloquent\Builder
*/
public function getBuilder()
@ -29,22 +36,19 @@ abstract class EloquentRepository extends Repository implements RepositoryInterf
}
/**
* {@inheritdoc}
* @param bool $force
* Create a new record in the database and return the associated model.
*
* @param array $fields
* @param bool $validate
* @param bool $force
* @return \Illuminate\Database\Eloquent\Model|bool
*
* @throws \Pterodactyl\Exceptions\Model\DataValidationException
*/
public function create(array $fields, $validate = true, $force = false)
public function create(array $fields, bool $validate = true, bool $force = false)
{
Assert::boolean($validate, 'Second argument passed to create must be boolean, recieved %s.');
Assert::boolean($force, 'Third argument passed to create must be boolean, received %s.');
$instance = $this->getBuilder()->newModelInstance();
if ($force) {
$instance->forceFill($fields);
} else {
$instance->fill($fields);
}
($force) ? $instance->forceFill($fields) : $instance->fill($fields);
if (! $validate) {
$saved = $instance->skipValidation()->save();
@ -58,99 +62,108 @@ abstract class EloquentRepository extends Repository implements RepositoryInterf
}
/**
* {@inheritdoc}
* @return \Illuminate\Database\Eloquent\Builder|\Illuminate\Database\Eloquent\Model
* Find a model that has the specific ID passed.
*
* @param int $id
* @return \Illuminate\Database\Eloquent\Model
*
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
*/
public function find($id)
public function find(int $id)
{
Assert::numeric($id, 'First argument passed to find must be numeric, received %s.');
$instance = $this->getBuilder()->find($id, $this->getColumns());
if (! $instance) {
throw new RecordNotFoundException();
try {
return $this->getBuilder()->findOrFail($id, $this->getColumns());
} catch (ModelNotFoundException $exception) {
throw new RecordNotFoundException;
}
return $instance;
}
/**
* {@inheritdoc}
* @return \Illuminate\Database\Eloquent\Collection
* Find a model matching an array of where clauses.
*
* @param array $fields
* @return \Illuminate\Support\Collection
*/
public function findWhere(array $fields)
public function findWhere(array $fields): Collection
{
return $this->getBuilder()->where($fields)->get($this->getColumns());
}
/**
* {@inheritdoc}
* Find and return the first matching instance for the given fields.
*
* @param array $fields
* @return \Illuminate\Database\Eloquent\Model
*
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
*/
public function findFirstWhere(array $fields)
{
$instance = $this->getBuilder()->where($fields)->first($this->getColumns());
if (! $instance) {
try {
return $this->getBuilder()->where($fields)->firstOrFail($this->getColumns());
} catch (ModelNotFoundException $exception) {
throw new RecordNotFoundException;
}
return $instance;
}
/**
* {@inheritdoc}.
* Return a count of records matching the passed arguments.
*
* @param array $fields
* @return int
*/
public function findCountWhere(array $fields)
public function findCountWhere(array $fields): int
{
return $this->getBuilder()->where($fields)->count($this->getColumns());
}
/**
* {@inheritdoc}
* Delete a given record from the database.
*
* @param int $id
* @param bool $destroy
* @return int
*/
public function delete($id, $destroy = false)
public function delete(int $id, bool $destroy = false): int
{
Assert::numeric($id, 'First argument passed to delete must be numeric, received %s.');
Assert::boolean($destroy, 'Second argument passed to delete must be boolean, received %s.');
$instance = $this->getBuilder()->where($this->getModel()->getKeyName(), $id);
return ($destroy) ? $instance->forceDelete() : $instance->delete();
return $this->deleteWhere(['id' => $id], $destroy);
}
/**
* {@inheritdoc}
* Delete records matching the given attributes.
*
* @param array $attributes
* @param bool $force
* @return int
*/
public function deleteWhere(array $attributes, $force = false)
public function deleteWhere(array $attributes, bool $force = false): int
{
Assert::boolean($force, 'Second argument passed to deleteWhere must be boolean, received %s.');
$instance = $this->getBuilder()->where($attributes);
return ($force) ? $instance->forceDelete() : $instance->delete();
}
/**
* {@inheritdoc}
* Update a given ID with the passed array of fields.
*
* @param int $id
* @param array $fields
* @param bool $validate
* @param bool $force
* @return \Illuminate\Database\Eloquent\Model|bool
*
* @throws \Pterodactyl\Exceptions\Model\DataValidationException
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
*/
public function update($id, array $fields, $validate = true, $force = false)
public function update($id, array $fields, bool $validate = true, bool $force = false)
{
Assert::numeric($id, 'First argument passed to update must be numeric, received %s.');
Assert::boolean($validate, 'Third argument passed to update must be boolean, received %s.');
Assert::boolean($force, 'Fourth argument passed to update must be boolean, received %s.');
$instance = $this->getBuilder()->where('id', $id)->first();
if (! $instance) {
throw new RecordNotFoundException();
try {
$instance = $this->getBuilder()->where('id', $id)->firstOrFail();
} catch (ModelNotFoundException $exception) {
throw new RecordNotFoundException;
}
if ($force) {
$instance->forceFill($fields);
} else {
$instance->fill($fields);
}
($force) ? $instance->forceFill($fields) : $instance->fill($fields);
if (! $validate) {
$saved = $instance->skipValidation()->save();
@ -164,40 +177,71 @@ abstract class EloquentRepository extends Repository implements RepositoryInterf
}
/**
* {@inheritdoc}
* Perform a mass update where matching records are updated using whereIn.
* This does not perform any model data validation.
*
* @param string $column
* @param array $values
* @param array $fields
* @return int
*/
public function updateWhereIn($column, array $values, array $fields)
public function updateWhereIn(string $column, array $values, array $fields): int
{
Assert::stringNotEmpty($column, 'First argument passed to updateWhereIn must be a non-empty string, received %s.');
Assert::notEmpty($column, 'First argument passed to updateWhereIn must be a non-empty string.');
return $this->getBuilder()->whereIn($column, $values)->update($fields);
}
/**
* {@inheritdoc}
* Update a record if it exists in the database, otherwise create it.
*
* @param array $where
* @param array $fields
* @param bool $validate
* @param bool $force
* @return \Illuminate\Database\Eloquent\Model
*
* @throws \Pterodactyl\Exceptions\Model\DataValidationException
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
*/
public function massUpdate(array $where, array $fields)
public function updateOrCreate(array $where, array $fields, bool $validate = true, bool $force = false)
{
// TODO: Implement massUpdate() method.
foreach ($where as $item) {
Assert::true(is_scalar($item) || is_null($item), 'First argument passed to updateOrCreate should be an array of scalar or null values, received an array value of %s.');
}
try {
$instance = $this->setColumns('id')->findFirstWhere($where);
} catch (RecordNotFoundException $exception) {
return $this->create(array_merge($where, $fields), $validate, $force);
}
return $this->update($instance->id, $fields, $validate, $force);
}
/**
* {@inheritdoc}
* Return all records associated with the given model.
*
* @return \Illuminate\Support\Collection
*/
public function all()
public function all(): Collection
{
$instance = $this->getBuilder();
if (is_subclass_of(get_called_class(), SearchableInterface::class)) {
$instance = $instance->search($this->searchTerm);
if (is_subclass_of(get_called_class(), SearchableInterface::class) && $this->hasSearchTerm()) {
$instance = $instance->setSearchTerm($this->getSearchTerm());
}
return $instance->get($this->getColumns());
}
/**
* {@inheritdoc}
* Insert a single or multiple records into the database at once skipping
* validation and mass assignment checking.
*
* @param array $data
* @return bool
*/
public function insert(array $data)
public function insert(array $data): bool
{
return $this->getBuilder()->insert($data);
}
@ -208,19 +252,15 @@ abstract class EloquentRepository extends Repository implements RepositoryInterf
* @param array $values
* @return bool
*/
public function insertIgnore(array $values)
public function insertIgnore(array $values): bool
{
if (empty($values)) {
return true;
}
if (! is_array(reset($values))) {
$values = [$values];
} else {
foreach ($values as $key => $value) {
ksort($value);
$values[$key] = $value;
}
foreach ($values as $key => $value) {
ksort($value);
$values[$key] = $value;
}
$bindings = array_values(array_filter(array_flatten($values, 1), function ($binding) {
@ -239,26 +279,4 @@ abstract class EloquentRepository extends Repository implements RepositoryInterf
return $this->getBuilder()->getConnection()->statement($statement, $bindings);
}
/**
* {@inheritdoc}
* @return bool|\Illuminate\Database\Eloquent\Model
*/
public function updateOrCreate(array $where, array $fields, $validate = true, $force = false)
{
Assert::boolean($validate, 'Third argument passed to updateOrCreate must be boolean, received %s.');
Assert::boolean($force, 'Fourth argument passed to updateOrCreate must be boolean, received %s.');
foreach ($where as $item) {
Assert::true(is_scalar($item) || is_null($item), 'First argument passed to updateOrCreate should be an array of scalar or null values, received an array value of %s.');
}
$instance = $this->withColumns('id')->findWhere($where)->first();
if (! $instance) {
return $this->create(array_merge($where, $fields), $validate, $force);
}
return $this->update($instance->id, $fields, $validate, $force);
}
}

View file

@ -1,16 +1,11 @@
<?php
/**
* Pterodactyl - Panel
* Copyright (c) 2015 - 2017 Dane Everitt <dane@daneeveritt.com>.
*
* This software is licensed under the terms of the MIT license.
* https://opensource.org/licenses/MIT
*/
namespace Pterodactyl\Repositories\Eloquent;
use Pterodactyl\Models\Location;
use Illuminate\Support\Collection;
use Pterodactyl\Repositories\Concerns\Searchable;
use Illuminate\Database\Eloquent\ModelNotFoundException;
use Pterodactyl\Exceptions\Repository\RecordNotFoundException;
use Pterodactyl\Contracts\Repository\LocationRepositoryInterface;
@ -19,7 +14,9 @@ class LocationRepository extends EloquentRepository implements LocationRepositor
use Searchable;
/**
* {@inheritdoc}
* Return the model backing this repository.
*
* @return string
*/
public function model()
{
@ -27,44 +24,56 @@ class LocationRepository extends EloquentRepository implements LocationRepositor
}
/**
* {@inheritdoc}
* Return locations with a count of nodes and servers attached to it.
*
* @return \Illuminate\Support\Collection
*/
public function getAllWithDetails()
public function getAllWithDetails(): Collection
{
return $this->getBuilder()->withCount('nodes', 'servers')->get($this->getColumns());
}
/**
* {@inheritdoc}
* Return all of the available locations with the nodes as a relationship.
*
* @return \Illuminate\Support\Collection
*/
public function getAllWithNodes()
public function getAllWithNodes(): Collection
{
return $this->getBuilder()->with('nodes')->get($this->getColumns());
}
/**
* {@inheritdoc}
* Return all of the nodes and their respective count of servers for a location.
*
* @param int $id
* @return mixed
*
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
*/
public function getWithNodes($id)
public function getWithNodes(int $id): Location
{
$instance = $this->getBuilder()->with('nodes.servers')->find($id, $this->getColumns());
if (! $instance) {
try {
return $this->getBuilder()->with('nodes.servers')->findOrFail($id, $this->getColumns());
} catch (ModelNotFoundException $exception) {
throw new RecordNotFoundException;
}
return $instance;
}
/**
* {@inheritdoc}
* Return a location and the count of nodes in that location.
*
* @param int $id
* @return mixed
*
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
*/
public function getWithNodeCount($id)
public function getWithNodeCount(int $id): Location
{
$instance = $this->getBuilder()->withCount('nodes')->find($id, $this->getColumns());
if (! $instance) {
try {
return $this->getBuilder()->withCount('nodes')->findOrFail($id, $this->getColumns());
} catch (ModelNotFoundException $exception) {
throw new RecordNotFoundException;
}
return $instance;
}
}

View file

@ -16,7 +16,9 @@ use Pterodactyl\Exceptions\Repository\RecordNotFoundException;
class NestRepository extends EloquentRepository implements NestRepositoryInterface
{
/**
* {@inheritdoc}
* Return the model backing this repository.
*
* @return string
*/
public function model()
{

View file

@ -1,16 +1,12 @@
<?php
/**
* Pterodactyl - Panel
* Copyright (c) 2015 - 2017 Dane Everitt <dane@daneeveritt.com>.
*
* This software is licensed under the terms of the MIT license.
* https://opensource.org/licenses/MIT
*/
namespace Pterodactyl\Repositories\Eloquent;
use Pterodactyl\Models\Node;
use Illuminate\Support\Collection;
use Pterodactyl\Repositories\Concerns\Searchable;
use Illuminate\Database\Eloquent\ModelNotFoundException;
use Illuminate\Contracts\Pagination\LengthAwarePaginator;
use Pterodactyl\Contracts\Repository\NodeRepositoryInterface;
use Pterodactyl\Exceptions\Repository\RecordNotFoundException;
@ -18,11 +14,10 @@ class NodeRepository extends EloquentRepository implements NodeRepositoryInterfa
{
use Searchable;
const THRESHOLD_PERCENTAGE_LOW = 75;
const THRESHOLD_PERCENTAGE_MEDIUM = 90;
/**
* {@inheritdoc}
* Return the model backing this repository.
*
* @return string
*/
public function model()
{
@ -30,113 +25,121 @@ class NodeRepository extends EloquentRepository implements NodeRepositoryInterfa
}
/**
* {@inheritdoc}
* Return the usage stats for a single node.
*
* @param \Pterodactyl\Models\Node $node
* @return array
*/
public function getUsageStats($id)
public function getUsageStats(Node $node): array
{
$node = $this->getBuilder()->select([
'nodes.disk_overallocate',
'nodes.memory_overallocate',
'nodes.disk',
'nodes.memory',
])->where('id', $id)->first();
$stats = $this->getBuilder()->select(
$this->getBuilder()->raw('IFNULL(SUM(servers.memory), 0) as sum_memory, IFNULL(SUM(servers.disk), 0) as sum_disk')
)->join('servers', 'servers.node_id', '=', 'nodes.id')->where('node_id', $id)->first();
)->join('servers', 'servers.node_id', '=', 'nodes.id')->where('node_id', $node->id)->first();
return collect(['disk' => $stats->sum_disk, 'memory' => $stats->sum_memory])
->mapWithKeys(function ($value, $key) use ($node) {
$maxUsage = $node->{$key};
if ($node->{$key . '_overallocate'} > 0) {
$maxUsage = $node->{$key} * (1 + ($node->{$key . '_overallocate'} / 100));
}
return collect(['disk' => $stats->sum_disk, 'memory' => $stats->sum_memory])->mapWithKeys(function ($value, $key) use ($node) {
$maxUsage = $node->{$key};
if ($node->{$key . '_overallocate'} > 0) {
$maxUsage = $node->{$key} * (1 + ($node->{$key . '_overallocate'} / 100));
}
$percent = ($value / $maxUsage) * 100;
$percent = ($value / $maxUsage) * 100;
return [
$key => [
'value' => number_format($value),
'max' => number_format($maxUsage),
'percent' => $percent,
'css' => ($percent <= self::THRESHOLD_PERCENTAGE_LOW) ? 'green' : (($percent > self::THRESHOLD_PERCENTAGE_MEDIUM) ? 'red' : 'yellow'),
],
];
})
->toArray();
return [
$key => [
'value' => number_format($value),
'max' => number_format($maxUsage),
'percent' => $percent,
'css' => ($percent <= self::THRESHOLD_PERCENTAGE_LOW) ? 'green' : (($percent > self::THRESHOLD_PERCENTAGE_MEDIUM) ? 'red' : 'yellow'),
],
];
})->toArray();
}
/**
* {@inheritdoc}
* Return all available nodes with a searchable interface.
*
* @return \Illuminate\Contracts\Pagination\LengthAwarePaginator
*/
public function getNodeListingData($count = 25)
public function getNodeListingData(): LengthAwarePaginator
{
$instance = $this->getBuilder()->with('location')->withCount('servers');
if ($this->searchTerm) {
$instance->search($this->searchTerm);
if ($this->hasSearchTerm()) {
$instance->setSearchTerm($this->getSearchTerm());
}
return $instance->paginate($count, $this->getColumns());
return $instance->paginate(25, $this->getColumns());
}
/**
* {@inheritdoc}
* Return a single node with location and server information.
*
* @param \Pterodactyl\Models\Node $node
* @param bool $refresh
* @return \Pterodactyl\Models\Node
*/
public function getSingleNode($id)
public function loadLocationAndServerCount(Node $node, bool $refresh = false): Node
{
$instance = $this->getBuilder()->with('location')->withCount('servers')->find($id, $this->getColumns());
if (! $instance) {
throw new RecordNotFoundException();
if (! $node->relationLoaded('location') || $refresh) {
$node->load('location');
}
return $instance;
// This is quite ugly and can probably be improved down the road.
// And by probably, I mean it should.
if (is_null($node->servers_count) || $refresh) {
$node->load('servers');
$node->setRelation('servers_count', count($node->getRelation('servers')));
unset($node->servers);
}
return $node;
}
/**
* {@inheritdoc}
* Attach a paginated set of allocations to a node mode including
* any servers that are also attached to those allocations.
*
* @param \Pterodactyl\Models\Node $node
* @param bool $refresh
* @return \Pterodactyl\Models\Node
*/
public function getNodeAllocations($id)
public function loadNodeAllocations(Node $node, bool $refresh = false): Node
{
$instance = $this->getBuilder()->find($id, $this->getColumns());
if (! $instance) {
throw new RecordNotFoundException();
}
$instance->setRelation(
'allocations',
$instance->allocations()->orderBy('ip', 'asc')->orderBy('port', 'asc')->with('server')->paginate(50)
$node->setRelation('allocations',
$node->allocations()->orderBy('ip', 'asc')->orderBy('port', 'asc')->with('server')->paginate(50)
);
return $instance;
return $node;
}
/**
* {@inheritdoc}
* Return a node with all of the servers attached to that node.
*
* @param int $id
* @return \Pterodactyl\Models\Node
*
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
*/
public function getNodeServers($id)
public function getNodeServers(int $id): Node
{
$instance = $this->getBuilder()->with('servers.user', 'servers.nest', 'servers.egg')
->find($id, $this->getColumns());
if (! $instance) {
throw new RecordNotFoundException();
try {
return $this->getBuilder()->with([
'servers.user', 'servers.nest', 'servers.egg',
])->findOrFail($id, $this->getColumns());
} catch (ModelNotFoundException $exception) {
throw new RecordNotFoundException;
}
return $instance;
}
/**
* {@inheritdoc}
* Return a collection of nodes for all locations to use in server creation UI.
*
* @return \Illuminate\Support\Collection
*/
public function getNodesForServerCreation()
public function getNodesForServerCreation(): Collection
{
$instance = $this->getBuilder()->with('allocations')->get();
return $instance->map(function ($item) {
$filtered = $item->allocations->where('server_id', null)->map(function ($map) {
return $this->getBuilder()->with('allocations')->get()->map(function (Node $item) {
$filtered = $item->getRelation('allocations')->where('server_id', null)->map(function ($map) {
return collect($map)->only(['id', 'ip', 'port']);
});

View file

@ -1,27 +1,20 @@
<?php
/**
* Pterodactyl - Panel
* Copyright (c) 2015 - 2017 Dane Everitt <dane@daneeveritt.com>.
*
* This software is licensed under the terms of the MIT license.
* https://opensource.org/licenses/MIT
*/
namespace Pterodactyl\Repositories\Eloquent;
use Pterodactyl\Models\Pack;
use Webmozart\Assert\Assert;
use Pterodactyl\Repositories\Concerns\Searchable;
use Illuminate\Database\Eloquent\ModelNotFoundException;
use Illuminate\Contracts\Pagination\LengthAwarePaginator;
use Pterodactyl\Contracts\Repository\PackRepositoryInterface;
use Illuminate\Contracts\Filesystem\Factory as FilesystemFactory;
class PackRepository extends EloquentRepository implements PackRepositoryInterface
{
use Searchable;
/**
* {@inheritdoc}
* Return the model backing this repository.
*
* @return string
*/
public function model()
{
@ -29,58 +22,32 @@ class PackRepository extends EloquentRepository implements PackRepositoryInterfa
}
/**
* {@inheritdoc}
* Return a pack with the associated server models attached to it.
*
* @param \Pterodactyl\Models\Pack $pack
* @param bool $refresh
* @return \Pterodactyl\Models\Pack
*/
public function getFileArchives($id, $collection = false)
public function loadServerData(Pack $pack, bool $refresh = false): Pack
{
Assert::numeric($id, 'First argument passed to getFileArchives must be numeric, received %s.');
Assert::boolean($collection, 'Second argument passed to getFileArchives must be boolean, received %s.');
$pack = $this->getBuilder()->find($id, ['id', 'uuid']);
if (! $pack) {
throw new ModelNotFoundException;
if ($refresh) {
$pack->load(['servers.node', 'servers.user']);
}
$storage = $this->app->make(FilesystemFactory::class);
$files = collect($storage->disk('default')->files('packs/' . $pack->uuid));
$pack->loadMissing(['servers.node', 'servers.user']);
$files = $files->map(function ($file) {
$path = storage_path('app/' . $file);
return (object) [
'name' => basename($file),
'hash' => sha1_file($path),
'size' => human_readable($path),
];
});
return ($collection) ? $files : (object) $files->all();
return $pack;
}
/**
* {@inheritdoc}
* Return a paginated listing of packs with their associated egg and server count.
*
* @return \Illuminate\Contracts\Pagination\LengthAwarePaginator
*/
public function getWithServers($id)
public function paginateWithEggAndServerCount(): LengthAwarePaginator
{
Assert::numeric($id, 'First argument passed to getWithServers must be numeric, received %s.');
$instance = $this->getBuilder()->with('servers.node', 'servers.user')->find($id, $this->getColumns());
if (! $instance) {
throw new ModelNotFoundException;
}
return $instance;
}
/**
* {@inheritdoc}
*/
public function paginateWithEggAndServerCount($paginate = 50)
{
Assert::integer($paginate, 'First argument passed to paginateWithOptionAndServerCount must be integer, received %s.');
return $this->getBuilder()->with('egg')->withCount('servers')
->search($this->searchTerm)
->paginate($paginate, $this->getColumns());
->setSearchTerm($this->getSearchTerm())
->paginate(50, $this->getColumns());
}
}

View file

@ -1,11 +1,4 @@
<?php
/**
* Pterodactyl - Panel
* Copyright (c) 2015 - 2017 Dane Everitt <dane@daneeveritt.com>.
*
* This software is licensed under the terms of the MIT license.
* https://opensource.org/licenses/MIT
*/
namespace Pterodactyl\Repositories\Eloquent;
@ -15,7 +8,9 @@ use Pterodactyl\Contracts\Repository\PermissionRepositoryInterface;
class PermissionRepository extends EloquentRepository implements PermissionRepositoryInterface
{
/**
* {@inheritdoc}
* Return the model backing this repository.
*
* @return string
*/
public function model()
{

View file

@ -1,23 +1,19 @@
<?php
/**
* Pterodactyl - Panel
* Copyright (c) 2015 - 2017 Dane Everitt <dane@daneeveritt.com>.
*
* This software is licensed under the terms of the MIT license.
* https://opensource.org/licenses/MIT
*/
namespace Pterodactyl\Repositories\Eloquent;
use Pterodactyl\Models\Schedule;
use Illuminate\Support\Collection;
use Illuminate\Database\Eloquent\ModelNotFoundException;
use Pterodactyl\Exceptions\Repository\RecordNotFoundException;
use Pterodactyl\Contracts\Repository\ScheduleRepositoryInterface;
class ScheduleRepository extends EloquentRepository implements ScheduleRepositoryInterface
{
/**
* {@inheritdoc}
* Return the model backing this repository.
*
* @return string
*/
public function model()
{
@ -45,19 +41,20 @@ class ScheduleRepository extends EloquentRepository implements ScheduleRepositor
*/
public function getScheduleWithTasks(int $schedule): Schedule
{
/** @var \Pterodactyl\Models\Schedule $instance */
$instance = $this->getBuilder()->with('tasks')->find($schedule, $this->getColumns());
if (! $instance) {
try {
return $this->getBuilder()->with('tasks')->findOrFail($schedule, $this->getColumns());
} catch (ModelNotFoundException $exception) {
throw new RecordNotFoundException;
}
return $instance;
}
/**
* {@inheritdoc}
* Return all of the schedules that should be processed.
*
* @param string $timestamp
* @return \Illuminate\Support\Collection
*/
public function getSchedulesToProcess($timestamp)
public function getSchedulesToProcess(string $timestamp): Collection
{
return $this->getBuilder()->with('tasks')
->where('is_active', true)

View file

@ -1,17 +1,14 @@
<?php
/**
* Pterodactyl - Panel
* Copyright (c) 2015 - 2017 Dane Everitt <dane@daneeveritt.com>.
*
* This software is licensed under the terms of the MIT license.
* https://opensource.org/licenses/MIT
*/
namespace Pterodactyl\Repositories\Eloquent;
use Pterodactyl\Models\User;
use Webmozart\Assert\Assert;
use Pterodactyl\Models\Server;
use Illuminate\Support\Collection;
use Pterodactyl\Repositories\Concerns\Searchable;
use Illuminate\Database\Eloquent\ModelNotFoundException;
use Illuminate\Contracts\Pagination\LengthAwarePaginator;
use Pterodactyl\Exceptions\Repository\RecordNotFoundException;
use Pterodactyl\Contracts\Repository\ServerRepositoryInterface;
@ -20,7 +17,9 @@ class ServerRepository extends EloquentRepository implements ServerRepositoryInt
use Searchable;
/**
* {@inheritdoc}
* Return the model backing this repository.
*
* @return string
*/
public function model()
{
@ -28,15 +27,16 @@ class ServerRepository extends EloquentRepository implements ServerRepositoryInt
}
/**
* {@inheritdoc}
* Returns a listing of all servers that exist including relationships.
*
* @param int $paginate
* @return \Illuminate\Contracts\Pagination\LengthAwarePaginator
*/
public function getAllServers($paginate = 25)
public function getAllServers(int $paginate): LengthAwarePaginator
{
Assert::nullOrIntegerish($paginate, 'First argument passed to getAllServers must be integer or null, received %s.');
$instance = $this->getBuilder()->with('node', 'user', 'allocation')->setSearchTerm($this->getSearchTerm());
$instance = $this->getBuilder()->with('node', 'user', 'allocation')->search($this->searchTerm);
return is_null($paginate) ? $instance->get($this->getColumns()) : $instance->paginate($paginate, $this->getColumns());
return $instance->paginate($paginate, $this->getColumns());
}
/**
@ -56,14 +56,15 @@ class ServerRepository extends EloquentRepository implements ServerRepositoryInt
}
/**
* {@inheritdoc}
* Return a collection of servers with their associated data for rebuild operations.
*
* @param int|null $server
* @param int|null $node
* @return \Illuminate\Support\Collection
*/
public function getDataForRebuild($server = null, $node = null)
public function getDataForRebuild(int $server = null, int $node = null): Collection
{
Assert::nullOrIntegerish($server, 'First argument passed to getDataForRebuild must be null or integer, received %s.');
Assert::nullOrIntegerish($node, 'Second argument passed to getDataForRebuild must be null or integer, received %s.');
$instance = $this->getBuilder()->with('allocation', 'allocations', 'pack', 'egg', 'node');
$instance = $this->getBuilder()->with(['allocation', 'allocations', 'pack', 'egg', 'node']);
if (! is_null($server) && is_null($node)) {
$instance = $instance->where('id', '=', $server);
@ -75,22 +76,22 @@ class ServerRepository extends EloquentRepository implements ServerRepositoryInt
}
/**
* {@inheritdoc}
* @return \Illuminate\Database\Eloquent\Model
* Return a server model and all variables associated with the server.
*
* @param int $id
* @return \Pterodactyl\Models\Server
*
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
*/
public function findWithVariables($id)
public function findWithVariables(int $id): Server
{
Assert::integerish($id, 'First argument passed to findWithVariables must be integer, received %s.');
$instance = $this->getBuilder()->with('egg.variables', 'variables')
->where($this->getModel()->getKeyName(), '=', $id)
->first($this->getColumns());
if (is_null($instance)) {
throw new RecordNotFoundException();
try {
return $this->getBuilder()->with('egg.variables', 'variables')
->where($this->getModel()->getKeyName(), '=', $id)
->firstOrFail($this->getColumns());
} catch (ModelNotFoundException $exception) {
throw new RecordNotFoundException;
}
return $instance;
}
/**
@ -98,51 +99,45 @@ class ServerRepository extends EloquentRepository implements ServerRepositoryInt
* the function, load the allocation relationship onto it. Otherwise, find and
* return the server from the database.
*
* @param int|\Pterodactyl\Models\Server $server
* @param bool $refresh
* @param \Pterodactyl\Models\Server $server
* @param bool $refresh
* @return \Pterodactyl\Models\Server
*
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
*/
public function getPrimaryAllocation($server, bool $refresh = false): Server
public function getPrimaryAllocation(Server $server, bool $refresh = false): Server
{
$instance = $server;
if (! $instance instanceof Server) {
Assert::integerish($server, 'First argument passed to getPrimaryAllocation must be instance of \Pterodactyl\Models\Server or integer, received %s.');
$instance = $this->getBuilder()->find($server, $this->getColumns());
if (! $server->relationLoaded('allocation') || $refresh) {
$server->load('allocation');
}
if (! $instance) {
throw new RecordNotFoundException;
}
if (! $instance->relationLoaded('allocation') || $refresh) {
$instance->load('allocation');
}
return $instance;
return $server;
}
/**
* {@inheritdoc}
* Return all of the server variables possible and default to the variable
* default if there is no value defined for the specific server requested.
*
* @param int $id
* @param bool $returnAsObject
* @return array|object
*
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
*/
public function getVariablesWithValues($id, $returnWithObject = false)
public function getVariablesWithValues(int $id, bool $returnAsObject = false)
{
$instance = $this->getBuilder()->with('variables', 'egg.variables')
->find($id, $this->getColumns());
if (! $instance) {
throw new RecordNotFoundException();
try {
$instance = $this->getBuilder()->with('variables', 'egg.variables')->find($id, $this->getColumns());
} catch (ModelNotFoundException $exception) {
throw new RecordNotFoundException;
}
$data = [];
$instance->egg->variables->each(function ($item) use (&$data, $instance) {
$display = $instance->variables->where('variable_id', $item->id)->pluck('variable_value')->first();
$instance->getRelation('egg')->getRelation('variables')->each(function ($item) use (&$data, $instance) {
$display = $instance->getRelation('variables')->where('variable_id', $item->id)->pluck('variable_value')->first();
$data[$item->env_variable] = $display ?? $item->default_value;
});
if ($returnWithObject) {
if ($returnAsObject) {
return (object) [
'data' => $data,
'server' => $instance,
@ -171,19 +166,19 @@ class ServerRepository extends EloquentRepository implements ServerRepositoryInt
}
/**
* {@inheritdoc}
* Load associated databases onto the server model.
*
* @param \Pterodactyl\Models\Server $server
* @param bool $refresh
* @return \Pterodactyl\Models\Server
*/
public function getWithDatabases($id)
public function loadDatabaseRelations(Server $server, bool $refresh = false): Server
{
$instance = $this->getBuilder()->with('databases.host')
->where('installed', 1)
->find($id, $this->getColumns());
if (! $instance) {
throw new RecordNotFoundException();
if (! $server->relationLoaded('databases') || $refresh) {
$server->load('databases.host');
}
return $instance;
return $server;
}
/**
@ -212,71 +207,70 @@ class ServerRepository extends EloquentRepository implements ServerRepositoryInt
}
/**
* {@inheritdoc}
* Return a paginated list of servers that a user can access at a given level.
*
* @param \Pterodactyl\Models\User $user
* @param int $level
* @return \Illuminate\Pagination\LengthAwarePaginator
*/
public function getUserAccessServers($user)
public function filterUserAccessServers(User $user, int $level): LengthAwarePaginator
{
Assert::numeric($user, 'First argument passed to getUserAccessServers must be numeric, received %s.');
$subuser = $this->app->make(SubuserRepository::class);
return $this->getBuilder()->select('id')->where('owner_id', $user)->union(
$subuser->getBuilder()->select('server_id')->where('user_id', $user)
)->pluck('id')->all();
}
/**
* {@inheritdoc}
*/
public function filterUserAccessServers($user, $admin = false, $level = 'all', array $relations = [])
{
Assert::numeric($user, 'First argument passed to filterUserAccessServers must be numeric, received %s.');
Assert::boolean($admin, 'Second argument passed to filterUserAccessServers must be boolean, received %s.');
Assert::stringNotEmpty($level, 'Third argument passed to filterUserAccessServers must be a non-empty string, received %s.');
$instance = $this->getBuilder()->with($relations);
$instance = $this->getBuilder()->with(['user']);
// If access level is set to owner, only display servers
// that the user owns.
if ($level === 'owner') {
$instance->where('owner_id', $user);
if ($level === User::FILTER_LEVEL_OWNER) {
$instance->where('owner_id', $user->id);
}
// If set to all, display all servers they can access, including
// those they access as an admin.
//
// If set to subuser, only return the servers they can access because
// those they access as an admin. If set to subuser, only return the servers they can access because
// they are owner, or marked as a subuser of the server.
if (($level === 'all' && ! $admin) || $level === 'subuser') {
$instance->whereIn('id', $this->getUserAccessServers($user));
elseif (($level === User::FILTER_LEVEL_ALL && ! $user->root_admin) || $level === User::FILTER_LEVEL_SUBUSER) {
$instance->whereIn('id', $this->getUserAccessServers($user->id));
}
// If set to admin, only display the servers a user can access
// as an administrator (leaves out owned and subuser of).
if ($level === 'admin' && $admin) {
$instance->whereIn('id', $this->getUserAccessServers($user));
elseif ($level === User::FILTER_LEVEL_ADMIN && $user->root_admin) {
$instance->whereNotIn('id', $this->getUserAccessServers($user->id));
}
return $instance->search($this->searchTerm)->paginate(
$this->app->make('config')->get('pterodactyl.paginate.frontend.servers')
);
return $instance->setSearchTerm($this->getSearchTerm())->paginate(25);
}
/**
* {@inheritdoc}
* Return a server by UUID.
*
* @param string $uuid
* @return \Pterodactyl\Models\Server
*
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
*/
public function getByUuid($uuid)
public function getByUuid(string $uuid): Server
{
Assert::stringNotEmpty($uuid, 'First argument passed to getByUuid must be a non-empty string, received %s.');
Assert::notEmpty($uuid, 'Expected non-empty string as first argument passed to ' . __METHOD__);
$instance = $this->getBuilder()->with('nest', 'node')->where(function ($query) use ($uuid) {
$query->where('uuidShort', $uuid)->orWhere('uuid', $uuid);
})->first($this->getColumns());
if (! $instance) {
try {
return $this->getBuilder()->with('nest', 'node')->where(function ($query) use ($uuid) {
$query->where('uuidShort', $uuid)->orWhere('uuid', $uuid);
})->firstOrFail($this->getColumns());
} catch (ModelNotFoundException $exception) {
throw new RecordNotFoundException;
}
}
return $instance;
/**
* Return an array of server IDs that a given user can access based
* on owner and subuser permissions.
*
* @param int $user
* @return int[]
*/
private function getUserAccessServers(int $user): array
{
return $this->getBuilder()->select('id')->where('owner_id', $user)->union(
$this->app->make(SubuserRepository::class)->getBuilder()->select('server_id')->where('user_id', $user)
)->pluck('id')->all();
}
}

View file

@ -1,11 +1,4 @@
<?php
/**
* Pterodactyl - Panel
* Copyright (c) 2015 - 2017 Dane Everitt <dane@daneeveritt.com>.
*
* This software is licensed under the terms of the MIT license.
* https://opensource.org/licenses/MIT
*/
namespace Pterodactyl\Repositories\Eloquent;
@ -15,7 +8,9 @@ use Pterodactyl\Contracts\Repository\ServerVariableRepositoryInterface;
class ServerVariableRepository extends EloquentRepository implements ServerVariableRepositoryInterface
{
/**
* {@inheritdoc}
* Return the model backing this repository.
*
* @return string
*/
public function model()
{

View file

@ -1,21 +1,17 @@
<?php
/**
* Pterodactyl - Panel
* Copyright (c) 2015 - 2017 Dane Everitt <dane@daneeveritt.com>.
*
* This software is licensed under the terms of the MIT license.
* https://opensource.org/licenses/MIT
*/
namespace Pterodactyl\Repositories\Eloquent;
use Pterodactyl\Models\Session;
use Illuminate\Support\Collection;
use Pterodactyl\Contracts\Repository\SessionRepositoryInterface;
class SessionRepository extends EloquentRepository implements SessionRepositoryInterface
{
/**
* {@inheritdoc}
* Return the model backing this repository.
*
* @return string
*/
public function model()
{
@ -23,17 +19,24 @@ class SessionRepository extends EloquentRepository implements SessionRepositoryI
}
/**
* {@inheritdoc}
* Return all of the active sessions for a user.
*
* @param int $user
* @return \Illuminate\Support\Collection
*/
public function getUserSessions($user)
public function getUserSessions(int $user): Collection
{
return $this->getBuilder()->where('user_id', $user)->get($this->getColumns());
}
/**
* {@inheritdoc}
* Delete a session for a given user.
*
* @param int $user
* @param int $session
* @return null|int
*/
public function deleteUserSession($user, $session)
public function deleteUserSession(int $user, int $session)
{
return $this->getBuilder()->where('user_id', $user)->where('id', $session)->delete();
}

View file

@ -10,16 +10,15 @@ class SettingsRepository extends EloquentRepository implements SettingsRepositor
/**
* @var array
*/
private $cache = [];
private static $cache = [];
/**
* @var array
*/
private $databaseMiss = [];
private static $databaseMiss = [];
/**
* Return an instance of the model that acts as the base for
* this repository.
* Return the model backing this repository.
*
* @return string
*/
@ -33,12 +32,17 @@ class SettingsRepository extends EloquentRepository implements SettingsRepositor
*
* @param string $key
* @param string $value
*
* @throws \Pterodactyl\Exceptions\Model\DataValidationException
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
*/
public function set(string $key, string $value)
{
// Clear item from the cache.
$this->clearCache($key);
$this->withoutFresh()->updateOrCreate(['key' => $key], ['value' => $value]);
$this->withoutFreshModel()->updateOrCreate(['key' => $key], ['value' => $value]);
self::$cache[$key] = $value;
}
/**
@ -51,32 +55,27 @@ class SettingsRepository extends EloquentRepository implements SettingsRepositor
public function get(string $key, $default = null)
{
// If item has already been requested return it from the cache. If
// we already know it is missing, immediately return the default
// value.
if (array_key_exists($key, $this->cache)) {
return $this->cache[$key];
} elseif (array_key_exists($key, $this->databaseMiss)) {
return $default;
// we already know it is missing, immediately return the default value.
if (array_key_exists($key, self::$cache)) {
return self::$cache[$key];
} elseif (array_key_exists($key, self::$databaseMiss)) {
return value($default);
}
$instance = $this->getBuilder()->where('key', $key)->first();
if (is_null($instance)) {
$this->databaseMiss[$key] = true;
self::$databaseMiss[$key] = true;
return $default;
return value($default);
}
$this->cache[$key] = $instance->value;
return $this->cache[$key];
return self::$cache[$key] = $instance->value;
}
/**
* Remove a key from the database cache.
*
* @param string $key
* @return mixed
*/
public function forget(string $key)
{
@ -89,8 +88,8 @@ class SettingsRepository extends EloquentRepository implements SettingsRepositor
*
* @param string $key
*/
protected function clearCache(string $key)
private function clearCache(string $key)
{
unset($this->cache[$key], $this->databaseMiss[$key]);
unset(self::$cache[$key], self::$databaseMiss[$key]);
}
}

View file

@ -1,15 +1,7 @@
<?php
/**
* Pterodactyl - Panel
* Copyright (c) 2015 - 2017 Dane Everitt <dane@daneeveritt.com>.
*
* This software is licensed under the terms of the MIT license.
* https://opensource.org/licenses/MIT
*/
namespace Pterodactyl\Repositories\Eloquent;
use Webmozart\Assert\Assert;
use Pterodactyl\Models\Subuser;
use Pterodactyl\Exceptions\Repository\RecordNotFoundException;
use Pterodactyl\Contracts\Repository\SubuserRepositoryInterface;
@ -17,7 +9,9 @@ use Pterodactyl\Contracts\Repository\SubuserRepositoryInterface;
class SubuserRepository extends EloquentRepository implements SubuserRepositoryInterface
{
/**
* {@inheritdoc}
* Return the model backing this repository.
*
* @return string
*/
public function model()
{
@ -86,39 +80,4 @@ class SubuserRepository extends EloquentRepository implements SubuserRepositoryI
return $instance;
}
/**
* {@inheritdoc}
*/
public function getWithServerAndPermissions($id)
{
Assert::numeric($id, 'First argument passed to getWithServerAndPermissions must be numeric, received %s.');
$instance = $this->getBuilder()->with('server', 'permission', 'user')->find($id, $this->getColumns());
if (! $instance) {
throw new RecordNotFoundException;
}
return $instance;
}
/**
* {@inheritdoc}
*/
public function getWithKey($user, $server)
{
Assert::integerish($user, 'First argument passed to getWithKey must be integer, received %s.');
Assert::integerish($server, 'Second argument passed to getWithKey must be integer, received %s.');
$instance = $this->getBuilder()->with('key')->where([
['user_id', '=', $user],
['server_id', '=', $server],
])->first();
if (is_null($instance)) {
throw new RecordNotFoundException;
}
return $instance;
}
}

View file

@ -1,23 +1,18 @@
<?php
/**
* Pterodactyl - Panel
* Copyright (c) 2015 - 2017 Dane Everitt <dane@daneeveritt.com>.
*
* This software is licensed under the terms of the MIT license.
* https://opensource.org/licenses/MIT
*/
namespace Pterodactyl\Repositories\Eloquent;
use Pterodactyl\Models\Task;
use Webmozart\Assert\Assert;
use Illuminate\Database\Eloquent\ModelNotFoundException;
use Pterodactyl\Contracts\Repository\TaskRepositoryInterface;
use Pterodactyl\Exceptions\Repository\RecordNotFoundException;
class TaskRepository extends EloquentRepository implements TaskRepositoryInterface
{
/**
* {@inheritdoc}
* Return the model backing this repository.
*
* @return string
*/
public function model()
{
@ -25,28 +20,31 @@ class TaskRepository extends EloquentRepository implements TaskRepositoryInterfa
}
/**
* {@inheritdoc}
* Get a task and the server relationship for that task.
*
* @param int $id
* @return \Pterodactyl\Models\Task
*
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
*/
public function getTaskWithServer($id)
public function getTaskWithServer(int $id): Task
{
Assert::integerish($id, 'First argument passed to getTaskWithServer must be numeric, received %s.');
$instance = $this->getBuilder()->with('server.user')->find($id, $this->getColumns());
if (! $instance) {
try {
return $this->getBuilder()->with('server.user')->findOrFail($id, $this->getColumns());
} catch (ModelNotFoundException $exception) {
throw new RecordNotFoundException;
}
return $instance;
}
/**
* {@inheritdoc}
* Returns the next task in a schedule.
*
* @param int $schedule
* @param int $index
* @return null|\Pterodactyl\Models\Task
*/
public function getNextTask($schedule, $index)
public function getNextTask(int $schedule, int $index)
{
Assert::integerish($schedule, 'First argument passed to getNextTask must be integer, received %s.');
Assert::integerish($index, 'Second argument passed to getNextTask must be integer, received %s.');
return $this->getBuilder()->where('schedule_id', '=', $schedule)
->where('sequence_id', '=', $index + 1)
->first($this->getColumns());

View file

@ -1,44 +1,21 @@
<?php
/**
* Pterodactyl - Panel
* Copyright (c) 2015 - 2017 Dane Everitt <dane@daneeveritt.com>.
*
* This software is licensed under the terms of the MIT license.
* https://opensource.org/licenses/MIT
*/
namespace Pterodactyl\Repositories\Eloquent;
use Pterodactyl\Models\User;
use Illuminate\Foundation\Application;
use Illuminate\Support\Collection;
use Pterodactyl\Repositories\Concerns\Searchable;
use Illuminate\Contracts\Pagination\LengthAwarePaginator;
use Pterodactyl\Contracts\Repository\UserRepositoryInterface;
use Illuminate\Contracts\Config\Repository as ConfigRepository;
class UserRepository extends EloquentRepository implements UserRepositoryInterface
{
use Searchable;
/**
* @var \Illuminate\Contracts\Config\Repository
*/
protected $config;
/**
* UserRepository constructor.
* Return the model backing this repository.
*
* @param \Illuminate\Foundation\Application $application
* @param \Illuminate\Contracts\Config\Repository $config
*/
public function __construct(Application $application, ConfigRepository $config)
{
parent::__construct($application);
$this->config = $config;
}
/**
* {@inheritdoc}
* @return string
*/
public function model()
{
@ -46,32 +23,30 @@ class UserRepository extends EloquentRepository implements UserRepositoryInterfa
}
/**
* {@inheritdoc}
* Return all users with counts of servers and subusers of servers.
*
* @return \Illuminate\Contracts\Pagination\LengthAwarePaginator
*/
public function getAllUsersWithCounts()
public function getAllUsersWithCounts(): LengthAwarePaginator
{
$users = $this->getBuilder()->withCount('servers', 'subuserOf');
if ($this->searchTerm) {
$users->search($this->searchTerm);
}
return $users->paginate(
$this->config->get('pterodactyl.paginate.admin.users'),
$this->getColumns()
);
return $this->getBuilder()->withCount('servers', 'subuserOf')
->setSearchTerm($this->getSearchTerm())
->paginate(50, $this->getColumns());
}
/**
* {@inheritdoc}
* Return all matching models for a user in a format that can be used for dropdowns.
*
* @param string $query
* @return \Illuminate\Support\Collection
*/
public function filterUsersByQuery($query)
public function filterUsersByQuery(string $query): Collection
{
$this->withColumns([
$this->setColumns([
'id', 'email', 'username', 'name_first', 'name_last',
]);
$instance = $this->getBuilder()->search($query)->get($this->getColumns());
$instance = $this->getBuilder()->setSearchTerm($query)->get($this->getColumns());
return $instance->transform(function ($item) {
$item->md5 = md5(strtolower($item->email));

View file

@ -1,14 +1,8 @@
<?php
/**
* Pterodactyl - Panel
* Copyright (c) 2015 - 2017 Dane Everitt <dane@daneeveritt.com>.
*
* This software is licensed under the terms of the MIT license.
* https://opensource.org/licenses/MIT
*/
namespace Pterodactyl\Repositories;
use InvalidArgumentException;
use Illuminate\Foundation\Application;
use Pterodactyl\Contracts\Repository\RepositoryInterface;
@ -43,35 +37,13 @@ abstract class Repository implements RepositoryInterface
{
$this->app = $application;
$this->setModel($this->model());
$this->initalizeModel($this->model());
}
/**
* Take the provided model and make it accessible to the rest of the repository.
* Return the model backing this repository.
*
* @param string|array $model
* @return mixed
*/
protected function setModel($model)
{
if (is_array($model)) {
if (count($model) !== 2) {
throw new \InvalidArgumentException(
printf('setModel expected exactly 2 parameters, %d received.', count($model))
);
}
return $this->model = call_user_func(
$model[1],
$this->app->make($model[0])
);
}
return $this->model = $this->app->make($model);
}
/**
* @return mixed
* @return string|\Closure|object
*/
abstract public function model();
@ -88,10 +60,10 @@ abstract class Repository implements RepositoryInterface
/**
* Setup column selection functionality.
*
* @param array $columns
* @param array|string $columns
* @return $this
*/
public function withColumns($columns = ['*'])
public function setColumns($columns = ['*'])
{
$clone = clone $this;
$clone->columns = is_array($columns) ? $columns : func_get_args();
@ -110,15 +82,56 @@ abstract class Repository implements RepositoryInterface
}
/**
* Set repository to not return a fresh record from the DB when completed.
* Stop repository update functions from returning a fresh
* model when changes are committed.
*
* @return $this
*/
public function withoutFresh()
public function withoutFreshModel()
{
return $this->setFreshModel(false);
}
/**
* Return a fresh model with a repository updates a model.
*
* @return $this
*/
public function withFreshModel()
{
return $this->setFreshModel(true);
}
/**
* Set wether or not the repository should return a fresh model
* when changes are committed.
*
* @param bool $fresh
* @return $this
*/
public function setFreshModel(bool $fresh = true)
{
$clone = clone $this;
$clone->withFresh = false;
$clone->withFresh = $fresh;
return $clone;
}
/**
* Take the provided model and make it accessible to the rest of the repository.
*
* @param array $model
* @return mixed
*/
protected function initalizeModel(...$model)
{
switch (count($model)) {
case 1:
return $this->model = $this->app->make($model[0]);
case 2:
return $this->model = call_user_func([$this->app->make($model[0]), $model[1]]);
default:
throw new InvalidArgumentException('Model must be a FQCN or an array with a count of two.');
}
}
}