Move admin API key view to Vue.

This commit is contained in:
Buster "Silver Eagle" Neece 2021-11-03 16:07:05 -05:00
parent ad1dd031ab
commit 2c84d55f20
No known key found for this signature in database
GPG Key ID: 6D9E12FF03411F4E
12 changed files with 166 additions and 144 deletions

View File

@ -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',
]
],
],
];

View File

@ -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',

View File

@ -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));

View File

@ -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>

View File

@ -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);

View File

@ -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',

View File

@ -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'));
}
}

View File

@ -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'),
],
);
}
}

View File

@ -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';
}

View File

@ -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);
}
}

View File

@ -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;

View File

@ -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;
}
}