diff options
Diffstat (limited to 'src/Wallabag/UserBundle')
8 files changed, 247 insertions, 60 deletions
diff --git a/src/Wallabag/UserBundle/Controller/ManageController.php b/src/Wallabag/UserBundle/Controller/ManageController.php index 92ee2b41..084f2c67 100644 --- a/src/Wallabag/UserBundle/Controller/ManageController.php +++ b/src/Wallabag/UserBundle/Controller/ManageController.php | |||
@@ -4,12 +4,15 @@ namespace Wallabag\UserBundle\Controller; | |||
4 | 4 | ||
5 | use FOS\UserBundle\Event\UserEvent; | 5 | use FOS\UserBundle\Event\UserEvent; |
6 | use FOS\UserBundle\FOSUserEvents; | 6 | use FOS\UserBundle\FOSUserEvents; |
7 | use Pagerfanta\Adapter\DoctrineORMAdapter; | ||
8 | use Pagerfanta\Exception\OutOfRangeCurrentPageException; | ||
9 | use Pagerfanta\Pagerfanta; | ||
7 | use Symfony\Component\HttpFoundation\Request; | 10 | use Symfony\Component\HttpFoundation\Request; |
8 | use Symfony\Bundle\FrameworkBundle\Controller\Controller; | 11 | use Symfony\Bundle\FrameworkBundle\Controller\Controller; |
9 | use Sensio\Bundle\FrameworkExtraBundle\Configuration\Method; | 12 | use Sensio\Bundle\FrameworkExtraBundle\Configuration\Method; |
10 | use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route; | 13 | use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route; |
11 | use Wallabag\UserBundle\Entity\User; | 14 | use Wallabag\UserBundle\Entity\User; |
12 | use Wallabag\CoreBundle\Entity\Config; | 15 | use Wallabag\UserBundle\Form\SearchUserType; |
13 | 16 | ||
14 | /** | 17 | /** |
15 | * User controller. | 18 | * User controller. |
@@ -17,23 +20,6 @@ use Wallabag\CoreBundle\Entity\Config; | |||
17 | class ManageController extends Controller | 20 | class ManageController extends Controller |
18 | { | 21 | { |
19 | /** | 22 | /** |
20 | * Lists all User entities. | ||
21 | * | ||
22 | * @Route("/", name="user_index") | ||
23 | * @Method("GET") | ||
24 | */ | ||
25 | public function indexAction() | ||
26 | { | ||
27 | $em = $this->getDoctrine()->getManager(); | ||
28 | |||
29 | $users = $em->getRepository('WallabagUserBundle:User')->findAll(); | ||
30 | |||
31 | return $this->render('WallabagUserBundle:Manage:index.html.twig', array( | ||
32 | 'users' => $users, | ||
33 | )); | ||
34 | } | ||
35 | |||
36 | /** | ||
37 | * Creates a new User entity. | 23 | * Creates a new User entity. |
38 | * | 24 | * |
39 | * @Route("/new", name="user_new") | 25 | * @Route("/new", name="user_new") |
@@ -47,9 +33,7 @@ class ManageController extends Controller | |||
47 | // enable created user by default | 33 | // enable created user by default |
48 | $user->setEnabled(true); | 34 | $user->setEnabled(true); |
49 | 35 | ||
50 | $form = $this->createForm('Wallabag\UserBundle\Form\NewUserType', $user, [ | 36 | $form = $this->createForm('Wallabag\UserBundle\Form\NewUserType', $user); |
51 | 'validation_groups' => ['Profile'], | ||
52 | ]); | ||
53 | $form->handleRequest($request); | 37 | $form->handleRequest($request); |
54 | 38 | ||
55 | if ($form->isSubmitted() && $form->isValid()) { | 39 | if ($form->isSubmitted() && $form->isValid()) { |
@@ -146,4 +130,49 @@ class ManageController extends Controller | |||
146 | ->getForm() | 130 | ->getForm() |
147 | ; | 131 | ; |
148 | } | 132 | } |
133 | |||
134 | /** | ||
135 | * @param Request $request | ||
136 | * @param int $page | ||
137 | * | ||
138 | * @Route("/list/{page}", name="user_index", defaults={"page" = 1}) | ||
139 | * | ||
140 | * Default parameter for page is hardcoded (in duplication of the defaults from the Route) | ||
141 | * because this controller is also called inside the layout template without any page as argument | ||
142 | * | ||
143 | * @return \Symfony\Component\HttpFoundation\Response | ||
144 | */ | ||
145 | public function searchFormAction(Request $request, $page = 1) | ||
146 | { | ||
147 | $em = $this->getDoctrine()->getManager(); | ||
148 | $qb = $em->getRepository('WallabagUserBundle:User')->createQueryBuilder('u'); | ||
149 | |||
150 | $form = $this->createForm(SearchUserType::class); | ||
151 | $form->handleRequest($request); | ||
152 | |||
153 | if ($form->isSubmitted() && $form->isValid()) { | ||
154 | $this->get('logger')->info('searching users'); | ||
155 | |||
156 | $searchTerm = (isset($request->get('search_user')['term']) ? $request->get('search_user')['term'] : ''); | ||
157 | |||
158 | $qb = $em->getRepository('WallabagUserBundle:User')->getQueryBuilderForSearch($searchTerm); | ||
159 | } | ||
160 | |||
161 | $pagerAdapter = new DoctrineORMAdapter($qb->getQuery(), true, false); | ||
162 | $pagerFanta = new Pagerfanta($pagerAdapter); | ||
163 | $pagerFanta->setMaxPerPage(50); | ||
164 | |||
165 | try { | ||
166 | $pagerFanta->setCurrentPage($page); | ||
167 | } catch (OutOfRangeCurrentPageException $e) { | ||
168 | if ($page > 1) { | ||
169 | return $this->redirect($this->generateUrl('user_index', ['page' => $pagerFanta->getNbPages()]), 302); | ||
170 | } | ||
171 | } | ||
172 | |||
173 | return $this->render('WallabagUserBundle:Manage:index.html.twig', [ | ||
174 | 'searchForm' => $form->createView(), | ||
175 | 'users' => $pagerFanta, | ||
176 | ]); | ||
177 | } | ||
149 | } | 178 | } |
diff --git a/src/Wallabag/UserBundle/Entity/User.php b/src/Wallabag/UserBundle/Entity/User.php index 3a167de7..aba76ca7 100644 --- a/src/Wallabag/UserBundle/Entity/User.php +++ b/src/Wallabag/UserBundle/Entity/User.php | |||
@@ -4,11 +4,12 @@ namespace Wallabag\UserBundle\Entity; | |||
4 | 4 | ||
5 | use Doctrine\Common\Collections\ArrayCollection; | 5 | use Doctrine\Common\Collections\ArrayCollection; |
6 | use Doctrine\ORM\Mapping as ORM; | 6 | use Doctrine\ORM\Mapping as ORM; |
7 | use JMS\Serializer\Annotation\Groups; | ||
8 | use JMS\Serializer\Annotation\XmlRoot; | ||
9 | use JMS\Serializer\Annotation\Accessor; | ||
7 | use Scheb\TwoFactorBundle\Model\Email\TwoFactorInterface; | 10 | use Scheb\TwoFactorBundle\Model\Email\TwoFactorInterface; |
8 | use Scheb\TwoFactorBundle\Model\TrustedComputerInterface; | 11 | use Scheb\TwoFactorBundle\Model\TrustedComputerInterface; |
9 | use FOS\UserBundle\Model\User as BaseUser; | 12 | use FOS\UserBundle\Model\User as BaseUser; |
10 | use JMS\Serializer\Annotation\ExclusionPolicy; | ||
11 | use JMS\Serializer\Annotation\Expose; | ||
12 | use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity; | 13 | use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity; |
13 | use Symfony\Component\Security\Core\User\UserInterface; | 14 | use Symfony\Component\Security\Core\User\UserInterface; |
14 | use Wallabag\ApiBundle\Entity\Client; | 15 | use Wallabag\ApiBundle\Entity\Client; |
@@ -18,23 +19,25 @@ use Wallabag\CoreBundle\Entity\Entry; | |||
18 | /** | 19 | /** |
19 | * User. | 20 | * User. |
20 | * | 21 | * |
22 | * @XmlRoot("user") | ||
21 | * @ORM\Entity(repositoryClass="Wallabag\UserBundle\Repository\UserRepository") | 23 | * @ORM\Entity(repositoryClass="Wallabag\UserBundle\Repository\UserRepository") |
22 | * @ORM\Table(name="`user`") | 24 | * @ORM\Table(name="`user`") |
23 | * @ORM\HasLifecycleCallbacks() | 25 | * @ORM\HasLifecycleCallbacks() |
24 | * @ExclusionPolicy("all") | ||
25 | * | 26 | * |
26 | * @UniqueEntity("email") | 27 | * @UniqueEntity("email") |
27 | * @UniqueEntity("username") | 28 | * @UniqueEntity("username") |
28 | */ | 29 | */ |
29 | class User extends BaseUser implements TwoFactorInterface, TrustedComputerInterface | 30 | class User extends BaseUser implements TwoFactorInterface, TrustedComputerInterface |
30 | { | 31 | { |
32 | /** @Serializer\XmlAttribute */ | ||
31 | /** | 33 | /** |
32 | * @var int | 34 | * @var int |
33 | * | 35 | * |
34 | * @Expose | ||
35 | * @ORM\Column(name="id", type="integer") | 36 | * @ORM\Column(name="id", type="integer") |
36 | * @ORM\Id | 37 | * @ORM\Id |
37 | * @ORM\GeneratedValue(strategy="AUTO") | 38 | * @ORM\GeneratedValue(strategy="AUTO") |
39 | * | ||
40 | * @Groups({"user_api", "user_api_with_client"}) | ||
38 | */ | 41 | */ |
39 | protected $id; | 42 | protected $id; |
40 | 43 | ||
@@ -42,20 +45,40 @@ class User extends BaseUser implements TwoFactorInterface, TrustedComputerInterf | |||
42 | * @var string | 45 | * @var string |
43 | * | 46 | * |
44 | * @ORM\Column(name="name", type="text", nullable=true) | 47 | * @ORM\Column(name="name", type="text", nullable=true) |
48 | * | ||
49 | * @Groups({"user_api", "user_api_with_client"}) | ||
45 | */ | 50 | */ |
46 | protected $name; | 51 | protected $name; |
47 | 52 | ||
48 | /** | 53 | /** |
49 | * @var date | 54 | * @var string |
55 | * | ||
56 | * @Groups({"user_api", "user_api_with_client"}) | ||
57 | */ | ||
58 | protected $username; | ||
59 | |||
60 | /** | ||
61 | * @var string | ||
62 | * | ||
63 | * @Groups({"user_api", "user_api_with_client"}) | ||
64 | */ | ||
65 | protected $email; | ||
66 | |||
67 | /** | ||
68 | * @var \DateTime | ||
50 | * | 69 | * |
51 | * @ORM\Column(name="created_at", type="datetime") | 70 | * @ORM\Column(name="created_at", type="datetime") |
71 | * | ||
72 | * @Groups({"user_api", "user_api_with_client"}) | ||
52 | */ | 73 | */ |
53 | protected $createdAt; | 74 | protected $createdAt; |
54 | 75 | ||
55 | /** | 76 | /** |
56 | * @var date | 77 | * @var \DateTime |
57 | * | 78 | * |
58 | * @ORM\Column(name="updated_at", type="datetime") | 79 | * @ORM\Column(name="updated_at", type="datetime") |
80 | * | ||
81 | * @Groups({"user_api", "user_api_with_client"}) | ||
59 | */ | 82 | */ |
60 | protected $updatedAt; | 83 | protected $updatedAt; |
61 | 84 | ||
@@ -75,7 +98,8 @@ class User extends BaseUser implements TwoFactorInterface, TrustedComputerInterf | |||
75 | private $authCode; | 98 | private $authCode; |
76 | 99 | ||
77 | /** | 100 | /** |
78 | * @var bool Enabled yes/no | 101 | * @var bool |
102 | * | ||
79 | * @ORM\Column(type="boolean") | 103 | * @ORM\Column(type="boolean") |
80 | */ | 104 | */ |
81 | private $twoFactorAuthentication = false; | 105 | private $twoFactorAuthentication = false; |
@@ -86,10 +110,20 @@ class User extends BaseUser implements TwoFactorInterface, TrustedComputerInterf | |||
86 | private $trusted; | 110 | private $trusted; |
87 | 111 | ||
88 | /** | 112 | /** |
113 | * @var ArrayCollection | ||
114 | * | ||
89 | * @ORM\OneToMany(targetEntity="Wallabag\ApiBundle\Entity\Client", mappedBy="user", cascade={"remove"}) | 115 | * @ORM\OneToMany(targetEntity="Wallabag\ApiBundle\Entity\Client", mappedBy="user", cascade={"remove"}) |
90 | */ | 116 | */ |
91 | protected $clients; | 117 | protected $clients; |
92 | 118 | ||
119 | /** | ||
120 | * @see getFirstClient() below | ||
121 | * | ||
122 | * @Groups({"user_api_with_client"}) | ||
123 | * @Accessor(getter="getFirstClient") | ||
124 | */ | ||
125 | protected $default_client; | ||
126 | |||
93 | public function __construct() | 127 | public function __construct() |
94 | { | 128 | { |
95 | parent::__construct(); | 129 | parent::__construct(); |
@@ -135,7 +169,7 @@ class User extends BaseUser implements TwoFactorInterface, TrustedComputerInterf | |||
135 | } | 169 | } |
136 | 170 | ||
137 | /** | 171 | /** |
138 | * @return string | 172 | * @return \DateTime |
139 | */ | 173 | */ |
140 | public function getCreatedAt() | 174 | public function getCreatedAt() |
141 | { | 175 | { |
@@ -143,7 +177,7 @@ class User extends BaseUser implements TwoFactorInterface, TrustedComputerInterf | |||
143 | } | 177 | } |
144 | 178 | ||
145 | /** | 179 | /** |
146 | * @return string | 180 | * @return \DateTime |
147 | */ | 181 | */ |
148 | public function getUpdatedAt() | 182 | public function getUpdatedAt() |
149 | { | 183 | { |
@@ -266,4 +300,16 @@ class User extends BaseUser implements TwoFactorInterface, TrustedComputerInterf | |||
266 | { | 300 | { |
267 | return $this->clients; | 301 | return $this->clients; |
268 | } | 302 | } |
303 | |||
304 | /** | ||
305 | * Only used by the API when creating a new user it'll also return the first client (which was also created at the same time). | ||
306 | * | ||
307 | * @return Client | ||
308 | */ | ||
309 | public function getFirstClient() | ||
310 | { | ||
311 | if (!empty($this->clients)) { | ||
312 | return $this->clients->first(); | ||
313 | } | ||
314 | } | ||
269 | } | 315 | } |
diff --git a/src/Wallabag/UserBundle/EventListener/AuthenticationFailureListener.php b/src/Wallabag/UserBundle/EventListener/AuthenticationFailureListener.php new file mode 100644 index 00000000..10f13233 --- /dev/null +++ b/src/Wallabag/UserBundle/EventListener/AuthenticationFailureListener.php | |||
@@ -0,0 +1,40 @@ | |||
1 | <?php | ||
2 | |||
3 | namespace Wallabag\UserBundle\EventListener; | ||
4 | |||
5 | use Psr\Log\LoggerInterface; | ||
6 | use Symfony\Component\EventDispatcher\EventSubscriberInterface; | ||
7 | use Symfony\Component\HttpFoundation\RequestStack; | ||
8 | use Symfony\Component\Security\Core\AuthenticationEvents; | ||
9 | |||
10 | class AuthenticationFailureListener implements EventSubscriberInterface | ||
11 | { | ||
12 | private $requestStack; | ||
13 | private $logger; | ||
14 | |||
15 | public function __construct(RequestStack $requestStack, LoggerInterface $logger) | ||
16 | { | ||
17 | $this->requestStack = $requestStack; | ||
18 | $this->logger = $logger; | ||
19 | } | ||
20 | |||
21 | /** | ||
22 | * {@inheritdoc} | ||
23 | */ | ||
24 | public static function getSubscribedEvents() | ||
25 | { | ||
26 | return [ | ||
27 | AuthenticationEvents::AUTHENTICATION_FAILURE => 'onAuthenticationFailure', | ||
28 | ]; | ||
29 | } | ||
30 | |||
31 | /** | ||
32 | * On failure, add a custom error in log so server admin can configure fail2ban to block IP from people who try to login too much. | ||
33 | */ | ||
34 | public function onAuthenticationFailure() | ||
35 | { | ||
36 | $request = $this->requestStack->getMasterRequest(); | ||
37 | |||
38 | $this->logger->error('Authentication failure for user "'.$request->request->get('_username').'", from IP "'.$request->getClientIp().'", with UA: "'.$request->server->get('HTTP_USER_AGENT').'".'); | ||
39 | } | ||
40 | } | ||
diff --git a/src/Wallabag/UserBundle/EventListener/CreateConfigListener.php b/src/Wallabag/UserBundle/EventListener/CreateConfigListener.php index 0bdd1cae..e4d55c19 100644 --- a/src/Wallabag/UserBundle/EventListener/CreateConfigListener.php +++ b/src/Wallabag/UserBundle/EventListener/CreateConfigListener.php | |||
@@ -5,7 +5,6 @@ namespace Wallabag\UserBundle\EventListener; | |||
5 | use Doctrine\ORM\EntityManager; | 5 | use Doctrine\ORM\EntityManager; |
6 | use FOS\UserBundle\Event\UserEvent; | 6 | use FOS\UserBundle\Event\UserEvent; |
7 | use FOS\UserBundle\FOSUserEvents; | 7 | use FOS\UserBundle\FOSUserEvents; |
8 | use Symfony\Component\EventDispatcher\EventDispatcherInterface; | ||
9 | use Symfony\Component\EventDispatcher\EventSubscriberInterface; | 8 | use Symfony\Component\EventDispatcher\EventSubscriberInterface; |
10 | use Wallabag\CoreBundle\Entity\Config; | 9 | use Wallabag\CoreBundle\Entity\Config; |
11 | 10 | ||
@@ -47,7 +46,7 @@ class CreateConfigListener implements EventSubscriberInterface | |||
47 | ]; | 46 | ]; |
48 | } | 47 | } |
49 | 48 | ||
50 | public function createConfig(UserEvent $event, $eventName = null, EventDispatcherInterface $eventDispatcher = null) | 49 | public function createConfig(UserEvent $event) |
51 | { | 50 | { |
52 | $config = new Config($event->getUser()); | 51 | $config = new Config($event->getUser()); |
53 | $config->setTheme($this->theme); | 52 | $config->setTheme($this->theme); |
diff --git a/src/Wallabag/UserBundle/Form/SearchUserType.php b/src/Wallabag/UserBundle/Form/SearchUserType.php new file mode 100644 index 00000000..9ce46ee1 --- /dev/null +++ b/src/Wallabag/UserBundle/Form/SearchUserType.php | |||
@@ -0,0 +1,29 @@ | |||
1 | <?php | ||
2 | |||
3 | namespace Wallabag\UserBundle\Form; | ||
4 | |||
5 | use Symfony\Component\Form\AbstractType; | ||
6 | use Symfony\Component\Form\Extension\Core\Type\TextType; | ||
7 | use Symfony\Component\Form\FormBuilderInterface; | ||
8 | use Symfony\Component\OptionsResolver\OptionsResolver; | ||
9 | |||
10 | class SearchUserType extends AbstractType | ||
11 | { | ||
12 | public function buildForm(FormBuilderInterface $builder, array $options) | ||
13 | { | ||
14 | $builder | ||
15 | ->setMethod('GET') | ||
16 | ->add('term', TextType::class, [ | ||
17 | 'required' => true, | ||
18 | 'label' => 'user.new.form_search.term_label', | ||
19 | ]) | ||
20 | ; | ||
21 | } | ||
22 | |||
23 | public function configureOptions(OptionsResolver $resolver) | ||
24 | { | ||
25 | $resolver->setDefaults([ | ||
26 | 'csrf_protection' => false, | ||
27 | ]); | ||
28 | } | ||
29 | } | ||
diff --git a/src/Wallabag/UserBundle/Repository/UserRepository.php b/src/Wallabag/UserBundle/Repository/UserRepository.php index f913f52d..6adbe329 100644 --- a/src/Wallabag/UserBundle/Repository/UserRepository.php +++ b/src/Wallabag/UserBundle/Repository/UserRepository.php | |||
@@ -52,4 +52,17 @@ class UserRepository extends EntityRepository | |||
52 | ->getQuery() | 52 | ->getQuery() |
53 | ->getSingleScalarResult(); | 53 | ->getSingleScalarResult(); |
54 | } | 54 | } |
55 | |||
56 | /** | ||
57 | * Retrieves users filtered with a search term. | ||
58 | * | ||
59 | * @param string $term | ||
60 | * | ||
61 | * @return QueryBuilder | ||
62 | */ | ||
63 | public function getQueryBuilderForSearch($term) | ||
64 | { | ||
65 | return $this->createQueryBuilder('u') | ||
66 | ->andWhere('lower(u.username) LIKE lower(:term) OR lower(u.email) LIKE lower(:term) OR lower(u.name) LIKE lower(:term)')->setParameter('term', '%'.$term.'%'); | ||
67 | } | ||
55 | } | 68 | } |
diff --git a/src/Wallabag/UserBundle/Resources/config/services.yml b/src/Wallabag/UserBundle/Resources/config/services.yml index 72f6f12c..d3925de3 100644 --- a/src/Wallabag/UserBundle/Resources/config/services.yml +++ b/src/Wallabag/UserBundle/Resources/config/services.yml | |||
@@ -7,7 +7,7 @@ services: | |||
7 | - "%scheb_two_factor.email.sender_email%" | 7 | - "%scheb_two_factor.email.sender_email%" |
8 | - "%scheb_two_factor.email.sender_name%" | 8 | - "%scheb_two_factor.email.sender_name%" |
9 | - '@=service(''craue_config'').get(''wallabag_support_url'')' | 9 | - '@=service(''craue_config'').get(''wallabag_support_url'')' |
10 | - '@=service(''craue_config'').get(''wallabag_url'')' | 10 | - '%domain_name%' |
11 | 11 | ||
12 | wallabag_user.password_resetting: | 12 | wallabag_user.password_resetting: |
13 | class: Wallabag\UserBundle\EventListener\PasswordResettingListener | 13 | class: Wallabag\UserBundle\EventListener\PasswordResettingListener |
@@ -35,3 +35,11 @@ services: | |||
35 | - "%wallabag_core.list_mode%" | 35 | - "%wallabag_core.list_mode%" |
36 | tags: | 36 | tags: |
37 | - { name: kernel.event_subscriber } | 37 | - { name: kernel.event_subscriber } |
38 | |||
39 | wallabag_user.listener.authentication_failure_event_listener: | ||
40 | class: Wallabag\UserBundle\EventListener\AuthenticationFailureListener | ||
41 | arguments: | ||
42 | - "@request_stack" | ||
43 | - "@logger" | ||
44 | tags: | ||
45 | - { name: kernel.event_listener, event: security.authentication.failure, method: onAuthenticationFailure } | ||
diff --git a/src/Wallabag/UserBundle/Resources/views/Manage/index.html.twig b/src/Wallabag/UserBundle/Resources/views/Manage/index.html.twig index daba29e4..15002632 100644 --- a/src/Wallabag/UserBundle/Resources/views/Manage/index.html.twig +++ b/src/Wallabag/UserBundle/Resources/views/Manage/index.html.twig | |||
@@ -7,37 +7,60 @@ | |||
7 | <div class="row"> | 7 | <div class="row"> |
8 | <div class="col s12"> | 8 | <div class="col s12"> |
9 | <div class="card-panel"> | 9 | <div class="card-panel"> |
10 | {% if users.getNbPages > 1 %} | ||
11 | {{ pagerfanta(users, 'twitter_bootstrap_translated', {'proximity': 1}) }} | ||
12 | {% endif %} | ||
10 | <div class="row"> | 13 | <div class="row"> |
11 | <div class="input-field col s12"> | 14 | <div class="col s6"> |
12 | <p class="help">{{ 'user.description'|trans|raw }}</p> | 15 | <p class="help">{{ 'user.description'|trans|raw }}</p> |
16 | </div> | ||
17 | <div class="col s6"> | ||
18 | <div class="input-field"> | ||
19 | <form name="search_users" method="GET" action="{{ path('user_index')}}"> | ||
20 | {% if form_errors(searchForm) %} | ||
21 | <span class="black-text">{{ form_errors(searchForm) }}</span> | ||
22 | {% endif %} | ||
23 | |||
24 | {% if form_errors(searchForm.term) %} | ||
25 | <span class="black-text">{{ form_errors(searchForm.term) }}</span> | ||
26 | {% endif %} | ||
13 | 27 | ||
14 | <table class="bordered"> | 28 | {{ form_widget(searchForm.term, { 'attr': {'autocomplete': 'off', 'placeholder': 'user.search.placeholder'} }) }} |
15 | <thead> | 29 | |
16 | <tr> | 30 | {{ form_rest(searchForm) }} |
17 | <th>{{ 'user.form.username_label'|trans }}</th> | 31 | </form> |
18 | <th>{{ 'user.form.email_label'|trans }}</th> | 32 | </div> |
19 | <th>{{ 'user.form.last_login_label'|trans }}</th> | ||
20 | <th>{{ 'user.list.actions'|trans }}</th> | ||
21 | </tr> | ||
22 | </thead> | ||
23 | <tbody> | ||
24 | {% for user in users %} | ||
25 | <tr> | ||
26 | <td>{{ user.username }}</td> | ||
27 | <td>{{ user.email }}</td> | ||
28 | <td>{% if user.lastLogin %}{{ user.lastLogin|date('Y-m-d H:i:s') }}{% endif %}</td> | ||
29 | <td> | ||
30 | <a href="{{ path('user_edit', { 'id': user.id }) }}">{{ 'user.list.edit_action'|trans }}</a> | ||
31 | </td> | ||
32 | </tr> | ||
33 | {% endfor %} | ||
34 | </tbody> | ||
35 | </table> | ||
36 | <br /> | ||
37 | <p> | ||
38 | <a href="{{ path('user_new') }}" class="waves-effect waves-light btn">{{ 'user.list.create_new_one'|trans }}</a> | ||
39 | </p> | ||
40 | </div> | 33 | </div> |
34 | |||
35 | <table class="bordered"> | ||
36 | <thead> | ||
37 | <tr> | ||
38 | <th>{{ 'user.form.username_label'|trans }}</th> | ||
39 | <th>{{ 'user.form.email_label'|trans }}</th> | ||
40 | <th>{{ 'user.form.last_login_label'|trans }}</th> | ||
41 | <th>{{ 'user.list.actions'|trans }}</th> | ||
42 | </tr> | ||
43 | </thead> | ||
44 | <tbody> | ||
45 | {% for user in users %} | ||
46 | <tr> | ||
47 | <td>{{ user.username }}</td> | ||
48 | <td>{{ user.email }}</td> | ||
49 | <td>{% if user.lastLogin %}{{ user.lastLogin|date('Y-m-d H:i:s') }}{% endif %}</td> | ||
50 | <td> | ||
51 | <a href="{{ path('user_edit', { 'id': user.id }) }}">{{ 'user.list.edit_action'|trans }}</a> | ||
52 | </td> | ||
53 | </tr> | ||
54 | {% endfor %} | ||
55 | </tbody> | ||
56 | </table> | ||
57 | <br /> | ||
58 | <p> | ||
59 | <a href="{{ path('user_new') }}" class="waves-effect waves-light btn">{{ 'user.list.create_new_one'|trans }}</a> | ||
60 | </p> | ||
61 | {% if users.getNbPages > 1 %} | ||
62 | {{ pagerfanta(users, 'twitter_bootstrap_translated', {'proximity': 1}) }} | ||
63 | {% endif %} | ||
41 | </div> | 64 | </div> |
42 | </div> | 65 | </div> |
43 | </div> | 66 | </div> |