mirror of
https://github.com/wallabag/wallabag.git
synced 2024-11-26 19:11:07 +00:00
Merge pull request #3065 from wallabag/api-creation-endpoint
Register through API
This commit is contained in:
commit
2150576d86
7 changed files with 284 additions and 10 deletions
139
src/Wallabag/ApiBundle/Controller/UserRestController.php
Normal file
139
src/Wallabag/ApiBundle/Controller/UserRestController.php
Normal file
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -17,3 +17,8 @@ misc:
|
||||||
type: rest
|
type: rest
|
||||||
resource: "WallabagApiBundle:WallabagRest"
|
resource: "WallabagApiBundle:WallabagRest"
|
||||||
name_prefix: api_
|
name_prefix: api_
|
||||||
|
|
||||||
|
user:
|
||||||
|
type: rest
|
||||||
|
resource: "WallabagApiBundle:UserRest"
|
||||||
|
name_prefix: api_
|
||||||
|
|
|
@ -33,9 +33,7 @@ class ManageController extends Controller
|
||||||
// enable created user by default
|
// enable created user by default
|
||||||
$user->setEnabled(true);
|
$user->setEnabled(true);
|
||||||
|
|
||||||
$form = $this->createForm('Wallabag\UserBundle\Form\NewUserType', $user, [
|
$form = $this->createForm('Wallabag\UserBundle\Form\NewUserType', $user);
|
||||||
'validation_groups' => ['Profile'],
|
|
||||||
]);
|
|
||||||
$form->handleRequest($request);
|
$form->handleRequest($request);
|
||||||
|
|
||||||
if ($form->isSubmitted() && $form->isValid()) {
|
if ($form->isSubmitted() && $form->isValid()) {
|
||||||
|
|
|
@ -4,11 +4,11 @@ namespace Wallabag\UserBundle\Entity;
|
||||||
|
|
||||||
use Doctrine\Common\Collections\ArrayCollection;
|
use Doctrine\Common\Collections\ArrayCollection;
|
||||||
use Doctrine\ORM\Mapping as ORM;
|
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\Email\TwoFactorInterface;
|
||||||
use Scheb\TwoFactorBundle\Model\TrustedComputerInterface;
|
use Scheb\TwoFactorBundle\Model\TrustedComputerInterface;
|
||||||
use FOS\UserBundle\Model\User as BaseUser;
|
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\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
|
||||||
use Symfony\Component\Security\Core\User\UserInterface;
|
use Symfony\Component\Security\Core\User\UserInterface;
|
||||||
use Wallabag\ApiBundle\Entity\Client;
|
use Wallabag\ApiBundle\Entity\Client;
|
||||||
|
@ -18,23 +18,25 @@ use Wallabag\CoreBundle\Entity\Entry;
|
||||||
/**
|
/**
|
||||||
* User.
|
* User.
|
||||||
*
|
*
|
||||||
|
* @XmlRoot("user")
|
||||||
* @ORM\Entity(repositoryClass="Wallabag\UserBundle\Repository\UserRepository")
|
* @ORM\Entity(repositoryClass="Wallabag\UserBundle\Repository\UserRepository")
|
||||||
* @ORM\Table(name="`user`")
|
* @ORM\Table(name="`user`")
|
||||||
* @ORM\HasLifecycleCallbacks()
|
* @ORM\HasLifecycleCallbacks()
|
||||||
* @ExclusionPolicy("all")
|
|
||||||
*
|
*
|
||||||
* @UniqueEntity("email")
|
* @UniqueEntity("email")
|
||||||
* @UniqueEntity("username")
|
* @UniqueEntity("username")
|
||||||
*/
|
*/
|
||||||
class User extends BaseUser implements TwoFactorInterface, TrustedComputerInterface
|
class User extends BaseUser implements TwoFactorInterface, TrustedComputerInterface
|
||||||
{
|
{
|
||||||
|
/** @Serializer\XmlAttribute */
|
||||||
/**
|
/**
|
||||||
* @var int
|
* @var int
|
||||||
*
|
*
|
||||||
* @Expose
|
|
||||||
* @ORM\Column(name="id", type="integer")
|
* @ORM\Column(name="id", type="integer")
|
||||||
* @ORM\Id
|
* @ORM\Id
|
||||||
* @ORM\GeneratedValue(strategy="AUTO")
|
* @ORM\GeneratedValue(strategy="AUTO")
|
||||||
|
*
|
||||||
|
* @Groups({"user_api"})
|
||||||
*/
|
*/
|
||||||
protected $id;
|
protected $id;
|
||||||
|
|
||||||
|
@ -42,13 +44,31 @@ class User extends BaseUser implements TwoFactorInterface, TrustedComputerInterf
|
||||||
* @var string
|
* @var string
|
||||||
*
|
*
|
||||||
* @ORM\Column(name="name", type="text", nullable=true)
|
* @ORM\Column(name="name", type="text", nullable=true)
|
||||||
|
*
|
||||||
|
* @Groups({"user_api"})
|
||||||
*/
|
*/
|
||||||
protected $name;
|
protected $name;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var string
|
||||||
|
*
|
||||||
|
* @Groups({"user_api"})
|
||||||
|
*/
|
||||||
|
protected $username;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var string
|
||||||
|
*
|
||||||
|
* @Groups({"user_api"})
|
||||||
|
*/
|
||||||
|
protected $email;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var date
|
* @var date
|
||||||
*
|
*
|
||||||
* @ORM\Column(name="created_at", type="datetime")
|
* @ORM\Column(name="created_at", type="datetime")
|
||||||
|
*
|
||||||
|
* @Groups({"user_api"})
|
||||||
*/
|
*/
|
||||||
protected $createdAt;
|
protected $createdAt;
|
||||||
|
|
||||||
|
@ -56,6 +76,8 @@ class User extends BaseUser implements TwoFactorInterface, TrustedComputerInterf
|
||||||
* @var date
|
* @var date
|
||||||
*
|
*
|
||||||
* @ORM\Column(name="updated_at", type="datetime")
|
* @ORM\Column(name="updated_at", type="datetime")
|
||||||
|
*
|
||||||
|
* @Groups({"user_api"})
|
||||||
*/
|
*/
|
||||||
protected $updatedAt;
|
protected $updatedAt;
|
||||||
|
|
||||||
|
|
110
tests/Wallabag/ApiBundle/Controller/UserRestControllerTest.php
Normal file
110
tests/Wallabag/ApiBundle/Controller/UserRestControllerTest.php
Normal file
|
@ -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'));
|
||||||
|
}
|
||||||
|
}
|
|
@ -37,7 +37,7 @@ abstract class WallabagApiTestCase extends WebTestCase
|
||||||
$firewallName = $container->getParameter('fos_user.firewall_name');
|
$firewallName = $container->getParameter('fos_user.firewall_name');
|
||||||
|
|
||||||
$this->user = $userManager->findUserBy(['username' => 'admin']);
|
$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
|
// 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()));
|
$container->get('session')->set('_security_'.$firewallName, serialize($container->get('security.token_storage')->getToken()));
|
||||||
|
|
|
@ -30,8 +30,8 @@ class ManageControllerTest extends WallabagCoreTestCase
|
||||||
$form = $crawler->selectButton('user.form.save')->form(array(
|
$form = $crawler->selectButton('user.form.save')->form(array(
|
||||||
'new_user[username]' => 'test_user',
|
'new_user[username]' => 'test_user',
|
||||||
'new_user[email]' => 'test@test.io',
|
'new_user[email]' => 'test@test.io',
|
||||||
'new_user[plainPassword][first]' => 'test',
|
'new_user[plainPassword][first]' => 'testtest',
|
||||||
'new_user[plainPassword][second]' => 'test',
|
'new_user[plainPassword][second]' => 'testtest',
|
||||||
));
|
));
|
||||||
|
|
||||||
$client->submit($form);
|
$client->submit($form);
|
||||||
|
|
Loading…
Reference in a new issue