aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/Wallabag/UserBundle
diff options
context:
space:
mode:
authorJérémy Benoist <j0k3r@users.noreply.github.com>2017-10-23 11:09:17 +0200
committerGitHub <noreply@github.com>2017-10-23 11:09:17 +0200
commit1953a872932a63792293b4aec087880265ba89f7 (patch)
treefd16599e737fcdaf193c933ef3ec4a4ee248b117 /src/Wallabag/UserBundle
parentd83d25dadec2c38460a32d96f5d2903426fec9d3 (diff)
parent702f2d67d60ca963492b90dad74cb5f8dcc84e51 (diff)
downloadwallabag-1953a872932a63792293b4aec087880265ba89f7.tar.gz
wallabag-1953a872932a63792293b4aec087880265ba89f7.tar.zst
wallabag-1953a872932a63792293b4aec087880265ba89f7.zip
Merge pull request #3011 from wallabag/2.3
wallabag 2.3.0
Diffstat (limited to 'src/Wallabag/UserBundle')
-rw-r--r--src/Wallabag/UserBundle/Controller/ManageController.php89
-rw-r--r--src/Wallabag/UserBundle/DependencyInjection/WallabagUserExtension.php6
-rw-r--r--src/Wallabag/UserBundle/Entity/User.php99
-rw-r--r--src/Wallabag/UserBundle/EventListener/AuthenticationFailureListener.php40
-rw-r--r--src/Wallabag/UserBundle/EventListener/CreateConfigListener.php3
-rw-r--r--src/Wallabag/UserBundle/EventListener/PasswordResettingListener.php2
-rw-r--r--src/Wallabag/UserBundle/Form/SearchUserType.php29
-rw-r--r--src/Wallabag/UserBundle/Form/UserType.php10
-rw-r--r--src/Wallabag/UserBundle/Mailer/AuthCodeMailer.php2
-rw-r--r--src/Wallabag/UserBundle/Repository/UserRepository.php28
-rw-r--r--src/Wallabag/UserBundle/Resources/config/services.yml10
-rw-r--r--src/Wallabag/UserBundle/Resources/translations/wallabag_user.oc.yml6
-rw-r--r--src/Wallabag/UserBundle/Resources/translations/wallabag_user.ru.yml11
-rw-r--r--src/Wallabag/UserBundle/Resources/views/Manage/index.html.twig77
14 files changed, 311 insertions, 101 deletions
diff --git a/src/Wallabag/UserBundle/Controller/ManageController.php b/src/Wallabag/UserBundle/Controller/ManageController.php
index 92ee2b41..f3de656f 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
5use FOS\UserBundle\Event\UserEvent; 5use FOS\UserBundle\Event\UserEvent;
6use FOS\UserBundle\FOSUserEvents; 6use FOS\UserBundle\FOSUserEvents;
7use Symfony\Component\HttpFoundation\Request; 7use Pagerfanta\Adapter\DoctrineORMAdapter;
8use Symfony\Bundle\FrameworkBundle\Controller\Controller; 8use Pagerfanta\Exception\OutOfRangeCurrentPageException;
9use Pagerfanta\Pagerfanta;
9use Sensio\Bundle\FrameworkExtraBundle\Configuration\Method; 10use Sensio\Bundle\FrameworkExtraBundle\Configuration\Method;
10use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route; 11use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
12use Symfony\Bundle\FrameworkBundle\Controller\Controller;
13use Symfony\Component\HttpFoundation\Request;
11use Wallabag\UserBundle\Entity\User; 14use Wallabag\UserBundle\Entity\User;
12use Wallabag\CoreBundle\Entity\Config; 15use Wallabag\UserBundle\Form\SearchUserType;
13 16
14/** 17/**
15 * User controller. 18 * User controller.
@@ -17,23 +20,6 @@ use Wallabag\CoreBundle\Entity\Config;
17class ManageController extends Controller 20class 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()) {
@@ -64,13 +48,13 @@ class ManageController extends Controller
64 $this->get('translator')->trans('flashes.user.notice.added', ['%username%' => $user->getUsername()]) 48 $this->get('translator')->trans('flashes.user.notice.added', ['%username%' => $user->getUsername()])
65 ); 49 );
66 50
67 return $this->redirectToRoute('user_edit', array('id' => $user->getId())); 51 return $this->redirectToRoute('user_edit', ['id' => $user->getId()]);
68 } 52 }
69 53
70 return $this->render('WallabagUserBundle:Manage:new.html.twig', array( 54 return $this->render('WallabagUserBundle:Manage:new.html.twig', [
71 'user' => $user, 55 'user' => $user,
72 'form' => $form->createView(), 56 'form' => $form->createView(),
73 )); 57 ]);
74 } 58 }
75 59
76 /** 60 /**
@@ -95,15 +79,15 @@ class ManageController extends Controller
95 $this->get('translator')->trans('flashes.user.notice.updated', ['%username%' => $user->getUsername()]) 79 $this->get('translator')->trans('flashes.user.notice.updated', ['%username%' => $user->getUsername()])
96 ); 80 );
97 81
98 return $this->redirectToRoute('user_edit', array('id' => $user->getId())); 82 return $this->redirectToRoute('user_edit', ['id' => $user->getId()]);
99 } 83 }
100 84
101 return $this->render('WallabagUserBundle:Manage:edit.html.twig', array( 85 return $this->render('WallabagUserBundle:Manage:edit.html.twig', [
102 'user' => $user, 86 'user' => $user,
103 'edit_form' => $editForm->createView(), 87 'edit_form' => $editForm->createView(),
104 'delete_form' => $deleteForm->createView(), 88 'delete_form' => $deleteForm->createView(),
105 'twofactor_auth' => $this->getParameter('twofactor_auth'), 89 'twofactor_auth' => $this->getParameter('twofactor_auth'),
106 )); 90 ]);
107 } 91 }
108 92
109 /** 93 /**
@@ -132,6 +116,51 @@ class ManageController extends Controller
132 } 116 }
133 117
134 /** 118 /**
119 * @param Request $request
120 * @param int $page
121 *
122 * @Route("/list/{page}", name="user_index", defaults={"page" = 1})
123 *
124 * Default parameter for page is hardcoded (in duplication of the defaults from the Route)
125 * because this controller is also called inside the layout template without any page as argument
126 *
127 * @return \Symfony\Component\HttpFoundation\Response
128 */
129 public function searchFormAction(Request $request, $page = 1)
130 {
131 $em = $this->getDoctrine()->getManager();
132 $qb = $em->getRepository('WallabagUserBundle:User')->createQueryBuilder('u');
133
134 $form = $this->createForm(SearchUserType::class);
135 $form->handleRequest($request);
136
137 if ($form->isSubmitted() && $form->isValid()) {
138 $this->get('logger')->info('searching users');
139
140 $searchTerm = (isset($request->get('search_user')['term']) ? $request->get('search_user')['term'] : '');
141
142 $qb = $em->getRepository('WallabagUserBundle:User')->getQueryBuilderForSearch($searchTerm);
143 }
144
145 $pagerAdapter = new DoctrineORMAdapter($qb->getQuery(), true, false);
146 $pagerFanta = new Pagerfanta($pagerAdapter);
147 $pagerFanta->setMaxPerPage(50);
148
149 try {
150 $pagerFanta->setCurrentPage($page);
151 } catch (OutOfRangeCurrentPageException $e) {
152 if ($page > 1) {
153 return $this->redirect($this->generateUrl('user_index', ['page' => $pagerFanta->getNbPages()]), 302);
154 }
155 }
156
157 return $this->render('WallabagUserBundle:Manage:index.html.twig', [
158 'searchForm' => $form->createView(),
159 'users' => $pagerFanta,
160 ]);
161 }
162
163 /**
135 * Creates a form to delete a User entity. 164 * Creates a form to delete a User entity.
136 * 165 *
137 * @param User $user The User entity 166 * @param User $user The User entity
@@ -141,7 +170,7 @@ class ManageController extends Controller
141 private function createDeleteForm(User $user) 170 private function createDeleteForm(User $user)
142 { 171 {
143 return $this->createFormBuilder() 172 return $this->createFormBuilder()
144 ->setAction($this->generateUrl('user_delete', array('id' => $user->getId()))) 173 ->setAction($this->generateUrl('user_delete', ['id' => $user->getId()]))
145 ->setMethod('DELETE') 174 ->setMethod('DELETE')
146 ->getForm() 175 ->getForm()
147 ; 176 ;
diff --git a/src/Wallabag/UserBundle/DependencyInjection/WallabagUserExtension.php b/src/Wallabag/UserBundle/DependencyInjection/WallabagUserExtension.php
index 99040f69..5ca3482e 100644
--- a/src/Wallabag/UserBundle/DependencyInjection/WallabagUserExtension.php
+++ b/src/Wallabag/UserBundle/DependencyInjection/WallabagUserExtension.php
@@ -2,10 +2,10 @@
2 2
3namespace Wallabag\UserBundle\DependencyInjection; 3namespace Wallabag\UserBundle\DependencyInjection;
4 4
5use Symfony\Component\DependencyInjection\ContainerBuilder;
6use Symfony\Component\Config\FileLocator; 5use Symfony\Component\Config\FileLocator;
7use Symfony\Component\HttpKernel\DependencyInjection\Extension; 6use Symfony\Component\DependencyInjection\ContainerBuilder;
8use Symfony\Component\DependencyInjection\Loader; 7use Symfony\Component\DependencyInjection\Loader;
8use Symfony\Component\HttpKernel\DependencyInjection\Extension;
9 9
10class WallabagUserExtension extends Extension 10class WallabagUserExtension extends Extension
11{ 11{
@@ -14,7 +14,7 @@ class WallabagUserExtension extends Extension
14 $configuration = new Configuration(); 14 $configuration = new Configuration();
15 $config = $this->processConfiguration($configuration, $configs); 15 $config = $this->processConfiguration($configuration, $configs);
16 16
17 $loader = new Loader\YamlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config')); 17 $loader = new Loader\YamlFileLoader($container, new FileLocator(__DIR__ . '/../Resources/config'));
18 $loader->load('services.yml'); 18 $loader->load('services.yml');
19 $container->setParameter('wallabag_user.registration_enabled', $config['registration_enabled']); 19 $container->setParameter('wallabag_user.registration_enabled', $config['registration_enabled']);
20 } 20 }
diff --git a/src/Wallabag/UserBundle/Entity/User.php b/src/Wallabag/UserBundle/Entity/User.php
index 3a167de7..48446e3c 100644
--- a/src/Wallabag/UserBundle/Entity/User.php
+++ b/src/Wallabag/UserBundle/Entity/User.php
@@ -4,37 +4,43 @@ namespace Wallabag\UserBundle\Entity;
4 4
5use Doctrine\Common\Collections\ArrayCollection; 5use Doctrine\Common\Collections\ArrayCollection;
6use Doctrine\ORM\Mapping as ORM; 6use Doctrine\ORM\Mapping as ORM;
7use FOS\UserBundle\Model\User as BaseUser;
8use JMS\Serializer\Annotation\Accessor;
9use JMS\Serializer\Annotation\Groups;
10use JMS\Serializer\Annotation\XmlRoot;
7use Scheb\TwoFactorBundle\Model\Email\TwoFactorInterface; 11use Scheb\TwoFactorBundle\Model\Email\TwoFactorInterface;
8use Scheb\TwoFactorBundle\Model\TrustedComputerInterface; 12use Scheb\TwoFactorBundle\Model\TrustedComputerInterface;
9use FOS\UserBundle\Model\User as BaseUser;
10use JMS\Serializer\Annotation\ExclusionPolicy;
11use JMS\Serializer\Annotation\Expose;
12use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity; 13use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
13use Symfony\Component\Security\Core\User\UserInterface; 14use Symfony\Component\Security\Core\User\UserInterface;
14use Wallabag\ApiBundle\Entity\Client; 15use Wallabag\ApiBundle\Entity\Client;
15use Wallabag\CoreBundle\Entity\Config; 16use Wallabag\CoreBundle\Entity\Config;
16use Wallabag\CoreBundle\Entity\Entry; 17use Wallabag\CoreBundle\Entity\Entry;
18use Wallabag\CoreBundle\Helper\EntityTimestampsTrait;
17 19
18/** 20/**
19 * User. 21 * User.
20 * 22 *
23 * @XmlRoot("user")
21 * @ORM\Entity(repositoryClass="Wallabag\UserBundle\Repository\UserRepository") 24 * @ORM\Entity(repositoryClass="Wallabag\UserBundle\Repository\UserRepository")
22 * @ORM\Table(name="`user`") 25 * @ORM\Table(name="`user`")
23 * @ORM\HasLifecycleCallbacks() 26 * @ORM\HasLifecycleCallbacks()
24 * @ExclusionPolicy("all")
25 * 27 *
26 * @UniqueEntity("email") 28 * @UniqueEntity("email")
27 * @UniqueEntity("username") 29 * @UniqueEntity("username")
28 */ 30 */
29class User extends BaseUser implements TwoFactorInterface, TrustedComputerInterface 31class User extends BaseUser implements TwoFactorInterface, TrustedComputerInterface
30{ 32{
33 use EntityTimestampsTrait;
34
35 /** @Serializer\XmlAttribute */
31 /** 36 /**
32 * @var int 37 * @var int
33 * 38 *
34 * @Expose
35 * @ORM\Column(name="id", type="integer") 39 * @ORM\Column(name="id", type="integer")
36 * @ORM\Id 40 * @ORM\Id
37 * @ORM\GeneratedValue(strategy="AUTO") 41 * @ORM\GeneratedValue(strategy="AUTO")
42 *
43 * @Groups({"user_api", "user_api_with_client"})
38 */ 44 */
39 protected $id; 45 protected $id;
40 46
@@ -42,20 +48,40 @@ class User extends BaseUser implements TwoFactorInterface, TrustedComputerInterf
42 * @var string 48 * @var string
43 * 49 *
44 * @ORM\Column(name="name", type="text", nullable=true) 50 * @ORM\Column(name="name", type="text", nullable=true)
51 *
52 * @Groups({"user_api", "user_api_with_client"})
45 */ 53 */
46 protected $name; 54 protected $name;
47 55
48 /** 56 /**
49 * @var date 57 * @var string
58 *
59 * @Groups({"user_api", "user_api_with_client"})
60 */
61 protected $username;
62
63 /**
64 * @var string
65 *
66 * @Groups({"user_api", "user_api_with_client"})
67 */
68 protected $email;
69
70 /**
71 * @var \DateTime
50 * 72 *
51 * @ORM\Column(name="created_at", type="datetime") 73 * @ORM\Column(name="created_at", type="datetime")
74 *
75 * @Groups({"user_api", "user_api_with_client"})
52 */ 76 */
53 protected $createdAt; 77 protected $createdAt;
54 78
55 /** 79 /**
56 * @var date 80 * @var \DateTime
57 * 81 *
58 * @ORM\Column(name="updated_at", type="datetime") 82 * @ORM\Column(name="updated_at", type="datetime")
83 *
84 * @Groups({"user_api", "user_api_with_client"})
59 */ 85 */
60 protected $updatedAt; 86 protected $updatedAt;
61 87
@@ -70,12 +96,35 @@ class User extends BaseUser implements TwoFactorInterface, TrustedComputerInterf
70 protected $config; 96 protected $config;
71 97
72 /** 98 /**
99 * @var ArrayCollection
100 *
101 * @ORM\OneToMany(targetEntity="Wallabag\CoreBundle\Entity\SiteCredential", mappedBy="user", cascade={"remove"})
102 */
103 protected $siteCredentials;
104
105 /**
106 * @var ArrayCollection
107 *
108 * @ORM\OneToMany(targetEntity="Wallabag\ApiBundle\Entity\Client", mappedBy="user", cascade={"remove"})
109 */
110 protected $clients;
111
112 /**
113 * @see getFirstClient() below
114 *
115 * @Groups({"user_api_with_client"})
116 * @Accessor(getter="getFirstClient")
117 */
118 protected $default_client;
119
120 /**
73 * @ORM\Column(type="integer", nullable=true) 121 * @ORM\Column(type="integer", nullable=true)
74 */ 122 */
75 private $authCode; 123 private $authCode;
76 124
77 /** 125 /**
78 * @var bool Enabled yes/no 126 * @var bool
127 *
79 * @ORM\Column(type="boolean") 128 * @ORM\Column(type="boolean")
80 */ 129 */
81 private $twoFactorAuthentication = false; 130 private $twoFactorAuthentication = false;
@@ -85,11 +134,6 @@ class User extends BaseUser implements TwoFactorInterface, TrustedComputerInterf
85 */ 134 */
86 private $trusted; 135 private $trusted;
87 136
88 /**
89 * @ORM\OneToMany(targetEntity="Wallabag\ApiBundle\Entity\Client", mappedBy="user", cascade={"remove"})
90 */
91 protected $clients;
92
93 public function __construct() 137 public function __construct()
94 { 138 {
95 parent::__construct(); 139 parent::__construct();
@@ -98,19 +142,6 @@ class User extends BaseUser implements TwoFactorInterface, TrustedComputerInterf
98 } 142 }
99 143
100 /** 144 /**
101 * @ORM\PrePersist
102 * @ORM\PreUpdate
103 */
104 public function timestamps()
105 {
106 if (is_null($this->createdAt)) {
107 $this->createdAt = new \DateTime();
108 }
109
110 $this->updatedAt = new \DateTime();
111 }
112
113 /**
114 * Set name. 145 * Set name.
115 * 146 *
116 * @param string $name 147 * @param string $name
@@ -135,7 +166,7 @@ class User extends BaseUser implements TwoFactorInterface, TrustedComputerInterf
135 } 166 }
136 167
137 /** 168 /**
138 * @return string 169 * @return \DateTime
139 */ 170 */
140 public function getCreatedAt() 171 public function getCreatedAt()
141 { 172 {
@@ -143,7 +174,7 @@ class User extends BaseUser implements TwoFactorInterface, TrustedComputerInterf
143 } 174 }
144 175
145 /** 176 /**
146 * @return string 177 * @return \DateTime
147 */ 178 */
148 public function getUpdatedAt() 179 public function getUpdatedAt()
149 { 180 {
@@ -266,4 +297,16 @@ class User extends BaseUser implements TwoFactorInterface, TrustedComputerInterf
266 { 297 {
267 return $this->clients; 298 return $this->clients;
268 } 299 }
300
301 /**
302 * 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).
303 *
304 * @return Client
305 */
306 public function getFirstClient()
307 {
308 if (!empty($this->clients)) {
309 return $this->clients->first();
310 }
311 }
269} 312}
diff --git a/src/Wallabag/UserBundle/EventListener/AuthenticationFailureListener.php b/src/Wallabag/UserBundle/EventListener/AuthenticationFailureListener.php
new file mode 100644
index 00000000..18f14a3a
--- /dev/null
+++ b/src/Wallabag/UserBundle/EventListener/AuthenticationFailureListener.php
@@ -0,0 +1,40 @@
1<?php
2
3namespace Wallabag\UserBundle\EventListener;
4
5use Psr\Log\LoggerInterface;
6use Symfony\Component\EventDispatcher\EventSubscriberInterface;
7use Symfony\Component\HttpFoundation\RequestStack;
8use Symfony\Component\Security\Core\AuthenticationEvents;
9
10class 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;
5use Doctrine\ORM\EntityManager; 5use Doctrine\ORM\EntityManager;
6use FOS\UserBundle\Event\UserEvent; 6use FOS\UserBundle\Event\UserEvent;
7use FOS\UserBundle\FOSUserEvents; 7use FOS\UserBundle\FOSUserEvents;
8use Symfony\Component\EventDispatcher\EventDispatcherInterface;
9use Symfony\Component\EventDispatcher\EventSubscriberInterface; 8use Symfony\Component\EventDispatcher\EventSubscriberInterface;
10use Wallabag\CoreBundle\Entity\Config; 9use 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/EventListener/PasswordResettingListener.php b/src/Wallabag/UserBundle/EventListener/PasswordResettingListener.php
index 3a7f2637..7df093f1 100644
--- a/src/Wallabag/UserBundle/EventListener/PasswordResettingListener.php
+++ b/src/Wallabag/UserBundle/EventListener/PasswordResettingListener.php
@@ -2,8 +2,8 @@
2 2
3namespace Wallabag\UserBundle\EventListener; 3namespace Wallabag\UserBundle\EventListener;
4 4
5use FOS\UserBundle\FOSUserEvents;
6use FOS\UserBundle\Event\FormEvent; 5use FOS\UserBundle\Event\FormEvent;
6use FOS\UserBundle\FOSUserEvents;
7use Symfony\Component\EventDispatcher\EventSubscriberInterface; 7use Symfony\Component\EventDispatcher\EventSubscriberInterface;
8use Symfony\Component\HttpFoundation\RedirectResponse; 8use Symfony\Component\HttpFoundation\RedirectResponse;
9use Symfony\Component\Routing\Generator\UrlGeneratorInterface; 9use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
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
3namespace Wallabag\UserBundle\Form;
4
5use Symfony\Component\Form\AbstractType;
6use Symfony\Component\Form\Extension\Core\Type\TextType;
7use Symfony\Component\Form\FormBuilderInterface;
8use Symfony\Component\OptionsResolver\OptionsResolver;
9
10class 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/Form/UserType.php b/src/Wallabag/UserBundle/Form/UserType.php
index d8cdbaf9..56fea640 100644
--- a/src/Wallabag/UserBundle/Form/UserType.php
+++ b/src/Wallabag/UserBundle/Form/UserType.php
@@ -3,12 +3,12 @@
3namespace Wallabag\UserBundle\Form; 3namespace Wallabag\UserBundle\Form;
4 4
5use Symfony\Component\Form\AbstractType; 5use Symfony\Component\Form\AbstractType;
6use Symfony\Component\Form\FormBuilderInterface;
7use Symfony\Component\OptionsResolver\OptionsResolver;
8use Symfony\Component\Form\Extension\Core\Type\CheckboxType; 6use Symfony\Component\Form\Extension\Core\Type\CheckboxType;
7use Symfony\Component\Form\Extension\Core\Type\EmailType;
9use Symfony\Component\Form\Extension\Core\Type\SubmitType; 8use Symfony\Component\Form\Extension\Core\Type\SubmitType;
10use Symfony\Component\Form\Extension\Core\Type\TextType; 9use Symfony\Component\Form\Extension\Core\Type\TextType;
11use Symfony\Component\Form\Extension\Core\Type\EmailType; 10use Symfony\Component\Form\FormBuilderInterface;
11use Symfony\Component\OptionsResolver\OptionsResolver;
12 12
13class UserType extends AbstractType 13class UserType extends AbstractType
14{ 14{
@@ -50,8 +50,8 @@ class UserType extends AbstractType
50 */ 50 */
51 public function configureOptions(OptionsResolver $resolver) 51 public function configureOptions(OptionsResolver $resolver)
52 { 52 {
53 $resolver->setDefaults(array( 53 $resolver->setDefaults([
54 'data_class' => 'Wallabag\UserBundle\Entity\User', 54 'data_class' => 'Wallabag\UserBundle\Entity\User',
55 )); 55 ]);
56 } 56 }
57} 57}
diff --git a/src/Wallabag/UserBundle/Mailer/AuthCodeMailer.php b/src/Wallabag/UserBundle/Mailer/AuthCodeMailer.php
index 961208f2..aed805c9 100644
--- a/src/Wallabag/UserBundle/Mailer/AuthCodeMailer.php
+++ b/src/Wallabag/UserBundle/Mailer/AuthCodeMailer.php
@@ -2,8 +2,8 @@
2 2
3namespace Wallabag\UserBundle\Mailer; 3namespace Wallabag\UserBundle\Mailer;
4 4
5use Scheb\TwoFactorBundle\Model\Email\TwoFactorInterface;
6use Scheb\TwoFactorBundle\Mailer\AuthCodeMailerInterface; 5use Scheb\TwoFactorBundle\Mailer\AuthCodeMailerInterface;
6use Scheb\TwoFactorBundle\Model\Email\TwoFactorInterface;
7 7
8/** 8/**
9 * Custom mailer for TwoFactorBundle email. 9 * Custom mailer for TwoFactorBundle email.
diff --git a/src/Wallabag/UserBundle/Repository/UserRepository.php b/src/Wallabag/UserBundle/Repository/UserRepository.php
index f913f52d..be693d3b 100644
--- a/src/Wallabag/UserBundle/Repository/UserRepository.php
+++ b/src/Wallabag/UserBundle/Repository/UserRepository.php
@@ -3,6 +3,8 @@
3namespace Wallabag\UserBundle\Repository; 3namespace Wallabag\UserBundle\Repository;
4 4
5use Doctrine\ORM\EntityRepository; 5use Doctrine\ORM\EntityRepository;
6use Doctrine\ORM\QueryBuilder;
7use Wallabag\UserBundle\Entity\User;
6 8
7class UserRepository extends EntityRepository 9class UserRepository extends EntityRepository
8{ 10{
@@ -52,4 +54,30 @@ class UserRepository extends EntityRepository
52 ->getQuery() 54 ->getQuery()
53 ->getSingleScalarResult(); 55 ->getSingleScalarResult();
54 } 56 }
57
58 /**
59 * Count how many users are existing.
60 *
61 * @return int
62 */
63 public function getSumUsers()
64 {
65 return $this->createQueryBuilder('u')
66 ->select('count(u)')
67 ->getQuery()
68 ->getSingleScalarResult();
69 }
70
71 /**
72 * Retrieves users filtered with a search term.
73 *
74 * @param string $term
75 *
76 * @return QueryBuilder
77 */
78 public function getQueryBuilderForSearch($term)
79 {
80 return $this->createQueryBuilder('u')
81 ->andWhere('lower(u.username) LIKE lower(:term) OR lower(u.email) LIKE lower(:term) OR lower(u.name) LIKE lower(:term)')->setParameter('term', '%' . $term . '%');
82 }
55} 83}
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/translations/wallabag_user.oc.yml b/src/Wallabag/UserBundle/Resources/translations/wallabag_user.oc.yml
index 53a1afd1..e62ea2bc 100644
--- a/src/Wallabag/UserBundle/Resources/translations/wallabag_user.oc.yml
+++ b/src/Wallabag/UserBundle/Resources/translations/wallabag_user.oc.yml
@@ -5,7 +5,7 @@ auth_code:
5 subject: "Còdi d'autentificacion wallabag" 5 subject: "Còdi d'autentificacion wallabag"
6 body: 6 body:
7 hello: "Bonjorn %user%," 7 hello: "Bonjorn %user%,"
8 first_para: "Estant qu'avètz activat la dobla autentificacion sus vòtre compte wallabag e que venètz de vos conectar dempuèi un novèl aparelh (ordinador, mobil, etc.) vos mandem un còdi per validar la connexion." 8 first_para: "Estant qu'avètz activat l'autentificacion en dos temps sus vòstre compte wallabag e que venètz de vos connectar dempuèi un novèl periferic (ordinador, mobil, etc.) vos mandem un còdi per validar la connexion."
9 second_para: "Vaquí lo còdi a dintrar :" 9 second_para: "Vaquí lo còdi per dintrar:"
10 support: "S'avètz un problèma de connexion, dobtetz pas a contacter l'assisténcia : " 10 support: "S'avètz un problèma de connexion, dobtetz pas a contactar l'assisténcia:"
11 signature: "La còla de wallabag" 11 signature: "La còla de wallabag"
diff --git a/src/Wallabag/UserBundle/Resources/translations/wallabag_user.ru.yml b/src/Wallabag/UserBundle/Resources/translations/wallabag_user.ru.yml
new file mode 100644
index 00000000..2a418224
--- /dev/null
+++ b/src/Wallabag/UserBundle/Resources/translations/wallabag_user.ru.yml
@@ -0,0 +1,11 @@
1# Two factor mail
2auth_code:
3 on: 'Вкл'
4 mailer:
5 subject: 'код аутентификации wallabag'
6 body:
7 hello: "Привет %user%,"
8 first_para: "Поскольку вы активируете двухфакторную аутентификацию на своей учетной записи wallabag и только что вошли в систему с нового устройства (компьютер, телефон и т. д.), мы отправляем вам код для подтверждения вашего соединения."
9 second_para: "Вот код:"
10 support: "Пожалуйста, не стесняйтесь обращаться к нам, если у вас есть какие-либо проблемы:"
11 signature: "Команда wallabag"
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>