]> git.immae.eu Git - github/wallabag/wallabag.git/commitdiff
Merge pull request #3065 from wallabag/api-creation-endpoint
authorJérémy Benoist <j0k3r@users.noreply.github.com>
Tue, 30 May 2017 13:26:11 +0000 (15:26 +0200)
committerGitHub <noreply@github.com>
Tue, 30 May 2017 13:26:11 +0000 (15:26 +0200)
Register through API

src/Wallabag/ApiBundle/Controller/UserRestController.php [new file with mode: 0644]
src/Wallabag/ApiBundle/Resources/config/routing_rest.yml
src/Wallabag/UserBundle/Controller/ManageController.php
src/Wallabag/UserBundle/Entity/User.php
tests/Wallabag/ApiBundle/Controller/UserRestControllerTest.php [new file with mode: 0644]
tests/Wallabag/ApiBundle/WallabagApiTestCase.php
tests/Wallabag/UserBundle/Controller/ManageControllerTest.php

diff --git a/src/Wallabag/ApiBundle/Controller/UserRestController.php b/src/Wallabag/ApiBundle/Controller/UserRestController.php
new file mode 100644 (file)
index 0000000..a1b78e3
--- /dev/null
@@ -0,0 +1,139 @@
+<?php
+
+namespace Wallabag\ApiBundle\Controller;
+
+use FOS\UserBundle\Event\UserEvent;
+use FOS\UserBundle\FOSUserEvents;
+use JMS\Serializer\SerializationContext;
+use Nelmio\ApiDocBundle\Annotation\ApiDoc;
+use Symfony\Component\HttpFoundation\Request;
+use Symfony\Component\HttpFoundation\JsonResponse;
+use Wallabag\UserBundle\Entity\User;
+
+class UserRestController extends WallabagRestController
+{
+    /**
+     * Retrieve current logged in user informations.
+     *
+     * @ApiDoc()
+     *
+     * @return JsonResponse
+     */
+    public function getUserAction()
+    {
+        $this->validateAuthentication();
+
+        return $this->sendUser($this->getUser());
+    }
+
+    /**
+     * Register an user.
+     *
+     * @ApiDoc(
+     *      requirements={
+     *          {"name"="username", "dataType"="string", "required"=true, "description"="The user's username"},
+     *          {"name"="password", "dataType"="string", "required"=true, "description"="The user's password"},
+     *          {"name"="email", "dataType"="string", "required"=true, "description"="The user's email"}
+     *      }
+     * )
+     *
+     * @todo Make this method (or the whole API) accessible only through https
+     *
+     * @return JsonResponse
+     */
+    public function putUserAction(Request $request)
+    {
+        if (!$this->container->getParameter('fosuser_registration')) {
+            $json = $this->get('serializer')->serialize(['error' => "Server doesn't allow registrations"], 'json');
+
+            return (new JsonResponse())->setJson($json)->setStatusCode(403);
+        }
+
+        $userManager = $this->get('fos_user.user_manager');
+        $user = $userManager->createUser();
+        // enable created user by default
+        $user->setEnabled(true);
+
+        $form = $this->createForm('Wallabag\UserBundle\Form\NewUserType', $user, [
+            'csrf_protection' => false,
+        ]);
+
+        // simulate form submission
+        $form->submit([
+            'username' => $request->request->get('username'),
+            'plainPassword' => [
+                'first' => $request->request->get('password'),
+                'second' => $request->request->get('password'),
+            ],
+            'email' => $request->request->get('email'),
+        ]);
+
+        if ($form->isSubmitted() && false === $form->isValid()) {
+            $view = $this->view($form, 400);
+            $view->setFormat('json');
+
+            // handle errors in a more beautiful way than the default view
+            $data = json_decode($this->handleView($view)->getContent(), true)['children'];
+            $errors = [];
+
+            if (isset($data['username']['errors'])) {
+                $errors['username'] = $this->translateErrors($data['username']['errors']);
+            }
+
+            if (isset($data['email']['errors'])) {
+                $errors['email'] = $this->translateErrors($data['email']['errors']);
+            }
+
+            if (isset($data['plainPassword']['children']['first']['errors'])) {
+                $errors['password'] = $this->translateErrors($data['plainPassword']['children']['first']['errors']);
+            }
+
+            $json = $this->get('serializer')->serialize(['error' => $errors], 'json');
+
+            return (new JsonResponse())->setJson($json)->setStatusCode(400);
+        }
+
+        $userManager->updateUser($user);
+
+        // dispatch a created event so the associated config will be created
+        $event = new UserEvent($user, $request);
+        $this->get('event_dispatcher')->dispatch(FOSUserEvents::USER_CREATED, $event);
+
+        return $this->sendUser($user);
+    }
+
+    /**
+     * Send user response.
+     *
+     * @param User $user
+     *
+     * @return JsonResponse
+     */
+    private function sendUser(User $user)
+    {
+        $json = $this->get('serializer')->serialize(
+            $user,
+            'json',
+            SerializationContext::create()->setGroups(['user_api'])
+        );
+
+        return (new JsonResponse())->setJson($json);
+    }
+
+    /**
+     * Translate errors message.
+     *
+     * @param array $errors
+     *
+     * @return array
+     */
+    private function translateErrors($errors)
+    {
+        $translatedErrors = [];
+        foreach ($errors as $error) {
+            $translatedErrors[] = $this->get('translator')->trans($error);
+        }
+
+        return $translatedErrors;
+    }
+}
index 57d37f4b454fa3aa15d3f4d6a36f194fd428d2ee..c0283e71f159603317b1179bbf194c21514c12fa 100644 (file)
@@ -17,3 +17,8 @@ misc:
   type: rest
   resource: "WallabagApiBundle:WallabagRest"
   name_prefix:  api_
