From 5e98aa9c53642e9cbfd307b6abc74f709f2734a5 Mon Sep 17 00:00:00 2001 From: ngodfraind Date: Tue, 14 Jul 2015 11:27:13 +0200 Subject: [PATCH 01/24] crud for clients --- Controller/Administration/OauthController.php | 141 ++++++++++++++++++ Form/Administration/OauthClientType.php | 62 ++++++++ Manager/OauthManager.php | 27 ++++ Menu/ExternalAuthenticationRenderer.php | 9 +- Resources/config/routing.yml | 5 + Resources/public/js/administration/oauth.js | 42 ++++++ .../Oauth/clientModalForm.html.twig | 10 ++ .../views/Administration/Oauth/list.html.twig | 85 +++++++++++ .../Oauth/modalCreateForm.html.twig | 22 +++ .../Parameters/oauthIndex.html.twig | 7 +- 10 files changed, 407 insertions(+), 3 deletions(-) create mode 100644 Controller/Administration/OauthController.php create mode 100644 Form/Administration/OauthClientType.php create mode 100644 Manager/OauthManager.php create mode 100644 Resources/public/js/administration/oauth.js create mode 100644 Resources/views/Administration/Oauth/clientModalForm.html.twig create mode 100644 Resources/views/Administration/Oauth/list.html.twig create mode 100644 Resources/views/Administration/Oauth/modalCreateForm.html.twig diff --git a/Controller/Administration/OauthController.php b/Controller/Administration/OauthController.php new file mode 100644 index 000000000..8f58ea5cc --- /dev/null +++ b/Controller/Administration/OauthController.php @@ -0,0 +1,141 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Claroline\CoreBundle\Controller\Administration; + +use Symfony\Bundle\FrameworkBundle\Controller\Controller; +use Sensio\Bundle\FrameworkExtraBundle\Configuration as EXT; +use JMS\DiExtraBundle\Annotation as DI; +use JMS\SecurityExtraBundle\Annotation as SEC; +use Symfony\Component\Security\Core\Exception\AccessDeniedException; +use Claroline\CoreBundle\Manager\OauthManager; +use Claroline\CoreBundle\Entity\Oauth\Client; +use Claroline\CoreBundle\Form\Administration\OauthClientType; +use Symfony\Component\HttpFoundation\JsonResponse; + +/** + * @DI\Tag("security.secure_service") + * @SEC\PreAuthorize("canOpenAdminTool('platform_parameters')") + */ +class OauthController extends Controller +{ + private $oauthManager; + private $request; + + /** + * @DI\InjectParams({ + * "oauthManager" = @DI\Inject("claroline.manager.oauth_manager"), + * "request" = @DI\Inject("request") + * }) + */ + public function __construct( + OauthManager $oauthManager, + $request + ) { + $this->oauthManager = $oauthManager; + $this->request = $request; + } + + /** + * @EXT\Route( + * "/", + * name="claro_admin_oauth_claroline", + * options = {"expose"=true} + * ) + * @EXT\Template() + * + * Display the plugin list + * + * @return Response + */ + public function listAction() + { + $clients = $this->oauthManager->findAllClients(); + + return array('clients' => $clients); + } + + /** + * @EXT\Route( + * "/form", + * name="claro_admin_oauth_form", + * options = {"expose"=true} + * ) + * @EXT\Template() + * + * Display the plugin list + * + * @return Response + */ + public function modalCreateFormAction() + { + $form = $this->get('form.factory')->create(new OauthClientType()); + + return array('form' => $form->createView()); + } + + /** + * @EXT\Route( + * "/form/create", + * name="claro_admin_oauth_client_create", + * options = {"expose"=true} + * ) + * @EXT\Template("ClarolineCoreBundle:Administration:oauth\clientModalForm.html.twig") + * + * Display the plugin list + * + * @return Response + */ + public function createClientAction() + { + $form = $this->get('form.factory')->create(new OauthClientType()); + + $form->handleRequest($this->request); + + if ($form->isValid()) { + $grantTypes = $form->get('allowed_grant_types')->getData(); + $client = $this->oauthManager->createClient(); + $client->setRedirectUris(array($form->get('uri')->getData())); + $client->setAllowedGrantTypes($grantTypes); + $client->setName($form->get('name')->getData()); + $this->oauthManager->updateClient($client); + + return new JsonResponse(array( + 'id' => $client->getId(), + 'name' => $form->get('name')->getData(), + 'uri' => $form->get('uri')->getData(), + 'grant_type' => $grantTypes + )); + } + + return array('form' => $form->createView()); + } + + /** + * @EXT\Route( + * "/delete/client/{client}", + * name="oauth_client_remove", + * options = {"expose"=true} + * ) + * + * Display the plugin list + * + * @return Response + */ + public function deleteClientAction(Client $client) + { + $oldid = $client->getId(); + $this->oauthManager->deleteClient($client); + + return new JsonResponse(array('id' => $oldid)); + + } +} diff --git a/Form/Administration/OauthClientType.php b/Form/Administration/OauthClientType.php new file mode 100644 index 000000000..f2dc3ec71 --- /dev/null +++ b/Form/Administration/OauthClientType.php @@ -0,0 +1,62 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Claroline\CoreBundle\Form\Administration; + +use Symfony\Component\Validator\Constraints\NotBlank; +use Symfony\Component\Form\AbstractType; +use Symfony\Component\Form\FormBuilderInterface; +use Symfony\Component\OptionsResolver\OptionsResolverInterface; + +class OauthClientType extends AbstractType +{ + public function buildForm(FormBuilderInterface $builder, array $options) + { + $builder->add( + 'name', + 'text', + array('constraints' => new NotBlank(), 'label' => 'name') + ); + $builder->add( + 'allowed_grant_types', + 'choice', + array( + 'choices' => array( + 'authorization_code' => '_authorization_code', + 'password' => '_password', + 'refresh_token' => '_refresh_token', + 'token' => '_token', + 'client_credentials' => '_client_credentials' + ), + 'disabled' => isset($this->lockedParams['mailer_transport']), + 'label' => 'grant_type', + 'multiple' => true, + 'constraints' => new NotBlank(), + 'expanded' => true + ) + ); + $builder->add( + 'uri', + 'text', + array('label' => 'uri', 'constraints' => new NotBlank()) + ); + } + + public function getName() + { + return 'oauth_client_form'; + } + + public function setDefaultOptions(OptionsResolverInterface $resolver) + { + $resolver->setDefaults(array('translation_domain' => 'platform')); + } +} diff --git a/Manager/OauthManager.php b/Manager/OauthManager.php new file mode 100644 index 000000000..d30ebf9c6 --- /dev/null +++ b/Manager/OauthManager.php @@ -0,0 +1,27 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Claroline\CoreBundle\Manager; + +use JMS\DiExtraBundle\Annotation as DI; +use Claroline\CoreBundle\Event\StrictDispatcher; +use FOS\OAuthServerBundle\Entity\ClientManager; + +/** + * @DI\Service("claroline.manager.oauth_manager", parent="fos_oauth_server.client_manager.default") + */ +class OauthManager extends ClientManager +{ + public function findAllClients() + { + return $this->repository->findAll(); + } +} diff --git a/Menu/ExternalAuthenticationRenderer.php b/Menu/ExternalAuthenticationRenderer.php index cdb0222df..5088c1ff0 100644 --- a/Menu/ExternalAuthenticationRenderer.php +++ b/Menu/ExternalAuthenticationRenderer.php @@ -37,14 +37,19 @@ public function __construct( ) { parent::__construct($matcher, $defaultOptions, $charset); - }/* + } protected function renderLinkElement(ItemInterface $item, array $options) { + return sprintf( + '%s', + $this->escape($item->getUri()), + $this->renderLabel($item, $options) + ); } protected function renderSpanElement(ItemInterface $item, array $options) { return $this->renderLinkElement($item, $options); - }*/ + } } diff --git a/Resources/config/routing.yml b/Resources/config/routing.yml index 2f45494e1..8a65da881 100644 --- a/Resources/config/routing.yml +++ b/Resources/config/routing.yml @@ -266,6 +266,11 @@ claro_admin_facet: prefix: admin/facet type: annotation +claro_admin_oauth: + resource: "@ClarolineCoreBundle/Controller/Administration/OauthController.php" + prefix: admin/oauth + type: annotation + claro_admin_i18n: resource: "@ClarolineCoreBundle/Controller/Administration/InternationalizationController.php" prefix: admin/i18n diff --git a/Resources/public/js/administration/oauth.js b/Resources/public/js/administration/oauth.js new file mode 100644 index 000000000..4e263ed4e --- /dev/null +++ b/Resources/public/js/administration/oauth.js @@ -0,0 +1,42 @@ +/* + * This file is part of the Claroline Connect package. + * + * (c) Claroline Consortium + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +(function () { + 'use strict'; + + var modal = window.Claroline.Modal; + + var addClient = function() { + window.location.reload(); + } + + var removeClientRow = function (event, clientId) { + $('#client-row-' + clientId).remove(); + }; + + $('body') + .on('click', '#add-client-btn', function(event) { + var url = Routing.generate('claro_admin_oauth_form'); + modal.displayForm(url, addClient, function(){}, 'form_client_creation'); + }) + .on('click', '.delete-client-btn', function(event) { + var clientid = $(event.target).attr('data-client-id'); + + modal.confirmRequest( + Routing.generate( + 'oauth_client_remove', + {'client': clientid} + ), + removeClientRow, + clientid, + Translator.trans('delete_client_message', {}, 'platform'), + Translator.trans('delete_client', {}, 'platform') + ); + }); +}) (); diff --git a/Resources/views/Administration/Oauth/clientModalForm.html.twig b/Resources/views/Administration/Oauth/clientModalForm.html.twig new file mode 100644 index 000000000..712ea4adc --- /dev/null +++ b/Resources/views/Administration/Oauth/clientModalForm.html.twig @@ -0,0 +1,10 @@ + diff --git a/Resources/views/Administration/Oauth/list.html.twig b/Resources/views/Administration/Oauth/list.html.twig new file mode 100644 index 000000000..9427e742d --- /dev/null +++ b/Resources/views/Administration/Oauth/list.html.twig @@ -0,0 +1,85 @@ +{% extends "ClarolineCoreBundle:Administration:layout.html.twig" %} + +{% block title %}{{ parent() ~ ' - ' ~ 'server' | trans({}, 'platform') | striptags | raw }}{% endblock %} + +{% block breadcrumb %} + {{ + macros.breadcrumbs([ + { + 'icon': 'fa fa-cog', + 'name': 'administration'|trans({}, 'platform'), + 'href': path('claro_admin_index') + }, + { + 'name': 'parameters'|trans({}, 'platform'), + 'href': path('claro_admin_index') + }, + { + 'name': 'oauth'|trans({}, 'platform'), + 'href': path('claro_admin_parameters_oauth_index') + }, + { + 'name': 'claroline'|trans({}, 'platform'), + 'href': '' + } + ]) + }} +{% endblock %} + +{% block section_content %} +
+

{{ 'claroline'|trans({}, 'platform') }}

+
+ +
+
+ + + + + + + + + + + {% for client in clients %} + + + + + + + {% endfor %} + +
{{ 'redirect_uri'|trans({}, 'platform') }} {{ 'grant_type'|trans({}, 'platform') }} {{ 'client_name'|trans({}, 'platform')}}
+ {% for uris in client.getRedirectUris() %} + {{ uris }} + {% endfor %} + + {% for grantType in client.getAllowedGrantTypes() %} + {{ grantType }} + {% endfor %} + {{ client.getName() }} +
+ +
+
+
+ +
+{% endblock %} + +{% block javascripts %} + {{ parent() }} + + +{% endblock %} diff --git a/Resources/views/Administration/Oauth/modalCreateForm.html.twig b/Resources/views/Administration/Oauth/modalCreateForm.html.twig new file mode 100644 index 000000000..513fd6ed2 --- /dev/null +++ b/Resources/views/Administration/Oauth/modalCreateForm.html.twig @@ -0,0 +1,22 @@ +{% extends "ClarolineCoreBundle:Administration\\Oauth:clientModalForm.html.twig" %} + +{% block header %} + {{ 'create_client'|trans({}, 'platform') }} +{% endblock %} + +{% block form %} +
+ + +
+{% endblock %} diff --git a/Resources/views/Administration/Parameters/oauthIndex.html.twig b/Resources/views/Administration/Parameters/oauthIndex.html.twig index 3bd8e3ecc..6592151bf 100644 --- a/Resources/views/Administration/Parameters/oauthIndex.html.twig +++ b/Resources/views/Administration/Parameters/oauthIndex.html.twig @@ -27,6 +27,11 @@

{{ 'oauth'|trans({}, 'platform') }}

- {{ knp_menu_render('ClarolineCoreBundle:Builder:externalAuthenticationMenu', {}, 'external_authentication') }} +
+ Claroline +
+
+ {{ knp_menu_render('ClarolineCoreBundle:Builder:externalAuthenticationMenu', {}, 'external_authentication') }} +
{% endblock %} From 5984d2d6a728d5219c73e68f26be669c5f31c173 Mon Sep 17 00:00:00 2001 From: ngodfraind Date: Tue, 14 Jul 2015 18:51:21 +0200 Subject: [PATCH 02/24] Serialisze + foxrest bundle. --- Controller/API/ApiController.php | 47 ++++++ Controller/API/UserController.php | 150 +++++++++++++++--- Controller/Administration/UsersController.php | 20 +-- Entity/Role.php | 4 + Entity/User.php | 24 ++- Manager/RoleManager.php | 19 +++ Manager/UserManager.php | 7 + Resources/config/routing.yml | 8 +- Resources/config/suggested/fos_rest.yml | 9 +- Resources/config/suggested/security.yml | 8 +- .../views/Administration/Oauth/list.html.twig | 2 + 11 files changed, 246 insertions(+), 52 deletions(-) create mode 100644 Controller/API/ApiController.php diff --git a/Controller/API/ApiController.php b/Controller/API/ApiController.php new file mode 100644 index 000000000..1464c4d84 --- /dev/null +++ b/Controller/API/ApiController.php @@ -0,0 +1,47 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Claroline\CoreBundle\Controller\API; + +use FOS\RestBundle\Util\Codes; +use Symfony\Bundle\FrameworkBundle\Controller\Controller; +use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route; +use Symfony\Component\HttpFoundation\JsonResponse; + +class ApiController extends Controller +{ + /** + * @Route("/connected_user") + */ + public function connectedUserAction() + { + /** @var \Symfony\Component\Security\Core\SecurityContext $securityContext */ + $tokenStorage = $this->container->get('security.token_storage'); + $securityToken = $tokenStorage->getToken(); + + if (null !== $securityToken) { + /** @var \Claroline\CoreBundle\Entity\User $user */ + $user = $securityToken->getUser(); + + if($user) { + return new JsonResponse(array( + 'id' => $user->getId(), + 'username' => $user->getUsername(), + 'user_id' => $user->getUsername() . $user->getId() + )); + } + } + + return new JsonResponse(array( + 'message' => 'User is not identified' + ), Codes::HTTP_NOT_FOUND); + } +} diff --git a/Controller/API/UserController.php b/Controller/API/UserController.php index ba8fbf07c..76ab8d357 100644 --- a/Controller/API/UserController.php +++ b/Controller/API/UserController.php @@ -11,40 +11,138 @@ namespace Claroline\CoreBundle\Controller\API; -use FOS\RestBundle\Util\Codes; +use FOS\RestBundle\Routing\ClassResourceInterface; +use FOS\RestBundle\Controller\FOSRestController; +use FOS\RestBundle\Controller\Annotations\View; +use Claroline\CoreBundle\Entity\Role; +use Claroline\CoreBundle\Entity\Tool\Tool; +use Claroline\CoreBundle\Entity\User; +use Claroline\CoreBundle\Form\ProfileCreationType; +use Claroline\CoreBundle\Library\Configuration\PlatformConfigurationHandler; +use Claroline\CoreBundle\Manager\AuthenticationManager; +use Claroline\CoreBundle\Manager\LocaleManager; +use Claroline\CoreBundle\Manager\MailManager; +use Claroline\CoreBundle\Manager\RightsManager; +use Claroline\CoreBundle\Manager\RoleManager; +use Claroline\CoreBundle\Manager\ToolManager; +use Claroline\CoreBundle\Manager\ToolMaskDecoderManager; +use Claroline\CoreBundle\Manager\UserManager; +use Claroline\CoreBundle\Manager\WorkspaceManager; +use JMS\DiExtraBundle\Annotation as DI; +use JMS\SecurityExtraBundle\Annotation as SEC; +use Sensio\Bundle\FrameworkExtraBundle\Configuration as EXT; use Symfony\Bundle\FrameworkBundle\Controller\Controller; -use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route; +use Symfony\Component\Form\FormFactory; use Symfony\Component\HttpFoundation\JsonResponse; +use Symfony\Component\HttpFoundation\RedirectResponse; +use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\HttpFoundation\Response; +use Symfony\Component\HttpFoundation\StreamedResponse; +use Symfony\Component\Security\Core\Exception\AccessDeniedException; +use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface; +use Claroline\CoreBundle\Persistence\ObjectManager; -/** - * @Route("/api") - */ -class UserController extends Controller +class UserController extends FOSRestController { /** - * @Route("/connected_user") + * @DI\InjectParams({ + * "authenticationManager" = @DI\Inject("claroline.common.authentication_manager"), + * "configHandler" = @DI\Inject("claroline.config.platform_config_handler"), + * "formFactory" = @DI\Inject("form.factory"), + * "localeManager" = @DI\Inject("claroline.common.locale_manager"), + * "mailManager" = @DI\Inject("claroline.manager.mail_manager"), + * "request" = @DI\Inject("request"), + * "rightsManager" = @DI\Inject("claroline.manager.rights_manager"), + * "roleManager" = @DI\Inject("claroline.manager.role_manager"), + * "toolManager" = @DI\Inject("claroline.manager.tool_manager"), + * "toolMaskDecoderManager" = @DI\Inject("claroline.manager.tool_mask_decoder_manager"), + * "userManager" = @DI\Inject("claroline.manager.user_manager"), + * "workspaceManager" = @DI\Inject("claroline.manager.workspace_manager"), + * "om" = @DI\Inject("claroline.persistence.object_manager") + * }) + */ + public function __construct( + AuthenticationManager $authenticationManager, + FormFactory $formFactory, + LocaleManager $localeManager, + MailManager $mailManager, + PlatformConfigurationHandler $configHandler, + Request $request, + RightsManager $rightsManager, + RoleManager $roleManager, + ToolManager $toolManager, + ToolMaskDecoderManager $toolMaskDecoderManager, + UserManager $userManager, + WorkspaceManager $workspaceManager, + ObjectManager $om + ) + { + $this->authenticationManager = $authenticationManager; + $this->configHandler = $configHandler; + $this->formFactory = $formFactory; + $this->localeManager = $localeManager; + $this->mailManager = $mailManager; + $this->request = $request; + $this->rightsManager = $rightsManager; + $this->roleManager = $roleManager; + $this->toolManager = $toolManager; + $this->toolMaskDecoderManager = $toolMaskDecoderManager; + $this->userAdminTool = $this->toolManager->getAdminToolByName('user_management'); + $this->userManager = $userManager; + $this->workspaceManager = $workspaceManager; + $this->om = $om; + } + + /** + * @View(serializerGroups={"api"}) */ - public function connectedUserAction() + public function getUsersAction() { - /** @var \Symfony\Component\Security\Core\SecurityContext $securityContext */ - $tokenStorage = $this->container->get('security.token_storage'); - $securityToken = $tokenStorage->getToken(); - - if (null !== $securityToken) { - /** @var \Claroline\CoreBundle\Entity\User $user */ - $user = $securityToken->getUser(); - - if($user) { - return new JsonResponse(array( - 'id' => $user->getId(), - 'username' => $user->getUsername(), - 'user_id' => $user->getUsername() . $user->getId() - )); - } + return $this->userManager->getAll(); + } + + public function putUserAction() + { + $roleUser = $this->roleManager->getRoleByName('ROLE_USER'); + + $profileType = new ProfileCreationType( + $this->localeManager, + array($roleUser), + true, + $this->authenticationManager->getDrivers() + ); + + $form = $this->formFactory->create($profileType); + $form->handleRequest($this->request); + $roles = $form->get('platformRoles')->getData(); + $unavailableRoles = $this->roleManager->validateNewUserRolesInsert($roles); + + if ($form->isValid() && count($unavailableRoles) === 0) { + $user = $form->getData(); + $this->userManager->createUser($user, true, $roles); + + return $this->redirect($this->generateUrl('claro_admin_user_list')); } - return new JsonResponse(array( - 'message' => 'User is not identified' - ), Codes::HTTP_NOT_FOUND); + return array( + 'form_complete_user' => $form->createView(), + 'error' => $error, + 'unavailableRoles' => $unavailableRoles, + ); + } + + /** + * @View(serializerGroups={"api"}) + */ + public function getUserAction($slug) + { + $user = $this->userManager->getUserByUsername($slug); + + return $user; + } + + public function deleteUserAction($slug) + { + } } diff --git a/Controller/Administration/UsersController.php b/Controller/Administration/UsersController.php index 628464065..d8b733115 100644 --- a/Controller/Administration/UsersController.php +++ b/Controller/Administration/UsersController.php @@ -214,24 +214,8 @@ public function createAction(User $currentUser) ); $form = $this->formFactory->create($profileType); $form->handleRequest($this->request); - - $unavailableRoles = []; - - foreach ($form->get('platformRoles')->getData() as $role) { - $isAvailable = $this->roleManager->validateRoleInsert(new User(), $role); - - if (!$isAvailable) { - $unavailableRoles[] = $role; - } - } - - $isAvailable = $this->roleManager->validateRoleInsert(new User(), $roleUser); - - if (!$isAvailable) { - $unavailableRoles[] = $roleUser; - } - - $unavailableRoles = array_unique($unavailableRoles); + $roles = $form->get('platformRoles')->getData(); + $unavailableRoles = $this->roleManager->validateNewUserRolesInsert($roles); if ($form->isValid() && count($unavailableRoles) === 0) { $user = $form->getData(); diff --git a/Entity/Role.php b/Entity/Role.php index cb39eac31..6fb37f1b0 100644 --- a/Entity/Role.php +++ b/Entity/Role.php @@ -22,6 +22,7 @@ use Claroline\CoreBundle\Entity\Tool\ToolRights; use Claroline\CoreBundle\Entity\Workspace\Workspace; use Claroline\CoreBundle\Entity\Tool\PwsToolConfig; +use JMS\Serializer\Annotation\Groups; /** * @ORM\Entity(repositoryClass="Claroline\CoreBundle\Repository\RoleRepository") @@ -40,12 +41,14 @@ class Role implements RoleInterface * @ORM\Id * @ORM\Column(type="integer") * @ORM\GeneratedValue(strategy="AUTO") + * @Groups({"api"}) */ protected $id; /** * @ORM\Column(unique=true) * @Assert\NotBlank() + * @Groups({"api"}) */ protected $name; @@ -110,6 +113,7 @@ class Role implements RoleInterface /** * @ORM\Column(type="integer") + * @Groups({"api"}) */ protected $type = self::PLATFORM_ROLE; diff --git a/Entity/User.php b/Entity/User.php index 4eb52b29c..706a517c7 100644 --- a/Entity/User.php +++ b/Entity/User.php @@ -30,6 +30,7 @@ use Symfony\Component\Validator\Mapping\ClassMetadata; use Claroline\CoreBundle\Entity\Facet\FieldFacetValue; use Claroline\CoreBundle\Entity\UserOptions; +use JMS\Serializer\Annotation\Groups; /** * @ORM\Table(name="claro_user") @@ -47,6 +48,7 @@ class User extends AbstractRoleSubject implements Serializable, AdvancedUserInte * @ORM\Id * @ORM\Column(type="integer") * @ORM\GeneratedValue(strategy="AUTO") + * @Groups({"api"}) */ protected $id; @@ -55,6 +57,7 @@ class User extends AbstractRoleSubject implements Serializable, AdvancedUserInte * * @ORM\Column(name="first_name", length=50) * @Assert\NotBlank() + * @Groups({"api"}) */ protected $firstName; @@ -63,6 +66,7 @@ class User extends AbstractRoleSubject implements Serializable, AdvancedUserInte * * @ORM\Column(name="last_name", length=50) * @Assert\NotBlank() + * @Groups({"api"}) */ protected $lastName; @@ -73,6 +77,7 @@ class User extends AbstractRoleSubject implements Serializable, AdvancedUserInte * @Assert\NotBlank() * @Assert\Length(min="3") * @ClaroAssert\Username() + * @Groups({"api"}) */ protected $username; @@ -87,6 +92,7 @@ class User extends AbstractRoleSubject implements Serializable, AdvancedUserInte * @var string * * @ORM\Column(nullable=true) + * @Groups({"api"}) */ protected $locale; @@ -109,6 +115,7 @@ class User extends AbstractRoleSubject implements Serializable, AdvancedUserInte * @var string * * @ORM\Column(nullable=true) + * @Groups({"api"}) */ protected $phone; @@ -118,6 +125,7 @@ class User extends AbstractRoleSubject implements Serializable, AdvancedUserInte * @ORM\Column(unique=true) * @Assert\NotBlank() * @Assert\Email(checkMX = false) + * @Groups({"api"}) */ protected $mail; @@ -125,6 +133,7 @@ class User extends AbstractRoleSubject implements Serializable, AdvancedUserInte * @var string * * @ORM\Column(name="administrative_code", nullable=true) + * @Groups({"api"}) */ protected $administrativeCode; @@ -149,6 +158,7 @@ class User extends AbstractRoleSubject implements Serializable, AdvancedUserInte * cascade={"merge"} * ) * @ORM\JoinTable(name="claro_user_role") + * @Groups({"api"}) */ protected $roles; @@ -177,6 +187,7 @@ class User extends AbstractRoleSubject implements Serializable, AdvancedUserInte * * @ORM\Column(name="creation_date", type="datetime") * @Gedmo\Timestampable(on="create") + * @Groups({"api"}) */ protected $created; @@ -184,6 +195,7 @@ class User extends AbstractRoleSubject implements Serializable, AdvancedUserInte * @var \DateTime * * @ORM\Column(name="initialization_date", type="datetime", nullable=true) + * @Groups({"api"}) */ protected $initDate; @@ -226,6 +238,7 @@ class User extends AbstractRoleSubject implements Serializable, AdvancedUserInte * @var boolean * * @ORM\Column(type="boolean", nullable=true) + * @Groups({"api"}) */ protected $hasAcceptedTerms; @@ -233,6 +246,7 @@ class User extends AbstractRoleSubject implements Serializable, AdvancedUserInte * @var boolean * * @ORM\Column(name="is_enabled", type="boolean") + * @Groups({"api"}) */ protected $isEnabled = true; @@ -240,11 +254,13 @@ class User extends AbstractRoleSubject implements Serializable, AdvancedUserInte * @var boolean * * @ORM\Column(name="is_mail_notified", type="boolean") + * @Groups({"api"}) */ protected $isMailNotified = true; /** * @ORM\Column(name="last_uri", length=255, nullable=true) + * @Groups({"api"}) */ protected $lastUri; @@ -252,6 +268,7 @@ class User extends AbstractRoleSubject implements Serializable, AdvancedUserInte * @var string * * @ORM\Column(name="public_url", type="string", nullable=true, unique=true) + * @Groups({"api"}) */ protected $publicUrl; @@ -259,6 +276,7 @@ class User extends AbstractRoleSubject implements Serializable, AdvancedUserInte * @var boolean * * @ORM\Column(name="has_tuned_public_url", type="boolean") + * @Groups({"api"}) */ protected $hasTunedPublicUrl = false; @@ -266,6 +284,7 @@ class User extends AbstractRoleSubject implements Serializable, AdvancedUserInte * @var \DateTime * * @ORM\Column(name="expiration_date", type="datetime", nullable=true) + * @Groups({"api"}) */ protected $expirationDate; @@ -294,6 +313,7 @@ class User extends AbstractRoleSubject implements Serializable, AdvancedUserInte * @var string * * @ORM\Column(nullable=true) + * @Groups({"api"}) */ protected $authentication; @@ -381,7 +401,7 @@ public function getSalt() { return $this->salt; } - + /** * @param string $salt * @@ -390,7 +410,7 @@ public function getSalt() public function setSalt($salt) { $this->salt = $salt; - + return $this; } diff --git a/Manager/RoleManager.php b/Manager/RoleManager.php index 83388226c..a26f22e91 100644 --- a/Manager/RoleManager.php +++ b/Manager/RoleManager.php @@ -803,6 +803,25 @@ public function validateRoleInsert(AbstractRoleSubject $ars, Role $role) return false; } + public function validateNewUserRolesInsert(array $roles) + { + foreach ($roles as $role) { + $isAvailable = $this->validateRoleInsert(new User(), $role); + + if (!$isAvailable) { + $unavailableRoles[] = $role; + } + } + + $isAvailable = $this->validateRoleInsert(new User(), $roleUser); + + if (!$isAvailable) { + $unavailableRoles[] = $roleUser; + } + + return array_unique($unavailableRoles); + } + /** * @param Role $role * @return bool diff --git a/Manager/UserManager.php b/Manager/UserManager.php index 64d9de163..b7d633ad5 100644 --- a/Manager/UserManager.php +++ b/Manager/UserManager.php @@ -524,6 +524,13 @@ public function getAllUsers($page, $max = 20, $orderedBy = 'id', $order = null) return $this->pagerFactory->createPager($query, $page, $max); } + /** + */ + public function getAll() + { + return $this->userRepo->findAll(); + } + /** * @param integer $page * @param integer $max diff --git a/Resources/config/routing.yml b/Resources/config/routing.yml index 8a65da881..c936631ee 100644 --- a/Resources/config/routing.yml +++ b/Resources/config/routing.yml @@ -277,9 +277,15 @@ claro_admin_i18n: type: annotation claro_api: - resource: "@ClarolineCoreBundle/Controller/API" + resource: "@ClarolineCoreBundle/Controller/API/ApiController.php" + prefix: api type: annotation +claro_user_api: + resource: "@ClarolineCoreBundle/Controller/API/UserController.php" + type: rest + prefix: api + claro_contact: resource: "@ClarolineCoreBundle/Controller/ContactController.php" prefix: contact diff --git a/Resources/config/suggested/fos_rest.yml b/Resources/config/suggested/fos_rest.yml index 19323d8d8..e21a35594 100644 --- a/Resources/config/suggested/fos_rest.yml +++ b/Resources/config/suggested/fos_rest.yml @@ -1 +1,8 @@ -fos_rest: ~ +fos_rest: + view: + view_response_listener: force + format_listener: + rules: + priorities: ['json'] + fallback_format: json + prefer_extension: true diff --git a/Resources/config/suggested/security.yml b/Resources/config/suggested/security.yml index 4eb83e951..f62e82bec 100644 --- a/Resources/config/suggested/security.yml +++ b/Resources/config/suggested/security.yml @@ -28,10 +28,10 @@ security: use_referer: true anonymous: true - api: - pattern: ^/api - fos_oauth: true - stateless: true + #api: + # pattern: ^/api + # fos_oauth: true + # stateless: true main: pattern: ^/ diff --git a/Resources/views/Administration/Oauth/list.html.twig b/Resources/views/Administration/Oauth/list.html.twig index 9427e742d..a2fb01e31 100644 --- a/Resources/views/Administration/Oauth/list.html.twig +++ b/Resources/views/Administration/Oauth/list.html.twig @@ -36,6 +36,7 @@ + @@ -45,6 +46,7 @@ {% for client in clients %} +
{{ 'id'|trans({}, 'platform') }} {{ 'redirect_uri'|trans({}, 'platform') }} {{ 'grant_type'|trans({}, 'platform') }} {{ 'client_name'|trans({}, 'platform')}}
{{ client.getId() }} {% for uris in client.getRedirectUris() %} {{ uris }} From 2afef26e11e462a57c98e68192c1bcb634deefef Mon Sep 17 00:00:00 2001 From: ngodfraind Date: Thu, 16 Jul 2015 16:35:40 +0200 Subject: [PATCH 03/24] Full api for workspace, users and groups. --- Controller/API/GroupController.php | 146 ++++++++++++++ Controller/API/UserController.php | 179 ++++++++++++------ Controller/API/WorkspaceController.php | 152 +++++++++++++++ .../Administration/GroupsController.php | 1 - Entity/Group.php | 3 + Entity/Workspace/Workspace.php | 20 ++ Form/GroupType.php | 30 ++- Form/ProfileCreationType.php | 19 +- Form/ProfileType.php | 17 +- Form/WorkspaceType.php | 116 +++++++++--- Manager/GroupManager.php | 1 + Resources/config/routing.yml | 10 + Resources/config/suggested/fos_rest.yml | 7 +- Resources/config/suggested/monolog_prod.yml | 2 +- Resources/config/suggested/security.yml | 5 +- 15 files changed, 604 insertions(+), 104 deletions(-) create mode 100644 Controller/API/GroupController.php create mode 100644 Controller/API/WorkspaceController.php diff --git a/Controller/API/GroupController.php b/Controller/API/GroupController.php new file mode 100644 index 000000000..bf120c450 --- /dev/null +++ b/Controller/API/GroupController.php @@ -0,0 +1,146 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Claroline\CoreBundle\Controller\API; + +use JMS\DiExtraBundle\Annotation as DI; +use FOS\RestBundle\Controller\FOSRestController; +use Claroline\CoreBundle\Persistence\ObjectManager; +use Claroline\CoreBundle\Manager\GroupManager; +use Claroline\CoreBundle\Manager\RoleManager; +use Symfony\Component\Form\FormFactory; +use Symfony\Component\HttpFoundation\Request; +use FOS\RestBundle\Controller\Annotations\View; +use Claroline\CoreBundle\Form\GroupType; +use Claroline\CoreBundle\Entity\Group; +use Claroline\CoreBundle\Entity\User; +use Claroline\CoreBundle\Entity\Role; + +class GroupController extends FOSRestController +{ + /** + * @DI\InjectParams({ + * "formFactory" = @DI\Inject("form.factory"), + * "groupManager" = @DI\Inject("claroline.manager.group_manager"), + * "roleManager" = @DI\Inject("claroline.manager.role_manager"), + * "request" = @DI\Inject("request"), + * "om" = @DI\Inject("claroline.persistence.object_manager") + * }) + */ + public function __construct( + FormFactory $formFactory, + GroupManager $groupManager, + RoleManager $roleManager, + ObjectManager $om, + Request $request + ) + { + $this->formFactory = $formFactory; + $this->groupManager = $groupManager; + $this->roleManager = $roleManager; + $this->om = $om; + $this->groupRepository = $this->om->getRepository('ClarolineCoreBundle:Group'); + $this->request = $request; + } + + /** + * @View(serializerGroups={"api"}) + */ + public function getGroupsAction() + { + return $this->groupRepository->findAll(); + } + + /** + * @View(serializerGroups={"api"}) + */ + public function getGroupAction(Group $group) + { + return $group; + } + + /** + * @View(serializerGroups={"api"}) + * group_form[fieldname] for the put request + */ + public function postGroupAction() + { + $groupType = new GroupType(); + $groupType->enableApi(); + $form = $this->formFactory->create($groupType, new Group()); + $form->submit($this->request); + //$form->handleRequest($this->request); + + if ($form->isValid()) { + $group = $form->getData(); + $userRole = $this->roleManager->getRoleByName('ROLE_USER'); + $group->setPlatformRole($userRole); + $this->groupManager->insertGroup($group); + + return $group; + } + + return $form; + } + + /** + * @View(serializerGroups={"api"}) + * group_form[fieldname] for the put request + */ + public function putGroupAction(Group $group) + { + $groupType = new GroupType(); + $groupType->enableApi(); + $form = $this->formFactory->create($groupType, $group); + $form->submit($this->request); + //$form->handleRequest($this->request); + + if ($form->isValid()) { + $group = $form->getData(); + $userRole = $this->roleManager->getRoleByName('ROLE_USER'); + $this->groupManager->insertGroup($group); + + return $group; + } + + return $form; + } + + /** + * @View() + */ + public function deleteGroupAction(Group $group) + { + $this->groupManager->deleteGroup($user); + + return array('success'); + } + + /** + * @View() + */ + public function addGroupRoleAction(Group $group, Role $role) + { + $this->roleManager->associateRole($group, $role, false); + + return array('success'); + } + + /** + * @View() + */ + public function removeGroupRoleAction(Group $group, Role $role) + { + $this->roleManager->dissociateRole($group, $role); + + return array('success'); + } +} diff --git a/Controller/API/UserController.php b/Controller/API/UserController.php index 76ab8d357..a46577afc 100644 --- a/Controller/API/UserController.php +++ b/Controller/API/UserController.php @@ -11,35 +11,23 @@ namespace Claroline\CoreBundle\Controller\API; -use FOS\RestBundle\Routing\ClassResourceInterface; use FOS\RestBundle\Controller\FOSRestController; use FOS\RestBundle\Controller\Annotations\View; -use Claroline\CoreBundle\Entity\Role; -use Claroline\CoreBundle\Entity\Tool\Tool; use Claroline\CoreBundle\Entity\User; +use Claroline\CoreBundle\Entity\Role; +use Claroline\CoreBundle\Entity\Group; use Claroline\CoreBundle\Form\ProfileCreationType; -use Claroline\CoreBundle\Library\Configuration\PlatformConfigurationHandler; -use Claroline\CoreBundle\Manager\AuthenticationManager; +use Claroline\CoreBundle\Form\ProfileType; use Claroline\CoreBundle\Manager\LocaleManager; -use Claroline\CoreBundle\Manager\MailManager; -use Claroline\CoreBundle\Manager\RightsManager; -use Claroline\CoreBundle\Manager\RoleManager; -use Claroline\CoreBundle\Manager\ToolManager; -use Claroline\CoreBundle\Manager\ToolMaskDecoderManager; use Claroline\CoreBundle\Manager\UserManager; -use Claroline\CoreBundle\Manager\WorkspaceManager; +use Claroline\CoreBundle\Manager\GroupManager; +use Claroline\CoreBundle\Manager\RoleManager; +use Claroline\CoreBundle\Manager\AuthenticationManager; +use Claroline\CoreBundle\Manager\ProfilePropertyManager; use JMS\DiExtraBundle\Annotation as DI; -use JMS\SecurityExtraBundle\Annotation as SEC; -use Sensio\Bundle\FrameworkExtraBundle\Configuration as EXT; use Symfony\Bundle\FrameworkBundle\Controller\Controller; use Symfony\Component\Form\FormFactory; -use Symfony\Component\HttpFoundation\JsonResponse; -use Symfony\Component\HttpFoundation\RedirectResponse; use Symfony\Component\HttpFoundation\Request; -use Symfony\Component\HttpFoundation\Response; -use Symfony\Component\HttpFoundation\StreamedResponse; -use Symfony\Component\Security\Core\Exception\AccessDeniedException; -use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface; use Claroline\CoreBundle\Persistence\ObjectManager; class UserController extends FOSRestController @@ -47,50 +35,40 @@ class UserController extends FOSRestController /** * @DI\InjectParams({ * "authenticationManager" = @DI\Inject("claroline.common.authentication_manager"), - * "configHandler" = @DI\Inject("claroline.config.platform_config_handler"), * "formFactory" = @DI\Inject("form.factory"), * "localeManager" = @DI\Inject("claroline.common.locale_manager"), - * "mailManager" = @DI\Inject("claroline.manager.mail_manager"), * "request" = @DI\Inject("request"), - * "rightsManager" = @DI\Inject("claroline.manager.rights_manager"), * "roleManager" = @DI\Inject("claroline.manager.role_manager"), - * "toolManager" = @DI\Inject("claroline.manager.tool_manager"), - * "toolMaskDecoderManager" = @DI\Inject("claroline.manager.tool_mask_decoder_manager"), * "userManager" = @DI\Inject("claroline.manager.user_manager"), - * "workspaceManager" = @DI\Inject("claroline.manager.workspace_manager"), - * "om" = @DI\Inject("claroline.persistence.object_manager") + * "groupManager" = @DI\Inject("claroline.manager.group_manager"), + * "om" = @DI\Inject("claroline.persistence.object_manager"), + * "profilePropertyManager" = @DI\Inject("claroline.manager.profile_property_manager") * }) */ public function __construct( AuthenticationManager $authenticationManager, FormFactory $formFactory, LocaleManager $localeManager, - MailManager $mailManager, - PlatformConfigurationHandler $configHandler, Request $request, - RightsManager $rightsManager, - RoleManager $roleManager, - ToolManager $toolManager, - ToolMaskDecoderManager $toolMaskDecoderManager, UserManager $userManager, - WorkspaceManager $workspaceManager, - ObjectManager $om + GroupManager $groupManager, + RoleManager $roleManager, + ObjectManager $om, + ProfilePropertyManager $profilePropertyManager ) { $this->authenticationManager = $authenticationManager; - $this->configHandler = $configHandler; $this->formFactory = $formFactory; $this->localeManager = $localeManager; - $this->mailManager = $mailManager; $this->request = $request; - $this->rightsManager = $rightsManager; - $this->roleManager = $roleManager; - $this->toolManager = $toolManager; - $this->toolMaskDecoderManager = $toolMaskDecoderManager; - $this->userAdminTool = $this->toolManager->getAdminToolByName('user_management'); $this->userManager = $userManager; - $this->workspaceManager = $workspaceManager; + $this->groupManager = $groupManager; + $this->roleManager = $roleManager; $this->om = $om; + $this->userRepo = $om->getRepository('ClarolineCoreBundle:User'); + $this->roleRepo = $om->getRepository('ClarolineCoreBundle:Role'); + $this->groupRepo = $om->getRepository('ClarolineCoreBundle:Group'); + $this->profilePropertyManager = $profilePropertyManager; } /** @@ -101,7 +79,12 @@ public function getUsersAction() return $this->userManager->getAll(); } - public function putUserAction() + /** + * @View(serializerGroups={"api"}) + * profile_form_creation[fieldname] for the put request + * profile_form_creation[platformRoles][] // for the list of roles + */ + public function postUserAction() { $roleUser = $this->roleManager->getRoleByName('ROLE_USER'); @@ -111,38 +94,122 @@ public function putUserAction() true, $this->authenticationManager->getDrivers() ); + $profileType->enableApi(); $form = $this->formFactory->create($profileType); - $form->handleRequest($this->request); - $roles = $form->get('platformRoles')->getData(); - $unavailableRoles = $this->roleManager->validateNewUserRolesInsert($roles); + $form->submit($this->request); + //$form->handleRequest($this->request); - if ($form->isValid() && count($unavailableRoles) === 0) { + if ($form->isValid()) { + $roles = $form->get('platformRoles')->getData(); $user = $form->getData(); $this->userManager->createUser($user, true, $roles); - return $this->redirect($this->generateUrl('claro_admin_user_list')); + return $user; } - return array( - 'form_complete_user' => $form->createView(), - 'error' => $error, - 'unavailableRoles' => $unavailableRoles, - ); + return $form; } /** * @View(serializerGroups={"api"}) + * profile_form[fieldname] for the put request + * profile_form[platformRoles][] // for the list of roles */ - public function getUserAction($slug) + public function putUserAction(User $user) { - $user = $this->userManager->getUserByUsername($slug); + $roles = $this->roleManager->getPlatformRoles($user); + $accesses = $this->profilePropertyManager->getAccessessByRoles(array('ROLE_ADMIN')); + $formType = new ProfileType( + $this->localeManager, + $roles, + true, + true, + $accesses, + $this->authenticationManager->getDrivers() + ); + + $formType->enableApi(); + $userRole = $this->roleManager->getUserRoleByUser($user); + $form = $this->formFactory->create($formType, $user); + $form->submit($this->request); + //$form->handleRequest($this->request); + + if ($form->isValid()) { + $user = $form->getData(); + $this->roleManager->renameUserRole($userRole, $user->getUsername()); + $this->userManager->rename($user, $user->getUsername()); + + if (isset($form['platformRoles'])) { + //verification: + //only the admin can grant the role admin + //simple users cannot change anything. Don't let them put whatever they want with a fake form. + $newRoles = $form['platformRoles']->getData(); + $this->userManager->setPlatformRoles($user, $newRoles); + } + + return $user; + } + + return $form; + } + + /** + * @View(serializerGroups={"api"}) + */ + public function getUserAction(User $user) + { return $user; } - public function deleteUserAction($slug) + /** + * @View() + */ + public function deleteUserAction(User $user) + { + $this->userManager->deleteUser($user); + + return array('success'); + } + + /** + * @View() + */ + public function addUserRoleAction(User $user, Role $role) + { + $this->roleManager->associateRole($user, $role, false); + + return array('success'); + } + + /** + * @View() + */ + public function removeUserRoleAction(User $user, Role $role) + { + $this->roleManager->dissociateRole($user, $role); + + return array('success'); + } + + /** + * @View() + */ + public function addUserGroupAction(User $user, Group $group) + { + $this->groupManager->addUsersToGroup($group, array($user)); + + return array('success'); + } + + /** + * @View() + */ + public function removeUserGroupAction(User $user, Group $group) { + $this->groupManager->removeUsersFromGroup($group, array($user)); + return array('success'); } } diff --git a/Controller/API/WorkspaceController.php b/Controller/API/WorkspaceController.php new file mode 100644 index 000000000..6b00ae535 --- /dev/null +++ b/Controller/API/WorkspaceController.php @@ -0,0 +1,152 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Claroline\CoreBundle\Controller\API; + +use JMS\DiExtraBundle\Annotation as DI; +use Claroline\CoreBundle\Entity\Workspace\Workspace; +use Claroline\CoreBundle\Entity\User; +use FOS\RestBundle\Controller\FOSRestController; +use Claroline\CoreBundle\Persistence\ObjectManager; +use Claroline\CoreBundle\Manager\WorkspaceManager; +use Claroline\CoreBundle\Form\WorkspaceType; +use Symfony\Component\Form\FormFactory; +use Symfony\Component\HttpFoundation\Request; +use FOS\RestBundle\Controller\Annotations\View; +use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface; +use Claroline\CoreBundle\Library\Workspace\Configuration; + +class WorkspaceController extends FOSRestController +{ + + /** + * @DI\InjectParams({ + * "formFactory" = @DI\Inject("form.factory"), + * "workspaceManager" = @DI\Inject("claroline.manager.workspace_manager"), + * "request" = @DI\Inject("request"), + * "tokenStorage" = @DI\Inject("security.token_storage"), + * "templateDir" = @DI\Inject("%claroline.param.templates_directory%"), + * "om" = @DI\Inject("claroline.persistence.object_manager") + * }) + */ + public function __construct( + FormFactory $formFactory, + WorkspaceManager $workspaceManager, + ObjectManager $om, + Request $request, + TokenStorageInterface $tokenStorage, + $templateDir + ) + { + $this->formFactory = $formFactory; + $this->workspaceManager = $workspaceManager; + $this->om = $om; + $this->workspaceRepo = $this->om->getRepository('ClarolineCoreBundle:Workspace\Workspace'); + $this->request = $request; + $this->tokenStorage = $tokenStorage; + $this->templateDir = $templateDir; + } + + /** + * @View(serializerGroups={"api"}) + */ + public function getWorkspacesAction() + { + return $this->workspaceRepo->findAll(); + } + + /** + * @View(serializerGroups={"api"}) + */ + public function getWorkspaceAction(Workspace $workspace) + { + return $workspace; + } + + /** + * @View(serializerGroups={"api"}) + * group_form[workspace_form] for the put request + */ + public function postWorkspaceUserAction(User $user) + { + $workspaceType = new WorkspaceType($user); + $workspaceType->enableApi(); + $form = $this->formFactory->create($workspaceType); + $form->submit($this->request); + //$form->handleRequest($this->request); + + if ($form->isValid()) { + $config = Configuration::fromTemplate( + $this->templateDir . DIRECTORY_SEPARATOR . 'default.zip' + ); + $config->setWorkspaceName($form->get('name')->getData()); + $config->setWorkspaceCode($form->get('code')->getData()); + $config->setDisplayable($form->get('displayable')->getData()); + $config->setSelfRegistration($form->get('selfRegistration')->getData()); + $config->setRegistrationValidation($form->get('registrationValidation')->getData()); + $config->setSelfUnregistration($form->get('selfUnregistration')->getData()); + $config->setWorkspaceDescription($form->get('description')->getData()); + $workspace = $this->workspaceManager->create($config, $user); + $workspace->setEndDate($form->get('endDate')->getData()); + $workspace->setMaxStorageSize($form->get('maxStorageSize')->getData()); + $workspace->setMaxUploadResources($form->get('maxUploadResources')->getData()); + $workspace->setMaxUsers($form->get('maxUsers')->getData()); + + $this->workspaceManager->editWorkspace($workspace); + + return $workspace; + } + + return $form; + } + + /** + * @View() + */ + public function deleteWorkspaceAction(Workspace $workspace) + { + $this->workspaceManager->deleteWorkspace($workspace); + + return array('success'); + } + + /** + * @View(serializerGroups={"api"}) + * group_form[workspace_form] for the put request + */ + public function putWorkspaceUserAction(Workspace $workspace, User $user) + { + $workspaceType = new WorkspaceType($user); + $workspaceType->enableApi(); + $form = $this->formFactory->create($workspaceType, $workspace); + $form->submit($this->request); + + if ($form->isValid()) { + $workspace->setName($form->get('name')->getData()); + $workspace->setCode($form->get('code')->getData()); + $workspace->setDisplayable($form->get('displayable')->getData()); + $workspace->setSelfRegistration($form->get('selfRegistration')->getData()); + $workspace->setRegistrationValidation($form->get('registrationValidation')->getData()); + $workspace->setSelfUnregistration($form->get('selfUnregistration')->getData()); + $workspace->setDescription($form->get('description')->getData()); + $workspace->setEndDate($form->get('endDate')->getData()); + $workspace->setMaxStorageSize($form->get('maxStorageSize')->getData()); + $workspace->setMaxUploadResources($form->get('maxUploadResources')->getData()); + $workspace->setMaxUsers($form->get('maxUsers')->getData()); + + $this->workspaceManager->editWorkspace($workspace); + + return $workspace; + } + + return $form; + } +} diff --git a/Controller/Administration/GroupsController.php b/Controller/Administration/GroupsController.php index 912fefe0e..576552251 100644 --- a/Controller/Administration/GroupsController.php +++ b/Controller/Administration/GroupsController.php @@ -118,7 +118,6 @@ public function createAction() $userRole = $this->roleManager->getRoleByName('ROLE_USER'); $group->setPlatformRole($userRole); $this->groupManager->insertGroup($group); - $this->eventDispatcher->dispatch('log', 'Log\LogGroupCreate', array($group)); return $this->redirect($this->generateUrl('claro_admin_group_list')); } diff --git a/Entity/Group.php b/Entity/Group.php index 23543e9e8..bdeeb7040 100644 --- a/Entity/Group.php +++ b/Entity/Group.php @@ -18,6 +18,7 @@ use Claroline\CoreBundle\Entity\AbstractRoleSubject; use Claroline\CoreBundle\Entity\User; use Claroline\CoreBundle\Entity\Model\WorkspaceModel; +use JMS\Serializer\Annotation\Groups; /** * @ORM\Entity(repositoryClass="Claroline\CoreBundle\Repository\GroupRepository") @@ -35,12 +36,14 @@ class Group extends AbstractRoleSubject implements OrderableInterface * @ORM\Id * @ORM\Column(type="integer") * @ORM\GeneratedValue(strategy="AUTO") + * @Groups({"api"}) */ protected $id; /** * @ORM\Column() * @Assert\NotBlank() + * @Groups({"api"}) */ protected $name; diff --git a/Entity/Workspace/Workspace.php b/Entity/Workspace/Workspace.php index e2254db24..79c188ce6 100644 --- a/Entity/Workspace/Workspace.php +++ b/Entity/Workspace/Workspace.php @@ -16,6 +16,7 @@ use Doctrine\ORM\Mapping as ORM; use Symfony\Bridge\Doctrine\Validator\Constraints as DoctrineAssert; use Symfony\Component\Validator\Constraints as Assert; +use JMS\Serializer\Annotation\Groups; /** * @ORM\Entity(repositoryClass="Claroline\CoreBundle\Repository\WorkspaceRepository") @@ -37,43 +38,51 @@ class Workspace * @ORM\Id * @ORM\Column(type="integer") * @ORM\GeneratedValue(strategy="AUTO") + * @Groups({"api"}) */ protected $id; /** * @ORM\Column() * @Assert\NotBlank() + * @Groups({"api"}) */ protected $name; /** * @ORM\Column(type="text", nullable=true) + * @Groups({"api"}) */ protected $description; /** * @ORM\Column(unique=true) * @Assert\NotBlank() + * @Groups({"api"}) */ protected $code; /** * @ORM\Column(type="string", nullable=false) + * @Groups({"api"}) */ protected $maxStorageSize = "1 TB"; /** * @ORM\Column(type="integer", nullable=false) + * @Groups({"api"}) */ protected $maxUploadResources = 10000; /** * @ORM\Column(type="integer", nullable=false) + * @Groups({"api"}) */ protected $maxUsers = 10000; /** * @ORM\Column(type="boolean") + * @Groups({"api"}) */ protected $displayable = false; @@ -116,56 +125,67 @@ class Workspace * targetEntity="Claroline\CoreBundle\Entity\User" * ) * @ORM\JoinColumn(name="user_id", onDelete="SET NULL") + * @Groups({"api"}) */ protected $creator; /** * @ORM\Column(unique=true) + * @Groups({"api"}) */ protected $guid; /** * @ORM\Column(name="self_registration", type="boolean") + * @Groups({"api"}) */ protected $selfRegistration = false; /** * @ORM\Column(name="registration_validation", type="boolean") + * @Groups({"api"}) */ protected $registrationValidation = false; /** * @ORM\Column(name="self_unregistration", type="boolean") + * @Groups({"api"}) */ protected $selfUnregistration = false; /** * @ORM\Column(name="creation_date", type="integer", nullable=true) + * @Groups({"api"}) */ protected $creationDate; /** * @ORM\Column(name="is_personal", type="boolean") + * @Groups({"api"}) */ protected $isPersonal = false; /** * @ORM\Column(name="start_date", type="datetime", nullable=true) + * @Groups({"api"}) */ protected $startDate; /** * @ORM\Column(name="end_date", type="datetime", nullable=true) + * @Groups({"api"}) */ protected $endDate; /** * @ORM\Column(name="is_access_date", type="boolean") + * @Groups({"api"}) */ protected $isAccessDate = false; /** * @ORM\Column(name="workspace_type", type="integer", nullable=true) + * @Groups({"api"}) */ protected $workspaceType; diff --git a/Form/GroupType.php b/Form/GroupType.php index 901e61567..46f182f2d 100644 --- a/Form/GroupType.php +++ b/Form/GroupType.php @@ -14,12 +14,25 @@ use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\OptionsResolver\OptionsResolverInterface; +use Symfony\Component\Validator\Constraints\NotBlank; class GroupType extends AbstractType { + public function __construct() + { + $this->forApi = false; + } + public function buildForm(FormBuilderInterface $builder, array $options) { - $builder->add('name', 'text', array('label' => 'name')); + $builder->add( + 'name', + 'text', + array( + 'label' => 'name', + 'constraints' => new NotBlank() + ) + ); } public function getName() @@ -29,11 +42,14 @@ public function getName() public function setDefaultOptions(OptionsResolverInterface $resolver) { - $resolver - ->setDefaults( - array( - 'translation_domain' => 'platform' - ) - ); + $default = array('translation_domain' => 'platform'); + if ($this->forApi) $default['csrf_protection'] = false; + + $resolver->setDefaults($default); + } + + public function enableApi() + { + $this->forApi = true; } } diff --git a/Form/ProfileCreationType.php b/Form/ProfileCreationType.php index 98da92154..bb3fb0219 100644 --- a/Form/ProfileCreationType.php +++ b/Form/ProfileCreationType.php @@ -44,6 +44,7 @@ public function __construct( $this->langs = $localeManager->retrieveAvailableLocales(); $this->isAdmin = $isAdmin; $this->authenticationDrivers = $authenticationDrivers; + $this->forApi = false; } public function buildForm(FormBuilderInterface $builder, array $options) @@ -116,12 +117,18 @@ public function getName() public function setDefaultOptions(OptionsResolverInterface $resolver) { - $resolver->setDefaults( - array( - 'data_class' => 'Claroline\CoreBundle\Entity\User', - 'validation_groups' => array('registration', 'Default'), - 'translation_domain' => 'platform' - ) + $default = array( + 'data_class' => 'Claroline\CoreBundle\Entity\User', + 'validation_groups' => array('registration', 'Default'), + 'translation_domain' => 'platform' ); + if ($this->forApi) $default['csrf_protection'] = false; + + $resolver->setDefaults($default); + } + + public function enableApi() + { + $this->forApi = true; } } diff --git a/Form/ProfileType.php b/Form/ProfileType.php index 156d866a1..cc9d9db5b 100644 --- a/Form/ProfileType.php +++ b/Form/ProfileType.php @@ -50,6 +50,7 @@ public function __construct( $this->isGrantedUserAdministration = $isGrantedUserAdministration; $this->langs = $localeManager->retrieveAvailableLocales(); $this->authenticationDrivers = $authenticationDrivers; + $this->forApi = false; } public function buildForm(FormBuilderInterface $builder, array $options) @@ -167,11 +168,17 @@ public function getName() public function setDefaultOptions(OptionsResolverInterface $resolver) { - $resolver->setDefaults( - array( - 'data_class' => 'Claroline\CoreBundle\Entity\User', - 'translation_domain' => 'platform' - ) + $default = array( + 'data_class' => 'Claroline\CoreBundle\Entity\User', + 'translation_domain' => 'platform' ); + if ($this->forApi) $default['csrf_protection'] = false; + + $resolver->setDefaults($default); + } + + public function enableApi() + { + $this->forApi = true; } } diff --git a/Form/WorkspaceType.php b/Form/WorkspaceType.php index a1601ddc1..53cb4c810 100644 --- a/Form/WorkspaceType.php +++ b/Form/WorkspaceType.php @@ -17,6 +17,7 @@ use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\OptionsResolver\OptionsResolverInterface; +use Symfony\Component\Validator\Constraints\NotBlank; class WorkspaceType extends AbstractType { @@ -25,6 +26,7 @@ class WorkspaceType extends AbstractType public function __construct(User $user) { $this->user = $user; + $this->forApi = false; } public function buildForm(FormBuilderInterface $builder, array $options) @@ -32,40 +34,96 @@ public function buildForm(FormBuilderInterface $builder, array $options) $user = $this->user; $builder - ->add('name', 'text', array('label' => 'name')) + ->add( + 'name', + 'text', + array( + 'label' => 'name', + 'constraints' => new NotBlank() + ) + ) ->add( 'code', 'text', - array('constraints' => array(new WorkspaceUniqueCode()), 'label' => 'code') - )->add( + array( + 'constraints' => array(new WorkspaceUniqueCode(), new NotBlank()), + 'label' => 'code' + ) + ) + ->add( 'description', isset($options['theme_options']['tinymce']) && !$options['theme_options']['tinymce'] ? 'textarea' : 'tinymce', array('required' => false, 'label' => 'description') - ) - ->add( - 'model', - 'entity', - array( - 'class' => 'ClarolineCoreBundle:Model\WorkspaceModel', - 'query_builder' => function (EntityRepository $er) use ($user) { + ); + + if (!$this->forApi) { + $builder->add( + 'model', + 'entity', + array( + 'class' => 'ClarolineCoreBundle:Model\WorkspaceModel', + 'query_builder' => function (EntityRepository $er) use ($user) { + + return $er->createQueryBuilder('wm') + ->join('wm.users', 'u') + ->where('u.id = :userId') + ->setParameter('userId', $user->getId()) + ->orderBy('wm.name', 'ASC'); + }, + 'property' => 'nameAndWorkspace', + 'required' => false, + 'label' => 'model' + ) + ); + } + $builder + ->add('displayable', 'checkbox', array('required' => false, 'label' => 'displayable_in_workspace_list')) + ->add('selfRegistration', 'checkbox', array('required' => false, 'label' => 'public_registration')) + ->add('registrationValidation', 'checkbox', array('required' => false, 'label' => 'registration_validation')) + ->add('selfUnregistration', 'checkbox', array('required' => false, 'label' => 'public_unregistration')); - return $er->createQueryBuilder('wm') - ->join('wm.users', 'u') - ->where('u.id = :userId') - ->setParameter('userId', $user->getId()) - ->orderBy('wm.name', 'ASC'); - }, - 'property' => 'nameAndWorkspace', - 'required' => false, - 'label' => 'model' + if ($this->forApi) { + $builder->add( + 'maxStorageSize', + 'text', + array( + 'label' => 'max_storage_size', + 'constraints' => array(new NotBlank()) ) - ) - ->add('displayable', 'checkbox', array('required' => false, 'label' => 'displayable_in_workspace_list')) - ->add('selfRegistration', 'checkbox', array('required' => false, 'label' => 'public_registration')) - ->add('registrationValidation', 'checkbox', array('required' => false, 'label' => 'registration_validation')) - ->add('selfUnregistration', 'checkbox', array('required' => false, 'label' => 'public_unregistration')); + ); + $builder->add( + 'maxUploadResources', + 'text', + array( + 'label' => 'max_amount_resources', + 'constraints' => array(new NotBlank()) + ) + ); + $builder->add( + 'maxUsers', + 'text', + array( + 'label' => 'workspace_max_users', + 'constraints' => array(new NotBlank()) + ) + ); + $params = array( + 'label' => 'expiration_date', + 'format' => 'dd-MM-yyyy', + 'widget' => 'single_text', + 'input' => 'datetime', + 'attr' => array( + 'class' => 'datepicker input-small', + 'data-date-format' => 'dd-mm-yyyy', + 'autocomplete' => 'off' + ), + 'constraints' => array(new NotBlank()) + ); + + $builder->add('endDate', 'datepicker', $params); + } } public function getName() @@ -73,8 +131,16 @@ public function getName() return 'workspace_form'; } + public function enableApi() + { + $this->forApi = true; + } + public function setDefaultOptions(OptionsResolverInterface $resolver) { - $resolver->setDefaults(array('translation_domain' => 'platform')); + $default = array('translation_domain' => 'platform'); + if ($this->forApi) $default['csrf_protection'] = false; + + $resolver->setDefaults($default); } } diff --git a/Manager/GroupManager.php b/Manager/GroupManager.php index 6adcf9073..0ddc6c422 100644 --- a/Manager/GroupManager.php +++ b/Manager/GroupManager.php @@ -74,6 +74,7 @@ public function __construct( public function insertGroup(Group $group) { $this->om->persist($group); + $this->eventDispatcher->dispatch('log', 'Log\LogGroupCreate', array($group)); $this->om->flush(); } diff --git a/Resources/config/routing.yml b/Resources/config/routing.yml index c936631ee..8bbe635e3 100644 --- a/Resources/config/routing.yml +++ b/Resources/config/routing.yml @@ -286,6 +286,16 @@ claro_user_api: type: rest prefix: api +claro_workspace_api: + resource: "@ClarolineCoreBundle/Controller/API/WorkspaceController.php" + type: rest + prefix: api + +claro_group_api: + resource: "@ClarolineCoreBundle/Controller/API/GroupController.php" + type: rest + prefix: api + claro_contact: resource: "@ClarolineCoreBundle/Controller/ContactController.php" prefix: contact diff --git a/Resources/config/suggested/fos_rest.yml b/Resources/config/suggested/fos_rest.yml index e21a35594..c82d858df 100644 --- a/Resources/config/suggested/fos_rest.yml +++ b/Resources/config/suggested/fos_rest.yml @@ -1,6 +1,11 @@ +# app/config/config.yml fos_rest: + disable_csrf_role: true + param_fetcher_listener: true + body_listener: true + format_listener: true view: - view_response_listener: force + view_response_listener: 'force' format_listener: rules: priorities: ['json'] diff --git a/Resources/config/suggested/monolog_prod.yml b/Resources/config/suggested/monolog_prod.yml index c02b124c6..c434cb482 100644 --- a/Resources/config/suggested/monolog_prod.yml +++ b/Resources/config/suggested/monolog_prod.yml @@ -4,7 +4,7 @@ monolog: type: fingers_crossed action_level: error handler: nested - exculded_404s: + excluded_404s: - ^/bundles - ^/js - ^/uploads diff --git a/Resources/config/suggested/security.yml b/Resources/config/suggested/security.yml index f62e82bec..183a7d56d 100644 --- a/Resources/config/suggested/security.yml +++ b/Resources/config/suggested/security.yml @@ -28,8 +28,9 @@ security: use_referer: true anonymous: true - #api: - # pattern: ^/api + api: + pattern: ^/api + security: false # fos_oauth: true # stateless: true From f67661db657cdda3735e3dec7f3e4c7d31ad773f Mon Sep 17 00:00:00 2001 From: ngodfraind Date: Fri, 17 Jul 2015 11:21:16 +0200 Subject: [PATCH 04/24] Platform parameters can be edited trough the api --- Controller/API/ParametersController.php | 49 +++++++++++++++++++++++++ Resources/config/routing.yml | 6 +++ Resources/config/suggested/security.yml | 9 ++--- 3 files changed, 59 insertions(+), 5 deletions(-) create mode 100644 Controller/API/ParametersController.php diff --git a/Controller/API/ParametersController.php b/Controller/API/ParametersController.php new file mode 100644 index 000000000..f2a3dbc1c --- /dev/null +++ b/Controller/API/ParametersController.php @@ -0,0 +1,49 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Claroline\CoreBundle\Controller\API; + +use JMS\DiExtraBundle\Annotation as DI; +use Symfony\Component\HttpFoundation\Request; +use FOS\RestBundle\Controller\FOSRestController; +use FOS\RestBundle\Controller\Annotations\View; +use Claroline\CoreBundle\Library\Configuration\PlatformConfigurationHandler; + +class ParametersController extends FOSRestController +{ + private $request; + + /** + * @DI\InjectParams({ + * "request" = @DI\Inject("request"), + * "ch" = @DI\Inject("claroline.config.platform_config_handler") + * }) + */ + public function __construct(Request $request, PlatformConfigurationHandler $ch) + { + $this->request = $request; + $this->ch = $ch; + } + + /** + * @View() + */ + public function postParametersAction() + { + $data = $this->request->request; + + foreach ($data as $parameter => $value) { + $this->ch->setParameter($parameter, $value); + } + + return $data; + } +} diff --git a/Resources/config/routing.yml b/Resources/config/routing.yml index 8bbe635e3..acb8d3c8c 100644 --- a/Resources/config/routing.yml +++ b/Resources/config/routing.yml @@ -296,6 +296,12 @@ claro_group_api: type: rest prefix: api +claro_parameters_api: + resource: "@ClarolineCoreBundle/Controller/API/ParametersController.php" + type: rest + prefix: api + + claro_contact: resource: "@ClarolineCoreBundle/Controller/ContactController.php" prefix: contact diff --git a/Resources/config/suggested/security.yml b/Resources/config/suggested/security.yml index 183a7d56d..373228f38 100644 --- a/Resources/config/suggested/security.yml +++ b/Resources/config/suggested/security.yml @@ -28,11 +28,10 @@ security: use_referer: true anonymous: true - api: - pattern: ^/api - security: false - # fos_oauth: true - # stateless: true + #api: + #pattern: ^/api + #fos_oauth: true + #stateless: true main: pattern: ^/ From 9b7cf0ee1b6e53cdffb47fd3f384078056c1f811 Mon Sep 17 00:00:00 2001 From: ngodfraind Date: Fri, 17 Jul 2015 16:00:38 +0200 Subject: [PATCH 05/24] wip --- Manager/OauthManager.php | 6 ++++++ Resources/config/suggested/security.yml | 8 ++++---- Resources/public/js/administration/oauth.js | 10 ++++++++++ .../views/Administration/Oauth/list.html.twig | 16 ++++++++++++++++ 4 files changed, 36 insertions(+), 4 deletions(-) diff --git a/Manager/OauthManager.php b/Manager/OauthManager.php index d30ebf9c6..f74f7bf16 100644 --- a/Manager/OauthManager.php +++ b/Manager/OauthManager.php @@ -14,6 +14,7 @@ use JMS\DiExtraBundle\Annotation as DI; use Claroline\CoreBundle\Event\StrictDispatcher; use FOS\OAuthServerBundle\Entity\ClientManager; +use Claroline\CoreBundle\Entity\Oauth\Client; /** * @DI\Service("claroline.manager.oauth_manager", parent="fos_oauth_server.client_manager.default") @@ -24,4 +25,9 @@ public function findAllClients() { return $this->repository->findAll(); } + + public function connect(Client $client) + { + + } } diff --git a/Resources/config/suggested/security.yml b/Resources/config/suggested/security.yml index 373228f38..4eb83e951 100644 --- a/Resources/config/suggested/security.yml +++ b/Resources/config/suggested/security.yml @@ -28,10 +28,10 @@ security: use_referer: true anonymous: true - #api: - #pattern: ^/api - #fos_oauth: true - #stateless: true + api: + pattern: ^/api + fos_oauth: true + stateless: true main: pattern: ^/ diff --git a/Resources/public/js/administration/oauth.js b/Resources/public/js/administration/oauth.js index 4e263ed4e..07a2339b4 100644 --- a/Resources/public/js/administration/oauth.js +++ b/Resources/public/js/administration/oauth.js @@ -11,6 +11,7 @@ 'use strict'; var modal = window.Claroline.Modal; + var id = ''; var addClient = function() { window.location.reload(); @@ -25,6 +26,15 @@ var url = Routing.generate('claro_admin_oauth_form'); modal.displayForm(url, addClient, function(){}, 'form_client_creation'); }) + .on('click', '.show-client-btn', function(event) { + modal.simpleContainer('', $(event.target).attr('data-client-id') + '_' + $(event.target).attr('data-client-random')); + }) + .on('click', '.show-secret-btn', function(event) { + modal.simpleContainer('', $(event.target).attr('data-secret')); + }) + .on('click', '.show-refresh-btn', function(event) { + modal.simpleContainer('', $(event.target).attr('data-url')); + }) .on('click', '.delete-client-btn', function(event) { var clientid = $(event.target).attr('data-client-id'); diff --git a/Resources/views/Administration/Oauth/list.html.twig b/Resources/views/Administration/Oauth/list.html.twig index a2fb01e31..c808d9312 100644 --- a/Resources/views/Administration/Oauth/list.html.twig +++ b/Resources/views/Administration/Oauth/list.html.twig @@ -60,6 +60,22 @@ {{ client.getName() }}
+ + + + +
+ + +
+ +
+
+
+ + + + + + + + + + + {% for request in friendRequests %} + + + + + + + {% endfor %} + +
{{ 'host'|trans({}, 'platform') }} {{ 'name'|trans({}, 'platform') }}
+ {% if request.isActivated() %} + activated + {% else %} + not activated + {% endif %} + {{ request.getHost() }} {{ request.getName() }} +
+ + {% if request.isActivated() and request.getClarolineAccess() != null %} + + + {% endif %} +
+
+
+
+
+
+
+ +
+
+
+ + + + + + + + + + {% for pendingFriend in pendingFriends %} + + + + + + {% endfor %} + +
{{ 'host'|trans({}, 'platform') }} {{ 'ip'|trans({}, 'platform') }}
{{ pendingFriend.getHost() }} {{ pendingFriend.getName() }} +
+ + +
+
+
+
+
+
+ - + {% endblock %} {% block javascripts %} diff --git a/Resources/views/Administration/Oauth/requestFriendForm.html.twig b/Resources/views/Administration/Oauth/requestFriendForm.html.twig new file mode 100644 index 000000000..02e88ccbd --- /dev/null +++ b/Resources/views/Administration/Oauth/requestFriendForm.html.twig @@ -0,0 +1,22 @@ +{% extends "ClarolineCoreBundle:Administration\\Oauth:clientModalForm.html.twig" %} + +{% block header %} + {{ 'request_friend'|trans({}, 'platform') }} +{% endblock %} + +{% block form %} +
+ + +
+{% endblock %} From 8530ab6d10a4cdb636d596ded99573a00e5c4ff9 Mon Sep 17 00:00:00 2001 From: ngodfraind Date: Wed, 29 Jul 2015 15:58:54 +0200 Subject: [PATCH 24/24] removing useless exception --- Manager/OauthManager.php | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/Manager/OauthManager.php b/Manager/OauthManager.php index 44584c5c8..20d9c5a77 100644 --- a/Manager/OauthManager.php +++ b/Manager/OauthManager.php @@ -141,13 +141,14 @@ public function acceptFriendAction(PendingFriend $friend) '/secret/' . $client->getSecret() . '/name/' . $friend->getName(); $data = $this->curlManager->exec($url); - throw new \Exception($data); - if (!json_decode($data)) { $this->om->remove($client); - $this->om->flush(); + } else { + $this->om->remove($friend); } + $this->om->flush(); + return $client; }