Add translations, add delete paths, fixes

This commit is contained in:
Cyril 2019-10-30 12:18:51 +01:00
parent b683f250e8
commit eca2625d33
10 changed files with 187 additions and 62 deletions

View File

@ -6,8 +6,10 @@ use App\Entity\AddressBook;
use App\Entity\Calendar;
use App\Entity\CalendarInstance;
use App\Entity\CalendarObject;
use App\Entity\CalendarSubscription;
use App\Entity\Card;
use App\Entity\Principal;
use App\Entity\SchedulingObject;
use App\Entity\User;
use App\Form\AddressBookType;
use App\Form\CalendarInstanceType;
@ -15,6 +17,7 @@ use App\Form\UserType;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Translation\TranslatorInterface;
class AdminController extends AbstractController
{
@ -69,13 +72,14 @@ class AdminController extends AbstractController
* @Route("/users/new", name="user_create")
* @Route("/users/edit/{username}", name="user_edit")
*/
public function userCreate(Request $request, ?string $username)
public function userCreate(Request $request, ?string $username, TranslatorInterface $trans)
{
if ($username) {
$user = $this->get('doctrine')->getRepository(User::class)->findOneByUsername($username);
if (!$user) {
throw new \Exception('User not found');
throw $this->createNotFoundException('User not found');
}
$oldHash = $user->getPassword();
$principal = $this->get('doctrine')->getRepository(Principal::class)->findOneByUri(Principal::PREFIX.$username);
} else {
$user = new User();
@ -94,8 +98,13 @@ class AdminController extends AbstractController
$email = $form->get('email')->getData();
// Create password for user
$hash = md5($user->getUsername().':'.$this->authRealm.':'.$user->getPassword());
$user->setPassword($hash);
if ($username && is_null($user->getPassword())) {
// The user is not new and does not want to change its password
$user->setPassword($oldHash);
} else {
$hash = md5($user->getUsername().':'.$this->authRealm.':'.$user->getPassword());
$user->setPassword($hash);
}
$entityManager = $this->get('doctrine')->getManager();
@ -106,14 +115,14 @@ class AdminController extends AbstractController
$calendarInstance = new CalendarInstance();
$calendar = new Calendar();
$calendarInstance->setPrincipalUri(Principal::PREFIX.$user->getUsername())
->setDisplayName('Default Calendar')
->setDescription('Default Calendar for '.$displayName)
->setDisplayName($trans->trans('default.calendar.title'))
->setDescription($trans->trans('default.calendar.description', ['users' => $displayName]))
->setCalendar($calendar);
$addressbook = new AddressBook();
$addressbook->setPrincipalUri(Principal::PREFIX.$user->getUsername())
->setDisplayName('Default Address Book')
->setDescription('Default Address book for '.$displayName);
->setDisplayName($trans->trans('default.addressbook.title'))
->setDescription($trans->trans('default.addressbook.description', ['users' => $displayName]));
$entityManager->persist($calendarInstance);
$entityManager->persist($addressbook);
$entityManager->persist($principal);
@ -125,6 +134,8 @@ class AdminController extends AbstractController
$entityManager->persist($user);
$entityManager->flush();
$this->addFlash('success', $trans->trans('user.saved'));
return $this->redirectToRoute('users');
}
@ -137,9 +148,55 @@ class AdminController extends AbstractController
/**
* @Route("/users/delete/{username}", name="user_delete")
*/
public function userDelete(?string $username)
public function userDelete(string $username, TranslatorInterface $trans)
{
//TODO
$user = $this->get('doctrine')->getRepository(User::class)->findOneByUsername($username);
if (!$user) {
throw $this->createNotFoundException('User not found');
}
$entityManager = $this->get('doctrine')->getManager();
$entityManager->remove($user);
$principal = $this->get('doctrine')->getRepository(Principal::class)->findOneByUri(Principal::PREFIX.$username);
$entityManager->remove($principal);
// Remove calendars and addressbooks
$calendars = $this->get('doctrine')->getRepository(CalendarInstance::class)->findByPrincipalUri(Principal::PREFIX.$username);
foreach ($calendars ?? [] as $instance) {
foreach ($instance->getCalendar()->getObjects() ?? [] as $object) {
$entityManager->remove($object);
}
foreach ($instance->getCalendar()->getChanges() ?? [] as $change) {
$entityManager->remove($change);
}
$entityManager->remove($instance->getCalendar());
$entityManager->remove($instance);
}
$calendarsSubscriptions = $this->get('doctrine')->getRepository(CalendarSubscription::class)->findByPrincipalUri(Principal::PREFIX.$username);
foreach ($calendarsSubscriptions ?? [] as $subscription) {
$entityManager->remove($subscription);
}
$schedulingObjects = $this->get('doctrine')->getRepository(SchedulingObject::class)->findByPrincipalUri(Principal::PREFIX.$username);
foreach ($schedulingObjects ?? [] as $object) {
$entityManager->remove($object);
}
$addressbooks = $this->get('doctrine')->getRepository(AddressBook::class)->findByPrincipalUri(Principal::PREFIX.$username);
foreach ($addressbooks ?? [] as $addressbook) {
foreach ($addressbook->getCards() ?? [] as $card) {
$entityManager->remove($card);
}
foreach ($addressbook->getChanges() ?? [] as $change) {
$entityManager->remove($change);
}
$entityManager->remove($addressbook);
}
$entityManager->flush();
$this->addFlash('success', $trans->trans('user.deleted'));
return $this->redirectToRoute('users');
}
/**
@ -161,18 +218,18 @@ class AdminController extends AbstractController
* @Route("/calendars/{username}/new", name="calendar_create")
* @Route("/calendars/{username}/edit/{id}", name="calendar_edit")
*/
public function calendarCreate(Request $request, string $username, ?int $id)
public function calendarCreate(Request $request, string $username, ?int $id, TranslatorInterface $trans)
{
$principal = $this->get('doctrine')->getRepository(Principal::class)->findOneByUri(Principal::PREFIX.$username);
if (!$principal) {
throw new \Exception('User not found');
throw $this->createNotFoundException('User not found');
}
if ($id) {
$calendarInstance = $this->get('doctrine')->getRepository(CalendarInstance::class)->findOneById($id);
if (!$calendarInstance) {
throw new \Exception('Calendar not found');
throw $this->createNotFoundException('Calendar not found');
}
} else {
$calendarInstance = new CalendarInstance();
@ -206,6 +263,8 @@ class AdminController extends AbstractController
$entityManager->persist($calendarInstance);
$entityManager->flush();
$this->addFlash('success', $trans->trans('calendar.saved'));
return $this->redirectToRoute('calendars', ['username' => $username]);
}
@ -217,6 +276,43 @@ class AdminController extends AbstractController
]);
}
/**
* @Route("/calendars/{username}/delete/{id}", name="calendar_delete")
*/
public function calendarDelete(string $username, string $id, TranslatorInterface $trans)
{
$instance = $this->get('doctrine')->getRepository(CalendarInstance::class)->findOneById($id);
if (!$instance) {
throw $this->createNotFoundException('Calendar not found');
}
$entityManager = $this->get('doctrine')->getManager();
$calendarsSubscriptions = $this->get('doctrine')->getRepository(CalendarSubscription::class)->findByPrincipalUri($instance->getPrincipalUri());
foreach ($calendarsSubscriptions ?? [] as $subscription) {
$entityManager->remove($subscription);
}
$schedulingObjects = $this->get('doctrine')->getRepository(SchedulingObject::class)->findByPrincipalUri($instance->getPrincipalUri());
foreach ($schedulingObjects ?? [] as $object) {
$entityManager->remove($object);
}
foreach ($instance->getCalendar()->getObjects() ?? [] as $object) {
$entityManager->remove($object);
}
foreach ($instance->getCalendar()->getChanges() ?? [] as $change) {
$entityManager->remove($change);
}
$entityManager->remove($instance->getCalendar());
$entityManager->remove($instance);
$entityManager->flush();
$this->addFlash('success', $trans->trans('calendar.deleted'));
return $this->redirectToRoute('calendars', ['username' => $username]);
}
/**
* @Route("/adressbooks/{username}", name="address_books")
*/
@ -236,18 +332,18 @@ class AdminController extends AbstractController
* @Route("/adressbooks/{username}/new", name="addressbook_create")
* @Route("/adressbooks/{username}/edit/{id}", name="addressbook_edit")
*/
public function addressbookCreate(Request $request, string $username, ?int $id)
public function addressbookCreate(Request $request, string $username, ?int $id, TranslatorInterface $trans)
{
$principal = $this->get('doctrine')->getRepository(Principal::class)->findOneByUri(Principal::PREFIX.$username);
if (!$principal) {
throw new \Exception('User not found');
throw $this->createNotFoundException('User not found');
}
if ($id) {
$addressbook = $this->get('doctrine')->getRepository(AddressBook::class)->findOneById($id);
if (!$addressbook) {
throw new \Exception('Address book not found');
throw $this->createNotFoundException('Address book not found');
}
} else {
$addressbook = new AddressBook();
@ -264,6 +360,8 @@ class AdminController extends AbstractController
$entityManager->persist($addressbook);
$entityManager->flush();
$this->addFlash('success', $trans->trans('addressbooks.saved'));
return $this->redirectToRoute('address_books', ['username' => $username]);
}
@ -274,4 +372,30 @@ class AdminController extends AbstractController
'addressbook' => $addressbook,
]);
}
/**
* @Route("/addressbooks/{username}/delete/{id}", name="addressbook_delete")
*/
public function addressbookDelete(string $username, string $id, TranslatorInterface $trans)
{
$addressbook = $this->get('doctrine')->getRepository(AddressBook::class)->findOneById($id);
if (!$addressbook) {
throw $this->createNotFoundException('Address Book not found');
}
$entityManager = $this->get('doctrine')->getManager();
foreach ($addressbook->getCards() ?? [] as $card) {
$entityManager->remove($card);
}
foreach ($addressbook->getChanges() ?? [] as $change) {
$entityManager->remove($change);
}
$entityManager->remove($addressbook);
$entityManager->flush();
$this->addFlash('success', $trans->trans('addressbooks.deleted'));
return $this->redirectToRoute('address_books', ['username' => $username]);
}
}