+
+user:
+  type: rest
+  resource: "WallabagApiBundle:UserRest"
+  name_prefix:  api_
index 1c5c86d45501f41c987edba0efa48bf320f3fa93..084f2c67e11ec176a3144cb1fff8ceec622e6139 100644 (file)
@@ -33,9 +33,7 @@ class ManageController extends Controller
         // enable created user by default
         $user->setEnabled(true);
 
-        $form = $this->createForm('Wallabag\UserBundle\Form\NewUserType', $user, [
-            'validation_groups' => ['Profile'],
-        ]);
+        $form = $this->createForm('Wallabag\UserBundle\Form\NewUserType', $user);
         $form->handleRequest($request);
 
         if ($form->isSubmitted() && $form->isValid()) {
index 3a167de740608567ae03b6e42f88ab8d7d512bf6..1ff3046a8c798a226e5964d8ebdde28b170a3040 100644 (file)
@@ -4,11 +4,11 @@ namespace Wallabag\UserBundle\Entity;
 
 use Doctrine\Common\Collections\ArrayCollection;
 use Doctrine\ORM\Mapping as ORM;
+use JMS\Serializer\Annotation\Groups;
+use JMS\Serializer\Annotation\XmlRoot;
 use Scheb\TwoFactorBundle\Model\Email\TwoFactorInterface;
 use Scheb\TwoFactorBundle\Model\TrustedComputerInterface;
 use FOS\UserBundle\Model\User as BaseUser;
-use JMS\Serializer\Annotation\ExclusionPolicy;
-use JMS\Serializer\Annotation\Expose;
 use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
 use Symfony\Component\Security\Core\User\UserInterface;
 use Wallabag\ApiBundle\Entity\Client;
@@ -18,23 +18,25 @@ use Wallabag\CoreBundle\Entity\Entry;
 /**
  * User.
  *
+ * @XmlRoot("user")
  * @ORM\Entity(repositoryClass="Wallabag\UserBundle\Repository\UserRepository")
  * @ORM\Table(name="`user`")
  * @ORM\HasLifecycleCallbacks()
- * @ExclusionPolicy("all")
  *
  * @UniqueEntity("email")
  * @UniqueEntity("username")
  */
 class User extends BaseUser implements TwoFactorInterface, TrustedComputerInterface
 {
+    /** @Serializer\XmlAttribute */
     /**
      * @var int
      *
-     * @Expose
      * @ORM\Column(name="id", type="integer")
      * @ORM\Id
      * @ORM\GeneratedValue(strategy="AUTO")
+     *
+     * @Groups({"user_api"})
      */
     protected $id;
 
@@ -42,13 +44,31 @@ class User extends BaseUser implements TwoFactorInterface, TrustedComputerInterf
      * @var string
      *
      * @ORM\Column(name="name", type="text", nullable=true)
+     *
+     * @Groups({"user_api"})
      */
     protected $name;
 
+    /**
+     * @var string
+     *
+     * @Groups({"user_api"})
+     */
+    protected $username;
+
+    /**
+     * @var string
+     *
+     * @Groups({"user_api"})
+     */
+    protected $email;
+
     /**
      * @var date
      *
      * @ORM\Column(name="created_at", type="datetime")
+     *
+     * @Groups({"user_api"})
      */
     protected $createdAt;
 
@@ -56,6 +76,8 @@ class User extends BaseUser implements TwoFactorInterface, TrustedComputerInterf
      * @var date
      *
      * @ORM\Column(name="updated_at", type="datetime")
+     *
+     * @Groups({"user_api"})
      */
     protected $updatedAt;
 
diff --git a/tests/Wallabag/ApiBundle/Controller/UserRestControllerTest.php b/tests/Wallabag/ApiBundle/Controller/UserRestControllerTest.php
new file mode 100644 (file)
index 0000000..3f4969a
--- /dev/null
@@ -0,0 +1,110 @@
+<?php
+
+namespace Tests\Wallabag\ApiBundle\Controller;
+
+use Tests\Wallabag\ApiBundle\WallabagApiTestCase;
+
+class UserRestControllerTest extends WallabagApiTestCase
+{
+    public function testGetUser()
+    {
+        $this->client->request('GET', '/api/user.json');
+        $this->assertEquals(200, $this->client->getResponse()->getStatusCode());
+
+        $content = json_decode($this->client->getResponse()->getContent(), true);
+
+        $this->assertArrayHasKey('id', $content);
+        $this->assertArrayHasKey('email', $content);
+        $this->assertArrayHasKey('name', $content);
+        $this->assertArrayHasKey('username', $content);
+        $this->assertArrayHasKey('created_at', $content);
+        $this->assertArrayHasKey('updated_at', $content);
+
+        $this->assertEquals('bigboss@wallabag.org', $content['email']);
+        $this->assertEquals('Big boss', $content['name']);
+        $this->assertEquals('admin', $content['username']);
+
+        $this->assertEquals('application/json', $this->client->getResponse()->headers->get('Content-Type'));
+    }
+
+    public function testCreateNewUser()
+    {
+        $this->client->request('PUT', '/api/user.json', [
+            'username' => 'google',
+            'password' => 'googlegoogle',
+            'email' => 'wallabag@google.com',
+        ]);
+
+        $this->assertEquals(200, $this->client->getResponse()->getStatusCode());
+
+        $content = json_decode($this->client->getResponse()->getContent(), true);
+
+        $this->assertArrayHasKey('id', $content);
+        $this->assertArrayHasKey('email', $content);
+        $this->assertArrayHasKey('username', $content);
+        $this->assertArrayHasKey('created_at', $content);
+        $this->assertArrayHasKey('updated_at', $content);
+
+        $this->assertEquals('wallabag@google.com', $content['email']);
+        $this->assertEquals('google', $content['username']);
+
+        $this->assertEquals('application/json', $this->client->getResponse()->headers->get('Content-Type'));
+
+        // remove the created user to avoid side effect on other tests
+        // @todo remove these lines when test will be isolated
+        $em = $this->client->getContainer()->get('doctrine.orm.entity_manager');
+
+        $query = $em->createQuery('DELETE FROM Wallabag\CoreBundle\Entity\Config c WHERE c.user = :user_id');
+        $query->setParameter('user_id', $content['id']);
+        $query->execute();
+
+        $query = $em->createQuery('DELETE FROM Wallabag\UserBundle\Entity\User u WHERE u.id = :id');
+        $query->setParameter('id', $content['id']);
+        $query->execute();
+    }
+
+    public function testCreateNewUserWithExistingEmail()
+    {
+        $this->client->request('PUT', '/api/user.json', [
+            'username' => 'admin',
+            'password' => 'googlegoogle',
+            'email' => 'bigboss@wallabag.org',
+        ]);
+
+        $this->assertEquals(400, $this->client->getResponse()->getStatusCode());
+
+        $content = json_decode($this->client->getResponse()->getContent(), true);
+
+        $this->assertArrayHasKey('error', $content);
+        $this->assertArrayHasKey('username', $content['error']);
+        $this->assertArrayHasKey('email', $content['error']);
+
+        // $this->assertEquals('fos_user.username.already_used', $content['error']['username'][0]);
+        // $this->assertEquals('fos_user.email.already_used', $content['error']['email'][0]);
+        // This shouldn't be translated ...
+        $this->assertEquals('This value is already used.', $content['error']['username'][0]);
+        $this->assertEquals('This value is already used.', $content['error']['email'][0]);
+
+        $this->assertEquals('application/json', $this->client->getResponse()->headers->get('Content-Type'));
+    }
+
+    public function testCreateNewUserWithTooShortPassword()
+    {
+        $this->client->request('PUT', '/api/user.json', [
+            'username' => 'facebook',
+            'password' => 'face',
+            'email' => 'facebook@wallabag.org',
+        ]);
+
+        $this->assertEquals(400, $this->client->getResponse()->getStatusCode());
+
+        $content = json_decode($this->client->getResponse()->getContent(), true);
+
+        $this->assertArrayHasKey('error', $content);
+        $this->assertArrayHasKey('password', $content['error']);
+
+        $this->assertEquals('validator.password_too_short', $content['error']['password'][0]);
+
+        $this->assertEquals('application/json', $this->client->getResponse()->headers->get('Content-Type'));
+    }
+}
index cf9b33471cb2d13fa36251378e4d9ce109ea7ca9..a67655c8620abcb5266eaabe4a8119c0e2b4607c 100644 (file)
@@ -37,7 +37,7 @@ abstract class WallabagApiTestCase extends WebTestCase
         $firewallName = $container->getParameter('fos_user.firewall_name');
 
         $this->user = $userManager->findUserBy(['username' => 'admin']);
-        $loginManager->loginUser($firewallName, $this->user);
+        $loginManager->logInUser($firewallName, $this->user);
 
         // save the login token into the session and put it in a cookie
         $container->get('session')->set('_security_'.$firewallName, serialize($container->get('security.token_storage')->getToken()));
index 44b9a0301c51e11b4ba255c6b0c13a266f6f0af8..b46256a6eea17b76be1f984e60906ab6effe0352 100644 (file)
@@ -30,8 +30,8 @@ class ManageControllerTest extends WallabagCoreTestCase
         $form = $crawler->selectButton('user.form.save')->form(array(
             'new_user[username]' => 'test_user',
             'new_user[email]' => 'test@test.io',
-            'new_user[plainPassword][first]' => 'test',
-            'new_user[plainPassword][second]' => 'test',
+            'new_user[plainPassword][first]' => 'testtest',
+            'new_user[plainPassword][second]' => 'testtest',
         ));
 
         $client->submit($form);