mirror of
https://github.com/wallabag/wallabag.git
synced 2025-09-15 18:57:05 +00:00
Add users management UI
- remove the “add a user” from the config page - add a CRUD on user - fix some missing translations (+ bad indentation)
This commit is contained in:
parent
52c1fc7449
commit
152fcccd44
29 changed files with 956 additions and 223 deletions
149
src/Wallabag/UserBundle/Controller/ManageController.php
Normal file
149
src/Wallabag/UserBundle/Controller/ManageController.php
Normal file
|
@ -0,0 +1,149 @@
|
|||
<?php
|
||||
|
||||
namespace Wallabag\UserBundle\Controller;
|
||||
|
||||
use FOS\UserBundle\Event\UserEvent;
|
||||
use FOS\UserBundle\FOSUserEvents;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
|
||||
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Method;
|
||||
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
|
||||
use Wallabag\UserBundle\Entity\User;
|
||||
use Wallabag\CoreBundle\Entity\Config;
|
||||
|
||||
/**
|
||||
* User controller.
|
||||
*/
|
||||
class ManageController extends Controller
|
||||
{
|
||||
/**
|
||||
* Lists all User entities.
|
||||
*
|
||||
* @Route("/", name="user_index")
|
||||
* @Method("GET")
|
||||
*/
|
||||
public function indexAction()
|
||||
{
|
||||
$em = $this->getDoctrine()->getManager();
|
||||
|
||||
$users = $em->getRepository('WallabagUserBundle:User')->findAll();
|
||||
|
||||
return $this->render('WallabagUserBundle:Manage:index.html.twig', array(
|
||||
'users' => $users,
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new User entity.
|
||||
*
|
||||
* @Route("/new", name="user_new")
|
||||
* @Method({"GET", "POST"})
|
||||
*/
|
||||
public function newAction(Request $request)
|
||||
{
|
||||
$userManager = $this->container->get('fos_user.user_manager');
|
||||
|
||||
$user = $userManager->createUser();
|
||||
// enable created user by default
|
||||
$user->setEnabled(true);
|
||||
|
||||
$form = $this->createForm('Wallabag\UserBundle\Form\NewUserType', $user, [
|
||||
'validation_groups' => ['Profile'],
|
||||
]);
|
||||
$form->handleRequest($request);
|
||||
|
||||
if ($form->isSubmitted() && $form->isValid()) {
|
||||
$userManager->updateUser($user);
|
||||
|
||||
// dispatch a created event so the associated config will be created
|
||||
$event = new UserEvent($user, $request);
|
||||
$this->get('event_dispatcher')->dispatch(FOSUserEvents::USER_CREATED, $event);
|
||||
|
||||
$this->get('session')->getFlashBag()->add(
|
||||
'notice',
|
||||
$this->get('translator')->trans('flashes.user.notice.added', ['%username%' => $user->getUsername()])
|
||||
);
|
||||
|
||||
return $this->redirectToRoute('user_edit', array('id' => $user->getId()));
|
||||
}
|
||||
|
||||
return $this->render('WallabagUserBundle:Manage:new.html.twig', array(
|
||||
'user' => $user,
|
||||
'form' => $form->createView(),
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays a form to edit an existing User entity.
|
||||
*
|
||||
* @Route("/{id}/edit", name="user_edit")
|
||||
* @Method({"GET", "POST"})
|
||||
*/
|
||||
public function editAction(Request $request, User $user)
|
||||
{
|
||||
$deleteForm = $this->createDeleteForm($user);
|
||||
$editForm = $this->createForm('Wallabag\UserBundle\Form\UserType', $user);
|
||||
$editForm->handleRequest($request);
|
||||
|
||||
if ($editForm->isSubmitted() && $editForm->isValid()) {
|
||||
$em = $this->getDoctrine()->getManager();
|
||||
$em->persist($user);
|
||||
$em->flush();
|
||||
|
||||
$this->get('session')->getFlashBag()->add(
|
||||
'notice',
|
||||
$this->get('translator')->trans('flashes.user.notice.updated', ['%username%' => $user->getUsername()])
|
||||
);
|
||||
|
||||
return $this->redirectToRoute('user_edit', array('id' => $user->getId()));
|
||||
}
|
||||
|
||||
return $this->render('WallabagUserBundle:Manage:edit.html.twig', array(
|
||||
'user' => $user,
|
||||
'edit_form' => $editForm->createView(),
|
||||
'delete_form' => $deleteForm->createView(),
|
||||
'twofactor_auth' => $this->getParameter('twofactor_auth'),
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes a User entity.
|
||||
*
|
||||
* @Route("/{id}", name="user_delete")
|
||||
* @Method("DELETE")
|
||||
*/
|
||||
public function deleteAction(Request $request, User $user)
|
||||
{
|
||||
$form = $this->createDeleteForm($user);
|
||||
$form->handleRequest($request);
|
||||
|
||||
if ($form->isSubmitted() && $form->isValid()) {
|
||||
$this->get('session')->getFlashBag()->add(
|
||||
'notice',
|
||||
$this->get('translator')->trans('flashes.user.notice.deleted', ['%username%' => $user->getUsername()])
|
||||
);
|
||||
|
||||
$em = $this->getDoctrine()->getManager();
|
||||
$em->remove($user);
|
||||
$em->flush();
|
||||
}
|
||||
|
||||
return $this->redirectToRoute('user_index');
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a form to delete a User entity.
|
||||
*
|
||||
* @param User $user The User entity
|
||||
*
|
||||
* @return \Symfony\Component\Form\Form The form
|
||||
*/
|
||||
private function createDeleteForm(User $user)
|
||||
{
|
||||
return $this->createFormBuilder()
|
||||
->setAction($this->generateUrl('user_delete', array('id' => $user->getId())))
|
||||
->setMethod('DELETE')
|
||||
->getForm()
|
||||
;
|
||||
}
|
||||
}
|
|
@ -64,7 +64,7 @@ class User extends BaseUser implements TwoFactorInterface, TrustedComputerInterf
|
|||
protected $entries;
|
||||
|
||||
/**
|
||||
* @ORM\OneToOne(targetEntity="Wallabag\CoreBundle\Entity\Config", mappedBy="user")
|
||||
* @ORM\OneToOne(targetEntity="Wallabag\CoreBundle\Entity\Config", mappedBy="user", cascade={"remove"})
|
||||
*/
|
||||
protected $config;
|
||||
|
||||
|
|
58
src/Wallabag/UserBundle/Form/NewUserType.php
Normal file
58
src/Wallabag/UserBundle/Form/NewUserType.php
Normal file
|
@ -0,0 +1,58 @@
|
|||
<?php
|
||||
|
||||
namespace Wallabag\UserBundle\Form;
|
||||
|
||||
use Symfony\Component\Form\AbstractType;
|
||||
use Symfony\Component\Form\Extension\Core\Type\EmailType;
|
||||
use Symfony\Component\Form\Extension\Core\Type\PasswordType;
|
||||
use Symfony\Component\Form\Extension\Core\Type\RepeatedType;
|
||||
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
|
||||
use Symfony\Component\Form\Extension\Core\Type\TextType;
|
||||
use Symfony\Component\Form\FormBuilderInterface;
|
||||
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||
use Symfony\Component\Validator\Constraints;
|
||||
|
||||
class NewUserType extends AbstractType
|
||||
{
|
||||
public function buildForm(FormBuilderInterface $builder, array $options)
|
||||
{
|
||||
$builder
|
||||
->add('username', TextType::class, [
|
||||
'required' => true,
|
||||
'label' => 'user.form.username_label',
|
||||
])
|
||||
->add('plainPassword', RepeatedType::class, [
|
||||
'type' => PasswordType::class,
|
||||
'invalid_message' => 'validator.password_must_match',
|
||||
'first_options' => ['label' => 'user.form.password_label'],
|
||||
'second_options' => ['label' => 'user.form.repeat_new_password_label'],
|
||||
'constraints' => [
|
||||
new Constraints\Length([
|
||||
'min' => 8,
|
||||
'minMessage' => 'validator.password_too_short',
|
||||
]),
|
||||
new Constraints\NotBlank(),
|
||||
],
|
||||
'label' => 'user.form.plain_password_label',
|
||||
])
|
||||
->add('email', EmailType::class, [
|
||||
'label' => 'user.form.email_label',
|
||||
])
|
||||
->add('save', SubmitType::class, [
|
||||
'label' => 'user.form.save',
|
||||
])
|
||||
;
|
||||
}
|
||||
|
||||
public function configureOptions(OptionsResolver $resolver)
|
||||
{
|
||||
$resolver->setDefaults([
|
||||
'data_class' => 'Wallabag\UserBundle\Entity\User',
|
||||
]);
|
||||
}
|
||||
|
||||
public function getBlockPrefix()
|
||||
{
|
||||
return 'new_user';
|
||||
}
|
||||
}
|
61
src/Wallabag/UserBundle/Form/UserType.php
Normal file
61
src/Wallabag/UserBundle/Form/UserType.php
Normal file
|
@ -0,0 +1,61 @@
|
|||
<?php
|
||||
|
||||
namespace Wallabag\UserBundle\Form;
|
||||
|
||||
use Symfony\Component\Form\AbstractType;
|
||||
use Symfony\Component\Form\FormBuilderInterface;
|
||||
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||
use Symfony\Component\Form\Extension\Core\Type\CheckboxType;
|
||||
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
|
||||
use Symfony\Component\Form\Extension\Core\Type\TextType;
|
||||
use Symfony\Component\Form\Extension\Core\Type\EmailType;
|
||||
|
||||
class UserType extends AbstractType
|
||||
{
|
||||
/**
|
||||
* @param FormBuilderInterface $builder
|
||||
* @param array $options
|
||||
*/
|
||||
public function buildForm(FormBuilderInterface $builder, array $options)
|
||||
{
|
||||
$builder
|
||||
->add('name', TextType::class, [
|
||||
'required' => false,
|
||||
'label' => 'user.form.name_label',
|
||||
])
|
||||
->add('username', TextType::class, [
|
||||
'required' => true,
|
||||
'label' => 'user.form.username_label',
|
||||
])
|
||||
->add('email', EmailType::class, [
|
||||
'required' => true,
|
||||
'label' => 'user.form.email_label',
|
||||
])
|
||||
->add('enabled', CheckboxType::class, [
|
||||
'required' => false,
|
||||
'label' => 'user.form.enabled_label',
|
||||
])
|
||||
->add('locked', CheckboxType::class, [
|
||||
'required' => false,
|
||||
'label' => 'user.form.locked_label',
|
||||
])
|
||||
->add('twoFactorAuthentication', CheckboxType::class, [
|
||||
'required' => false,
|
||||
'label' => 'user.form.twofactor_label',
|
||||
])
|
||||
->add('save', SubmitType::class, [
|
||||
'label' => 'user.form.save',
|
||||
])
|
||||
;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param OptionsResolver $resolver
|
||||
*/
|
||||
public function configureOptions(OptionsResolver $resolver)
|
||||
{
|
||||
$resolver->setDefaults(array(
|
||||
'data_class' => 'Wallabag\UserBundle\Entity\User',
|
||||
));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,86 @@
|
|||
{% extends "WallabagCoreBundle::layout.html.twig" %}
|
||||
|
||||
{% block title %}{{ 'user.page_title'|trans }}{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
<div class="row">
|
||||
<div class="col s12">
|
||||
<div class="card-panel">
|
||||
<div class="row">
|
||||
<div class="input-field col s12">
|
||||
<h4>{{ 'user.edit_user'|trans }}</h4>
|
||||
|
||||
<div id="set6" class="col s12">
|
||||
{{ form_start(edit_form) }}
|
||||
{{ form_errors(edit_form) }}
|
||||
|
||||
<div class="row">
|
||||
<div class="input-field col s12">
|
||||
{{ form_label(edit_form.name) }}
|
||||
{{ form_errors(edit_form.name) }}
|
||||
{{ form_widget(edit_form.name) }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="input-field col s12">
|
||||
{{ form_label(edit_form.username) }}
|
||||
{{ form_errors(edit_form.username) }}
|
||||
{{ form_widget(edit_form.username) }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="input-field col s12">
|
||||
{{ form_label(edit_form.email) }}
|
||||
{{ form_errors(edit_form.email) }}
|
||||
{{ form_widget(edit_form.email) }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="input-field col s12">
|
||||
{{ form_widget(edit_form.enabled) }}
|
||||
{{ form_label(edit_form.enabled) }}
|
||||
{{ form_errors(edit_form.enabled) }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="input-field col s12">
|
||||
{{ form_widget(edit_form.locked) }}
|
||||
{{ form_label(edit_form.locked) }}
|
||||
{{ form_errors(edit_form.locked) }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% if twofactor_auth %}
|
||||
<div class="row">
|
||||
<div class="input-field col s12">
|
||||
{{ form_widget(edit_form.twoFactorAuthentication) }}
|
||||
{{ form_label(edit_form.twoFactorAuthentication) }}
|
||||
{{ form_errors(edit_form.twoFactorAuthentication) }}
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<br/>
|
||||
|
||||
{{ form_widget(edit_form.save, {'attr': {'class': 'btn waves-effect waves-light'}}) }}
|
||||
{{ form_rest(edit_form) }}
|
||||
</form>
|
||||
<p>
|
||||
{{ form_start(delete_form) }}
|
||||
<button onclick="return confirm('{{ 'user.form.delete_confirm'|trans|escape('js') }}')" type="submit" class="btn waves-effect waves-light red">{{ 'user.form.delete'|trans }}</button>
|
||||
{{ form_end(delete_form) }}
|
||||
</p>
|
||||
<p><a class="waves-effect waves-light btn blue-grey" href="{{ path('user_index') }}">{{ 'user.form.back_to_list'|trans }}</a></p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
|
@ -0,0 +1,48 @@
|
|||
{% extends "WallabagCoreBundle::layout.html.twig" %}
|
||||
|
||||
{% block title %}{{ 'user.page_title'|trans }}{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
<div class="row">
|
||||
<div class="col s12">
|
||||
<div class="card-panel">
|
||||
<div class="row">
|
||||
<div class="input-field col s12">
|
||||
<p class="help">{{ 'user.description'|trans|raw }}</p>
|
||||
|
||||
<table class="bordered">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>{{ 'user.form.username_label'|trans }}</th>
|
||||
<th>{{ 'user.form.email_label'|trans }}</th>
|
||||
<th>{{ 'user.form.last_login_label'|trans }}</th>
|
||||
<th>{{ 'user.form.locked_label'|trans }}</th>
|
||||
<th>{{ 'user.list.actions'|trans }}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for user in users %}
|
||||
<tr>
|
||||
<td>{{ user.username }}</td>
|
||||
<td>{{ user.email }}</td>
|
||||
<td>{% if user.lastLogin %}{{ user.lastLogin|date('Y-m-d H:i:s') }}{% endif %}</td>
|
||||
<td>{% if user.locked %}{{ 'user.list.yes'|trans }}{% else %}{{ 'user.list.no'|trans }}{% endif %}</td>
|
||||
<td>
|
||||
<a href="{{ path('user_edit', { 'id': user.id }) }}">{{ 'user.list.edit_action'|trans }}</a>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
<br />
|
||||
<p>
|
||||
<a href="{{ path('user_new') }}" class="waves-effect waves-light btn">{{ 'user.list.create_new_one'|trans }}</a>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
61
src/Wallabag/UserBundle/Resources/views/Manage/new.html.twig
Normal file
61
src/Wallabag/UserBundle/Resources/views/Manage/new.html.twig
Normal file
|
@ -0,0 +1,61 @@
|
|||
{% extends "WallabagCoreBundle::layout.html.twig" %}
|
||||
|
||||
{% block title %}{{ 'user.page_title'|trans }}{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
<div class="row">
|
||||
<div class="col s12">
|
||||
<div class="card-panel">
|
||||
<div class="row">
|
||||
<div class="input-field col s12">
|
||||
<h4>{{ 'user.new_user'|trans }}</h4>
|
||||
|
||||
<div id="set6" class="col s12">
|
||||
{{ form_start(form) }}
|
||||
{{ form_errors(form) }}
|
||||
|
||||
<div class="row">
|
||||
<div class="input-field col s12">
|
||||
{{ form_label(form.username) }}
|
||||
{{ form_errors(form.username) }}
|
||||
{{ form_widget(form.username) }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="input-field col s12">
|
||||
{{ form_label(form.plainPassword.first) }}
|
||||
{{ form_errors(form.plainPassword.first) }}
|
||||
{{ form_widget(form.plainPassword.first) }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="input-field col s12">
|
||||
{{ form_label(form.plainPassword.second) }}
|
||||
{{ form_errors(form.plainPassword.second) }}
|
||||
{{ form_widget(form.plainPassword.second) }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="input-field col s12">
|
||||
{{ form_label(form.email) }}
|
||||
{{ form_errors(form.email) }}
|
||||
{{ form_widget(form.email) }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{ form_widget(form.save, {'attr': {'class': 'btn waves-effect waves-light'}}) }}
|
||||
{{ form_rest(form) }}
|
||||
</form>
|
||||
<p><a class="waves-effect waves-light btn blue-grey" href="{{ path('user_index') }}">{{ 'user.form.back_to_list'|trans }}</a></p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
43
src/Wallabag/UserBundle/Resources/views/manage.html.twig
Normal file
43
src/Wallabag/UserBundle/Resources/views/manage.html.twig
Normal file
|
@ -0,0 +1,43 @@
|
|||
{% extends "WallabagCoreBundle::layout.html.twig" %}
|
||||
|
||||
{% block title %}{{ 'user.manage.page_title'|trans }}{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
<div class="row">
|
||||
<div class="col s12">
|
||||
<div class="card-panel">
|
||||
<div class="row">
|
||||
<div class="input-field col s12">
|
||||
<p class="help">{{ 'user.manage.description'|trans|raw }}</p>
|
||||
|
||||
<table class="bordered">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>{{ 'user.manage.field.username'|trans }}</th>
|
||||
<th>{{ 'user.manage.field.email'|trans }}</th>
|
||||
<th>{{ 'user.manage.field.last_login'|trans }}</th>
|
||||
<th>{{ 'user.manage.field.locked'|trans }}</th>
|
||||
<th>{{ 'user.manage.action'|trans }}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
<tbody>
|
||||
{% for user in users %}
|
||||
<tr>
|
||||
<td>{{ user.username }}</td>
|
||||
<td>{{ user.email }}</td>
|
||||
<td>{{ user.lastLogin|date('d/m/Y H:i:s') }}</td>
|
||||
<td>{{ user.locked ? 'yes' : 'no' }}</td>
|
||||
<td>edit - delete</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
Loading…
Add table
Add a link
Reference in a new issue