View File

@ -2,6 +2,7 @@
namespace App\Controller;
use App\Entity\User;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;

View File

@ -3,12 +3,12 @@
{% block body %}
<a href="{{ path('address_books', {username: username}) }}" class="btn btn-link">« Back to Address Books for {{ principal.displayName }}</a>
<a href="{{ path('address_books', {username: username}) }}" class="btn btn-link">« {{ "addressbooks.back"|trans({'user': principal.displayName }) }}</a>
{% if addressbook.id %}
<h1 class="display-4 mb-5">Editing «{{ addressbook.displayName }}»</h1>
<h1 class="display-4 mb-5">{{ "addressbooks.edit"|trans({'name': addressbook.displayName }) }}</h1>
{% else %}
<h1 class="display-4 mb-5">New Address Book <small class="text-muted">for {{ principal.displayName }}</small></h1>
<h1 class="display-4 mb-5">{{ "addressbooks.new"|trans }} <small class="text-muted">for {{ principal.displayName }}</small></h1>
{% endif %}
{{ form(form) }}

View File

@ -3,20 +3,20 @@
{% block body %}
<a href="{{ path('users') }}" class="btn btn-link">« Back to Users</a>
<a href="{{ path('users') }}" class="btn btn-link">« {{ "users.back"|trans }}</a>
<h1 class="display-4 d-flex justify-content-between">Address books for {{ principal.displayName }} <a href="{{ path('addressbook_create', {username: username}) }}" class="btn btn-success mb-auto mt-auto">+ New address book</a></h1>
<h1 class="display-4 d-flex justify-content-between">{{ "addressbooks.for"|trans({'who': principal.displayName}) }} <a href="{{ path('addressbook_create', {username: username}) }}" class="btn btn-success mb-auto mt-auto">+ {{ "addressbooks.new"|trans }}</a></h1>
<div class="list-group mt-5">
{% for addressbook in addressbooks %}
<div class="list-group-item list-group-item-action">
<div class="d-flex w-100 justify-content-between">
<h5 class="mb-1 mr-auto">{{ addressbook.displayName }}</h5>
<a href="{{ path('addressbook_edit',{username: username, id: addressbook.id})}}" class="btn btn-primary ml-1">✎ Edit</a>
<!-- <a href="{{ path('user_delete',{username: principal.username})}}" class="btn btn-danger ml-1">⚠ Delete</a> -->
<a href="{{ path('addressbook_edit',{username: username, id: addressbook.id})}}" class="btn btn-primary ml-1">✎ {{ "edit"|trans }}</a>
<a href="{{ path('addressbook_delete',{username: username, id: addressbook.id})}}" class="btn btn-danger ml-1">⚠ {{ "delete"|trans }}</a>
</div>
<p class="mb-1">{{ addressbook.description }}</p>
<small>Calendar URI : <code>{{ addressbook.uri }}</code> — {{ addressbook.cards|length }} contact(s)</small>
<small>{{ "addressbooks.uri"|trans }} : <code>{{ addressbook.uri }}</code> — {{ "addressbooks.contacts"|trans({'%count%': addressbook.cards|length}) }}{{ addressbook.cards|length }}</small>
</div>
{% endfor %}
</div>

