Move admin API key view to Vue.
This commit is contained in:
parent
ad1dd031ab
commit
2c84d55f20
|
@ -1,25 +0,0 @@
|
|||
<?php
|
||||
|
||||
return [
|
||||
'method' => 'post',
|
||||
'elements' => [
|
||||
|
||||
'comment' => [
|
||||
'text',
|
||||
[
|
||||
'label' => __('Comments'),
|
||||
'description' => __('Describe the use-case for this API key for future reference.'),
|
||||
'class' => 'half-width',
|
||||
]
|
||||
],
|
||||
|
||||
'submit' => [
|
||||
'submit',
|
||||
[
|
||||
'type' => 'submit',
|
||||
'label' => __('Save Changes'),
|
||||
'class' => 'btn btn-lg btn-primary',
|
||||
]
|
||||
],
|
||||
],
|
||||
];
|
|
@ -65,19 +65,9 @@ return static function (RouteCollectorProxy $app) {
|
|||
->setName('admin:auditlog:index')
|
||||
->add(new Middleware\Permissions(Acl::GLOBAL_LOGS));
|
||||
|
||||
$group->group(
|
||||
'/api',
|
||||
function (RouteCollectorProxy $group) {
|
||||
$group->get('', Controller\Admin\ApiController::class . ':indexAction')
|
||||
->setName('admin:api:index');
|
||||
|
||||
$group->map(['GET', 'POST'], '/edit/{id}', Controller\Admin\ApiController::class . ':editAction')
|
||||
->setName('admin:api:edit');
|
||||
|
||||
$group->get('/delete/{id}/{csrf}', Controller\Admin\ApiController::class . ':deleteAction')
|
||||
->setName('admin:api:delete');
|
||||
}
|
||||
)->add(new Middleware\Permissions(Acl::GLOBAL_API_KEYS));
|
||||
$group->get('/api-keys', Controller\Admin\ApiKeysAction::class)
|
||||
->setName('admin:api:index')
|
||||
->add(new Middleware\Permissions(Acl::GLOBAL_API_KEYS));
|
||||
|
||||
$group->group(
|
||||
'/backups',
|
||||
|
|
|
@ -160,6 +160,26 @@ return static function (RouteCollectorProxy $app) {
|
|||
$group->group(
|
||||
'/admin',
|
||||
function (RouteCollectorProxy $group) {
|
||||
$group->group(
|
||||
'',
|
||||
function (RouteCollectorProxy $group) {
|
||||
$group->get(
|
||||
'/api-keys',
|
||||
Controller\Api\Admin\ApiKeysController::class . ':listAction'
|
||||
)->setName('api:admin:api-keys');
|
||||
|
||||
$group->get(
|
||||
'/api-key/{id}',
|
||||
Controller\Api\Admin\ApiKeysController::class . ':getAction'
|
||||
)->setName('api:admin:api-key');
|
||||
|
||||
$group->delete(
|
||||
'/api-key/{id}',
|
||||
Controller\Api\Admin\ApiKeysController::class . ':deleteAction'
|
||||
);
|
||||
}
|
||||
)->add(new Middleware\Permissions(Acl::GLOBAL_API_KEYS));
|
||||
|
||||
$group->get('/auditlog', Controller\Api\Admin\AuditLogAction::class)
|
||||
->setName('api:admin:auditlog')
|
||||
->add(new Middleware\Permissions(Acl::GLOBAL_LOGS));
|
||||
|
|
|
@ -0,0 +1,68 @@
|
|||
<template>
|
||||
<section class="card" role="region">
|
||||
<b-card-header header-bg-variant="primary-dark">
|
||||
<h2 class="card-title">
|
||||
<translate key="lang_hdr">API Keys</translate>
|
||||
</h2>
|
||||
</b-card-header>
|
||||
|
||||
<data-table ref="datatable" id="api_keys" :fields="fields" :api-url="apiUrl">
|
||||
<template #cell(owner)="row">
|
||||
{{ row.item.user.email }}
|
||||
</template>
|
||||
<template #cell(actions)="row">
|
||||
<b-button-group size="sm">
|
||||
<b-button size="sm" variant="danger" @click.prevent="doDelete(row.item.links.self)">
|
||||
<translate key="lang_btn_delete">Delete</translate>
|
||||
</b-button>
|
||||
</b-button-group>
|
||||
</template>
|
||||
</data-table>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import DataTable from "~/components/Common/DataTable";
|
||||
|
||||
export default {
|
||||
name: 'AdminApiKeys',
|
||||
components: {DataTable},
|
||||
props: {
|
||||
apiUrl: String
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
fields: [
|
||||
{
|
||||
key: 'comment',
|
||||
isRowHeader: true,
|
||||
label: this.$gettext('API Key Description/Comments'),
|
||||
sortable: false
|
||||
},
|
||||
{
|
||||
key: 'owner',
|
||||
label: this.$gettext('Owner'),
|
||||
sortable: false
|
||||
},
|
||||
{key: 'actions', label: this.$gettext('Actions'), sortable: false, class: 'shrink'}
|
||||
]
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
doDelete(url) {
|
||||
this.$confirmDelete({
|
||||
title: this.$gettext('Delete API Key?'),
|
||||
}).then((result) => {
|
||||
if (result.value) {
|
||||
this.$wrapWithLoading(
|
||||
this.axios.delete(url)
|
||||
).then((resp) => {
|
||||
this.$notifySuccess(resp.data.message);
|
||||
this.relist();
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
|
@ -0,0 +1,8 @@
|
|||
import initBase from '~/base.js';
|
||||
|
||||
import '~/vendor/bootstrapVue.js';
|
||||
import '~/vendor/sweetalert.js';
|
||||
|
||||
import AdminApiKeys from '~/components/Admin/ApiKeys.vue';
|
||||
|
||||
export default initBase(AdminApiKeys);
|
|
@ -8,6 +8,7 @@ module.exports = {
|
|||
entry: {
|
||||
Account: '~/pages/Account.js',
|
||||
Dashboard: '~/pages/Dashboard.js',
|
||||
AdminApiKeys: '~/pages/Admin/ApiKeys.js',
|
||||
AdminAuditLog: '~/pages/Admin/AuditLog.js',
|
||||
AdminBranding: '~/pages/Admin/Branding.js',
|
||||
AdminCustomFields: '~/pages/Admin/CustomFields.js',
|
||||
|
|
|
@ -1,67 +0,0 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Controller\Admin;
|
||||
|
||||
use App\Form\ApiKeyForm;
|
||||
use App\Form\EntityFormFactory;
|
||||
use App\Http\Response;
|
||||
use App\Http\ServerRequest;
|
||||
use App\Session\Flash;
|
||||
use DI\FactoryInterface;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
|
||||
class ApiController extends AbstractAdminCrudController
|
||||
{
|
||||
public function __construct(
|
||||
FactoryInterface $factory
|
||||
) {
|
||||
parent::__construct($factory->make(ApiKeyForm::class));
|
||||
$this->csrf_namespace = 'admin_api';
|
||||
}
|
||||
|
||||
public function indexAction(ServerRequest $request, Response $response): ResponseInterface
|
||||
{
|
||||
$records = $this->em->createQuery(
|
||||
<<<'DQL'
|
||||
SELECT a, u FROM App\Entity\ApiKey a JOIN a.user u
|
||||
DQL
|
||||
)->getArrayResult();
|
||||
|
||||
return $request->getView()->renderToResponse($response, 'admin/api/index', [
|
||||
'records' => $records,
|
||||
'csrf' => $request->getCsrf()->generate($this->csrf_namespace),
|
||||
]);
|
||||
}
|
||||
|
||||
public function editAction(ServerRequest $request, Response $response, string $id): ResponseInterface
|
||||
{
|
||||
if (false !== $this->doEdit($request, $id)) {
|
||||
$request->getFlash()->addMessage(__('API Key updated.'), Flash::SUCCESS);
|
||||
return $response->withRedirect((string)$request->getRouter()->named('admin:api:index'));
|
||||
}
|
||||
|
||||
return $request->getView()->renderToResponse(
|
||||
$response,
|
||||
'system/form_page',
|
||||
[
|
||||
'form' => $this->form,
|
||||
'render_mode' => 'edit',
|
||||
'title' => __('Edit API Key'),
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
public function deleteAction(
|
||||
ServerRequest $request,
|
||||
Response $response,
|
||||
string $id,
|
||||
string $csrf
|
||||
): ResponseInterface {
|
||||
$this->doDelete($request, $id, $csrf);
|
||||
|
||||
$request->getFlash()->addMessage(__('API Key deleted.'), Flash::SUCCESS);
|
||||
return $response->withRedirect((string)$request->getRouter()->named('admin:api:index'));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Controller\Admin;
|
||||
|
||||
use App\Http\Response;
|
||||
use App\Http\ServerRequest;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
|
||||
class ApiKeysAction
|
||||
{
|
||||
public function __invoke(
|
||||
ServerRequest $request,
|
||||
Response $response
|
||||
): ResponseInterface {
|
||||
$router = $request->getRouter();
|
||||
|
||||
return $request->getView()->renderVuePage(
|
||||
response: $response,
|
||||
component: 'Vue_AdminApiKeys',
|
||||
id: 'admin-api-keys',
|
||||
title: __('API Keys'),
|
||||
props: [
|
||||
'apiUrl' => (string)$router->named('api:admin:api-keys'),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Controller\Api\Admin;
|
||||
|
||||
use App\Entity;
|
||||
|
||||
/**
|
||||
* @extends AbstractAdminApiCrudController<Entity\ApiKey>
|
||||
*/
|
||||
class ApiKeysController extends AbstractAdminApiCrudController
|
||||
{
|
||||
protected string $entityClass = Entity\ApiKey::class;
|
||||
protected string $resourceRouteName = 'api:admin:api-key';
|
||||
}
|
|
@ -118,4 +118,20 @@ class ApiKeysController extends AbstractApiCrudController
|
|||
|
||||
return parent::editRecord($data, $record, $context);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param TEntity $record
|
||||
* @param array<string, mixed> $context
|
||||
*
|
||||
* @return array<mixed>
|
||||
*/
|
||||
protected function toArray(object $record, array $context = []): array
|
||||
{
|
||||
$context[AbstractNormalizer::GROUPS] = [
|
||||
Entity\Interfaces\EntityGroupsInterface::GROUP_ID,
|
||||
Entity\Interfaces\EntityGroupsInterface::GROUP_GENERAL,
|
||||
];
|
||||
|
||||
return parent::toArray($record, $context);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,10 +6,11 @@ namespace App\Entity;
|
|||
|
||||
use App\Entity\Interfaces\EntityGroupsInterface;
|
||||
use App\Entity\Interfaces\IdentifiableEntityInterface;
|
||||
use App\Normalizer\Attributes\DeepNormalize;
|
||||
use App\Security\SplitToken;
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
use JsonSerializable;
|
||||
use Stringable;
|
||||
use Symfony\Component\Serializer\Annotation as Serializer;
|
||||
use Symfony\Component\Serializer\Annotation\Groups;
|
||||
|
||||
#[
|
||||
|
@ -17,7 +18,7 @@ use Symfony\Component\Serializer\Annotation\Groups;
|
|||
ORM\Table(name: 'api_keys'),
|
||||
ORM\Entity(readOnly: true)
|
||||
]
|
||||
class ApiKey implements JsonSerializable, Stringable, IdentifiableEntityInterface
|
||||
class ApiKey implements Stringable, IdentifiableEntityInterface
|
||||
{
|
||||
use Traits\HasSplitTokenFields;
|
||||
use Traits\TruncateStrings;
|
||||
|
@ -25,6 +26,8 @@ class ApiKey implements JsonSerializable, Stringable, IdentifiableEntityInterfac
|
|||
#[ORM\ManyToOne(targetEntity: User::class, fetch: 'EAGER', inversedBy: 'api_keys')]
|
||||
#[ORM\JoinColumn(name: 'user_id', referencedColumnName: 'id', nullable: false, onDelete: 'CASCADE')]
|
||||
#[Groups([EntityGroupsInterface::GROUP_ADMIN, EntityGroupsInterface::GROUP_ALL])]
|
||||
#[DeepNormalize(true)]
|
||||
#[Serializer\MaxDepth(1)]
|
||||
protected User $user;
|
||||
|
||||
#[ORM\Column(length: 255, nullable: false)]
|
||||
|
@ -52,17 +55,6 @@ class ApiKey implements JsonSerializable, Stringable, IdentifiableEntityInterfac
|
|||
$this->comment = $this->truncateString($comment);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed[]
|
||||
*/
|
||||
public function jsonSerialize(): array
|
||||
{
|
||||
return [
|
||||
'id' => $this->id,
|
||||
'comment' => $this->comment,
|
||||
];
|
||||
}
|
||||
|
||||
public function __toString(): string
|
||||
{
|
||||
return $this->comment;
|
||||
|
|
|
@ -1,26 +0,0 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Form;
|
||||
|
||||
use App\Config;
|
||||
use App\Entity;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Symfony\Component\Serializer\Serializer;
|
||||
use Symfony\Component\Validator\Validator\ValidatorInterface;
|
||||
|
||||
class ApiKeyForm extends EntityForm
|
||||
{
|
||||
public function __construct(
|
||||
EntityManagerInterface $em,
|
||||
Serializer $serializer,
|
||||
ValidatorInterface $validator,
|
||||
Config $config
|
||||
) {
|
||||
$form_config = $config->get('forms/api_key');
|
||||
parent::__construct($em, $serializer, $validator, $form_config);
|
||||
|
||||
$this->entityClass = Entity\ApiKey::class;
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue