aboutsummaryrefslogtreecommitdiffhomepage
path: root/src
diff options
context:
space:
mode:
authorJeremy Benoist <jeremy.benoist@gmail.com>2017-05-30 07:56:01 +0200
committerJeremy Benoist <jeremy.benoist@gmail.com>2017-05-30 07:56:01 +0200
commit5709ecb36809fb009446a11a758232bbe8f264e4 (patch)
tree0880f40fe8e6e563ef5648c267bb1f65251a0355 /src
parent2251045901875aa815dee43ec467fb1af8d416d0 (diff)
downloadwallabag-5709ecb36809fb009446a11a758232bbe8f264e4.tar.gz
wallabag-5709ecb36809fb009446a11a758232bbe8f264e4.tar.zst
wallabag-5709ecb36809fb009446a11a758232bbe8f264e4.zip
Re-use `NewUserType` to validate registration
The only ugly things is how we handle error by generating the view and then parse the content to retrieve all errors… Fix exposition fields in User entity
Diffstat (limited to 'src')
-rw-r--r--src/Wallabag/ApiBundle/Controller/UserRestController.php119
-rw-r--r--src/Wallabag/UserBundle/Entity/User.php25
2 files changed, 101 insertions, 43 deletions
diff --git a/src/Wallabag/ApiBundle/Controller/UserRestController.php b/src/Wallabag/ApiBundle/Controller/UserRestController.php
index c5ffbdf1..a1b78e3f 100644
--- a/src/Wallabag/ApiBundle/Controller/UserRestController.php
+++ b/src/Wallabag/ApiBundle/Controller/UserRestController.php
@@ -6,12 +6,14 @@ use FOS\UserBundle\Event\UserEvent;
6use FOS\UserBundle\FOSUserEvents; 6use FOS\UserBundle\FOSUserEvents;
7use JMS\Serializer\SerializationContext; 7use JMS\Serializer\SerializationContext;
8use Nelmio\ApiDocBundle\Annotation\ApiDoc; 8use Nelmio\ApiDocBundle\Annotation\ApiDoc;
9use Symfony\Component\HttpFoundation\Request;
9use Symfony\Component\HttpFoundation\JsonResponse; 10use Symfony\Component\HttpFoundation\JsonResponse;
11use Wallabag\UserBundle\Entity\User;
10 12
11class UserRestController extends WallabagRestController 13class UserRestController extends WallabagRestController
12{ 14{
13 /** 15 /**
14 * Retrieve user informations 16 * Retrieve current logged in user informations.
15 * 17 *
16 * @ApiDoc() 18 * @ApiDoc()
17 * 19 *
@@ -21,78 +23,117 @@ class UserRestController extends WallabagRestController
21 { 23 {
22 $this->validateAuthentication(); 24 $this->validateAuthentication();
23 25
24 $serializationContext = SerializationContext::create()->setGroups(['user_api']); 26 return $this->sendUser($this->getUser());
25 $json = $this->get('serializer')->serialize($this->getUser(), 'json', $serializationContext);
26
27 return (new JsonResponse())->setJson($json);
28 } 27 }
29 28
30 /** 29 /**
31 * Register an user 30 * Register an user.
32 * 31 *
33 * @ApiDoc( 32 * @ApiDoc(
34 * requirements={ 33 * requirements={
35 * {"name"="username", "dataType"="string", "required"=true, "description"="The user's username"}, 34 * {"name"="username", "dataType"="string", "required"=true, "description"="The user's username"},
36 * {"name"="password", "dataType"="string", "required"=true, "description"="The user's password"} 35 * {"name"="password", "dataType"="string", "required"=true, "description"="The user's password"},
37 * {"name"="email", "dataType"="string", "required"=true, "description"="The user's email"} 36 * {"name"="email", "dataType"="string", "required"=true, "description"="The user's email"}
38 * } 37 * }
39 * ) 38 * )
39 *
40 * @todo Make this method (or the whole API) accessible only through https
41 *
40 * @return JsonResponse 42 * @return JsonResponse
41 */ 43 */
42 // TODO : Make this method (or the whole API) accessible only through https 44 public function putUserAction(Request $request)
43 public function putUserAction($username, $password, $email)
44 { 45 {
45 if (!$this->container->getParameter('fosuser_registration')) { 46 if (!$this->container->getParameter('fosuser_registration')) {
46 $json = $this->get('serializer')->serialize(['error' => "Server doesn't allow registrations"], 'json'); 47 $json = $this->get('serializer')->serialize(['error' => "Server doesn't allow registrations"], 'json');
48
47 return (new JsonResponse())->setJson($json)->setStatusCode(403); 49 return (new JsonResponse())->setJson($json)->setStatusCode(403);
48 } 50 }
49 51
50 if ($password === '') { // TODO : might be a good idea to enforce restrictions here 52 $userManager = $this->get('fos_user.user_manager');
51 $json = $this->get('serializer')->serialize(['error' => 'Password is blank'], 'json'); 53 $user = $userManager->createUser();
52 return (new JsonResponse())->setJson($json)->setStatusCode(400); 54 // enable created user by default
53 } 55 $user->setEnabled(true);
54 56
57 $form = $this->createForm('Wallabag\UserBundle\Form\NewUserType', $user, [
58 'csrf_protection' => false,
59 ]);
55 60
56 // TODO : Make only one call to database by using a custom repository method 61 // simulate form submission
57 if ($this->getDoctrine() 62 $form->submit([
58 ->getRepository('WallabagUserBundle:User') 63 'username' => $request->request->get('username'),
59 ->findOneByUserName($username)) { 64 'plainPassword' => [
60 $json = $this->get('serializer')->serialize(['error' => 'Username is already taken'], 'json'); 65 'first' => $request->request->get('password'),
61 return (new JsonResponse())->setJson($json)->setStatusCode(409); 66 'second' => $request->request->get('password'),
62 } 67 ],
68 'email' => $request->request->get('email'),
69 ]);
63 70
64 if ($this->getDoctrine() 71 if ($form->isSubmitted() && false === $form->isValid()) {
65 ->getRepository('WallabagUserBundle:User') 72 $view = $this->view($form, 400);
66 ->findOneByEmail($email)) { 73 $view->setFormat('json');
67 $json = $this->get('serializer')->serialize(['error' => 'An account with this email already exists'], 'json');
68 return (new JsonResponse())->setJson($json)->setStatusCode(409);
69 }
70 74
71 $em = $this->get('doctrine.orm.entity_manager'); 75 // handle errors in a more beautiful way than the default view
76 $data = json_decode($this->handleView($view)->getContent(), true)['children'];
77 $errors = [];
72 78
73 $userManager = $this->get('fos_user.user_manager'); 79 if (isset($data['username']['errors'])) {
74 $user = $userManager->createUser(); 80 $errors['username'] = $this->translateErrors($data['username']['errors']);
81 }
75 82
76 $user->setUsername($username); 83 if (isset($data['email']['errors'])) {
84 $errors['email'] = $this->translateErrors($data['email']['errors']);
85 }
77 86
78 $user->setPlainPassword($password); 87 if (isset($data['plainPassword']['children']['first']['errors'])) {
88 $errors['password'] = $this->translateErrors($data['plainPassword']['children']['first']['errors']);
89 }
79 90
80 $user->setEmail($email); 91 $json = $this->get('serializer')->serialize(['error' => $errors], 'json');
81 92
82 $user->setEnabled(true); 93 return (new JsonResponse())->setJson($json)->setStatusCode(400);
83 $user->addRole('ROLE_USER'); 94 }
84 95
85 $em->persist($user); 96 $userManager->updateUser($user);
86 97
87 // dispatch a created event so the associated config will be created 98 // dispatch a created event so the associated config will be created
88 $event = new UserEvent($user); 99 $event = new UserEvent($user, $request);
89 $this->get('event_dispatcher')->dispatch(FOSUserEvents::USER_CREATED, $event); 100 $this->get('event_dispatcher')->dispatch(FOSUserEvents::USER_CREATED, $event);
90 101
91 $serializationContext = SerializationContext::create()->setGroups(['user_api']); 102 return $this->sendUser($user);
92 $json = $this->get('serializer')->serialize($user, 'json', $serializationContext); 103 }
93 104
94 return (new JsonResponse())->setJson($json); 105 /**
106 * Send user response.
107 *
108 * @param User $user
109 *
110 * @return JsonResponse
111 */
112 private function sendUser(User $user)
113 {
114 $json = $this->get('serializer')->serialize(
115 $user,
116 'json',
117 SerializationContext::create()->setGroups(['user_api'])
118 );
95 119
120 return (new JsonResponse())->setJson($json);
96 } 121 }
97 122
123 /**
124 * Translate errors message.
125 *
126 * @param array $errors
127 *
128 * @return array
129 */
130 private function translateErrors($errors)
131 {
132 $translatedErrors = [];
133 foreach ($errors as $error) {
134 $translatedErrors[] = $this->get('translator')->trans($error);
135 }
136
137 return $translatedErrors;
138 }
98} 139}
diff --git a/src/Wallabag/UserBundle/Entity/User.php b/src/Wallabag/UserBundle/Entity/User.php
index 1863c966..1ff3046a 100644
--- a/src/Wallabag/UserBundle/Entity/User.php
+++ b/src/Wallabag/UserBundle/Entity/User.php
@@ -5,11 +5,10 @@ namespace Wallabag\UserBundle\Entity;
5use Doctrine\Common\Collections\ArrayCollection; 5use Doctrine\Common\Collections\ArrayCollection;
6use Doctrine\ORM\Mapping as ORM; 6use Doctrine\ORM\Mapping as ORM;
7use JMS\Serializer\Annotation\Groups; 7use JMS\Serializer\Annotation\Groups;
8use JMS\Serializer\Annotation\XmlRoot;
8use Scheb\TwoFactorBundle\Model\Email\TwoFactorInterface; 9use Scheb\TwoFactorBundle\Model\Email\TwoFactorInterface;
9use Scheb\TwoFactorBundle\Model\TrustedComputerInterface; 10use Scheb\TwoFactorBundle\Model\TrustedComputerInterface;
10use FOS\UserBundle\Model\User as BaseUser; 11use FOS\UserBundle\Model\User as BaseUser;
11use JMS\Serializer\Annotation\ExclusionPolicy;
12use JMS\Serializer\Annotation\Expose;
13use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity; 12use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
14use Symfony\Component\Security\Core\User\UserInterface; 13use Symfony\Component\Security\Core\User\UserInterface;
15use Wallabag\ApiBundle\Entity\Client; 14use Wallabag\ApiBundle\Entity\Client;
@@ -19,23 +18,24 @@ use Wallabag\CoreBundle\Entity\Entry;
19/** 18/**
20 * User. 19 * User.
21 * 20 *
21 * @XmlRoot("user")
22 * @ORM\Entity(repositoryClass="Wallabag\UserBundle\Repository\UserRepository") 22 * @ORM\Entity(repositoryClass="Wallabag\UserBundle\Repository\UserRepository")
23 * @ORM\Table(name="`user`") 23 * @ORM\Table(name="`user`")
24 * @ORM\HasLifecycleCallbacks() 24 * @ORM\HasLifecycleCallbacks()
25 * @ExclusionPolicy("all")
26 * 25 *
27 * @UniqueEntity("email") 26 * @UniqueEntity("email")
28 * @UniqueEntity("username") 27 * @UniqueEntity("username")
29 */ 28 */
30class User extends BaseUser implements TwoFactorInterface, TrustedComputerInterface 29class User extends BaseUser implements TwoFactorInterface, TrustedComputerInterface
31{ 30{
31 /** @Serializer\XmlAttribute */
32 /** 32 /**
33 * @var int 33 * @var int
34 * 34 *
35 * @Expose
36 * @ORM\Column(name="id", type="integer") 35 * @ORM\Column(name="id", type="integer")
37 * @ORM\Id 36 * @ORM\Id
38 * @ORM\GeneratedValue(strategy="AUTO") 37 * @ORM\GeneratedValue(strategy="AUTO")
38 *
39 * @Groups({"user_api"}) 39 * @Groups({"user_api"})
40 */ 40 */
41 protected $id; 41 protected $id;
@@ -44,14 +44,30 @@ class User extends BaseUser implements TwoFactorInterface, TrustedComputerInterf
44 * @var string 44 * @var string
45 * 45 *
46 * @ORM\Column(name="name", type="text", nullable=true) 46 * @ORM\Column(name="name", type="text", nullable=true)
47 *
47 * @Groups({"user_api"}) 48 * @Groups({"user_api"})
48 */ 49 */
49 protected $name; 50 protected $name;
50 51
51 /** 52 /**
53 * @var string
54 *
55 * @Groups({"user_api"})
56 */
57 protected $username;
58
59 /**
60 * @var string
61 *
62 * @Groups({"user_api"})
63 */
64 protected $email;
65
66 /**
52 * @var date 67 * @var date
53 * 68 *
54 * @ORM\Column(name="created_at", type="datetime") 69 * @ORM\Column(name="created_at", type="datetime")
70 *
55 * @Groups({"user_api"}) 71 * @Groups({"user_api"})
56 */ 72 */
57 protected $createdAt; 73 protected $createdAt;
@@ -60,6 +76,7 @@ class User extends BaseUser implements TwoFactorInterface, TrustedComputerInterf
60 * @var date 76 * @var date
61 * 77 *
62 * @ORM\Column(name="updated_at", type="datetime") 78 * @ORM\Column(name="updated_at", type="datetime")
79 *
63 * @Groups({"user_api"}) 80 * @Groups({"user_api"})
64 */ 81 */
65 protected $updatedAt; 82 protected $updatedAt;