View File

@ -3,12 +3,12 @@
{% block body %}
<a href="{{ path('calendars', {username: username}) }}" class="btn btn-link">« Back to Calendars for {{ principal.displayName }}</a>
<a href="{{ path('calendars', {username: username}) }}" class="btn btn-link">« {{ "calendars.back"|trans({'user': principal.displayName }) }}</a>
{% if calendar.id %}
<h1 class="display-4 mb-5">Editing «{{ calendar.displayName }}»</h1>
<h1 class="display-4 mb-5">{{ "calendars.edit"|trans({'name': calendar.displayName }) }}</h1>
{% else %}
<h1 class="display-4 mb-5">New calendar <small class="text-muted">for {{ principal.displayName }}</small></h1>
<h1 class="display-4 mb-5">{{ "calendars.new"|trans }} <small class="text-muted">for {{ principal.displayName }}</small></h1>
{% endif %}
{{ form(form) }}

View File

@ -3,20 +3,20 @@
{% block body %}
<a href="{{ path('users') }}" class="btn btn-link">« Back to Users</a>
<a href="{{ path('users') }}" class="btn btn-link">« {{ "users.back"|trans }}</a>
<h1 class="display-4 d-flex justify-content-between">Calendars for {{ principal.displayName }} <a href="{{ path('calendar_create', {username: username}) }}" class="btn btn-success mb-auto mt-auto">+ New calendar</a></h1>
<h1 class="display-4 d-flex justify-content-between">{{ "calendars.for"|trans({'who': principal.displayName}) }} <a href="{{ path('calendar_create', {username: username}) }}" class="btn btn-success mb-auto mt-auto">+ {{ "calendars.new"|trans }}</a></h1>
<div class="list-group mt-5">
{% for calendar in calendars %}
<div class="list-group-item list-group-item-action">
<div class="d-flex w-100 justify-content-between">
<h5 class="mb-1 mr-auto">{{ calendar.displayName }} <span class="badge badge-pill" style="background-color: {{ calendar.calendarColor }}">&nbsp;</span></h5>
<a href="{{ path('calendar_edit',{username: username, id: calendar.id})}}" class="btn btn-primary ml-1">✎ Edit</a>
<!-- <a href="{{ path('user_delete',{username: principal.username})}}" class="btn btn-danger ml-1">⚠ Delete</a> -->
<a href="{{ path('calendar_edit',{username: username, id: calendar.id})}}" class="btn btn-primary ml-1">✎ {{ "edit"|trans }}</a>
<a href="{{ path('calendar_delete',{username: username, id: calendar.id})}}" class="btn btn-danger ml-1">⚠ {{ "delete"|trans }}</a>
</div>
<p class="mb-1">{{ calendar.description }}</p>
<small>Calendar URI : <code>{{ calendar.uri }}</code> — {{ calendar.calendar.objects|length }} event(s)</small>
<small>{{ "calendars.uri"|trans }} : <code>{{ calendar.uri }}</code> — {{ "calendars.events"|trans({'%count%': calendar.calendar.objects|length}) }}</small>
</div>
{% endfor %}
</div>

