diff options
Diffstat (limited to 'src/Wallabag/UserBundle')
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 | ||
5 | use FOS\UserBundle\Event\UserEvent; | 5 | use FOS\UserBundle\Event\UserEvent; |
6 | use FOS\UserBundle\FOSUserEvents; | 6 | use FOS\UserBundle\FOSUserEvents; |
7 | use Symfony\Component\HttpFoundation\Request; | 7 | use Pagerfanta\Adapter\DoctrineORMAdapter; |
8 | use Symfony\Bundle\FrameworkBundle\Controller\Controller; | 8 | use Pagerfanta\Exception\OutOfRangeCurrentPageException; |
9 | use Pagerfanta\Pagerfanta; | ||
9 | use Sensio\Bundle\FrameworkExtraBundle\Configuration\Method; | 10 | use Sensio\Bundle\FrameworkExtraBundle\Configuration\Method; |
10 | use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route; | 11 | use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route; |
12 | use Symfony\Bundle\FrameworkBundle\Controller\Controller; | ||
13 | use Symfony\Component\HttpFoundation\Request; | ||
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()) { |
@@ -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 | ||
3 | namespace Wallabag\UserBundle\DependencyInjection; | 3 | namespace Wallabag\UserBundle\DependencyInjection; |
4 | 4 | ||
5 | use Symfony\Component\DependencyInjection\ContainerBuilder; | ||
6 | use Symfony\Component\Config\FileLocator; | 5 | use Symfony\Component\Config\FileLocator; |
7 | use Symfony\Component\HttpKernel\DependencyInjection\Extension; | 6 | use Symfony\Component\DependencyInjection\ContainerBuilder; |
8 | use Symfony\Component\DependencyInjection\Loader; | 7 | use Symfony\Component\DependencyInjection\Loader; |
8 | use Symfony\Component\HttpKernel\DependencyInjection\Extension; | ||
9 | 9 | ||
10 | class WallabagUserExtension extends Extension | 10 | class 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 | ||
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 FOS\UserBundle\Model\User as BaseUser; | ||
8 | use JMS\Serializer\Annotation\Accessor; | ||
9 | use JMS\Serializer\Annotation\Groups; | ||
10 | use JMS\Serializer\Annotation\XmlRoot; | ||
7 | use Scheb\TwoFactorBundle\Model\Email\TwoFactorInterface; | 11 | use Scheb\TwoFactorBundle\Model\Email\TwoFactorInterface; |
8 | use Scheb\TwoFactorBundle\Model\TrustedComputerInterface; | 12 | use Scheb\TwoFactorBundle\Model\TrustedComputerInterface; |
9 | 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; |
15 | use Wallabag\CoreBundle\Entity\Config; | 16 | use Wallabag\CoreBundle\Entity\Config; |
16 | use Wallabag\CoreBundle\Entity\Entry; | 17 | use Wallabag\CoreBundle\Entity\Entry; |
18 | use 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 | */ |
29 | class User extends BaseUser implements TwoFactorInterface, TrustedComputerInterface | 31 | class 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 | |||
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/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 | ||
3 | namespace Wallabag\UserBundle\EventListener; | 3 | namespace Wallabag\UserBundle\EventListener; |
4 | 4 | ||
5 | use FOS\UserBundle\FOSUserEvents; | ||
6 | use FOS\UserBundle\Event\FormEvent; | 5 | use FOS\UserBundle\Event\FormEvent; |
6 | use FOS\UserBundle\FOSUserEvents; | ||
7 | use Symfony\Component\EventDispatcher\EventSubscriberInterface; | 7 | use Symfony\Component\EventDispatcher\EventSubscriberInterface; |
8 | use Symfony\Component\HttpFoundation\RedirectResponse; | 8 | use Symfony\Component\HttpFoundation\RedirectResponse; |
9 | use Symfony\Component\Routing\Generator\UrlGeneratorInterface; | 9 | use 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 | |||
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/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 @@ | |||
3 | namespace Wallabag\UserBundle\Form; | 3 | namespace Wallabag\UserBundle\Form; |
4 | 4 | ||
5 | use Symfony\Component\Form\AbstractType; | 5 | use Symfony\Component\Form\AbstractType; |
6 | use Symfony\Component\Form\FormBuilderInterface; | ||
7 | use Symfony\Component\OptionsResolver\OptionsResolver; | ||
8 | use Symfony\Component\Form\Extension\Core\Type\CheckboxType; | 6 | use Symfony\Component\Form\Extension\Core\Type\CheckboxType; |
7 | use Symfony\Component\Form\Extension\Core\Type\EmailType; | ||
9 | use Symfony\Component\Form\Extension\Core\Type\SubmitType; | 8 | use Symfony\Component\Form\Extension\Core\Type\SubmitType; |
10 | use Symfony\Component\Form\Extension\Core\Type\TextType; | 9 | use Symfony\Component\Form\Extension\Core\Type\TextType; |
11 | use Symfony\Component\Form\Extension\Core\Type\EmailType; | 10 | use Symfony\Component\Form\FormBuilderInterface; |
11 | use Symfony\Component\OptionsResolver\OptionsResolver; | ||
12 | 12 | ||
13 | class UserType extends AbstractType | 13 | class 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 | ||
3 | namespace Wallabag\UserBundle\Mailer; | 3 | namespace Wallabag\UserBundle\Mailer; |
4 | 4 | ||
5 | use Scheb\TwoFactorBundle\Model\Email\TwoFactorInterface; | ||
6 | use Scheb\TwoFactorBundle\Mailer\AuthCodeMailerInterface; | 5 | use Scheb\TwoFactorBundle\Mailer\AuthCodeMailerInterface; |
6 | use 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 @@ | |||
3 | namespace Wallabag\UserBundle\Repository; | 3 | namespace Wallabag\UserBundle\Repository; |
4 | 4 | ||
5 | use Doctrine\ORM\EntityRepository; | 5 | use Doctrine\ORM\EntityRepository; |
6 | use Doctrine\ORM\QueryBuilder; | ||
7 | use Wallabag\UserBundle\Entity\User; | ||
6 | 8 | ||
7 | class UserRepository extends EntityRepository | 9 | class 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 | ||
2 | auth_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> |