mirror of
https://github.com/ConvoyPanel/panel.git
synced 2026-07-01 01:24:21 +08:00
Add repositories and exceptions
This commit is contained in:
@@ -0,0 +1,169 @@
|
||||
<?php
|
||||
|
||||
namespace App\Contracts\Repository;
|
||||
|
||||
use Illuminate\Support\Collection;
|
||||
use Illuminate\Contracts\Pagination\LengthAwarePaginator;
|
||||
|
||||
interface RepositoryInterface
|
||||
{
|
||||
/**
|
||||
* Return an identifier or Model object to be used by the repository.
|
||||
*
|
||||
* @return string|\Closure|object
|
||||
*/
|
||||
public function model();
|
||||
|
||||
/**
|
||||
* Return the model being used for this repository instance.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function getModel();
|
||||
|
||||
/**
|
||||
* Returns an instance of a query builder.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function getBuilder();
|
||||
|
||||
/**
|
||||
* Returns the columns to be selected or returned by the query.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function getColumns();
|
||||
|
||||
/**
|
||||
* An array of columns to filter the response by.
|
||||
*
|
||||
* @param array|string $columns
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setColumns($columns = ['*']);
|
||||
|
||||
/**
|
||||
* Stop repository update functions from returning a fresh
|
||||
* model when changes are committed.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function withoutFreshModel();
|
||||
|
||||
/**
|
||||
* Return a fresh model with a repository updates a model.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function withFreshModel();
|
||||
|
||||
/**
|
||||
* Set whether or not the repository should return a fresh model
|
||||
* when changes are committed.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setFreshModel(bool $fresh = true);
|
||||
|
||||
/**
|
||||
* Create a new model instance and persist it to the database.
|
||||
*
|
||||
* @return mixed
|
||||
*
|
||||
* @throws \App\Exceptions\Model\DataValidationException
|
||||
*/
|
||||
public function create(array $fields, bool $validate = true, bool $force = false);
|
||||
|
||||
/**
|
||||
* Find a model that has the specific ID passed.
|
||||
*
|
||||
* @return mixed
|
||||
*
|
||||
* @throws \App\Exceptions\Repository\RecordNotFoundException
|
||||
*/
|
||||
public function find(int $id);
|
||||
|
||||
/**
|
||||
* Find a model matching an array of where clauses.
|
||||
*/
|
||||
public function findWhere(array $fields): Collection;
|
||||
|
||||
/**
|
||||
* Find and return the first matching instance for the given fields.
|
||||
*
|
||||
* @return mixed
|
||||
*
|
||||
* @throws \App\Exceptions\Repository\RecordNotFoundException
|
||||
*/
|
||||
public function findFirstWhere(array $fields);
|
||||
|
||||
/**
|
||||
* Return a count of records matching the passed arguments.
|
||||
*/
|
||||
public function findCountWhere(array $fields): int;
|
||||
|
||||
/**
|
||||
* Delete a given record from the database.
|
||||
*/
|
||||
public function delete(int $id): int;
|
||||
|
||||
/**
|
||||
* Delete records matching the given attributes.
|
||||
*/
|
||||
public function deleteWhere(array $attributes): int;
|
||||
|
||||
/**
|
||||
* Update a given ID with the passed array of fields.
|
||||
*
|
||||
* @param int $id
|
||||
*
|
||||
* @return mixed
|
||||
*
|
||||
* @throws \App\Exceptions\Model\DataValidationException
|
||||
* @throws \App\Exceptions\Repository\RecordNotFoundException
|
||||
*/
|
||||
public function update($id, array $fields, bool $validate = true, bool $force = false);
|
||||
|
||||
/**
|
||||
* Perform a mass update where matching records are updated using whereIn.
|
||||
* This does not perform any model data validation.
|
||||
*/
|
||||
public function updateWhereIn(string $column, array $values, array $fields): int;
|
||||
|
||||
/**
|
||||
* Update a record if it exists in the database, otherwise create it.
|
||||
*
|
||||
* @return mixed
|
||||
*
|
||||
* @throws \App\Exceptions\Model\DataValidationException
|
||||
*/
|
||||
public function updateOrCreate(array $where, array $fields, bool $validate = true, bool $force = false);
|
||||
|
||||
/**
|
||||
* Return all records associated with the given model.
|
||||
*/
|
||||
public function all(): Collection;
|
||||
|
||||
/**
|
||||
* Return a paginated result set using a search term if set on the repository.
|
||||
*/
|
||||
public function paginated(int $perPage): LengthAwarePaginator;
|
||||
|
||||
/**
|
||||
* Insert a single or multiple records into the database at once skipping
|
||||
* validation and mass assignment checking.
|
||||
*/
|
||||
public function insert(array $data): bool;
|
||||
|
||||
/**
|
||||
* Insert multiple records into the database and ignore duplicates.
|
||||
*/
|
||||
public function insertIgnore(array $values): bool;
|
||||
|
||||
/**
|
||||
* Get the amount of entries in the database.
|
||||
*/
|
||||
public function count(): int;
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
<?php
|
||||
|
||||
namespace App\Exceptions;
|
||||
|
||||
use Exception;
|
||||
|
||||
class ConvoyException extends Exception
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
<?php
|
||||
|
||||
namespace App\Exceptions\Model;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Contracts\Validation\Validator;
|
||||
use App\Exceptions\ConvoyException;
|
||||
use Illuminate\Contracts\Support\MessageProvider;
|
||||
use Symfony\Component\HttpKernel\Exception\HttpExceptionInterface;
|
||||
|
||||
class DataValidationException extends ConvoyException implements HttpExceptionInterface, MessageProvider
|
||||
{
|
||||
/**
|
||||
* The validator instance.
|
||||
*/
|
||||
protected Validator $validator;
|
||||
|
||||
/**
|
||||
* The underlying model instance that triggered this exception.
|
||||
*/
|
||||
protected Model $model;
|
||||
|
||||
/**
|
||||
* DataValidationException constructor.
|
||||
*/
|
||||
public function __construct(Validator $validator, Model $model)
|
||||
{
|
||||
$message = sprintf(
|
||||
'Could not save %s[%s]: failed to validate data: %s',
|
||||
get_class($model),
|
||||
$model->getKey(),
|
||||
$validator->errors()->toJson()
|
||||
);
|
||||
|
||||
parent::__construct($message);
|
||||
|
||||
$this->validator = $validator;
|
||||
$this->model = $model;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the validator message bag.
|
||||
*
|
||||
* @return \Illuminate\Support\MessageBag
|
||||
*/
|
||||
public function getMessageBag()
|
||||
{
|
||||
return $this->validator->errors();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the status code for this request.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getStatusCode(): int
|
||||
{
|
||||
return 500;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function getHeaders(): array
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
public function getValidator(): Validator
|
||||
{
|
||||
return $this->validator;
|
||||
}
|
||||
|
||||
public function getModel(): Model
|
||||
{
|
||||
return $this->model;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
namespace App\Exceptions\Repository;
|
||||
|
||||
use Illuminate\Http\Response;
|
||||
use Symfony\Component\HttpKernel\Exception\HttpExceptionInterface;
|
||||
|
||||
class RecordNotFoundException extends RepositoryException implements HttpExceptionInterface
|
||||
{
|
||||
/**
|
||||
* Returns the status code.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getStatusCode(): int
|
||||
{
|
||||
return Response::HTTP_NOT_FOUND;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns response headers.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getHeaders(): array
|
||||
{
|
||||
return [];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
<?php
|
||||
|
||||
namespace App\Exceptions\Repository;
|
||||
|
||||
use App\Exceptions\ConvoyException;
|
||||
|
||||
class RepositoryException extends ConvoyException
|
||||
{
|
||||
}
|
||||
@@ -14,17 +14,18 @@ use Spatie\QueryBuilder\QueryBuilder;
|
||||
|
||||
class AddressController extends ApplicationApiController
|
||||
{
|
||||
public function index(Request $request)
|
||||
public function index(Node $node, Request $request)
|
||||
{
|
||||
$addresses = QueryBuilder::for(IPAddress::query())
|
||||
->allowedFilters(['server_id', 'node_id', 'address', 'cidr', 'gateway', 'type'])
|
||||
->allowedSorts(['id', 'server_id', 'node_id'])
|
||||
->where('node_id', $node->id)
|
||||
->paginate($request->query('per_page') ?? 50);
|
||||
|
||||
return $addresses;
|
||||
}
|
||||
|
||||
public function show(IPAddress $address)
|
||||
public function show(Node $node, IPAddress $address)
|
||||
{
|
||||
return $this->returnContent([
|
||||
'data' => $address,
|
||||
|
||||
@@ -0,0 +1,80 @@
|
||||
<?php
|
||||
|
||||
namespace App\Repositories\Proxmox;
|
||||
|
||||
use GuzzleHttp\Client;
|
||||
use App\Models\Node;
|
||||
use Webmozart\Assert\Assert;
|
||||
use App\Models\Server;
|
||||
use Illuminate\Contracts\Foundation\Application;
|
||||
|
||||
abstract class DaemonRepository
|
||||
{
|
||||
/**
|
||||
* @var Application
|
||||
*/
|
||||
protected $app;
|
||||
|
||||
/**
|
||||
* @var Server|null
|
||||
*/
|
||||
protected $server;
|
||||
|
||||
/**
|
||||
* @var Node|null
|
||||
*/
|
||||
protected $node;
|
||||
|
||||
/**
|
||||
* BaseWingsRepository constructor.
|
||||
*/
|
||||
public function __construct(Application $application)
|
||||
{
|
||||
$this->app = $application;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the server model this request is stemming from.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setServer(Server $server): static
|
||||
{
|
||||
$this->server = $server;
|
||||
|
||||
$this->setNode($this->server->node);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the node model this request is stemming from.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setNode(Node $node): static
|
||||
{
|
||||
$this->node = $node;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an instance of the Guzzle HTTP Client to be used for requests.
|
||||
*/
|
||||
public function getHttpClient(array $headers = []): Client
|
||||
{
|
||||
Assert::isInstanceOf($this->node, Node::class);
|
||||
|
||||
return new Client([
|
||||
'base_uri' => $this->node->getConnectionAddress(),
|
||||
'timeout' => config('pterodactyl.guzzle.timeout'),
|
||||
'connect_timeout' => config('pterodactyl.guzzle.connect_timeout'),
|
||||
'headers' => array_merge($headers, [
|
||||
'Authorization' => 'Bearer ' . $this->node->getDecryptedKey(),
|
||||
'Accept' => 'application/json',
|
||||
'Content-Type' => 'application/json',
|
||||
]),
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,137 @@
|
||||
<?php
|
||||
|
||||
namespace App\Repositories;
|
||||
|
||||
use Closure;
|
||||
use InvalidArgumentException;
|
||||
use Illuminate\Foundation\Application;
|
||||
use App\Contracts\Repository\RepositoryInterface;
|
||||
|
||||
abstract class Repository implements RepositoryInterface
|
||||
{
|
||||
/**
|
||||
* @var Application
|
||||
*/
|
||||
protected Application $app;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected array $columns = ['*'];
|
||||
|
||||
/**
|
||||
* @var mixed
|
||||
*/
|
||||
protected mixed $model;
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
protected bool $withFresh = true;
|
||||
|
||||
/**
|
||||
* Repository constructor.
|
||||
*/
|
||||
public function __construct(Application $application)
|
||||
{
|
||||
$this->app = $application;
|
||||
|
||||
$this->initializeModel($this->model());
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the model backing this repository.
|
||||
*
|
||||
* @return string|Closure|object
|
||||
*/
|
||||
abstract public function model();
|
||||
|
||||
/**
|
||||
* Return the model being used for this repository.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function getModel(): mixed
|
||||
{
|
||||
return $this->model;
|
||||
}
|
||||
|
||||
/**
|
||||
* Setup column selection functionality.
|
||||
*
|
||||
* @param array|string $columns
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setColumns($columns = ['*']): Repository|static
|
||||
{
|
||||
$clone = clone $this;
|
||||
$clone->columns = is_array($columns) ? $columns : func_get_args();
|
||||
|
||||
return $clone;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the columns to be selected in the repository call.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getColumns(): array
|
||||
{
|
||||
return $this->columns;
|
||||
}
|
||||
|
||||
/**
|
||||
* Stop repository update functions from returning a fresh
|
||||
* model when changes are committed.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function withoutFreshModel(): Repository|static
|
||||
{
|
||||
return $this->setFreshModel(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a fresh model with a repository updates a model.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function withFreshModel()
|
||||
{
|
||||
return $this->setFreshModel(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set whether or not the repository should return a fresh model
|
||||
* when changes are committed.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setFreshModel(bool $fresh = true)
|
||||
{
|
||||
$clone = clone $this;
|
||||
$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 initializeModel(...$model): mixed
|
||||
{
|
||||
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 FQDN or an array with a count of two.');
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -52,7 +52,7 @@ Route::group(['prefix' => '/servers'], function () {
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Server Controller Routes
|
||||
| Node Controller Routes
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Endpoint: /api/application/servers
|
||||
|
||||
Reference in New Issue
Block a user