View File

@ -3,54 +3,54 @@
{% block body %}
<h1 class="display-4">Dashboard</h1>
<h1 class="display-4">{{ "title.dashboard"|trans }}</h1>
<div class="row">
<div class="col-md">
<h3 class="mb-3 mt-4">Configured environment</h3>
<h3 class="mb-3 mt-4">{{ "dashboard.env"|trans }}</h3>
<ul class="list-group">
<li class="list-group-item list-group-item-primary">Version : <code>{{ version }}</code> (SabreDAV <code>{{ sabredav_version }}</code>)</li>
<li class="list-group-item list-group-item-secondary">Auth Realm : <code>{{ authRealm }}</code></li>
<li class="list-group-item list-group-item-secondary">Invite from address : <code>{{ invite_from_address|default('Not set') }}</code></li>
<li class="list-group-item list-group-item-secondary">Server timezone : <code>{{ timezone }}</code> <a class="small ml-2" target="_blank" href="https://www.php.net/manual/en/datetime.configuration.php#ini.date.timezone">How to change it ?</a></li>
<li class="list-group-item list-group-item-primary">{{ "dashboard.version"|trans }} : <code>{{ version }}</code> (SabreDAV <code>{{ sabredav_version }}</code>)</li>
<li class="list-group-item list-group-item-secondary">{{ "dashboard.auth_realm"|trans }} : <code>{{ authRealm }}</code></li>
<li class="list-group-item list-group-item-secondary">{{ "dashboard.invite_from_address"|trans }} : <code>{{ invite_from_address|default('Not set') }}</code></li>
<li class="list-group-item list-group-item-secondary">{{ "dashboard.server_timezone"|trans }} : <code>{{ timezone }}</code> <a class="small ml-2" target="_blank" href="https://www.php.net/manual/en/datetime.configuration.php#ini.date.timezone">{{ "dashboard.how_to_change_it"|trans }}</a></li>
{% if calDAVEnabled %}
<li class="list-group-item d-flex justify-content-between align-items-center list-group-item-success">CalDAV
<span class="badge badge-success badge-pill">enabled</span></li>
<span class="badge badge-success badge-pill">{{ "enabled"|trans }}</span></li>
{% else %}
<li class="list-group-item d-flex justify-content-between align-items-center list-group-item-danger">CalDAV
<span class="badge badge-danger badge-pill">enabled</span></li>
<span class="badge badge-danger badge-pill">{{ "disabled"|trans }}</span></li>
{% endif %}
{% if cardDAVEnabled %}
<li class="list-group-item d-flex justify-content-between align-items-center list-group-item-success">CardDAV
<span class="badge badge-success badge-pill">enabled</span></li>
<span class="badge badge-success badge-pill">{{ "enabled"|trans }}</span></li>
{% else %}
<li class="list-group-item d-flex justify-content-between align-items-center list-group-item-danger">CardDAV
<span class="badge badge-danger badge-pill">disabled</span></li>
<span class="badge badge-danger badge-pill">{{ "disabled"|trans }}</span></li>
{% endif %}
</ul>
</div>
<div class="col-md">
<h3 class="mb-3 mt-4">Objects</h3>
<h3 class="mb-3 mt-4">{{ "dashboard.objects"|trans }}</h3>
<ul class="list-group mb-5">
<li class="list-group-item d-flex justify-content-between align-items-center">
Users <span class="badge badge-primary badge-pill">{{ users|length }}</span>
{{ "dashboard.users"|trans }} <span class="badge badge-primary badge-pill">{{ users|length }}</span>
</li>
<li class="list-group-item d-flex justify-content-between align-items-center">
Calendars <span class="badge badge-primary badge-pill">{{ calendars|length }}</span>
{{ "dashboard.calendars"|trans }} <span class="badge badge-primary badge-pill">{{ calendars|length }}</span>
</li>
<li class="list-group-item d-flex justify-content-between align-items-center">
Events <span class="badge badge-secondary badge-pill">{{ events|length }}</span>
{{ "dashboard.events"|trans }} <span class="badge badge-secondary badge-pill">{{ events|length }}</span>
</li>
<li class="list-group-item d-flex justify-content-between align-items-center">
Address books <span class="badge badge-primary badge-pill">{{ addressbooks|length }}</span>
{{ "dashboard.address_books"|trans }} <span class="badge badge-primary badge-pill">{{ addressbooks|length }}</span>
</li>
<li class="list-group-item d-flex justify-content-between align-items-center">
Contacts <span class="badge badge-secondary badge-pill">{{ contacts|length }}</span>
{{ "dashboard.contacts"|trans }} <span class="badge badge-secondary badge-pill">{{ contacts|length }}</span>
</li>
</ul>
</div>

