diff --git a/config/routes.yaml b/config/routes.yaml index 8eeffea..0c938b7 100644 --- a/config/routes.yaml +++ b/config/routes.yaml @@ -47,9 +47,21 @@ user_auth_login: user_auth_logout: path: /auth/logout -user_account_invites: - path: /account/invites - controller: App\Controller\AccountController::invites +user_account: + path: /account + controller: App\Controller\AccountController::account + requirements: + method: GET + +user_account_token_create: + path: /profile/api/token/create + controller: App\Controller\AccountController::addApiToken + requirements: + method: GET + +user_account_token_revoke: + path: /profile/api/token/revoke/{key} + controller: App\Controller\AccountController::revokeApiToken requirements: method: GET diff --git a/src/Controller/AccountController.php b/src/Controller/AccountController.php index e7a0a7d..3ee3608 100644 --- a/src/Controller/AccountController.php +++ b/src/Controller/AccountController.php @@ -2,22 +2,60 @@ namespace App\Controller; +use App\Entity\ApiToken; use App\Entity\User; +use App\Repository\ApiTokenRepository; use App\Repository\InviteRepository; +use Doctrine\ORM\EntityManagerInterface; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Component\HttpFoundation\Response; class AccountController extends AbstractController { - public function invites(InviteRepository $inviteRepo): Response + public function account(InviteRepository $inviteRepo, ApiTokenRepository $apiTokenRepo): Response { /** @var User $user */ if (null === $user = $this->getUser()) { throw $this->createAccessDeniedException('User not found exception'); } - return $this->render('Account/invites.html.twig', [ + return $this->render( + 'Account/account.html.twig', [ 'invites' => $inviteRepo->findInvitesByUser($user), + 'tokens' => $apiTokenRepo->findBy(['user' => $user->getId()]), + 'user' => $user, ]); } -} \ No newline at end of file + + public function addApiToken(EntityManagerInterface $em): Response + { + /** @var User|null $user */ + if (null === $user = $this->getUser()) { + throw $this->createAccessDeniedException(); + } + + $token = new ApiToken($user); + $em->persist($token); + $em->flush(); + + $this->addFlash('success', 'API token created.'); + + return $this->redirectToRoute('user_account'); + } + + public function revokeApiToken(string $key, ApiTokenRepository $repo, EntityManagerInterface $em): Response + { + $token = $repo->findOneBy(['key' => $key]); + + if (null === $token || $token->getUser() !== $this->getUser()) { + throw $this->createNotFoundException('Token not found'); + } + + $em->remove($token); + $em->flush(); + + $this->addFlash('success', 'API token removed.'); + + return $this->redirectToRoute('user_account'); + } +} diff --git a/templates/Account/account.html.twig b/templates/Account/account.html.twig new file mode 100644 index 0000000..8be0b68 --- /dev/null +++ b/templates/Account/account.html.twig @@ -0,0 +1,26 @@ +{% extends 'base.html.twig' %} + +{% block content %} + +
+
+ {% include 'Account/profile.html.twig' with {'user': user} %} +
+
+ {% include 'Account/invites.html.twig' with {'invites': invites} %} +
+
+ {% include 'Account/api.html.twig' with {'tokens': tokens} %} +
+
+{% endblock %} diff --git a/templates/Account/api.html.twig b/templates/Account/api.html.twig new file mode 100644 index 0000000..f94a03c --- /dev/null +++ b/templates/Account/api.html.twig @@ -0,0 +1,34 @@ +
+ Create token +
+ + + + + + + + + + + + + {% for token in tokens %} + + + + + + + {% endfor %} + +
TokenRSS linkCreatedActions
+ {{ token.key }} + + {# We can't use constant() in the hash so it's necessay to hard-code query parameter here #} + + + {{ token.createdAt | date('Y-m-d H:i:s') }} + + Revoke +
\ No newline at end of file diff --git a/templates/Account/invites.html.twig b/templates/Account/invites.html.twig index 22985bc..34f9112 100644 --- a/templates/Account/invites.html.twig +++ b/templates/Account/invites.html.twig @@ -1,30 +1,28 @@ -{% extends 'base.html.twig' %} +
+ +
-{% block content %} -

Your invites

- - - - - - - - - - {# @var invite \App\Entity\Invite #} - {% for invite in invites %} - - - - - {% endfor %} - -
#
{{ loop.index }} - {% if invite.usedBy %} - Used by {{ invite.usedBy.username }}. - {% else %} - {% set invite_url = url('user_register', { code: invite.code }) %} - - {% endif %} -
-{% endblock %} + + + + + + + + + {# @var invite \App\Entity\Invite #} + {% for invite in invites %} + + + + + {% endfor %} + +
#
{{ loop.index }} + {% if invite.usedBy %} + Used by {{ invite.usedBy.username }}. + {% else %} + {% set invite_url = url('user_register', { code: invite.code }) %} + + {% endif %} +
diff --git a/templates/Account/profile.html.twig b/templates/Account/profile.html.twig new file mode 100644 index 0000000..34a0c6d --- /dev/null +++ b/templates/Account/profile.html.twig @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + + + +
FieldValueActions
Username{{ user.username }}
Email{{ user.email }} + +
\ No newline at end of file diff --git a/templates/base.html.twig b/templates/base.html.twig index 2708829..5dc6e59 100644 --- a/templates/base.html.twig +++ b/templates/base.html.twig @@ -36,8 +36,8 @@ {{ app.user.username }} @@ -62,6 +62,16 @@ {% endif %} +
+ {% for type, messages in app.flashes %} + {% for message in messages %} + + {% endfor %} + {% endfor %} +
+
{% block content %}{% endblock %}