View File

@ -47,10 +47,10 @@
<body>
<div class="hero">
<img src="/images/logo.png" width="60px">
<h3>Davis is running.</h3>
<div>CalDAV : {% if calDAVEnabled %}<span class="badge badge-success">enabled</span>{% else %}<span class="badge badge-warning">disabled</span>{% endif %}</div>
<div>CardDAV : {% if cardDAVEnabled %}<span class="badge badge-success">enabled</span>{% else %}<span class="badge badge-warning">disabled</span>{% endif %}</div>
<a href="{{ path('dashboard') }}" class="admin">Administration interface</a>
<h3>{{ "davis.running"|trans }}</h3>
<div>CalDAV : {% if calDAVEnabled %}<span class="badge badge-success">{{ "enabled"|trans }}</span>{% else %}<span class="badge badge-warning">{{ "disabled"|trans }}</span>{% endif %}</div>
<div>CardDAV : {% if cardDAVEnabled %}<span class="badge badge-success">{{ "enabled"|trans }}</span>{% else %}<span class="badge badge-warning">{{ "disabled"|trans }}</span>{% endif %}</div>
<a href="{{ path('dashboard') }}" class="admin">{{ "admin.interface"|trans }}</a>
</div>
</body>
</html>

View File

@ -3,12 +3,12 @@
{% block body %}
<a href="{{ path('users') }}" class="btn btn-link">« Back to Users</a>
<a href="{{ path('users') }}" class="btn btn-link">« {{ "users.back"|trans }}</a>
{% if username %}
<h1 class="display-4 mb-5">Editing user {{ username }}</h1>
<h1 class="display-4 mb-5">{{ "users.edit"|trans({'username': username }) }}</h1>
{% else %}
<h1 class="display-4 mb-5">New user</h1>
<h1 class="display-4 mb-5">{{ "users.new"|trans }}</h1>
{% endif %}
{{ form(form) }}

View File

@ -3,7 +3,7 @@
{% block body %}
<h1 class="display-4 d-flex justify-content-between">Users<a href="{{ path('user_create') }}" class="btn btn-success mb-auto mt-auto">+ New user</a></h1>
<h1 class="display-4 d-flex justify-content-between">{{ "title.users_and_resources"|trans }}<a href="{{ path('user_create') }}" class="btn btn-success mb-auto mt-auto">+ {{ "users.new"|trans }}</a></h1>
<div class="list-group mt-5">
{% for principal in principals %}
@ -11,13 +11,13 @@
<div class="d-flex w-100 justify-content-between">
<h5 class="mb-1 mr-auto">{{ principal.displayName }} <a href="mailto:{{ principal.email }}">&lsaquo;{{ principal.email }}&rsaquo;</a></h5>
<a href="{{ path('calendars',{username: principal.username}) }}" class="btn btn-light">🗓 Calendars</a>
<a href="{{ path('address_books',{username: principal.username})}}" class="btn btn-light ml-1">📖 Address books</a>
<a href="{{ path('user_edit',{username: principal.username})}}" class="btn btn-primary ml-1">✎ Edit</a>
<a href="{{ path('user_delete',{username: principal.username})}}" class="btn btn-danger ml-1">⚠ Delete</a>
<a href="{{ path('calendars',{username: principal.username}) }}" class="btn btn-light">🗓 {{ "users.calendars"|trans }}</a>
<a href="{{ path('address_books',{username: principal.username})}}" class="btn btn-light ml-1">📖 {{ "users.addressbooks"|trans }}</a>
<a href="{{ path('user_edit',{username: principal.username})}}" class="btn btn-primary ml-1">✎ {{ "edit"|trans }}</a>
<a href="{{ path('user_delete',{username: principal.username})}}" class="btn btn-danger ml-1">⚠ {{ "delete"|trans }}</a>
</div>
<p class="mb-1">Username : <code>{{ principal.username }}</code></p>
<small>Principal URI : <code>{{ principal.uri }}</code></small>
<p class="mb-1">{{ "users.username"|trans }} : <code>{{ principal.username }}</code></p>
<small>{{ "users.uri"|trans }} : <code>{{ principal.uri }}</code></small>
</div>
{% endfor %}
</div>