diff --git a/docs/sections/application/index.md b/docs/sections/application/index.md index 4c720f2f6f0..2954459de8e 100644 --- a/docs/sections/application/index.md +++ b/docs/sections/application/index.md @@ -4,3 +4,21 @@ title: Application --- # Application + +## Components + +### Context + +### DataSource + +### Tool + +### Widget + +### Importer + +### Exporter + +### Planned Task + +### Template diff --git a/src/integration/big-blue-button/Controller/AdministrationController.php b/src/integration/big-blue-button/Controller/AdministrationController.php index 1d8423833fc..7c35048964f 100644 --- a/src/integration/big-blue-button/Controller/AdministrationController.php +++ b/src/integration/big-blue-button/Controller/AdministrationController.php @@ -18,6 +18,7 @@ use Claroline\BigBlueButtonBundle\Entity\Recording; use Claroline\BigBlueButtonBundle\Manager\BBBManager; use Claroline\CoreBundle\API\Serializer\Resource\AbstractResourceSerializer; +use Claroline\CoreBundle\Component\Context\AdministrationContext; use Claroline\CoreBundle\Library\Configuration\PlatformConfigurationHandler; use Claroline\CoreBundle\Manager\Tool\ToolManager; use Symfony\Component\HttpFoundation\JsonResponse; @@ -33,33 +34,14 @@ class AdministrationController { use RequestDecoderTrait; - /** @var AuthorizationCheckerInterface */ - private $authorization; - /** @var PlatformConfigurationHandler */ - private $config; - /** @var ObjectManager */ - private $om; - /** @var Crud */ - private $crud; - /** @var ToolManager */ - private $toolManager; - /** @var BBBManager */ - private $bbbManager; - public function __construct( - AuthorizationCheckerInterface $authorization, - PlatformConfigurationHandler $config, - ObjectManager $om, - Crud $crud, - ToolManager $toolManager, - BBBManager $bbbManager + private readonly AuthorizationCheckerInterface $authorization, + private readonly PlatformConfigurationHandler $config, + private readonly ObjectManager $om, + private readonly Crud $crud, + private readonly ToolManager $toolManager, + private readonly BBBManager $bbbManager ) { - $this->authorization = $authorization; - $this->config = $config; - $this->om = $om; - $this->crud = $crud; - $this->toolManager = $toolManager; - $this->bbbManager = $bbbManager; } /** @@ -153,9 +135,9 @@ public function deleteRecordingsAction(Request $request): JsonResponse return new JsonResponse(null, 204); } - private function checkAccess() + private function checkAccess(): void { - $integrationTool = $this->toolManager->getAdminToolByName('integration'); + $integrationTool = $this->toolManager->getOrderedTool('integration', AdministrationContext::getName()); if (is_null($integrationTool) || !$this->authorization->isGranted('OPEN', $integrationTool)) { throw new AccessDeniedException(); } diff --git a/src/integration/big-blue-button/Installation/ClarolineBigBlueButtonInstaller.php b/src/integration/big-blue-button/Installation/ClarolineBigBlueButtonInstaller.php index e457e3435bf..f8d8f92058a 100644 --- a/src/integration/big-blue-button/Installation/ClarolineBigBlueButtonInstaller.php +++ b/src/integration/big-blue-button/Installation/ClarolineBigBlueButtonInstaller.php @@ -6,4 +6,8 @@ class ClarolineBigBlueButtonInstaller extends AdditionalInstaller { + public function hasMigrations(): bool + { + return true; + } } diff --git a/src/integration/peertube/Installation/ClarolinePeerTubeInstaller.php b/src/integration/peertube/Installation/ClarolinePeerTubeInstaller.php index ffbabe7b52c..4963cf51c3d 100644 --- a/src/integration/peertube/Installation/ClarolinePeerTubeInstaller.php +++ b/src/integration/peertube/Installation/ClarolinePeerTubeInstaller.php @@ -6,4 +6,8 @@ class ClarolinePeerTubeInstaller extends AdditionalInstaller { + public function hasMigrations(): bool + { + return true; + } } diff --git a/src/integration/youtube/Installation/ClarolineYouTubeInstaller.php b/src/integration/youtube/Installation/ClarolineYouTubeInstaller.php index 3db145cdaab..eeea47fabef 100644 --- a/src/integration/youtube/Installation/ClarolineYouTubeInstaller.php +++ b/src/integration/youtube/Installation/ClarolineYouTubeInstaller.php @@ -6,4 +6,8 @@ class ClarolineYouTubeInstaller extends AdditionalInstaller { + public function hasMigrations(): bool + { + return true; + } } diff --git a/src/main/app/API/Crud.php b/src/main/app/API/Crud.php index 61f81ca7baa..e1d89d364b4 100644 --- a/src/main/app/API/Crud.php +++ b/src/main/app/API/Crud.php @@ -18,17 +18,17 @@ class Crud use PermissionCheckerTrait; /** @var string */ - const COLLECTION_ADD = 'add'; + public const COLLECTION_ADD = 'add'; /** @var string */ - const COLLECTION_REMOVE = 'remove'; + public const COLLECTION_REMOVE = 'remove'; /** @var string */ - const PROPERTY_SET = 'set'; + public const PROPERTY_SET = 'set'; // TODO : remove me. only for retro compatibility it should be always the case // but I don't know if it will break things if I do it now - const THROW_EXCEPTION = 'throw_exception'; + public const THROW_EXCEPTION = 'throw_exception'; - const NO_PERMISSIONS = 'NO_PERMISSIONS'; - const NO_VALIDATION = 'NO_VALIDATION'; + public const NO_PERMISSIONS = 'NO_PERMISSIONS'; + public const NO_VALIDATION = 'NO_VALIDATION'; /** @var ObjectManager */ private $om; @@ -98,12 +98,12 @@ public function get(string $class, $id, string $idProp = 'id', ?array $options = return $object; } - public function find(string $class, $data) + public function find(string $class, $data): ?object { return $this->om->getObject($data, $class, $this->schema->getIdentifiers($class)); } - public function list(string $class, array $query = [], array $options = []) + public function list(string $class, array $query = [], array $options = []): array { $results = $this->finder->searchEntities($class, $query); @@ -118,14 +118,14 @@ public function list(string $class, array $query = [], array $options = []) * Creates a new entry for `class` and populates it with `data`. * * @param mixed $classOrObject - the class of the entity to create or an instance of the entity - * @param mixed $data - the serialized data of the object to create + * @param array $data - the serialized data of the object to create * @param array $options - additional creation options * * @return object|array * * @throws InvalidDataException */ - public function create($classOrObject, $data, array $options = []) + public function create(mixed $classOrObject, array $data = [], array $options = []): mixed { if (is_string($classOrObject)) { // class name received @@ -133,7 +133,7 @@ public function create($classOrObject, $data, array $options = []) $object = new $classOrObject(); } else { // object instance received - $class = get_class($classOrObject); + $class = $this->getRealClass($classOrObject); $object = $classOrObject; } @@ -183,7 +183,7 @@ public function create($classOrObject, $data, array $options = []) * * @throws InvalidDataException */ - public function update($classOrObject, $data, array $options = []) + public function update(mixed $classOrObject, array $data, array $options = []): mixed { if (is_string($classOrObject)) { // class name received @@ -192,7 +192,7 @@ public function update($classOrObject, $data, array $options = []) $oldObject = $this->om->getObject($data, $class, $this->schema->getIdentifiers($class) ?? []) ?? new $class(); } else { // object instance received - $class = get_class($classOrObject); + $class = $this->getRealClass($classOrObject); $oldObject = $classOrObject; } @@ -237,7 +237,7 @@ public function update($classOrObject, $data, array $options = []) * @param object $object - the entity to delete * @param array $options - additional delete options */ - public function delete($object, array $options = []) + public function delete(mixed $object, array $options = []): void { if (!in_array(static::NO_PERMISSIONS, $options)) { $this->checkPermission('DELETE', $object, [], true); @@ -264,12 +264,12 @@ public function delete($object, array $options = []) * @param array $data - the list of entries to delete * @param array $options - additional delete options */ - public function deleteBulk(array $data, array $options = []) + public function deleteBulk(array $data, array $options = []): void { $this->om->startFlushSuite(); foreach ($data as $el) { - //get the element + // get the element $this->delete($el, $options); } @@ -285,7 +285,7 @@ public function deleteBulk(array $data, array $options = []) * * @return object */ - public function copy($object, array $options = [], array $extra = []) + public function copy(mixed $object, array $options = [], array $extra = []): mixed { if (!in_array(static::NO_PERMISSIONS, $options)) { $this->checkPermission('COPY', $object, [], true); @@ -308,7 +308,7 @@ public function copy($object, array $options = [], array $extra = []) $this->om->persist($new); - //first event is the pre one + // first event is the pre one if ($this->dispatch('copy', 'pre', [$object, $options, $new, $extra])) { if (!in_array(Options::FORCE_FLUSH, $options)) { $this->om->flush(); @@ -327,16 +327,14 @@ public function copy($object, array $options = [], array $extra = []) * * @param array $data - the list of entries to copy * @param array $options - additional copy options - * - * @return array */ - public function copyBulk(array $data, array $options = []) + public function copyBulk(array $data, array $options = []): array { $this->om->startFlushSuite(); $copies = []; foreach ($data as $el) { - //get the element + // get the element $copies[] = $this->copy($el, $options); } @@ -357,7 +355,7 @@ public function copyBulk(array $data, array $options = []) * @todo only flush once (do not flush for each collection element) * @todo only dispatch lifecycle events once with the full collection in param */ - public function patch($object, string $property, string $action, array $elements, array $options = []) + public function patch(mixed $object, string $property, string $action, array $elements, array $options = []): mixed { $methodName = $action.ucfirst(strtolower($property)); @@ -408,7 +406,7 @@ public function patch($object, string $property, string $action, array $elements * * @deprecated should use standard update instead */ - public function replace($object, string $property, $data, array $options = []) + public function replace(mixed $object, string $property, mixed $data, array $options = []): mixed { $methodName = 'set'.ucfirst($property); @@ -417,9 +415,9 @@ public function replace($object, string $property, $data, array $options = []) } if (!in_array(static::NO_PERMISSIONS, $options)) { - //add the options to pass on here + // add the options to pass on here $this->checkPermission('PATCH', $object, [], true); - //we'll need to pass the $action and $data here aswell later + // we'll need to pass the $action and $data here aswell later } if ($this->dispatch('patch', 'pre', [$object, $options, $property, $data, self::PROPERTY_SET])) { @@ -442,28 +440,24 @@ public function replace($object, string $property, $data, array $options = []) * Validates `data` with the available validator for `class`. * * @param string $class - the class of the entity used for validation - * @param mixed $data - the serialized data to validate + * @param array $data - the serialized data to validate * @param string $mode - the validation mode * @param array $options - the validation options - * - * @return array */ - public function validate($class, $data, $mode, array $options = []) + public function validate(mixed $class, array $data, string $mode, array $options = []): array { return $this->validator->validate($class, $data, $mode, true, $options); } /** - * We dispatch 2 events: a generic one and an other with a custom name. + * We dispatch 2 events: a generic one and another with a custom name. * Listen to what you want. Both have their uses. * * @param string $action (create, copy, delete, patch, update) * @param string $when (post, pre) * @param array $args the event arguments - * - * @return bool */ - public function dispatch($action, $when, array $args) + public function dispatch(string $action, string $when, array $args): bool { $className = $this->getRealClass($args[0]); @@ -500,7 +494,7 @@ public static function getEventName(string $action, string $when, string $classN return $name; } - private function getRealClass($object) + private function getRealClass($object): string { return $this->om->getMetadataFactory()->getMetadataFor(get_class($object))->getName(); } diff --git a/src/main/app/Component/AbstractComponentProvider.php b/src/main/app/Component/AbstractComponentProvider.php index 0f6f934ed68..e4dbfc066e6 100644 --- a/src/main/app/Component/AbstractComponentProvider.php +++ b/src/main/app/Component/AbstractComponentProvider.php @@ -8,12 +8,12 @@ public function getComponent(string $componentName): ComponentInterface { $components = $this->getRegisteredComponents(); foreach ($components as $component) { - if ($component->getShortName() === $componentName) { + if ($component::getName() === $componentName) { return $component; } } - throw new \Exception(sprintf('Component %s can not be found. Maybe its plugin is disabled or the component service does not have the correct tag.', $componentName)); + throw new \Exception(sprintf('Component %s can not be found. Maybe its plugin is disabled or the component service does not have the correct tag (expected tag : %s).', $componentName, static::getServiceTag())); } abstract protected function getRegisteredComponents(): iterable; diff --git a/src/main/app/Component/ComponentInterface.php b/src/main/app/Component/ComponentInterface.php index b1345849190..002badb4fd9 100644 --- a/src/main/app/Component/ComponentInterface.php +++ b/src/main/app/Component/ComponentInterface.php @@ -7,5 +7,5 @@ */ interface ComponentInterface { - public static function getShortName(): string; + public static function getName(): string; } diff --git a/src/main/app/Component/ConfigurableInterface.php b/src/main/app/Component/ConfigurableInterface.php deleted file mode 100644 index d50662b62f6..00000000000 --- a/src/main/app/Component/ConfigurableInterface.php +++ /dev/null @@ -1,12 +0,0 @@ -toolManager = $toolManager; + $this->toolProvider = $toolProvider; } - public function getTools(?string $contextId): array + public function getTools(?ContextSubjectInterface $contextSubject): array { - return $this->toolManager->getOrderedTools(static::getShortName(), $contextId); + return $this->toolProvider->getEnabledTools(static::getName(), $contextSubject); + } + + public function getShortcuts(?ContextSubjectInterface $contextSubject): array + { + // only supported by Workspace context atm + return []; + } + + public function getAdditionalData(?ContextSubjectInterface $contextSubject): array + { + return []; } } diff --git a/src/main/app/Component/Context/ContextInterface.php b/src/main/app/Component/Context/ContextInterface.php index 7566359d95f..d8ca5a5daf9 100644 --- a/src/main/app/Component/Context/ContextInterface.php +++ b/src/main/app/Component/Context/ContextInterface.php @@ -10,30 +10,30 @@ */ interface ContextInterface extends ComponentInterface { - public function getObject(?string $contextId): mixed; + public function getObject(?string $contextId): ?ContextSubjectInterface; - public function isAvailable(?string $contextId, TokenInterface $token): bool; + public function isAvailable(?string $contextId): bool; - public function isManager(?string $contextId, TokenInterface $token): bool; + public function isManager(TokenInterface $token, ?ContextSubjectInterface $contextSubject): bool; - public function isImpersonated(?string $contextId, TokenInterface $token): bool; + public function isImpersonated(TokenInterface $token, ?ContextSubjectInterface $contextSubject): bool; - public function getRoles(?string $contextId, TokenInterface $token): array; + public function getRoles(TokenInterface $token, ?ContextSubjectInterface $contextSubject): array; - public function getAccessErrors(?string $contextId, TokenInterface $token): array; + public function getAccessErrors(TokenInterface $token, ?ContextSubjectInterface $contextSubject): array; /** * Get additional data required by the context (ex. current user evaluation). */ - public function getAdditionalData(?string $contextId): array; + public function getAdditionalData(?ContextSubjectInterface $contextSubject): array; /** * Gets the list of tools enabled for the context. */ - public function getTools(?string $contextId): array; + public function getTools(?ContextSubjectInterface $contextSubject): array; /** * Gets the list of shortcuts for the context. */ - public function getShortcuts(?string $contextId): array; + public function getShortcuts(?ContextSubjectInterface $contextSubject): array; } diff --git a/src/main/app/Component/Context/ContextProvider.php b/src/main/app/Component/Context/ContextProvider.php index 2c645db7a6f..21abdb56870 100644 --- a/src/main/app/Component/Context/ContextProvider.php +++ b/src/main/app/Component/Context/ContextProvider.php @@ -6,7 +6,7 @@ // $wsContext = $this->contextManager->getContext(WorkspaceContext::class, $contextId); // $desktopContext = $this->contextManager->getContext(DesktopContext::class); -// $this->>toolManager->getTool(ResourcesTool::class, $wsContext); +// $this->toolManager->getTool(ResourcesTool::class, $wsContext); /** * Aggregates all the contexts defined in the Claroline app. @@ -38,4 +38,27 @@ protected function getRegisteredComponents(): iterable { return $this->registeredContexts; } + + public function getAvailableContexts(): array + { + $available = []; + foreach ($this->getRegisteredComponents() as $contextComponent) { + if ($contextComponent->isAvailable()) { + $available[] = $contextComponent; + } + } + + return $available; + } + + public function getContext(string $contextName, string $contextId = null): ContextInterface + { + /** @var ContextInterface $contextHandler */ + $contextHandler = $this->getComponent($contextName); + if (!$contextHandler->isAvailable($contextId)) { + throw new \RuntimeException(sprintf('Context "%s(%s)" is not available. Check %s::isAvailable() for more info.', $contextName, $contextId || '', get_class($contextHandler))); + } + + return $contextHandler; + } } diff --git a/src/main/app/Component/Context/ContextSubjectInterface.php b/src/main/app/Component/Context/ContextSubjectInterface.php index 879180bf17d..f99f46a2b88 100644 --- a/src/main/app/Component/Context/ContextSubjectInterface.php +++ b/src/main/app/Component/Context/ContextSubjectInterface.php @@ -4,5 +4,5 @@ interface ContextSubjectInterface { - public function getId(): string; + public function getContextIdentifier(): string; } diff --git a/src/main/app/Component/DataSource/DataSourceInterface.php b/src/main/app/Component/DataSource/DataSourceInterface.php index f119e525c4f..19b430a4383 100644 --- a/src/main/app/Component/DataSource/DataSourceInterface.php +++ b/src/main/app/Component/DataSource/DataSourceInterface.php @@ -3,10 +3,13 @@ namespace Claroline\AppBundle\Component\Tool; use Claroline\AppBundle\Component\ComponentInterface; +use Claroline\AppBundle\Component\Context\ContextSubjectInterface; use Claroline\AppBundle\Component\Context\ContextualInterface; use Claroline\CoreBundle\Event\DataSource\GetDataEvent; interface DataSourceInterface extends ComponentInterface, ContextualInterface { public function getData(GetDataEvent $event): void; + + public function configure(string $context, ContextSubjectInterface $contextSubject = null, array $configData = []): ?array; } diff --git a/src/main/app/Component/Resource/ResourceInterface.php b/src/main/app/Component/Resource/ResourceInterface.php new file mode 100644 index 00000000000..395b8f4256f --- /dev/null +++ b/src/main/app/Component/Resource/ResourceInterface.php @@ -0,0 +1,16 @@ +orderedToolRepo = $om->getRepository(OrderedTool::class); } final public static function getServiceTag(): string @@ -38,24 +40,64 @@ protected function getRegisteredComponents(): iterable return $this->registeredTools; } - public function open(string $toolName, string $context, string $contextId = null): array + public function getAvailableTools(string $context, ContextSubjectInterface $contextSubject = null): array + { + $available = []; + foreach ($this->getRegisteredComponents() as $toolComponent) { + if ($toolComponent->supportsContext($context) && (empty($contextSubject) || $toolComponent->supportsSubject($contextSubject))) { + $available[] = $toolComponent; + } + } + + return $available; + } + + public function getEnabledTools(string $context, ContextSubjectInterface $contextSubject = null): array + { + return $this->orderedToolRepo->findByContext($context, $contextSubject ? $contextSubject->getContextIdentifier() : null); + } + + public function isEnabled(string $toolName, string $context, ContextSubjectInterface $contextSubject = null): bool + { + return !empty($this->orderedToolRepo->findOneByNameAndContext($toolName, $context, $contextSubject ? $contextSubject->getContextIdentifier() : null)); + } + + public function getTool(string $toolName, string $context, ContextSubjectInterface $contextSubject = null): ?OrderedTool { - /** @var ToolInterface $tool */ - $tool = $this->getComponent($toolName); + /** @var ToolInterface $toolHandler */ + $toolHandler = $this->getComponent($toolName); + + if (!$toolHandler->supportsContext($context)) { + throw new \Exception(sprintf('Tool "%s" does not support the context "%s". Check %s::supportsContext() for more info.', $toolName, $context, get_class($toolHandler))); + } + + if ($contextSubject && !$toolHandler->supportsSubject($contextSubject)) { + throw new \RuntimeException(sprintf('Tool "%s" does not support the context "%s(%s)". Check %s::supportsSubject() for more info.', $toolName, $context, $contextSubject->getContextIdentifier(), get_class($toolHandler))); + } - if (!$tool->supportsContext($context)) { - throw new \Exception(sprintf('Tool "%s" does not support the context "%s". Check %s::supportsContext() for more info.', $toolName, $context, get_class($tool))); + $orderedTool = $this->orderedToolRepo->findOneByNameAndContext($toolName, $context, $contextSubject ? $contextSubject->getContextIdentifier() : null); + if (empty($orderedTool)) { + // tool is not enabled in the context + throw new \RuntimeException(sprintf('Tool "%s" is not enabled for the context "%s(%s)".', $toolName, $context, $contextSubject ? $contextSubject->getContextIdentifier() : '')); } - // dispatch open event - $openEvent = new OpenToolEvent($toolName, $context, null, $this->securityManager->getCurrentUser()); - $this->eventDispatcher->dispatch($openEvent, ToolEvents::OPEN); + return $orderedTool; + } - return $openEvent->getResponse() ?? []; + public function open(string $toolName, string $context, ContextSubjectInterface $contextSubject = null): ?array + { + /** @var ToolInterface $toolHandler */ + $toolHandler = $this->getComponent($toolName); + + return $toolHandler->open($context, $contextSubject) ?? []; } - public function configure() + public function configure(string $toolName, string $context, ContextSubjectInterface $contextSubject = null, array $data = []): ?array { + /** @var ToolInterface $toolHandler */ + $toolHandler = $this->getComponent($toolName); + + return $toolHandler->configure($context, $contextSubject, $data) ?? []; } public function import() diff --git a/src/main/core/Controller/APINew/Context/ContextController.php b/src/main/app/Controller/Component/ContextController.php similarity index 81% rename from src/main/core/Controller/APINew/Context/ContextController.php rename to src/main/app/Controller/Component/ContextController.php index 7f537136331..d71d7733521 100644 --- a/src/main/core/Controller/APINew/Context/ContextController.php +++ b/src/main/app/Controller/Component/ContextController.php @@ -1,10 +1,9 @@ contextProvider->getComponent($context); + $contextHandler = $this->contextProvider->getContext($context, $contextId); } catch (\Exception $e) { throw new NotFoundHttpException($e->getMessage()); } - $isImpersonated = $contextHandler->isImpersonated($contextId, $this->tokenStorage->getToken()); - $isManager = $contextHandler->isManager($contextId, $this->tokenStorage->getToken()); - $accessErrors = $contextHandler->getAccessErrors($contextId, $this->tokenStorage->getToken()); - $contextObject = $contextHandler->getObject($contextId); - $contextRoles = $contextHandler->getRoles($contextId, $this->tokenStorage->getToken()); + + $contextRoles = $contextHandler->getRoles($this->tokenStorage->getToken(), $contextObject); + $isImpersonated = $contextHandler->isImpersonated($this->tokenStorage->getToken(), $contextObject); + $isManager = $contextHandler->isManager($this->tokenStorage->getToken(), $contextObject); + $accessErrors = $contextHandler->getAccessErrors($this->tokenStorage->getToken(), $contextObject); + + // $this->authorization->isGranted('OPEN', $contextObject) if (empty($accessErrors) || $isManager) { $openEvent = new OpenContextEvent($context, $contextId); @@ -73,11 +73,11 @@ public function openAction(string $context, string $contextId = null): JsonRespo // this will allow the ui to know if a user try to access a closed tool or a non-existent one. 'tools' => array_map(function (OrderedTool $orderedTool) { return $this->serializer->serialize($orderedTool, [SerializerInterface::SERIALIZE_MINIMAL]); - }, $contextHandler->getTools($contextId)), + }, $contextHandler->getTools($contextObject)), 'shortcuts' => array_map(function (Shortcuts $shortcuts) { return $this->serializer->serialize($shortcuts, [SerializerInterface::SERIALIZE_MINIMAL]); - }, $contextHandler->getShortcuts($contextId)), - ], $contextHandler->getAdditionalData($contextId))); + }, $contextHandler->getShortcuts($contextObject)), + ], $contextHandler->getAdditionalData($contextObject))); } // return the details of access errors to display it to users diff --git a/src/main/core/Controller/APINew/Context/ToolController.php b/src/main/app/Controller/Component/ToolController.php similarity index 59% rename from src/main/core/Controller/APINew/Context/ToolController.php rename to src/main/app/Controller/Component/ToolController.php index 3aece83e6f8..44885dfdbcf 100644 --- a/src/main/core/Controller/APINew/Context/ToolController.php +++ b/src/main/app/Controller/Component/ToolController.php @@ -9,22 +9,18 @@ * file that was distributed with this source code. */ -namespace Claroline\CoreBundle\Controller\APINew\Context; +namespace Claroline\AppBundle\Controller\Component; use Claroline\AppBundle\API\Crud; use Claroline\AppBundle\API\SerializerProvider; +use Claroline\AppBundle\Component\Context\ContextProvider; +use Claroline\AppBundle\Component\Tool\ToolProvider; use Claroline\AppBundle\Controller\RequestDecoderTrait; use Claroline\AppBundle\Persistence\ObjectManager; -use Claroline\CoreBundle\Entity\Tool\OrderedTool; -use Claroline\CoreBundle\Entity\Tool\Tool; use Claroline\CoreBundle\Entity\Tool\ToolRights; -use Claroline\CoreBundle\Entity\User; -use Claroline\CoreBundle\Entity\Workspace\Workspace; use Claroline\CoreBundle\Event\CatalogEvents\ToolEvents; use Claroline\CoreBundle\Event\Tool\ConfigureToolEvent; use Claroline\CoreBundle\Event\Tool\OpenToolEvent; -use Claroline\CoreBundle\Manager\LogConnectManager; -use Claroline\CoreBundle\Manager\Tool\ToolManager; use Symfony\Component\EventDispatcher\EventDispatcherInterface; use Symfony\Component\HttpFoundation\JsonResponse; use Symfony\Component\HttpFoundation\Request; @@ -48,8 +44,8 @@ public function __construct( private readonly EventDispatcherInterface $eventDispatcher, private readonly Crud $crud, private readonly SerializerProvider $serializer, - private readonly ToolManager $toolManager, - private readonly LogConnectManager $logConnectManager + private readonly ContextProvider $contextProvider, + private readonly ToolProvider $toolProvider ) { } @@ -60,40 +56,26 @@ public function __construct( */ public function openAction(string $name, string $context, string $contextId = null): JsonResponse { - $orderedTool = $this->toolManager->getOrderedTool($name, $context, $contextId); - if (!$orderedTool) { - throw new NotFoundHttpException(sprintf('Tool "%s" for context "%s" not found', $name, $context)); + try { + $contextHandler = $this->contextProvider->getContext($context, $contextId); + $contextSubject = $contextHandler->getObject($contextId); + + $orderedTool = $this->toolProvider->getTool($name, $context, $contextHandler->getObject($contextId)); + } catch (\Exception $e) { + throw new NotFoundHttpException($e->getMessage()); } if (!$this->authorization->isGranted('OPEN', $orderedTool)) { throw new AccessDeniedException(); } - $currentUser = $this->tokenStorage->getToken()->getUser(); - - $openEvent = new OpenToolEvent( - $name, - $context, - $orderedTool->getWorkspace(), - $currentUser instanceof User ? $currentUser : null, - ); - - // Dispatch a generic tool event to be able to listen to all tool opening at once - // (used by logs for example) - $this->eventDispatcher->dispatch( - $openEvent, - ToolEvents::OPEN - ); - - // Dispatch a specialized tool event (used to grab custom data required by the tool) - $this->eventDispatcher->dispatch( - $openEvent, - ToolEvents::getEventName(ToolEvents::OPEN, $context, $name) - ); - - return new JsonResponse(array_merge($openEvent->getData(), [ + // dispatch open event + $openEvent = new OpenToolEvent($name, $context, $contextSubject); + $this->eventDispatcher->dispatch($openEvent, ToolEvents::OPEN); + + return new JsonResponse(array_merge([], $openEvent->getResponse(), [ 'data' => $this->serializer->serialize($orderedTool), - ])); + ], $this->toolProvider->open($name, $context, $contextSubject))); } /** @@ -101,10 +83,13 @@ public function openAction(string $name, string $context, string $contextId = nu */ public function configureAction(Request $request, string $name, string $context, string $contextId = null): JsonResponse { - /** @var OrderedTool|null $orderedTool */ - $orderedTool = $this->toolManager->getOrderedTool($name, $context, $contextId); - if (!$orderedTool) { - throw new NotFoundHttpException(sprintf('Tool "%s" not found', $name)); + try { + $contextHandler = $this->contextProvider->getContext($context, $contextId); + $contextSubject = $contextHandler->getObject($contextId); + + $orderedTool = $this->toolProvider->getTool($name, $context, $contextHandler->getObject($contextId)); + } catch (\Exception $e) { + throw new NotFoundHttpException($e->getMessage()); } if (!$this->authorization->isGranted('EDIT', $orderedTool)) { @@ -113,22 +98,14 @@ public function configureAction(Request $request, string $name, string $context, $data = $this->decodeRequest($request); - $this->crud->update(OrderedTool::class, $data, [Crud::THROW_EXCEPTION]); - - $contextObject = null; - if (Tool::WORKSPACE === $context) { - $contextObject = $this->om->getRepository(Workspace::class)->findOneBy(['uuid' => $contextId]); - } + $this->crud->update($orderedTool, $data, [Crud::THROW_EXCEPTION]); - /** @var ConfigureToolEvent $event */ - $event = $this->eventDispatcher->dispatch( - new ConfigureToolEvent($name, $context, $contextObject, $data), - ToolEvents::getEventName(ToolEvents::CONFIGURE, $context, $name) - ); + $configureEvent = new ConfigureToolEvent($name, $context, $contextSubject, $data); + $this->eventDispatcher->dispatch($configureEvent, ToolEvents::CONFIGURE); - return new JsonResponse(array_merge($event->getData(), [ + return new JsonResponse(array_merge($configureEvent->getData(), [ 'data' => $this->serializer->serialize($orderedTool), - ])); + ], $this->toolProvider->configure($name, $context, $contextSubject, $data))); } /** @@ -136,10 +113,12 @@ public function configureAction(Request $request, string $name, string $context, */ public function getRightsAction(string $name, string $context, string $contextId = null): JsonResponse { - /** @var OrderedTool|null $orderedTool */ - $orderedTool = $this->toolManager->getOrderedTool($name, $context, $contextId); - if (!$orderedTool) { - throw new NotFoundHttpException(sprintf('Tool "%s" not found', $name)); + try { + $contextHandler = $this->contextProvider->getContext($context, $contextId); + + $orderedTool = $this->toolProvider->getTool($name, $context, $contextHandler->getObject($contextId)); + } catch (\Exception $e) { + throw new NotFoundHttpException($e->getMessage()); } if (!$this->authorization->isGranted('ADMINISTRATE', $orderedTool)) { @@ -156,10 +135,12 @@ public function getRightsAction(string $name, string $context, string $contextId */ public function updateRightsAction(Request $request, string $name, string $context, string $contextId = null): JsonResponse { - /** @var OrderedTool|null $orderedTool */ - $orderedTool = $this->toolManager->getOrderedTool($name, $context, $contextId); - if (!$orderedTool) { - throw new NotFoundHttpException(sprintf('Tool "%s" not found', $name)); + try { + $contextHandler = $this->contextProvider->getContext($context, $contextId); + + $orderedTool = $this->toolProvider->getTool($name, $context, $contextHandler->getObject($contextId)); + } catch (\Exception $e) { + throw new NotFoundHttpException($e->getMessage()); } if (!$this->authorization->isGranted('ADMINISTRATE', $orderedTool)) { @@ -170,20 +151,22 @@ public function updateRightsAction(Request $request, string $name, string $conte $this->om->startFlushSuite(); - $existingRights = $orderedTool->getRights(); + $existingRights = $orderedTool->getRights()->toArray(); $roles = []; foreach ($requestData as $right) { if (!empty($right['id'])) { /** @var ToolRights $toolRights */ - $toolRights = $this->crud->update(ToolRights::class, array_merge($right, ['orderedToolId' => $orderedTool->getUuid()]), [Crud::THROW_EXCEPTION, Crud::NO_PERMISSIONS]); + $toolRights = $this->crud->update(ToolRights::class, $right, [Crud::THROW_EXCEPTION, Crud::NO_PERMISSIONS]); } else { /** @var ToolRights $toolRights */ - $toolRights = $this->crud->create(ToolRights::class, array_merge($right, ['orderedToolId' => $orderedTool->getUuid()]), [Crud::THROW_EXCEPTION, Crud::NO_PERMISSIONS]); + $toolRights = $this->crud->create(ToolRights::class, $right, [Crud::THROW_EXCEPTION, Crud::NO_PERMISSIONS]); } + $orderedTool->addRight($toolRights); + // keep reference to the created/update rights, it will be used later to know the ones to delete. - // I don't use ToolRights id because there is a flush suite and it is not already generated. + // I don't use ToolRights id because there is a flush suite, and it is not already generated. $roles[] = $toolRights->getRole()->getName(); } diff --git a/src/main/app/Controller/Platform/LocaleController.php b/src/main/app/Controller/Platform/LocaleController.php deleted file mode 100644 index bb22eba23c5..00000000000 --- a/src/main/app/Controller/Platform/LocaleController.php +++ /dev/null @@ -1,73 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Claroline\AppBundle\Controller\Platform; - -use Claroline\CoreBundle\Entity\User; -use Claroline\CoreBundle\Manager\LocaleManager; -use Symfony\Component\HttpFoundation\JsonResponse; -use Symfony\Component\HttpFoundation\RedirectResponse; -use Symfony\Component\HttpFoundation\Request; -use Symfony\Component\Routing\Annotation\Route; -use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface; - -/** - * Manages platform locales. - * - * @Route("/locale") - */ -class LocaleController -{ - /** @var LocaleManager */ - private $localeManager; - /** @var TokenStorageInterface */ - private $tokenStorage; - - public function __construct( - LocaleManager $localeManager, - TokenStorageInterface $tokenStorage - ) { - $this->localeManager = $localeManager; - $this->tokenStorage = $tokenStorage; - } - - /** - * List platform locales. - * - * @Route("/", name="apiv2_locale_list", methods={"GET"}) - */ - public function listAction(): JsonResponse - { - return new JsonResponse( - $this->localeManager->getLocales() - ); - } - - /** - * Change locale. - * - * @Route("/{locale}", name="claroline_locale_change") - */ - public function changeAction(Request $request, string $locale): RedirectResponse - { - $user = $this->tokenStorage->getToken()->getUser(); - if ($user instanceof User) { - $this->localeManager->setUserLocale($locale); - } - - $request->setLocale($locale); - $request->getSession()->set('_locale', $locale); - - return new RedirectResponse( - $request->headers->get('referer') - ); - } -} diff --git a/src/main/app/Controller/Platform/ClientController.php b/src/main/app/Controller/PlatformController.php similarity index 85% rename from src/main/app/Controller/Platform/ClientController.php rename to src/main/app/Controller/PlatformController.php index c26df28f634..9f5e1352bcf 100644 --- a/src/main/app/Controller/Platform/ClientController.php +++ b/src/main/app/Controller/PlatformController.php @@ -1,6 +1,6 @@ tokenStorage->getToken()->getUser(); + if ($user instanceof User) { + $this->localeManager->setUserLocale($locale); + } + + $request->setLocale($locale); + $request->getSession()->set('_locale', $locale); + + return new RedirectResponse( + $request->headers->get('referer') + ); + } + /** * Gets the javascript injected by the plugins if any. */ diff --git a/src/main/app/DependencyInjection/ClarolineAppExtension.php b/src/main/app/DependencyInjection/ClarolineAppExtension.php index ce48bad721b..1d0f6015b22 100644 --- a/src/main/app/DependencyInjection/ClarolineAppExtension.php +++ b/src/main/app/DependencyInjection/ClarolineAppExtension.php @@ -16,15 +16,9 @@ use Symfony\Component\DependencyInjection\Loader\YamlFileLoader; use Symfony\Component\HttpKernel\DependencyInjection\Extension; -/** - * Loads the core services configuration files. - */ class ClarolineAppExtension extends Extension { - /** - * {@inheritdoc} - */ - public function load(array $configs, ContainerBuilder $container) + public function load(array $configs, ContainerBuilder $container): void { $locator = new FileLocator(__DIR__.'/../Resources/config'); $loader = new YamlFileLoader($container, $locator); diff --git a/src/main/app/Entity/Address.php b/src/main/app/Entity/Address.php index d753b53b620..88920e25293 100644 --- a/src/main/app/Entity/Address.php +++ b/src/main/app/Entity/Address.php @@ -8,50 +8,35 @@ trait Address { /** * @ORM\Column(name="address_street1", nullable=true) - * - * @var string */ - protected $addressStreet1; + protected ?string $addressStreet1; /** * @ORM\Column(name="address_street2", nullable=true) - * - * @var string */ - protected $addressStreet2; + protected ?string $addressStreet2; /** * @ORM\Column(name="address_postal_code", nullable=true) - * - * @var string */ - protected $addressPostalCode; + protected ?string $addressPostalCode; /** * @ORM\Column(name="address_city", nullable=true) - * - * @var string */ - protected $addressCity; + protected ?string $addressCity; /** * @ORM\Column(name="address_state", nullable=true) - * - * @var string */ - protected $addressState; + protected ?string $addressState; /** * @ORM\Column(name="address_country", nullable=true) - * - * @var string */ - protected $addressCountry; + protected ?string $addressCountry; - /** - * @return string - */ - public function getAddress() + public function getAddress(): string { return trim(join(PHP_EOL, [ $this->addressStreet1 ?? '', @@ -63,98 +48,62 @@ public function getAddress() ])); } - /** - * @return string - */ - public function getAddressStreet1() + public function getAddressStreet1(): ?string { return $this->addressStreet1; } - /** - * @param string $addressStreet1 - */ - public function setAddressStreet1($addressStreet1) + public function setAddressStreet1(?string $addressStreet1): void { $this->addressStreet1 = $addressStreet1; } - /** - * @return string - */ - public function getAddressStreet2() + public function getAddressStreet2(): ?string { return $this->addressStreet2; } - /** - * @param string $addressStreet2 - */ - public function setAddressStreet2($addressStreet2) + public function setAddressStreet2(?string $addressStreet2): void { $this->addressStreet2 = $addressStreet2; } - /** - * @return string - */ - public function getAddressPostalCode() + public function getAddressPostalCode(): ?string { return $this->addressPostalCode; } - /** - * @param string $addressPostalCode - */ - public function setAddressPostalCode($addressPostalCode) + public function setAddressPostalCode(?string $addressPostalCode): void { $this->addressPostalCode = $addressPostalCode; } - /** - * @return string - */ - public function getAddressCity() + public function getAddressCity(): ?string { return $this->addressCity; } - /** - * @param string $addressCity - */ - public function setAddressCity($addressCity) + public function setAddressCity(?string $addressCity): void { $this->addressCity = $addressCity; } - /** - * @return string - */ - public function getAddressState() + public function getAddressState(): ?string { return $this->addressState; } - /** - * @param string $addressState - */ - public function setAddressState($addressState) + public function setAddressState(?string $addressState): void { $this->addressState = $addressState; } - /** - * @return string - */ - public function getAddressCountry() + public function getAddressCountry(): ?string { return $this->addressCountry; } - /** - * @param string $addressCountry - */ - public function setAddressCountry($addressCountry) + public function setAddressCountry(?string $addressCountry): void { $this->addressCountry = $addressCountry; } diff --git a/src/main/app/Entity/HasContext.php b/src/main/app/Entity/HasContext.php new file mode 100644 index 00000000000..54781606836 --- /dev/null +++ b/src/main/app/Entity/HasContext.php @@ -0,0 +1,38 @@ +contextName; + } + + public function setContextName(string $contextName): void + { + $this->contextName = $contextName; + } + + public function getContextId(): ?string + { + return $this->contextId; + } + + public function setContextId(?string $contextId): void + { + $this->contextId = $contextId; + } +} diff --git a/src/main/app/Event/StrictDispatcher.php b/src/main/app/Event/StrictDispatcher.php index 2f26e72fa82..501d74dd1d2 100644 --- a/src/main/app/Event/StrictDispatcher.php +++ b/src/main/app/Event/StrictDispatcher.php @@ -24,7 +24,7 @@ */ class StrictDispatcher { - /** @var EventDispatcher */ + /** @var EventDispatcherInterface */ private $eventDispatcher; public function __construct(EventDispatcherInterface $ed) diff --git a/src/main/app/Log/LoggableTrait.php b/src/main/app/Log/LoggableTrait.php index cd5a1807342..c1ee1e932cb 100644 --- a/src/main/app/Log/LoggableTrait.php +++ b/src/main/app/Log/LoggableTrait.php @@ -6,7 +6,7 @@ use Psr\Log\LogLevel; /** - * @todo : make compliant with Psr\Log\LoggerAwareTrait and Psr\Log\LoggerTrait. + * @deprecated use Psr\Log\LoggerAwareTrait */ trait LoggableTrait { diff --git a/src/main/app/Manager/CommandManager.php b/src/main/app/Manager/CommandManager.php deleted file mode 100644 index c140f19b8cd..00000000000 --- a/src/main/app/Manager/CommandManager.php +++ /dev/null @@ -1,22 +0,0 @@ -kernel); - $application->setAutoExit(false); - $application->run($input, $output); - } -} diff --git a/src/main/app/Manager/Component/AbstractComponentManager.php b/src/main/app/Manager/Component/AbstractComponentManager.php new file mode 100644 index 00000000000..1dd5ca54211 --- /dev/null +++ b/src/main/app/Manager/Component/AbstractComponentManager.php @@ -0,0 +1,22 @@ +getRegisteredComponents(); + foreach ($components as $component) { + if ($component::getName() === $componentName) { + return $component; + } + } + + throw new \Exception(sprintf('Component %s can not be found. Maybe its plugin is disabled or the component service does not have the correct tag (expected tag : %s).', $componentName, static::getServiceTag())); + } + + abstract protected function getRegisteredComponents(): iterable; +} diff --git a/src/main/app/Manager/Component/ComponentManagerInterface.php b/src/main/app/Manager/Component/ComponentManagerInterface.php new file mode 100644 index 00000000000..b6a41542da4 --- /dev/null +++ b/src/main/app/Manager/Component/ComponentManagerInterface.php @@ -0,0 +1,18 @@ + - } else { + } else if (isEmpty(this.props.tools)) { + CurrentComp = ( + + ) + }else { CurrentComp = ( + + +const ContextMenu = (props) => { + let actionPromise + if (props.actions && isArray(props.actions)) { + actionPromise = Promise.resolve(props.actions) + } else { + actionPromise = props.actions + } + + return ( + hasPermission('open', tool)) + .map(tool => ({ + name: tool.name, + icon: tool.icon, + path: props.basePath + '/' + tool.name, + order: get(tool, 'display.order'), + displayed: !get(tool, 'restrictions.hidden', false) + })) + } + actions={props.actions} + > + {props.children} + + {!isEmpty(props.shortcuts) && + { + return props.shortcuts + .map(shortcut => { + if ('tool' === shortcut.type) { + const tool = props.tools.find(tool => tool.name === shortcut.name) + if (tool) { + return { + name: tool.name, + type: LINK_BUTTON, + icon: `fa fa-fw fa-${tool.icon}`, + label: trans('open-tool', {tool: trans(tool.name, {}, 'tools')}, 'actions'), + target: props.basePath + '/' + tool.name + } + } + + } else { + return actions.find(action => action.name === shortcut.name) + } + }) + .filter(link => !!link) + })} + /> + } + + props.changeSection('tool')} + /> + + ) +} + +ContextMenu.propTypes = { + basePath: T.string, + title: T.string.isRequired, + backAction: T.shape(ActionTypes.propTypes), + actions: T.oneOfType([ + // a regular array of actions + T.arrayOf(T.shape( + ActionTypes.propTypes + )), + // a promise that will resolve a list of actions + T.shape( + PromisedActionTypes.propTypes + ) + ]), + + section: T.string, + + shortcuts: T.arrayOf(T.shape({ + type: T.oneOf(['tool', 'action']).isRequired, + name: T.string.isRequired + })), + tools: T.arrayOf(T.shape({ + icon: T.string.isRequired, + name: T.string.isRequired, + permissions: T.object + })), + children: T.node, + changeSection: T.func.isRequired +} + +ContextMenu.defaultProps = { + basePath: '', + actions: [], + shortcuts: [] +} + +export { + ContextMenu +} diff --git a/src/main/app/Resources/modules/context/containers/menu.jsx b/src/main/app/Resources/modules/context/containers/menu.jsx index e69de29bb2d..f43242e081c 100644 --- a/src/main/app/Resources/modules/context/containers/menu.jsx +++ b/src/main/app/Resources/modules/context/containers/menu.jsx @@ -0,0 +1,19 @@ +import {connect} from 'react-redux' + +import {ContextMenu as ContextMenuComponent} from '#/main/app/context/components/menu' +import {actions as menuActions, selectors as menuSelectors} from '#/main/app/layout/menu/store' + +const ContextMenu = connect( + (state) => ({ + section: menuSelectors.openedSection(state) + }), + (dispatch) => ({ + changeSection(section) { + dispatch(menuActions.changeSection(section)) + } + }) +)(ContextMenuComponent) + +export { + ContextMenu +} diff --git a/src/main/app/Resources/modules/contexts/account/components/context.jsx b/src/main/app/Resources/modules/contexts/account/components/context.jsx index 063fcf2ae18..ca841ff51cf 100644 --- a/src/main/app/Resources/modules/contexts/account/components/context.jsx +++ b/src/main/app/Resources/modules/contexts/account/components/context.jsx @@ -13,6 +13,7 @@ const AccountContext = (props) => {...props} parent="desktop" + name="account" title={trans('my_account')} diff --git a/src/main/app/Resources/modules/contexts/workspace/components/menu.jsx b/src/main/app/Resources/modules/contexts/workspace/components/menu.jsx index 6c10b46ba7b..77113679128 100644 --- a/src/main/app/Resources/modules/contexts/workspace/components/menu.jsx +++ b/src/main/app/Resources/modules/contexts/workspace/components/menu.jsx @@ -11,8 +11,6 @@ import {Toolbar} from '#/main/app/action/components/toolbar' import {LINK_BUTTON, URL_BUTTON} from '#/main/app/buttons' import {LiquidGauge} from '#/main/core/layout/gauge/components/liquid-gauge' -import {MenuMain} from '#/main/app/layout/menu/containers/main' -import {ToolMenu} from '#/main/core/tool/containers/menu' import {route as toolRoute} from '#/main/core/tool/routing' import {User as UserTypes} from '#/main/community/prop-types' import {constants as baseConstants} from '#/main/evaluation/constants' @@ -24,6 +22,7 @@ import {Workspace as WorkspaceTypes} from '#/main/core/workspace/prop-types' import {constants} from '#/main/core/workspace/constants' import {WorkspaceEvaluation as WorkspaceEvaluationTypes} from '#/main/evaluation/workspace/prop-types' import {constants as evalConstants} from '#/main/evaluation/workspace/constants' +import {ContextMenu} from '#/main/app/context/containers/menu' const WorkspaceImpersonation = (props) =>
@@ -101,16 +100,6 @@ WorkspaceProgression.propTypes = { ) } -const WorkspaceShortcuts = props => - - const WorkspaceMenu = (props) => { let workspaceActions if (!isEmpty(props.workspace)) { @@ -125,7 +114,8 @@ const WorkspaceMenu = (props) => { } return ( - { tools={props.tools // hide tools that can not be configured in models for now .filter(tool => !get(props.workspace, 'meta.model', false) || -1 !== constants.WORKSPACE_MODEL_TOOLS.indexOf(tool.name)) - .filter(tool => hasPermission('open', tool)) - .map(tool => ({ - name: tool.name, - icon: tool.icon, - path: workspaceRoute(props.workspace, tool.name), - order: get(tool, 'display.order'), - displayed: !get(tool, 'restrictions.hidden', false) - })) } actions={workspaceActions} + shortcuts={props.shortcuts} > {!props.impersonated && get(props.workspace, 'display.showProgression') && { workspace={props.workspace} /> } - - {!isEmpty(props.shortcuts) && - { - return props.shortcuts - .map(shortcut => { - if ('tool' === shortcut.type) { - const tool = props.tools.find(tool => tool.name === shortcut.name) - if (tool) { - return { - name: tool.name, - type: LINK_BUTTON, - icon: `fa fa-fw fa-${tool.icon}`, - label: trans('open-tool', {tool: trans(tool.name, {}, 'tools')}, 'actions'), - target: workspaceRoute(props.workspace, tool.name) - } - } - - } else { - return actions.find(action => action.name === shortcut.name) - } - }) - .filter(link => !!link) - })} - /> - } - - props.changeSection('tool')} - /> - + ) } @@ -225,7 +177,6 @@ WorkspaceMenu.propTypes = { name: T.string.isRequired, permissions: T.object })), - changeSection: T.func.isRequired, update: T.func.isRequired } diff --git a/src/main/app/Resources/modules/contexts/workspace/containers/menu.jsx b/src/main/app/Resources/modules/contexts/workspace/containers/menu.jsx index bd76a6ed6e3..a74d5a72dc0 100644 --- a/src/main/app/Resources/modules/contexts/workspace/containers/menu.jsx +++ b/src/main/app/Resources/modules/contexts/workspace/containers/menu.jsx @@ -3,7 +3,6 @@ import {connect} from 'react-redux' import {withRouter} from '#/main/app/router' import {selectors as securitySelectors} from '#/main/app/security/store' -import {actions as menuActions, selectors as menuSelectors} from '#/main/app/layout/menu/store' import {selectors as contextSelectors} from '#/main/app/context/store' import {WorkspaceMenu as WorkspaceMenuComponent} from '#/main/app/contexts/workspace/components/menu' @@ -16,7 +15,8 @@ const WorkspaceMenu = withRouter( impersonated: contextSelectors.impersonated(state), roles: contextSelectors.roles(state), workspace: contextSelectors.data(state), - section: menuSelectors.openedSection(state), + + basePath: contextSelectors.path(state), tools: contextSelectors.tools(state), shortcuts: contextSelectors.shortcuts(state), userEvaluation: selectors.userEvaluation(state) @@ -24,9 +24,6 @@ const WorkspaceMenu = withRouter( (dispatch) => ({ update(workspace) { dispatch(actions.reload(workspace)) - }, - changeSection(section) { - dispatch(menuActions.changeSection(section)) } }) )(WorkspaceMenuComponent) diff --git a/src/main/app/Security/Voter/AbstractVoter.php b/src/main/app/Security/Voter/AbstractVoter.php index ec558c5cfc1..c414e1fd30b 100644 --- a/src/main/app/Security/Voter/AbstractVoter.php +++ b/src/main/app/Security/Voter/AbstractVoter.php @@ -14,7 +14,6 @@ use Claroline\AppBundle\Persistence\ObjectManager; use Claroline\AppBundle\Security\ObjectCollection; use Claroline\AppBundle\Security\Voter\VoterInterface as ClarolineVoterInterface; -use Claroline\CoreBundle\Entity\Tool\AdminTool; use Claroline\CoreBundle\Entity\Tool\OrderedTool; use Claroline\CoreBundle\Entity\User; use Claroline\CoreBundle\Entity\Workspace\Workspace; @@ -59,7 +58,7 @@ public function vote(TokenInterface $token, $subject, array $attributes): int } } - //maybe abstain sometimes + // maybe abstain sometimes return VoterInterface::ACCESS_GRANTED; } @@ -76,9 +75,6 @@ protected function getObjectManager() /** * /!\ Try not to go infinite looping with this. Careful. * - * @param mixed $attributes - * @param mixed $object - * * @deprecated do it yourself ! */ protected function isGranted($attributes, $object = null): bool @@ -86,9 +82,6 @@ protected function isGranted($attributes, $object = null): bool return $this->security->isGranted($attributes, $object); } - /** - * @param mixed $object - */ private function supports($object): bool { return is_a($object, $this->getClass(), true) @@ -113,27 +106,26 @@ public function supportsAttribute(string $attribute): bool return in_array($attribute, $this->getSupportedActions()); } + /** + * @deprecated + */ protected function isToolGranted($permission, string $toolName, Workspace $workspace = null): bool { $orderedToolRepo = $this->getObjectManager()->getRepository(OrderedTool::class); - - if ($workspace) { - $orderedTool = $orderedToolRepo->findOneByNameAndWorkspace($toolName, $workspace); - } else { - $orderedTool = $orderedToolRepo->findOneByNameAndDesktop($toolName); - } + $orderedTool = $orderedToolRepo->findOneByNameAndContext($toolName, !empty($workspace) ? 'workspace' : 'desktop', $workspace); return $this->isGranted($permission, $orderedTool); } + /** + * @deprecated + */ protected function hasAdminToolAccess(TokenInterface $token, string $name): bool { - /** @var AdminTool $tool */ - $tool = $this->getObjectManager() - ->getRepository(AdminTool::class) - ->findOneBy(['name' => $name]); + $orderedToolRepo = $this->getObjectManager()->getRepository(OrderedTool::class); + $orderedTool = $orderedToolRepo->findOneByNameAndContext($name, 'administration'); - return $this->isGranted('OPEN', $tool); + return $this->isGranted('OPEN', $orderedTool); } /** @@ -161,7 +153,7 @@ public function checkPermission(TokenInterface $token, $object, array $attribute { $collection = isset($options['collection']) ? $options['collection'] : null; - //crud actions + // crud actions switch ($attributes[0]) { case self::VIEW: return $this->checkView($token, $object); case self::CREATE: return $this->checkCreation($token, $object); diff --git a/src/main/authentication/Component/Tool/AuthenticationTool.php b/src/main/authentication/Component/Tool/AuthenticationTool.php new file mode 100644 index 00000000000..e231bb2de26 --- /dev/null +++ b/src/main/authentication/Component/Tool/AuthenticationTool.php @@ -0,0 +1,55 @@ + $this->serializer->serialize( + $this->authenticationManager->getParameters() + ), + ]; + } + + return []; + } + + public function configure(string $context, ContextSubjectInterface $contextSubject = null, array $configData = []): ?array + { + return []; + } +} diff --git a/src/main/authentication/DependencyInjection/ClarolineAuthenticationExtension.php b/src/main/authentication/DependencyInjection/ClarolineAuthenticationExtension.php index 5481445ce47..f0c171d02b9 100644 --- a/src/main/authentication/DependencyInjection/ClarolineAuthenticationExtension.php +++ b/src/main/authentication/DependencyInjection/ClarolineAuthenticationExtension.php @@ -16,19 +16,14 @@ use Symfony\Component\DependencyInjection\Loader\YamlFileLoader; use Symfony\Component\HttpKernel\DependencyInjection\Extension; -/** - * Loads the authentication services configuration files. - */ class ClarolineAuthenticationExtension extends Extension { - /** - * {@inheritdoc} - */ - public function load(array $configs, ContainerBuilder $container) + public function load(array $configs, ContainerBuilder $container): void { $locator = new FileLocator(__DIR__.'/../Resources/config'); $loader = new YamlFileLoader($container, $locator); $loader->load('services.yml'); + $loader->load('components.yml'); } } diff --git a/src/main/authentication/Installation/ClarolineAuthenticationInstaller.php b/src/main/authentication/Installation/ClarolineAuthenticationInstaller.php index 0616764c03f..a35da049fd1 100644 --- a/src/main/authentication/Installation/ClarolineAuthenticationInstaller.php +++ b/src/main/authentication/Installation/ClarolineAuthenticationInstaller.php @@ -13,4 +13,9 @@ public static function getUpdaters(): array '14.0.0' => Updater140000::class, ]; } + + public function hasMigrations(): bool + { + return true; + } } diff --git a/src/main/authentication/Installation/Updater/Updater140000.php b/src/main/authentication/Installation/Updater/Updater140000.php index 930728b8b54..f361e6c4b07 100644 --- a/src/main/authentication/Installation/Updater/Updater140000.php +++ b/src/main/authentication/Installation/Updater/Updater140000.php @@ -22,7 +22,7 @@ public function __construct( public function postUpdate(): void { - $this->log('Update AuthenticationParameters ...'); + $this->logger->info('Update AuthenticationParameters ...'); $authenticationParameters = $this->authenticationManager->getParameters(); diff --git a/src/main/authentication/Resources/config/components.yml b/src/main/authentication/Resources/config/components.yml new file mode 100644 index 00000000000..cc128a70a3d --- /dev/null +++ b/src/main/authentication/Resources/config/components.yml @@ -0,0 +1,2 @@ +imports: + - { resource: components/tool.yml } diff --git a/src/main/authentication/Resources/config/components/tool.yml b/src/main/authentication/Resources/config/components/tool.yml new file mode 100644 index 00000000000..438ebe39f31 --- /dev/null +++ b/src/main/authentication/Resources/config/components/tool.yml @@ -0,0 +1,7 @@ +services: + Claroline\AuthenticationBundle\Component\Tool\AuthenticationTool: + parent: Claroline\AppBundle\Component\Tool\AbstractTool + tags: [ 'claroline.component.tool' ] + arguments: + - '@Claroline\AppBundle\API\SerializerProvider' + - '@Claroline\AuthenticationBundle\Manager\AuthenticationManager' diff --git a/src/main/authentication/Resources/config/services/subscriber.yml b/src/main/authentication/Resources/config/services/subscriber.yml index c6e27b75d58..c5616714fb1 100644 --- a/src/main/authentication/Resources/config/services/subscriber.yml +++ b/src/main/authentication/Resources/config/services/subscriber.yml @@ -10,10 +10,3 @@ services: - '@Claroline\CoreBundle\Library\Configuration\PlatformConfigurationHandler' - '@Claroline\AppBundle\API\SerializerProvider' - '@Claroline\AuthenticationBundle\Manager\AuthenticationManager' - - # Administration - Claroline\AuthenticationBundle\Subscriber\Administration\ParametersSubscriber: - tags: [ kernel.event_subscriber ] - arguments: - - '@Claroline\AppBundle\API\SerializerProvider' - - '@Claroline\AuthenticationBundle\Manager\AuthenticationManager' diff --git a/src/main/authentication/Resources/modules/account/tokens/components/main.jsx b/src/main/authentication/Resources/modules/account/authentication/components/tool.jsx similarity index 92% rename from src/main/authentication/Resources/modules/account/tokens/components/main.jsx rename to src/main/authentication/Resources/modules/account/authentication/components/tool.jsx index 77dc9c3b308..ea3372cbe35 100644 --- a/src/main/authentication/Resources/modules/account/tokens/components/main.jsx +++ b/src/main/authentication/Resources/modules/account/authentication/components/tool.jsx @@ -12,9 +12,9 @@ import {route} from '#/main/app/account/routing' import {MODAL_TOKEN_PARAMETERS} from '#/main/authentication/token/modals/parameters' import {TokenList} from '#/main/authentication/token/components/list' -import {selectors} from '#/main/authentication/account/tokens/store' +import {selectors} from '#/main/authentication/account/authentication/store' -const TokensMain = props => +const AuthenticationTool = props => -TokensMain.propTypes = { +AuthenticationTool.propTypes = { currentUser: T.shape( UserTypes.propTypes ).isRequired, @@ -75,5 +75,5 @@ TokensMain.propTypes = { } export { - TokensMain + AuthenticationTool } diff --git a/src/main/authentication/Resources/modules/account/tokens/containers/main.jsx b/src/main/authentication/Resources/modules/account/authentication/containers/tool.jsx similarity index 66% rename from src/main/authentication/Resources/modules/account/tokens/containers/main.jsx rename to src/main/authentication/Resources/modules/account/authentication/containers/tool.jsx index 09c91f9f194..283547292b7 100644 --- a/src/main/authentication/Resources/modules/account/tokens/containers/main.jsx +++ b/src/main/authentication/Resources/modules/account/authentication/containers/tool.jsx @@ -4,10 +4,10 @@ import {withReducer} from '#/main/app/store/components/withReducer' import {selectors as securitySelectors} from '#/main/app/security/store' import {actions as listActions} from '#/main/app/content/list/store' -import {reducer, selectors} from '#/main/authentication/account/tokens/store' -import {TokensMain as TokensMainComponent} from '#/main/authentication/account/tokens/components/main' +import {reducer, selectors} from '#/main/authentication/account/authentication/store' +import {AuthenticationTool as AuthenticationToolComponent} from '#/main/authentication/account/authentication/components/tool' -const TokensMain = withReducer(selectors.STORE_NAME, reducer)( +const AuthenticationTool = withReducer(selectors.STORE_NAME, reducer)( connect( (state) => ({ currentUser: securitySelectors.currentUser(state) @@ -17,9 +17,9 @@ const TokensMain = withReducer(selectors.STORE_NAME, reducer)( dispatch(listActions.invalidateData(selectors.STORE_NAME)) } }) - )(TokensMainComponent) + )(AuthenticationToolComponent) ) export { - TokensMain + AuthenticationTool } diff --git a/src/main/authentication/Resources/modules/account/authentication/index.js b/src/main/authentication/Resources/modules/account/authentication/index.js new file mode 100644 index 00000000000..0f9caf598e1 --- /dev/null +++ b/src/main/authentication/Resources/modules/account/authentication/index.js @@ -0,0 +1,8 @@ +import {AuthenticationTool} from '#/main/authentication/account/authentication/containers/tool' + +export default { + component: AuthenticationTool/*, + name: 'tokens', + icon: 'fa fa-fw fa-coins', + label: trans('tokens', {}, 'security')*/ +} diff --git a/src/main/authentication/Resources/modules/account/authentication/store/index.js b/src/main/authentication/Resources/modules/account/authentication/store/index.js new file mode 100644 index 00000000000..a69327fb471 --- /dev/null +++ b/src/main/authentication/Resources/modules/account/authentication/store/index.js @@ -0,0 +1,7 @@ +import {reducer} from '#/main/authentication/account/authentication/store/reducer' +import {selectors} from '#/main/authentication/account/authentication/store/selectors' + +export { + reducer, + selectors +} diff --git a/src/main/authentication/Resources/modules/account/tokens/store/reducer.js b/src/main/authentication/Resources/modules/account/authentication/store/reducer.js similarity index 50% rename from src/main/authentication/Resources/modules/account/tokens/store/reducer.js rename to src/main/authentication/Resources/modules/account/authentication/store/reducer.js index d36a5ac6133..ffe384681aa 100644 --- a/src/main/authentication/Resources/modules/account/tokens/store/reducer.js +++ b/src/main/authentication/Resources/modules/account/authentication/store/reducer.js @@ -1,7 +1,6 @@ -import {combineReducers} from '#/main/app/store/reducer' import {makeListReducer} from '#/main/app/content/list/store' -import {selectors} from '#/main/authentication/account/tokens/store/selectors' +import {selectors} from '#/main/authentication/account/authentication/store/selectors' const reducer = makeListReducer(selectors.STORE_NAME) diff --git a/src/main/authentication/Resources/modules/account/tokens/store/selectors.js b/src/main/authentication/Resources/modules/account/authentication/store/selectors.js similarity index 55% rename from src/main/authentication/Resources/modules/account/tokens/store/selectors.js rename to src/main/authentication/Resources/modules/account/authentication/store/selectors.js index dbe275e1af7..d8bd3f3cc69 100644 --- a/src/main/authentication/Resources/modules/account/tokens/store/selectors.js +++ b/src/main/authentication/Resources/modules/account/authentication/store/selectors.js @@ -1,5 +1,5 @@ -const STORE_NAME = 'accountTokens' +const STORE_NAME = 'authentication' export const selectors = { STORE_NAME diff --git a/src/main/authentication/Resources/modules/account/tokens/index.js b/src/main/authentication/Resources/modules/account/tokens/index.js deleted file mode 100644 index c1f5494dd53..00000000000 --- a/src/main/authentication/Resources/modules/account/tokens/index.js +++ /dev/null @@ -1,10 +0,0 @@ -import {trans} from '#/main/app/intl/translation' - -import {TokensMain} from '#/main/authentication/account/tokens/containers/main' - -export default { - name: 'tokens', - icon: 'fa fa-fw fa-coins', - label: trans('tokens', {}, 'security'), - component: TokensMain -} diff --git a/src/main/authentication/Resources/modules/account/tokens/store/index.js b/src/main/authentication/Resources/modules/account/tokens/store/index.js deleted file mode 100644 index 3319e109c41..00000000000 --- a/src/main/authentication/Resources/modules/account/tokens/store/index.js +++ /dev/null @@ -1,7 +0,0 @@ -import {reducer} from '#/main/authentication/account/tokens/store/reducer' -import {selectors} from '#/main/authentication/account/tokens/store/selectors' - -export { - reducer, - selectors -} diff --git a/src/main/authentication/Resources/modules/administration/authentication/components/menu.jsx b/src/main/authentication/Resources/modules/administration/authentication/components/menu.jsx new file mode 100644 index 00000000000..070daaef8ca --- /dev/null +++ b/src/main/authentication/Resources/modules/administration/authentication/components/menu.jsx @@ -0,0 +1,25 @@ +import React from 'react' +import {PropTypes as T} from 'prop-types' +import omit from 'lodash/omit' + +import {trans} from '#/main/app/intl/translation' +import {MenuSection} from '#/main/app/layout/menu/components/section' + +const AuthenticationMenu = (props) => + + +AuthenticationMenu.propTypes = { + path: T.string, + + // from menu + opened: T.bool.isRequired, + toggle: T.func.isRequired, + autoClose: T.func.isRequired +} + +export { + AuthenticationMenu +} diff --git a/src/main/authentication/Resources/modules/administration/authentication/components/tool.jsx b/src/main/authentication/Resources/modules/administration/authentication/components/tool.jsx index 1ed57d637c3..702e4341e05 100644 --- a/src/main/authentication/Resources/modules/administration/authentication/components/tool.jsx +++ b/src/main/authentication/Resources/modules/administration/authentication/components/tool.jsx @@ -5,6 +5,7 @@ import get from 'lodash/get' import {trans} from '#/main/app/intl/translation' import {LINK_BUTTON} from '#/main/app/buttons' import {FormData} from '#/main/app/content/form/containers/data' +import {ToolPage} from '#/main/core/tool/containers/page' import {selectors} from '#/main/authentication/administration/authentication/store/selectors' @@ -15,8 +16,8 @@ const displayPasswordValidation = (data) => get(data, 'password._forceComplexity || get(data, 'password.requireNumber') || get(data, 'password.requireSpecialChar') -const AuthenticationTool = (props) => { - return ( +const AuthenticationTool = (props) => + { } ]} /> - ) -} + AuthenticationTool.propTypes = { path: T.string.isRequired, diff --git a/src/main/authentication/Resources/modules/administration/authentication/index.js b/src/main/authentication/Resources/modules/administration/authentication/index.js new file mode 100644 index 00000000000..8ff1fd16607 --- /dev/null +++ b/src/main/authentication/Resources/modules/administration/authentication/index.js @@ -0,0 +1,9 @@ +import {reducer} from '#/main/authentication/administration/authentication/store' +import {AuthenticationTool} from '#/main/authentication/administration/authentication/containers/tool' +import {AuthenticationMenu} from '#/main/authentication/administration/authentication/components/menu' + +export default { + component: AuthenticationTool, + menu: AuthenticationMenu, + store: reducer +} diff --git a/src/main/authentication/Resources/modules/administration/authentication/store/selectors.js b/src/main/authentication/Resources/modules/administration/authentication/store/selectors.js index 045f40b4b0d..b0ca2e7f842 100644 --- a/src/main/authentication/Resources/modules/administration/authentication/store/selectors.js +++ b/src/main/authentication/Resources/modules/administration/authentication/store/selectors.js @@ -2,7 +2,7 @@ import {createSelector} from 'reselect' import {selectors as paramSelectors} from '#/main/core/administration/parameters/store/selectors' -const STORE_NAME = 'authenticationParameters' +const STORE_NAME = 'authentication' const FORM_NAME = paramSelectors.STORE_NAME+'.'+STORE_NAME const store = createSelector( diff --git a/src/main/authentication/Resources/modules/plugin.js b/src/main/authentication/Resources/modules/plugin.js index bd7efc95cdc..ca6041c3211 100644 --- a/src/main/authentication/Resources/modules/plugin.js +++ b/src/main/authentication/Resources/modules/plugin.js @@ -17,7 +17,11 @@ registry.add('ClarolineAuthenticationBundle', { * Provides current user Account sections. */ account: { - 'tokens': () => { return import(/* webpackChunkName: "authentication-account-tokens" */ '#/main/authentication/account/tokens') } + 'authentication': () => { return import(/* webpackChunkName: "authentication-account-authentication" */ '#/main/authentication/account/authentication') } + }, + + administration: { + 'authentication': () => { return import(/* webpackChunkName: "authentication-administration-authentication" */ '#/main/authentication/administration/authentication') } }, integration: { diff --git a/src/main/authentication/Subscriber/Administration/ParametersSubscriber.php b/src/main/authentication/Subscriber/Administration/ParametersSubscriber.php deleted file mode 100644 index e674c98a9b6..00000000000 --- a/src/main/authentication/Subscriber/Administration/ParametersSubscriber.php +++ /dev/null @@ -1,41 +0,0 @@ -serializer = $serializer; - $this->authenticationManager = $authenticationManager; - } - - public static function getSubscribedEvents(): array - { - return [ - ToolEvents::getEventName(ToolEvents::OPEN, Tool::ADMINISTRATION, static::NAME) => 'onOpen', - ]; - } - - public function onOpen(OpenToolEvent $event): void - { - $event->setData([ - 'authentication' => $this->serializer->serialize( - $this->authenticationManager->getParameters() - ), - ]); - } -} diff --git a/src/main/community/Component/Tool/CommunityTool.php b/src/main/community/Component/Tool/CommunityTool.php new file mode 100644 index 00000000000..e8ee8c1862f --- /dev/null +++ b/src/main/community/Component/Tool/CommunityTool.php @@ -0,0 +1,248 @@ +tokenStorage->getToken()->getUser() instanceof User && $context === WorkspaceContext::getName()) { + $userTeams = $this->teamManager->getTeamsByUserAndWorkspace($this->tokenStorage->getToken()->getUser(), $contextSubject); + } + + return [ + 'userTeams' => array_map(function (Team $team) { + return $this->serializer->serialize($team, [SerializerInterface::SERIALIZE_MINIMAL]); + }, $userTeams), + 'profile' => $this->profileSerializer->serialize(), + 'usersLimitReached' => $this->userManager->hasReachedLimit(), + // for retro compatibility : + // - in workspace tool, configuration is stored in the workspace entity + // - in desktop tool, configuration is stored in the platform options + // to remove when the community options get their own entity + 'parameters' => $contextSubject ? $this->getWorkspaceParameters($contextSubject) : $this->getDesktopParameters(), + ]; + } + + public function configure(string $context, ContextSubjectInterface $contextSubject = null, array $configData = []): ?array + { + if (isset($configData['parameters'])) { + if (!empty($contextSubject)) { + // configure workspace tool + $updatedParameters = $this->updateWorkspaceParameters($configData['parameters'], $contextSubject); + } else { + // configure desktop tool + $updatedParameters = $this->updateDesktopParameters($configData['parameters']); + } + + // send updated data to the caller + return [ + 'parameters' => $updatedParameters, + ]; + } + + return []; + } + + public function export(string $context, ContextSubjectInterface $contextSubject = null, FileBag $fileBag = null): ?array + { + if (WorkspaceContext::getName() !== $context) { + return []; + } + + $teams = $this->om->getRepository(Team::class)->findBy(['workspace' => $contextSubject]); + + return [ + 'teams' => array_map(function (Team $team) { + return $this->serializer->serialize($team); + }, $teams), + ]; + } + + public function import(string $context, ContextSubjectInterface $contextSubject = null, FileBag $fileBag = null, array $data = [], array $entities = []): ?array + { + if (WorkspaceContext::getName() !== $context) { + return []; + } + + if (empty($data['teams'])) { + return []; + } + + $this->om->startFlushSuite(); + + // import teams + foreach ($data['teams'] as $teamData) { + // correct relation to external entities + if (isset($teamData['workspace'])) { + unset($teamData['workspace']); + } + + if (!empty($teamData['directory']) && $entities[$teamData['directory']['id']]) { + $teamData['directory'] = [ + 'id' => $entities[$teamData['directory']['id']]->getUuid(), + ]; + } + + if (!empty($teamData['role']) && $entities[$teamData['role']['id']]) { + $teamData['role'] = [ + 'id' => $entities[$teamData['role']['id']]->getUuid(), + ]; + } + + if (!empty($teamData['managerRole']) && $entities[$teamData['managerRole']['id']]) { + $teamData['managerRole'] = [ + 'id' => $entities[$teamData['managerRole']['id']]->getUuid(), + ]; + } + + $team = new Team(); + $team->setWorkspace($contextSubject); + + $this->crud->create($team, $teamData, [Crud::NO_PERMISSIONS, Crud::NO_VALIDATION, Options::REFRESH_UUID]); + + $entities[$teamData['id']] = $team; + } + + $this->om->endFlushSuite(); + + return []; + } + + private function getWorkspaceParameters(Workspace $workspace): array + { + $parameters = $this->serializer->serialize($workspace); + + // only grab workspace props we want + return [ + 'registration' => $parameters['registration'], + ]; + } + + private function getDesktopParameters(): array + { + $parameters = $this->parametersSerializer->serialize(); + + // load default role entity for UI rendering + $defaultRoleName = ArrayUtils::get($parameters, 'registration.default_role') ?? PlatformRoles::USER; + $roleUser = $this->roleManager->getRoleByName($defaultRoleName); + if (empty($parameters['registration'])) { + $parameters['registration'] = []; + } + $parameters['registration']['default_role'] = $this->serializer->serialize($roleUser, [SerializerInterface::SERIALIZE_MINIMAL]); + + // only grab platform options we want + return [ + 'registration' => $parameters['registration'] ?? [], + 'authentication' => $parameters['authentication'] ?? [], + 'profile' => $parameters['profile'] ?? [], + 'community' => $parameters['community'] ?? [], + ]; + } + + private function updateDesktopParameters(array $parametersData): array + { + // only keep parameters linked to community to avoid exposing all the platform parameters here + $communityParameters = []; + if (isset($parametersData['registration'])) { + $communityParameters['registration'] = $parametersData['registration']; + + // only store default role name in platform options + if (!empty($parametersData['registration']['default_role'])) { + $communityParameters['registration']['default_role'] = $parametersData['registration']['default_role']['name']; + } + } + if (isset($parametersData['authentication'])) { + $communityParameters['authentication'] = $parametersData['authentication']; + } + if (isset($parametersData['profile'])) { + $communityParameters['profile'] = $parametersData['profile']; + } + if (isset($parametersData['community'])) { + $communityParameters['community'] = $parametersData['community']; + } + + // removes locked parameters values if any + $locked = $this->config->getParameter('lockedParameters') ?? []; + foreach ($locked as $lockedParam) { + ArrayUtils::remove($communityParameters, $lockedParam); + } + + // save updated parameters + $this->parametersSerializer->deserialize($communityParameters); + + return $this->parametersSerializer->serialize(); + } + + private function updateWorkspaceParameters(array $parametersData, Workspace $workspace): array + { + // only keep parameters linked to community to avoid exposing all the workspace parameters here + $communityParameters = []; + if (isset($parametersData['registration'])) { + $communityParameters['registration'] = $parametersData['registration']; + } + + $this->crud->update($workspace, $communityParameters, [Crud::THROW_EXCEPTION]); + + return $this->serializer->serialize($workspace); + } +} diff --git a/src/main/community/Component/Tool/ProfileTool.php b/src/main/community/Component/Tool/ProfileTool.php new file mode 100644 index 00000000000..4df8aae2dff --- /dev/null +++ b/src/main/community/Component/Tool/ProfileTool.php @@ -0,0 +1,35 @@ +checkToolAccess('SHOW_ACTIVITY', $contextId)) { throw new AccessDeniedException(); @@ -132,7 +130,7 @@ public function openAction(?string $contextId = null): JsonResponse /** * @Route("/global/{contextId}", name="apiv2_community_activity_global") */ - public function globalAction(Request $request, ?string $contextId = null): JsonResponse + public function globalAction(Request $request, string $contextId = null): JsonResponse { if (!$this->checkToolAccess('SHOW_ACTIVITY', $contextId)) { throw new AccessDeniedException(); @@ -154,7 +152,7 @@ public function globalAction(Request $request, ?string $contextId = null): JsonR /** * @Route("/logs/{contextId}", name="apiv2_community_activity_logs", methods={"GET"}) */ - public function listLogsAction(Request $request, ?string $contextId = null): JsonResponse + public function listLogsAction(Request $request, string $contextId = null): JsonResponse { if (!$this->checkToolAccess('SHOW_ACTIVITY', $contextId)) { throw new AccessDeniedException(); @@ -165,7 +163,7 @@ public function listLogsAction(Request $request, ?string $contextId = null): Jso ); } - private function checkToolAccess(string $rights = 'OPEN', ?string $contextId = null): bool + private function checkToolAccess(string $rights = 'OPEN', string $contextId = null): bool { if ($contextId) { $communityTool = $this->toolManager->getOrderedTool('community', Tool::WORKSPACE, $contextId); @@ -180,7 +178,7 @@ private function checkToolAccess(string $rights = 'OPEN', ?string $contextId = n return true; } - private function filterQuery(array $query, ?string $contextId = null): array + private function filterQuery(array $query, string $contextId = null): array { if ($contextId) { $workspace = $this->om->getRepository(Workspace::class)->findOneBy(['uuid' => $contextId]); diff --git a/src/main/community/Controller/RoleController.php b/src/main/community/Controller/RoleController.php index fe2290c86f5..24acd97c8aa 100644 --- a/src/main/community/Controller/RoleController.php +++ b/src/main/community/Controller/RoleController.php @@ -16,12 +16,6 @@ use Claroline\CoreBundle\Controller\APINew\Model\HasGroupsTrait; use Claroline\CoreBundle\Controller\APINew\Model\HasUsersTrait; use Claroline\CoreBundle\Entity\Role; -use Claroline\CoreBundle\Entity\Tool\AdminTool; -use Claroline\CoreBundle\Entity\Tool\OrderedTool; -use Claroline\CoreBundle\Entity\Tool\Tool; -use Claroline\CoreBundle\Entity\User; -use Claroline\CoreBundle\Entity\Workspace\Workspace; -use Claroline\CoreBundle\Manager\LogManager; use Claroline\CoreBundle\Manager\Tool\ToolManager; use Claroline\CoreBundle\Security\PermissionCheckerTrait; use Sensio\Bundle\FrameworkExtraBundle\Configuration as EXT; @@ -39,21 +33,11 @@ class RoleController extends AbstractCrudController use HasGroupsTrait; use PermissionCheckerTrait; - /** @var AuthorizationCheckerInterface */ - private $authorization; - /** @var ToolManager */ - private $toolManager; - /** @var LogManager */ - private $logManager; - public function __construct( AuthorizationCheckerInterface $authorization, - ToolManager $toolManager, - LogManager $logManager + private readonly ToolManager $toolManager ) { $this->authorization = $authorization; - $this->toolManager = $toolManager; - $this->logManager = $logManager; } public function getName(): string @@ -91,41 +75,18 @@ public function listAction(Request $request, $class): JsonResponse * Get a role rights for the given context. * * @Route("/{id}/rights/{contextType}/{contextId}", name="apiv2_role_rights_list", defaults={"contextId"=null}, methods={"GET"}) + * * @EXT\ParamConverter("role", options={"mapping": {"id": "uuid"}}) */ - public function listRightsAction(Role $role, string $contextType, ?string $contextId = null): JsonResponse + public function listRightsAction(Role $role, string $contextType, string $contextId = null): JsonResponse { $this->checkPermission('OPEN', $role, [], true); $rights = []; - switch ($contextType) { - case Tool::DESKTOP: - // get desktop tools - $orderedTools = $this->om->getRepository(OrderedTool::class)->findByDesktop(); - foreach ($orderedTools as $orderedTool) { - $rights[$orderedTool->getTool()->getName()] = $this->toolManager->getPermissions($orderedTool, $role); - } - - break; - case Tool::WORKSPACE: - // get workspace tools - $workspace = $this->om->getRepository(Workspace::class)->findOneBy(['uuid' => $contextId]); - $orderedTools = $this->om->getRepository(OrderedTool::class)->findByWorkspace($workspace); - foreach ($orderedTools as $orderedTool) { - $rights[$orderedTool->getTool()->getName()] = $this->toolManager->getPermissions($orderedTool, $role); - } - - break; - case Tool::ADMINISTRATION: - $adminTools = $this->om->getRepository(AdminTool::class)->findAll(); - foreach ($adminTools as $adminTool) { - $rights[$adminTool->getName()] = [ - 'open' => $role->getAdminTools()->contains($adminTool), - ]; - } - - break; + $orderedTools = $this->toolManager->getOrderedTools($contextType, $contextId); + foreach ($orderedTools as $orderedTool) { + $rights[$orderedTool->getName()] = $this->toolManager->getPermissions($orderedTool, $role); } return new JsonResponse($rights); @@ -135,9 +96,10 @@ public function listRightsAction(Role $role, string $contextType, ?string $conte * Manages workspace tools accesses for a Role. * * @Route("/{id}/rights/{contextType}/{contextId}", name="apiv2_role_rights_update", defaults={"contextId"=null}, methods={"PUT"}) + * * @EXT\ParamConverter("role", options={"mapping": {"id": "uuid"}}) */ - public function updateRightsAction(Request $request, Role $role, string $contextType, ?string $contextId = null): JsonResponse + public function updateRightsAction(Request $request, Role $role, string $contextType, string $contextId = null): JsonResponse { $this->checkPermission('ADMINISTRATE', $role, [], true); @@ -146,32 +108,11 @@ public function updateRightsAction(Request $request, Role $role, string $context if ($rightsData) { $this->om->startFlushSuite(); - switch ($contextType) { - case Tool::DESKTOP: - case Tool::WORKSPACE: - foreach ($rightsData as $toolName => $toolRights) { - $orderedTool = $this->toolManager->getOrderedTool($toolName, $contextType, $contextId); - if ($orderedTool) { - $this->toolManager->setPermissions($toolRights, $orderedTool, $role); - } - } - - break; - case Tool::ADMINISTRATION: - foreach ($rightsData as $toolName => $toolRights) { - $adminTool = $this->toolManager->getAdminToolByName($toolName); - if ($adminTool) { - if ($toolRights['open']) { - $adminTool->addRole($role); - } else { - $adminTool->removeRole($role); - } - - $this->om->persist($adminTool); - } - } - - break; + foreach ($rightsData as $toolName => $toolRights) { + $orderedTool = $this->toolManager->getOrderedTool($toolName, $contextType, $contextId); + if ($orderedTool) { + $this->toolManager->setPermissions($toolRights, $orderedTool, $role); + } } $this->om->endFlushSuite(); @@ -180,62 +121,6 @@ public function updateRightsAction(Request $request, Role $role, string $context return new JsonResponse(); } - /** - * @Route("/{id}/analytics/{year}", name="apiv2_role_analytics") - * @EXT\ParamConverter("role", options={"mapping": {"id": "uuid"}}) - * @EXT\ParamConverter("currentUser", converter="current_user", options={"allowAnonymous"=false}) - */ - public function analyticsAction(User $currentUser, Role $role, string $year): JsonResponse - { - $this->checkPermission('OPEN', $role, [], true); - - // get values for user administrated organizations - $organizations = null; - $defaultFilters = []; - if (!$currentUser->hasRole('ROLE_ADMIN')) { - $organizations = $currentUser->getOrganizations(); - $defaultFilters = [ - 'organization' => $organizations, - ]; - } - - $connections = $this->logManager->getData([ - 'hiddenFilters' => array_merge($defaultFilters, [ - 'doerActive' => true, - 'doerCreated' => $year.'-12-31', - 'doerRoles' => [$role->getId()], - 'action' => 'user-login', - 'unique' => true, - - // filter for current year - 'dateLog' => $year.'-01-01', - 'dateTo' => $year.'-12-31', - ]), - ]); - - $actions = $this->logManager->getData([ - 'hiddenFilters' => array_merge($defaultFilters, [ - 'doerActive' => true, - 'doerCreated' => $year.'-12-31', - 'doerRoles' => [$role->getId()], - - // filter for current year - 'dateLog' => $year.'-01-01', - 'dateTo' => $year.'-12-31', - ]), - ]); - - return new JsonResponse([ - 'users' => $this->om->getRepository(User::class)->countUsersByRole($role, $organizations, $year.'-12-31'), - 'connections' => array_reduce($connections, function (int $total, array $connection) { - return $total + ($connection['total'] ?? 0); - }, 0), - 'actions' => array_reduce($actions, function (int $total, array $action) { - return $total + ($action['total'] ?? 0); - }, 0), - ]); - } - protected function getDefaultHiddenFilters(): array { return [ diff --git a/src/main/community/Controller/UserController.php b/src/main/community/Controller/UserController.php index 1969a71bfff..2d278bd0b38 100644 --- a/src/main/community/Controller/UserController.php +++ b/src/main/community/Controller/UserController.php @@ -16,6 +16,7 @@ use Claroline\AppBundle\API\Options; use Claroline\AppBundle\Controller\AbstractCrudController; use Claroline\AuthenticationBundle\Manager\MailManager; +use Claroline\CoreBundle\Component\Context\DesktopContext; use Claroline\CoreBundle\Controller\APINew\Model\HasGroupsTrait; use Claroline\CoreBundle\Controller\APINew\Model\HasOrganizationsTrait; use Claroline\CoreBundle\Controller\APINew\Model\HasRolesTrait; @@ -229,7 +230,7 @@ public function disableAction(Request $request): JsonResponse */ public function disableInactiveAction(Request $request): JsonResponse { - $tool = $this->toolManager->getToolByName('community'); + $tool = $this->toolManager->getOrderedTool('community', DesktopContext::getName()); $this->checkPermission('ADMINISTRATE', $tool, [], true); $data = $this->decodeRequest($request); diff --git a/src/main/community/DependencyInjection/ClarolineCommunityExtension.php b/src/main/community/DependencyInjection/ClarolineCommunityExtension.php index a846d5c96a0..c6089275af6 100644 --- a/src/main/community/DependencyInjection/ClarolineCommunityExtension.php +++ b/src/main/community/DependencyInjection/ClarolineCommunityExtension.php @@ -18,13 +18,11 @@ class ClarolineCommunityExtension extends Extension { - /** - * {@inheritdoc} - */ - public function load(array $configs, ContainerBuilder $container) + public function load(array $configs, ContainerBuilder $container): void { $locator = new FileLocator(__DIR__.'/../Resources/config'); $loader = new YamlFileLoader($container, $locator); $loader->load('services.yml'); + $loader->load('components.yml'); } } diff --git a/src/main/community/Installation/ClarolineCommunityInstaller.php b/src/main/community/Installation/ClarolineCommunityInstaller.php index 37009d278cc..32f6cc939fa 100644 --- a/src/main/community/Installation/ClarolineCommunityInstaller.php +++ b/src/main/community/Installation/ClarolineCommunityInstaller.php @@ -15,4 +15,8 @@ class ClarolineCommunityInstaller extends AdditionalInstaller { + public function hasMigrations(): bool + { + return true; + } } diff --git a/src/main/community/Manager/TeamManager.php b/src/main/community/Manager/TeamManager.php index 7c5fbc8b6d0..a5fbe6a4812 100644 --- a/src/main/community/Manager/TeamManager.php +++ b/src/main/community/Manager/TeamManager.php @@ -15,51 +15,32 @@ use Claroline\AppBundle\API\Options; use Claroline\AppBundle\Persistence\ObjectManager; use Claroline\CommunityBundle\Entity\Team; +use Claroline\CommunityBundle\Repository\TeamRepository; +use Claroline\CoreBundle\Component\Context\WorkspaceContext; use Claroline\CoreBundle\Entity\Resource\Directory; use Claroline\CoreBundle\Entity\Resource\ResourceNode; use Claroline\CoreBundle\Entity\Role; -use Claroline\CoreBundle\Entity\Tool\OrderedTool; -use Claroline\CoreBundle\Entity\Tool\Tool; use Claroline\CoreBundle\Entity\User; use Claroline\CoreBundle\Entity\Workspace\Workspace; use Claroline\CoreBundle\Manager\Resource\RightsManager; use Claroline\CoreBundle\Manager\ResourceManager; use Claroline\CoreBundle\Manager\RoleManager; +use Claroline\CoreBundle\Manager\Tool\ToolManager; use Claroline\CoreBundle\Manager\Tool\ToolRightsManager; class TeamManager { - /** @var ObjectManager */ - private $om; - /** @var Crud */ - private $crud; - /** @var ResourceManager */ - private $resourceManager; - /** @var RightsManager */ - private $rightsManager; - /** @var RoleManager */ - private $roleManager; - /** @var ToolRightsManager */ - private $toolRightsManager; - private $resourceNodeRepo; - private $teamRepo; + private TeamRepository $teamRepo; public function __construct( - ObjectManager $om, - Crud $crud, - ResourceManager $resourceManager, - RightsManager $rightsManager, - RoleManager $roleManager, - ToolRightsManager $toolRightsManager + private readonly ObjectManager $om, + private readonly Crud $crud, + private readonly ResourceManager $resourceManager, + private readonly RightsManager $rightsManager, + private readonly RoleManager $roleManager, + private readonly ToolManager $toolManager, + private readonly ToolRightsManager $toolRightsManager ) { - $this->om = $om; - $this->crud = $crud; - $this->resourceManager = $resourceManager; - $this->rightsManager = $rightsManager; - $this->roleManager = $roleManager; - $this->toolRightsManager = $toolRightsManager; - - $this->resourceNodeRepo = $om->getRepository(ResourceNode::class); $this->teamRepo = $om->getRepository(Team::class); } @@ -79,11 +60,8 @@ public function createTeamRole(Team $team, ?bool $isManager = false): Role $root = $this->resourceManager->getWorkspaceRoot($workspace); $this->rightsManager->update(['open' => true], $role, $root); - $tool = $this->om->getRepository(Tool::class)->findOneBy(['name' => 'resources']); - $orderedTool = $this->om - ->getRepository(OrderedTool::class) - ->findOneBy(['workspace' => $workspace, 'tool' => $tool]); + $orderedTool = $this->toolManager->getOrderedTool('resources', WorkspaceContext::getName(), $workspace->getUuid()); if (!empty($orderedTool)) { $this->toolRightsManager->setToolRights($orderedTool, $role, 1); } diff --git a/src/main/community/Resources/config/components.yml b/src/main/community/Resources/config/components.yml new file mode 100644 index 00000000000..cc128a70a3d --- /dev/null +++ b/src/main/community/Resources/config/components.yml @@ -0,0 +1,2 @@ +imports: + - { resource: components/tool.yml } diff --git a/src/main/community/Resources/config/components/tool.yml b/src/main/community/Resources/config/components/tool.yml new file mode 100644 index 00000000000..c6dd3a46dec --- /dev/null +++ b/src/main/community/Resources/config/components/tool.yml @@ -0,0 +1,19 @@ +services: + Claroline\CommunityBundle\Component\Tool\CommunityTool: + parent: Claroline\AppBundle\Component\Tool\AbstractTool + tags: [ 'claroline.component.tool' ] + arguments: + - '@security.token_storage' + - '@Claroline\AppBundle\Persistence\ObjectManager' + - '@Claroline\AppBundle\API\SerializerProvider' + - '@Claroline\AppBundle\API\Crud' + - '@Claroline\CoreBundle\Library\Configuration\PlatformConfigurationHandler' + - '@Claroline\CoreBundle\API\Serializer\ParametersSerializer' + - '@Claroline\CommunityBundle\Serializer\ProfileSerializer' + - '@Claroline\CoreBundle\Manager\UserManager' + - '@Claroline\CoreBundle\Manager\RoleManager' + - '@Claroline\CommunityBundle\Manager\TeamManager' + + Claroline\CommunityBundle\Component\Tool\ProfileTool: + parent: Claroline\AppBundle\Component\Tool\AbstractTool + tags: [ 'claroline.component.tool' ] diff --git a/src/main/community/Resources/config/services/controller.yml b/src/main/community/Resources/config/services/controller.yml index de1a988f500..d3289d5915c 100644 --- a/src/main/community/Resources/config/services/controller.yml +++ b/src/main/community/Resources/config/services/controller.yml @@ -54,7 +54,6 @@ services: arguments: - '@security.authorization_checker' - '@Claroline\CoreBundle\Manager\Tool\ToolManager' - - '@Claroline\CoreBundle\Manager\LogManager' Claroline\CommunityBundle\Controller\TeamController: parent: Claroline\AppBundle\Controller\AbstractCrudController diff --git a/src/main/community/Resources/config/services/manager.yml b/src/main/community/Resources/config/services/manager.yml index 6755b87241b..2d50e717381 100644 --- a/src/main/community/Resources/config/services/manager.yml +++ b/src/main/community/Resources/config/services/manager.yml @@ -13,4 +13,5 @@ services: - '@Claroline\CoreBundle\Manager\ResourceManager' - '@Claroline\CoreBundle\Manager\Resource\RightsManager' - '@Claroline\CoreBundle\Manager\RoleManager' + - '@Claroline\CoreBundle\Manager\Tool\ToolManager' - '@Claroline\CoreBundle\Manager\Tool\ToolRightsManager' diff --git a/src/main/community/Resources/modules/account/profile/index.js b/src/main/community/Resources/modules/account/profile/index.js index ac5f23c7fb7..0c101270ab1 100644 --- a/src/main/community/Resources/modules/account/profile/index.js +++ b/src/main/community/Resources/modules/account/profile/index.js @@ -1,11 +1,10 @@ -import {trans} from '#/main/app/intl/translation' - import {ProfileMain} from '#/main/community/account/profile/containers/main' export default { + component: ProfileMain/*, + name: 'profile', icon: 'fa fa-fw fa-user-circle', label: trans('user_profile'), - component: ProfileMain, - order: 1 + order: 1*/ } diff --git a/src/main/community/Resources/modules/role/components/metrics.jsx b/src/main/community/Resources/modules/role/components/metrics.jsx deleted file mode 100644 index 13af0437007..00000000000 --- a/src/main/community/Resources/modules/role/components/metrics.jsx +++ /dev/null @@ -1,115 +0,0 @@ -import React, {Component} from 'react' -import {PropTypes as T} from 'prop-types' -import moment from 'moment' -import {schemeCategory20c} from '#/main/theme/color/utils' - -import {trans} from '#/main/app/intl/translation' -import {Toolbar} from '#/main/app/action/components/toolbar' -import {ContentCounter} from '#/main/app/content/components/counter' -import {CALLBACK_BUTTON} from '#/main/app/buttons' - -class RoleMetrics extends Component { - constructor(props) { - super(props) - - this.state = { - loaded: false, - current: moment().year(), - available: [ - moment().year(), - moment().year() - 1, - moment().year() - 2 - ], - count: { - users: 20, - connections: 50, - actions: 90 - } - } - } - - componentDidMount() { - this.props.load(this.state.current).then((response) => this.setState({ - count: response, - loaded: true - })) - } - - changeYear(year) { - this.setState({ - loaded: false, - current: year - }) - - // reload - this.props.load(year).then((response) => this.setState({ - count: response, - loaded: true - })) - } - - render() { - let ellapsedDays = 365 - if (this.state.current === moment().year()) { - // current period - ellapsedDays = moment().diff(moment([this.state.current, '01, 01']), 'days') + 1 - } - - return ( -
- 'y'+year).join(' ')} - size="sm" - actions={this.state.available.map(year => ( - { - primary: year === this.state.current, - name: 'y'+year, - type: CALLBACK_BUTTON, - label: year, - callback: () => this.changeYear(year) - } - ))} - /> - - - - - - -
- ) - } -} - -RoleMetrics.propTypes = { - load: T.func.isRequired -} - -export { - RoleMetrics -} diff --git a/src/main/community/Resources/modules/tools/community/role/components/show.jsx b/src/main/community/Resources/modules/tools/community/role/components/show.jsx index 618d676cf28..88a6a3dfac5 100644 --- a/src/main/community/Resources/modules/tools/community/role/components/show.jsx +++ b/src/main/community/Resources/modules/tools/community/role/components/show.jsx @@ -16,7 +16,6 @@ import {GroupList} from '#/main/community/group/components/list' import {constants} from '#/main/community/constants' import {Role as RoleTypes} from '#/main/community/role/prop-types' import {RolePage} from '#/main/community/role/components/page' -import {RoleMetrics} from '#/main/community/role/components/metrics' import {selectors} from '#/main/community/tools/community/role/store/selectors' import {RoleShortcuts} from '#/main/community/tools/community/role/containers/shortcuts' import {RoleRights} from '#/main/community/tools/community/role/components/rights' @@ -28,12 +27,6 @@ const RoleShow = (props) => reload={(role) => props.reload(role, props.contextData)} >
- {get(props.role, 'id') && - props.loadMetrics(props.role.id, year)} - /> - } - (dispatch) => dispatch({ } }) -actions.fetchMetrics = (id, year) => ({ - [API_REQUEST]: { - url: ['apiv2_role_analytics', {id: id, year: year}], - silent: true - } -}) - actions.fetchWorkspaceRights = (id, contextId = null) => (dispatch) => dispatch({ [API_REQUEST]: { url: ['apiv2_role_rights_list', {id: id, contextType: 'workspace', contextId: contextId}], diff --git a/src/main/community/Security/Voter/UserVoter.php b/src/main/community/Security/Voter/UserVoter.php index a0752c05747..b4fde620d5a 100644 --- a/src/main/community/Security/Voter/UserVoter.php +++ b/src/main/community/Security/Voter/UserVoter.php @@ -13,21 +13,16 @@ use Claroline\AppBundle\Security\ObjectCollection; use Claroline\CoreBundle\Entity\Role; -use Claroline\CoreBundle\Entity\Tool\OrderedTool; use Claroline\CoreBundle\Entity\User; use Claroline\CoreBundle\Library\Configuration\PlatformConfigurationHandler; -use Claroline\CoreBundle\Repository\Tool\OrderedToolRepository; use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; use Symfony\Component\Security\Core\Authorization\Voter\VoterInterface; class UserVoter extends AbstractRoleSubjectVoter { - /** @var PlatformConfigurationHandler */ - private $config; - - public function __construct(PlatformConfigurationHandler $config) - { - $this->config = $config; + public function __construct( + private readonly PlatformConfigurationHandler $config + ) { } /** @@ -68,17 +63,7 @@ private function checkOpen(TokenInterface $token, User $user): int return VoterInterface::ACCESS_GRANTED; } - if ($this->isToolGranted('EDIT', 'community')) { - return VoterInterface::ACCESS_GRANTED; - } - - // allow open for all of those who have the open right on community tool - // TODO : this should also check user is in the same organization - /** @var OrderedToolRepository $orderedToolRepo */ - $orderedToolRepo = $this->getObjectManager()->getRepository(OrderedTool::class); - /** @var OrderedTool $communityTools */ - $communityTool = $orderedToolRepo->findOneByNameAndDesktop('community'); - if ($communityTool && $this->isGranted('OPEN', $communityTool)) { + if ($this->isToolGranted('OPEN', 'community')) { return VoterInterface::ACCESS_GRANTED; } @@ -159,19 +144,6 @@ private function checkCreate(TokenInterface $token, User $user) return VoterInterface::ACCESS_GRANTED; } - // allow creation for all of those who have the create right on a community tool - /** @var OrderedToolRepository $orderedToolRepo */ - $orderedToolRepo = $this->getObjectManager()->getRepository(OrderedTool::class); - /** @var OrderedTool[] $communityTools */ - $communityTools = $orderedToolRepo->findByName('community'); - foreach ($communityTools as $communityTool) { - // we do not take into account tool in personal ws, otherwise anyone will be granted - // (users are managers of their personal ws) - if ((empty($communityTool->getWorkspace()) || !$communityTool->getWorkspace()->isPersonal()) && $this->isGranted('CREATE_USER', $communityTool)) { - return VoterInterface::ACCESS_GRANTED; - } - } - // allow creation for self registration if ($this->config->getParameter('registration.self')) { $defaultRole = $this->config->getParameter('registration.default_role'); diff --git a/src/main/community/Tests/Repository/RoleRepositoryTest.php b/src/main/community/Tests/Repository/RoleRepositoryTest.php index 914fe7016ce..9b567fa918c 100644 --- a/src/main/community/Tests/Repository/RoleRepositoryTest.php +++ b/src/main/community/Tests/Repository/RoleRepositoryTest.php @@ -25,14 +25,13 @@ public static function setUpBeforeClass(): void self::createWorkspace('ws_1'); self::createWorkspace('ws_2'); - self::createTool('tool_1'); self::createRole('ROLE_WS_VISITOR_'.self::get('ws_1')->getUuid(), self::get('ws_1')); self::createRole('ROLE_WS_COLLABORATOR_'.self::get('ws_1')->getUuid(), self::get('ws_1')); self::createRole('ROLE_WS_MANAGER_'.self::get('ws_1')->getUuid(), self::get('ws_1')); self::createRole('ROLE_WS_CUSTOM_1', self::get('ws_1')); self::createRole('ROLE_WS_CUSTOM_2', self::get('ws_1')); self::createRole('ROLE_PLATFORM_CUSTOM'); - self::createWorkspaceTool(self::get('tool_1'), self::get('ws_1'), [self::get('ROLE_WS_CUSTOM_1')], 1); + self::createWorkspaceTool('tool_1', self::get('ws_1'), [self::get('ROLE_WS_CUSTOM_1')], 1); self::createUser('john', [self::get('ROLE_WS_CUSTOM_1'), self::get('ROLE_PLATFORM_CUSTOM')]); self::createGroup('group_1', [], [self::get('ROLE_WS_CUSTOM_2')]); } diff --git a/src/main/core/API/Finder/Tool/AdminToolFinder.php b/src/main/core/API/Finder/Tool/AdminToolFinder.php deleted file mode 100644 index a0b47ad8f65..00000000000 --- a/src/main/core/API/Finder/Tool/AdminToolFinder.php +++ /dev/null @@ -1,63 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Claroline\CoreBundle\API\Finder\Tool; - -use Claroline\AppBundle\API\Finder\AbstractFinder; -use Claroline\CoreBundle\Entity\Tool\AdminTool; -use Claroline\CoreBundle\Manager\PluginManager; -use Doctrine\ORM\QueryBuilder; - -class AdminToolFinder extends AbstractFinder -{ - /** @var PluginManager */ - private $pluginManager; - - /** - * AdminToolFinder constructor. - */ - public function __construct(PluginManager $pluginManager) - { - $this->pluginManager = $pluginManager; - } - - public static function getClass(): string - { - return AdminTool::class; - } - - public function configureQueryBuilder(QueryBuilder $qb, array $searches = [], array $sortBy = null): QueryBuilder - { - $bundles = $this->pluginManager->getEnabled(); - - // only grab tools from enabled plugins - $qb->leftJoin('obj.plugin', 'p'); - $qb->andWhere($qb->expr()->orX( - $qb->expr()->in('CONCAT(p.vendorName, p.bundleName)', ':bundles'), - $qb->expr()->isNull('p') - )); - $qb->setParameter('bundles', $bundles); - - foreach ($searches as $filterName => $filterValue) { - switch ($filterName) { - case 'roles': - $qb->join('obj.roles', 'r'); - $qb->andWhere("r.name IN (:{$filterName})"); - $qb->setParameter($filterName, is_array($filterValue) ? $filterValue : [$filterValue]); - break; - default: - $this->setDefaults($qb, $filterName, $filterValue); - } - } - - return $qb; - } -} diff --git a/src/main/core/API/Finder/Tool/OrderedToolFinder.php b/src/main/core/API/Finder/Tool/OrderedToolFinder.php index ad85e4c94f4..bf47f11387d 100644 --- a/src/main/core/API/Finder/Tool/OrderedToolFinder.php +++ b/src/main/core/API/Finder/Tool/OrderedToolFinder.php @@ -26,17 +26,20 @@ public function configureQueryBuilder(QueryBuilder $qb, array $searches = [], ar { foreach ($searches as $filterName => $filterValue) { switch ($filterName) { + case 'context': + $qb->andWhere('obj.contextName = :contextName'); + $qb->setParameter('contextName', $filterValue); + break; + case 'contextId': case 'workspace': - $qb->leftJoin('obj.workspace', 'ws'); - $qb->andWhere($qb->expr()->orX( - $qb->expr()->eq('ws.uuid', ':workspace') - )); - $qb->setParameter('workspace', $filterValue); + $qb->andWhere('obj.contextId = :contextId'); + $qb->setParameter('contextId', $filterValue); break; case 'tool': $qb->leftJoin('obj.tool', 'tool'); $qb->andWhere('tool.name = :tool'); $qb->setParameter('tool', $filterValue); + break; } } diff --git a/src/main/core/API/Finder/Tool/ToolFinder.php b/src/main/core/API/Finder/Tool/ToolFinder.php deleted file mode 100644 index 65ce4e432c8..00000000000 --- a/src/main/core/API/Finder/Tool/ToolFinder.php +++ /dev/null @@ -1,88 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Claroline\CoreBundle\API\Finder\Tool; - -use Claroline\AppBundle\API\Finder\AbstractFinder; -use Claroline\CoreBundle\Entity\Tool\Tool; -use Claroline\CoreBundle\Manager\PluginManager; -use Claroline\CoreBundle\Manager\Tool\ToolManager; -use Doctrine\ORM\Query\Expr\Join; -use Doctrine\ORM\QueryBuilder; - -class ToolFinder extends AbstractFinder -{ - /** @var PluginManager */ - private $pluginManager; - - public function __construct(PluginManager $pluginManager) - { - $this->pluginManager = $pluginManager; - } - - public static function getClass(): string - { - return Tool::class; - } - - public function configureQueryBuilder(QueryBuilder $qb, array $searches = [], array $sortBy = null): QueryBuilder - { - $bundles = $this->pluginManager->getEnabled(); - - $qb->leftJoin('obj.plugin', 'p'); - $qb->andWhere($qb->expr()->orX( - $qb->expr()->in('CONCAT(p.vendorName, p.bundleName)', ':bundles'), - $qb->expr()->isNull('p') - )); - $qb->setParameter('bundles', $bundles); - - $otJoin = false; - - foreach ($searches as $filterName => $filterValue) { - switch ($filterName) { - case 'user': - if (!$otJoin) { - $qb->join('Claroline\\CoreBundle\\Entity\\Tool\\OrderedTool', 'ot', Join::WITH, 'ot.tool = obj'); - $otJoin = true; - } - - $qb->andWhere('ot.user IS NULL AND ot.workspace IS NULL'); - break; - case 'workspace': - if (!$otJoin) { - $qb->join('Claroline\\CoreBundle\\Entity\\Tool\\OrderedTool', 'ot', Join::WITH, 'ot.tool = obj'); - $otJoin = true; - } - $qb->join('ot.workspace', 'w'); - $qb->andWhere("w.uuid = :{$filterName}"); - $qb->andWhere('(w.model = false OR obj.name IN (:availableTools))'); - $qb->setParameter($filterName, $filterValue); - $qb->setParameter('availableTools', ToolManager::WORKSPACE_MODEL_TOOLS); - break; - case 'roles': - if (!$otJoin) { - $qb->join('Claroline\\CoreBundle\\Entity\\Tool\\OrderedTool', 'ot', Join::WITH, 'ot.tool = obj'); - $otJoin = true; - } - $qb->join('ot.rights', 'r'); - $qb->join('r.role', 'rr'); - $qb->andWhere('BIT_AND(r.mask, 1) = 1'); - $qb->andWhere("rr.name IN (:{$filterName})"); - $qb->setParameter($filterName, is_array($filterValue) ? $filterValue : [$filterValue]); - break; - default: - $this->setDefaults($qb, $filterName, $filterValue); - } - } - - return $qb; - } -} diff --git a/src/main/core/API/Serializer/Log/Connection/LogConnectAdminToolSerializer.php b/src/main/core/API/Serializer/Log/Connection/LogConnectAdminToolSerializer.php deleted file mode 100644 index 22d0ca9fedb..00000000000 --- a/src/main/core/API/Serializer/Log/Connection/LogConnectAdminToolSerializer.php +++ /dev/null @@ -1,48 +0,0 @@ -serializer = $serializer; // bad - } - - public function getClass() - { - return LogConnectAdminTool::class; - } - - public function getName() - { - return 'log_connect_admin_tool'; - } - - /** - * @return array - */ - public function serialize(LogConnectAdminTool $log, array $options = []) - { - $serialized = [ - 'id' => $log->getUuid(), - 'date' => $log->getConnectionDate()->format('Y-m-d\TH:i:s'), - 'duration' => $log->getDuration(), - 'user' => $this->serializer->serialize($log->getUser(), [Options::SERIALIZE_MINIMAL]), - 'tool' => $this->serializer->serialize($log->getTool(), [Options::SERIALIZE_MINIMAL]), - 'toolName' => $log->getToolName(), - ]; - - return $serialized; - } -} diff --git a/src/main/core/API/Serializer/Log/Connection/LogConnectPlatformSerializer.php b/src/main/core/API/Serializer/Log/Connection/LogConnectPlatformSerializer.php deleted file mode 100644 index 63b7ef661f6..00000000000 --- a/src/main/core/API/Serializer/Log/Connection/LogConnectPlatformSerializer.php +++ /dev/null @@ -1,46 +0,0 @@ -serializer = $serializer; // bad - } - - public function getClass() - { - return LogConnectPlatform::class; - } - - public function getName() - { - return 'log_connect_platform'; - } - - /** - * @return array - */ - public function serialize(LogConnectPlatform $log, array $options = []) - { - $serialized = [ - 'id' => $log->getUuid(), - 'date' => $log->getConnectionDate()->format('Y-m-d\TH:i:s'), - 'duration' => $log->getDuration(), - 'user' => $this->serializer->serialize($log->getUser(), [Options::SERIALIZE_MINIMAL]), - ]; - - return $serialized; - } -} diff --git a/src/main/core/API/Serializer/Log/Connection/LogConnectResourceSerializer.php b/src/main/core/API/Serializer/Log/Connection/LogConnectResourceSerializer.php deleted file mode 100644 index d0a88853e00..00000000000 --- a/src/main/core/API/Serializer/Log/Connection/LogConnectResourceSerializer.php +++ /dev/null @@ -1,49 +0,0 @@ -serializer = $serializer; // bad - } - - public function getClass() - { - return LogConnectResource::class; - } - - public function getName() - { - return 'log_connect_resource'; - } - - /** - * @return array - */ - public function serialize(LogConnectResource $log, array $options = []) - { - $serialized = [ - 'id' => $log->getUuid(), - 'date' => $log->getConnectionDate()->format('Y-m-d\TH:i:s'), - 'duration' => $log->getDuration(), - 'user' => $this->serializer->serialize($log->getUser(), [Options::SERIALIZE_MINIMAL]), - 'resource' => $this->serializer->serialize($log->getResource(), [Options::SERIALIZE_MINIMAL]), - 'resourceName' => $log->getResourceName(), - 'resourceType' => $log->getResourceType(), - ]; - - return $serialized; - } -} diff --git a/src/main/core/API/Serializer/Log/Connection/LogConnectToolSerializer.php b/src/main/core/API/Serializer/Log/Connection/LogConnectToolSerializer.php deleted file mode 100644 index 30e1bdeb5b3..00000000000 --- a/src/main/core/API/Serializer/Log/Connection/LogConnectToolSerializer.php +++ /dev/null @@ -1,53 +0,0 @@ -serializer = $serializer; - } - - public function getClass() - { - return LogConnectTool::class; - } - - public function getName() - { - return 'log_connect_tool'; - } - - /** - * @return array - */ - public function serialize(LogConnectTool $log, array $options = []) - { - $serialized = [ - 'id' => $log->getUuid(), - 'date' => $log->getConnectionDate()->format('Y-m-d\TH:i:s'), - 'duration' => $log->getDuration(), - 'user' => $this->serializer->serialize($log->getUser(), [Options::SERIALIZE_MINIMAL]), - 'tool' => $this->serializer->serialize($log->getTool(), [Options::SERIALIZE_MINIMAL]), - 'toolName' => $log->getToolName(), - 'originalToolName' => $log->getOrignalToolName(), - 'workspace' => $log->getWorkspace() ? - $this->serializer->serialize($log->getWorkspace(), [Options::SERIALIZE_MINIMAL]) : - null, - 'workspaceName' => $log->getWorkspaceName(), - ]; - - return $serialized; - } -} diff --git a/src/main/core/API/Serializer/Log/Connection/LogConnectWorkspaceSerializer.php b/src/main/core/API/Serializer/Log/Connection/LogConnectWorkspaceSerializer.php deleted file mode 100644 index 4b8c9307ded..00000000000 --- a/src/main/core/API/Serializer/Log/Connection/LogConnectWorkspaceSerializer.php +++ /dev/null @@ -1,48 +0,0 @@ -serializer = $serializer; - } - - public function getClass() - { - return LogConnectWorkspace::class; - } - - public function getName() - { - return 'log_connect_workspace'; - } - - /** - * @return array - */ - public function serialize(LogConnectWorkspace $log, array $options = []) - { - $serialized = [ - 'id' => $log->getUuid(), - 'date' => $log->getConnectionDate()->format('Y-m-d\TH:i:s'), - 'duration' => $log->getDuration(), - 'user' => $this->serializer->serialize($log->getUser(), [Options::SERIALIZE_MINIMAL]), - 'workspace' => $this->serializer->serialize($log->getWorkspace(), [Options::SERIALIZE_MINIMAL]), - 'workspaceName' => $log->getWorkspaceName(), - ]; - - return $serialized; - } -} diff --git a/src/main/core/API/Serializer/Tool/AdminToolSerializer.php b/src/main/core/API/Serializer/Tool/AdminToolSerializer.php deleted file mode 100644 index 645a4503c63..00000000000 --- a/src/main/core/API/Serializer/Tool/AdminToolSerializer.php +++ /dev/null @@ -1,27 +0,0 @@ - $tool->getUuid(), - 'icon' => $tool->getClass(), - 'name' => $tool->getName(), - ]; - - return $serialized; - } -} diff --git a/src/main/core/API/Serializer/Tool/OrderedToolSerializer.php b/src/main/core/API/Serializer/Tool/OrderedToolSerializer.php index a251d81c1be..3a6f1e038bc 100644 --- a/src/main/core/API/Serializer/Tool/OrderedToolSerializer.php +++ b/src/main/core/API/Serializer/Tool/OrderedToolSerializer.php @@ -32,8 +32,8 @@ public function serialize(OrderedTool $orderedTool, ?array $options = []): array { $serialized = [ 'id' => $orderedTool->getUuid(), - 'name' => $orderedTool->getTool()->getName(), - 'icon' => $orderedTool->getTool()->getClass(), + 'name' => $orderedTool->getName(), + // 'icon' => $orderedTool->getTool()->getClass(), 'poster' => $orderedTool->getPoster(), 'thumbnail' => $orderedTool->getThumbnail(), 'display' => [ @@ -61,12 +61,13 @@ public function deserialize(array $data, OrderedTool $orderedTool, ?array $optio $orderedTool->refreshUuid(); } + $this->sipe('name', 'setName', $data, $orderedTool); + $this->sipe('poster', 'setPoster', $data, $orderedTool); + $this->sipe('thumbnail', 'setThumbnail', $data, $orderedTool); $this->sipe('display.order', 'setOrder', $data, $orderedTool); $this->sipe('display.showIcon', 'setShowIcon', $data, $orderedTool); $this->sipe('display.fullscreen', 'setFullscreen', $data, $orderedTool); $this->sipe('restrictions.hidden', 'setHidden', $data, $orderedTool); - $this->sipe('poster', 'setPoster', $data, $orderedTool); - $this->sipe('thumbnail', 'setThumbnail', $data, $orderedTool); return $orderedTool; } diff --git a/src/main/core/API/Serializer/Tool/ToolRightsSerializer.php b/src/main/core/API/Serializer/Tool/ToolRightsSerializer.php index 227347a7a57..d923deb5f73 100644 --- a/src/main/core/API/Serializer/Tool/ToolRightsSerializer.php +++ b/src/main/core/API/Serializer/Tool/ToolRightsSerializer.php @@ -12,29 +12,19 @@ class ToolRightsSerializer { - /** @var ObjectManager */ - private $om; - /** @var RoleSerializer */ - private $roleSerializer; - /** @var ToolMaskDecoderManager */ - private $maskManager; - public function __construct( - ObjectManager $om, - RoleSerializer $roleSerializer, - ToolMaskDecoderManager $maskManager + private readonly ObjectManager $om, + private readonly RoleSerializer $roleSerializer, + private readonly ToolMaskDecoderManager $maskManager ) { - $this->om = $om; - $this->roleSerializer = $roleSerializer; - $this->maskManager = $maskManager; } - public function getClass() + public function getClass(): string { return ToolRights::class; } - public function getName() + public function getName(): string { return 'tool_rights'; } @@ -46,9 +36,9 @@ public function serialize(ToolRights $toolRights): array $serialized = [ 'id' => $toolRights->getId(), - 'orderedToolId' => $orderedTool->getUuid(), + 'orderedToolId' => $orderedTool->getUuid(), // TODO : to remove 'role' => $this->roleSerializer->serialize($role, [SerializerInterface::SERIALIZE_MINIMAL]), - 'permissions' => $this->maskManager->decodeMask($toolRights->getMask(), $orderedTool->getTool()), + 'permissions' => $this->maskManager->decodeMask($toolRights->getMask(), $orderedTool->getName()), // TODO : do not flatten role data (UI expects this structure). 'translationKey' => $role->getTranslationKey(), @@ -80,16 +70,16 @@ public function deserialize(array $data, ToolRights $toolRights): ToolRights $toolRights->setRole($role); } - if (!empty($data['orderedToolId'])) { + if (!empty($data['orderedTool'])) { /** @var OrderedTool $orderedTool */ - $orderedTool = $this->om->getRepository(OrderedTool::class)->findOneBy(['uuid' => $data['orderedToolId']]); + $orderedTool = $this->om->getObject($data['orderedTool'], OrderedTool::class); if ($orderedTool) { $toolRights->setOrderedTool($orderedTool); } } if ($toolRights->getOrderedTool()) { - $toolRights->setMask($this->maskManager->encodeMask($data['permissions'], $toolRights->getOrderedTool()->getTool())); + $toolRights->setMask($this->maskManager->encodeMask($data['permissions'], $toolRights->getOrderedTool()->getName())); } return $toolRights; diff --git a/src/main/core/API/Serializer/Tool/ToolSerializer.php b/src/main/core/API/Serializer/Tool/ToolSerializer.php deleted file mode 100644 index 0997a9feb7e..00000000000 --- a/src/main/core/API/Serializer/Tool/ToolSerializer.php +++ /dev/null @@ -1,27 +0,0 @@ - $tool->getUuid(), - 'name' => $tool->getName(), - 'icon' => $tool->getClass(), - ]; - } - - public function getName() - { - return 'tool'; - } -} diff --git a/src/main/core/Component/Context/AccountContext.php b/src/main/core/Component/Context/AccountContext.php index 4626814ea1f..e3bd326a8f4 100644 --- a/src/main/core/Component/Context/AccountContext.php +++ b/src/main/core/Component/Context/AccountContext.php @@ -3,6 +3,7 @@ namespace Claroline\CoreBundle\Component\Context; use Claroline\AppBundle\Component\Context\AbstractContext; +use Claroline\AppBundle\Component\Context\ContextSubjectInterface; use Claroline\AppBundle\Manager\SecurityManager; use Claroline\CoreBundle\Entity\Role; use Claroline\CoreBundle\Entity\User; @@ -15,7 +16,7 @@ public function __construct( ) { } - public static function getShortName(): string + public static function getName(): string { return 'account'; } @@ -25,32 +26,27 @@ public function getObject(?string $contextId): ?User return $this->securityManager->getCurrentUser(); } - public function isAvailable(?string $contextId, TokenInterface $token): bool + public function isAvailable(?string $contextId): bool { return !empty($this->securityManager->getCurrentUser()); } - public function getAccessErrors(?string $contextId, TokenInterface $token): array + public function getAccessErrors(TokenInterface $token, ?ContextSubjectInterface $contextSubject): array { return []; } - public function isManager(?string $contextId, TokenInterface $token): bool + public function isManager(TokenInterface $token, ?ContextSubjectInterface $contextSubject): bool { return $this->securityManager->isAdmin(); } - public function isImpersonated(?string $contextId, TokenInterface $token): bool + public function isImpersonated(TokenInterface $token, ?ContextSubjectInterface $contextSubject): bool { return $this->securityManager->isImpersonated(); } - public function getAdditionalData(?string $contextId): array - { - return []; - } - - public function getRoles(?string $contextId, TokenInterface $token): array + public function getRoles(TokenInterface $token, ?ContextSubjectInterface $contextSubject): array { $currentUser = $this->securityManager->getCurrentUser(); if (empty($currentUser)) { @@ -61,10 +57,4 @@ public function getRoles(?string $contextId, TokenInterface $token): array return Role::PLATFORM_ROLE === $role->getType(); }); } - - public function getShortcuts(?string $contextId): array - { - // only supported by Workspace context atm - return []; - } } diff --git a/src/main/core/Component/Context/AdministrationContext.php b/src/main/core/Component/Context/AdministrationContext.php index cdd54c0c9c1..c1b6ccea35c 100644 --- a/src/main/core/Component/Context/AdministrationContext.php +++ b/src/main/core/Component/Context/AdministrationContext.php @@ -3,6 +3,7 @@ namespace Claroline\CoreBundle\Component\Context; use Claroline\AppBundle\Component\Context\AbstractContext; +use Claroline\AppBundle\Component\Context\ContextSubjectInterface; use Claroline\AppBundle\Manager\SecurityManager; use Claroline\CoreBundle\Entity\Role; use Claroline\CoreBundle\Library\Configuration\PlatformConfigurationHandler; @@ -21,38 +22,38 @@ public function __construct( ) { } - public static function getShortName(): string + public static function getName(): string { return 'administration'; } - public function getObject(?string $contextId): mixed + public function getObject(?string $contextId): ?ContextSubjectInterface { return null; } - public function isAvailable(?string $contextId, TokenInterface $token): bool + public function isAvailable(?string $contextId): bool { - return !empty($this->securityManager->getCurrentUser()) - && !empty($this->toolManager->getAdminToolsByRoles($token->getRoleNames())); + return !empty($this->securityManager->getCurrentUser()); + // && !empty($this->toolManager->getAdminToolsByRoles($token->getRoleNames())); } - public function getAccessErrors(?string $contextId, TokenInterface $token): array + public function getAccessErrors(TokenInterface $token, ?ContextSubjectInterface $contextSubject): array { return []; } - public function isImpersonated(?string $contextId, TokenInterface $token): bool + public function isImpersonated(TokenInterface $token, ?ContextSubjectInterface $contextSubject): bool { return $this->securityManager->isImpersonated(); } - public function isManager(?string $contextId, TokenInterface $token): bool + public function isManager(TokenInterface $token, ?ContextSubjectInterface $contextSubject): bool { return $this->securityManager->isAdmin(); } - public function getAdditionalData(?string $contextId): array + public function getAdditionalData(?ContextSubjectInterface $contextSubject): array { // for retro-compatibility, should not be exposed here $defaultTool = $this->config->getParameter('admin.default_tool'); @@ -68,7 +69,7 @@ public function getAdditionalData(?string $contextId): array ]; } - public function getRoles(?string $contextId, TokenInterface $token): array + public function getRoles(TokenInterface $token, ?ContextSubjectInterface $contextSubject): array { $currentUser = $this->securityManager->getCurrentUser(); if (empty($currentUser)) { @@ -79,10 +80,4 @@ public function getRoles(?string $contextId, TokenInterface $token): array return Role::PLATFORM_ROLE === $role->getType(); }); } - - public function getShortcuts(?string $contextId): array - { - // only supported by Workspace context atm - return []; - } } diff --git a/src/main/core/Component/Context/DesktopContext.php b/src/main/core/Component/Context/DesktopContext.php index 707086e6642..9dd988a81dd 100644 --- a/src/main/core/Component/Context/DesktopContext.php +++ b/src/main/core/Component/Context/DesktopContext.php @@ -3,6 +3,7 @@ namespace Claroline\CoreBundle\Component\Context; use Claroline\AppBundle\Component\Context\AbstractContext; +use Claroline\AppBundle\Component\Context\ContextSubjectInterface; use Claroline\AppBundle\Manager\SecurityManager; use Claroline\CoreBundle\Entity\Role; use Claroline\CoreBundle\Library\Configuration\PlatformConfigurationHandler; @@ -16,39 +17,51 @@ public function __construct( ) { } - public static function getShortName(): string + public static function getName(): string { return 'desktop'; } - public function getObject(?string $contextId): mixed + public function getObject(?string $contextId): ?ContextSubjectInterface { return null; } - public function isAvailable(?string $contextId, TokenInterface $token): bool + public function isAvailable(?string $contextId): bool { + return !empty($this->securityManager->getCurrentUser()); // do user have access to at least one tool ? - return !empty($this->toolManager->getOrderedToolsByDesktop($token->getRoleNames())); + // return !empty($this->toolManager->getOrderedToolsByDesktop($token->getRoleNames())); } - public function getAccessErrors(?string $contextId, TokenInterface $token): array + public function getAccessErrors(TokenInterface $token, ?ContextSubjectInterface $contextSubject): array { - return [ - ]; + return []; } - public function isImpersonated(?string $contextId, TokenInterface $token): bool + public function isImpersonated(TokenInterface $token, ?ContextSubjectInterface $contextSubject): bool { return $this->securityManager->isImpersonated(); } - public function isManager(?string $contextId, TokenInterface $token): bool + public function isManager(TokenInterface $token, ?ContextSubjectInterface $contextSubject): bool { return $this->securityManager->isAdmin(); } - public function getAdditionalData(?string $contextId): array + public function getRoles(TokenInterface $token, ?ContextSubjectInterface $contextSubject): array + { + $currentUser = $this->securityManager->getCurrentUser(); + if (empty($currentUser)) { + return []; + } + + return array_filter($currentUser->getEntityRoles(), function (Role $role) { + return Role::PLATFORM_ROLE === $role->getType(); + }); + } + + public function getAdditionalData(?ContextSubjectInterface $contextSubject): array { // for retro-compatibility, should not be exposed here $defaultTool = $this->config->getParameter('desktop.default_tool'); @@ -63,23 +76,4 @@ public function getAdditionalData(?string $contextId): array ], ]; } - - public function getRoles(?string $contextId, TokenInterface $token): array - { - $currentUser = $this->securityManager->getCurrentUser(); - if (empty($currentUser)) { - return []; - } - - return array_filter($currentUser->getEntityRoles(), function (Role $role) { - return Role::PLATFORM_ROLE === $role->getType(); - }); - } - - public function getShortcuts(?string $contextId): array - { - // only supported by Workspace context atm - // return $this->config->getParameter('desktop.shortcuts') ?? []; - return []; - } } diff --git a/src/main/core/Component/Context/PublicContext.php b/src/main/core/Component/Context/PublicContext.php index 172428f9a35..30997981a28 100644 --- a/src/main/core/Component/Context/PublicContext.php +++ b/src/main/core/Component/Context/PublicContext.php @@ -3,6 +3,7 @@ namespace Claroline\CoreBundle\Component\Context; use Claroline\AppBundle\Component\Context\AbstractContext; +use Claroline\AppBundle\Component\Context\ContextSubjectInterface; use Claroline\AppBundle\Manager\SecurityManager; use Claroline\CoreBundle\Entity\Role; use Claroline\CoreBundle\Library\Configuration\PlatformConfigurationHandler; @@ -16,37 +17,49 @@ public function __construct( ) { } - public static function getShortName(): string + public static function getName(): string { return 'public'; } - public function getObject(?string $contextId): mixed + public function getObject(?string $contextId): ?ContextSubjectInterface { return null; } - public function isAvailable(?string $contextId, TokenInterface $token): bool + public function isAvailable(?string $contextId): bool { return 'tool' === $this->config->getParameter('home.type'); } - public function getAccessErrors(?string $contextId, TokenInterface $token): array + public function getAccessErrors(TokenInterface $token, ?ContextSubjectInterface $contextSubject): array { return []; } - public function isImpersonated(?string $contextId, TokenInterface $token): bool + public function isImpersonated(TokenInterface $token, ?ContextSubjectInterface $contextSubject): bool { return $this->securityManager->isImpersonated(); } - public function isManager(?string $contextId, TokenInterface $token): bool + public function isManager(TokenInterface $token, ?ContextSubjectInterface $contextSubject): bool { return $this->securityManager->isAdmin(); } - public function getAdditionalData(?string $contextId): array + public function getRoles(TokenInterface $token, ?ContextSubjectInterface $contextSubject): array + { + $currentUser = $this->securityManager->getCurrentUser(); + if (empty($currentUser)) { + return []; + } + + return array_filter($currentUser->getEntityRoles(), function (Role $role) { + return Role::PLATFORM_ROLE === $role->getType(); + }); + } + + public function getAdditionalData(?ContextSubjectInterface $contextSubject): array { // for retro-compatibility, should not be exposed here $type = $this->config->getParameter('home.type'); @@ -61,22 +74,4 @@ public function getAdditionalData(?string $contextId): array ], ]; } - - public function getRoles(?string $contextId, TokenInterface $token): array - { - $currentUser = $this->securityManager->getCurrentUser(); - if (empty($currentUser)) { - return []; - } - - return array_filter($currentUser->getEntityRoles(), function (Role $role) { - return Role::PLATFORM_ROLE === $role->getType(); - }); - } - - public function getShortcuts(?string $contextId): array - { - // only supported by Workspace context atm - return []; - } } diff --git a/src/main/core/Component/Context/WorkspaceContext.php b/src/main/core/Component/Context/WorkspaceContext.php index f0aa25f8c53..2790a1ca50c 100644 --- a/src/main/core/Component/Context/WorkspaceContext.php +++ b/src/main/core/Component/Context/WorkspaceContext.php @@ -5,6 +5,7 @@ use Claroline\AppBundle\API\Serializer\SerializerInterface; use Claroline\AppBundle\API\SerializerProvider; use Claroline\AppBundle\Component\Context\AbstractContext; +use Claroline\AppBundle\Component\Context\ContextSubjectInterface; use Claroline\AppBundle\Persistence\ObjectManager; use Claroline\CoreBundle\Entity\Resource\ResourceNode; use Claroline\CoreBundle\Entity\User; @@ -27,88 +28,83 @@ public function __construct( ) { } - public static function getShortName(): string + public static function getName(): string { return 'workspace'; } - public function getObject(?string $contextId): ?Workspace + public function getObject(?string $contextId): Workspace { + if (empty($contextId)) { + throw new \RuntimeException('WorkspaceContext can not be opened without an ID.'); + } + // we receive the slug on context open, // and we receive the uuid when tools are opened return $this->om->getObject(['id' => $contextId, 'slug' => $contextId], Workspace::class, ['slug']); } - public function getAdditionalData(?string $contextId): array - { - $workspace = $this->getObject($contextId); - $user = $this->tokenStorage->getToken()->getUser(); - - $userEvaluation = null; - if ($user instanceof User) { - $userEvaluation = $this->serializer->serialize( - $this->evaluationManager->getUserEvaluation($workspace, $user), - [SerializerInterface::SERIALIZE_MINIMAL] - ); - } - - $rootNode = $this->om->getRepository(ResourceNode::class)->findOneBy(['workspace' => $workspace, 'parent' => null]); - - return [ - 'userEvaluation' => $userEvaluation, - // do not expose root resource here (used in the WS to configure opening target) - 'root' => $this->serializer->serialize($rootNode, [SerializerInterface::SERIALIZE_MINIMAL]), - ]; - } - - public function isAvailable(?string $contextId, TokenInterface $token): bool + public function isAvailable(?string $contextId): bool { - return true; + return !empty($contextId); } - public function isManager(?string $contextId, TokenInterface $token): bool + public function isManager(TokenInterface $token, ?ContextSubjectInterface $contextSubject): bool { - $workspace = $this->getObject($contextId); + /** @var Workspace $workspace */ + $workspace = $contextSubject; return $this->manager->isManager($workspace, $token); } - public function getAccessErrors(?string $contextId, TokenInterface $token): array + public function getAccessErrors(TokenInterface $token, ?ContextSubjectInterface $contextSubject): array { - $workspace = $this->getObject($contextId); + /** @var Workspace $workspace */ + $workspace = $contextSubject; return $this->restrictionsManager->getErrors($workspace, $token->getUser() instanceof User ? $token->getUser() : null); } - public function isImpersonated(?string $contextId, TokenInterface $token): bool + public function isImpersonated(TokenInterface $token, ?ContextSubjectInterface $contextSubject): bool { return $this->manager->isImpersonated($token); } - public function getRoles(?string $contextId, TokenInterface $token): array + public function getRoles(TokenInterface $token, ?ContextSubjectInterface $contextSubject): array { - if (empty($contextId)) { - return []; - } - - $workspace = $this->getObject($contextId); + /** @var Workspace $workspace */ + $workspace = $contextSubject; return $this->manager->getTokenRoles($token, $workspace); } - public function getTools(?string $contextId): array + public function getAdditionalData(?ContextSubjectInterface $contextSubject): array { - // TODO : filter based on workspace model flag. - return parent::getTools($contextId); - } + /** @var Workspace $workspace */ + $workspace = $contextSubject; + $user = $this->tokenStorage->getToken()->getUser(); - public function getShortcuts(?string $contextId): array - { - if (empty($contextId)) { - return []; + $userEvaluation = null; + if ($user instanceof User) { + $userEvaluation = $this->serializer->serialize( + $this->evaluationManager->getUserEvaluation($workspace, $user), + [SerializerInterface::SERIALIZE_MINIMAL] + ); } - $workspace = $this->getObject($contextId); + $rootNode = $this->om->getRepository(ResourceNode::class)->findOneBy(['workspace' => $workspace, 'parent' => null]); + + return [ + 'userEvaluation' => $userEvaluation, + // do not expose root resource here (used in the WS to configure opening target) + 'root' => $this->serializer->serialize($rootNode, [SerializerInterface::SERIALIZE_MINIMAL]), + ]; + } + + public function getShortcuts(?ContextSubjectInterface $contextSubject): array + { + /** @var Workspace $workspace */ + $workspace = $contextSubject; // TODO : only export current user shortcuts (we get all roles for the configuration in community/editor) // $this->manager->getShortcuts($workspace, $this->tokenStorage->getToken()->getRoleNames()), diff --git a/src/main/core/Component/Tool/ConnectionMessagesTool.php b/src/main/core/Component/Tool/ConnectionMessagesTool.php new file mode 100644 index 00000000000..e69de29bb2d diff --git a/src/main/core/Component/Tool/IntegrationTool.php b/src/main/core/Component/Tool/IntegrationTool.php new file mode 100644 index 00000000000..e69de29bb2d diff --git a/src/main/core/Component/Tool/LocationsTool.php b/src/main/core/Component/Tool/LocationsTool.php new file mode 100644 index 00000000000..e69de29bb2d diff --git a/src/main/core/Component/Tool/ParametersTool.php b/src/main/core/Component/Tool/ParametersTool.php index 1ceed87aa4a..1a296fc1868 100644 --- a/src/main/core/Component/Tool/ParametersTool.php +++ b/src/main/core/Component/Tool/ParametersTool.php @@ -2,18 +2,56 @@ namespace Claroline\CoreBundle\Component\Tool; +use Claroline\AppBundle\Component\Context\ContextSubjectInterface; use Claroline\AppBundle\Component\Tool\AbstractTool; +use Claroline\CoreBundle\API\Serializer\ParametersSerializer; +use Claroline\CoreBundle\Component\Context\AccountContext; use Claroline\CoreBundle\Component\Context\AdministrationContext; +use Claroline\CoreBundle\Manager\LocaleManager; class ParametersTool extends AbstractTool { - public static function getShortName(): string + public function __construct( + private readonly ParametersSerializer $serializer, + private readonly LocaleManager $localeManager + ) { + } + + public static function getName(): string { return 'parameters'; } + public function isRequired(string $context, ?string $contextId): bool + { + return true; + } + public function supportsContext(string $context): bool { - return AdministrationContext::class === $context; + return in_array($context, [ + AccountContext::getName(), + AdministrationContext::getName(), + ]); + } + + public function open(string $context, ContextSubjectInterface $contextSubject = null): ?array + { + if (AdministrationContext::getName() === $context) { + $parameters = $this->serializer->serialize(); + + return [ + 'lockedParameters' => $parameters['lockedParameters'] ?? [], + 'parameters' => $parameters, + 'availableLocales' => $this->localeManager->getAvailableLocales(), + ]; + } + + return []; + } + + public function configure(string $context, ContextSubjectInterface $contextSubject = null, array $configData = []): ?array + { + return []; } } diff --git a/src/main/core/Component/Tool/ResourcesTool.php b/src/main/core/Component/Tool/ResourcesTool.php index bc8d15a5730..ae747a300ae 100644 --- a/src/main/core/Component/Tool/ResourcesTool.php +++ b/src/main/core/Component/Tool/ResourcesTool.php @@ -2,13 +2,39 @@ namespace Claroline\CoreBundle\Component\Tool; +use Claroline\AppBundle\API\Crud; +use Claroline\AppBundle\API\Options; +use Claroline\AppBundle\API\Serializer\SerializerInterface; +use Claroline\AppBundle\API\SerializerProvider; +use Claroline\AppBundle\API\Utils\FileBag; +use Claroline\AppBundle\Component\Context\ContextSubjectInterface; use Claroline\AppBundle\Component\Tool\AbstractTool; +use Claroline\AppBundle\Persistence\ObjectManager; use Claroline\CoreBundle\Component\Context\DesktopContext; use Claroline\CoreBundle\Component\Context\WorkspaceContext; +use Claroline\CoreBundle\Entity\Resource\AbstractResource; +use Claroline\CoreBundle\Entity\Resource\ResourceNode; +use Claroline\CoreBundle\Entity\Resource\ResourceRights; +use Claroline\CoreBundle\Entity\Workspace\Workspace; +use Claroline\CoreBundle\Event\Resource\ExportResourceEvent; +use Claroline\CoreBundle\Event\Resource\ImportResourceEvent; +use Claroline\CoreBundle\Repository\Resource\ResourceNodeRepository; +use Symfony\Contracts\EventDispatcher\EventDispatcherInterface; class ResourcesTool extends AbstractTool { - public static function getShortName(): string + private ResourceNodeRepository $resourceRepository; + + public function __construct( + private readonly ObjectManager $om, + private readonly EventDispatcherInterface $dispatcher, + private readonly SerializerProvider $serializer, + private readonly Crud $crud + ) { + $this->resourceRepository = $om->getRepository(ResourceNode::class); + } + + public static function getName(): string { return 'resources'; } @@ -16,8 +42,191 @@ public static function getShortName(): string public function supportsContext(string $context): bool { return in_array($context, [ - DesktopContext::class, - WorkspaceContext::class, + DesktopContext::getName(), + WorkspaceContext::getName(), ]); } + + public function open(string $context, ContextSubjectInterface $contextSubject = null): ?array + { + $root = null; + if (WorkspaceContext::getName() === $context) { + // filters resources for the current workspace + $root = $this->serializer->serialize( + $this->resourceRepository->findWorkspaceRoot($contextSubject) + ); + } + + return [ + 'root' => $root, + ]; + } + + public function configure(string $context, ContextSubjectInterface $contextSubject = null, array $configData = []): ?array + { + return []; + } + + public function export(string $context, ContextSubjectInterface $contextSubject = null, FileBag $fileBag = null): ?array + { + if (WorkspaceContext::getName() !== $context) { + return []; + } + + $root = $this->resourceRepository->findWorkspaceRoot($contextSubject); + if (empty($root)) { + return []; + } + + return [ + 'resources' => $this->recursiveExport($root, $fileBag), + ]; + } + + public function import(string $context, ContextSubjectInterface $contextSubject = null, FileBag $fileBag = null, array $data = [], array $entities = []): ?array + { + if (WorkspaceContext::getName() !== $context) { + return []; + } + + if (empty($data['resources'])) { + return []; + } + + $resources = $data['resources']; + + // we need to push the resource types with linked resources last, because we need all resources to be created + // to link them to the new resources. + // this should not be done here and as is it doesn't work in all cases (e.g. if we link paths to others paths). + $typesWithResourceLinks = ['innova_path', 'shortcut']; + uksort($resources, function (int $a, int $b) use ($resources, $typesWithResourceLinks) { + if (in_array($resources[$a]['resourceNode']['meta']['type'], $typesWithResourceLinks)) { + return 1; + } elseif (in_array($resources[$b]['resourceNode']['meta']['type'], $typesWithResourceLinks)) { + return -1; + } + + // we want to keep the original order (required for the parent directories to be created first) + // that's why we use uksort and not usort (from the usort doc : If two members compare as equal, they retain their original order. Prior to PHP 8.0.0, their relative order in the sorted array was undefined.) + return $a - $b; + }); + + /** @var Workspace $workspace */ + $workspace = $contextSubject; + + // manage workspace opening + // this is for retro-compatibility, we have stored the autoincrement id of the resource in the workspace options + // when using the UUID, replacement is automatically done in the serialized data + $workspaceOptions = $workspace->getOptions()->getDetails(); + $openingResourceId = null; + if ($workspaceOptions && 'resource' === $workspaceOptions['opening_target'] && !empty($workspaceOptions['workspace_opening_resource'])) { + // this only works because the WorkspaceSerializer::deserialize does not check if the resource exists + $openingResourceId = $workspaceOptions['workspace_opening_resource']; + } + + foreach ($resources as $resourceData) { + // create resource node + $nodeData = $resourceData['resourceNode']; + unset($nodeData['workspace']); + unset($nodeData['slug']); + + $resourceNode = new ResourceNode(); + $resourceNode->setWorkspace($workspace); + + // workspace name root directory based on the new workspace name + if (empty($nodeData['parent'])) { + $nodeData['name'] = $workspace->getName(); + $nodeData['code'] = $workspace->getCode(); + } + + if (!empty($nodeData['parent']) && $entities[$nodeData['parent']['id']]) { + $resourceNode->setParent($entities[$nodeData['parent']['id']]); + unset($nodeData['parent']); + } + + $this->crud->create($resourceNode, $nodeData, [Crud::NO_PERMISSIONS, Crud::NO_VALIDATION, Options::NO_RIGHTS/* , Options::REFRESH_UUID */]); + + $entities[$nodeData['id']] = $resourceNode; + // $event->addCreatedEntity($nodeData['id'], $resourceNode); + + // create rights + if (!empty($resourceData['rights'])) { + foreach ($resourceData['rights'] as $rightsData) { + $role = $entities[$rightsData['role']['id']]; + if (empty($role)) { + continue; + } + + $rights = new ResourceRights(); + $rights->setResourceNode($resourceNode); + $this->serializer->deserialize(array_merge($rightsData, [ + 'role' => [ + 'id' => $role->getUuid(), + ], + ]), $rights); + + $this->om->persist($rights); + } + } + + // create custom resource Entity + $resourceClass = $resourceNode->getResourceType()->getClass(); + + // should be removed. It's only used by quizzes + $resSerializer = $this->serializer->get($resourceClass); + $resSerializeOptions = method_exists($resSerializer, 'getCopyOptions') ? $resSerializer->getCopyOptions() : []; + + /** @var AbstractResource $resource */ + $resource = $this->crud->create($resourceClass, $resourceData['resource'], array_merge([Crud::NO_PERMISSIONS, Crud::NO_VALIDATION, Options::REFRESH_UUID], $resSerializeOptions)); + $resource->setResourceNode($resourceNode); + + $importEvent = new ImportResourceEvent($resource, $fileBag, $resourceData); + $this->dispatcher->dispatch($importEvent, 'resource.'.$resourceNode->getType().'.import'); + + // replace workspace opening resource id by the new one + // this is for retro-compatibility, when we have stored the autoincrement id of the resource in the workspace options + // when using the UUID, replacement is automatically done in the serialized data + if (!empty($openingResourceId) && $resourceData['autoId'] === $openingResourceId) { + $workspace->getOptions()->setDetails(array_merge($workspaceOptions, [ + 'workspace_opening_resource' => $resourceNode->getUuid(), + ])); + } + + // we need the resources to be persisted in DB to be exploitable in listeners (e.g. path do a DB call to retrieve linked resources) + $this->om->forceFlush(); + } + + return []; + } + + private function recursiveExport(ResourceNode $resourceNode, FileBag $fileBag): array + { + $exported = []; + + $resource = $this->om->getRepository($resourceNode->getClass())->findOneBy(['resourceNode' => $resourceNode]); + if ($resource) { + // should be removed. It's only used by quizzes + $resSerializer = $this->serializer->get($resourceNode->getClass()); + $resSerializeOptions = method_exists($resSerializer, 'getCopyOptions') ? $resSerializer->getCopyOptions() : []; + + $exportEvent = new ExportResourceEvent($resource, $fileBag); + $this->dispatcher->dispatch($exportEvent, 'resource.'.$resourceNode->getType().'.export'); + + $exported[] = array_merge([ + 'resourceNode' => $this->serializer->serialize($resourceNode, [SerializerInterface::SERIALIZE_TRANSFER, Options::NO_RIGHTS]), + 'resource' => $this->serializer->serialize($resource, array_merge([SerializerInterface::SERIALIZE_TRANSFER], $resSerializeOptions)), + 'rights' => array_map(function (ResourceRights $rights) { + return $this->serializer->serialize($rights, [SerializerInterface::SERIALIZE_TRANSFER]); + }, $resourceNode->getRights()->toArray()), + ], $exportEvent->getData()); + + foreach ($resourceNode->getChildren() as $child) { + if ($child->isActive()) { + $exported = array_merge($exported, $this->recursiveExport($child, $fileBag)); + } + } + } + + return $exported; + } } diff --git a/src/main/core/Component/Tool/ResourcesTrashTool.php b/src/main/core/Component/Tool/ResourcesTrashTool.php new file mode 100644 index 00000000000..e69de29bb2d diff --git a/src/main/core/Component/Tool/TemplateTool.php b/src/main/core/Component/Tool/TemplateTool.php new file mode 100644 index 00000000000..e69de29bb2d diff --git a/src/main/core/Component/Tool/WorkspacesTool.php b/src/main/core/Component/Tool/WorkspacesTool.php new file mode 100644 index 00000000000..e69de29bb2d diff --git a/src/main/core/Controller/APINew/Location/MaterialController.php b/src/main/core/Controller/APINew/Location/MaterialController.php index 6b196acbdbc..d37f9cd6be4 100644 --- a/src/main/core/Controller/APINew/Location/MaterialController.php +++ b/src/main/core/Controller/APINew/Location/MaterialController.php @@ -13,10 +13,10 @@ use Claroline\AppBundle\API\Crud; use Claroline\AppBundle\Controller\AbstractCrudController; +use Claroline\CoreBundle\Component\Context\DesktopContext; use Claroline\CoreBundle\Entity\Location\Material; use Claroline\CoreBundle\Entity\Location\MaterialBooking; -use Claroline\CoreBundle\Entity\Tool\OrderedTool; -use Claroline\CoreBundle\Repository\Tool\OrderedToolRepository; +use Claroline\CoreBundle\Manager\Tool\ToolManager; use Claroline\CoreBundle\Security\PermissionCheckerTrait; use Sensio\Bundle\FrameworkExtraBundle\Configuration as EXT; use Symfony\Component\HttpFoundation\JsonResponse; @@ -31,11 +31,10 @@ class MaterialController extends AbstractCrudController { use PermissionCheckerTrait; - /** @var AuthorizationCheckerInterface */ - private $authorization; - - public function __construct(AuthorizationCheckerInterface $authorization) - { + public function __construct( + AuthorizationCheckerInterface $authorization, + private readonly ToolManager $toolManager + ) { $this->authorization = $authorization; } @@ -51,6 +50,7 @@ public function getClass(): string /** * @Route("/{material}/booking", name="apiv2_booking_material_book", methods={"POST"}) + * * @EXT\ParamConverter("material", class="Claroline\CoreBundle\Entity\Location\Material", options={"mapping": {"material": "uuid"}}) */ public function bookAction(Material $material, Request $request): JsonResponse @@ -72,6 +72,7 @@ public function bookAction(Material $material, Request $request): JsonResponse /** * @Route("/{material}/booking", name="apiv2_booking_material_list_booking", methods={"GET"}) + * * @EXT\ParamConverter("material", class="Claroline\CoreBundle\Entity\Location\Material", options={"mapping": {"material": "uuid"}}) */ public function listBookingAction(Material $material, Request $request): JsonResponse @@ -90,6 +91,7 @@ public function listBookingAction(Material $material, Request $request): JsonRes /** * @Route("/{$material}/booking", name="apiv2_booking_material_remove_booking", methods={"DELETE"}) + * * @EXT\ParamConverter("$material", class="Claroline\CoreBundle\Entity\Location\Material", options={"mapping": {"$material": "uuid"}}) */ public function deleteBookingAction(Material $material, Request $request): JsonResponse @@ -103,12 +105,9 @@ public function deleteBookingAction(Material $material, Request $request): JsonR return new JsonResponse(null, 204); } - private function canBook() + private function canBook(): void { - /** @var OrderedToolRepository $orderedToolRepo */ - $orderedToolRepo = $this->om->getRepository(OrderedTool::class); - - $bookingTool = $orderedToolRepo->findOneByNameAndDesktop('locations'); + $bookingTool = $this->toolManager->getOrderedTool('locations', DesktopContext::getName()); $this->checkPermission('BOOK', $bookingTool, [], true); } diff --git a/src/main/core/Controller/APINew/Log/LogConnectController.php b/src/main/core/Controller/APINew/Log/LogConnectController.php deleted file mode 100644 index 9a9f854b0cf..00000000000 --- a/src/main/core/Controller/APINew/Log/LogConnectController.php +++ /dev/null @@ -1,176 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Claroline\CoreBundle\Controller\APINew\Log; - -use Claroline\AppBundle\API\FinderProvider; -use Claroline\CoreBundle\Entity\Log\Connection\LogConnectPlatform; -use Claroline\CoreBundle\Entity\Log\Connection\LogConnectResource; -use Claroline\CoreBundle\Entity\Log\Connection\LogConnectWorkspace; -use Claroline\CoreBundle\Entity\Organization\Organization; -use Claroline\CoreBundle\Entity\Resource\ResourceNode; -use Claroline\CoreBundle\Entity\User; -use Claroline\CoreBundle\Entity\Workspace\Workspace; -use Claroline\CoreBundle\Manager\LogConnectManager; -use Claroline\CoreBundle\Manager\Tool\ToolManager; -use Claroline\CoreBundle\Security\ToolPermissions; -use Sensio\Bundle\FrameworkExtraBundle\Configuration as EXT; -use Symfony\Component\HttpFoundation\JsonResponse; -use Symfony\Component\HttpFoundation\Request; -use Symfony\Component\Routing\Annotation\Route; -use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface; -use Symfony\Component\Security\Core\Exception\AccessDeniedException; - -/** - * @Route("/log_connect") - */ -class LogConnectController -{ - /** @var AuthorizationCheckerInterface */ - private $authorization; - - /** @var FinderProvider */ - private $finder; - - /** @var LogConnectManager */ - private $logConnectManager; - - /** @var ToolManager */ - private $toolManager; - - /** - * CourseController constructor. - */ - public function __construct( - AuthorizationCheckerInterface $authorization, - FinderProvider $finder, - LogConnectManager $logConnectManager, - ToolManager $toolManager - ) { - $this->authorization = $authorization; - $this->finder = $finder; - $this->logConnectManager = $logConnectManager; - $this->toolManager = $toolManager; - } - - public function getName() - { - return 'log_connect_platform'; - } - - /** - * @Route( - * "/platform/list", - * name="apiv2_log_connect_platform_list" - * ) - * - * @EXT\ParamConverter("user", converter="current_user", options={"allowAnonymous"=false}) - */ - public function logConnectPlatformListAction(User $user, Request $request): JsonResponse - { - $this->checkAdminToolAccess(); - $isAdmin = $this->authorization->isGranted('ROLE_ADMIN'); - $hiddenFilters = $isAdmin ? - [] : - ['hiddenFilters' => [ - 'organizations' => array_map(function (Organization $organization) { - return $organization->getUuid(); - }, $user->getAdministratedOrganizations()->toArray()), - ]]; - - return new JsonResponse( - $this->finder->search(LogConnectPlatform::class, array_merge( - $request->query->all(), - $hiddenFilters - )) - ); - } - - /** - * @Route( - * "/workspace/{workspace}/list", - * name="apiv2_log_connect_workspace_list" - * ) - * - * @EXT\ParamConverter( - * "workspace", - * class="Claroline\CoreBundle\Entity\Workspace\Workspace", - * options={"mapping": {"workspace": "uuid"}} - * ) - * - * @return JsonResponse - */ - public function logConnectWorkspaceListAction(Workspace $workspace, Request $request) - { - $this->checkWorkspaceToolAccess($workspace); - - return new JsonResponse( - $this->finder->search(LogConnectWorkspace::class, array_merge( - $request->query->all(), - [ - 'hiddenFilters' => [ - 'workspace' => $workspace->getUuid(), - ], - ] - )) - ); - } - - /** - * @Route( - * "/resource/{resource}/list", - * name="apiv2_log_connect_resource_list" - * ) - * - * @EXT\ParamConverter( - * "resource", - * class="Claroline\CoreBundle\Entity\Resource\ResourceNode", - * options={"mapping": {"resource": "uuid"}} - * ) - * @EXT\ParamConverter("user", converter="current_user", options={"allowAnonymous"=false}) - * - * @return JsonResponse - */ - public function logConnectResourceListAction(ResourceNode $resource, User $user, Request $request) - { - $hiddenFilters = ['resource' => $resource->getUuid()]; - - if (!$this->authorization->isGranted('ADMINISTRATE', $resource->getWorkspace())) { - $hiddenFilters['user'] = $user->getUuid(); - } - - return new JsonResponse( - $this->finder->search(LogConnectResource::class, array_merge( - $request->query->all(), - ['hiddenFilters' => $hiddenFilters] - )) - ); - } - - /** - * @param string $rights - */ - private function checkAdminToolAccess($rights = 'OPEN') - { - $logsTool = $this->toolManager->getAdminToolByName('dashboard'); - - if (is_null($logsTool) || !$this->authorization->isGranted($rights, $logsTool)) { - throw new AccessDeniedException(); - } - } - - private function checkWorkspaceToolAccess(Workspace $workspace, ?string $permission = 'OPEN'): void - { - if (!$this->authorization->isGranted(ToolPermissions::getPermission('dashboard', $permission), $workspace)) { - throw new AccessDeniedException(); - } - } -} diff --git a/src/main/core/Controller/APINew/Workspace/WorkspaceController.php b/src/main/core/Controller/APINew/Workspace/WorkspaceController.php index 2d823b03e43..cfabdd469c9 100644 --- a/src/main/core/Controller/APINew/Workspace/WorkspaceController.php +++ b/src/main/core/Controller/APINew/Workspace/WorkspaceController.php @@ -14,7 +14,6 @@ use Claroline\AppBundle\Annotations\ApiDoc; use Claroline\AppBundle\API\Options; use Claroline\AppBundle\Controller\AbstractCrudController; -use Claroline\AppBundle\Event\StrictDispatcher; use Claroline\AppBundle\Manager\File\TempFileManager; use Claroline\AuthenticationBundle\Messenger\Stamp\AuthenticationStamp; use Claroline\CoreBundle\Controller\APINew\Model\HasGroupsTrait; @@ -24,9 +23,9 @@ use Claroline\CoreBundle\Entity\User; use Claroline\CoreBundle\Entity\Workspace\Workspace; use Claroline\CoreBundle\Library\Normalizer\TextNormalizer; -use Claroline\CoreBundle\Manager\LogConnectManager; use Claroline\CoreBundle\Manager\RoleManager; use Claroline\CoreBundle\Manager\Workspace\WorkspaceManager; +use Claroline\CoreBundle\Manager\Workspace\WorkspaceRestrictionsManager; use Claroline\CoreBundle\Messenger\Message\CopyWorkspace; use Claroline\CoreBundle\Messenger\Message\ImportWorkspace; use Claroline\CoreBundle\Security\PermissionCheckerTrait; @@ -49,32 +48,16 @@ class WorkspaceController extends AbstractCrudController use HasRolesTrait; use PermissionCheckerTrait; - private TokenStorageInterface $tokenStorage; - private StrictDispatcher $dispatcher; - private MessageBusInterface $messageBus; - private RoleManager $roleManager; - private WorkspaceManager $workspaceManager; - private LogConnectManager $logConnectManager; - private TempFileManager $tempManager; - public function __construct( - TokenStorageInterface $tokenStorage, + private readonly TokenStorageInterface $tokenStorage, AuthorizationCheckerInterface $authorization, - StrictDispatcher $dispatcher, - MessageBusInterface $messageBus, - RoleManager $roleManager, - WorkspaceManager $workspaceManager, - LogConnectManager $logConnectManager, - TempFileManager $tempManager + private readonly MessageBusInterface $messageBus, + private readonly TempFileManager $tempManager, + private readonly RoleManager $roleManager, + private readonly WorkspaceManager $workspaceManager, + private readonly WorkspaceRestrictionsManager $restrictionsManager ) { - $this->tokenStorage = $tokenStorage; $this->authorization = $authorization; - $this->dispatcher = $dispatcher; - $this->messageBus = $messageBus; - $this->roleManager = $roleManager; - $this->workspaceManager = $workspaceManager; - $this->logConnectManager = $logConnectManager; - $this->tempManager = $tempManager; } public function getName(): string @@ -365,6 +348,20 @@ public function unarchiveBulkAction(Request $request): JsonResponse }, $processed)); } + /** + * Submit access code. + * + * @Route("/unlock/{id}", name="claro_workspace_unlock", methods={"POST"}) + * + * @EXT\ParamConverter("workspace", options={"mapping": {"id": "uuid"}}) + */ + public function unlockAction(Workspace $workspace, Request $request): JsonResponse + { + $this->restrictionsManager->unlock($workspace, json_decode($request->getContent(), true)['code']); + + return new JsonResponse(null, 204); + } + /** * @Route("/{id}/users", name="apiv2_workspace_list_users", methods={"GET"}) * diff --git a/src/main/core/Controller/AdministrationController.php b/src/main/core/Controller/AdministrationController.php deleted file mode 100644 index 3eac9a01fad..00000000000 --- a/src/main/core/Controller/AdministrationController.php +++ /dev/null @@ -1,155 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Claroline\CoreBundle\Controller; - -use Claroline\AppBundle\Event\StrictDispatcher; -use Claroline\CoreBundle\Entity\Tool\AbstractTool; -use Claroline\CoreBundle\Entity\Tool\AdminTool; -use Claroline\CoreBundle\Entity\User; -use Claroline\CoreBundle\Event\CatalogEvents\ToolEvents; -use Claroline\CoreBundle\Event\Tool\OpenToolEvent; -use Claroline\CoreBundle\Manager\Tool\ToolManager; -use Symfony\Component\HttpFoundation\JsonResponse; -use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; -use Symfony\Component\Routing\Annotation\Route; -use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface; -use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface; -use Symfony\Component\Security\Core\Exception\AccessDeniedException; - -/** - * @Route("/admin", options={"expose"=true}) - */ -class AdministrationController -{ - /** @var AuthorizationCheckerInterface */ - private $authorization; - - /** @var TokenStorageInterface */ - private $tokenStorage; - - /** @var ToolManager */ - private $toolManager; - - /** @var StrictDispatcher */ - private $strictDispatcher; - - public function __construct( - AuthorizationCheckerInterface $authorization, - TokenStorageInterface $tokenStorage, - ToolManager $toolManager, - StrictDispatcher $strictDispatcher - ) { - $this->authorization = $authorization; - $this->toolManager = $toolManager; - $this->tokenStorage = $tokenStorage; - $this->strictDispatcher = $strictDispatcher; - } - - /** - * Opens the administration index. - * - * @Route("/", name="claro_admin_index") - * @Route("/", name="claro_admin_open") - * - * @return JsonResponse - * - * @throws AccessDeniedException - */ - public function openAction() - { - $tools = $this->toolManager->getAdminToolsByRoles($this->tokenStorage->getToken()->getRoleNames()); - if (0 === count($tools)) { - throw new AccessDeniedException(); - } - - return new JsonResponse([ - 'tools' => array_values(array_map(function (AdminTool $tool) { - return [ - 'icon' => $tool->getClass(), - 'name' => $tool->getName(), - ]; - }, $tools)), - ]); - } - - /** - * Opens an administration tool. - * - * @Route("/open/{toolName}", name="claro_admin_open_tool") - * - * @return JsonResponse - * - * @throws AccessDeniedException - */ - public function openToolAction($toolName) - { - $tool = $this->toolManager->getAdminToolByName($toolName); - if (!$tool) { - throw new NotFoundHttpException('Tool not found'); - } - - if (!$this->authorization->isGranted('OPEN', $tool)) { - throw new AccessDeniedException(); - } - - $currentUser = $this->tokenStorage->getToken()->getUser(); - $eventParams = [ - $toolName, - AbstractTool::ADMINISTRATION, - null, - $currentUser instanceof User ? $currentUser : null, - ]; - - $this->strictDispatcher->dispatch( - ToolEvents::OPEN, - OpenToolEvent::class, - $eventParams - ); - - /** @var OpenToolEvent $event */ - $event = $this->strictDispatcher->dispatch( - ToolEvents::getEventName(ToolEvents::OPEN, AbstractTool::ADMINISTRATION, $toolName), - OpenToolEvent::class, - $eventParams - ); - - return new JsonResponse(array_merge($event->getData(), [ - 'data' => [ - 'permissions' => [ - 'open' => $this->authorization->isGranted('OPEN', $tool), - 'edit' => $this->authorization->isGranted('EDIT', $tool), - ], - ], - ])); - } - - /** - * Lists admin tools accessible by the current user. - * - * @Route("/tools", name="claro_admin_tools") - * - * @return JsonResponse - */ - public function listToolsAction() - { - $tools = $this->toolManager->getAdminToolsByRoles($this->tokenStorage->getToken()->getRoleNames()); - - return new JsonResponse([ - 'tools' => array_values(array_map(function (AdminTool $tool) { - return [ - 'icon' => $tool->getClass(), - 'name' => $tool->getName(), - ]; - }, $tools)), - ]); - } -} diff --git a/src/main/core/Controller/WorkspaceController.php b/src/main/core/Controller/WorkspaceController.php deleted file mode 100644 index ce69fe31dba..00000000000 --- a/src/main/core/Controller/WorkspaceController.php +++ /dev/null @@ -1,182 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Claroline\CoreBundle\Controller; - -use Claroline\AppBundle\API\Serializer\SerializerInterface; -use Claroline\AppBundle\API\SerializerProvider; -use Claroline\AppBundle\Event\StrictDispatcher; -use Claroline\AppBundle\Persistence\ObjectManager; -use Claroline\CoreBundle\Entity\Resource\ResourceNode; -use Claroline\CoreBundle\Entity\Role; -use Claroline\CoreBundle\Entity\Tool\OrderedTool; -use Claroline\CoreBundle\Entity\User; -use Claroline\CoreBundle\Entity\Workspace\Shortcuts; -use Claroline\CoreBundle\Entity\Workspace\Workspace; -use Claroline\CoreBundle\Event\CatalogEvents\WorkspaceEvents; -use Claroline\CoreBundle\Event\Log\LogWorkspaceEnterEvent; -use Claroline\CoreBundle\Event\Workspace\OpenWorkspaceEvent; -use Claroline\CoreBundle\Manager\Tool\ToolManager; -use Claroline\CoreBundle\Manager\Workspace\WorkspaceManager; -use Claroline\CoreBundle\Manager\Workspace\WorkspaceRestrictionsManager; -use Claroline\EvaluationBundle\Manager\WorkspaceEvaluationManager; -use Sensio\Bundle\FrameworkExtraBundle\Configuration as EXT; -use Symfony\Component\HttpFoundation\JsonResponse; -use Symfony\Component\HttpFoundation\Request; -use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; -use Symfony\Component\Routing\Annotation\Route; -use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface; -use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface; - -/** - * @Route("/workspaces", options={"expose" = true}) - */ -class WorkspaceController -{ - /** @var AuthorizationCheckerInterface */ - private $authorization; - /** @var ObjectManager */ - private $om; - /** @var TokenStorageInterface */ - private $tokenStorage; - /** @var SerializerProvider */ - private $serializer; - /** @var ToolManager */ - private $toolManager; - /** @var WorkspaceManager */ - private $manager; - /** @var WorkspaceRestrictionsManager */ - private $restrictionsManager; - /** @var WorkspaceEvaluationManager */ - private $evaluationManager; - /** @var StrictDispatcher */ - private $strictDispatcher; - - public function __construct( - AuthorizationCheckerInterface $authorization, - ObjectManager $om, - TokenStorageInterface $tokenStorage, - SerializerProvider $serializer, - ToolManager $toolManager, - WorkspaceManager $manager, - WorkspaceRestrictionsManager $restrictionsManager, - WorkspaceEvaluationManager $evaluationManager, - StrictDispatcher $strictDispatcher - ) { - $this->authorization = $authorization; - $this->om = $om; - $this->tokenStorage = $tokenStorage; - $this->serializer = $serializer; - $this->toolManager = $toolManager; - $this->manager = $manager; - $this->restrictionsManager = $restrictionsManager; - $this->evaluationManager = $evaluationManager; - $this->strictDispatcher = $strictDispatcher; - } - - /** - * @Route("/{slug}", name="claro_workspace_open") - * - * @EXT\ParamConverter("user", converter="current_user", options={"allowAnonymous"=true}) - */ - public function openAction(string $slug, User $user = null): JsonResponse - { - /** @var Workspace $workspace */ - $workspace = $this->om->getRepository(Workspace::class)->findOneBy(['slug' => $slug]); - - if (!$workspace) { - throw new NotFoundHttpException('Workspace not found'); - } - - // this should not be done here - $this->toolManager->addMissingWorkspaceTools($workspace); - - $isManager = $this->manager->isManager($workspace, $this->tokenStorage->getToken()); - $accessErrors = $this->restrictionsManager->getErrors($workspace, $user); - if (empty($accessErrors) || $isManager) { - $this->strictDispatcher->dispatch( - WorkspaceEvents::OPEN, - OpenWorkspaceEvent::class, - [$workspace] - ); - - // Log workspace opening - $this->strictDispatcher->dispatch( - 'log', - LogWorkspaceEnterEvent::class, - [$workspace] - ); - - $userEvaluation = null; - if ($user) { - $userEvaluation = $this->serializer->serialize( - $this->evaluationManager->getUserEvaluation($workspace, $user), - [SerializerInterface::SERIALIZE_MINIMAL] - ); - } - - return new JsonResponse([ - 'workspace' => $this->serializer->serialize($workspace), - 'managed' => $isManager, - 'impersonated' => $this->manager->isImpersonated($this->tokenStorage->getToken()), - // the list of current workspace roles the user owns - 'roles' => array_map(function (Role $role) { - return $this->serializer->serialize($role, [SerializerInterface::SERIALIZE_MINIMAL]); - }, $this->manager->getTokenRoles($this->tokenStorage->getToken(), $workspace)), - // append access restrictions to the loaded data if any - // to let the manager knows that other users can not enter the workspace - 'accessErrors' => $accessErrors, - 'userEvaluation' => $userEvaluation, - // get the list of enabled workspace tool - 'tools' => array_values(array_map(function (OrderedTool $orderedTool) { - return $this->serializer->serialize($orderedTool, [SerializerInterface::SERIALIZE_MINIMAL]); - }, $this->toolManager->getOrderedToolsByWorkspace($workspace))), - // do not expose root resource here (used in the WS to configure opening target) - 'root' => $this->serializer->serialize($this->om->getRepository(ResourceNode::class)->findOneBy(['workspace' => $workspace, 'parent' => null]), [SerializerInterface::SERIALIZE_MINIMAL]), - // TODO : only export current user shortcuts (we get all roles for the configuration in community/editor) - // 'shortcuts' => $this->manager->getShortcuts($workspace, $this->tokenStorage->getToken()->getRoleNames()), - 'shortcuts' => array_values(array_map(function (Shortcuts $shortcuts) { - return $this->serializer->serialize($shortcuts); - }, $workspace->getShortcuts()->toArray())), - ]); - } - - $statusCode = 403; - if (!$workspace->getSelfRegistration() && !$this->authorization->isGranted('IS_AUTHENTICATED_FULLY') && !$this->restrictionsManager->hasRights($workspace)) { - // let the API handles the access error - $statusCode = 401; - } - - // return the details of access errors to display it to users - return new JsonResponse([ - 'impersonated' => $this->manager->isImpersonated($this->tokenStorage->getToken()), - 'roles' => array_map(function (Role $role) { - return $this->serializer->serialize($role, [SerializerInterface::SERIALIZE_MINIMAL]); - }, $this->manager->getTokenRoles($this->tokenStorage->getToken(), $workspace)), - 'workspace' => $this->serializer->serialize($workspace), - 'accessErrors' => $accessErrors, - ], $statusCode); - } - - /** - * Submit access code. - * - * @Route("/unlock/{id}", name="claro_workspace_unlock", methods={"POST"}) - * - * @EXT\ParamConverter("workspace", class="Claroline\CoreBundle\Entity\Workspace\Workspace", options={"mapping": {"id": "uuid"}}) - */ - public function unlockAction(Workspace $workspace, Request $request): JsonResponse - { - $this->restrictionsManager->unlock($workspace, json_decode($request->getContent(), true)['code']); - - return new JsonResponse(null, 204); - } -} diff --git a/src/main/core/DependencyInjection/ClarolineCoreExtension.php b/src/main/core/DependencyInjection/ClarolineCoreExtension.php index d089f19bc48..e20b9e711ff 100644 --- a/src/main/core/DependencyInjection/ClarolineCoreExtension.php +++ b/src/main/core/DependencyInjection/ClarolineCoreExtension.php @@ -21,7 +21,7 @@ */ class ClarolineCoreExtension extends Extension { - public function load(array $configs, ContainerBuilder $container) + public function load(array $configs, ContainerBuilder $container): void { $locator = new FileLocator(__DIR__.'/../Resources/config'); $loader = new YamlFileLoader($container, $locator); diff --git a/src/main/core/Entity/Log/Connection/AbstractLogConnect.php b/src/main/core/Entity/Log/Connection/AbstractLogConnect.php deleted file mode 100644 index 3e99c8bc84c..00000000000 --- a/src/main/core/Entity/Log/Connection/AbstractLogConnect.php +++ /dev/null @@ -1,94 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Claroline\CoreBundle\Entity\Log\Connection; - -use Claroline\AppBundle\Entity\Identifier\Id; -use Claroline\AppBundle\Entity\Identifier\Uuid; -use Claroline\CoreBundle\Entity\User; -use Doctrine\ORM\Mapping as ORM; - -/** - * @ORM\MappedSuperclass - */ -abstract class AbstractLogConnect -{ - use Id; - use Uuid; - - /** - * @ORM\ManyToOne(targetEntity="Claroline\CoreBundle\Entity\User") - * @ORM\JoinColumn(name="user_id", onDelete="CASCADE") - */ - protected $user; - - /** - * @ORM\Column(name="connection_date", type="datetime") - */ - protected $connectionDate; - - /** - * @ORM\Column(name="total_duration", type="integer", nullable=true) - */ - protected $duration; - - /** - * AbstractLogConnect constructor. - */ - public function __construct() - { - $this->refreshUuid(); - - $this->connectionDate = new \DateTime(); - } - - /** - * @return User - */ - public function getUser() - { - return $this->user; - } - - public function setUser(User $user) - { - $this->user = $user; - } - - /** - * @return \DateTime - */ - public function getConnectionDate() - { - return $this->connectionDate; - } - - public function setConnectionDate(\DateTime $connectionDate) - { - $this->connectionDate = $connectionDate; - } - - /** - * @return int - */ - public function getDuration() - { - return $this->duration; - } - - /** - * @param int $duration - */ - public function setDuration($duration) - { - $this->duration = $duration; - } -} diff --git a/src/main/core/Entity/Log/Connection/LogConnectAdminTool.php b/src/main/core/Entity/Log/Connection/LogConnectAdminTool.php deleted file mode 100644 index 79ea675fa57..00000000000 --- a/src/main/core/Entity/Log/Connection/LogConnectAdminTool.php +++ /dev/null @@ -1,69 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Claroline\CoreBundle\Entity\Log\Connection; - -use Claroline\CoreBundle\Entity\Tool\AdminTool; -use Doctrine\ORM\Mapping as ORM; - -/** - * @ORM\Entity - * @ORM\Table(name="claro_log_connect_admin_tool") - */ -class LogConnectAdminTool extends AbstractLogConnect -{ - /** - * @ORM\ManyToOne(targetEntity="Claroline\CoreBundle\Entity\Tool\AdminTool") - * @ORM\JoinColumn(name="tool_id", onDelete="SET NULL", nullable=true) - */ - protected $tool; - - /** - * @ORM\Column(name="tool_name") - */ - protected $toolName; - - /** - * @return AdminTool - */ - public function getTool() - { - return $this->tool; - } - - /** - * @param AdminTool $tool - */ - public function setTool(AdminTool $tool = null) - { - $this->tool = $tool; - - if ($tool) { - $this->setToolName($tool->getName()); - } - } - - /** - * @return string - */ - public function getToolName() - { - return $this->toolName; - } - - /** - * @param string $toolName - */ - public function setToolName($toolName) - { - $this->toolName = $toolName; - } -} diff --git a/src/main/core/Entity/Log/Connection/LogConnectPlatform.php b/src/main/core/Entity/Log/Connection/LogConnectPlatform.php deleted file mode 100644 index 03fd808d3f2..00000000000 --- a/src/main/core/Entity/Log/Connection/LogConnectPlatform.php +++ /dev/null @@ -1,22 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Claroline\CoreBundle\Entity\Log\Connection; - -use Doctrine\ORM\Mapping as ORM; - -/** - * @ORM\Entity(repositoryClass="Claroline\CoreBundle\Repository\Log\Connection\LogConnectPlatformRepository") - * @ORM\Table(name="claro_log_connect_platform") - */ -class LogConnectPlatform extends AbstractLogConnect -{ -} diff --git a/src/main/core/Entity/Log/Connection/LogConnectResource.php b/src/main/core/Entity/Log/Connection/LogConnectResource.php deleted file mode 100644 index 158cb109381..00000000000 --- a/src/main/core/Entity/Log/Connection/LogConnectResource.php +++ /dev/null @@ -1,112 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Claroline\CoreBundle\Entity\Log\Connection; - -use Claroline\CoreBundle\Entity\Resource\ResourceNode; -use Doctrine\ORM\Mapping as ORM; - -/** - * @ORM\Entity(repositoryClass="Claroline\CoreBundle\Repository\Log\Connection\LogConnectResourceRepository") - * @ORM\Table(name="claro_log_connect_resource") - */ -class LogConnectResource extends AbstractLogConnect -{ - /** - * @ORM\ManyToOne(targetEntity="Claroline\CoreBundle\Entity\Resource\ResourceNode") - * @ORM\JoinColumn(name="resource_id", onDelete="SET NULL", nullable=true) - */ - protected $resource; - - /** - * @ORM\Column(name="resource_name") - */ - protected $resourceName; - - /** - * @ORM\Column(name="resource_type") - */ - protected $resourceType; - - /** - * @ORM\Column(name="embedded", type="boolean") - */ - protected $embedded = false; - - /** - * @return ResourceNode - */ - public function getResource() - { - return $this->resource; - } - - /** - * @param ResourceNode $resource - */ - public function setResource(ResourceNode $resource = null) - { - $this->resource = $resource; - - if ($resource) { - $this->setResourceName($resource->getName()); - $this->setResourceType($resource->getResourceType()->getName()); - } - } - - /** - * @return string - */ - public function getResourceName() - { - return $this->resourceName; - } - - /** - * @param string $resourceName - */ - public function setResourceName($resourceName) - { - $this->resourceName = $resourceName; - } - - /** - * @return string - */ - public function getResourceType() - { - return $this->resourceType; - } - - /** - * @param string $resourceType - */ - public function setResourceType($resourceType) - { - $this->resourceType = $resourceType; - } - - /** - * @return bool - */ - public function isEmbedded() - { - return $this->embedded; - } - - /** - * @param bool $embedded - */ - public function setEmbedded($embedded) - { - $this->embedded = $embedded; - } -} diff --git a/src/main/core/Entity/Log/Connection/LogConnectTool.php b/src/main/core/Entity/Log/Connection/LogConnectTool.php deleted file mode 100644 index 8cb4cf52f13..00000000000 --- a/src/main/core/Entity/Log/Connection/LogConnectTool.php +++ /dev/null @@ -1,146 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Claroline\CoreBundle\Entity\Log\Connection; - -use Claroline\CoreBundle\Entity\Tool\OrderedTool; -use Claroline\CoreBundle\Entity\Workspace\Workspace; -use Doctrine\ORM\Mapping as ORM; - -/** - * @ORM\Entity - * @ORM\Table(name="claro_log_connect_tool") - */ -class LogConnectTool extends AbstractLogConnect -{ - /** - * @ORM\ManyToOne(targetEntity="Claroline\CoreBundle\Entity\Tool\OrderedTool") - * @ORM\JoinColumn(name="tool_id", onDelete="SET NULL", nullable=true) - */ - protected $tool; - - /** - * @ORM\Column(name="tool_name") - */ - protected $toolName; - - /** - * @ORM\Column(name="original_tool_name") - */ - protected $originalToolName; - - /** - * @ORM\ManyToOne(targetEntity="Claroline\CoreBundle\Entity\Workspace\Workspace") - * @ORM\JoinColumn(name="workspace_id", onDelete="SET NULL", nullable=true) - */ - protected $workspace; - - /** - * @ORM\Column(name="workspace_name", nullable=true) - */ - protected $workspaceName; - - /** - * @return OrderedTool - */ - public function getTool() - { - return $this->tool; - } - - /** - * @param OrderedTool $tool - */ - public function setTool(OrderedTool $tool = null) - { - $this->tool = $tool; - - if ($tool) { - $this->setToolName($tool->getTool()->getName()); - $this->setOrignalToolName($tool->getTool()->getName()); - - $workspace = $tool->getWorkspace(); - - if ($workspace) { - $this->setWorkspace($workspace); - $this->setWorkspaceName($tool->getWorkspace()->getName()); - } - } - } - - /** - * @return string - */ - public function getToolName() - { - return $this->toolName; - } - - /** - * @param string $toolName - */ - public function setToolName($toolName) - { - $this->toolName = $toolName; - } - - /** - * @return string - */ - public function getOrignalToolName() - { - return $this->originalToolName; - } - - /** - * @param string $originalToolName - */ - public function setOrignalToolName($originalToolName) - { - $this->originalToolName = $originalToolName; - } - - /** - * @return Workspace - */ - public function getWorkspace() - { - return $this->workspace; - } - - /** - * @param Workspace $workspace - */ - public function setWorkspace(Workspace $workspace = null) - { - $this->workspace = $workspace; - - if ($workspace) { - $this->setWorkspaceName($workspace->getName()); - } - } - - /** - * @return string - */ - public function getWorkspaceName() - { - return $this->workspaceName; - } - - /** - * @param string $workspaceName - */ - public function setWorkspaceName($workspaceName) - { - $this->workspaceName = $workspaceName; - } -} diff --git a/src/main/core/Entity/Log/Connection/LogConnectWorkspace.php b/src/main/core/Entity/Log/Connection/LogConnectWorkspace.php deleted file mode 100644 index 0ebf60d0a60..00000000000 --- a/src/main/core/Entity/Log/Connection/LogConnectWorkspace.php +++ /dev/null @@ -1,69 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Claroline\CoreBundle\Entity\Log\Connection; - -use Claroline\CoreBundle\Entity\Workspace\Workspace; -use Doctrine\ORM\Mapping as ORM; - -/** - * @ORM\Entity(repositoryClass="Claroline\CoreBundle\Repository\Log\Connection\LogConnectWorkspaceRepository") - * @ORM\Table(name="claro_log_connect_workspace") - */ -class LogConnectWorkspace extends AbstractLogConnect -{ - /** - * @ORM\ManyToOne(targetEntity="Claroline\CoreBundle\Entity\Workspace\Workspace") - * @ORM\JoinColumn(name="workspace_id", onDelete="SET NULL", nullable=true) - */ - protected $workspace; - - /** - * @ORM\Column(name="workspace_name") - */ - protected $workspaceName; - - /** - * @return Workspace - */ - public function getWorkspace() - { - return $this->workspace; - } - - /** - * @param Workspace $workspace - */ - public function setWorkspace(Workspace $workspace = null) - { - $this->workspace = $workspace; - - if ($workspace) { - $this->setWorkspaceName($workspace->getName()); - } - } - - /** - * @return string - */ - public function getWorkspaceName() - { - return $this->workspaceName; - } - - /** - * @param string $workspaceName - */ - public function setWorkspaceName($workspaceName) - { - $this->workspaceName = $workspaceName; - } -} diff --git a/src/main/core/Entity/Tool/OrderedTool.php b/src/main/core/Entity/Tool/OrderedTool.php index 1552e634fd9..40eb432f875 100644 --- a/src/main/core/Entity/Tool/OrderedTool.php +++ b/src/main/core/Entity/Tool/OrderedTool.php @@ -11,14 +11,13 @@ namespace Claroline\CoreBundle\Entity\Tool; +use Claroline\AppBundle\Entity\Display\Hidden; +use Claroline\AppBundle\Entity\Display\Order; +use Claroline\AppBundle\Entity\Display\Poster; +use Claroline\AppBundle\Entity\Display\Thumbnail; +use Claroline\AppBundle\Entity\HasContext; use Claroline\AppBundle\Entity\Identifier\Id; use Claroline\AppBundle\Entity\Identifier\Uuid; -use Claroline\AppBundle\Entity\Meta\Order; -use Claroline\AppBundle\Entity\Meta\Poster; -use Claroline\AppBundle\Entity\Meta\Thumbnail; -use Claroline\AppBundle\Entity\Restriction\Hidden; -use Claroline\CoreBundle\Entity\User; -use Claroline\CoreBundle\Entity\Workspace\Workspace; use Doctrine\Common\Collections\ArrayCollection; use Doctrine\ORM\Mapping as ORM; use Symfony\Bridge\Doctrine\Validator\Constraints as DoctrineAssert; @@ -26,34 +25,26 @@ /** * @ORM\Entity(repositoryClass="Claroline\CoreBundle\Repository\Tool\OrderedToolRepository") * - * @ORM\Table( - * name="claro_ordered_tool", - * uniqueConstraints={ + * @ORM\Table(name="claro_ordered_tool") * - * @ORM\UniqueConstraint( - * name="ordered_tool_unique_tool_user_type", - * columns={"tool_id", "user_id"} - * ), - * @ORM\UniqueConstraint( - * name="ordered_tool_unique_tool_ws_type", - * columns={"tool_id", "workspace_id"} - * ) - * } - * ) - * - * @DoctrineAssert\UniqueEntity({"tool", "workspace"}) - * @DoctrineAssert\UniqueEntity({"tool", "user"}) + * @DoctrineAssert\UniqueEntity({"tool", "contextName", "contextId"}) */ class OrderedTool { use Id; use Uuid; + use HasContext; // meta use Thumbnail; use Poster; use Order; use Hidden; + /** + * @ORM\Column(name="tool_name", type="string", nullable=false) + */ + private ?string $name; + /** * Display tool icon when the tool is rendered. * @@ -68,42 +59,6 @@ class OrderedTool */ private bool $fullscreen = false; - /** - * @ORM\ManyToOne( - * targetEntity="Claroline\CoreBundle\Entity\Workspace\Workspace", - * cascade={"persist", "merge"}, - * inversedBy="orderedTools" - * ) - * - * @ORM\JoinColumn(onDelete="CASCADE") - * - * @var Workspace - */ - private $workspace; - - /** - * @ORM\ManyToOne( - * targetEntity="Claroline\CoreBundle\Entity\Tool\Tool" - * ) - * - * @ORM\JoinColumn(nullable=false, onDelete="CASCADE") - * - * @var Tool - */ - private $tool; - - /** - * @ORM\ManyToOne( - * targetEntity="Claroline\CoreBundle\Entity\User", - * cascade={"persist"} - * ) - * - * @ORM\JoinColumn(onDelete="CASCADE") - * - * @var User - */ - private $user; - /** * @ORM\OneToMany( * targetEntity="Claroline\CoreBundle\Entity\Tool\ToolRights", @@ -121,28 +76,24 @@ public function __construct() $this->rights = new ArrayCollection(); } - public function __toString() + public function getName(): string { - if (!empty($this->workspace)) { - return '['.$this->workspace->getName().'] '.$this->tool->getName(); - } - - return $this->tool->getName(); + return $this->name; } - public function getShowIcon() + public function setName(string $name): void { - return $this->showIcon; + $this->name = $name; } - public function setShowIcon($showIcon) + public function getShowIcon(): bool { - $this->showIcon = $showIcon; + return $this->showIcon; } - public function setFullscreen(bool $fullscreen) + public function setShowIcon(bool $showIcon): void { - $this->fullscreen = $fullscreen; + $this->showIcon = $showIcon; } public function getFullscreen(): bool @@ -150,43 +101,9 @@ public function getFullscreen(): bool return $this->fullscreen; } - public function setWorkspace(Workspace $ws = null) + public function setFullscreen(bool $fullscreen): void { - $this->workspace = $ws; - } - - /** - * @return Workspace - */ - public function getWorkspace() - { - return $this->workspace; - } - - public function setTool(Tool $tool) - { - $this->tool = $tool; - } - - /** - * @return Tool - */ - public function getTool() - { - return $this->tool; - } - - public function setUser(User $user = null) - { - $this->user = $user; - } - - /** - * @return User - */ - public function getUser() - { - return $this->user; + $this->fullscreen = $fullscreen; } /** @@ -197,14 +114,15 @@ public function getRights() return $this->rights; } - public function addRight(ToolRights $right) + public function addRight(ToolRights $right): void { if (!$this->rights->contains($right)) { $this->rights->add($right); + $right->setOrderedTool($this); } } - public function removeRight(ToolRights $right) + public function removeRight(ToolRights $right): void { if ($this->rights->contains($right)) { $this->rights->removeElement($right); diff --git a/src/main/core/Entity/Tool/ToolMaskDecoder.php b/src/main/core/Entity/Tool/ToolMaskDecoder.php index 7060aa57a32..5243075350b 100644 --- a/src/main/core/Entity/Tool/ToolMaskDecoder.php +++ b/src/main/core/Entity/Tool/ToolMaskDecoder.php @@ -23,7 +23,7 @@ * * @ORM\UniqueConstraint( * name="tool_mask_decoder_unique_tool_and_name", - * columns={"tool_id", "name"} + * columns={"tool_name", "name"} * ) * }) */ @@ -41,53 +41,44 @@ class ToolMaskDecoder /** * @ORM\Column(type="integer") */ - protected $value; + private int $value; /** * @ORM\Column() */ - protected $name; + protected string $name; /** - * @ORM\ManyToOne( - * targetEntity="Claroline\CoreBundle\Entity\Tool\Tool", - * inversedBy="maskDecoders", - * cascade={"persist"} - * ) - * - * @ORM\JoinColumn(name="tool_id", onDelete="CASCADE", nullable=false) + * @ORM\Column(name="tool_name", nullable=false) */ - protected $tool; + protected string $tool; - public function getValue() + public function getValue(): int { return $this->value; } - public function setValue($value) + public function setValue($value): void { $this->value = $value; } - public function getName() + public function getName(): string { return $this->name; } - public function setName($name) + public function setName($name): void { $this->name = $name; } - /** - * @return Tool - */ - public function getTool() + public function getTool(): string { return $this->tool; } - public function setTool(Tool $tool) + public function setTool(string $tool): void { $this->tool = $tool; } diff --git a/src/main/core/Entity/Tool/ToolRights.php b/src/main/core/Entity/Tool/ToolRights.php index a026ab36156..e92ca7143ea 100644 --- a/src/main/core/Entity/Tool/ToolRights.php +++ b/src/main/core/Entity/Tool/ToolRights.php @@ -11,14 +11,17 @@ namespace Claroline\CoreBundle\Entity\Tool; +use Claroline\AppBundle\Entity\Identifier\Id; use Claroline\CoreBundle\Entity\Role; use Doctrine\ORM\Mapping as ORM; /** * @ORM\Entity(repositoryClass="Claroline\CoreBundle\Repository\Tool\ToolRightsRepository") + * * @ORM\Table( * name="claro_tool_rights", * uniqueConstraints={ + * * @ORM\UniqueConstraint( * name="tool_rights_unique_ordered_tool_role", * columns={"ordered_tool_id", "role_id"} @@ -28,26 +31,22 @@ */ class ToolRights { - /** - * @ORM\Id - * @ORM\Column(type="integer") - * @ORM\GeneratedValue(strategy="AUTO") - */ - protected $id; + use Id; /** * @ORM\Column(type="integer") */ - protected $mask = 0; + private int $mask = 0; /** * @ORM\ManyToOne( * targetEntity="Claroline\CoreBundle\Entity\Role", * inversedBy="toolRights" * ) + * * @ORM\JoinColumn(name="role_id", nullable=false, onDelete="CASCADE") */ - protected $role; + private Role $role; /** * @ORM\ManyToOne( @@ -55,58 +54,40 @@ class ToolRights * inversedBy="rights", * cascade={"persist"} * ) + * * @ORM\JoinColumn(name="ordered_tool_id", nullable=false, onDelete="CASCADE") */ - protected $orderedTool; + private OrderedTool $orderedTool; - /** - * @return int - */ - public function getId() - { - return $this->id; - } - - /** - * @return int - */ - public function getMask() + public function getMask(): int { return $this->mask; } - /** - * @return Role - */ - public function getRole() + public function setMask(int $mask): void { - return $this->role; - } - - /** - * @return OrderedTool - */ - public function getOrderedTool() - { - return $this->orderedTool; + $this->mask = $mask; } - public function setId($id) + public function getRole(): Role { - $this->id = $id; + return $this->role; } - public function setMask($mask) + public function setRole(Role $role): void { - $this->mask = $mask; + $this->role = $role; } - public function setRole(Role $role) + public function getOrderedTool(): OrderedTool { - $this->role = $role; + return $this->orderedTool; } - public function setOrderedTool(OrderedTool $orderedTool) + /** + * @internal + */ + public function setOrderedTool(OrderedTool $orderedTool): void { $this->orderedTool = $orderedTool; } diff --git a/src/main/core/Entity/User.php b/src/main/core/Entity/User.php index a0c775251ff..ca8cb9f3fc4 100644 --- a/src/main/core/Entity/User.php +++ b/src/main/core/Entity/User.php @@ -11,6 +11,7 @@ namespace Claroline\CoreBundle\Entity; +use Claroline\AppBundle\Component\Context\ContextSubjectInterface; use Claroline\AppBundle\Entity\IdentifiableInterface; use Claroline\AppBundle\Entity\Identifier\Id; use Claroline\AppBundle\Entity\Identifier\Uuid; @@ -42,7 +43,7 @@ * @ORM\Index(name="is_removed", columns={"is_removed"}) * }) */ -class User extends AbstractRoleSubject implements UserInterface, EquatableInterface, PasswordAuthenticatedUserInterface, LegacyPasswordAuthenticatedUserInterface, IdentifiableInterface +class User extends AbstractRoleSubject implements UserInterface, EquatableInterface, PasswordAuthenticatedUserInterface, LegacyPasswordAuthenticatedUserInterface, IdentifiableInterface, ContextSubjectInterface { use Id; use Uuid; @@ -353,6 +354,11 @@ public function getUserIdentifier(): string return $this->username; } + public function getContextIdentifier(): string + { + return $this->uuid; + } + public function getFirstName(): ?string { return $this->firstName; diff --git a/src/main/core/Entity/Workspace/Workspace.php b/src/main/core/Entity/Workspace/Workspace.php index a01df19cc98..ea02bca7aae 100644 --- a/src/main/core/Entity/Workspace/Workspace.php +++ b/src/main/core/Entity/Workspace/Workspace.php @@ -11,6 +11,7 @@ namespace Claroline\CoreBundle\Entity\Workspace; +use Claroline\AppBundle\Component\Context\ContextSubjectInterface; use Claroline\AppBundle\Entity\IdentifiableInterface; use Claroline\AppBundle\Entity\Identifier\Code; use Claroline\AppBundle\Entity\Identifier\Id; @@ -45,7 +46,7 @@ * @ORM\Index(name="name_idx", columns={"entity_name"}) * }) */ -class Workspace implements IdentifiableInterface +class Workspace implements IdentifiableInterface, ContextSubjectInterface { // identifiers use Id; @@ -261,6 +262,11 @@ public function __toString(): string return $this->name.' ['.$this->code.']'; } + public function getContextIdentifier(): string + { + return $this->uuid; + } + public function getSlug(): ?string { return $this->slug; diff --git a/src/main/core/Event/Tool/AbstractToolEvent.php b/src/main/core/Event/Tool/AbstractToolEvent.php index dd6ef12a49b..9e82db4e61f 100644 --- a/src/main/core/Event/Tool/AbstractToolEvent.php +++ b/src/main/core/Event/Tool/AbstractToolEvent.php @@ -11,23 +11,20 @@ namespace Claroline\CoreBundle\Event\Tool; -use Claroline\CoreBundle\Entity\Workspace\Workspace; +use Claroline\AppBundle\Component\Context\ContextSubjectInterface; use Symfony\Contracts\EventDispatcher\Event; abstract class AbstractToolEvent extends Event { - /** @var string */ - private $toolName; - /** @var string */ - private $context; - /** @var Workspace */ - private $workspace; - - public function __construct(string $toolName, string $context, ?Workspace $workspace = null) + private string $toolName; + private string $context; + private ?ContextSubjectInterface $contextSubject = null; + + public function __construct(string $toolName, string $context, ContextSubjectInterface $contextSubject = null) { $this->toolName = $toolName; $this->context = $context; - $this->workspace = $workspace; + $this->contextSubject = $contextSubject; } public function getToolName(): string @@ -40,8 +37,16 @@ public function getContext(): string return $this->context; } - public function getWorkspace(): ?Workspace + public function getContextSubject(): ?ContextSubjectInterface + { + return $this->contextSubject; + } + + /** + * @deprecated use getContextSubject() instead + */ + public function getWorkspace(): ?ContextSubjectInterface { - return $this->workspace; + return $this->getContextSubject(); } } diff --git a/src/main/core/Event/Tool/ExportToolEvent.php b/src/main/core/Event/Tool/ExportToolEvent.php index 4caad9d410e..2960f0c2e9c 100644 --- a/src/main/core/Event/Tool/ExportToolEvent.php +++ b/src/main/core/Event/Tool/ExportToolEvent.php @@ -8,24 +8,22 @@ class ExportToolEvent extends AbstractToolEvent { - /** @var FileBag */ - private $fileBag; + private FileBag $fileBag; - /** @var array */ - private $data = []; + private array $data = []; public function __construct( string $toolName, string $context, - ?Workspace $workspace = null, - ?FileBag $fileBag = null + Workspace $workspace = null, + FileBag $fileBag = null ) { parent::__construct($toolName, $context, $workspace); $this->fileBag = $fileBag ?? new FileBag(); } - public function setData(?array $data = []) + public function setData(?array $data = []): void { $this->data = $data; } @@ -35,7 +33,7 @@ public function getData(): array return $this->data; } - public function addFile($path, $file) + public function addFile($path, $file): void { $this->fileBag->add($path, $file); } @@ -45,7 +43,7 @@ public function getFileBag(): FileBag return $this->fileBag; } - public function overwrite($key, $value) + public function overwrite($key, $value): void { ArrayUtils::set($this->data, $key, $value); } diff --git a/src/main/core/Event/Tool/ImportToolEvent.php b/src/main/core/Event/Tool/ImportToolEvent.php index 6e1b6309704..181cbedc3ca 100644 --- a/src/main/core/Event/Tool/ImportToolEvent.php +++ b/src/main/core/Event/Tool/ImportToolEvent.php @@ -7,28 +7,23 @@ class ImportToolEvent extends AbstractToolEvent { - /** @var FileBag */ - private $fileBag; + private FileBag $fileBag; /** * The serialized data to import. - * - * @var array */ - private $data; + private array $data; /** * The list of entities created by the import. Keys are the old UUIDs of the entities. - * - * @var array */ - private $entities; + private array $entities; public function __construct( string $toolName, string $context, - ?Workspace $workspace = null, - ?FileBag $fileBag = null, + Workspace $workspace = null, + FileBag $fileBag = null, ?array $data = [], ?array $entities = [] ) { @@ -59,7 +54,7 @@ public function getCreatedEntities(): array return $this->entities; } - public function getCreatedEntity(string $oldUuid) + public function getCreatedEntity(string $oldUuid): mixed { if (!empty($this->entities[$oldUuid])) { return $this->entities[$oldUuid]; @@ -68,7 +63,7 @@ public function getCreatedEntity(string $oldUuid) return null; } - public function addCreatedEntity(string $oldUuid, $entity) + public function addCreatedEntity(string $oldUuid, $entity): void { $this->entities[$oldUuid] = $entity; } diff --git a/src/main/core/Event/Tool/OpenToolEvent.php b/src/main/core/Event/Tool/OpenToolEvent.php index 8e2adc0dbf3..54de45848f9 100644 --- a/src/main/core/Event/Tool/OpenToolEvent.php +++ b/src/main/core/Event/Tool/OpenToolEvent.php @@ -11,8 +11,8 @@ namespace Claroline\CoreBundle\Event\Tool; +use Claroline\AppBundle\Component\Context\ContextSubjectInterface; use Claroline\CoreBundle\Entity\User; -use Claroline\CoreBundle\Entity\Workspace\Workspace; use Symfony\Contracts\Translation\TranslatorInterface; class OpenToolEvent extends AbstractToolEvent @@ -23,10 +23,10 @@ class OpenToolEvent extends AbstractToolEvent public function __construct( string $toolName, string $context, - Workspace $workspace = null, + ContextSubjectInterface $contextSubject = null, User $user = null ) { - parent::__construct($toolName, $context, $workspace); + parent::__construct($toolName, $context, $contextSubject); $this->user = $user; } diff --git a/src/main/core/Installation/ClarolineCoreInstaller.php b/src/main/core/Installation/ClarolineCoreInstaller.php index 6cb202dafb3..58ab91c343c 100644 --- a/src/main/core/Installation/ClarolineCoreInstaller.php +++ b/src/main/core/Installation/ClarolineCoreInstaller.php @@ -13,6 +13,7 @@ use Claroline\CoreBundle\Installation\Updater\Updater140000; use Claroline\CoreBundle\Installation\Updater\Updater140010; +use Claroline\CoreBundle\Installation\Updater\Updater140100; use Claroline\CoreBundle\Library\Configuration\PlatformConfigurationHandler; use Claroline\CoreBundle\Library\Normalizer\DateNormalizer; use Claroline\InstallationBundle\Additional\AdditionalInstaller; @@ -24,15 +25,21 @@ public static function getUpdaters(): array return [ '14.0.0' => Updater140000::class, '14.0.10' => Updater140010::class, + '14.1.0' => Updater140100::class, ]; } + public function hasMigrations(): bool + { + return true; + } + public function hasFixtures(): bool { return true; } - public function postInstall() + public function postInstall(): void { parent::postInstall(); @@ -40,14 +47,14 @@ public function postInstall() $this->setUpdateDate(); } - public function postUpdate($currentVersion, $targetVersion) + public function postUpdate(string $currentVersion, string $targetVersion): void { parent::postUpdate($currentVersion, $targetVersion); $this->setUpdateDate(); } - public function end($currentVersion, $targetVersion) + public function end(string $currentVersion, string $targetVersion): void { $workspaceManager = $this->container->get('claroline.manager.workspace_manager'); @@ -56,7 +63,7 @@ public function end($currentVersion, $targetVersion) $workspaceManager->getDefaultModel(true); } - private function setInstallationDate() + private function setInstallationDate(): void { /** @var PlatformConfigurationHandler $ch */ $ch = $this->container->get(PlatformConfigurationHandler::class); @@ -64,7 +71,7 @@ private function setInstallationDate() $ch->setParameter('meta.created', DateNormalizer::normalize(new \DateTime())); } - private function setUpdateDate() + private function setUpdateDate(): void { /** @var PlatformConfigurationHandler $ch */ $ch = $this->container->get(PlatformConfigurationHandler::class); diff --git a/src/main/core/Installation/DataFixtures/PlatformRolesData.php b/src/main/core/Installation/DataFixtures/PlatformRolesData.php index 804c70a20bd..5caed3efba8 100644 --- a/src/main/core/Installation/DataFixtures/PlatformRolesData.php +++ b/src/main/core/Installation/DataFixtures/PlatformRolesData.php @@ -11,7 +11,7 @@ namespace Claroline\CoreBundle\Installation\DataFixtures; -use Claroline\CoreBundle\Entity\Tool\Tool; +use Claroline\CoreBundle\Component\Context\DesktopContext; use Claroline\CoreBundle\Manager\RoleManager; use Claroline\CoreBundle\Manager\Tool\ToolManager; use Claroline\CoreBundle\Security\PlatformRoles; @@ -53,7 +53,7 @@ public function load(ObjectManager $manager) $userRole = $this->roleManager->createBaseRole(PlatformRoles::USER, 'user', true, true); // initialize some tools rights to let users open their desktop foreach (['home', 'resources', 'workspaces'] as $tool) { - $orderedTool = $this->toolManager->getOrderedTool($tool, Tool::DESKTOP); + $orderedTool = $this->toolManager->getOrderedTool($tool, DesktopContext::getName()); if ($orderedTool) { $this->toolManager->setPermissions(['open' => true], $orderedTool, $userRole); } diff --git a/src/main/core/Installation/Migrations/Version20231110053448.php b/src/main/core/Installation/Migrations/Version20231110053448.php new file mode 100644 index 00000000000..9acc70bfe26 --- /dev/null +++ b/src/main/core/Installation/Migrations/Version20231110053448.php @@ -0,0 +1,40 @@ +addSql(' + ALTER TABLE claro_resource_evaluation CHANGE progression progression DOUBLE PRECISION NOT NULL + '); + $this->addSql(' + ALTER TABLE claro_resource_user_evaluation CHANGE progression progression DOUBLE PRECISION NOT NULL + '); + $this->addSql(' + ALTER TABLE claro_workspace_evaluation CHANGE progression progression DOUBLE PRECISION NOT NULL + '); + } + + public function down(Schema $schema): void + { + $this->addSql(' + ALTER TABLE claro_resource_evaluation CHANGE progression progression INT NOT NULL + '); + $this->addSql(' + ALTER TABLE claro_resource_user_evaluation CHANGE progression progression INT NOT NULL + '); + $this->addSql(' + ALTER TABLE claro_workspace_evaluation CHANGE progression progression INT NOT NULL + '); + } +} diff --git a/src/main/core/Installation/Migrations/Version20231110053450.php b/src/main/core/Installation/Migrations/Version20231110053450.php new file mode 100644 index 00000000000..7ac8d5aeb75 --- /dev/null +++ b/src/main/core/Installation/Migrations/Version20231110053450.php @@ -0,0 +1,96 @@ +addSql(' + ALTER TABLE claro_ordered_tool + ADD context_name VARCHAR(255) NOT NULL, + ADD context_id VARCHAR(255) DEFAULT NULL + '); + + // migrate desktop tools + $this->addSql(' + UPDATE claro_ordered_tool SET context_name = "desktop" WHERE workspace_id IS NULL + '); + + // migrate workspace tools + $this->addSql(' + UPDATE claro_ordered_tool AS t + LEFT JOIN claro_workspace AS w ON t.workspace_id = w.id + SET context_name = "workspace", context_id = w.uuid WHERE workspace_id IS NOT NULL + '); + + $this->addSql(' + ALTER TABLE claro_ordered_tool + DROP FOREIGN KEY FK_6CF1320E82D40A1F + '); + $this->addSql(' + ALTER TABLE claro_ordered_tool + DROP FOREIGN KEY FK_6CF1320EA76ED395 + '); + $this->addSql(' + DROP INDEX ordered_tool_unique_tool_user_type ON claro_ordered_tool + '); + $this->addSql(' + DROP INDEX ordered_tool_unique_tool_ws_type ON claro_ordered_tool + '); + $this->addSql(' + DROP INDEX IDX_6CF1320E82D40A1F ON claro_ordered_tool + '); + $this->addSql(' + DROP INDEX IDX_6CF1320EA76ED395 ON claro_ordered_tool + '); + $this->addSql(' + ALTER TABLE claro_ordered_tool + DROP workspace_id, + DROP user_id + '); + } + + public function down(Schema $schema): void + { + $this->addSql(' + ALTER TABLE claro_ordered_tool + ADD workspace_id INT DEFAULT NULL, + ADD user_id INT DEFAULT NULL, + DROP context_name, + DROP context_id + '); + $this->addSql(' + ALTER TABLE claro_ordered_tool + ADD CONSTRAINT FK_6CF1320E82D40A1F FOREIGN KEY (workspace_id) + REFERENCES claro_workspace (id) ON UPDATE NO ACTION + ON DELETE CASCADE + '); + $this->addSql(' + ALTER TABLE claro_ordered_tool + ADD CONSTRAINT FK_6CF1320EA76ED395 FOREIGN KEY (user_id) + REFERENCES claro_user (id) ON UPDATE NO ACTION + ON DELETE CASCADE + '); + $this->addSql(' + CREATE UNIQUE INDEX ordered_tool_unique_tool_user_type ON claro_ordered_tool (tool_id, user_id) + '); + $this->addSql(' + CREATE UNIQUE INDEX ordered_tool_unique_tool_ws_type ON claro_ordered_tool (tool_id, workspace_id) + '); + $this->addSql(' + CREATE INDEX IDX_6CF1320E82D40A1F ON claro_ordered_tool (workspace_id) + '); + $this->addSql(' + CREATE INDEX IDX_6CF1320EA76ED395 ON claro_ordered_tool (user_id) + '); + } +} diff --git a/src/main/core/Installation/Migrations/Version20231116084035.php b/src/main/core/Installation/Migrations/Version20231116084035.php new file mode 100644 index 00000000000..c8ad9cdf20c --- /dev/null +++ b/src/main/core/Installation/Migrations/Version20231116084035.php @@ -0,0 +1,107 @@ +addSql(' + ALTER TABLE claro_tool_mask_decoder + DROP FOREIGN KEY FK_323623448F7B22CC + '); + $this->addSql(' + DROP INDEX IDX_323623448F7B22CC ON claro_tool_mask_decoder + '); + $this->addSql(' + DROP INDEX tool_mask_decoder_unique_tool_and_name ON claro_tool_mask_decoder + '); + $this->addSql(' + ALTER TABLE claro_tool_mask_decoder + ADD tool_name VARCHAR(255) NOT NULL + '); + + $this->addSql(' + UPDATE claro_tool_mask_decoder AS m + LEFT JOIN claro_tools AS t ON m.tool_id = t.id + SET m.tool_name = t.name + '); + + /*$this->addSql(' + ALTER TABLE claro_tool_mask_decoder + DROP tool_id + ');*/ + + $this->addSql(' + CREATE UNIQUE INDEX tool_mask_decoder_unique_tool_and_name ON claro_tool_mask_decoder (tool_name, `name`) + '); + $this->addSql(' + ALTER TABLE claro_ordered_tool + DROP FOREIGN KEY FK_6CF1320E8F7B22CC + '); + $this->addSql(' + DROP INDEX IDX_6CF1320E8F7B22CC ON claro_ordered_tool + '); + $this->addSql(' + ALTER TABLE claro_ordered_tool + ADD tool_name VARCHAR(255) NOT NULL + '); + + $this->addSql(' + UPDATE claro_ordered_tool AS ot + LEFT JOIN claro_tools AS t ON ot.tool_id = t.id + SET ot.tool_name = t.name + '); + + /*$this->addSql(' + ALTER TABLE claro_ordered_tool + DROP tool_id + ');*/ + } + + public function down(Schema $schema): void + { + $this->addSql(' + ALTER TABLE claro_ordered_tool + ADD tool_id INT NOT NULL, + DROP tool_name + '); + $this->addSql(' + ALTER TABLE claro_ordered_tool + ADD CONSTRAINT FK_6CF1320E8F7B22CC FOREIGN KEY (tool_id) + REFERENCES claro_tools (id) ON UPDATE NO ACTION + ON DELETE CASCADE + '); + $this->addSql(' + CREATE INDEX IDX_6CF1320E8F7B22CC ON claro_ordered_tool (tool_id) + '); + $this->addSql(' + DROP INDEX tool_mask_decoder_unique_tool_and_name ON claro_tool_mask_decoder + '); + $this->addSql(' + ALTER TABLE claro_tool_mask_decoder + ADD tool_id INT NOT NULL, + DROP tool_name + '); + $this->addSql(' + ALTER TABLE claro_tool_mask_decoder + ADD CONSTRAINT FK_323623448F7B22CC FOREIGN KEY (tool_id) + REFERENCES claro_tools (id) ON UPDATE NO ACTION + ON DELETE CASCADE + '); + $this->addSql(' + CREATE INDEX IDX_323623448F7B22CC ON claro_tool_mask_decoder (tool_id) + '); + $this->addSql(' + CREATE UNIQUE INDEX tool_mask_decoder_unique_tool_and_name ON claro_tool_mask_decoder (tool_id, name) + '); + } +} diff --git a/src/main/core/Installation/Updater/Updater140000.php b/src/main/core/Installation/Updater/Updater140000.php index c32c9052b6c..f4c78057401 100644 --- a/src/main/core/Installation/Updater/Updater140000.php +++ b/src/main/core/Installation/Updater/Updater140000.php @@ -20,7 +20,7 @@ public function __construct( $this->connection = $connection; } - public function preUpdate() + public function preUpdate(): void { // Adds migration FQCN in the versions tables (required by new doctrine migrations version) $this->renameMigrations(); @@ -28,7 +28,7 @@ public function preUpdate() // the namespace of the migrations has changed (eg. removed the `pdo_mysql` part) // Doctrine will try to re-execute migrations because of the renaming // we need to update the version classnames in the DB to avoid breaking updates - $this->log('Updating doctrine migration versions...'); + $this->logger->info('Updating doctrine migration versions...'); // retrieve all doctrine versions tables $stmt = $this->connection->prepare(' SHOW TABLES LIKE "doctrine_%_versions" @@ -38,7 +38,7 @@ public function preUpdate() $tables = $results->fetchFirstColumn(); foreach ($tables as $table) { - $this->log(sprintf('Updating doctrine migration versions %s...', $table)); + $this->logger->info(sprintf('Updating doctrine migration versions %s...', $table)); // update last version execution $versionsQuery = $this->connection->prepare(" diff --git a/src/main/core/Installation/Updater/Updater140010.php b/src/main/core/Installation/Updater/Updater140010.php index 9e8c1c69f84..c26d9b06c48 100644 --- a/src/main/core/Installation/Updater/Updater140010.php +++ b/src/main/core/Installation/Updater/Updater140010.php @@ -15,7 +15,7 @@ public function __construct( $this->connection = $connection; } - public function postUpdate() + public function postUpdate(): void { $updateUsers = $this->connection->prepare(" UPDATE claro_user AS u SET u.mail = CONCAT('email', CONCAT(u.id, '@deleted.com')) WHERE u.is_removed = true diff --git a/src/main/core/Installation/Updater/Updater140100.php b/src/main/core/Installation/Updater/Updater140100.php new file mode 100644 index 00000000000..6cd90451116 --- /dev/null +++ b/src/main/core/Installation/Updater/Updater140100.php @@ -0,0 +1,50 @@ +createAccountTools(); + // create home tools + // migrate old home config + } + + private function createAccountTools(): void + { + // static list to preserve original order + $tools = [ + 'profile', + 'parameters', + 'privacy', + 'authentication', + 'badges', + 'notifications', + 'logs', + ]; + + foreach ($tools as $index => $tool) { + $orderedTool = new OrderedTool(); + $orderedTool->setContextName(AccountContext::getName()); + $orderedTool->setOrder($index); + $orderedTool->setName($tool); + + $this->om->persist($orderedTool); + } + + $this->om->flush(); + } +} diff --git a/src/main/core/Library/Installation/Plugin/DatabaseWriter.php b/src/main/core/Library/Installation/Plugin/DatabaseWriter.php index 141a65ed86a..43cbfce1c56 100644 --- a/src/main/core/Library/Installation/Plugin/DatabaseWriter.php +++ b/src/main/core/Library/Installation/Plugin/DatabaseWriter.php @@ -11,7 +11,6 @@ namespace Claroline\CoreBundle\Library\Installation\Plugin; -use Claroline\AppBundle\Log\LoggableTrait; use Claroline\AppBundle\Persistence\ObjectManager; use Claroline\CoreBundle\Entity\DataSource; use Claroline\CoreBundle\Entity\Plugin; @@ -23,14 +22,13 @@ use Claroline\CoreBundle\Entity\Tool\Tool; use Claroline\CoreBundle\Entity\Widget\Widget; use Claroline\CoreBundle\Manager\Resource\MaskManager; -use Claroline\CoreBundle\Manager\Tool\ToolManager; use Claroline\CoreBundle\Manager\Tool\ToolMaskDecoderManager; use Claroline\CoreBundle\Repository\PluginRepository; use Claroline\KernelBundle\Bundle\PluginBundleInterface; use Claroline\ThemeBundle\Entity\Theme; use Claroline\ThemeBundle\Manager\IconSetBuilderManager; use Psr\Log\LoggerAwareInterface; -use Psr\Log\LogLevel; +use Psr\Log\LoggerAwareTrait; use Symfony\Component\Filesystem\Filesystem; /** @@ -41,39 +39,17 @@ */ class DatabaseWriter implements LoggerAwareInterface { - use LoggableTrait; - - /** @var ObjectManager */ - private $em; - /** @var MaskManager */ - private $mm; - /** @var Filesystem */ - private $fileSystem; - /** @var ToolManager */ - private $toolManager; - /** @var ToolMaskDecoderManager */ - private $toolMaskManager; - /** @var IconSetBuilderManager */ - private $iconSetManager; - - /** @var PluginRepository */ - private $pluginRepository; + use LoggerAwareTrait; + + private PluginRepository $pluginRepository; public function __construct( - ObjectManager $em, - MaskManager $mm, - Filesystem $fileSystem, - ToolManager $toolManager, - ToolMaskDecoderManager $toolMaskManager, - IconSetBuilderManager $iconSetManager + private readonly ObjectManager $em, + private readonly MaskManager $mm, + private readonly Filesystem $fileSystem, + private readonly ToolMaskDecoderManager $toolMaskManager, + private readonly IconSetBuilderManager $iconSetManager ) { - $this->em = $em; - $this->mm = $mm; - $this->fileSystem = $fileSystem; - $this->toolManager = $toolManager; - $this->toolMaskManager = $toolMaskManager; - $this->iconSetManager = $iconSetManager; - $this->pluginRepository = $this->em->getRepository(Plugin::class); } @@ -106,13 +82,13 @@ public function update(PluginBundleInterface $pluginBundle, array $pluginConfigu ]); if (null === $plugin) { - $this->log('Unable to retrieve plugin for updating its configuration.', LogLevel::ERROR); + $this->logger->error('Unable to retrieve plugin for updating its configuration.'); return null; } $this->em->persist($plugin); - $this->log('Configuration was retrieved: updating...'); + $this->logger->info('Configuration was retrieved: updating...'); $this->updateConfiguration($pluginConfiguration, $plugin, $pluginBundle); @@ -226,7 +202,7 @@ private function updateConfiguration(array $processedConfiguration, Plugin $plug }); foreach ($widgetsToDelete as $widget) { - $this->log('Removing widget '.$widget->getName()); + $this->logger->info('Removing widget '.$widget->getName()); $this->em->remove($widget); } @@ -242,7 +218,7 @@ private function updateConfiguration(array $processedConfiguration, Plugin $plug }); foreach ($sourcesToDelete as $source) { - $this->log('Removing data source '.$source->getName()); + $this->logger->info('Removing data source '.$source->getName()); $this->em->remove($source); } @@ -260,7 +236,7 @@ private function updateConfiguration(array $processedConfiguration, Plugin $plug }); foreach ($toRemove as $tool) { - $this->log('Removing tool '.$tool->getName()); + $this->logger->info('Removing tool '.$tool->getName()); $this->em->remove($tool); } @@ -281,7 +257,7 @@ private function updateConfiguration(array $processedConfiguration, Plugin $plug private function updateResourceType(array $resourceConfiguration, Plugin $plugin, PluginBundleInterface $pluginBundle): ResourceType { - $this->log(sprintf('Updating the resource type : "%s".', $resourceConfiguration['name'])); + $this->logger->info(sprintf('Updating the resource type : "%s".', $resourceConfiguration['name'])); $resourceType = $this->em->getRepository(ResourceType::class) ->findOneBy(['name' => $resourceConfiguration['name']]); @@ -323,7 +299,7 @@ private function updateResourceType(array $resourceConfiguration, Plugin $plugin foreach ($toRemove as $el) { $mask = $this->em->getRepository(MaskDecoder::class)->findOneBy(['resourceType' => $resourceType, 'name' => $el]); - $this->log('Remove mask decoder '.$el, LogLevel::ERROR); + $this->logger->info('Remove mask decoder '.$el); $this->em->remove($mask); } @@ -371,7 +347,7 @@ public function persistResourceAction(array $action, Plugin $plugin): void ->findOneBy(['name' => $action['resource_type']]); } - $this->log(sprintf('Updating resource action : "%s".', $action['name'])); + $this->logger->info(sprintf('Updating resource action : "%s".', $action['name'])); // initializes the mask decoder if needed $this->mm->createDecoder($action['decoder'], $resourceType); @@ -405,7 +381,7 @@ public function updateResourceAction(array $action, Plugin $plugin): void private function persistResourceType(array $resourceConfiguration, Plugin $plugin, PluginBundleInterface $pluginBundle): ResourceType { - $this->log('Adding resource type '.$resourceConfiguration['name']); + $this->logger->info('Adding resource type '.$resourceConfiguration['name']); $resourceType = new ResourceType(); $resourceType->setName($resourceConfiguration['name']); $resourceType->setClass($resourceConfiguration['class']); @@ -507,7 +483,7 @@ private function updateDataSource($sourceConfiguration, Plugin $plugin): DataSou private function persistTool(array $toolConfiguration, Plugin $plugin, Tool $tool): void { - $this->log(sprintf('Updating the tool : "%s".', $toolConfiguration['name'])); + $this->logger->info(sprintf('Updating the tool : "%s".', $toolConfiguration['name'])); $tool->setName($toolConfiguration['name']); $tool->setPlugin($plugin); @@ -520,8 +496,10 @@ private function persistTool(array $toolConfiguration, Plugin $plugin, Tool $too $tool->setClass('tools'); } - $this->toolManager->setLogger($this->logger); - $this->toolManager->create($tool); + $this->em->persist($tool); + + $this->toolMaskManager->createDefaultToolMaskDecoders($tool->getName()); + $this->persistCustomToolRights($toolConfiguration['tool_rights'], $tool); } @@ -558,7 +536,7 @@ private function createAdminTool(array $adminToolConfiguration, Plugin $plugin): private function persistAdminTool(array $adminToolConfiguration, Plugin $plugin, AdminTool $adminTool): void { - $this->log(sprintf('Update the administration tool : "%s".', $adminToolConfiguration['name'])); + $this->logger->info(sprintf('Update the administration tool : "%s".', $adminToolConfiguration['name'])); $adminTool->setName($adminToolConfiguration['name']); $adminTool->setClass($adminToolConfiguration['class']); @@ -581,17 +559,17 @@ private function updateAdminTool(array $adminToolConfiguration, Plugin $plugin): private function persistCustomToolRights(array $rights, Tool $tool): void { - $decoders = $this->toolMaskManager->getMaskDecodersByTool($tool); + $decoders = $this->toolMaskManager->getMaskDecodersByTool($tool->getName()); $nb = count($decoders); foreach ($rights as $right) { $maskDecoder = $this->toolMaskManager - ->getMaskDecoderByToolAndName($tool, $right['name']); + ->getMaskDecoderByToolAndName($tool->getName(), $right['name']); if (is_null($maskDecoder)) { $value = pow(2, $nb); $this->toolMaskManager->createToolMaskDecoder( - $tool, + $tool->getName(), $right['name'], $value ); diff --git a/src/main/core/Library/Installation/Plugin/Installer.php b/src/main/core/Library/Installation/Plugin/Installer.php deleted file mode 100644 index 62ee34ab281..00000000000 --- a/src/main/core/Library/Installation/Plugin/Installer.php +++ /dev/null @@ -1,138 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Claroline\CoreBundle\Library\Installation\Plugin; - -use Claroline\AppBundle\Log\LoggableTrait; -use Claroline\AppBundle\Persistence\ObjectManager; -use Claroline\CoreBundle\Manager\PluginManager; -use Claroline\CoreBundle\Manager\VersionManager; -use Claroline\InstallationBundle\Manager\InstallationManager; -use Claroline\KernelBundle\Bundle\PluginBundleInterface; -use Psr\Log\LoggerAwareInterface; - -/** - * This class is used to perform the (un-)installation of a plugin. - */ -class Installer implements LoggerAwareInterface -{ - use LoggableTrait; - - /** @var Validator */ - private $validator; - /** @var Recorder */ - private $recorder; - /** @var InstallationManager */ - private $baseInstaller; - /** @var ObjectManager */ - private $om; - /** @var VersionManager */ - private $versionManager; - /** @var PluginManager */ - private $pluginManager; - - public function __construct( - Validator $validator, - Recorder $recorder, - InstallationManager $installer, - ObjectManager $om, - PluginManager $pluginManager, - VersionManager $versionManager - ) { - $this->validator = $validator; - $this->recorder = $recorder; - $this->baseInstaller = $installer; - $this->om = $om; - $this->pluginManager = $pluginManager; - $this->versionManager = $versionManager; - } - - /** - * Installs a plugin. - * - * @throws \Exception if the plugin doesn't pass the validation - */ - public function install(PluginBundleInterface $plugin) - { - $this->baseInstaller->install($plugin); - - $pluginEntity = $this->pluginManager->getPluginByShortName( - $plugin->getName() - ); - - if (!$this->pluginManager->isReady($pluginEntity)) { - $errors = $this->pluginManager->getMissingRequirements($pluginEntity); - - foreach ($errors['extensions'] as $extension) { - $this->log(sprintf('Extension %s missing for %s !', $extension, $plugin->getName())); - } - - foreach ($errors['plugins'] as $bundle) { - $this->log(sprintf('The plugin %s is required for %s ! You must enable it first to use %s.', $bundle, $plugin->getName(), $plugin->getName())); - } - - foreach ($errors['extras'] as $extra) { - $this->log(sprintf('The plugin %s has extra requirements ! %s.', $plugin->getName(), $extra)); - } - - $this->log(sprintf('Disabling %s...', $plugin->getName())); - $this->pluginManager->disable($pluginEntity); - } - - $version = $this->versionManager->register($plugin); - $this->versionManager->execute($version); - } - - /** - * Uninstalls a plugin. - */ - public function uninstall(PluginBundleInterface $plugin) - { - $this->checkInstallationStatus($plugin, true); - - $this->log('Removing plugin configuration...'); - $this->recorder->unregister($plugin); - $this->baseInstaller->uninstall($plugin); - } - - /** - * Upgrades/downgrades a plugin to a specific version. - * - * @param string $currentVersion - * @param string $targetVersion - */ - public function update(PluginBundleInterface $plugin, $currentVersion, $targetVersion) - { - $this->checkInstallationStatus($plugin, true); - - $this->baseInstaller->update($plugin, $currentVersion, $targetVersion); - - // updates plugin version - $version = $this->versionManager->register($plugin); - $this->versionManager->execute($version); - } - - public function end(PluginBundleInterface $plugin, $currentVersion = null, $targetVersion = null) - { - $this->baseInstaller->end($plugin, $currentVersion, $targetVersion); - } - - private function checkInstallationStatus(PluginBundleInterface $plugin, $shouldBeInstalled = true): void - { - $this->log(sprintf('Checking installation status for plugin %s', $plugin->getName())); - - if ($this->recorder->isRegistered($plugin) !== $shouldBeInstalled) { - $stateDiscr = $shouldBeInstalled ? 'not' : 'already'; - - throw new \LogicException("Plugin '{$plugin->getName()}' is {$stateDiscr} installed."); - } - } -} diff --git a/src/main/core/Library/Testing/RepositoryTestCase.php b/src/main/core/Library/Testing/RepositoryTestCase.php index 5fdd4b122f4..1e6de79ff1b 100644 --- a/src/main/core/Library/Testing/RepositoryTestCase.php +++ b/src/main/core/Library/Testing/RepositoryTestCase.php @@ -11,7 +11,6 @@ namespace Claroline\CoreBundle\Library\Testing; -use Claroline\CoreBundle\Entity\Log\Log; use Claroline\CoreBundle\Entity\Plugin; use Claroline\CoreBundle\Entity\Resource\AbstractResource; use Claroline\CoreBundle\Entity\Resource\Directory; @@ -19,16 +18,11 @@ use Claroline\CoreBundle\Entity\Resource\ResourceNode; use Claroline\CoreBundle\Entity\Resource\ResourceRights; use Claroline\CoreBundle\Entity\Resource\ResourceType; -use Claroline\CoreBundle\Entity\Resource\Revision; -use Claroline\CoreBundle\Entity\Resource\Text; use Claroline\CoreBundle\Entity\Role; use Claroline\CoreBundle\Entity\Tool\OrderedTool; -use Claroline\CoreBundle\Entity\Tool\Tool; use Claroline\CoreBundle\Entity\Tool\ToolRights; use Claroline\CoreBundle\Entity\User; use Claroline\CoreBundle\Entity\Workspace\Workspace; -use Claroline\MessageBundle\Entity\Message; -use Claroline\MessageBundle\Entity\UserMessage; use Gedmo\Timestampable\TimestampableListener; use Symfony\Bundle\FrameworkBundle\Test\WebTestCase; @@ -61,8 +55,8 @@ public static function setUpBeforeClass(): void public function tearDown(): void { - //we don't want to tear down between each tests because we lose the container otherwise - //and can't shut down everything properly afterwards + // we don't want to tear down between each tests because we lose the container otherwise + // and can't shut down everything properly afterwards } public static function tearDownAfterClass(): void @@ -123,12 +117,12 @@ protected static function getTime($format = 'Y-m-d H:i:s') * * @param int $seconds */ - protected static function sleep($seconds) + protected static function sleep($seconds): void { self::$time->add(new \DateInterval("PT{$seconds}S")); } - protected static function createUser($name, array $roles = [], Workspace $personalWorkspace = null) + protected static function createUser($name, array $roles = [], Workspace $personalWorkspace = null): void { $user = self::$persister->user($name); @@ -143,7 +137,7 @@ protected static function createUser($name, array $roles = [], Workspace $person self::create($name, $user); } - protected static function createGroup($name, array $users = [], array $roles = []) + protected static function createGroup($name, array $users = [], array $roles = []): void { $group = self::$persister->group($name); @@ -158,7 +152,7 @@ protected static function createGroup($name, array $users = [], array $roles = [ self::create($name, $group); } - protected static function createRole($name, Workspace $workspace = null) + protected static function createRole($name, Workspace $workspace = null): void { $role = new Role(); $role->setName($name); @@ -178,7 +172,7 @@ protected static function createRole($name, Workspace $workspace = null) } } - protected static function createWorkspace($name) + protected static function createWorkspace($name): void { $workspace = new Workspace(); $workspace->setName($name); @@ -188,7 +182,7 @@ protected static function createWorkspace($name) self::create($name, $workspace); } - protected static function createDisplayableWorkspace($name, $selfRegistration) + protected static function createDisplayableWorkspace($name, $selfRegistration): void { $workspace = new Workspace(); $workspace->setName($name); @@ -199,7 +193,7 @@ protected static function createDisplayableWorkspace($name, $selfRegistration) self::create($name, $workspace); } - protected static function createResourceType($name, $class, $isExportable = true, Plugin $plugin = null) + protected static function createResourceType($name, $class, $isExportable = true, Plugin $plugin = null): void { $type = new ResourceType(); $type->setName($name); @@ -219,7 +213,7 @@ protected static function createDirectory( User $creator, Workspace $workspace, Directory $parent = null - ) { + ): void { if ($parent) { $parent = $parent->getResourceNode(); } @@ -236,7 +230,7 @@ protected static function createDirectory( self::create($name, $directory); } - protected static function createFile($name, ResourceType $type, User $creator, Directory $parent) + protected static function createFile($name, ResourceType $type, User $creator, Directory $parent): void { $file = self::prepareResource( new File(), @@ -252,37 +246,12 @@ protected static function createFile($name, ResourceType $type, User $creator, D self::create($name, $file); } - protected static function createText( - $name, - $revisionNumber, - ResourceType $type, - User $creator, - Directory $parent - ) { - $text = self::prepareResource( - new Text(), - $type, - $creator, - $parent->getResourceNode()->getWorkspace(), - $name, - 'text/mime', - $parent->getResourceNode() - ); - self::create($name, $text); - - $revision = new Revision(); - $revision->setVersion($revisionNumber); - $revision->setContent($name.'Content'); - $revision->setText($text); - self::create("revision/{$text->getName()}-{$revisionNumber}", $revision); - } - protected static function createResourceRights( Role $role, AbstractResource $resource, $mask, array $creatableResourceTypes = [] - ) { + ): void { $rights = new ResourceRights(); $rights->setRole($role); $rights->setResourceNode($resource->getResourceNode()); @@ -295,23 +264,16 @@ protected static function createResourceRights( self::create("resource_right/{$role->getName()}-{$resource->getResourceNode()->getName()}", $rights); } - protected static function createTool($name) - { - $tool = new Tool(); - $tool->setName($name); - $tool->setClass($name.'Class'); - self::create($name, $tool); - } - protected static function createWorkspaceTool( - Tool $tool, + string $toolName, Workspace $workspace, array $roles, $position - ) { + ): void { $orderedTool = new OrderedTool(); - $orderedTool->setTool($tool); - $orderedTool->setWorkspace($workspace); + $orderedTool->setName($toolName); + $orderedTool->setContextName('workspace'); + $orderedTool->setContextId($workspace->getUuid()); $orderedTool->setOrder($position); foreach ($roles as $role) { @@ -322,23 +284,10 @@ protected static function createWorkspaceTool( self::$om->persist($rights); } - self::create("orderedTool/{$workspace->getName()}-{$tool->getName()}", $orderedTool); - } - - protected static function createDesktopTool( - Tool $tool, - User $user, - $position - ) { - $orderedTool = new OrderedTool(); - $orderedTool->setTool($tool); - $orderedTool->setUser($user); - $orderedTool->setOrder($position); - - self::create("orderedTool/{$user->getUsername()}-{$tool->getName()}", $orderedTool); + self::create("orderedTool/{$workspace->getName()}-{$toolName}", $orderedTool); } - protected static function createPlugin($vendor, $bundle) + protected static function createPlugin($vendor, $bundle): void { $plugin = new Plugin(); $plugin->setVendorName($vendor); @@ -346,63 +295,8 @@ protected static function createPlugin($vendor, $bundle) self::create($vendor.$bundle, $plugin); } - protected static function createLog(User $doer, $action, Workspace $workspace = null) - { - $log = new Log(); - $log->setDoer($doer); - $log->setAction($action); - $log->setDoerType(Log::DOER_USER); - $log->setDateLog(self::$time); - - if ($workspace) { - $log->setWorkspace($workspace); - } - - self::$om->persist($log); - self::$om->flush(); - } - - protected static function createMessage( - $alias, - User $sender, - array $receivers, - $object, - $content, - Message $parent = null, - $removed = false - ) { - $message = new Message(); - $message->setSender($sender); - $message->setObject($object); - $message->setContent($content); - $message->setDate(self::$time); - $message->setTo('x1;x2;x3'); - if ($parent) { - $message->setParent($parent); - } - self::$om->startFlushSuite(); - self::create($alias, $message); - $userMessage = new UserMessage(); - $userMessage->setIsSent(true); - $userMessage->setUser($sender); - $userMessage->setMessage($message); - if ($removed) { - $userMessage->setRemoved($removed); - } - self::create($alias.'/'.$sender->getUsername(), $userMessage); - foreach ($receivers as $receiver) { - $userMessage = new UserMessage(); - $userMessage->setUser($receiver); - $userMessage->setMessage($message); - self::create($alias.'/'.$receiver->getUsername(), $userMessage); - } - self::$om->endFlushSuite(); - } - /** * Sets the common properties of a resource. - * - * @return AbstractResource */ private static function prepareResource( AbstractResource $resource, @@ -412,7 +306,7 @@ private static function prepareResource( $name, $mimeType, $parent = null - ) { + ): AbstractResource { $node = new ResourceNode(); $node->setResourceType($type); $node->setCreator($creator); @@ -437,9 +331,9 @@ private static function prepareResource( /** * Disables the timestamp listener so that fixture methods are forced to set - * dates explicitely. + * dates explicitly. */ - private static function disableTimestampableListener() + private static function disableTimestampableListener(): void { $eventManager = self::$om->getEventManager(); @@ -460,7 +354,7 @@ private static function disableTimestampableListener() * * @throws \InvalidArgumentException if the reference is already set */ - private static function set($reference, $entity) + private static function set($reference, $entity): void { if (isset(self::$references[$reference])) { throw new \InvalidArgumentException("Fixture reference '{$reference}' is already set"); @@ -475,7 +369,7 @@ private static function set($reference, $entity) * @param string $reference * @param object $entity */ - private static function create($reference, $entity) + private static function create($reference, $entity): void { self::$om->persist($entity); self::$om->flush(); diff --git a/src/main/core/Manager/Tool/ToolManager.php b/src/main/core/Manager/Tool/ToolManager.php index 96ebfeef282..270d3936b45 100644 --- a/src/main/core/Manager/Tool/ToolManager.php +++ b/src/main/core/Manager/Tool/ToolManager.php @@ -13,8 +13,8 @@ use Claroline\AppBundle\Log\LoggableTrait; use Claroline\AppBundle\Persistence\ObjectManager; +use Claroline\CoreBundle\Component\Context\DesktopContext; use Claroline\CoreBundle\Entity\Role; -use Claroline\CoreBundle\Entity\Tool\AbstractTool; use Claroline\CoreBundle\Entity\Tool\AdminTool; use Claroline\CoreBundle\Entity\Tool\OrderedTool; use Claroline\CoreBundle\Entity\Tool\Tool; @@ -33,96 +33,36 @@ class ToolManager implements LoggerAwareInterface // todo adds a config in tools to avoid this public const WORKSPACE_MODEL_TOOLS = ['home', 'resources', 'community', 'badges']; - /** @var AuthorizationCheckerInterface */ - private $authorization; - /** @var ObjectManager */ - private $om; - /** @var ToolMaskDecoderManager */ - private $toolMaskManager; - /** @var ToolRightsManager */ - private $toolRightsManager; - - /** @var OrderedToolRepository */ - private $orderedToolRepo; - /** @var ToolRepository */ - private $toolRepo; - /** @var AdministrationToolRepository */ - private $adminToolRepo; + private OrderedToolRepository $orderedToolRepo; + private ToolRepository $toolRepo; + private AdministrationToolRepository $adminToolRepo; public function __construct( - AuthorizationCheckerInterface $authorization, - ObjectManager $om, - ToolMaskDecoderManager $toolMaskManager, - ToolRightsManager $toolRightsManager + private readonly AuthorizationCheckerInterface $authorization, + private readonly ObjectManager $om, + private readonly ToolMaskDecoderManager $toolMaskManager, + private readonly ToolRightsManager $toolRightsManager ) { - $this->authorization = $authorization; - $this->om = $om; - $this->toolMaskManager = $toolMaskManager; - $this->toolRightsManager = $toolRightsManager; - $this->orderedToolRepo = $om->getRepository(OrderedTool::class); $this->toolRepo = $om->getRepository(Tool::class); $this->adminToolRepo = $om->getRepository(AdminTool::class); } - public function create(Tool $tool): void + /** + * @deprecated + */ + public function create(string $toolName): void { - $this->om->startFlushSuite(); - $this->om->persist($tool); - $this->om->forceFlush(); - $this->toolMaskManager->createDefaultToolMaskDecoders($tool); - $this->om->endFlushSuite(); - - if ($tool->isDisplayableInWorkspace()) { - // check if there are already workspace tools, if not we add them - $ot = $this->om->getRepository(OrderedTool::class)->findBy(['tool' => $tool], [], 1, 0); - if (0 === count($ot)) { - $offset = 0; - $totalTools = $this->om->count(Tool::class); - $total = $this->om->count(Workspace::class); - $this->log('Adding tool '.$tool->getName().' to workspaces ('.$total.')'); - - $this->om->startFlushSuite(); - - while ($offset < $total) { - /** @var Workspace $workspaces */ - $workspaces = $this->om->getRepository(Workspace::class)->findBy([], [], 500, $offset); - - foreach ($workspaces as $workspace) { - $this->setWorkspaceTool($tool, $totalTools, $workspace); - ++$offset; - $this->log('Adding tool '.$offset.'/'.$total); - } - - $this->log('Flush'); - $this->om->forceFlush(); - } - - $this->om->endFlushSuite(); - } - } - - if ($tool->isDisplayableInDesktop()) { - // check if there is already desktop tool, if not we add it - $ot = $this->om->getRepository(OrderedTool::class)->findBy(['tool' => $tool, 'workspace' => null, 'user' => null], [], 1, 0); - if (0 === count($ot)) { - $desktopTools = $this->om->getRepository(OrderedTool::class)->findBy(['workspace' => null, 'user' => null]); - - $orderedTool = new OrderedTool(); - $orderedTool->setWorkspace(null); - $orderedTool->setUser(null); - $orderedTool->setTool($tool); - $orderedTool->setOrder(count($desktopTools) + 1); - - $this->om->persist($orderedTool); - $this->om->flush(); - } - } + //$this->om->startFlushSuite(); + //$this->om->persist($tool); + //$this->om->forceFlush(); + $this->toolMaskManager->createDefaultToolMaskDecoders($toolName); + //$this->om->endFlushSuite(); } public function getCurrentPermissions(OrderedTool $orderedTool): array { - $decoders = $this->toolMaskManager->getMaskDecodersByTool($orderedTool->getTool()); + $decoders = $this->toolMaskManager->getMaskDecodersByTool($orderedTool->getName()); // certainly not the optimal way to generate it, but it avoids to replicate logic from OrderedToolVoter $perms = []; @@ -142,7 +82,7 @@ public function getPermissions(OrderedTool $orderedTool, Role $role): array $mask = 0 < count($toolRights) ? $toolRights[0]->getMask() : 0; - return $this->toolMaskManager->decodeMask($mask, $orderedTool->getTool()); + return $this->toolMaskManager->decodeMask($mask, $orderedTool->getName()); } /** @@ -150,89 +90,21 @@ public function getPermissions(OrderedTool $orderedTool, Role $role): array */ public function setPermissions(array $perms, OrderedTool $orderedTool, Role $role): void { - $mask = $this->toolMaskManager->encodeMask($perms, $orderedTool->getTool()); + $mask = $this->toolMaskManager->encodeMask($perms, $orderedTool->getName()); $this->toolRightsManager->setToolRights($orderedTool, $role, $mask); } public function getOrderedTool(string $name, string $context, string $contextId = null): ?OrderedTool { - /** @var OrderedTool|null $orderedTool */ - $orderedTool = null; - switch ($context) { - case AbstractTool::DESKTOP: - $orderedTool = $this->orderedToolRepo->findOneByNameAndDesktop($name); - - break; - case AbstractTool::WORKSPACE: - $contextObject = $this->om->getRepository(Workspace::class)->findOneBy(['uuid' => $contextId]); - $orderedTool = $this->orderedToolRepo->findOneByNameAndWorkspace($name, $contextObject); - - break; - case AbstractTool::ADMINISTRATION: - // implement later - break; - } - - return $orderedTool; + return $this->orderedToolRepo->findOneByNameAndContext($name, $context, $contextId); } /** * @return OrderedTool[] */ - public function getOrderedTools(string $context, string $contextId = null): array + public function getOrderedTools(string $context, string $contextId = null, ?array $roles = []): array { - $tools = []; - - switch ($context) { - case AbstractTool::DESKTOP: - return $this->orderedToolRepo->findByDesktop(); - - case AbstractTool::WORKSPACE: - $contextObject = $this->om->getRepository(Workspace::class)->findOneBy(['slug' => $contextId]); - - return $this->orderedToolRepo->findByWorkspace($contextObject); - - case AbstractTool::ADMINISTRATION: - // TODO : implement later - break; - } - - return $tools; - } - - /** - * @return OrderedTool[] - * - * @deprecated - */ - public function getOrderedToolsByDesktop(array $roles = []): array - { - if (empty($roles) || in_array('ROLE_ADMIN', $roles)) { - return $this->orderedToolRepo->findByDesktop(); - } - - return $this->orderedToolRepo->findByDesktopAndRoles($roles); - } - - /** - * @return OrderedTool[] - * - * @deprecated - */ - public function getOrderedToolsByWorkspace(Workspace $workspace, array $roles = []): array - { - if (empty($roles)) { - $tools = $this->orderedToolRepo->findByWorkspace($workspace); - } else { - $tools = $this->orderedToolRepo->findByWorkspaceAndRoles($workspace, $roles); - } - - return $tools; - } - - public function getAdminToolByName(string $name): ?AdminTool - { - return $this->adminToolRepo->findOneBy(['name' => $name]); + return $this->orderedToolRepo->findByContext($context, $contextId, $roles); } /** @@ -245,52 +117,11 @@ public function getAdminToolsByRoles(array $roles) return $this->adminToolRepo->findByRoles($roles); } - public function getToolByName(string $name): ?Tool - { - return $this->toolRepo->findOneBy(['name' => $name]); - } - - /** - * Adds the tools missing in the database for a workspace. - */ - public function addMissingWorkspaceTools(Workspace $workspace): void - { - $undisplayedTools = $this->toolRepo->findUndisplayedToolsByWorkspace($workspace); - if (0 === count($undisplayedTools)) { - return; - } - - $initPos = $this->toolRepo->countDisplayedToolsByWorkspace($workspace); - ++$initPos; - - $this->om->startFlushSuite(); - - foreach ($undisplayedTools as $undisplayedTool) { - $wot = $this->orderedToolRepo->findOneBy([ - 'workspace' => $workspace, - 'tool' => $undisplayedTool, - ]); - - // create a WorkspaceOrderedTool for each Tool that hasn't already one - if (null === $wot) { - $this->setWorkspaceTool( - $undisplayedTool, - $initPos, - $workspace - ); - - ++$initPos; - } - } - - $this->om->endFlushSuite(); - } - - private function setWorkspaceTool(Tool $tool, int $position, Workspace $workspace): OrderedTool + private function setWorkspaceTool(string $toolName, int $position, Workspace $workspace): OrderedTool { $orderedTool = $this->orderedToolRepo->findOneBy([ - 'workspace' => $workspace, - 'tool' => $tool, + 'contextId' => $workspace->getUuid(), + 'tool' => $toolName, ]); if (!$orderedTool) { @@ -301,7 +132,7 @@ private function setWorkspaceTool(Tool $tool, int $position, Workspace $workspac // At the workspace creation, the workspace id is still null because we only flush once at the very end. if (null !== $workspace->getId()) { $switchTool = $this->orderedToolRepo->findOneBy([ - 'workspace' => $workspace, + 'contextId' => $workspace->getUuid(), 'order' => $position, ]); } @@ -309,14 +140,14 @@ private function setWorkspaceTool(Tool $tool, int $position, Workspace $workspac while (!is_null($switchTool)) { ++$position; $switchTool = $this->orderedToolRepo->findOneBy([ - 'workspace' => $workspace, + 'contextId' => $workspace->getUuid(), 'order' => $position, ]); } $orderedTool->setWorkspace($workspace); $orderedTool->setOrder($position); - $orderedTool->setTool($tool); + $orderedTool->setName($toolName); $this->om->persist($orderedTool); $this->om->flush(); diff --git a/src/main/core/Manager/Tool/ToolMaskDecoderManager.php b/src/main/core/Manager/Tool/ToolMaskDecoderManager.php index 05e758bd5ac..389d8ffd108 100644 --- a/src/main/core/Manager/Tool/ToolMaskDecoderManager.php +++ b/src/main/core/Manager/Tool/ToolMaskDecoderManager.php @@ -30,15 +30,15 @@ public function __construct(ObjectManager $om) /** * Create a mask decoder with default actions for a tool. */ - public function createDefaultToolMaskDecoders(Tool $tool): void + public function createDefaultToolMaskDecoders(string $toolName): void { foreach (ToolMaskDecoder::DEFAULT_ACTIONS as $action) { $maskDecoder = $this->maskRepo - ->findMaskDecoderByToolAndName($tool, $action); + ->findMaskDecoderByToolAndName($toolName, $action); if (is_null($maskDecoder)) { $maskDecoder = new ToolMaskDecoder(); - $maskDecoder->setTool($tool); + $maskDecoder->setTool($toolName); $maskDecoder->setName($action); $maskDecoder->setValue(ToolMaskDecoder::DEFAULT_VALUES[$action]); @@ -51,10 +51,10 @@ public function createDefaultToolMaskDecoders(Tool $tool): void /** * Create a specific mask decoder for a tool. */ - public function createToolMaskDecoder(Tool $tool, string $action, int $value): void + public function createToolMaskDecoder(string $toolName, string $action, int $value): void { $maskDecoder = new ToolMaskDecoder(); - $maskDecoder->setTool($tool); + $maskDecoder->setTool($toolName); $maskDecoder->setName($action); $maskDecoder->setValue($value); @@ -65,11 +65,11 @@ public function createToolMaskDecoder(Tool $tool, string $action, int $value): v /** * Returns an array containing the permission for a mask and a tool. */ - public function decodeMask(int $mask, Tool $tool): array + public function decodeMask(int $mask, string $toolName): array { - $decoders = $this->maskRepo->findMaskDecodersByTool($tool); $perms = []; + $decoders = $this->maskRepo->findMaskDecodersByTool($toolName); foreach ($decoders as $decoder) { $perms[$decoder->getName()] = ($mask & $decoder->getValue()) ? true : false; } @@ -83,11 +83,12 @@ public function decodeMask(int $mask, Tool $tool): array * * array('open' => true, 'edit' => false, ...) */ - public function encodeMask(array $perms, Tool $tool): int + public function encodeMask(array $perms, string $toolName): int { - $decoders = $this->maskRepo->findMaskDecodersByTool($tool); - $mask = 0; + + $decoders = $this->maskRepo->findMaskDecodersByTool($toolName); + foreach ($decoders as $decoder) { if (isset($perms[$decoder->getName()])) { $mask += $perms[$decoder->getName()] ? $decoder->getValue() : 0; @@ -100,18 +101,18 @@ public function encodeMask(array $perms, Tool $tool): int /** * @return ToolMaskDecoder[] */ - public function getMaskDecodersByTool(Tool $tool) + public function getMaskDecodersByTool(string $toolName) { - return $this->maskRepo->findMaskDecodersByTool($tool); + return $this->maskRepo->findMaskDecodersByTool($toolName); } - public function getMaskDecoderByToolAndName(Tool $tool, string $name): ?ToolMaskDecoder + public function getMaskDecoderByToolAndName(string $toolName, string $name): ?ToolMaskDecoder { - return $this->maskRepo->findMaskDecoderByToolAndName($tool, $name); + return $this->maskRepo->findMaskDecoderByToolAndName($toolName, $name); } - public function getCustomMaskDecodersByTool(Tool $tool) + public function getCustomMaskDecodersByTool(string $toolName) { - return $this->maskRepo->findCustomMaskDecodersByTool($tool); + return $this->maskRepo->findCustomMaskDecodersByTool($toolName); } } diff --git a/src/main/core/Manager/Workspace/TransferManager.php b/src/main/core/Manager/Workspace/TransferManager.php index 39252f9765c..53826f75b0a 100644 --- a/src/main/core/Manager/Workspace/TransferManager.php +++ b/src/main/core/Manager/Workspace/TransferManager.php @@ -11,6 +11,7 @@ use Claroline\AppBundle\Log\LoggableTrait; use Claroline\AppBundle\Manager\File\ArchiveManager; use Claroline\AppBundle\Persistence\ObjectManager; +use Claroline\CoreBundle\Component\Context\WorkspaceContext; use Claroline\CoreBundle\Entity\Role; use Claroline\CoreBundle\Entity\Tool\AbstractTool; use Claroline\CoreBundle\Entity\Tool\OrderedTool; @@ -58,7 +59,7 @@ public function __construct( $this->crud = $crud; } - public function import(string $archivePath, ?Workspace $workspace = null): Workspace + public function import(string $archivePath, Workspace $workspace = null): Workspace { $archive = new \ZipArchive(); $archive->open($archivePath); @@ -186,7 +187,7 @@ private function exportRoles(Workspace $workspace): array }, $workspace->getRoles()->toArray()); } - private function importRoles(array $data, Workspace $workspace, ?array $defaultRole = null): array + private function importRoles(array $data, Workspace $workspace, array $defaultRole = null): array { $roles = []; @@ -221,7 +222,7 @@ private function exportTools(Workspace $workspace, FileBag $fileBag): array $idx = null; foreach ($orderedTools as $key => $tool) { - if ('resources' === $tool->getTool()->getName()) { + if ('resources' === $tool->getName()) { $idx = $key; } } @@ -233,15 +234,15 @@ private function exportTools(Workspace $workspace, FileBag $fileBag): array array_unshift($orderedTools, $first); } - return array_map(function (OrderedTool $orderedTool) use ($fileBag) { + return array_map(function (OrderedTool $orderedTool) use ($workspace, $fileBag) { // get custom tool data /** @var ExportToolEvent $event */ - $event = $this->dispatcher->dispatch(ToolEvents::getEventName(ToolEvents::EXPORT, AbstractTool::WORKSPACE, $orderedTool->getTool()->getName()), ExportToolEvent::class, [ - $orderedTool->getTool()->getName(), AbstractTool::WORKSPACE, $orderedTool->getWorkspace(), $fileBag, + $event = $this->dispatcher->dispatch(ToolEvents::getEventName(ToolEvents::EXPORT, AbstractTool::WORKSPACE, $orderedTool->getName()), ExportToolEvent::class, [ + $orderedTool->getName(), AbstractTool::WORKSPACE, $workspace, $fileBag, ]); return [ - 'name' => $orderedTool->getTool()->getName(), + 'name' => $orderedTool->getName(), 'orderedTool' => $this->serializer->serialize($orderedTool, [SerializerInterface::SERIALIZE_TRANSFER]), 'rights' => array_map(function (ToolRights $rights) { return $this->serializer->serialize($rights, [SerializerInterface::SERIALIZE_TRANSFER]); @@ -257,40 +258,37 @@ private function importTools(array $data, Workspace $workspace, array $roles, Fi $createdObjects = $roles; // keep a map of old ID => new object for all imported objects foreach ($data['tools'] as $orderedToolData) { - $tool = $this->om->getRepository(Tool::class)->findOneBy(['name' => $orderedToolData['name']]); - if ($tool) { - $orderedTool = $this->serializer->deserialize($orderedToolData['orderedTool'], new OrderedTool(), [SerializerInterface::REFRESH_UUID]); - $orderedTool->setWorkspace($workspace); - $orderedTool->setTool($tool); - $this->om->persist($orderedTool); - - foreach ($orderedToolData['rights'] as $rightsData) { - if (empty($createdObjects[$rightsData['role']['id']])) { - continue; - } - - $rights = new ToolRights(); - $rights->setOrderedTool($orderedTool); - unset($rightsData['orderedToolId']); + $orderedTool = new OrderedTool(); + $orderedTool->setContextName(WorkspaceContext::getName()); + $orderedTool->setContextId($workspace->getUuid()); - $this->serializer->deserialize(array_merge($rightsData, [ - 'role' => [ - 'id' => $createdObjects[$rightsData['role']['id']]->getUuid(), - ], - ]), $rights); + $this->crud->create($orderedTool, $orderedToolData['orderedTool'], [SerializerInterface::REFRESH_UUID, Crud::NO_PERMISSIONS, Crud::THROW_EXCEPTION]); - $this->om->persist($rights); + foreach ($orderedToolData['rights'] as $rightsData) { + if (empty($createdObjects[$rightsData['role']['id']])) { + continue; } - /* @var ImportToolEvent $event */ - $event = $this->dispatcher->dispatch( - ToolEvents::getEventName(ToolEvents::IMPORT, AbstractTool::WORKSPACE, $orderedTool->getTool()->getName()), - ImportToolEvent::class, - [$orderedTool->getTool()->getName(), AbstractTool::WORKSPACE, $orderedTool->getWorkspace(), $fileBag, $orderedToolData['data'] ?? [], $createdObjects] - ); + $rights = new ToolRights(); + $rights->setOrderedTool($orderedTool); + + $this->serializer->deserialize(array_merge($rightsData, [ + 'role' => [ + 'id' => $createdObjects[$rightsData['role']['id']]->getUuid(), + ], + ]), $rights); - $createdObjects = array_merge([], $createdObjects, $event->getCreatedEntities()); + $this->om->persist($rights); } + + /* @var ImportToolEvent $event */ + $event = $this->dispatcher->dispatch( + ToolEvents::getEventName(ToolEvents::IMPORT, AbstractTool::WORKSPACE, $orderedTool->getName()), + ImportToolEvent::class, + [$orderedTool->getName(), AbstractTool::WORKSPACE, $workspace, $fileBag, $orderedToolData['data'] ?? [], $createdObjects] + ); + + $createdObjects = array_merge([], $createdObjects, $event->getCreatedEntities()); } $this->om->flush(); diff --git a/src/main/core/Manager/Workspace/WorkspaceManager.php b/src/main/core/Manager/Workspace/WorkspaceManager.php index 74302957fc7..41f214ae2fd 100644 --- a/src/main/core/Manager/Workspace/WorkspaceManager.php +++ b/src/main/core/Manager/Workspace/WorkspaceManager.php @@ -314,7 +314,6 @@ public function getDefaultModel($isPersonal = false, $restore = false): Workspac ['type' => 'tool', 'name' => 'resources'], ['type' => 'tool', 'name' => 'agenda'], ['type' => 'tool', 'name' => 'community'], - ['type' => 'tool', 'name' => 'dashboard'], ['type' => 'action', 'name' => 'favourite'], ['type' => 'action', 'name' => 'configure'], ['type' => 'action', 'name' => 'impersonation'], diff --git a/src/main/core/Manager/Workspace/WorkspaceRestrictionsManager.php b/src/main/core/Manager/Workspace/WorkspaceRestrictionsManager.php index ca39552963a..ff795f20d95 100644 --- a/src/main/core/Manager/Workspace/WorkspaceRestrictionsManager.php +++ b/src/main/core/Manager/Workspace/WorkspaceRestrictionsManager.php @@ -22,11 +22,11 @@ class WorkspaceRestrictionsManager { public function __construct( - private EventDispatcherInterface $dispatcher, - private RequestStack $requestStack, - private TokenStorageInterface $tokenStorage, - private WorkspaceManager $workspaceManager, - private WorkspaceUserQueueManager $workspaceUserQueueManager + private readonly EventDispatcherInterface $dispatcher, + private readonly RequestStack $requestStack, + private readonly TokenStorageInterface $tokenStorage, + private readonly WorkspaceManager $workspaceManager, + private readonly WorkspaceUserQueueManager $workspaceUserQueueManager ) { } diff --git a/src/main/core/Repository/Tool/OrderedToolRepository.php b/src/main/core/Repository/Tool/OrderedToolRepository.php index 950c2c329ba..2463052b4fd 100644 --- a/src/main/core/Repository/Tool/OrderedToolRepository.php +++ b/src/main/core/Repository/Tool/OrderedToolRepository.php @@ -12,174 +12,38 @@ namespace Claroline\CoreBundle\Repository\Tool; use Claroline\CoreBundle\Entity\Tool\OrderedTool; -use Claroline\CoreBundle\Entity\Workspace\Workspace; -use Claroline\CoreBundle\Manager\PluginManager; -use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository; -use Doctrine\Persistence\ManagerRegistry; +use Doctrine\ORM\EntityRepository; -class OrderedToolRepository extends ServiceEntityRepository +class OrderedToolRepository extends EntityRepository { - /** @var array */ - private $bundles; - - public function __construct(ManagerRegistry $registry, PluginManager $pluginManager) - { - $this->bundles = $pluginManager->getEnabled(); - - parent::__construct($registry, OrderedTool::class); - } - - public function findByName($name) - { - return $this->getEntityManager() - ->createQuery(' - SELECT ot - FROM Claroline\CoreBundle\Entity\Tool\OrderedTool ot - JOIN ot.tool t - WHERE t.name = :name - ORDER BY ot.order - ') - ->setParameter('name', $name) - ->getResult(); - } - - public function findOneByNameAndWorkspace(string $name, ?Workspace $workspace = null): ?OrderedTool - { - return $this->getEntityManager() - ->createQuery(' - SELECT ot - FROM Claroline\CoreBundle\Entity\Tool\OrderedTool ot - JOIN ot.tool t - WHERE ot.workspace = :workspace - AND t.name = :name - ORDER BY ot.order - ') - ->setParameter('workspace', $workspace) - ->setParameter('name', $name) - ->getOneOrNullResult(); - } - - /** - * Returns all the workspace ordered tools. - * - * @return OrderedTool[] - */ - public function findByWorkspace(Workspace $workspace) - { - return $this->getEntityManager() - ->createQuery(' - SELECT ot - FROM Claroline\CoreBundle\Entity\Tool\OrderedTool AS ot - JOIN ot.tool AS t - LEFT JOIN t.plugin AS p - WHERE ot.workspace = :workspace - AND ( - CONCAT(p.vendorName, p.bundleName) IN (:bundles) - OR t.plugin is NULL - ) - ORDER BY ot.order ASC - ') - ->setParameter('workspace', $workspace) - ->setParameter('bundles', $this->bundles) - ->getResult(); - } - - /** - * Returns the workspace ordered tools accessible to some given roles. - * - * @return OrderedTool[] - */ - public function findByWorkspaceAndRoles(Workspace $workspace, array $roles) + public function findByContext(string $context, string $contextId = null): array { - if (0 === count($roles)) { - return []; - } - return $this->getEntityManager() ->createQuery(' SELECT ot FROM Claroline\CoreBundle\Entity\Tool\OrderedTool AS ot - JOIN ot.tool AS t - LEFT JOIN t.plugin AS p - JOIN ot.rights AS r - JOIN r.role AS rr - WHERE ot.workspace = :workspace - AND rr.name IN (:roleNames) - AND BIT_AND(r.mask, 1) = 1 - AND ( - CONCAT(p.vendorName, p.bundleName) IN (:bundles) - OR t.plugin is NULL - ) - ORDER BY ot.order ASC + WHERE ot.contextName = :contextName + AND (ot.contextId IS NULL OR ot.contextId = :contextId) + ORDER BY ot.order ') - ->setParameter('workspace', $workspace) - ->setParameter('roleNames', $roles) - ->setParameter('bundles', $this->bundles) + ->setParameter('contextName', $context) + ->setParameter('contextId', $contextId) ->getResult(); } - public function findOneByNameAndDesktop(string $name): ?OrderedTool + public function findOneByNameAndContext(string $name, string $context, string $contextId = null): ?OrderedTool { return $this->getEntityManager() ->createQuery(' SELECT ot FROM Claroline\CoreBundle\Entity\Tool\OrderedTool ot - JOIN ot.tool t - WHERE ot.workspace IS NULL - AND ot.user IS NULL - AND t.name = :name - ORDER BY ot.order + WHERE ot.contextName = :contextName + AND (ot.contextId IS NULL OR ot.contextId = :contextId) + AND ot.name = :name ') ->setParameter('name', $name) + ->setParameter('contextName', $context) + ->setParameter('contextId', $contextId) ->getOneOrNullResult(); } - - public function findByDesktop() - { - return $this->getEntityManager() - ->createQuery(' - SELECT ot - FROM Claroline\CoreBundle\Entity\Tool\OrderedTool AS ot - JOIN ot.tool AS t - LEFT JOIN t.plugin AS p - WHERE ot.workspace IS NULL - AND ot.user IS NULL - AND ( - CONCAT(p.vendorName, p.bundleName) IN (:bundles) - OR t.plugin is NULL - ) - ORDER BY ot.order - ') - ->setParameter('bundles', $this->bundles) - ->getResult(); - } - - public function findByDesktopAndRoles(array $roles) - { - if (0 === count($roles)) { - return []; - } - - return $this->getEntityManager() - ->createQuery(' - SELECT ot - FROM Claroline\CoreBundle\Entity\Tool\OrderedTool AS ot - JOIN ot.tool AS t - LEFT JOIN t.plugin AS p - JOIN ot.rights AS r - JOIN r.role AS rr - WHERE ot.workspace IS NULL - AND ot.user IS NULL - AND rr.name IN (:roleNames) - AND BIT_AND(r.mask, 1) = 1 - AND ( - CONCAT(p.vendorName, p.bundleName) IN (:bundles) - OR t.plugin is NULL - ) - ORDER BY ot.order - ') - ->setParameter('roleNames', $roles) - ->setParameter('bundles', $this->bundles) - ->getResult(); - } } diff --git a/src/main/core/Repository/Tool/ToolMaskDecoderRepository.php b/src/main/core/Repository/Tool/ToolMaskDecoderRepository.php index c5b40482f3d..34f30b30c12 100644 --- a/src/main/core/Repository/Tool/ToolMaskDecoderRepository.php +++ b/src/main/core/Repository/Tool/ToolMaskDecoderRepository.php @@ -10,7 +10,6 @@ namespace Claroline\CoreBundle\Repository\Tool; -use Claroline\CoreBundle\Entity\Tool\Tool; use Claroline\CoreBundle\Entity\Tool\ToolMaskDecoder; use Doctrine\ORM\EntityRepository; @@ -18,8 +17,10 @@ class ToolMaskDecoderRepository extends EntityRepository { /** * @return ToolMaskDecoder[] + * + * @deprecated we don't need a custom repo method for this */ - public function findMaskDecodersByTool(Tool $tool) + public function findMaskDecodersByTool(string $toolName): array { $dql = ' SELECT tmd @@ -28,17 +29,15 @@ public function findMaskDecodersByTool(Tool $tool) ORDER BY tmd.value ASC '; $query = $this->getEntityManager()->createQuery($dql); - $query->setParameter('tool', $tool); + $query->setParameter('tool', $toolName); return $query->getResult(); } /** - * @param string $name - * - * @return ToolMaskDecoder|null + * @deprecated we don't need a custom repo method for this */ - public function findMaskDecoderByToolAndName(Tool $tool, $name) + public function findMaskDecoderByToolAndName(string $toolName, string $name): ?ToolMaskDecoder { $dql = ' SELECT tmd @@ -48,13 +47,13 @@ public function findMaskDecoderByToolAndName(Tool $tool, $name) ORDER BY tmd.value ASC '; $query = $this->getEntityManager()->createQuery($dql); - $query->setParameter('tool', $tool); + $query->setParameter('tool', $toolName); $query->setParameter('name', $name); return $query->getOneOrNullResult(); } - public function findCustomMaskDecodersByTool(Tool $tool) + public function findCustomMaskDecodersByTool(string $toolName): array { $dql = ' SELECT tmd @@ -64,7 +63,7 @@ public function findCustomMaskDecodersByTool(Tool $tool) ORDER BY tmd.value ASC '; $query = $this->getEntityManager()->createQuery($dql); - $query->setParameter('tool', $tool); + $query->setParameter('tool', $toolName); $query->setParameter('defaultActions', ToolMaskDecoder::DEFAULT_ACTIONS); return $query->getResult(); diff --git a/src/main/core/Repository/Tool/ToolRepository.php b/src/main/core/Repository/Tool/ToolRepository.php index 75be696d0a8..c72f529776d 100644 --- a/src/main/core/Repository/Tool/ToolRepository.php +++ b/src/main/core/Repository/Tool/ToolRepository.php @@ -17,6 +17,9 @@ use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository; use Doctrine\Persistence\ManagerRegistry; +/** + * @deprecated no longer needed + */ class ToolRepository extends ServiceEntityRepository { /** @var array */ diff --git a/src/main/core/Repository/Tool/ToolRightsRepository.php b/src/main/core/Repository/Tool/ToolRightsRepository.php index 7a21faab8c7..1bab665a8ae 100644 --- a/src/main/core/Repository/Tool/ToolRightsRepository.php +++ b/src/main/core/Repository/Tool/ToolRightsRepository.php @@ -10,8 +10,7 @@ namespace Claroline\CoreBundle\Repository\Tool; -use Claroline\CoreBundle\Entity\Tool\Tool; -use Claroline\CoreBundle\Entity\Workspace\Workspace; +use Claroline\CoreBundle\Entity\Tool\OrderedTool; use Doctrine\ORM\EntityRepository; class ToolRightsRepository extends EntityRepository @@ -19,9 +18,9 @@ class ToolRightsRepository extends EntityRepository /** * Returns the maximum rights on a given tool for a set of roles. */ - public function findMaximumRights(array $roles, Tool $tool, Workspace $workspace = null): int + public function findMaximumRights(array $roles, OrderedTool $orderedTool): int { - //add the role anonymous for everyone ! + // add the role anonymous for everyone ! if (!in_array('ROLE_ANONYMOUS', $roles)) { $roles[] = 'ROLE_ANONYMOUS'; } @@ -31,26 +30,15 @@ public function findMaximumRights(array $roles, Tool $tool, Workspace $workspace FROM Claroline\CoreBundle\Entity\Tool\ToolRights AS tr JOIN tr.role AS role JOIN tr.orderedTool AS ot - JOIN ot.tool AS t - WHERE t.id = :toolId + WHERE ot.id = :toolId AND role.name IN (:roles) '; - if (!empty($workspace)) { - $dql .= ' AND ot.workspace = :workspace'; - } else { - $dql .= ' AND ot.workspace IS NULL'; - } - $query = $this->getEntityManager() ->createQuery($dql) - ->setParameter('toolId', $tool->getId()) + ->setParameter('toolId', $orderedTool->getId()) ->setParameter('roles', $roles); - if (!empty($workspace)) { - $query->setParameter('workspace', $workspace); - } - $results = $query->getResult(); $mask = 0; diff --git a/src/main/core/Repository/WorkspaceRepository.php b/src/main/core/Repository/WorkspaceRepository.php index 318ed678934..d01dd4f6ac8 100644 --- a/src/main/core/Repository/WorkspaceRepository.php +++ b/src/main/core/Repository/WorkspaceRepository.php @@ -11,6 +11,7 @@ namespace Claroline\CoreBundle\Repository; +use Claroline\CoreBundle\Component\Context\WorkspaceContext; use Claroline\CoreBundle\Entity\Workspace\Workspace; use Doctrine\ORM\EntityRepository; @@ -73,9 +74,10 @@ public function findByRoles(array $roleNames) FROM Claroline\CoreBundle\Entity\Tool\OrderedTool ot JOIN ot.rights otr JOIN otr.role otrr - WHERE ot.workspace = w - AND otrr.name in (:roles) - AND BIT_AND(otr.mask, 1) = 1 + WHERE ot.contextName = "workspace" + AND ot.contextId = w.uuid + AND otrr.name in (:roles) + AND BIT_AND(otr.mask, 1) = 1 ) ') @@ -83,16 +85,19 @@ public function findByRoles(array $roleNames) ->getResult(); } - public function checkAccess(Workspace $workspace, array $roleNames, ?string $toolName = null, ?string $action = 'open') + /** + * @deprecated + */ + public function checkAccess(Workspace $workspace, array $roleNames, string $toolName = null, ?string $action = 'open') { $dql = ' SELECT COUNT(ot) FROM Claroline\CoreBundle\Entity\Tool\OrderedTool ot - JOIN ot.workspace w JOIN ot.tool t JOIN ot.rights r JOIN r.role rr - WHERE w.id = :workspaceId + WHERE ot.contextName = :contextName + AND ot.contextId = :workspaceId AND rr.name IN (:roleNames) AND EXISTS ( SELECT d @@ -108,7 +113,8 @@ public function checkAccess(Workspace $workspace, array $roleNames, ?string $too } $query = $this->getEntityManager()->createQuery($dql); - $query->setParameter('workspaceId', $workspace->getId()); + $query->setParameter('workspaceId', $workspace->getUuid()); + $query->setParameter('contextName', WorkspaceContext::getName()); $query->setParameter('roleNames', $roleNames); $query->setParameter('action', strtoupper($action)); diff --git a/src/main/core/Resources/config/components.yml b/src/main/core/Resources/config/components.yml index 56582d270ef..99833132c83 100644 --- a/src/main/core/Resources/config/components.yml +++ b/src/main/core/Resources/config/components.yml @@ -1,2 +1,3 @@ imports: - { resource: components/context.yml } + - { resource: components/tool.yml } diff --git a/src/main/core/Resources/config/components/tool.yml b/src/main/core/Resources/config/components/tool.yml new file mode 100644 index 00000000000..cbec0df3f4a --- /dev/null +++ b/src/main/core/Resources/config/components/tool.yml @@ -0,0 +1,16 @@ +services: + Claroline\CoreBundle\Component\Tool\ParametersTool: + parent: Claroline\AppBundle\Component\Tool\AbstractTool + tags: [ 'claroline.component.tool' ] + arguments: + - '@Claroline\CoreBundle\API\Serializer\ParametersSerializer' + - '@Claroline\CoreBundle\Manager\LocaleManager' + + Claroline\CoreBundle\Component\Tool\ResourcesTool: + parent: Claroline\AppBundle\Component\Tool\AbstractTool + tags: [ 'claroline.component.tool' ] + arguments: + - '@Claroline\AppBundle\Persistence\ObjectManager' + - '@event_dispatcher' + - '@Claroline\AppBundle\API\SerializerProvider' + - '@Claroline\AppBundle\API\Crud' diff --git a/src/main/core/Resources/config/routing.yml b/src/main/core/Resources/config/routing.yml index 24ff678f58c..77b53354f53 100644 --- a/src/main/core/Resources/config/routing.yml +++ b/src/main/core/Resources/config/routing.yml @@ -3,14 +3,6 @@ claro_authentication: type: annotation options: { expose: true } -claro_workspace: - resource: "@ClarolineCoreBundle/Controller/WorkspaceController.php" - type: annotation - -claro_admin: - resource: "@ClarolineCoreBundle/Controller/AdministrationController.php" - type: annotation - claro_resource: resource: "@ClarolineCoreBundle/Controller/ResourceController.php" type: annotation diff --git a/src/main/core/Resources/config/services/controller.yml b/src/main/core/Resources/config/services/controller.yml index 1d0c983b29e..b1e652230e3 100644 --- a/src/main/core/Resources/config/services/controller.yml +++ b/src/main/core/Resources/config/services/controller.yml @@ -2,13 +2,6 @@ services: _defaults: public: true # because controller - Claroline\CoreBundle\Controller\APINew\Log\LogConnectController: - arguments: - - '@security.authorization_checker' - - '@Claroline\AppBundle\API\FinderProvider' - - '@Claroline\CoreBundle\Manager\LogConnectManager' - - '@Claroline\CoreBundle\Manager\Tool\ToolManager' - Claroline\CoreBundle\Controller\APINew\Platform\PluginController: parent: Claroline\AppBundle\Controller\AbstractSecurityController public: true @@ -69,24 +62,6 @@ services: - '@Claroline\AppBundle\API\SerializerProvider' - '@Claroline\CoreBundle\Manager\Template\TemplateManager' - Claroline\CoreBundle\Controller\APINew\Context\ContextController: - arguments: - - '@security.token_storage' - - '@event_dispatcher' - - '@Claroline\AppBundle\API\SerializerProvider' - - '@Claroline\AppBundle\Component\Context\ContextProvider' - - Claroline\CoreBundle\Controller\APINew\Context\ToolController: - arguments: - - '@security.authorization_checker' - - '@security.token_storage' - - '@Claroline\AppBundle\Persistence\ObjectManager' - - '@event_dispatcher' - - '@Claroline\AppBundle\API\Crud' - - '@Claroline\AppBundle\API\SerializerProvider' - - '@Claroline\CoreBundle\Manager\Tool\ToolManager' - - '@Claroline\CoreBundle\Manager\LogConnectManager' - Claroline\CoreBundle\Controller\APINew\Workspace\RegistrationController: arguments: - '@security.authorization_checker' @@ -110,12 +85,11 @@ services: arguments: - '@security.token_storage' - '@security.authorization_checker' - - '@Claroline\AppBundle\Event\StrictDispatcher' - '@messenger.default_bus' + - '@Claroline\AppBundle\Manager\File\TempFileManager' - '@Claroline\CoreBundle\Manager\RoleManager' - '@Claroline\CoreBundle\Manager\Workspace\WorkspaceManager' - - '@Claroline\CoreBundle\Manager\LogConnectManager' - - '@Claroline\AppBundle\Manager\File\TempFileManager' + - '@Claroline\CoreBundle\Manager\Workspace\WorkspaceRestrictionsManager' Claroline\CoreBundle\Controller\APINew\Platform\ConnectionMessageController: parent: Claroline\AppBundle\Controller\AbstractCrudController @@ -165,13 +139,6 @@ services: - '@Claroline\CoreBundle\Manager\WidgetManager' - '@Claroline\CoreBundle\Manager\DataSourceManager' - Claroline\CoreBundle\Controller\AdministrationController: - arguments: - - '@security.authorization_checker' - - '@security.token_storage' - - '@Claroline\CoreBundle\Manager\Tool\ToolManager' - - '@Claroline\AppBundle\Event\StrictDispatcher' - Claroline\CoreBundle\Controller\AuthenticationController: arguments: - '@Claroline\CoreBundle\Manager\UserManager' @@ -208,18 +175,6 @@ services: - '@Claroline\CoreBundle\Library\Configuration\PlatformConfigurationHandler' - '@event_dispatcher' - Claroline\CoreBundle\Controller\WorkspaceController: - arguments: - - '@security.authorization_checker' - - '@Claroline\AppBundle\Persistence\ObjectManager' - - '@security.token_storage' - - '@Claroline\AppBundle\API\SerializerProvider' - - '@Claroline\CoreBundle\Manager\Tool\ToolManager' - - '@Claroline\CoreBundle\Manager\Workspace\WorkspaceManager' - - '@Claroline\CoreBundle\Manager\Workspace\WorkspaceRestrictionsManager' - - '@Claroline\EvaluationBundle\Manager\WorkspaceEvaluationManager' - - '@Claroline\AppBundle\Event\StrictDispatcher' - Claroline\CoreBundle\Controller\APINew\Location\LocationController: parent: Claroline\AppBundle\Controller\AbstractCrudController public: true @@ -238,3 +193,4 @@ services: public: true arguments: - '@security.authorization_checker' + - '@Claroline\CoreBundle\Manager\Tool\ToolManager' diff --git a/src/main/core/Resources/config/services/finder.yml b/src/main/core/Resources/config/services/finder.yml index 5ed9581bbb5..99a7585aac6 100644 --- a/src/main/core/Resources/config/services/finder.yml +++ b/src/main/core/Resources/config/services/finder.yml @@ -41,18 +41,6 @@ services: - '@security.authorization_checker' - '@security.token_storage' - Claroline\CoreBundle\API\Finder\Tool\ToolFinder: - parent: Claroline\AppBundle\API\Finder\AbstractFinder - tags: [ claroline.finder ] - arguments: - - '@Claroline\CoreBundle\Manager\PluginManager' - - Claroline\CoreBundle\API\Finder\Tool\AdminToolFinder: - parent: Claroline\AppBundle\API\Finder\AbstractFinder - tags: [ claroline.finder ] - arguments: - - '@Claroline\CoreBundle\Manager\PluginManager' - Claroline\CoreBundle\API\Finder\Tool\OrderedToolFinder: parent: Claroline\AppBundle\API\Finder\AbstractFinder tags: [ claroline.finder ] diff --git a/src/main/core/Resources/config/services/library.yml b/src/main/core/Resources/config/services/library.yml index b1fbeee5749..25f55dcedb3 100644 --- a/src/main/core/Resources/config/services/library.yml +++ b/src/main/core/Resources/config/services/library.yml @@ -16,23 +16,11 @@ services: Claroline\CoreBundle\Library\Installation\Plugin\Loader: ~ - Claroline\CoreBundle\Library\Installation\Plugin\Installer: - arguments: - - '@claroline.plugin.validator' - - '@Claroline\CoreBundle\Library\Installation\Plugin\Recorder' - - '@Claroline\InstallationBundle\Manager\InstallationManager' - - '@Claroline\AppBundle\Persistence\ObjectManager' - - '@Claroline\CoreBundle\Manager\PluginManager' - - '@Claroline\CoreBundle\Manager\VersionManager' - calls: - - setLogger: [ '@logger' ] - Claroline\CoreBundle\Library\Installation\Plugin\DatabaseWriter: arguments: - '@Claroline\AppBundle\Persistence\ObjectManager' - '@Claroline\CoreBundle\Manager\Resource\MaskManager' - '@filesystem' - - '@Claroline\CoreBundle\Manager\Tool\ToolManager' - '@Claroline\CoreBundle\Manager\Tool\ToolMaskDecoderManager' - '@Claroline\ThemeBundle\Manager\IconSetBuilderManager' calls: @@ -43,17 +31,6 @@ services: - '@claroline.symfony_yaml' - '@doctrine.orm.entity_manager' - Claroline\CoreBundle\Library\Installation\PlatformInstaller: - arguments: - - '@kernel' - - '@Claroline\CoreBundle\Manager\PluginManager' - - '@Claroline\CoreBundle\Library\Installation\Plugin\Installer' - - '@Claroline\AppBundle\Persistence\ObjectManager' - - '@Claroline\InstallationBundle\Manager\InstallationManager' - - '@service_container' - calls: - - setLogger: [ '@logger' ] - Claroline\CoreBundle\Library\Mailing\TransportFactory: arguments: - '@Claroline\CoreBundle\Library\Configuration\PlatformConfigurationHandler' diff --git a/src/main/core/Resources/config/services/repository.yml b/src/main/core/Resources/config/services/repository.yml index ae1e01a3526..91eb440b7d2 100644 --- a/src/main/core/Resources/config/services/repository.yml +++ b/src/main/core/Resources/config/services/repository.yml @@ -8,11 +8,6 @@ services: - '@Doctrine\Persistence\ManagerRegistry' - '@Claroline\CoreBundle\Manager\PluginManager' - Claroline\CoreBundle\Repository\Tool\OrderedToolRepository: - arguments: - - '@Doctrine\Persistence\ManagerRegistry' - - '@Claroline\CoreBundle\Manager\PluginManager' - Claroline\CoreBundle\Repository\Resource\ResourceActionRepository: arguments: - '@Doctrine\Persistence\ManagerRegistry' diff --git a/src/main/core/Resources/config/services/serializer.yml b/src/main/core/Resources/config/services/serializer.yml index 0b262736b2b..534a047c62b 100644 --- a/src/main/core/Resources/config/services/serializer.yml +++ b/src/main/core/Resources/config/services/serializer.yml @@ -31,9 +31,6 @@ services: Claroline\CoreBundle\API\Serializer\DataSourceSerializer: tags: [claroline.serializer] - Claroline\CoreBundle\API\Serializer\Tool\AdminToolSerializer: - tags: [claroline.serializer] - Claroline\CoreBundle\API\Serializer\Workspace\WorkspaceSerializer: tags: [claroline.serializer] arguments: @@ -118,9 +115,6 @@ services: - '@Claroline\CoreBundle\Manager\LocaleManager' - '@request_stack' - Claroline\CoreBundle\API\Serializer\Tool\ToolSerializer: - tags: [claroline.serializer] - Claroline\CoreBundle\API\Serializer\Tool\ToolRightsSerializer: tags: [ claroline.serializer ] arguments: @@ -214,31 +208,6 @@ services: - '@Claroline\CoreBundle\API\Serializer\Workspace\WorkspaceSerializer' - '@Claroline\CoreBundle\API\Serializer\Resource\ResourceNodeSerializer' - Claroline\CoreBundle\API\Serializer\Log\Connection\LogConnectWorkspaceSerializer: - tags: [claroline.serializer] - arguments: - - '@Claroline\AppBundle\API\SerializerProvider' - - Claroline\CoreBundle\API\Serializer\Log\Connection\LogConnectToolSerializer: - tags: [claroline.serializer] - arguments: - - '@Claroline\AppBundle\API\SerializerProvider' - - Claroline\CoreBundle\API\Serializer\Log\Connection\LogConnectResourceSerializer: - tags: [claroline.serializer] - arguments: - - '@Claroline\AppBundle\API\SerializerProvider' - - Claroline\CoreBundle\API\Serializer\Log\Connection\LogConnectPlatformSerializer: - tags: [claroline.serializer] - arguments: - - '@Claroline\AppBundle\API\SerializerProvider' - - Claroline\CoreBundle\API\Serializer\Log\Connection\LogConnectAdminToolSerializer: - tags: [claroline.serializer] - arguments: - - '@Claroline\AppBundle\API\SerializerProvider' - Claroline\CoreBundle\API\Serializer\File\PublicFileSerializer: tags: [claroline.serializer] arguments: diff --git a/src/main/core/Resources/config/services/updater.yml b/src/main/core/Resources/config/services/updater.yml index 1ac4e7b576f..4d9ee767e5a 100644 --- a/src/main/core/Resources/config/services/updater.yml +++ b/src/main/core/Resources/config/services/updater.yml @@ -1,12 +1,16 @@ services: - _defaults: - tags: [ 'claroline.platform.updater' ] + _defaults: + tags: [ 'claroline.platform.updater' ] - Claroline\CoreBundle\Installation\Updater\Updater140000: - arguments: - - '@kernel' - - '@doctrine.dbal.default_connection' + Claroline\CoreBundle\Installation\Updater\Updater140000: + arguments: + - '@kernel' + - '@doctrine.dbal.default_connection' - Claroline\CoreBundle\Installation\Updater\Updater140010: - arguments: - - '@doctrine.dbal.default_connection' + Claroline\CoreBundle\Installation\Updater\Updater140010: + arguments: + - '@doctrine.dbal.default_connection' + + Claroline\CoreBundle\Installation\Updater\Updater140100: + arguments: + - '@Claroline\AppBundle\Persistence\ObjectManager' diff --git a/src/main/core/Resources/config/services/voter.yml b/src/main/core/Resources/config/services/voter.yml index eca9a836a14..5e9304f7487 100644 --- a/src/main/core/Resources/config/services/voter.yml +++ b/src/main/core/Resources/config/services/voter.yml @@ -8,18 +8,12 @@ services: Claroline\CoreBundle\Security\Voter\Template\TemplateVoter: parent: Claroline\AppBundle\Security\Voter\AbstractVoter - Claroline\CoreBundle\Security\Voter\Tool\ToolVoter: + Claroline\CoreBundle\Security\Voter\Tool\OrderedToolVoter: parent: Claroline\AppBundle\Security\Voter\AbstractVoter arguments: - '@Claroline\AppBundle\Persistence\ObjectManager' - '@Claroline\CoreBundle\Manager\Tool\ToolMaskDecoderManager' - Claroline\CoreBundle\Security\Voter\Tool\OrderedToolVoter: - parent: Claroline\AppBundle\Security\Voter\AbstractVoter - - Claroline\CoreBundle\Security\Voter\Tool\AdministrationToolVoter: - parent: Claroline\AppBundle\Security\Voter\AbstractVoter - Claroline\CoreBundle\Security\Voter\PublicFileVoter: parent: Claroline\AppBundle\Security\Voter\AbstractVoter diff --git a/src/main/core/Resources/modules/account/parameters/index.js b/src/main/core/Resources/modules/account/parameters/index.js index 666c132b0db..5f964db6f64 100644 --- a/src/main/core/Resources/modules/account/parameters/index.js +++ b/src/main/core/Resources/modules/account/parameters/index.js @@ -1,11 +1,9 @@ -import {trans} from '#/main/app/intl/translation' - import {ParametersMain} from '#/main/core/account/parameters/containers/main' export default { - name: 'parameters', + /*name: 'parameters', icon: 'fa fa-fw fa-cog', label: trans('parameters'), - component: ParametersMain, - order: 2 + */component: ParametersMain/*, + order: 2*/ } diff --git a/src/main/core/Resources/modules/administration/connection-messages/modals/slide/components/modal.jsx b/src/main/core/Resources/modules/administration/connection-messages/modals/slide/components/modal.jsx index 3b03609aa46..965ba13ed3d 100644 --- a/src/main/core/Resources/modules/administration/connection-messages/modals/slide/components/modal.jsx +++ b/src/main/core/Resources/modules/administration/connection-messages/modals/slide/components/modal.jsx @@ -10,7 +10,8 @@ import {User as UserTypes} from '#/main/community/prop-types' import {Select} from '#/main/app/input/components/select' import {getActions} from '#/main/core/desktop' -import {getTools} from '#/main/core/tools' +import {getTools} from '#/main/core/tool/utils' + const ShortcutRow = (props) => { let shortcutChoices = {} if ('action' === props.value.type) { @@ -68,7 +69,7 @@ class SlideFormModal extends Component { this.state = { actions: [], - tools: Object.keys(getTools(this.props.currentUser)) || [] + tools: Object.keys(getTools()) || [] } } diff --git a/src/main/core/Resources/modules/administration/index.js b/src/main/core/Resources/modules/administration/index.js deleted file mode 100644 index 262eed9224b..00000000000 --- a/src/main/core/Resources/modules/administration/index.js +++ /dev/null @@ -1,32 +0,0 @@ -import identity from 'lodash/identity' - -import {getApp, getApps} from '#/main/app/plugins' - -function getTool(name) { - return getApp('administration', name)() -} - -function getActions(user, desktopRefresher = {}) { - // adds default refresher actions - const refresher = Object.assign({ - add: identity, - update: identity, - delete: identity - }, desktopRefresher) - - // get all actions declared for workspace - const actions = getApps('actions.administration') - - return Promise.all( - // boot actions applications - Object.keys(actions).map(action => actions[action]()) - ).then((loadedActions) => loadedActions - // generate action - .map(actionModule => actionModule.default(user, refresher)) - ) -} - -export { - getTool, - getActions -} diff --git a/src/main/core/Resources/modules/plugin.js b/src/main/core/Resources/modules/plugin.js index d4e8571a7cf..243eab3fa1c 100644 --- a/src/main/core/Resources/modules/plugin.js +++ b/src/main/core/Resources/modules/plugin.js @@ -39,6 +39,7 @@ registry.add('ClarolineCoreBundle', { * Provides actions for base Claroline objects. */ actions: { + account: {}, administration: {}, desktop: {}, @@ -113,7 +114,6 @@ registry.add('ClarolineCoreBundle', { tools: { 'workspaces' : () => { return import(/* webpackChunkName: "core-tool-workspaces" */ '#/main/core/tools/workspaces') }, 'resources' : () => { return import(/* webpackChunkName: "core-tool-resources" */ '#/main/core/tools/resources') }, - 'parameters' : () => { return import(/* webpackChunkName: "core-tool-parameters" */ '#/main/core/tools/parameters') }, 'resource_trash' : () => { return import(/* webpackChunkName: "core-tool-trash" */ '#/main/core/tools/trash') }, 'locations' : () => { return import(/* webpackChunkName: "core-tool-locations" */ '#/main/core/tools/locations') } }, diff --git a/src/main/core/Resources/modules/tool/components/main.jsx b/src/main/core/Resources/modules/tool/components/main.jsx index 513c2b0790d..80974f092ca 100644 --- a/src/main/core/Resources/modules/tool/components/main.jsx +++ b/src/main/core/Resources/modules/tool/components/main.jsx @@ -10,9 +10,7 @@ import {ContentLoader} from '#/main/app/content/components/loader' import {ContentForbidden} from '#/main/app/content/components/forbidden' import {ContentNotFound} from '#/main/app/content/components/not-found' -import {constants} from '#/main/core/tool/constants' -import {getTool} from '#/main/core/tools' -import {getTool as getAdminTool} from '#/main/core/administration' +import {getTool} from '#/main/core/tool/utils' const Tool = props => { if (props.loaded) { @@ -116,14 +114,9 @@ class ToolMain extends Component { if (!this.pendingApp) { this.setState({appLoaded: false}) - let app - if (constants.TOOL_ADMINISTRATION === this.props.contextType) { - app = getAdminTool(this.props.toolName) - } else { - app = getTool(this.props.toolName) - } - - this.pendingApp = makeCancelable(app) + this.pendingApp = makeCancelable( + getTool(this.props.toolName, this.props.contextType) + ) this.pendingApp.promise .then( diff --git a/src/main/core/Resources/modules/tool/components/menu.jsx b/src/main/core/Resources/modules/tool/components/menu.jsx index f2862ca87ba..3b9a74a156a 100644 --- a/src/main/core/Resources/modules/tool/components/menu.jsx +++ b/src/main/core/Resources/modules/tool/components/menu.jsx @@ -3,22 +3,13 @@ import {PropTypes as T} from 'prop-types' import {Await} from '#/main/app/components/await' -import {constants} from '#/main/core/tool/constants' -import {getTool} from '#/main/core/tools' -import {getTool as getAdminTool} from '#/main/core/administration' +import {getTool} from '#/main/core/tool/utils' const ToolMenu = props => { - if (props.name && props.loaded) { - let app - if (constants.TOOL_ADMINISTRATION === props.contextType) { - app = getAdminTool(props.name) - } else { - app = getTool(props.name) - } - + if (props.name && props.loaded && !props.notFound) { return ( { if (module.default.menu) { return createElement(module.default.menu, { @@ -43,6 +34,7 @@ ToolMenu.propTypes = { name: T.string, contextType: T.string, loaded: T.bool.isRequired, + notFound: T.bool.isRequired, // from menu opened: T.bool.isRequired, diff --git a/src/main/core/Resources/modules/tool/components/page.jsx b/src/main/core/Resources/modules/tool/components/page.jsx index 6baedd8933f..3a7fe3e95c0 100644 --- a/src/main/core/Resources/modules/tool/components/page.jsx +++ b/src/main/core/Resources/modules/tool/components/page.jsx @@ -83,7 +83,7 @@ ToolPage.propTypes = { permissions: T.object.isRequired }), currentContext: T.shape({ - type: T.oneOf(['administration', 'desktop', 'workspace']), + type: T.oneOf(['administration', 'desktop', 'workspace', 'account', 'home']), data: T.object }).isRequired, // the name of the primary action of the tool (if we want to override the default one). diff --git a/src/main/core/Resources/modules/tool/constants.js b/src/main/core/Resources/modules/tool/constants.js index 90422392f4b..3f49a29f94c 100644 --- a/src/main/core/Resources/modules/tool/constants.js +++ b/src/main/core/Resources/modules/tool/constants.js @@ -5,11 +5,13 @@ const TOOL_HOME = 'home' const TOOL_DESKTOP = 'desktop' const TOOL_WORKSPACE = 'workspace' const TOOL_ADMINISTRATION = 'administration' +const TOOL_ACCOUNT = 'account' const TOOL_TYPES = { [TOOL_DESKTOP]: trans('desktop_tool'), [TOOL_WORKSPACE]: trans('workspace_tool'), - [TOOL_ADMINISTRATION]: trans('administration_tool') + [TOOL_ADMINISTRATION]: trans('administration_tool'), + [TOOL_ACCOUNT]: trans('account_tool') } export const constants = { @@ -17,5 +19,6 @@ export const constants = { TOOL_HOME, TOOL_DESKTOP, TOOL_WORKSPACE, - TOOL_ADMINISTRATION + TOOL_ADMINISTRATION, + TOOL_ACCOUNT } diff --git a/src/main/core/Resources/modules/tool/containers/menu.jsx b/src/main/core/Resources/modules/tool/containers/menu.jsx index 664d326809f..46dbcaa237c 100644 --- a/src/main/core/Resources/modules/tool/containers/menu.jsx +++ b/src/main/core/Resources/modules/tool/containers/menu.jsx @@ -13,7 +13,8 @@ const ToolMenu = withRouter( contextType: selectors.contextType(state), name: selectors.name(state), path: selectors.path(state), - loaded: selectors.loaded(state) + loaded: selectors.loaded(state), + notFound: selectors.notFound(state) }) )(ToolMenuComponent) ) diff --git a/src/main/core/Resources/modules/tool/modals/parameters/components/modal.jsx b/src/main/core/Resources/modules/tool/modals/parameters/components/modal.jsx index 879f6458928..240a9aef5b8 100644 --- a/src/main/core/Resources/modules/tool/modals/parameters/components/modal.jsx +++ b/src/main/core/Resources/modules/tool/modals/parameters/components/modal.jsx @@ -8,7 +8,7 @@ import {CALLBACK_BUTTON} from '#/main/app/buttons' import {Modal} from '#/main/app/overlays/modal/components/modal' import {FormData} from '#/main/app/content/form/containers/data' -import {getTool} from '#/main/core/tools' +import {getTool} from '#/main/core/tool/utils' import {selectors} from '#/main/core/tool/modals/parameters/store' class ParametersModal extends Component { @@ -21,7 +21,7 @@ class ParametersModal extends Component { } componentDidMount() { - getTool(this.props.toolName).then((module) => { + getTool(this.props.toolName, this.props.currentContext.type).then((module) => { let parametersComponent = null if (module.default && module.default.parameters) { parametersComponent = module.default.parameters diff --git a/src/main/core/Resources/modules/tool/store/reducer.js b/src/main/core/Resources/modules/tool/store/reducer.js index 05dd8e63a6f..df3e62cd7fe 100644 --- a/src/main/core/Resources/modules/tool/store/reducer.js +++ b/src/main/core/Resources/modules/tool/store/reducer.js @@ -15,6 +15,7 @@ import { const reducer = combineReducers({ name: makeReducer(null, { + [CONTEXT_OPEN]: () => null, [TOOL_OPEN]: (state, action) => action.name }), diff --git a/src/main/core/Resources/modules/tool/utils.js b/src/main/core/Resources/modules/tool/utils.js index cb7f71c09f3..cad5c1ad261 100644 --- a/src/main/core/Resources/modules/tool/utils.js +++ b/src/main/core/Resources/modules/tool/utils.js @@ -4,7 +4,7 @@ import identity from 'lodash/identity' import {trans} from '#/main/app/intl/translation' import {LINK_BUTTON} from '#/main/app/buttons' import {showBreadcrumb} from '#/main/app/layout/utils' -import {getApps} from '#/main/app/plugins' +import {getApp, getApps} from '#/main/app/plugins' import {constants} from '#/main/core/tool/constants' @@ -12,6 +12,26 @@ import {route as toolRoute} from '#/main/core/tool/routing' import {route as workspaceRoute} from '#/main/core/workspace/routing' import {route as adminRoute} from '#/main/core/administration/routing' +function getTools(contextType) { + if (constants.TOOL_ADMINISTRATION === contextType) { + return getApps('administration') + } else if (constants.TOOL_ACCOUNT === contextType) { + return getApps('account') + } + + return getApps('tools') +} + +function getTool(name, contextType) { + if (constants.TOOL_ADMINISTRATION === contextType) { + return getApp('administration', name)() + } else if (constants.TOOL_ACCOUNT === contextType) { + return getApp('account', name)() + } + + return getApp('tools', name)() +} + function getActions(tool, context, toolRefresher, path, currentUser) { // adds default refresher actions const refresher = Object.assign({ @@ -47,6 +67,25 @@ function getToolBreadcrumb(toolName = null, contextType, contextData = {}) { let path = [] switch (contextType) { + case constants.TOOL_ACCOUNT: + path = [ + { + type: LINK_BUTTON, + label: trans('account'), + target: '/account' + } + ] + + if (toolName) { + path.push({ + type: LINK_BUTTON, + label: trans(toolName, {}, 'tools'), + target: toolRoute(toolName) + }) + } + + break + case constants.TOOL_DESKTOP: path = [ { @@ -144,6 +183,8 @@ function showToolBreadcrumb(contextType, contextData) { } export { + getTools, + getTool, getActions, getToolBreadcrumb, showToolBreadcrumb diff --git a/src/main/core/Resources/modules/tools/index.js b/src/main/core/Resources/modules/tools/index.js deleted file mode 100644 index 2463e6f8196..00000000000 --- a/src/main/core/Resources/modules/tools/index.js +++ /dev/null @@ -1,14 +0,0 @@ -import {getApp, getApps} from '#/main/app/plugins' - -function getTools() { - return getApps('tools') -} - -function getTool(name) { - return getApp('tools', name)() -} - -export { - getTools, - getTool -} diff --git a/src/main/core/Resources/modules/tools/parameters/components/menu.jsx b/src/main/core/Resources/modules/tools/parameters/components/menu.jsx deleted file mode 100644 index 876edbbcd3c..00000000000 --- a/src/main/core/Resources/modules/tools/parameters/components/menu.jsx +++ /dev/null @@ -1,56 +0,0 @@ -import React from 'react' -import {PropTypes as T} from 'prop-types' -import omit from 'lodash/omit' - -import {trans} from '#/main/app/intl/translation' -import {LINK_BUTTON} from '#/main/app/buttons' -import {Toolbar} from '#/main/app/action/components/toolbar' -import {MenuSection} from '#/main/app/layout/menu/components/section' - -const ParametersMenu = (props) => - - - - -ParametersMenu.propTypes = { - path: T.string, - - // from menu - opened: T.bool.isRequired, - toggle: T.func.isRequired, - autoClose: T.func.isRequired -} - -export { - ParametersMenu -} diff --git a/src/main/core/Resources/modules/tools/parameters/components/tool.jsx b/src/main/core/Resources/modules/tools/parameters/components/tool.jsx deleted file mode 100644 index d4f29d3825f..00000000000 --- a/src/main/core/Resources/modules/tools/parameters/components/tool.jsx +++ /dev/null @@ -1,31 +0,0 @@ -import React from 'react' -import {PropTypes as T} from 'prop-types' - -import {Routes} from '#/main/app/router' - -// TODO : make it dynamic -import {ExternalTool} from '#/main/core/tools/parameters/external/components/tool' -import {TokensTool} from '#/main/core/tools/parameters/tokens/containers/tool' - -const ParametersTool = (props) => - - -ParametersTool.propTypes = { - path: T.string.isRequired -} - -export { - ParametersTool -} diff --git a/src/main/core/Resources/modules/tools/parameters/external/components/tool.jsx b/src/main/core/Resources/modules/tools/parameters/external/components/tool.jsx deleted file mode 100644 index a698d0b60a4..00000000000 --- a/src/main/core/Resources/modules/tools/parameters/external/components/tool.jsx +++ /dev/null @@ -1,26 +0,0 @@ -import React from 'react' -import {PropTypes as T} from 'prop-types' - -import {trans} from '#/main/app/intl/translation' -import {LINK_BUTTON} from '#/main/app/buttons' -import {ToolPage} from '#/main/core/tool/containers/page' - -const ExternalTool = (props) => - - - - -ExternalTool.propTypes = { - path: T.string.isRequired -} - -export { - ExternalTool -} diff --git a/src/main/core/Resources/modules/tools/parameters/external/containers/tool.jsx b/src/main/core/Resources/modules/tools/parameters/external/containers/tool.jsx deleted file mode 100644 index bc0e3daeac4..00000000000 --- a/src/main/core/Resources/modules/tools/parameters/external/containers/tool.jsx +++ /dev/null @@ -1,24 +0,0 @@ -import {connect} from 'react-redux' - -import {withReducer} from '#/main/app/store/components/withReducer' - -import {ExternalTool as ExternalToolComponent} from '#/main/core/tools/parameters/external/components/tool' -import {actions, reducer, selectors} from '#/main/core/tools/parameters/external/store/actions' - -const ExternalTool = withReducer(selectors.STORE_NAME, reducer)( - connect( - (state) => ({ - loaded: selectors.loaded(state), - accounts: selectors.accounts(state) - }), - (dispatch) => ({ - loadAccounts() { - dispatch(actions.fetchAccounts()) - } - }) - )(ExternalToolComponent) -) - -export { - ExternalTool -} diff --git a/src/main/core/Resources/modules/tools/parameters/external/store/actions.js b/src/main/core/Resources/modules/tools/parameters/external/store/actions.js deleted file mode 100644 index 847cdee4fab..00000000000 --- a/src/main/core/Resources/modules/tools/parameters/external/store/actions.js +++ /dev/null @@ -1,15 +0,0 @@ -import {makeActionCreator} from '#/main/app/store/actions' -import {API_REQUEST} from '#/main/app/api' - -export const USER_LOAD_EXTERNAL_ACCOUNTS = 'USER_LOAD_EXTERNAL_ACCOUNTS' - -export const actions = {} - -actions.loadAccounts = makeActionCreator(USER_LOAD_EXTERNAL_ACCOUNTS, 'data') - -actions.fetchAccounts = () => ({ - [API_REQUEST]: { - url: [], - success: (response, dispatch) => dispatch(actions.loadAccounts(response)) - } -}) diff --git a/src/main/core/Resources/modules/tools/parameters/external/store/index.js b/src/main/core/Resources/modules/tools/parameters/external/store/index.js deleted file mode 100644 index c4411c7a537..00000000000 --- a/src/main/core/Resources/modules/tools/parameters/external/store/index.js +++ /dev/null @@ -1,10 +0,0 @@ - -import {actions} from '#/main/core/tools/parameters/external/store/actions' -import {reducer} from '#/main/core/tools/parameters/external/store/reducer' -import {selectors} from '#/main/core/tools/parameters/external/store/selectors' - -export { - actions, - reducer, - selectors -} diff --git a/src/main/core/Resources/modules/tools/parameters/external/store/reducer.js b/src/main/core/Resources/modules/tools/parameters/external/store/reducer.js deleted file mode 100644 index 734f52812da..00000000000 --- a/src/main/core/Resources/modules/tools/parameters/external/store/reducer.js +++ /dev/null @@ -1,12 +0,0 @@ -import {makeReducer, combineReducers} from '#/main/app/store/reducer' - -import {USER_LOAD_EXTERNAL_ACCOUNTS} from '#/main/core/tools/parameters/external/store/actions' - -export const reducer = combineReducers({ - accounts: makeReducer([], { - [USER_LOAD_EXTERNAL_ACCOUNTS]: (state, action) => action.data - }), - loaded: makeReducer(false, { - [USER_LOAD_EXTERNAL_ACCOUNTS]: () => true - }) -}) \ No newline at end of file diff --git a/src/main/core/Resources/modules/tools/parameters/external/store/selectors.js b/src/main/core/Resources/modules/tools/parameters/external/store/selectors.js deleted file mode 100644 index b02e4b74d32..00000000000 --- a/src/main/core/Resources/modules/tools/parameters/external/store/selectors.js +++ /dev/null @@ -1,22 +0,0 @@ -import {createSelector} from 'reselect' - -const STORE_NAME = 'userExternalParameters' - -const store = (state) => state[STORE_NAME] - -const loaded = createSelector( - [store], - (store) => store.loaded -) - -const accounts = createSelector( - [store], - (store) => store.accounts -) - -export const selectors = { - STORE_NAME, - - loaded, - accounts -} diff --git a/src/main/core/Resources/modules/tools/parameters/index.js b/src/main/core/Resources/modules/tools/parameters/index.js deleted file mode 100644 index 86db770a9e7..00000000000 --- a/src/main/core/Resources/modules/tools/parameters/index.js +++ /dev/null @@ -1,9 +0,0 @@ -import {reducer} from '#/main/core/tools/parameters/store/reducer' -import {ParametersTool} from '#/main/core/tools/parameters/components/tool' -import {ParametersMenu} from '#/main/core/tools/parameters/components/menu' - -export default { - menu: ParametersMenu, - component: ParametersTool, - store: reducer -} diff --git a/src/main/core/Resources/modules/tools/parameters/store/index.js b/src/main/core/Resources/modules/tools/parameters/store/index.js deleted file mode 100644 index 161a22e0555..00000000000 --- a/src/main/core/Resources/modules/tools/parameters/store/index.js +++ /dev/null @@ -1,11 +0,0 @@ -/** - * Desktop parameters store. - */ - -import {reducer} from '#/main/core/tools/parameters/store/reducer' -import {selectors} from '#/main/core/tools/parameters/store/selectors' - -export { - reducer, - selectors -} diff --git a/src/main/core/Resources/modules/tools/parameters/store/reducer.js b/src/main/core/Resources/modules/tools/parameters/store/reducer.js deleted file mode 100644 index 412be5c9cf3..00000000000 --- a/src/main/core/Resources/modules/tools/parameters/store/reducer.js +++ /dev/null @@ -1,26 +0,0 @@ -import {makeInstanceAction} from '#/main/app/store/actions' -import {makeFormReducer} from '#/main/app/content/form/store/reducer' -import {reducer as tokenReducer} from '#/main/core/tools/parameters/tokens/store/reducer' -import {combineReducers, makeReducer} from '#/main/app/store/reducer' - -import {TOOL_LOAD} from '#/main/core/tool/store/actions' -import {selectors} from '#/main/core/tools/parameters/store/selectors' - -const reducer = combineReducers({ - tools: makeReducer([], { - [makeInstanceAction(TOOL_LOAD, selectors.STORE_NAME)]: (state, action) => action.toolData.tools - }), - toolsConfig: makeFormReducer(selectors.STORE_NAME+'.toolsConfig', {}, { - originalData: makeReducer([], { - [makeInstanceAction(TOOL_LOAD, selectors.STORE_NAME)]: (state, action) => action.toolData.toolsConfig - }), - data: makeReducer([], { - [makeInstanceAction(TOOL_LOAD, selectors.STORE_NAME)]: (state, action) => action.toolData.toolsConfig - }) - }), - tokens: tokenReducer -}) - -export { - reducer -} diff --git a/src/main/core/Resources/modules/tools/parameters/store/selectors.js b/src/main/core/Resources/modules/tools/parameters/store/selectors.js deleted file mode 100644 index 926209d656b..00000000000 --- a/src/main/core/Resources/modules/tools/parameters/store/selectors.js +++ /dev/null @@ -1,21 +0,0 @@ -import {createSelector} from 'reselect' - -const STORE_NAME = 'parameters' - -const store = (state) => state[STORE_NAME] - -const tools = createSelector( - [store], - (store) => store.tools -) - -const toolsConfig = createSelector( - [store], - (store) => store.toolsConfig -) - -export const selectors = { - STORE_NAME, - tools, - toolsConfig -} diff --git a/src/main/core/Resources/modules/tools/parameters/tokens/components/token.jsx b/src/main/core/Resources/modules/tools/parameters/tokens/components/token.jsx deleted file mode 100644 index 35a76cf2a5f..00000000000 --- a/src/main/core/Resources/modules/tools/parameters/tokens/components/token.jsx +++ /dev/null @@ -1,58 +0,0 @@ -import React from 'react' -import {PropTypes as T} from 'prop-types' -import {connect} from 'react-redux' - -import {trans} from '#/main/app/intl/translation' -import {FormData} from '#/main/app/content/form/containers/data' -import {LINK_BUTTON} from '#/main/app/buttons' -import {selectors as toolSelectors} from '#/main/core/tool/store' - -import {selectors} from '#/main/core/tools/parameters/store/selectors' - -const TokenForm = (props) => - ['apiv2_apitoken_update', {id: token.id}]} - cancel={{ - type: LINK_BUTTON, - target: props.path + '/tokens', - exact: true - }} - sections={[ - { - title: trans('general'), - primary: true, - fields: [ - { - name: 'description', - type: 'string', - label: trans('description'), - required: true - }, - { - name: 'token', - type: 'string', - label: trans('token'), - required: true, - disabled: true - } - ] - } - ]} - /> - -TokenForm.propTypes = { - path: T.string.isRequired -} - -const Token = connect( - state => ({ - path: toolSelectors.path(state) - }) -)(TokenForm) - -export { - Token -} diff --git a/src/main/core/Resources/modules/tools/parameters/tokens/components/tokens.jsx b/src/main/core/Resources/modules/tools/parameters/tokens/components/tokens.jsx deleted file mode 100644 index be480668841..00000000000 --- a/src/main/core/Resources/modules/tools/parameters/tokens/components/tokens.jsx +++ /dev/null @@ -1,43 +0,0 @@ -import React from 'react' - -import {trans} from '#/main/app/intl/translation' -import {LINK_BUTTON} from '#/main/app/buttons' -import {ListData} from '#/main/app/content/list/containers/data' - -import {selectors} from '#/main/core/tools/parameters/store/selectors' - -const Tokens = () => - ({ - type: LINK_BUTTON, - target: `/tokens/${row.id}`, - label: trans('edit', {}, 'actions') - })} - delete={{ - url: ['apiv2_apitoken_delete_bulk'] - }} - definition={[ - { - name: 'token', - type: 'string', - label: trans('token'), - displayed: true, - primary: true - }, - { - name: 'description', - type: 'string', - label: trans('description'), - displayed: true - } - ]} - /> - -export { - Tokens -} diff --git a/src/main/core/Resources/modules/tools/parameters/tokens/components/tool.jsx b/src/main/core/Resources/modules/tools/parameters/tokens/components/tool.jsx deleted file mode 100644 index a6ff2347118..00000000000 --- a/src/main/core/Resources/modules/tools/parameters/tokens/components/tool.jsx +++ /dev/null @@ -1,54 +0,0 @@ -import React from 'react' -import {PropTypes as T} from 'prop-types' - -import {trans} from '#/main/app/intl/translation' -import {Routes} from '#/main/app/router' -import {LINK_BUTTON} from '#/main/app/buttons' -import {ToolPage} from '#/main/core/tool/containers/page' - -import {Tokens} from '#/main/core/tools/parameters/tokens/components/tokens' -import {Token} from '#/main/core/tools/parameters/tokens/components/token' - -const TokensTool = props => - - props.openForm(params.id) - } - ]} - /> - - -TokensTool.propTypes = { - path: T.string.isRequired, - openForm: T.func.isRequired -} - -export { - TokensTool -} diff --git a/src/main/core/Resources/modules/tools/parameters/tokens/containers/tool.jsx b/src/main/core/Resources/modules/tools/parameters/tokens/containers/tool.jsx deleted file mode 100644 index 5f2ad5693a3..00000000000 --- a/src/main/core/Resources/modules/tools/parameters/tokens/containers/tool.jsx +++ /dev/null @@ -1,22 +0,0 @@ -import {connect} from 'react-redux' - -import {selectors as toolSelectors} from '#/main/core/tool/store' - -import {selectors} from '#/main/core/tools/parameters/store/selectors' -import {TokensTool as TokensToolComponent} from '#/main/core/tools/parameters/tokens/components/tool' -import {actions} from '#/main/core/tools/parameters/tokens/store/actions' - -const TokensTool = connect( - (state) => ({ - path: toolSelectors.path(state) - }), - dispatch => ({ - openForm(id) { - dispatch(actions.open(selectors.STORE_NAME+'.tokens.current', id)) - } - }) -)(TokensToolComponent) - -export { - TokensTool -} diff --git a/src/main/core/Resources/modules/tools/parameters/tokens/store/actions.js b/src/main/core/Resources/modules/tools/parameters/tokens/store/actions.js deleted file mode 100644 index 33bdbc46bef..00000000000 --- a/src/main/core/Resources/modules/tools/parameters/tokens/store/actions.js +++ /dev/null @@ -1,33 +0,0 @@ -import {url} from '#/main/app/api/router' - -import {API_REQUEST} from '#/main/app/api' -import {actions as listActions} from '#/main/app/content/list/store/actions' -import {actions as formActions} from '#/main/app/content/form/store/actions' - -import {selectors} from '#/main/core/tools/parameters/store/selectors' - -export const actions = {} - -actions.create = () => ({ - [API_REQUEST]: { - url: url(['apiv2_apitoken_create']), - request: { - method: 'POST', - body: JSON.stringify({}) - }, - success: (data, dispatch) => { - dispatch(listActions.invalidateData(selectors.STORE_NAME+'tokens.list')) - } - } -}) - -actions.open = (formName, id) => { - if (id) { - return { - [API_REQUEST]: { - url: ['apiv2_apitoken_get', {id}], - success: (response, dispatch) => dispatch(formActions.resetForm(formName, response, false)) - } - } - } -} diff --git a/src/main/core/Resources/modules/tools/parameters/tokens/store/index.js b/src/main/core/Resources/modules/tools/parameters/tokens/store/index.js deleted file mode 100644 index c5eaa9374a1..00000000000 --- a/src/main/core/Resources/modules/tools/parameters/tokens/store/index.js +++ /dev/null @@ -1,11 +0,0 @@ -/** - * Desktop parameters store. - */ - -import {reducer} from '#/main/core/tools/parameters/tokens/store/reducer' -import {selectors} from '#/main/core/tools/parameters/tokens/store/selectors' - -export { - reducer, - selectors -} diff --git a/src/main/core/Resources/modules/tools/parameters/tokens/store/reducer.js b/src/main/core/Resources/modules/tools/parameters/tokens/store/reducer.js deleted file mode 100644 index 8fe1a82d20f..00000000000 --- a/src/main/core/Resources/modules/tools/parameters/tokens/store/reducer.js +++ /dev/null @@ -1,20 +0,0 @@ -import {makeListReducer} from '#/main/app/content/list/store' -import {combineReducers, makeReducer} from '#/main/app/store/reducer' -import {makeFormReducer} from '#/main/app/content/form/store/reducer' -import {makeInstanceAction} from '#/main/app/store/actions' - -import {TOOL_LOAD} from '#/main/core/tool/store/actions' -import {selectors} from '#/main/core/tools/parameters/store/selectors' - -const reducer = combineReducers({ - list: makeListReducer(selectors.STORE_NAME+'.tokens.list', {}, { - invalidated: makeReducer(false, { - [makeInstanceAction(TOOL_LOAD, selectors.STORE_NAME)]: () => true - }) - }), - current: makeFormReducer(selectors.STORE_NAME+'.tokens.current') -}) - -export { - reducer -} diff --git a/src/main/core/Security/Voter/ResourceVoter.php b/src/main/core/Security/Voter/ResourceVoter.php index e5d07ec221e..1ed7523ba2d 100644 --- a/src/main/core/Security/Voter/ResourceVoter.php +++ b/src/main/core/Security/Voter/ResourceVoter.php @@ -201,12 +201,12 @@ private function checkAction(string $action, array $nodes, TokenInterface $token } } - //the workspace manager he can do w/e he wants + // the workspace manager he can do w/e he wants if ($haveSameWorkspace && $ws && $this->workspaceManager->isManager($ws, $token)) { return []; } - //the resource creator can do w/e he wants + // the resource creator can do w/e he wants $timesCreator = 0; foreach ($nodes as $node) { @@ -215,12 +215,12 @@ private function checkAction(string $action, array $nodes, TokenInterface $token } } - //but it only work if he's not usurping a workspace role to see if everything is good + // but it only works if he's not usurping a workspace role to see if everything is good if ($timesCreator === count($nodes) && !$this->workspaceManager->isImpersonated($token)) { return []; } - //check if the action is possible on the node + // check if the action is possible on the node $errors = []; $action = strtolower($action); @@ -233,11 +233,11 @@ private function checkAction(string $action, array $nodes, TokenInterface $token $adminDecoder = $this->maskManager->getDecoder($type, 'administrate'); $canAdministrate = $adminDecoder ? (0 !== ($mask & $adminDecoder->getValue())) : false; // If user can administrate OR resource is open then check action - if ($canAdministrate || - ($this->restrictionsManager->isStarted($node) && - !$this->restrictionsManager->isEnded($node) && - $node->isPublished())) { - //gotta check + if ($canAdministrate + || ($this->restrictionsManager->isStarted($node) + && !$this->restrictionsManager->isEnded($node) + && $node->isPublished())) { + // gotta check if (!$decoder) { return ['The permission '.$action.' does not exists for the type '.$type->getName()]; } @@ -276,7 +276,7 @@ private function checkCreation($type, ResourceNode $node, TokenInterface $token) return $errors; } - //otherwise we need to check + // otherwise we need to check $rightsCreation = $this->repository->findCreationRights($token->getRoleNames(), $node); if (!$this->canCreate($rightsCreation, $type)) { @@ -306,16 +306,16 @@ private function checkMove(ResourceNode $parent, array $nodes, TokenInterface $t { $errors = []; - //first I need to know if I can create + // first I need to know if I can create foreach ($nodes as $node) { $type = $node->getResourceType()->getName(); $errors = array_merge($errors, $this->checkCreation($type, $parent, $token)); } - //then I need to know if I can copy + // then I need to know if I can copy $errors = array_merge($errors, $this->checkCopy($parent, $nodes, $token)); - //and finally I need to know if I can delete + // and finally I need to know if I can delete $errors = array_merge($errors, $this->checkAction('DELETE', $nodes, $token)); return $errors; @@ -329,7 +329,7 @@ private function checkMove(ResourceNode $parent, array $nodes, TokenInterface $t */ private function checkCopy(ResourceNode $parent, array $nodes, TokenInterface $token): array { - //first I need to know if I can create what I want in the parent directory + // first I need to know if I can create what I want in the parent directory $errors = []; foreach ($nodes as $node) { @@ -337,7 +337,7 @@ private function checkCopy(ResourceNode $parent, array $nodes, TokenInterface $t $errors = array_merge($errors, $this->checkCreation($type, $parent, $token)); } - //then we need to know if we can copy + // then we need to know if we can copy $errors = array_merge($errors, $this->checkAction('COPY', $nodes, $token)); return $errors; diff --git a/src/main/core/Security/Voter/Tool/AdministrationToolVoter.php b/src/main/core/Security/Voter/Tool/AdministrationToolVoter.php deleted file mode 100644 index 00ad03b1f51..00000000000 --- a/src/main/core/Security/Voter/Tool/AdministrationToolVoter.php +++ /dev/null @@ -1,49 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Claroline\CoreBundle\Security\Voter\Tool; - -use Claroline\AppBundle\Security\Voter\AbstractVoter; -use Claroline\CoreBundle\Entity\Tool\AdminTool; -use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; -use Symfony\Component\Security\Core\Authorization\Voter\VoterInterface; - -class AdministrationToolVoter extends AbstractVoter -{ - /** - * @param AdminTool $object - */ - public function checkPermission(TokenInterface $token, $object, array $attributes, array $options): int - { - $roles = $object->getRoles(); - $tokenRoles = $token->getRoleNames(); - foreach ($tokenRoles as $tokenRole) { - foreach ($roles as $role) { - if ($role->getRole() === $tokenRole) { - return VoterInterface::ACCESS_GRANTED; - } - } - } - - return VoterInterface::ACCESS_DENIED; - } - - public function getClass(): string - { - return AdminTool::class; - } - - public function getSupportedActions(): ?array - { - //atm, null means "everything is supported... implement this later" - return null; - } -} diff --git a/src/main/core/Security/Voter/Tool/OrderedToolVoter.php b/src/main/core/Security/Voter/Tool/OrderedToolVoter.php index 6934e4d06aa..58e8cd777da 100644 --- a/src/main/core/Security/Voter/Tool/OrderedToolVoter.php +++ b/src/main/core/Security/Voter/Tool/OrderedToolVoter.php @@ -11,9 +11,12 @@ namespace Claroline\CoreBundle\Security\Voter\Tool; +use Claroline\AppBundle\Persistence\ObjectManager; use Claroline\AppBundle\Security\Voter\AbstractVoter; use Claroline\CoreBundle\Entity\Tool\OrderedTool; -use Claroline\CoreBundle\Security\ToolPermissions; +use Claroline\CoreBundle\Entity\Tool\ToolRights; +use Claroline\CoreBundle\Manager\Tool\ToolMaskDecoderManager; +use Claroline\CoreBundle\Repository\Tool\ToolRightsRepository; use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; use Symfony\Component\Security\Core\Authorization\Voter\VoterInterface; @@ -23,24 +26,35 @@ */ class OrderedToolVoter extends AbstractVoter { + private ToolMaskDecoderManager $maskManager; + private ToolRightsRepository $rightsRepository; + + public function __construct( + ObjectManager $om, + ToolMaskDecoderManager $maskManager + ) { + $this->maskManager = $maskManager; + $this->rightsRepository = $om->getRepository(ToolRights::class); + } + /** * @param OrderedTool $object */ public function checkPermission(TokenInterface $token, $object, array $attributes, array $options): int { - if (!empty($object->getWorkspace())) { - // let the workspace voter decide - $isGranted = $this->isGranted(ToolPermissions::getPermission($object->getTool()->getName(), $attributes[0]), $object->getWorkspace()); - } else { - // let the base tool voter decide - $isGranted = $this->isGranted($attributes[0], $object->getTool()); - } + // FIXME : admin bypass will not work + $decoder = $this->maskManager->getMaskDecoderByToolAndName($object->getName(), $attributes[0]); + if ($decoder) { + $mask = $this->rightsRepository->findMaximumRights($token->getRoleNames(), $object); + + if ($mask & $decoder->getValue()) { + return VoterInterface::ACCESS_GRANTED; + } - if ($isGranted) { - return VoterInterface::ACCESS_GRANTED; + return VoterInterface::ACCESS_DENIED; } - return VoterInterface::ACCESS_DENIED; + return VoterInterface::ACCESS_ABSTAIN; } public function getClass(): string @@ -50,7 +64,7 @@ public function getClass(): string public function getSupportedActions(): ?array { - //atm, null means "everything is supported... implement this later" + // atm, null means "everything is supported... implement this later" return null; } } diff --git a/src/main/core/Security/Voter/Tool/ToolVoter.php b/src/main/core/Security/Voter/Tool/ToolVoter.php deleted file mode 100644 index 3d278903252..00000000000 --- a/src/main/core/Security/Voter/Tool/ToolVoter.php +++ /dev/null @@ -1,65 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Claroline\CoreBundle\Security\Voter\Tool; - -use Claroline\AppBundle\Persistence\ObjectManager; -use Claroline\AppBundle\Security\Voter\AbstractVoter; -use Claroline\CoreBundle\Entity\Tool\Tool; -use Claroline\CoreBundle\Entity\Tool\ToolRights; -use Claroline\CoreBundle\Manager\Tool\ToolMaskDecoderManager; -use Claroline\CoreBundle\Repository\Tool\ToolRightsRepository; -use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; -use Symfony\Component\Security\Core\Authorization\Voter\VoterInterface; - -/** - * ATTENTION : it does not work with Workspace tools. For them, it's the OrderedToolVoter or WorkspaceVoter. - */ -class ToolVoter extends AbstractVoter -{ - private ToolMaskDecoderManager $maskManager; - private ToolRightsRepository $rightsRepository; - - public function __construct( - ObjectManager $om, - ToolMaskDecoderManager $maskManager - ) { - $this->maskManager = $maskManager; - $this->rightsRepository = $om->getRepository(ToolRights::class); - } - - public function checkPermission(TokenInterface $token, $object, array $attributes, array $options): int - { - $decoder = $this->maskManager->getMaskDecoderByToolAndName($object, $attributes[0]); - if ($decoder) { - $mask = $this->rightsRepository->findMaximumRights($token->getRoleNames(), $object); - - if ($mask & $decoder->getValue()) { - return VoterInterface::ACCESS_GRANTED; - } - - return VoterInterface::ACCESS_DENIED; - } - - return VoterInterface::ACCESS_ABSTAIN; - } - - public function getClass(): string - { - return Tool::class; - } - - public function getSupportedActions(): ?array - { - // atm, null means "everything is supported... implement this later" - return null; - } -} diff --git a/src/main/core/Tests/Repository/Tool/OrderedToolRepositoryTest.php b/src/main/core/Tests/Repository/Tool/OrderedToolRepositoryTest.php deleted file mode 100644 index 70b397b3afd..00000000000 --- a/src/main/core/Tests/Repository/Tool/OrderedToolRepositoryTest.php +++ /dev/null @@ -1,40 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Claroline\CoreBundle\Tests\Repository\Tool; - -use Claroline\CoreBundle\Entity\Tool\OrderedTool; -use Claroline\CoreBundle\Library\Testing\RepositoryTestCase; - -class OrderedToolRepositoryTest extends RepositoryTestCase -{ - public static $repo; - - public static function setUpBeforeClass(): void - { - parent::setUpBeforeClass(); - self::$repo = self::getRepository(OrderedTool::class); - - self::createWorkspace('ws_1'); - self::createRole('ROLE_1', self::get('ws_1')); - self::createRole('ROLE_2', self::get('ws_1')); - self::createTool('tool_1'); - self::createTool('tool_2'); - self::createWorkspaceTool(self::get('tool_1'), self::get('ws_1'), [self::get('ROLE_1')], 1); - self::createWorkspaceTool(self::get('tool_2'), self::get('ws_1'), [self::get('ROLE_2')], 1); - } - - public function testFindByWorkspaceAndRole() - { - $tools = self::$repo->findByWorkspaceAndRoles(self::get('ws_1'), ['ROLE_1', 'ROLE_2']); - $this->assertEquals(2, count($tools)); - } -} diff --git a/src/main/core/Tests/Repository/Tool/ToolRepositoryTest.php b/src/main/core/Tests/Repository/Tool/ToolRepositoryTest.php deleted file mode 100644 index 381ee2d3359..00000000000 --- a/src/main/core/Tests/Repository/Tool/ToolRepositoryTest.php +++ /dev/null @@ -1,58 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Claroline\CoreBundle\Tests\Repository\Tool; - -use Claroline\CoreBundle\Entity\Tool\Tool; -use Claroline\CoreBundle\Library\Testing\RepositoryTestCase; - -class ToolRepositoryTest extends RepositoryTestCase -{ - /** @var ToolRepository */ - private static $repo; - - public static function setUpBeforeClass(): void - { - parent::setUpBeforeClass(); - - self::$repo = self::getRepository(Tool::class); - - self::createUser('john'); - self::createWorkspace('ws_1'); - self::createTool('tool_1'); - self::createTool('tool_2'); - self::createRole('ROLE_1', self::get('ws_1')); - self::createRole('ROLE_2', self::get('ws_1')); - self::createWorkspaceTool(self::get('tool_1'), self::get('ws_1'), [self::get('ROLE_1')], 1); - self::createWorkspaceTool(self::get('tool_2'), self::get('ws_1'), [self::get('ROLE_2')], 1); - self::createDesktopTool(self::get('tool_2'), self::get('john'), 1); - } - - public function testFindUndisplayedToolsByWorkspace() - { - $result = self::$repo->findUndisplayedToolsByWorkspace(self::get('ws_1')); - $toolNames = array_map(function (Tool $tool) { - return $tool->getName(); - }, $result); - - // I cannot check the number of tools returned because it can change over time. - // Also the claroline instance can contain plugins which inject tools from the outside of the distribution bundle. - // Instead I will just check for some of the expected tools from the core - $this->assertTrue(in_array('home', $toolNames)); - $this->assertTrue(in_array('community', $toolNames)); - $this->assertTrue(in_array('resources', $toolNames)); - } - - public function testCountDisplayedToolsByWorkspace() - { - $this->assertEquals(2, self::$repo->countDisplayedToolsByWorkspace(self::get('ws_1'))); - } -} diff --git a/src/main/core/Tests/Repository/WorkspaceRepositoryTest.php b/src/main/core/Tests/Repository/WorkspaceRepositoryTest.php index 92b65cc6e04..df7adce01a4 100644 --- a/src/main/core/Tests/Repository/WorkspaceRepositoryTest.php +++ b/src/main/core/Tests/Repository/WorkspaceRepositoryTest.php @@ -35,14 +35,9 @@ public static function setUpBeforeClass(): void self::createRole('ROLE_4', self::get('ws_4')); self::createRole('ROLE_5', self::get('ws_5')); self::createRole('ROLE_ANONYMOUS'); - self::createTool('tool_1'); - self::createTool('tool_2'); - self::createWorkspaceTool(self::get('tool_1'), self::get('ws_1'), [self::get('ROLE_ANONYMOUS')], 1); - self::createWorkspaceTool(self::get('tool_2'), self::get('ws_2'), [self::get('ROLE_2')], 1); + self::createWorkspaceTool('tool_1', self::get('ws_1'), [self::get('ROLE_ANONYMOUS')], 1); + self::createWorkspaceTool('tool_2', self::get('ws_2'), [self::get('ROLE_2')], 1); self::createUser('john', [self::get('ROLE_1'), self::get('ROLE_2')], self::get('ws_1')); - self::createLog(self::get('john'), 'workspace-tool-read', self::get('ws_1')); - self::sleep(1); // dates involved - self::createLog(self::get('john'), 'workspace-tool-read', self::get('ws_2')); self::createResourceType('t_dir', 'Directory'); self::createDirectory('dir_1', self::get('t_dir'), self::get('john'), self::get('ws_2')); self::createDirectory('dir_2', self::get('t_dir'), self::get('john'), self::get('ws_2')); diff --git a/src/main/dev/DependencyInjection/ClarolineDevExtension.php b/src/main/dev/DependencyInjection/ClarolineDevExtension.php index 54212ba0ced..34f69b3e1a2 100644 --- a/src/main/dev/DependencyInjection/ClarolineDevExtension.php +++ b/src/main/dev/DependencyInjection/ClarolineDevExtension.php @@ -21,10 +21,7 @@ */ class ClarolineDevExtension extends Extension { - /** - * {@inheritdoc} - */ - public function load(array $configs, ContainerBuilder $container) + public function load(array $configs, ContainerBuilder $container): void { $locator = new FileLocator(__DIR__.'/../Resources/config'); $loader = new YamlFileLoader($container, $locator); diff --git a/src/main/evaluation/Controller/WorkspaceEvaluationController.php b/src/main/evaluation/Controller/WorkspaceEvaluationController.php index d64d0e8c40c..ee75c2adeb2 100644 --- a/src/main/evaluation/Controller/WorkspaceEvaluationController.php +++ b/src/main/evaluation/Controller/WorkspaceEvaluationController.php @@ -17,13 +17,15 @@ use Claroline\AppBundle\API\SerializerProvider; use Claroline\AppBundle\Controller\RequestDecoderTrait; use Claroline\AppBundle\Persistence\ObjectManager; +use Claroline\CoreBundle\Component\Context\DesktopContext; +use Claroline\CoreBundle\Component\Context\WorkspaceContext; use Claroline\CoreBundle\Entity\Resource\ResourceNode; use Claroline\CoreBundle\Entity\Resource\ResourceUserEvaluation; -use Claroline\CoreBundle\Entity\Tool\OrderedTool; use Claroline\CoreBundle\Entity\User; use Claroline\CoreBundle\Entity\Workspace\Evaluation; use Claroline\CoreBundle\Entity\Workspace\Workspace; use Claroline\CoreBundle\Library\Normalizer\TextNormalizer; +use Claroline\CoreBundle\Manager\Tool\ToolManager; use Claroline\CoreBundle\Security\PermissionCheckerTrait; use Claroline\EvaluationBundle\Manager\PdfManager; use Claroline\EvaluationBundle\Manager\WorkspaceEvaluationManager; @@ -46,14 +48,15 @@ class WorkspaceEvaluationController use PermissionCheckerTrait; public function __construct( - private TokenStorageInterface $tokenStorage, AuthorizationCheckerInterface $authorization, - private ObjectManager $om, - private Crud $crud, - private FinderProvider $finder, - private SerializerProvider $serializer, - private WorkspaceEvaluationManager $manager, - private PdfManager $pdfManager + private readonly TokenStorageInterface $tokenStorage, + private readonly ObjectManager $om, + private readonly Crud $crud, + private readonly FinderProvider $finder, + private readonly SerializerProvider $serializer, + private readonly WorkspaceEvaluationManager $manager, + private readonly PdfManager $pdfManager, + private readonly ToolManager $toolManager ) { $this->authorization = $authorization; } @@ -339,7 +342,7 @@ public function removeRequiredResourcesAction(Workspace $workspace, Request $req $resources = $this->decodeIdsString($request, ResourceNode::class); - // we can not do it inside a flush suite because it will trigger the Workspace to recompute its evaluation + // we can not do it inside a flush suite because it will trigger the Workspace to recompute its evaluation, // and it requires to have all the data recorded inside the db. // we can create a messenger message for it later if there are performances issues. foreach ($resources as $resource) { @@ -358,9 +361,9 @@ public function removeRequiredResourcesAction(Workspace $workspace, Request $req private function checkToolAccess(string $permission, Workspace $workspace = null, bool $exception = true): bool { if (!empty($workspace)) { - $evaluationTool = $this->om->getRepository(OrderedTool::class)->findOneByNameAndWorkspace('evaluation', $workspace); + $evaluationTool = $this->toolManager->getOrderedTool('evaluation', WorkspaceContext::getName(), $workspace->getUuid()); } else { - $evaluationTool = $this->om->getRepository(OrderedTool::class)->findOneByNameAndDesktop('evaluation'); + $evaluationTool = $this->toolManager->getOrderedTool('evaluation', DesktopContext::getName()); } return $this->checkPermission($permission, $evaluationTool, [], $exception); diff --git a/src/main/evaluation/DependencyInjection/ClarolineEvaluationExtension.php b/src/main/evaluation/DependencyInjection/ClarolineEvaluationExtension.php index 87ce2ccdcdf..8447be546d3 100644 --- a/src/main/evaluation/DependencyInjection/ClarolineEvaluationExtension.php +++ b/src/main/evaluation/DependencyInjection/ClarolineEvaluationExtension.php @@ -18,7 +18,7 @@ class ClarolineEvaluationExtension extends Extension { - public function load(array $configs, ContainerBuilder $container) + public function load(array $configs, ContainerBuilder $container): void { $locator = new FileLocator(__DIR__.'/../Resources/config'); $loader = new YamlFileLoader($container, $locator); diff --git a/src/main/evaluation/Installation/ClarolineEvaluationInstaller.php b/src/main/evaluation/Installation/ClarolineEvaluationInstaller.php index 045b3daffb1..048fa872cf0 100644 --- a/src/main/evaluation/Installation/ClarolineEvaluationInstaller.php +++ b/src/main/evaluation/Installation/ClarolineEvaluationInstaller.php @@ -19,9 +19,4 @@ public function hasFixtures(): bool { return true; } - - public function hasMigrations(): bool - { - return false; - } } diff --git a/src/main/evaluation/Resources/config/services/controller.yml b/src/main/evaluation/Resources/config/services/controller.yml index 8f922b39506..bd8d3c27c2f 100644 --- a/src/main/evaluation/Resources/config/services/controller.yml +++ b/src/main/evaluation/Resources/config/services/controller.yml @@ -4,14 +4,15 @@ services: Claroline\EvaluationBundle\Controller\WorkspaceEvaluationController: arguments: - - '@security.token_storage' - '@security.authorization_checker' + - '@security.token_storage' - '@Claroline\AppBundle\Persistence\ObjectManager' - '@Claroline\AppBundle\API\Crud' - '@Claroline\AppBundle\API\FinderProvider' - '@Claroline\AppBundle\API\SerializerProvider' - '@Claroline\EvaluationBundle\Manager\WorkspaceEvaluationManager' - '@Claroline\EvaluationBundle\Manager\PdfManager' + - '@Claroline\CoreBundle\Manager\Tool\ToolManager' Claroline\EvaluationBundle\Controller\ResourceUserEvaluationController: arguments: diff --git a/src/main/evaluation/Tests/Library/Checker/ProgressionCheckerTest.php b/src/main/evaluation/Tests/Library/Checker/ProgressionCheckerTest.php new file mode 100644 index 00000000000..74e6c7af8bf --- /dev/null +++ b/src/main/evaluation/Tests/Library/Checker/ProgressionCheckerTest.php @@ -0,0 +1,55 @@ +expectException(\InvalidArgumentException::class); + new ProgressionChecker(-1); + } + + public function testThresholdOverHundredThrowsException(): void + { + $this->expectException(\InvalidArgumentException::class); + new ProgressionChecker(300); + } + + public function testSupportEvaluation(): void + { + $checker = new ProgressionChecker(100); + + $evaluation = new GenericEvaluation(100); + $this->assertTrue($checker->supports($evaluation)); + } + + public function testVoteNotAttempted(): void + { + $checker = new ProgressionChecker(70); + + $notAttemptedEvaluation = new GenericEvaluation(0); + $this->assertEquals(EvaluationStatus::NOT_ATTEMPTED, $checker->vote($notAttemptedEvaluation)); + } + + public function testVoteIncomplete(): void + { + $checker = new ProgressionChecker(70); + + $incompleteEvaluation = new GenericEvaluation(69); + $this->assertEquals(EvaluationStatus::INCOMPLETE, $checker->vote($incompleteEvaluation)); + } + + public function testVotePassed(): void + { + $checker = new ProgressionChecker(); + + $endedEvaluation = new GenericEvaluation(100); + $this->assertEquals(EvaluationStatus::COMPLETED, $checker->vote($endedEvaluation)); + } +} diff --git a/src/main/evaluation/Tests/Library/Checker/ScoreCheckerTest.php b/src/main/evaluation/Tests/Library/Checker/ScoreCheckerTest.php index 5f361f863d6..b7dd154db0c 100644 --- a/src/main/evaluation/Tests/Library/Checker/ScoreCheckerTest.php +++ b/src/main/evaluation/Tests/Library/Checker/ScoreCheckerTest.php @@ -2,26 +2,26 @@ namespace Claroline\EvaluationBundle\Tests\Library; -use Claroline\EvaluationBundle\Entity\AbstractEvaluation; use Claroline\EvaluationBundle\Library\Checker\ScoreChecker; +use Claroline\EvaluationBundle\Library\EvaluationStatus; use Claroline\EvaluationBundle\Library\GenericEvaluation; use PHPUnit\Framework\TestCase; final class ScoreCheckerTest extends TestCase { - public function testSuccessScoreUnderZeroThrowsException() + public function testSuccessScoreUnderZeroThrowsException(): void { $this->expectException(\InvalidArgumentException::class); new ScoreChecker(-1); } - public function testSuccessScoreOverHundredThrowsException() + public function testSuccessScoreOverHundredThrowsException(): void { $this->expectException(\InvalidArgumentException::class); new ScoreChecker(300); } - public function testSupportEvaluationWithScore() + public function testSupportEvaluationWithScore(): void { $checker = new ScoreChecker(100); @@ -29,7 +29,7 @@ public function testSupportEvaluationWithScore() $this->assertTrue($checker->supports($evaluationWithScore)); } - public function testDontSupportEvaluationWithoutScore() + public function testDontSupportEvaluationWithoutScore(): void { $checker = new ScoreChecker(100); @@ -37,14 +37,14 @@ public function testDontSupportEvaluationWithoutScore() $this->assertFalse($checker->supports($evaluationWithoutScore)); } - public function testDontVoteIfNoSuccessScore() + public function testDontVoteIfNoSuccessScore(): void { $checker = new ScoreChecker(0); $this->assertNull($checker->vote(new GenericEvaluation(100, 10))); } - public function testDontVoteForNonTerminatedEvaluation() + public function testDontVoteForNonTerminatedEvaluation(): void { $checker = new ScoreChecker(100); @@ -52,7 +52,7 @@ public function testDontVoteForNonTerminatedEvaluation() $this->assertNull($checker->vote($nonTerminatedEvaluation)); } - public function testVoteForTerminatedEvaluationWithScore() + public function testVoteForTerminatedEvaluationWithScore(): void { $checker = new ScoreChecker(100); @@ -60,19 +60,19 @@ public function testVoteForTerminatedEvaluationWithScore() $this->assertNotNull($checker->vote($terminatedEvaluation)); } - public function testVotePassed() + public function testVotePassed(): void { $checker = new ScoreChecker(70); $passedEvaluation = new GenericEvaluation(100, 100, 70); - $this->assertEquals(AbstractEvaluation::STATUS_PASSED, $checker->vote($passedEvaluation)); + $this->assertEquals(EvaluationStatus::PASSED, $checker->vote($passedEvaluation)); } - public function testVoteFailed() + public function testVoteFailed(): void { $checker = new ScoreChecker(70); $failedEvaluation = new GenericEvaluation(100, 100, 60); - $this->assertEquals(AbstractEvaluation::STATUS_PASSED, $checker->vote($failedEvaluation)); + $this->assertEquals(EvaluationStatus::FAILED, $checker->vote($failedEvaluation)); } } diff --git a/src/main/evaluation/Tests/Library/GenericEvaluationTest.php b/src/main/evaluation/Tests/Library/GenericEvaluationTest.php index de09a429e81..6fb759cb469 100644 --- a/src/main/evaluation/Tests/Library/GenericEvaluationTest.php +++ b/src/main/evaluation/Tests/Library/GenericEvaluationTest.php @@ -7,43 +7,43 @@ final class GenericEvaluationTest extends TestCase { - public function testProgressionUnderZeroThrowsException() + public function testProgressionUnderZeroThrowsException(): void { $this->expectException(\InvalidArgumentException::class); new GenericEvaluation(-1); } - public function testProgressionOverHundredThrowsException() + public function testProgressionOverHundredThrowsException(): void { $this->expectException(\InvalidArgumentException::class); new GenericEvaluation(300); } - public function testGetProgression() + public function testGetProgression(): void { $evaluation = new GenericEvaluation(1); $this->assertEquals(1, $evaluation->getProgression()); } - public function testGetScoreMax() + public function testGetScoreMax(): void { $evaluation = new GenericEvaluation(100, 5); $this->assertEquals(5, $evaluation->getScoreMax()); } - public function testGetScore() + public function testGetScore(): void { $evaluation = new GenericEvaluation(100, 5, 2); $this->assertEquals(2, $evaluation->getScore()); } - public function testIsTerminatedIfProgressionIsHundred() + public function testIsTerminatedIfProgressionIsHundred(): void { $evaluation = new GenericEvaluation(100, 5, 2); $this->assertTrue($evaluation->isTerminated()); } - public function testIsNotTerminatedIfProgressionIsNotHundred() + public function testIsNotTerminatedIfProgressionIsNotHundred(): void { $evaluation = new GenericEvaluation(50, 5, 2); $this->assertFalse($evaluation->isTerminated()); diff --git a/src/main/installation/Additional/AdditionalInstaller.php b/src/main/installation/Additional/AdditionalInstaller.php index 67d16b6649e..9a17ff0248d 100644 --- a/src/main/installation/Additional/AdditionalInstaller.php +++ b/src/main/installation/Additional/AdditionalInstaller.php @@ -11,46 +11,36 @@ namespace Claroline\InstallationBundle\Additional; -use Claroline\AppBundle\Log\LoggableTrait; use Claroline\AppBundle\Persistence\ObjectManager; use Claroline\CoreBundle\Entity\Update\UpdaterExecution; use Claroline\InstallationBundle\Repository\UpdaterExecutionRepository; use Claroline\InstallationBundle\Updater\NonReplayableUpdaterInterface; use Psr\Container\ContainerInterface; use Psr\Log\LoggerAwareInterface; +use Psr\Log\LoggerAwareTrait; use Symfony\Component\DependencyInjection\ContainerAwareInterface; use Symfony\Component\DependencyInjection\ContainerAwareTrait; -abstract class AdditionalInstaller implements LoggerAwareInterface, ContainerAwareInterface, AdditionalInstallerInterface +abstract class AdditionalInstaller implements AdditionalInstallerInterface, ContainerAwareInterface, LoggerAwareInterface { - use LoggableTrait; use ContainerAwareTrait; + use LoggerAwareTrait; /** - * @var string + * Whether updaters should be executed even if they have been already. */ - protected $environment; + private bool $shouldReplayUpdaters = false; /** - * @var bool whether updaters should be executed even if they have been already + * A scoped container allowing to load Updater services. */ - private $shouldReplayUpdaters = false; - - /** - * @var ContainerInterface|null a scoped container allowing to load Updater services - */ - private $updaterLocator; + private ?ContainerInterface $updaterLocator; public function __construct(ContainerInterface $updaterLocator = null) { $this->updaterLocator = $updaterLocator; } - public function setEnvironment($environment) - { - $this->environment = $environment; - } - public function setShouldReplayUpdaters(bool $shouldReplayUpdaters): void { $this->shouldReplayUpdaters = $shouldReplayUpdaters; @@ -63,7 +53,7 @@ public function shouldReplayUpdaters(): bool public function hasMigrations(): bool { - return true; // should be false by default + return false; } public function hasFixtures(): bool @@ -71,15 +61,15 @@ public function hasFixtures(): bool return false; } - public function preInstall() + public function preInstall(): void { } - public function postInstall() + public function postInstall(): void { } - public function preUpdate($currentVersion, $targetVersion) + public function preUpdate(string $currentVersion, string $targetVersion): void { /** @var UpdaterExecutionRepository $updaterExecutionRepository */ $updaterExecutionRepository = $this->container->get(ObjectManager::class)->getRepository(UpdaterExecution::class); @@ -91,17 +81,17 @@ public function preUpdate($currentVersion, $targetVersion) $hasBeenExecuted = $updaterExecutionRepository->hasBeenExecuted($updaterClass); if ($hasBeenExecuted && (!$this->shouldReplayUpdaters() || \is_subclass_of($updaterClass, NonReplayableUpdaterInterface::class))) { - $this->log(sprintf('Skipping "%s" because it has been already executed.', $updaterClass)); + $this->logger->info(sprintf('Skipping "%s" because it has been already executed.', $updaterClass)); continue; } - $this->log(sprintf('Executing "%s" preUpdate.', $updaterClass)); + $this->logger->info(sprintf('Executing "%s" preUpdate.', $updaterClass)); $updater = $this->updaterLocator->get($updaterClass); $updater->preUpdate(); } } - public function postUpdate($currentVersion, $targetVersion) + public function postUpdate(string $currentVersion, string $targetVersion): void { /** @var UpdaterExecutionRepository $updaterExecutionRepository */ $updaterExecutionRepository = $this->container->get(ObjectManager::class)->getRepository(UpdaterExecution::class); @@ -117,7 +107,7 @@ public function postUpdate($currentVersion, $targetVersion) return; } - $this->log(sprintf('Executing "%s" postUpdate.', $updaterClass)); + $this->logger->info(sprintf('Executing "%s" postUpdate.', $updaterClass)); $updater = $this->updaterLocator->get($updaterClass); $updater->postUpdate(); @@ -127,15 +117,15 @@ public function postUpdate($currentVersion, $targetVersion) } } - public function preUninstall() + public function preUninstall(): void { } - public function postUninstall() + public function postUninstall(): void { } - public function end($currentVersion, $targetVersion) + public function end(string $currentVersion, string $targetVersion): void { } diff --git a/src/main/installation/Additional/AdditionalInstallerInterface.php b/src/main/installation/Additional/AdditionalInstallerInterface.php index 702feea4972..3170425c59a 100644 --- a/src/main/installation/Additional/AdditionalInstallerInterface.php +++ b/src/main/installation/Additional/AdditionalInstallerInterface.php @@ -11,29 +11,25 @@ namespace Claroline\InstallationBundle\Additional; -use Psr\Log\LoggerAwareInterface; - -interface AdditionalInstallerInterface extends LoggerAwareInterface +interface AdditionalInstallerInterface { - public function setEnvironment($environment); - public function setShouldReplayUpdaters(bool $shouldReplayUpdaters): void; public function shouldReplayUpdaters(): bool; - public function preInstall(); + public function preInstall(): void; - public function postInstall(); + public function postInstall(): void; - public function preUpdate($currentVersion, $targetVersion); + public function preUpdate(string $currentVersion, string $targetVersion): void; - public function postUpdate($currentVersion, $targetVersion); + public function postUpdate(string $currentVersion, string $targetVersion); - public function preUninstall(); + public function preUninstall(): void; - public function postUninstall(); + public function postUninstall(): void; - public function end($currentVersion, $targetVersion); + public function end(string $currentVersion, string $targetVersion); /** * @return string[] An array of Updater service identifiers (i.e. FQCN) indexed by version diff --git a/src/main/installation/Command/AbstractPluginCommand.php b/src/main/installation/Command/AbstractPluginCommand.php index b3e9cff05e8..116c2032f22 100644 --- a/src/main/installation/Command/AbstractPluginCommand.php +++ b/src/main/installation/Command/AbstractPluginCommand.php @@ -11,7 +11,7 @@ namespace Claroline\InstallationBundle\Command; -use Claroline\CoreBundle\Library\Installation\Plugin\Installer; +use Claroline\InstallationBundle\Manager\PluginManager; use Claroline\KernelBundle\Bundle\PluginBundle; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\ArrayInput; @@ -24,28 +24,28 @@ */ abstract class AbstractPluginCommand extends Command { - protected $pluginInstaller; + protected PluginManager $pluginInstaller; - public function __construct(Installer $pluginInstaller) + public function __construct(PluginManager $pluginInstaller) { $this->pluginInstaller = $pluginInstaller; parent::__construct(); } - protected function configure() + protected function configure(): void { $this->addArgument('bundle', InputArgument::REQUIRED, 'The bundle name'); } - protected function getPlugin(InputInterface $input) + protected function getPlugin(InputInterface $input): PluginBundle { $bundleName = $input->getArgument('bundle'); $kernel = $this->getApplication()->getKernel(); $bundle = $kernel->getBundle($bundleName); if (empty($bundle)) { - throw new \Exception("Cannot found bundle '{$bundleName}' in the bundles.ini"); + throw new \Exception("Cannot find bundle '{$bundleName}' in the bundles.ini"); } if (!$bundle instanceof PluginBundle) { @@ -58,7 +58,7 @@ protected function getPlugin(InputInterface $input) /** * Clears the cache (mandatory after plugin installation/uninstallation). */ - protected function resetCache(OutputInterface $output) + protected function resetCache(OutputInterface $output): void { $command = $this->getApplication()->get('cache:clear'); diff --git a/src/main/installation/Command/PlatformUpdateCommand.php b/src/main/installation/Command/PlatformUpdateCommand.php index 347bd1d31ad..e5e6ddcc3b3 100644 --- a/src/main/installation/Command/PlatformUpdateCommand.php +++ b/src/main/installation/Command/PlatformUpdateCommand.php @@ -12,9 +12,9 @@ namespace Claroline\InstallationBundle\Command; use Claroline\CoreBundle\Library\Configuration\PlatformConfigurationHandler; -use Claroline\CoreBundle\Library\Installation\PlatformInstaller; use Claroline\CoreBundle\Library\Maintenance\MaintenanceHandler; use Claroline\CoreBundle\Manager\VersionManager; +use Claroline\InstallationBundle\Manager\PlatformManager; use Claroline\InstallationBundle\Manager\RefreshManager; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\InputArgument; @@ -35,7 +35,7 @@ class PlatformUpdateCommand extends Command public function __construct( RefreshManager $refresher, - PlatformInstaller $installer, + PlatformManager $installer, VersionManager $versionManager, PlatformConfigurationHandler $config, string $environment diff --git a/src/main/installation/Command/PluginInstallCommand.php b/src/main/installation/Command/PluginInstallCommand.php index 71da0450c79..030911eb09d 100644 --- a/src/main/installation/Command/PluginInstallCommand.php +++ b/src/main/installation/Command/PluginInstallCommand.php @@ -19,7 +19,7 @@ */ class PluginInstallCommand extends AbstractPluginCommand { - protected function configure() + protected function configure(): void { parent::configure(); diff --git a/src/main/installation/Command/PluginUninstallCommand.php b/src/main/installation/Command/PluginUninstallCommand.php index 5547a85a772..7bf878ea4ef 100644 --- a/src/main/installation/Command/PluginUninstallCommand.php +++ b/src/main/installation/Command/PluginUninstallCommand.php @@ -19,7 +19,7 @@ */ class PluginUninstallCommand extends AbstractPluginCommand { - protected function configure() + protected function configure(): void { parent::configure(); diff --git a/src/main/installation/Fixtures/FixtureLoader.php b/src/main/installation/Fixtures/FixtureLoader.php index acb1c9955ca..3376a5da5cc 100644 --- a/src/main/installation/Fixtures/FixtureLoader.php +++ b/src/main/installation/Fixtures/FixtureLoader.php @@ -11,10 +11,10 @@ namespace Claroline\InstallationBundle\Fixtures; -use Claroline\AppBundle\Log\LoggableTrait; use Doctrine\Common\DataFixtures\Executor\ORMExecutor; use Psr\Container\ContainerInterface; use Psr\Log\LoggerAwareInterface; +use Psr\Log\LoggerAwareTrait; use Symfony\Component\HttpKernel\Bundle\BundleInterface; /** @@ -22,7 +22,7 @@ */ class FixtureLoader implements LoggerAwareInterface { - use LoggableTrait; + use LoggerAwareTrait; private $container; private $executor; @@ -50,7 +50,7 @@ public function load(BundleInterface $bundle, string $event): bool $toLoad = []; foreach ($fixtures as $fixture) { if ($fixture instanceof $event) { - $this->log(sprintf('Found %s fixture to load', get_class($fixture))); + $this->logger->info(sprintf('Found %s fixture to load', get_class($fixture))); if (method_exists($fixture, 'setLogger')) { $fixture->setLogger($this->logger); diff --git a/src/main/installation/Manager/InstallationManager.php b/src/main/installation/Manager/BundleManager.php similarity index 75% rename from src/main/installation/Manager/InstallationManager.php rename to src/main/installation/Manager/BundleManager.php index 35400097ac9..d04ea1e3a78 100644 --- a/src/main/installation/Manager/InstallationManager.php +++ b/src/main/installation/Manager/BundleManager.php @@ -11,7 +11,6 @@ namespace Claroline\InstallationBundle\Manager; -use Claroline\AppBundle\Log\LoggableTrait; use Claroline\CoreBundle\Library\Installation\Plugin\Recorder; use Claroline\InstallationBundle\Additional\AdditionalInstallerInterface; use Claroline\InstallationBundle\Bundle\InstallableInterface; @@ -24,12 +23,16 @@ use Claroline\MigrationBundle\Manager\Manager; use Claroline\MigrationBundle\Migrator\Migrator; use Psr\Log\LoggerAwareInterface; +use Psr\Log\LoggerAwareTrait; use Symfony\Component\DependencyInjection\ContainerAwareInterface; use Symfony\Component\DependencyInjection\ContainerInterface; -class InstallationManager implements LoggerAwareInterface +/** + * Manages installation for Installable bundles. + */ +class BundleManager implements LoggerAwareInterface { - use LoggableTrait; + use LoggerAwareTrait; /** * Whether additional installers should re-execute updaters that have been previously executed. @@ -40,20 +43,19 @@ public function __construct( private readonly ContainerInterface $container, private readonly Manager $migrationManager, private readonly FixtureLoader $fixtureLoader, - private readonly Recorder $recorder, - private readonly string $environment + private readonly Recorder $recorder ) { } public function install(InstallableInterface $bundle): void { - $this->log(sprintf('Installing %s %s... ', $bundle->getName(), $bundle->getVersion())); + $this->logger->info(sprintf('Installing %s %s...>', $bundle->getName(), $bundle->getVersion())); $additionalInstaller = $this->getAdditionalInstaller($bundle); if (!$additionalInstaller) { // Load configuration if ($bundle instanceof PluginBundleInterface) { - $this->log('Saving configuration...'); + $this->logger->info('Saving configuration...'); $this->recorder->register($bundle); } @@ -61,43 +63,43 @@ public function install(InstallableInterface $bundle): void return; } - $this->log('Launching pre-installation actions...'); + $this->logger->info('Launching pre-installation actions...'); $additionalInstaller->preInstall(); if ($additionalInstaller->hasMigrations()) { - $this->log('Executing migrations...'); + $this->logger->info('Executing migrations...'); $this->migrationManager->upgradeBundle($bundle, Migrator::VERSION_LATEST); } if ($additionalInstaller->hasFixtures()) { - $this->log('Loading pre-install fixtures...'); + $this->logger->info('Loading pre-install fixtures...'); $this->fixtureLoader->load($bundle, PreInstallInterface::class); } // Load configuration if ($bundle instanceof PluginBundleInterface) { - $this->log('Saving configuration...'); + $this->logger->info('Saving configuration...'); $this->recorder->register($bundle); } - $this->log('Launching post-installation actions...'); + $this->logger->info('Launching post-installation actions...'); $additionalInstaller->postInstall(); if ($additionalInstaller->hasFixtures()) { - $this->log('Loading post-install fixtures...'); + $this->logger->info('Loading post-install fixtures...'); $this->fixtureLoader->load($bundle, PostInstallInterface::class); } } public function update(InstallableInterface $bundle, $currentVersion, $targetVersion): void { - $this->log(sprintf('Updating %s from %s to %s...', $bundle->getName(), $currentVersion, $targetVersion)); + $this->logger->info(sprintf('Updating %s from %s to %s...', $bundle->getName(), $currentVersion, $targetVersion)); $additionalInstaller = $this->getAdditionalInstaller($bundle); if (!$additionalInstaller) { // Update configuration if ($bundle instanceof PluginBundleInterface) { - $this->log('Updating configuration...'); + $this->logger->info('Updating configuration...'); $this->recorder->update($bundle); } @@ -105,31 +107,31 @@ public function update(InstallableInterface $bundle, $currentVersion, $targetVer return; } - $this->log('Launching pre-update actions...'); + $this->logger->info('Launching pre-update actions...'); $additionalInstaller->setShouldReplayUpdaters($this->shouldReplayUpdaters); $additionalInstaller->preUpdate($currentVersion, $targetVersion); if ($additionalInstaller->hasMigrations()) { - $this->log('Executing migrations...'); + $this->logger->info('Executing migrations...'); $this->migrationManager->upgradeBundle($bundle, Migrator::VERSION_LATEST); } if ($additionalInstaller->hasFixtures()) { - $this->log('Loading pre-update fixtures...'); + $this->logger->info('Loading pre-update fixtures...'); $this->fixtureLoader->load($bundle, PreUpdateInterface::class); } // Update configuration if ($bundle instanceof PluginBundleInterface) { - $this->log('Updating configuration...'); + $this->logger->info('Updating configuration...'); $this->recorder->update($bundle); } - $this->log('Launching post-update actions...'); + $this->logger->info('Launching post-update actions...'); $additionalInstaller->postUpdate($currentVersion, $targetVersion); if ($additionalInstaller->hasFixtures()) { - $this->log('Loading post-update fixtures...'); + $this->logger->info('Loading post-update fixtures...'); $this->fixtureLoader->load($bundle, PostUpdateInterface::class); } } @@ -148,7 +150,7 @@ public function end(InstallableInterface $bundle, $currentVersion = null, $targe public function uninstall(InstallableInterface $bundle): void { - $this->log(sprintf('Uninstalling %s...', $bundle->getName())); + $this->logger->info(sprintf('Uninstalling %s...', $bundle->getName())); $additionalInstaller = $this->getAdditionalInstaller($bundle); if (!$additionalInstaller) { @@ -156,15 +158,15 @@ public function uninstall(InstallableInterface $bundle): void return; } - $this->log('Launching pre-uninstallation actions...'); + $this->logger->info('Launching pre-uninstallation actions...'); $additionalInstaller->preUninstall(); if ($additionalInstaller->hasMigrations()) { - $this->log('Executing migrations...'); + $this->logger->info('Executing migrations...'); $this->migrationManager->downgradeBundle($bundle, Migrator::VERSION_LATEST); } - $this->log('Launching post-uninstallation actions...'); + $this->logger->info('Launching post-uninstallation actions...'); $additionalInstaller->postUninstall(); } @@ -178,8 +180,9 @@ private function getAdditionalInstaller(InstallableInterface $bundle): ?Addition $installer = $bundle->getAdditionalInstaller(); if ($installer instanceof AdditionalInstallerInterface) { - $installer->setEnvironment($this->environment); - $installer->setLogger($this->logger); + if ($installer instanceof LoggerAwareInterface) { + $installer->setLogger($this->logger); + } if ($installer instanceof ContainerAwareInterface) { $installer->setContainer($this->container); diff --git a/src/main/core/Library/Installation/PlatformInstaller.php b/src/main/installation/Manager/PlatformManager.php similarity index 70% rename from src/main/core/Library/Installation/PlatformInstaller.php rename to src/main/installation/Manager/PlatformManager.php index 076534e54e9..7d051cf10c6 100644 --- a/src/main/core/Library/Installation/PlatformInstaller.php +++ b/src/main/installation/Manager/PlatformManager.php @@ -9,18 +9,15 @@ * file that was distributed with this source code. */ -namespace Claroline\CoreBundle\Library\Installation; +namespace Claroline\InstallationBundle\Manager; -use Claroline\AppBundle\Log\LoggableTrait; use Claroline\AppBundle\Persistence\ObjectManager; use Claroline\CoreBundle\Entity\Plugin; -use Claroline\CoreBundle\Library\Installation\Plugin\Installer; -use Claroline\CoreBundle\Manager\PluginManager; use Claroline\InstallationBundle\Bundle\InstallableInterface; -use Claroline\InstallationBundle\Manager\InstallationManager; use Doctrine\Bundle\DoctrineBundle\Command\CreateDatabaseDoctrineCommand; use Doctrine\DBAL\Exception\TableNotFoundException; use Psr\Log\LoggerAwareInterface; +use Psr\Log\LoggerAwareTrait; use Symfony\Component\Console\Input\ArrayInput; use Symfony\Component\Console\Output\NullOutput; use Symfony\Component\Console\Output\OutputInterface; @@ -31,32 +28,19 @@ * Entry point of platform installation/update, ensuring that minimal requirements * (e.g. existing database) are met before executing operations. */ -class PlatformInstaller implements LoggerAwareInterface +class PlatformManager implements LoggerAwareInterface { - use LoggableTrait; + use LoggerAwareTrait; - private $kernel; - private $pluginManager; - private $pluginInstaller; - private $om; - private $baseInstaller; - private $container; - private $output; + private OutputInterface $output; public function __construct( - KernelInterface $kernel, - PluginManager $pluginManager, - Installer $pluginInstaller, - ObjectManager $om, - InstallationManager $baseInstaller, - ContainerInterface $container + private readonly ContainerInterface $container, + private readonly KernelInterface $kernel, + private readonly ObjectManager $om, + private readonly BundleManager $baseInstaller, + private readonly PluginManager $pluginInstaller ) { - $this->kernel = $kernel; - $this->pluginManager = $pluginManager; - $this->pluginInstaller = $pluginInstaller; - $this->om = $om; - $this->baseInstaller = $baseInstaller; - $this->container = $container; } public function setShouldReplayUpdaters(bool $shouldReplayUpdaters): void @@ -64,7 +48,7 @@ public function setShouldReplayUpdaters(bool $shouldReplayUpdaters): void $this->baseInstaller->setShouldReplayUpdaters($shouldReplayUpdaters); } - public function setOutput(OutputInterface $output) + public function setOutput(OutputInterface $output): void { $this->output = $output; } @@ -72,7 +56,7 @@ public function setOutput(OutputInterface $output) /** * Installs platform packages based on the bundles configuration (INI file). */ - public function installAll() + public function installAll(): void { $this->launchPreInstallActions(); @@ -82,7 +66,7 @@ public function installAll() $this->end($bundles); } - public function updateAll($from, $to) + public function updateAll($from, $to): void { $bundles = $this->getInstallableBundles(); @@ -90,7 +74,7 @@ public function updateAll($from, $to) $this->end($bundles, $from, $to); } - public function execute(array $bundles, ?string $fromVersion = null, ?string $toVersion = null) + public function execute(array $bundles, ?string $fromVersion = null, ?string $toVersion = null): void { $isFreshInstall = !$fromVersion && !$toVersion; @@ -105,9 +89,9 @@ public function execute(array $bundles, ?string $fromVersion = null, ?string $to } } - private function end(array $bundles, ?string $fromVersion = null, ?string $toVersion = null) + private function end(array $bundles, ?string $fromVersion = null, ?string $toVersion = null): void { - $this->log('Ending operations...'); + $this->logger->info('Ending operations...'); $isFreshInstall = !$fromVersion && !$toVersion; @@ -122,42 +106,43 @@ private function end(array $bundles, ?string $fromVersion = null, ?string $toVer private function getInstallableBundles(): array { - // during the install/update process all the available bundles are loaded in the kernel + // during the installation/update process all the available bundles are loaded in the kernel // @see Claroline\KernelBundle\Kernel::registerBundles() return array_filter($this->kernel->getBundles(), function ($bundle) { return $bundle instanceof InstallableInterface; }); } - private function isBundleAlreadyInstalled($bundleFqcn, $checkCoreBundle = true) + private function isBundleAlreadyInstalled(string $bundleFqcn, bool $checkCoreBundle = true): bool { if ('Claroline\CoreBundle\ClarolineCoreBundle' === $bundleFqcn && !$checkCoreBundle) { return true; } try { - return $this->om->getRepository(Plugin::class)->findOneByBundleFQCN($bundleFqcn); + return !empty($this->om->getRepository(Plugin::class)->findOneByBundleFQCN($bundleFqcn)); } catch (TableNotFoundException $e) { // we're probably installing the platform because the database isn't here yet do... return false return false; } } - private function launchPreInstallActions() + private function launchPreInstallActions(): void { $this->createDatabaseIfNotExists(); } - private function createDatabaseIfNotExists() + private function createDatabaseIfNotExists(): void { try { - $this->log('Checking database connection...'); - $cn = $this->container->get('doctrine.dbal.default_connection'); + $this->logger->info('Checking database connection...'); + $cn = $this->container->get('doctrine.dbal.default_connection'); // see http://stackoverflow.com/questions/3668506/efficient-sql-test-query-or-validation-query-that-will-work-across-all-or-most $cn->query('SELECT 1'); } catch (\Exception $ex) { - $this->log('Unable to connect to database: trying to create database...'); + $this->logger->notice('Unable to connect to database: trying to create database...'); + $command = new CreateDatabaseDoctrineCommand($this->container->get('doctrine')); $code = $command->run(new ArrayInput([]), $this->output ?: new NullOutput()); diff --git a/src/main/installation/Manager/PluginManager.php b/src/main/installation/Manager/PluginManager.php new file mode 100644 index 00000000000..7f7d726036e --- /dev/null +++ b/src/main/installation/Manager/PluginManager.php @@ -0,0 +1,106 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Claroline\InstallationBundle\Manager; + +use Claroline\AppBundle\Persistence\ObjectManager; +use Claroline\CoreBundle\Library\Installation\Plugin\Recorder; +use Claroline\CoreBundle\Library\Installation\Plugin\Validator; +use Claroline\CoreBundle\Manager\PluginManager as BasePluginManager; +use Claroline\CoreBundle\Manager\VersionManager; +use Claroline\KernelBundle\Bundle\PluginBundleInterface; +use Psr\Log\LoggerAwareInterface; +use Psr\Log\LoggerAwareTrait; + +/** + * This class is used to perform the (un-)installation of a plugin. + */ +class PluginManager implements LoggerAwareInterface +{ + use LoggerAwareTrait; + + public function __construct( + private readonly Validator $validator, + private readonly Recorder $recorder, + private readonly BundleManager $baseInstaller, + private readonly ObjectManager $om, + private readonly BasePluginManager $pluginManager, + private readonly VersionManager $versionManager + ) { + } + + public function install(PluginBundleInterface $plugin): void + { + $this->baseInstaller->install($plugin); + + $pluginEntity = $this->pluginManager->getPluginByShortName( + $plugin->getName() + ); + + if (!$this->pluginManager->isReady($pluginEntity)) { + $errors = $this->pluginManager->getMissingRequirements($pluginEntity); + + foreach ($errors['extensions'] as $extension) { + $this->logger->error(sprintf('Extension %s missing for %s !', $extension, $plugin->getName())); + } + + foreach ($errors['plugins'] as $bundle) { + $this->logger->error(sprintf('The plugin %s is required for %s ! You must enable it first to use %s.', $bundle, $plugin->getName(), $plugin->getName())); + } + + foreach ($errors['extras'] as $extra) { + $this->logger->error(sprintf('The plugin %s has extra requirements ! %s.', $plugin->getName(), $extra)); + } + + $this->logger->critical(sprintf('Disabling %s...', $plugin->getName())); + $this->pluginManager->disable($pluginEntity); + } + + $version = $this->versionManager->register($plugin); + $this->versionManager->execute($version); + } + + public function uninstall(PluginBundleInterface $plugin): void + { + $this->checkInstallationStatus($plugin, true); + + $this->logger->info('Removing plugin configuration...'); + $this->recorder->unregister($plugin); + $this->baseInstaller->uninstall($plugin); + } + + public function update(PluginBundleInterface $plugin, string $currentVersion, string $targetVersion): void + { + $this->checkInstallationStatus($plugin, true); + + $this->baseInstaller->update($plugin, $currentVersion, $targetVersion); + + // updates plugin version + $version = $this->versionManager->register($plugin); + $this->versionManager->execute($version); + } + + public function end(PluginBundleInterface $plugin, string $currentVersion = null, string $targetVersion = null): void + { + $this->baseInstaller->end($plugin, $currentVersion, $targetVersion); + } + + private function checkInstallationStatus(PluginBundleInterface $plugin, $shouldBeInstalled = true): void + { + $this->logger->info(sprintf('Checking installation status for plugin %s', $plugin->getName())); + + if ($this->recorder->isRegistered($plugin) !== $shouldBeInstalled) { + $stateDiscr = $shouldBeInstalled ? 'not' : 'already'; + + throw new \LogicException("Plugin '{$plugin->getName()}' is {$stateDiscr} installed."); + } + } +} diff --git a/src/main/installation/Manager/RefreshManager.php b/src/main/installation/Manager/RefreshManager.php index 89aac2205e0..34d9b11b5db 100644 --- a/src/main/installation/Manager/RefreshManager.php +++ b/src/main/installation/Manager/RefreshManager.php @@ -11,61 +11,36 @@ namespace Claroline\InstallationBundle\Manager; -use Claroline\AppBundle\Manager\CommandManager; use Psr\Log\LogLevel; +use Symfony\Bundle\FrameworkBundle\Console\Application; use Symfony\Component\Console\Input\ArrayInput; use Symfony\Component\Console\Output\NullOutput; use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\Filesystem\Filesystem; +use Symfony\Component\HttpKernel\KernelInterface; class RefreshManager { - /** @var Filesystem */ - private $filesystem; - /** @var CommandManager */ - private $commandManager; - - /** @var string */ - private $projectDir; - /** @var string */ - private $cacheDir; - /** @var string */ - private $publicDir; - /** @var string */ - private $publicDataDir; - /** @var string */ - private $filesDataDir; - - /** @var OutputInterface */ - private $output; + private OutputInterface $output; public function __construct( - Filesystem $filesystem, - CommandManager $commandManager, - string $projectDir, - string $cacheDir, - string $publicDir, - string $publicDataDir, - string $filesDataDir + private readonly KernelInterface $kernel, + private readonly Filesystem $filesystem, + private readonly string $projectDir, + private readonly string $cacheDir, + private readonly string $publicDir, + private readonly string $publicDataDir, + private readonly string $filesDataDir ) { - $this->filesystem = $filesystem; - $this->commandManager = $commandManager; - - $this->projectDir = $projectDir; - $this->cacheDir = $cacheDir; - $this->publicDir = $publicDir; - $this->publicDataDir = $publicDataDir; - $this->filesDataDir = $filesDataDir; - $this->output = new NullOutput(); } - public function setOutput(OutputInterface $output) + public function setOutput(OutputInterface $output): void { $this->output = $output; } - public function refresh($environment) + public function refresh(string $environment): void { $this->buildSymlinks(); $this->installAssets(); @@ -73,18 +48,18 @@ public function refresh($environment) $this->clearCache($environment); } - public function installAssets() + public function installAssets(): void { - $this->commandManager->run(new ArrayInput([ + $this->runCommand(new ArrayInput([ 'command' => 'assets:install', 'target' => $this->publicDir, '--symlink' => true, ]), $this->output); } - public function dumpAssets() + public function dumpAssets(): void { - $this->commandManager->run(new ArrayInput([ + $this->runCommand(new ArrayInput([ 'command' => 'bazinga:js-translation:dump', 'target' => $this->publicDir.DIRECTORY_SEPARATOR.'js', '--format' => ['js'], @@ -92,29 +67,27 @@ public function dumpAssets() ]), $this->output); } - public function buildThemes() + public function buildThemes(): void { - $this->commandManager->run(new ArrayInput([ + $this->runCommand(new ArrayInput([ 'command' => 'claroline:theme:build', ]), $this->output); } - public function buildSymlinks() + public function buildSymlinks(): void { $this->linkPublicFiles(); $this->linkPackageFiles(); } - public function clearCache(string $environment) + public function clearCache(string $environment): void { - if ($this->output) { - $this->output->writeln('Clearing the cache...'); - } + $this->output->writeln('Clearing the cache...'); $this->removeContentFrom($this->cacheDir.DIRECTORY_SEPARATOR.$environment); } - private function removeContentFrom($directory) + private function removeContentFrom($directory): void { if (is_dir($directory)) { $cacheIterator = new \DirectoryIterator($directory); @@ -127,7 +100,7 @@ private function removeContentFrom($directory) } } - private function linkPublicFiles() + private function linkPublicFiles(): void { if (!$this->filesystem->exists($this->publicDataDir)) { $this->output->writeln('Creating symlink to public directory of files directory in public directory...'); @@ -142,7 +115,7 @@ private function linkPublicFiles() } } - private function linkPackageFiles() + private function linkPackageFiles(): void { $packageDir = $this->publicDir.DIRECTORY_SEPARATOR.'packages'; @@ -150,7 +123,14 @@ private function linkPackageFiles() $this->output->writeln('Creating symlink to '.$packageDir); $this->filesystem->symlink($this->projectDir.DIRECTORY_SEPARATOR.'node_modules', $packageDir); } elseif (!is_link($packageDir)) { - $this->output->writeln('Couldn\'t create symlink from node_modules to public/packages. You must remove public/packages or create the link manually'); + $this->output->writeln('Cannot create symlink from node_modules to public/packages. You must remove public/packages or create the link manually'); } } + + private function runCommand(ArrayInput $input, $output): void + { + $application = new Application($this->kernel); + $application->setAutoExit(false); + $application->run($input, $output); + } } diff --git a/src/main/installation/Resources/config/services/command.yml b/src/main/installation/Resources/config/services/command.yml index a85a1a7c04e..ac50b4da8a0 100644 --- a/src/main/installation/Resources/config/services/command.yml +++ b/src/main/installation/Resources/config/services/command.yml @@ -18,7 +18,7 @@ services: Claroline\InstallationBundle\Command\PlatformUpdateCommand: arguments: - '@Claroline\InstallationBundle\Manager\RefreshManager' - - '@Claroline\CoreBundle\Library\Installation\PlatformInstaller' + - '@Claroline\InstallationBundle\Manager\PlatformManager' - '@Claroline\CoreBundle\Manager\VersionManager' - '@Claroline\CoreBundle\Library\Configuration\PlatformConfigurationHandler' - '%kernel.environment%' @@ -35,12 +35,12 @@ services: Claroline\InstallationBundle\Command\PluginInstallCommand: arguments: - - '@Claroline\CoreBundle\Library\Installation\Plugin\Installer' + - '@Claroline\InstallationBundle\Manager\PluginManager' tags: - { name: 'console.command', command: 'claroline:plugin:install' } Claroline\InstallationBundle\Command\PluginUninstallCommand: arguments: - - '@Claroline\CoreBundle\Library\Installation\Plugin\Installer' + - '@Claroline\InstallationBundle\Manager\PluginManager' tags: - { name: 'console.command', command: 'claroline:plugin:uninstall' } diff --git a/src/main/installation/Resources/config/services/manager.yml b/src/main/installation/Resources/config/services/manager.yml index e6cc46a8bf5..183faf56dea 100644 --- a/src/main/installation/Resources/config/services/manager.yml +++ b/src/main/installation/Resources/config/services/manager.yml @@ -1,18 +1,38 @@ services: - Claroline\InstallationBundle\Manager\InstallationManager: + Claroline\InstallationBundle\Manager\BundleManager: arguments: - '@service_container' - '@claroline.migration.manager' - '@claroline.installation.fixture_loader' - '@Claroline\CoreBundle\Library\Installation\Plugin\Recorder' - - '%kernel.environment%' + calls: + - setLogger: [ '@logger' ] + + Claroline\InstallationBundle\Manager\PluginManager: + arguments: + - '@claroline.plugin.validator' + - '@Claroline\CoreBundle\Library\Installation\Plugin\Recorder' + - '@Claroline\InstallationBundle\Manager\BundleManager' + - '@Claroline\AppBundle\Persistence\ObjectManager' + - '@Claroline\CoreBundle\Manager\PluginManager' + - '@Claroline\CoreBundle\Manager\VersionManager' + calls: + - setLogger: [ '@logger' ] + + Claroline\InstallationBundle\Manager\PlatformManager: + arguments: + - '@service_container' + - '@kernel' + - '@Claroline\AppBundle\Persistence\ObjectManager' + - '@Claroline\InstallationBundle\Manager\BundleManager' + - '@Claroline\InstallationBundle\Manager\PluginManager' calls: - setLogger: [ '@logger' ] Claroline\InstallationBundle\Manager\RefreshManager: arguments: + - '@kernel' - '@filesystem' - - '@Claroline\AppBundle\Manager\CommandManager' - '%kernel.project_dir%' - '%kernel.cache_dir%' - '%claroline.param.public_directory%' diff --git a/src/main/installation/Updater/Updater.php b/src/main/installation/Updater/Updater.php index 94610abf432..679ecdc8bf3 100644 --- a/src/main/installation/Updater/Updater.php +++ b/src/main/installation/Updater/Updater.php @@ -11,18 +11,18 @@ namespace Claroline\InstallationBundle\Updater; -use Claroline\AppBundle\Log\LoggableTrait; use Psr\Log\LoggerAwareInterface; +use Psr\Log\LoggerAwareTrait; abstract class Updater implements LoggerAwareInterface { - use LoggableTrait; + use LoggerAwareTrait; - public function preUpdate() + public function preUpdate(): void { } - public function postUpdate() + public function postUpdate(): void { } } diff --git a/src/main/kernel/Recorder/BundleFileLoader.php b/src/main/kernel/Recorder/BundleFileLoader.php index 26fefd9f780..522930dea0a 100644 --- a/src/main/kernel/Recorder/BundleFileLoader.php +++ b/src/main/kernel/Recorder/BundleFileLoader.php @@ -11,24 +11,20 @@ namespace Claroline\KernelBundle\Recorder; -use Claroline\AppBundle\Log\LoggableTrait; use Claroline\KernelBundle\Bundle\AutoConfigurableInterface; -use Psr\Log\LoggerAwareInterface; use Symfony\Component\HttpKernel\Bundle\BundleInterface; /** * Loads the list of Bundles registered in the Claroline Kernel from an INI file. */ -class BundleFileLoader implements LoggerAwareInterface +class BundleFileLoader { - use LoggableTrait; - - private $env; - private $bundlesFile; + private string $env; + private string $bundlesFile; private static $selfInstance; - public static function initialize(string $env, string $bundlesFile) + public static function initialize(string $env, string $bundlesFile): void { static::$selfInstance = new self($env, $bundlesFile); } @@ -62,8 +58,6 @@ public function getActiveBundles(?bool $fetchAll = false): array $bundles[\get_class($requiredBundle)] = $requiredBundle; } } - } else { - $this->log("Class {$bundleClass} was not loaded"); } } } @@ -71,7 +65,7 @@ public function getActiveBundles(?bool $fetchAll = false): array return $bundles; } - private function __construct(string $env, $bundlesFile) + private function __construct(string $env, string $bundlesFile) { if (!file_exists($bundlesFile)) { throw new \InvalidArgumentException("'{$bundlesFile}' does not exist"); diff --git a/src/main/log/Component/Tool/LogsTool.php b/src/main/log/Component/Tool/LogsTool.php new file mode 100644 index 00000000000..0903b8b5ce2 --- /dev/null +++ b/src/main/log/Component/Tool/LogsTool.php @@ -0,0 +1,34 @@ +load('services.yml'); + $loader->load('components.yml'); } } diff --git a/src/main/log/Installation/ClarolineLogInstaller.php b/src/main/log/Installation/ClarolineLogInstaller.php index 07a8fa5f4b8..dbe159f47d7 100644 --- a/src/main/log/Installation/ClarolineLogInstaller.php +++ b/src/main/log/Installation/ClarolineLogInstaller.php @@ -15,4 +15,8 @@ class ClarolineLogInstaller extends AdditionalInstaller { + public function hasMigrations(): bool + { + return true; + } } diff --git a/src/main/log/Resources/config/components.yml b/src/main/log/Resources/config/components.yml new file mode 100644 index 00000000000..cc128a70a3d --- /dev/null +++ b/src/main/log/Resources/config/components.yml @@ -0,0 +1,2 @@ +imports: + - { resource: components/tool.yml } diff --git a/src/main/log/Resources/config/components/tool.yml b/src/main/log/Resources/config/components/tool.yml new file mode 100644 index 00000000000..2b2e3e8a040 --- /dev/null +++ b/src/main/log/Resources/config/components/tool.yml @@ -0,0 +1,4 @@ +services: + Claroline\LogBundle\Component\Tool\LogsTool: + parent: Claroline\AppBundle\Component\Tool\AbstractTool + tags: [ 'claroline.component.tool' ] diff --git a/src/main/log/Resources/config/services/subscriber.yml b/src/main/log/Resources/config/services/subscriber.yml index 009db1ce157..0746df836da 100644 --- a/src/main/log/Resources/config/services/subscriber.yml +++ b/src/main/log/Resources/config/services/subscriber.yml @@ -6,10 +6,6 @@ services: tags: - { name: kernel.event_subscriber } - Claroline\LogBundle\Subscriber\Administration\LogsSubscriber: - tags: - - { name: kernel.event_subscriber } - # move those subscribers in their respective plugin when old log system will be removed Claroline\LogBundle\Subscriber\Functional\GroupLogSubscriber: arguments: diff --git a/src/main/log/Resources/modules/account/logs/index.js b/src/main/log/Resources/modules/account/logs/index.js index 2c4b6cf0273..b947659e9bf 100644 --- a/src/main/log/Resources/modules/account/logs/index.js +++ b/src/main/log/Resources/modules/account/logs/index.js @@ -1,10 +1,8 @@ -import {trans} from '#/main/app/intl/translation' - import {LogsMain} from '#/main/log/account/logs/containers/main' export default { - name: 'logs', + /*name: 'logs', icon: 'fa fa-fw fa-shoe-prints', label: trans('logs', {}, 'tools'), - component: LogsMain + */component: LogsMain } diff --git a/src/main/log/Subscriber/Administration/LogsSubscriber.php b/src/main/log/Subscriber/Administration/LogsSubscriber.php deleted file mode 100644 index 25037acd56c..00000000000 --- a/src/main/log/Subscriber/Administration/LogsSubscriber.php +++ /dev/null @@ -1,26 +0,0 @@ - 'onOpen', - ]; - } - - public function onOpen(OpenToolEvent $event) - { - $event->setData([]); - $event->stopPropagation(); - } -} diff --git a/src/main/log/Subscriber/FunctionalLogSubscriber.php b/src/main/log/Subscriber/FunctionalLogSubscriber.php index 9809d608feb..f0a1244ed3e 100644 --- a/src/main/log/Subscriber/FunctionalLogSubscriber.php +++ b/src/main/log/Subscriber/FunctionalLogSubscriber.php @@ -2,6 +2,7 @@ namespace Claroline\LogBundle\Subscriber; +use Claroline\CoreBundle\Event\CatalogEvents\ContextEvents; use Claroline\CoreBundle\Event\CatalogEvents\ResourceEvents; use Claroline\CoreBundle\Event\CatalogEvents\ToolEvents; use Claroline\EvaluationBundle\Event\EvaluationEvents; @@ -32,7 +33,8 @@ public static function getSubscribedEvents(): array return [ EvaluationEvents::RESOURCE_EVALUATION => ['logEvaluation', 10], ResourceEvents::RESOURCE_OPEN => ['logEvent', 10], - ToolEvents::OPEN => ['logEvent', 10], + // ContextEvents::OPEN => ['logEvent', 10], + // ToolEvents::OPEN => ['logEvent', 10], ]; } diff --git a/src/main/privacy/Component/Tool/PrivacyTool.php b/src/main/privacy/Component/Tool/PrivacyTool.php new file mode 100644 index 00000000000..ccd391af1f3 --- /dev/null +++ b/src/main/privacy/Component/Tool/PrivacyTool.php @@ -0,0 +1,49 @@ +serializer->serialize(); + + return [ + 'lockedParameters' => $parameters['lockedParameters'] ?? [], + 'parameters' => $parameters, + ]; + } + + return []; + } + + public function configure(string $context, ContextSubjectInterface $contextSubject = null, array $configData = []): ?array + { + return []; + } +} diff --git a/src/main/app/Controller/Platform/TermsOfServiceController.php b/src/main/privacy/Controller/TermsOfServiceController.php similarity index 73% rename from src/main/app/Controller/Platform/TermsOfServiceController.php rename to src/main/privacy/Controller/TermsOfServiceController.php index 943b6cf98b4..e72cd37f49f 100644 --- a/src/main/app/Controller/Platform/TermsOfServiceController.php +++ b/src/main/privacy/Controller/TermsOfServiceController.php @@ -1,6 +1,6 @@ om = $om; - $this->serializer = $serializer; - $this->manager = $manager; } /** * @Route("/", name="apiv2_platform_terms_of_service", methods={"GET"}) */ - public function getCurrentAction(Request $request) + public function getCurrentAction(Request $request): JsonResponse { $terms = null; if ($this->manager->isActive()) { diff --git a/src/main/privacy/DependencyInjection/ClarolinePrivacyExtension.php b/src/main/privacy/DependencyInjection/ClarolinePrivacyExtension.php index e1db2082fc4..7fd6b324de2 100644 --- a/src/main/privacy/DependencyInjection/ClarolinePrivacyExtension.php +++ b/src/main/privacy/DependencyInjection/ClarolinePrivacyExtension.php @@ -11,7 +11,6 @@ namespace Claroline\PrivacyBundle\DependencyInjection; -use Exception; use Symfony\Component\Config\FileLocator; use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\Loader\YamlFileLoader; @@ -19,15 +18,12 @@ class ClarolinePrivacyExtension extends Extension { - /** - * {@inheritdoc} - * - * @throws Exception - */ - public function load(array $configs, ContainerBuilder $container) + public function load(array $configs, ContainerBuilder $container): void { $locator = new FileLocator(__DIR__.'/../Resources/config'); $loader = new YamlFileLoader($container, $locator); + $loader->load('services.yml'); + $loader->load('components.yml'); } } diff --git a/src/main/privacy/Resources/config/components.yml b/src/main/privacy/Resources/config/components.yml new file mode 100644 index 00000000000..cc128a70a3d --- /dev/null +++ b/src/main/privacy/Resources/config/components.yml @@ -0,0 +1,2 @@ +imports: + - { resource: components/tool.yml } diff --git a/src/main/privacy/Resources/config/components/tool.yml b/src/main/privacy/Resources/config/components/tool.yml new file mode 100644 index 00000000000..6aeb75c8c4a --- /dev/null +++ b/src/main/privacy/Resources/config/components/tool.yml @@ -0,0 +1,4 @@ +services: + Claroline\PrivacyBundle\Component\Tool\PrivacyTool: + parent: Claroline\AppBundle\Component\Tool\AbstractTool + tags: [ 'claroline.component.tool' ] diff --git a/src/main/privacy/Resources/config/services.yml b/src/main/privacy/Resources/config/services.yml index be8e54d4076..82897926eb6 100644 --- a/src/main/privacy/Resources/config/services.yml +++ b/src/main/privacy/Resources/config/services.yml @@ -1,4 +1,3 @@ imports: - { resource: services/controller.yml } - - { resource: services/subscriber.yml } - { resource: services/serializer.yml } diff --git a/src/main/privacy/Resources/config/services/controller.yml b/src/main/privacy/Resources/config/services/controller.yml index aa3f636b215..be31cf6e73b 100644 --- a/src/main/privacy/Resources/config/services/controller.yml +++ b/src/main/privacy/Resources/config/services/controller.yml @@ -1,4 +1,7 @@ services: + _defaults: + public: true # required by controllers + Claroline\PrivacyBundle\Controller\PrivacyController: parent: Claroline\AppBundle\Controller\AbstractSecurityController public: true @@ -6,3 +9,9 @@ services: - '@security.authorization_checker' - '@Claroline\CoreBundle\Library\Configuration\PlatformConfigurationHandler' - '@Claroline\CoreBundle\API\Serializer\ParametersSerializer' + + Claroline\PrivacyBundle\Controller\TermsOfServiceController: + arguments: + - '@Claroline\AppBundle\Persistence\ObjectManager' + - '@Claroline\AppBundle\API\SerializerProvider' + - '@Claroline\AppBundle\Manager\TermsOfServiceManager' diff --git a/src/main/privacy/Resources/config/services/subscriber.yml b/src/main/privacy/Resources/config/services/subscriber.yml deleted file mode 100644 index 9c7bb2cc895..00000000000 --- a/src/main/privacy/Resources/config/services/subscriber.yml +++ /dev/null @@ -1,5 +0,0 @@ -services: - Claroline\PrivacyBundle\Subscriber\Administration\PrivacySubscriber: - tags: [ kernel.event_subscriber ] - arguments: - - '@Claroline\CoreBundle\API\Serializer\ParametersSerializer' diff --git a/src/main/privacy/Resources/modules/account/privacy/index.js b/src/main/privacy/Resources/modules/account/privacy/index.js index 2d68006e96a..638a8dfaaaa 100644 --- a/src/main/privacy/Resources/modules/account/privacy/index.js +++ b/src/main/privacy/Resources/modules/account/privacy/index.js @@ -1,11 +1,9 @@ -import {trans} from '#/main/app/intl/translation' - import {PrivacyMain} from '#/main/privacy/account/privacy/containers/main' export default { + component: PrivacyMain/*, name: 'privacy', icon: 'fa fa-fw fa-user-shield', label: trans('privacy'), - component: PrivacyMain, - order: 3 + order: 3*/ } diff --git a/src/main/privacy/Subscriber/Administration/PrivacySubscriber.php b/src/main/privacy/Subscriber/Administration/PrivacySubscriber.php deleted file mode 100644 index 6cc14b7fd6d..00000000000 --- a/src/main/privacy/Subscriber/Administration/PrivacySubscriber.php +++ /dev/null @@ -1,39 +0,0 @@ -serializer = $serializer; - } - - public static function getSubscribedEvents(): array - { - return [ - ToolEvents::getEventName(ToolEvents::OPEN, Tool::ADMINISTRATION, static::NAME) => 'onOpen', - ]; - } - - public function onOpen(OpenToolEvent $event): void - { - $parameters = $this->serializer->serialize(); - - $event->setData([ - 'lockedParameters' => $parameters['lockedParameters'] ?? [], - 'parameters' => $parameters, - ]); - } -} diff --git a/src/main/scheduler/Installation/ClarolineSchedulerInstaller.php b/src/main/scheduler/Installation/ClarolineSchedulerInstaller.php index 98c801c2bf0..87f2cfb005b 100644 --- a/src/main/scheduler/Installation/ClarolineSchedulerInstaller.php +++ b/src/main/scheduler/Installation/ClarolineSchedulerInstaller.php @@ -15,4 +15,8 @@ class ClarolineSchedulerInstaller extends AdditionalInstaller { + public function hasMigrations(): bool + { + return true; + } } diff --git a/src/main/theme/Installation/ClarolineThemeInstaller.php b/src/main/theme/Installation/ClarolineThemeInstaller.php index 21b6d29384f..306a4c30e02 100644 --- a/src/main/theme/Installation/ClarolineThemeInstaller.php +++ b/src/main/theme/Installation/ClarolineThemeInstaller.php @@ -6,4 +6,8 @@ class ClarolineThemeInstaller extends AdditionalInstaller { + public function hasMigrations(): bool + { + return true; + } } diff --git a/src/main/transfer/Installation/ClarolineTransferInstaller.php b/src/main/transfer/Installation/ClarolineTransferInstaller.php index 29c3b645084..c805a373fa6 100644 --- a/src/main/transfer/Installation/ClarolineTransferInstaller.php +++ b/src/main/transfer/Installation/ClarolineTransferInstaller.php @@ -15,4 +15,8 @@ class ClarolineTransferInstaller extends AdditionalInstaller { + public function hasMigrations(): bool + { + return true; + } } diff --git a/src/plugin/agenda/Installation/ClarolineAgendaInstaller.php b/src/plugin/agenda/Installation/ClarolineAgendaInstaller.php index 5e8c23bcfed..e3f509836bf 100644 --- a/src/plugin/agenda/Installation/ClarolineAgendaInstaller.php +++ b/src/plugin/agenda/Installation/ClarolineAgendaInstaller.php @@ -6,6 +6,11 @@ class ClarolineAgendaInstaller extends AdditionalInstaller { + public function hasMigrations(): bool + { + return true; + } + public function hasFixtures(): bool { return true; diff --git a/src/plugin/agenda/Security/Voter/AbstractEventVoter.php b/src/plugin/agenda/Security/Voter/AbstractEventVoter.php index d51e8c8c938..c89fbde6048 100644 --- a/src/plugin/agenda/Security/Voter/AbstractEventVoter.php +++ b/src/plugin/agenda/Security/Voter/AbstractEventVoter.php @@ -12,10 +12,6 @@ namespace Claroline\AgendaBundle\Security\Voter; use Claroline\AppBundle\Security\Voter\AbstractVoter; -use Claroline\CoreBundle\Entity\Planning\AbstractPlanned; -use Claroline\CoreBundle\Entity\Tool\OrderedTool; -use Claroline\CoreBundle\Entity\User; -use Claroline\CoreBundle\Repository\Tool\OrderedToolRepository; use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; use Symfony\Component\Security\Core\Authorization\Voter\VoterInterface; @@ -27,39 +23,15 @@ public function checkPermission(TokenInterface $token, $object, array $attribute case self::CREATE: case self::EDIT: case self::DELETE: - return $this->checkEdit($token, $object); - } - - return VoterInterface::ACCESS_ABSTAIN; - } - - public function checkEdit(TokenInterface $token, AbstractPlanned $object): int - { - $workspace = $object->getWorkspace(); - - $currentUser = $token->getUser(); - $user = $object->getCreator(); + $workspace = $object->getWorkspace(); + if ($this->isToolGranted('EDIT', 'agenda', $workspace)) { + return VoterInterface::ACCESS_GRANTED; + } - // the user is the creator of the event - if ($currentUser instanceof User && (!$user || $currentUser->getUuid() === $user->getUuid())) { - return VoterInterface::ACCESS_GRANTED; + return VoterInterface::ACCESS_DENIED; } - // the user has EDIT right on the corresponding tool - /** @var OrderedToolRepository $orderedToolRepo */ - $orderedToolRepo = $this->getObjectManager()->getRepository(OrderedTool::class); - - if (!empty($workspace)) { - $agendaTool = $orderedToolRepo->findOneByNameAndWorkspace('agenda', $workspace); - } else { - $agendaTool = $orderedToolRepo->findOneByNameAndDesktop('agenda'); - } - - if ($this->isGranted('EDIT', $agendaTool)) { - return VoterInterface::ACCESS_GRANTED; - } - - return VoterInterface::ACCESS_DENIED; + return VoterInterface::ACCESS_ABSTAIN; } public function getSupportedActions(): array diff --git a/src/plugin/analytics/Installation/ClarolineAnalyticsInstaller.php b/src/plugin/analytics/Installation/ClarolineAnalyticsInstaller.php index adcbe9562ba..c3c58aac905 100644 --- a/src/plugin/analytics/Installation/ClarolineAnalyticsInstaller.php +++ b/src/plugin/analytics/Installation/ClarolineAnalyticsInstaller.php @@ -6,8 +6,4 @@ class ClarolineAnalyticsInstaller extends AdditionalInstaller { - public function hasMigrations(): bool - { - return false; - } } diff --git a/src/plugin/announcement/Installation/ClarolineAnnouncementInstaller.php b/src/plugin/announcement/Installation/ClarolineAnnouncementInstaller.php index 10047d4c966..e954e09ba91 100644 --- a/src/plugin/announcement/Installation/ClarolineAnnouncementInstaller.php +++ b/src/plugin/announcement/Installation/ClarolineAnnouncementInstaller.php @@ -15,6 +15,11 @@ class ClarolineAnnouncementInstaller extends AdditionalInstaller { + public function hasMigrations(): bool + { + return true; + } + public function hasFixtures(): bool { return true; diff --git a/src/plugin/audio-player/Installation/ClarolineAudioPlayerInstaller.php b/src/plugin/audio-player/Installation/ClarolineAudioPlayerInstaller.php index e1817ff5637..ca9e9a9732b 100644 --- a/src/plugin/audio-player/Installation/ClarolineAudioPlayerInstaller.php +++ b/src/plugin/audio-player/Installation/ClarolineAudioPlayerInstaller.php @@ -6,4 +6,8 @@ class ClarolineAudioPlayerInstaller extends AdditionalInstaller { + public function hasMigrations(): bool + { + return true; + } } diff --git a/src/plugin/bibliography/Installation/IcapBibliographyInstaller.php b/src/plugin/bibliography/Installation/IcapBibliographyInstaller.php index 8bda36a1305..718a2003a34 100644 --- a/src/plugin/bibliography/Installation/IcapBibliographyInstaller.php +++ b/src/plugin/bibliography/Installation/IcapBibliographyInstaller.php @@ -6,4 +6,8 @@ class IcapBibliographyInstaller extends AdditionalInstaller { + public function hasMigrations(): bool + { + return true; + } } diff --git a/src/plugin/blog/Installation/IcapBlogInstaller.php b/src/plugin/blog/Installation/IcapBlogInstaller.php index b86dcd8838e..0857b0d5b74 100644 --- a/src/plugin/blog/Installation/IcapBlogInstaller.php +++ b/src/plugin/blog/Installation/IcapBlogInstaller.php @@ -6,4 +6,8 @@ class IcapBlogInstaller extends AdditionalInstaller { + public function hasMigrations(): bool + { + return true; + } } diff --git a/src/plugin/claco-form/Installation/ClarolineClacoFormInstaller.php b/src/plugin/claco-form/Installation/ClarolineClacoFormInstaller.php index f6513ed0455..a9faeebc2d4 100644 --- a/src/plugin/claco-form/Installation/ClarolineClacoFormInstaller.php +++ b/src/plugin/claco-form/Installation/ClarolineClacoFormInstaller.php @@ -15,4 +15,8 @@ class ClarolineClacoFormInstaller extends AdditionalInstaller { + public function hasMigrations(): bool + { + return true; + } } diff --git a/src/plugin/claco-form/Manager/ClacoFormManager.php b/src/plugin/claco-form/Manager/ClacoFormManager.php index c901c700e2c..60e076593f8 100644 --- a/src/plugin/claco-form/Manager/ClacoFormManager.php +++ b/src/plugin/claco-form/Manager/ClacoFormManager.php @@ -11,7 +11,6 @@ namespace Claroline\ClacoFormBundle\Manager; -use Claroline\AppBundle\Log\LoggableTrait; use Claroline\AppBundle\Persistence\ObjectManager; use Claroline\ClacoFormBundle\Entity\Category; use Claroline\ClacoFormBundle\Entity\ClacoForm; @@ -43,7 +42,6 @@ use Claroline\CoreBundle\Entity\User; use Claroline\CoreBundle\Messenger\Message\SendMessage; use Doctrine\Common\Collections\ArrayCollection; -use Psr\Log\LoggerAwareInterface; use Ramsey\Uuid\Uuid; use Symfony\Component\EventDispatcher\EventDispatcherInterface; use Symfony\Component\HttpFoundation\File\UploadedFile; @@ -55,10 +53,8 @@ use Symfony\Component\Security\Core\Exception\AccessDeniedException; use Symfony\Contracts\Translation\TranslatorInterface; -class ClacoFormManager implements LoggerAwareInterface +class ClacoFormManager { - use LoggableTrait; - /** @var AuthorizationCheckerInterface */ private $authorization; /** @var EventDispatcherInterface */ diff --git a/src/plugin/claco-form/Resources/config/services/manager.yml b/src/plugin/claco-form/Resources/config/services/manager.yml index 3b0636d1e73..cf3dbd731c0 100644 --- a/src/plugin/claco-form/Resources/config/services/manager.yml +++ b/src/plugin/claco-form/Resources/config/services/manager.yml @@ -15,8 +15,6 @@ services: - '@translator' - '@messenger.default_bus' - '@Claroline\ClacoFormBundle\Manager\CategoryManager' - calls: - - setLogger: [ '@logger' ] Claroline\ClacoFormBundle\Manager\CategoryManager: arguments: diff --git a/src/plugin/competency/Controller/CompetencyController.php b/src/plugin/competency/Controller/CompetencyController.php index 1ca5356a893..c294834c2c1 100644 --- a/src/plugin/competency/Controller/CompetencyController.php +++ b/src/plugin/competency/Controller/CompetencyController.php @@ -13,6 +13,7 @@ use Claroline\AppBundle\API\Options; use Claroline\AppBundle\Controller\AbstractCrudController; +use Claroline\CoreBundle\Component\Context\DesktopContext; use Claroline\CoreBundle\Entity\Resource\ResourceNode; use Claroline\CoreBundle\Manager\Tool\ToolManager; use Claroline\CoreBundle\Security\PermissionCheckerTrait; @@ -89,6 +90,7 @@ public function competenciesRootListAction(Request $request): JsonResponse * "/competency/{id}/list", * name="apiv2_competency_tree_list" * ) + * * @EXT\ParamConverter( * "competency", * class="HeVinci\CompetencyBundle\Entity\Competency", @@ -118,6 +120,7 @@ public function competenciesTreeListAction(Competency $competency, Request $requ * "/framework/{id}/export", * name="apiv2_competency_framework_export" * ) + * * @EXT\ParamConverter( * "framework", * class="HeVinci\CompetencyBundle\Entity\Competency", @@ -185,6 +188,7 @@ public function frameworkImportAction(Request $request): JsonResponse * "/node/{node}/competencies/fetch", * name="apiv2_competency_resource_competencies_list" * ) + * * @EXT\ParamConverter( * "node", * class="Claroline\CoreBundle\Entity\Resource\ResourceNode", @@ -210,6 +214,7 @@ public function resourceCompetenciesFetchAction(ResourceNode $node): JsonRespons * name="apiv2_competency_resource_associate", * methods={"POST"} * ) + * * @EXT\ParamConverter( * "node", * class="Claroline\CoreBundle\Entity\Resource\ResourceNode", @@ -239,6 +244,7 @@ public function resourceCompetencyAssociateAction(ResourceNode $node, Competency * name="apiv2_competency_resource_dissociate", * methods={"DELETE"} * ) + * * @EXT\ParamConverter( * "node", * class="Claroline\CoreBundle\Entity\Resource\ResourceNode", @@ -268,7 +274,7 @@ public static function getOptions(): array private function checkToolAccess(string $rights = 'OPEN'): void { - $competenciesTool = $this->toolManager->getAdminToolByName('competencies'); + $competenciesTool = $this->toolManager->getOrderedTool('competencies', DesktopContext::getName()); if (is_null($competenciesTool) || !$this->authorization->isGranted($rights, $competenciesTool)) { throw new AccessDeniedException(); diff --git a/src/plugin/competency/Installation/HeVinciCompetencyInstaller.php b/src/plugin/competency/Installation/HeVinciCompetencyInstaller.php index cec305c292e..cbd12f9ac30 100644 --- a/src/plugin/competency/Installation/HeVinciCompetencyInstaller.php +++ b/src/plugin/competency/Installation/HeVinciCompetencyInstaller.php @@ -6,4 +6,8 @@ class HeVinciCompetencyInstaller extends AdditionalInstaller { + public function hasMigrations(): bool + { + return true; + } } diff --git a/src/plugin/cursus/Installation/ClarolineCursusInstaller.php b/src/plugin/cursus/Installation/ClarolineCursusInstaller.php index 470d62fb631..d75ffc3b967 100644 --- a/src/plugin/cursus/Installation/ClarolineCursusInstaller.php +++ b/src/plugin/cursus/Installation/ClarolineCursusInstaller.php @@ -6,6 +6,11 @@ class ClarolineCursusInstaller extends AdditionalInstaller { + public function hasMigrations(): bool + { + return true; + } + public function hasFixtures(): bool { return true; diff --git a/src/plugin/cursus/Security/Voter/CourseVoter.php b/src/plugin/cursus/Security/Voter/CourseVoter.php index 20e5a3c4d9a..53bd61560ad 100644 --- a/src/plugin/cursus/Security/Voter/CourseVoter.php +++ b/src/plugin/cursus/Security/Voter/CourseVoter.php @@ -12,15 +12,13 @@ namespace Claroline\CursusBundle\Security\Voter; use Claroline\AppBundle\Security\Voter\AbstractVoter; -use Claroline\CoreBundle\Entity\Tool\OrderedTool; -use Claroline\CoreBundle\Repository\Tool\OrderedToolRepository; use Claroline\CursusBundle\Entity\Course; use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; use Symfony\Component\Security\Core\Authorization\Voter\VoterInterface; class CourseVoter extends AbstractVoter { - const REGISTER = 'REGISTER'; + public const REGISTER = 'REGISTER'; public function getClass(): string { @@ -32,14 +30,9 @@ public function getClass(): string */ public function checkPermission(TokenInterface $token, $object, array $attributes, array $options): int { - /** @var OrderedToolRepository $orderedToolRepo */ - $orderedToolRepo = $this->getObjectManager()->getRepository(OrderedTool::class); - - $trainingsTool = $orderedToolRepo->findOneByNameAndDesktop('trainings'); - switch ($attributes[0]) { case self::CREATE: // EDIT right on tool - if ($this->isGranted('EDIT', $trainingsTool)) { + if ($this->isToolGranted('EDIT', 'trainings')) { return VoterInterface::ACCESS_GRANTED; } @@ -48,7 +41,7 @@ public function checkPermission(TokenInterface $token, $object, array $attribute case self::EDIT: // admin of organization | EDIT right on tool case self::PATCH: case self::DELETE: - if ($this->isGranted('EDIT', $trainingsTool)) { + if ($this->isToolGranted('EDIT', 'trainings')) { return VoterInterface::ACCESS_GRANTED; } @@ -56,14 +49,14 @@ public function checkPermission(TokenInterface $token, $object, array $attribute case self::OPEN: // member of organization & OPEN right on tool case self::VIEW: - if ($this->isGranted('OPEN', $trainingsTool)) { + if ($this->isToolGranted('OPEN', 'trainings')) { return VoterInterface::ACCESS_GRANTED; } return VoterInterface::ACCESS_DENIED; case self::REGISTER: - if ($this->isGranted('REGISTER', $trainingsTool)) { + if ($this->isToolGranted('REGISTER', 'trainings')) { return VoterInterface::ACCESS_GRANTED; } diff --git a/src/plugin/cursus/Security/Voter/EventVoter.php b/src/plugin/cursus/Security/Voter/EventVoter.php index dd210ef2736..2318c125b6e 100644 --- a/src/plugin/cursus/Security/Voter/EventVoter.php +++ b/src/plugin/cursus/Security/Voter/EventVoter.php @@ -12,15 +12,13 @@ namespace Claroline\CursusBundle\Security\Voter; use Claroline\AppBundle\Security\Voter\AbstractVoter; -use Claroline\CoreBundle\Entity\Tool\OrderedTool; -use Claroline\CoreBundle\Repository\Tool\OrderedToolRepository; use Claroline\CursusBundle\Entity\Event; use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; use Symfony\Component\Security\Core\Authorization\Voter\VoterInterface; class EventVoter extends AbstractVoter { - const REGISTER = 'REGISTER'; + public const REGISTER = 'REGISTER'; public function getClass(): string { @@ -32,20 +30,15 @@ public function getClass(): string */ public function checkPermission(TokenInterface $token, $object, array $attributes, array $options): int { - /** @var OrderedToolRepository $orderedToolRepo */ - $orderedToolRepo = $this->getObjectManager()->getRepository(OrderedTool::class); - + $workspace = null; if ($object->getSession() && $object->getSession()->getWorkspace()) { - $trainingsTool = $orderedToolRepo->findOneByNameAndWorkspace('training_events', $object->getSession()->getWorkspace()); - } else { - $trainingsTool = $orderedToolRepo->findOneByNameAndDesktop('trainings'); + $workspace = $object->getSession()->getWorkspace(); } - $toolEdit = $this->isGranted('EDIT', $trainingsTool); - switch ($attributes[0]) { case self::CREATE: // EDIT right on tool - if ($toolEdit) { + if ($this->isToolGranted('EDIT', 'training_events', $workspace) + || $this->isToolGranted('EDIT', 'trainings')) { return VoterInterface::ACCESS_GRANTED; } @@ -54,21 +47,24 @@ public function checkPermission(TokenInterface $token, $object, array $attribute case self::EDIT: case self::DELETE: case self::PATCH: - if ($toolEdit || ($object->getSession() && $this->isGranted('EDIT', $object->getSession()))) { + if ($this->isToolGranted('EDIT', 'training_events', $workspace) + || ($object->getSession() && $this->isGranted('EDIT', $object->getSession()))) { return VoterInterface::ACCESS_GRANTED; } return VoterInterface::ACCESS_DENIED; case self::OPEN: case self::VIEW: - if ($this->isGranted('OPEN', $trainingsTool) || ($object->getSession() && $this->isGranted('OPEN', $object->getSession()))) { + if ($this->isToolGranted('OPEN', 'training_events', $workspace) + || ($object->getSession() && $this->isGranted('OPEN', $object->getSession()))) { return VoterInterface::ACCESS_GRANTED; } return VoterInterface::ACCESS_DENIED; case self::REGISTER: - if ($this->isGranted('REGISTER', $trainingsTool) || ($object->getSession() && $this->isGranted('REGISTER', $object->getSession()))) { + if ($this->isToolGranted('REGISTER', 'training_events', $workspace) + || ($object->getSession() && $this->isGranted('REGISTER', $object->getSession()))) { return VoterInterface::ACCESS_GRANTED; } diff --git a/src/plugin/drop-zone/Installation/ClarolineDropZoneInstaller.php b/src/plugin/drop-zone/Installation/ClarolineDropZoneInstaller.php index ba511516148..679ffbc5677 100644 --- a/src/plugin/drop-zone/Installation/ClarolineDropZoneInstaller.php +++ b/src/plugin/drop-zone/Installation/ClarolineDropZoneInstaller.php @@ -15,4 +15,8 @@ class ClarolineDropZoneInstaller extends AdditionalInstaller { + public function hasMigrations(): bool + { + return true; + } } diff --git a/src/plugin/exo/Installation/UJMExoInstaller.php b/src/plugin/exo/Installation/UJMExoInstaller.php index 9ab458617ab..1578a13af97 100644 --- a/src/plugin/exo/Installation/UJMExoInstaller.php +++ b/src/plugin/exo/Installation/UJMExoInstaller.php @@ -6,4 +6,8 @@ class UJMExoInstaller extends AdditionalInstaller { + public function hasMigrations(): bool + { + return true; + } } diff --git a/src/plugin/favourite/Installation/HeVinciFavouriteInstaller.php b/src/plugin/favourite/Installation/HeVinciFavouriteInstaller.php index 93df521d308..e4ce237a6f2 100644 --- a/src/plugin/favourite/Installation/HeVinciFavouriteInstaller.php +++ b/src/plugin/favourite/Installation/HeVinciFavouriteInstaller.php @@ -6,4 +6,8 @@ class HeVinciFavouriteInstaller extends AdditionalInstaller { + public function hasMigrations(): bool + { + return true; + } } diff --git a/src/plugin/forum/Installation/ClarolineForumInstaller.php b/src/plugin/forum/Installation/ClarolineForumInstaller.php index ff395d796c0..111687b3f6e 100644 --- a/src/plugin/forum/Installation/ClarolineForumInstaller.php +++ b/src/plugin/forum/Installation/ClarolineForumInstaller.php @@ -6,6 +6,11 @@ class ClarolineForumInstaller extends AdditionalInstaller { + public function hasMigrations(): bool + { + return true; + } + public function hasFixtures(): bool { return true; diff --git a/src/plugin/history/Command/CleanHistoryCommand.php b/src/plugin/history/Command/CleanHistoryCommand.php deleted file mode 100644 index 796f824de8e..00000000000 --- a/src/plugin/history/Command/CleanHistoryCommand.php +++ /dev/null @@ -1,32 +0,0 @@ -historyManager = $historyManager; - - parent::__construct(); - } - - protected function configure() - { - $this->setDescription('Cleans the recent workspaces and resources table of obsolete entries'); - } - - protected function execute(InputInterface $input, OutputInterface $output): int - { - $this->historyManager->cleanRecent(); - - return 0; - } -} diff --git a/src/plugin/history/Installation/ClarolineHistoryInstaller.php b/src/plugin/history/Installation/ClarolineHistoryInstaller.php index df313a44dc0..839d6202d1d 100644 --- a/src/plugin/history/Installation/ClarolineHistoryInstaller.php +++ b/src/plugin/history/Installation/ClarolineHistoryInstaller.php @@ -6,4 +6,8 @@ class ClarolineHistoryInstaller extends AdditionalInstaller { + public function hasMigrations(): bool + { + return true; + } } diff --git a/src/plugin/history/Manager/HistoryManager.php b/src/plugin/history/Manager/HistoryManager.php index 9923a9efcd3..9de19bd2b1d 100644 --- a/src/plugin/history/Manager/HistoryManager.php +++ b/src/plugin/history/Manager/HistoryManager.php @@ -2,7 +2,6 @@ namespace Claroline\HistoryBundle\Manager; -use Claroline\AppBundle\Log\LoggableTrait; use Claroline\AppBundle\Persistence\ObjectManager; use Claroline\CoreBundle\Entity\Resource\ResourceNode; use Claroline\CoreBundle\Entity\User; @@ -12,25 +11,20 @@ use Claroline\HistoryBundle\Repository\ResourceRecentRepository; use Claroline\HistoryBundle\Repository\WorkspaceRecentRepository; use Psr\Log\LoggerAwareInterface; +use Psr\Log\LoggerAwareTrait; class HistoryManager implements LoggerAwareInterface { - use LoggableTrait; + use LoggerAwareTrait; /** * The number of results to fetch when retrieving user history. */ - const HISTORY_RESULTS = 5; + public const HISTORY_RESULTS = 5; - /** @var ObjectManager */ - private $om; - - /** - * HistoryManager constructor. - */ - public function __construct(ObjectManager $om) - { - $this->om = $om; + public function __construct( + private readonly ObjectManager $om + ) { } /** @@ -38,7 +32,7 @@ public function __construct(ObjectManager $om) * * @return Workspace[] */ - public function getWorkspaces(User $user) + public function getWorkspaces(User $user): array { /** @var WorkspaceRecentRepository $repo */ $repo = $this->om->getRepository(WorkspaceRecent::class); @@ -55,7 +49,7 @@ public function getWorkspaces(User $user) * * @return ResourceNode[] */ - public function getResources(User $user) + public function getResources(User $user): array { /** @var ResourceRecentRepository $repo */ $repo = $this->om->getRepository(ResourceRecent::class); @@ -70,7 +64,7 @@ public function getResources(User $user) /** * Add a workspace to the user history. */ - public function addWorkspace(Workspace $workspace, User $user) + public function addWorkspace(Workspace $workspace, User $user): void { // If object already in recent workspaces, update date $recentWorkspace = $this->om @@ -95,7 +89,7 @@ public function addWorkspace(Workspace $workspace, User $user) /** * Add a resource to the user history. */ - public function addResource(ResourceNode $resource, User $user) + public function addResource(ResourceNode $resource, User $user): void { // If object already in recent workspaces, update date $recentResource = $this->om @@ -116,22 +110,4 @@ public function addResource(ResourceNode $resource, User $user) $this->om->persist($recentResource); $this->om->flush(); } - - /** - * Clean all recent workspaces and resources that are more than 6 months old. - */ - public function cleanRecent() - { - $this->log('Cleaning recent workspaces entries that are older than six months'); - - /** @var WorkspaceRecentRepository $recentWorkspaceRepo */ - $recentWorkspaceRepo = $this->om->getRepository(WorkspaceRecent::class); - $recentWorkspaceRepo->removeAllEntriesBefore(new \DateTime('-6 months')); - - $this->log('Cleaning recent resources entries that are older than six months'); - - /** @var ResourceRecentRepository $recentResourceRepo */ - $recentResourceRepo = $this->om->getRepository(ResourceRecent::class); - $recentResourceRepo->removeAllEntriesBefore(new \DateTime('-6 months')); - } } diff --git a/src/plugin/history/Repository/ResourceRecentRepository.php b/src/plugin/history/Repository/ResourceRecentRepository.php index c21e21a2f37..f25ceca8a74 100644 --- a/src/plugin/history/Repository/ResourceRecentRepository.php +++ b/src/plugin/history/Repository/ResourceRecentRepository.php @@ -18,15 +18,4 @@ public function findEntries(User $user, int $nbResults) ->getQuery() ->getResult(); } - - public function removeAllEntriesBefore($date) - { - $qb = $this - ->createQueryBuilder('rw') - ->delete() - ->andWhere('rw.createdAt <= :date') - ->setParameter('date', $date); - - return $qb->getQuery()->getResult(); - } } diff --git a/src/plugin/history/Repository/WorkspaceRecentRepository.php b/src/plugin/history/Repository/WorkspaceRecentRepository.php index 62ef49c65d3..c7032f78019 100644 --- a/src/plugin/history/Repository/WorkspaceRecentRepository.php +++ b/src/plugin/history/Repository/WorkspaceRecentRepository.php @@ -18,15 +18,4 @@ public function findEntries(User $user, int $nbResults) ->getQuery() ->getResult(); } - - public function removeAllEntriesBefore($date) - { - $qb = $this - ->createQueryBuilder('rw') - ->delete() - ->andWhere('rw.createdAt <= :date') - ->setParameter('date', $date); - - return $qb->getQuery()->getResult(); - } } diff --git a/src/plugin/history/Resources/config/services.yml b/src/plugin/history/Resources/config/services.yml index aee369a1012..b6d4b0ab6e0 100644 --- a/src/plugin/history/Resources/config/services.yml +++ b/src/plugin/history/Resources/config/services.yml @@ -30,11 +30,3 @@ services: arguments: - '@Claroline\AppBundle\API\SerializerProvider' - '@Claroline\HistoryBundle\Manager\HistoryManager' - - # Console commands - - Claroline\HistoryBundle\Command\CleanHistoryCommand: - arguments: - - '@Claroline\HistoryBundle\Manager\HistoryManager' - tags: - - { name: console.command, command: claroline:history:clean } diff --git a/src/plugin/history/Resources/translations/history.en.json b/src/plugin/history/Resources/translations/history.en.json index 7e98a6e8987..b5609b1e6ef 100644 --- a/src/plugin/history/Resources/translations/history.en.json +++ b/src/plugin/history/Resources/translations/history.en.json @@ -5,5 +5,6 @@ "empty_workspaces": "You have not viewed any workspace", "empty_workspaces_help": "Browse your workspaces to see them appear here", "empty_resources": "You have not viewed any resource", - "empty_resources_help": "Browse your resources to see them appear here" + "empty_resources_help": "Browse your resources to see them appear here", + "history_loading": "We are loading your history..." } diff --git a/src/plugin/history/Resources/translations/history.fr.json b/src/plugin/history/Resources/translations/history.fr.json index d17730f377e..d90f67fbde4 100644 --- a/src/plugin/history/Resources/translations/history.fr.json +++ b/src/plugin/history/Resources/translations/history.fr.json @@ -5,5 +5,6 @@ "empty_workspaces": "Vous n'avez consulté aucun espace d'activité", "empty_workspaces_help": "Parcourez vos espaces d'activités pour les voir apparaître ici", "empty_resources": "Vous n'avez consulté aucune ressource", - "empty_resources_help": "Parcourez vos ressources pour les voir apparaître ici" + "empty_resources_help": "Parcourez vos ressources pour les voir apparaître ici", + "history_loading": "Nous chargeons votre historique..." } diff --git a/src/plugin/home/Controller/HomeController.php b/src/plugin/home/Controller/HomeController.php index 18fb84fde50..bbcb0400fb7 100644 --- a/src/plugin/home/Controller/HomeController.php +++ b/src/plugin/home/Controller/HomeController.php @@ -15,9 +15,10 @@ use Claroline\AppBundle\API\FinderProvider; use Claroline\AppBundle\Controller\RequestDecoderTrait; use Claroline\AppBundle\Persistence\ObjectManager; -use Claroline\CoreBundle\Entity\Tool\OrderedTool; +use Claroline\CoreBundle\Component\Context\DesktopContext; use Claroline\CoreBundle\Entity\User; use Claroline\CoreBundle\Manager\LockManager; +use Claroline\CoreBundle\Manager\Tool\ToolManager; use Claroline\HomeBundle\Entity\HomeTab; use Claroline\HomeBundle\Manager\HomeManager; use Claroline\HomeBundle\Serializer\HomeTabSerializer; @@ -30,46 +31,24 @@ /** * @Route("/home") + * + * @deprecated should be merged with HomeTabController */ class HomeController { use RequestDecoderTrait; - /** @var TokenStorageInterface */ - private $tokenStorage; - /** @var AuthorizationCheckerInterface */ - private $authorization; - /** @var ObjectManager */ - private $om; - /** @var FinderProvider */ - private $finder; - /** @var Crud */ - private $crud; - /** @var HomeTabSerializer */ - private $serializer; - /** @var LockManager */ - private $lockManager; - /** @var HomeManager */ - private $manager; - public function __construct( - TokenStorageInterface $tokenStorage, - AuthorizationCheckerInterface $authorization, - ObjectManager $om, - FinderProvider $finder, - Crud $crud, - LockManager $lockManager, - HomeTabSerializer $serializer, - HomeManager $manager + private readonly TokenStorageInterface $tokenStorage, + private readonly AuthorizationCheckerInterface $authorization, + private readonly ObjectManager $om, + private readonly FinderProvider $finder, + private readonly Crud $crud, + private readonly LockManager $lockManager, + private readonly ToolManager $toolManager, + private readonly HomeTabSerializer $serializer, + private readonly HomeManager $manager ) { - $this->tokenStorage = $tokenStorage; - $this->authorization = $authorization; - $this->om = $om; - $this->finder = $finder; - $this->crud = $crud; - $this->lockManager = $lockManager; - $this->serializer = $serializer; - $this->manager = $manager; } /** @@ -234,7 +213,7 @@ public function adminTabsFetchAction(): JsonResponse ); } - private function cleanDatabase(array $installedTabs, array $ids) + private function cleanDatabase(array $installedTabs, array $ids): void { foreach ($installedTabs as $installedTab) { $this->lockManager->unlock(HomeTab::class, $installedTab->getUuid()); @@ -246,9 +225,9 @@ private function cleanDatabase(array $installedTabs, array $ids) } } - private function checkDesktopPermissions(string $perm) + private function checkDesktopPermissions(string $perm): void { - $homeTool = $this->om->getRepository(OrderedTool::class)->findOneByNameAndDesktop('home'); + $homeTool = $this->toolManager->getOrderedTool('home', DesktopContext::getName()); if (!$homeTool || !$this->authorization->isGranted($perm, $homeTool)) { throw new AccessDeniedException(); } diff --git a/src/plugin/home/Installation/ClarolineHomeInstaller.php b/src/plugin/home/Installation/ClarolineHomeInstaller.php index 6b50ce3b1bd..4257b63dc75 100644 --- a/src/plugin/home/Installation/ClarolineHomeInstaller.php +++ b/src/plugin/home/Installation/ClarolineHomeInstaller.php @@ -6,6 +6,11 @@ class ClarolineHomeInstaller extends AdditionalInstaller { + public function hasMigrations(): bool + { + return true; + } + public function hasFixtures(): bool { return true; diff --git a/src/plugin/home/Resources/config/services/controller.yml b/src/plugin/home/Resources/config/services/controller.yml index 0159e919f30..fe2d72d29f5 100644 --- a/src/plugin/home/Resources/config/services/controller.yml +++ b/src/plugin/home/Resources/config/services/controller.yml @@ -10,6 +10,7 @@ services: - '@Claroline\AppBundle\API\FinderProvider' - '@Claroline\AppBundle\API\Crud' - '@Claroline\CoreBundle\Manager\LockManager' + - '@Claroline\CoreBundle\Manager\Tool\ToolManager' - '@Claroline\HomeBundle\Serializer\HomeTabSerializer' - '@Claroline\HomeBundle\Manager\HomeManager' diff --git a/src/plugin/home/Resources/config/services/voter.yml b/src/plugin/home/Resources/config/services/voter.yml index 8461a3c6577..adf742055ea 100644 --- a/src/plugin/home/Resources/config/services/voter.yml +++ b/src/plugin/home/Resources/config/services/voter.yml @@ -4,5 +4,3 @@ services: Claroline\HomeBundle\Security\Voter\HomeTabVoter: parent: Claroline\AppBundle\Security\Voter\AbstractVoter - arguments: - - '@Claroline\AppBundle\Persistence\ObjectManager' diff --git a/src/plugin/home/Security/Voter/HomeTabVoter.php b/src/plugin/home/Security/Voter/HomeTabVoter.php index 9d0dc6c97dd..7f612a96ab0 100644 --- a/src/plugin/home/Security/Voter/HomeTabVoter.php +++ b/src/plugin/home/Security/Voter/HomeTabVoter.php @@ -11,31 +11,14 @@ namespace Claroline\HomeBundle\Security\Voter; -use Claroline\AppBundle\Persistence\ObjectManager; use Claroline\AppBundle\Security\Voter\AbstractVoter; -use Claroline\CoreBundle\Entity\Tool\OrderedTool; use Claroline\CoreBundle\Entity\User; -use Claroline\CoreBundle\Repository\Tool\OrderedToolRepository; -use Claroline\CoreBundle\Security\ToolPermissions; use Claroline\HomeBundle\Entity\HomeTab; use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; use Symfony\Component\Security\Core\Authorization\Voter\VoterInterface; class HomeTabVoter extends AbstractVoter { - /** @var ObjectManager */ - private $om; - - /** @var OrderedToolRepository */ - private $orderedToolRepo; - - public function __construct(ObjectManager $om) - { - $this->om = $om; - - $this->orderedToolRepo = $this->om->getRepository(OrderedTool::class); - } - public function checkPermission(TokenInterface $token, $object, array $attributes, array $options): int { switch ($attributes[0]) { @@ -62,20 +45,17 @@ private function check(TokenInterface $token, HomeTab $object): int break; case HomeTab::TYPE_DESKTOP: - $homeTool = $this->orderedToolRepo->findOneByNameAndDesktop('home'); $isOwner = $object->getUser() && $token->getUser() instanceof User && $object->getUser()->getId() === $token->getUser()->getId(); - $granted = $isOwner && $homeTool && $this->isGranted(self::OPEN, $homeTool); + $granted = $isOwner && $this->isToolGranted(self::OPEN, 'home'); break; case HomeTab::TYPE_ADMIN_DESKTOP: - $homeTool = $this->orderedToolRepo->findOneByNameAndDesktop('home'); - - $granted = $homeTool && $this->isGranted(self::OPEN, $homeTool); + $granted = $this->isToolGranted(self::OPEN, 'home'); break; case HomeTab::TYPE_WORKSPACE: - $granted = $object->getWorkspace() && $this->isGranted(ToolPermissions::getPermission('home', self::OPEN), $object->getWorkspace()); + $granted = $object->getWorkspace() && $this->isToolGranted(self::OPEN, 'home', $object->getWorkspace()); break; } @@ -99,20 +79,17 @@ private function checkEdit(TokenInterface $token, HomeTab $object): int break; case HomeTab::TYPE_DESKTOP: - $homeTool = $this->orderedToolRepo->findOneByNameAndDesktop('home'); $isOwner = $object->getUser() && $token->getUser() instanceof User && $object->getUser()->getId() === $token->getUser()->getId(); - $granted = $isOwner && $homeTool && $this->isGranted(self::EDIT, $homeTool); + $granted = $isOwner && $this->isToolGranted(self::EDIT, 'home'); break; case HomeTab::TYPE_ADMIN_DESKTOP: - $homeTool = $this->orderedToolRepo->findOneByNameAndDesktop('home'); - - $granted = $homeTool && $this->isGranted(self::ADMINISTRATE, $homeTool); + $granted = $this->isToolGranted(self::ADMINISTRATE, 'home'); break; case HomeTab::TYPE_WORKSPACE: - $granted = $object->getWorkspace() && $this->isGranted(ToolPermissions::getPermission('home', self::EDIT), $object->getWorkspace()); + $granted = $object->getWorkspace() && $this->isToolGranted(self::EDIT, 'home', $object->getWorkspace()); break; } diff --git a/src/plugin/lesson/Installation/IcapLessonInstaller.php b/src/plugin/lesson/Installation/IcapLessonInstaller.php index c2d31e3cae7..54aec4f419d 100644 --- a/src/plugin/lesson/Installation/IcapLessonInstaller.php +++ b/src/plugin/lesson/Installation/IcapLessonInstaller.php @@ -6,4 +6,8 @@ class IcapLessonInstaller extends AdditionalInstaller { + public function hasMigrations(): bool + { + return true; + } } diff --git a/src/plugin/link/Installation/ClarolineLinkInstaller.php b/src/plugin/link/Installation/ClarolineLinkInstaller.php index 0f4408d9b3d..a4066b2617d 100644 --- a/src/plugin/link/Installation/ClarolineLinkInstaller.php +++ b/src/plugin/link/Installation/ClarolineLinkInstaller.php @@ -6,4 +6,8 @@ class ClarolineLinkInstaller extends AdditionalInstaller { + public function hasMigrations(): bool + { + return true; + } } diff --git a/src/plugin/message/Installation/ClarolineMessageInstaller.php b/src/plugin/message/Installation/ClarolineMessageInstaller.php index b58aedc726a..ed5b7058c6c 100644 --- a/src/plugin/message/Installation/ClarolineMessageInstaller.php +++ b/src/plugin/message/Installation/ClarolineMessageInstaller.php @@ -6,4 +6,8 @@ class ClarolineMessageInstaller extends AdditionalInstaller { + public function hasMigrations(): bool + { + return true; + } } diff --git a/src/plugin/notification/Component/Tool/NotificationsTool.php b/src/plugin/notification/Component/Tool/NotificationsTool.php new file mode 100644 index 00000000000..95f0a3255c5 --- /dev/null +++ b/src/plugin/notification/Component/Tool/NotificationsTool.php @@ -0,0 +1,30 @@ +load('services.yml'); + $loader->load('components.yml'); } } diff --git a/src/plugin/notification/Installation/IcapNotificationInstaller.php b/src/plugin/notification/Installation/IcapNotificationInstaller.php index 614255f1295..05ba84e9e54 100644 --- a/src/plugin/notification/Installation/IcapNotificationInstaller.php +++ b/src/plugin/notification/Installation/IcapNotificationInstaller.php @@ -6,4 +6,8 @@ class IcapNotificationInstaller extends AdditionalInstaller { + public function hasMigrations(): bool + { + return true; + } } diff --git a/src/plugin/notification/Resources/config/components.yml b/src/plugin/notification/Resources/config/components.yml new file mode 100644 index 00000000000..cc128a70a3d --- /dev/null +++ b/src/plugin/notification/Resources/config/components.yml @@ -0,0 +1,2 @@ +imports: + - { resource: components/tool.yml } diff --git a/src/plugin/notification/Resources/config/components/tool.yml b/src/plugin/notification/Resources/config/components/tool.yml new file mode 100644 index 00000000000..9d02a516f56 --- /dev/null +++ b/src/plugin/notification/Resources/config/components/tool.yml @@ -0,0 +1,4 @@ +services: + Icap\NotificationBundle\Component\Tool\NotificationsTool: + parent: Claroline\AppBundle\Component\Tool\AbstractTool + tags: [ 'claroline.component.tool' ] diff --git a/src/plugin/notification/Resources/modules/account/notifications/index.js b/src/plugin/notification/Resources/modules/account/notifications/index.js index 5d09b805fbf..417468d8eb8 100644 --- a/src/plugin/notification/Resources/modules/account/notifications/index.js +++ b/src/plugin/notification/Resources/modules/account/notifications/index.js @@ -1,10 +1,8 @@ -import {trans} from '#/main/app/intl' - import {NotificationMain} from '#/plugin/notification/account/notifications/containers/main' export default { - name: 'notifications', + /*name: 'notifications', icon: 'fa fa-fw fa-bell', label: trans('notifications'), - component: NotificationMain + */component: NotificationMain } diff --git a/src/plugin/notification/Resources/translations/tools.en.json b/src/plugin/notification/Resources/translations/tools.en.json new file mode 100644 index 00000000000..7740761896c --- /dev/null +++ b/src/plugin/notification/Resources/translations/tools.en.json @@ -0,0 +1,3 @@ +{ + "notifications": "Notifications" +} diff --git a/src/plugin/notification/Resources/translations/tools.fr.json b/src/plugin/notification/Resources/translations/tools.fr.json new file mode 100644 index 00000000000..7740761896c --- /dev/null +++ b/src/plugin/notification/Resources/translations/tools.fr.json @@ -0,0 +1,3 @@ +{ + "notifications": "Notifications" +} diff --git a/src/plugin/open-badge/Component/Tool/BadgesTool.php b/src/plugin/open-badge/Component/Tool/BadgesTool.php new file mode 100644 index 00000000000..2eea60ea0b5 --- /dev/null +++ b/src/plugin/open-badge/Component/Tool/BadgesTool.php @@ -0,0 +1,107 @@ +om->getRepository(BadgeClass::class)->findBy(['workspace' => $contextSubject]); + + $badgesData = []; + /** @var BadgeClass $badge */ + foreach ($badges as $badge) { + $badgesData[] = $this->serializer->serialize($badge); + + if (!empty($badge->getImage())) { + $fileBag->add($badge->getUuid(), $badge->getImage()); + } + } + + return [ + 'badges' => $badgesData, + ]; + } + + public function import(string $context, ContextSubjectInterface $contextSubject = null, FileBag $fileBag = null, array $data = [], array $entities = []): ?array + { + if (WorkspaceContext::getName() !== $context) { + return []; + } + + if (empty($data['badges'])) { + return []; + } + + $this->om->startFlushSuite(); + foreach ($data['badges'] as $badgeData) { + if (isset($badgeData['workspace'])) { + unset($badgeData['workspace']); + } + + $new = new BadgeClass(); + $new->setWorkspace($contextSubject); + + $badgeImage = $fileBag->get($badgeData['id']); + if ($badgeImage && !$this->fileManager->exists($badgeImage)) { + $file = $this->fileManager->createFile(new File($badgeImage)); + $badgeData['image'] = $file->getUrl(); + } + + $this->crud->create($new, $badgeData, [Crud::NO_PERMISSIONS, Crud::NO_VALIDATION, Options::REFRESH_UUID]); + + $entities[$badgeData['id']] = $new; + } + $this->om->endFlushSuite(); + + return []; + } +} diff --git a/src/plugin/open-badge/DependencyInjection/ClarolineOpenBadgeExtension.php b/src/plugin/open-badge/DependencyInjection/ClarolineOpenBadgeExtension.php index f7db29f45b8..4afac9796fa 100644 --- a/src/plugin/open-badge/DependencyInjection/ClarolineOpenBadgeExtension.php +++ b/src/plugin/open-badge/DependencyInjection/ClarolineOpenBadgeExtension.php @@ -16,18 +16,14 @@ use Symfony\Component\DependencyInjection\Loader\YamlFileLoader; use Symfony\Component\HttpKernel\DependencyInjection\Extension; -/** - * Loads the core services configuration files. - */ class ClarolineOpenBadgeExtension extends Extension { - /** - * {@inheritdoc} - */ - public function load(array $configs, ContainerBuilder $container) + public function load(array $configs, ContainerBuilder $container): void { $locator = new FileLocator(__DIR__.'/../Resources/config'); $loader = new YamlFileLoader($container, $locator); + $loader->load('services.yml'); + $loader->load('components.yml'); } } diff --git a/src/plugin/open-badge/Finder/AssertionFinder.php b/src/plugin/open-badge/Finder/AssertionFinder.php index baa80d61136..757739dd497 100644 --- a/src/plugin/open-badge/Finder/AssertionFinder.php +++ b/src/plugin/open-badge/Finder/AssertionFinder.php @@ -116,11 +116,9 @@ public function configureQueryBuilder(QueryBuilder $qb, array $searches = [], ar $subQb = $this->om->createQueryBuilder() ->select('ot') ->from('Claroline\CoreBundle\Entity\Tool\OrderedTool', 'ot') - ->leftJoin('ot.workspace', 'otw') ->join('ot.rights', 'r') ->join('r.role', 'rr') - ->where('ot.user IS NULL') - ->andWhere('((w.id IS NULL AND ot.workspace IS NULL) OR otw.id = w.id)') + ->where('(ot.contextId IS NULL OR ot.contextId = w.uuid)') ->andWhere('BIT_AND(r.mask, :grantMask) = :grantMask') ->andWhere('rr.name IN (:userRoles)') ->getDQL() @@ -149,7 +147,7 @@ public function configureQueryBuilder(QueryBuilder $qb, array $searches = [], ar break; default: - $this->setDefaults($qb, $filterName, $filterValue); + $this->setDefaults($qb, $filterName, $filterValue); } } diff --git a/src/plugin/open-badge/Finder/BadgeClassFinder.php b/src/plugin/open-badge/Finder/BadgeClassFinder.php index de697c6c4ba..9872ee30363 100644 --- a/src/plugin/open-badge/Finder/BadgeClassFinder.php +++ b/src/plugin/open-badge/Finder/BadgeClassFinder.php @@ -89,11 +89,9 @@ public function configureQueryBuilder(QueryBuilder $qb, array $searches = [], ar $subQb = $this->om->createQueryBuilder() ->select('ot') ->from('Claroline\CoreBundle\Entity\Tool\OrderedTool', 'ot') - ->leftJoin('ot.workspace', 'otw') ->join('ot.rights', 'r') ->join('r.role', 'rr') - ->where('ot.user IS NULL') - ->andWhere('((w.id IS NULL AND ot.workspace IS NULL) OR otw.id = w.id)') + ->where('(ot.contextId IS NULL OR ot.contextId = w.uuid)') ->andWhere('BIT_AND(r.mask, :grantMask) = :grantMask') ->andWhere('rr.name IN (:userRoles)') ->getDQL() diff --git a/src/plugin/open-badge/Installation/ClarolineOpenBadgeInstaller.php b/src/plugin/open-badge/Installation/ClarolineOpenBadgeInstaller.php index dd6c1d55e70..e5c445e3105 100644 --- a/src/plugin/open-badge/Installation/ClarolineOpenBadgeInstaller.php +++ b/src/plugin/open-badge/Installation/ClarolineOpenBadgeInstaller.php @@ -6,6 +6,11 @@ class ClarolineOpenBadgeInstaller extends AdditionalInstaller { + public function hasMigrations(): bool + { + return true; + } + public function hasFixtures(): bool { return true; diff --git a/src/plugin/open-badge/Resources/config/components.yml b/src/plugin/open-badge/Resources/config/components.yml new file mode 100644 index 00000000000..cc128a70a3d --- /dev/null +++ b/src/plugin/open-badge/Resources/config/components.yml @@ -0,0 +1,2 @@ +imports: + - { resource: components/tool.yml } diff --git a/src/plugin/open-badge/Resources/config/components/tool.yml b/src/plugin/open-badge/Resources/config/components/tool.yml new file mode 100644 index 00000000000..dd6cd3ece59 --- /dev/null +++ b/src/plugin/open-badge/Resources/config/components/tool.yml @@ -0,0 +1,9 @@ +services: + Claroline\OpenBadgeBundle\Component\Tool\BadgesTool: + parent: Claroline\AppBundle\Component\Tool\AbstractTool + tags: [ 'claroline.component.tool' ] + arguments: + - '@Claroline\AppBundle\Persistence\ObjectManager' + - '@Claroline\AppBundle\API\SerializerProvider' + - '@Claroline\AppBundle\API\Crud' + - '@Claroline\CoreBundle\Manager\FileManager' diff --git a/src/plugin/open-badge/Resources/config/services/subscriber.yml b/src/plugin/open-badge/Resources/config/services/subscriber.yml index 761e6000155..94aa466e206 100644 --- a/src/plugin/open-badge/Resources/config/services/subscriber.yml +++ b/src/plugin/open-badge/Resources/config/services/subscriber.yml @@ -13,13 +13,6 @@ services: - '@Claroline\AppBundle\Persistence\ObjectManager' - '@Claroline\AppBundle\API\Crud' - Claroline\OpenBadgeBundle\Subscriber\Tool\BadgesSubscriber: - arguments: - - '@Claroline\AppBundle\Persistence\ObjectManager' - - '@Claroline\AppBundle\API\SerializerProvider' - - '@Claroline\AppBundle\API\Crud' - - '@Claroline\CoreBundle\Manager\FileManager' - Claroline\OpenBadgeBundle\Subscriber\BadgeLogSubscriber: arguments: - '@translator' diff --git a/src/plugin/open-badge/Resources/modules/account/badges/index.js b/src/plugin/open-badge/Resources/modules/account/badges/index.js index 9757d37af6e..d07e97584d6 100644 --- a/src/plugin/open-badge/Resources/modules/account/badges/index.js +++ b/src/plugin/open-badge/Resources/modules/account/badges/index.js @@ -1,11 +1,9 @@ -import {trans} from '#/main/app/intl/translation' - import {BadgesMain} from '#/plugin/open-badge/account/badges/containers/main' export default { - name: 'badges', + /*name: 'badges', icon: 'fa fa-fw fa-trophy', - label: trans('my_badges', {}, 'badge'), + label: trans('my_badges', {}, 'badge'),*/ component: BadgesMain, styles: ['claroline-distribution-plugin-open-badge-badges-tool'] } diff --git a/src/plugin/open-badge/Subscriber/Tool/BadgesSubscriber.php b/src/plugin/open-badge/Subscriber/Tool/BadgesSubscriber.php deleted file mode 100644 index 77ceabb63f0..00000000000 --- a/src/plugin/open-badge/Subscriber/Tool/BadgesSubscriber.php +++ /dev/null @@ -1,127 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Claroline\OpenBadgeBundle\Subscriber\Tool; - -use Claroline\AppBundle\API\Crud; -use Claroline\AppBundle\API\Options; -use Claroline\AppBundle\API\SerializerProvider; -use Claroline\AppBundle\Persistence\ObjectManager; -use Claroline\CoreBundle\Entity\Tool\AbstractTool; -use Claroline\CoreBundle\Event\CatalogEvents\ToolEvents; -use Claroline\CoreBundle\Event\Tool\ExportToolEvent; -use Claroline\CoreBundle\Event\Tool\ImportToolEvent; -use Claroline\CoreBundle\Event\Tool\OpenToolEvent; -use Claroline\CoreBundle\Manager\FileManager; -use Claroline\OpenBadgeBundle\Entity\BadgeClass; -use Symfony\Component\EventDispatcher\EventSubscriberInterface; -use Symfony\Component\HttpFoundation\File\File; - -/** - * Badge tool. - */ -class BadgesSubscriber implements EventSubscriberInterface -{ - public const NAME = 'badges'; - - /** @var ObjectManager */ - private $om; - /** @var SerializerProvider */ - private $serializer; - /** @var Crud */ - private $crud; - /** @var FileManager */ - private $fileManager; - - public function __construct( - ObjectManager $om, - SerializerProvider $serializer, - Crud $crud, - FileManager $fileManager - ) { - $this->om = $om; - $this->serializer = $serializer; - $this->crud = $crud; - $this->fileManager = $fileManager; - } - - public static function getSubscribedEvents(): array - { - return [ - ToolEvents::getEventName(ToolEvents::OPEN, AbstractTool::DESKTOP, static::NAME) => 'onOpenDesktop', - ToolEvents::getEventName(ToolEvents::OPEN, AbstractTool::WORKSPACE, static::NAME) => 'onOpenWorkspace', - ToolEvents::getEventName(ToolEvents::EXPORT, AbstractTool::WORKSPACE, static::NAME) => 'onExportWorkspace', - ToolEvents::getEventName(ToolEvents::IMPORT, AbstractTool::WORKSPACE, static::NAME) => 'onImportWorkspace', - ]; - } - - public function onOpenDesktop(OpenToolEvent $event) - { - $event->setData([]); - - $event->stopPropagation(); - } - - public function onOpenWorkspace(OpenToolEvent $event) - { - $event->setData([]); - - $event->stopPropagation(); - } - - public function onExportWorkspace(ExportToolEvent $event) - { - $badges = $this->om->getRepository(BadgeClass::class)->findBy(['workspace' => $event->getWorkspace()]); - - $badgesData = []; - /** @var BadgeClass $badge */ - foreach ($badges as $badge) { - $badgesData[] = $this->serializer->serialize($badge); - - if (!empty($badge->getImage())) { - $event->addFile($badge->getUuid(), $badge->getImage()); - } - } - - $event->setData([ - 'badges' => $badgesData, - ]); - } - - public function onImportWorkspace(ImportToolEvent $event) - { - $data = $event->getData(); - if (empty($data['badges'])) { - return; - } - - $this->om->startFlushSuite(); - foreach ($data['badges'] as $badgeData) { - if (isset($badgeData['workspace'])) { - unset($badgeData['workspace']); - } - - $new = new BadgeClass(); - $new->setWorkspace($event->getWorkspace()); - - $badgeImage = $event->getFile($badgeData['id']); - if ($badgeImage && !$this->fileManager->exists($badgeImage)) { - $file = $this->fileManager->createFile(new File($badgeImage)); - $badgeData['image'] = $file->getUrl(); - } - - $this->crud->create($new, $badgeData, [Crud::NO_PERMISSIONS, Crud::NO_VALIDATION, Options::REFRESH_UUID]); - - $event->addCreatedEntity($badgeData['id'], $new); - } - $this->om->endFlushSuite(); - } -} diff --git a/src/plugin/path/Installation/InnovaPathInstaller.php b/src/plugin/path/Installation/InnovaPathInstaller.php index a872429cb50..00d3fa0686d 100644 --- a/src/plugin/path/Installation/InnovaPathInstaller.php +++ b/src/plugin/path/Installation/InnovaPathInstaller.php @@ -6,4 +6,8 @@ class InnovaPathInstaller extends AdditionalInstaller { + public function hasMigrations(): bool + { + return true; + } } diff --git a/src/plugin/rss/Installation/ClarolineRssInstaller.php b/src/plugin/rss/Installation/ClarolineRssInstaller.php index cc0ca375f2b..2a85f547bfe 100644 --- a/src/plugin/rss/Installation/ClarolineRssInstaller.php +++ b/src/plugin/rss/Installation/ClarolineRssInstaller.php @@ -6,4 +6,8 @@ class ClarolineRssInstaller extends AdditionalInstaller { + public function hasMigrations(): bool + { + return true; + } } diff --git a/src/plugin/scorm/Installation/ClarolineScormInstaller.php b/src/plugin/scorm/Installation/ClarolineScormInstaller.php index b1e9b8da96c..9cb40fcf65b 100644 --- a/src/plugin/scorm/Installation/ClarolineScormInstaller.php +++ b/src/plugin/scorm/Installation/ClarolineScormInstaller.php @@ -6,4 +6,8 @@ class ClarolineScormInstaller extends AdditionalInstaller { + public function hasMigrations(): bool + { + return true; + } } diff --git a/src/plugin/slideshow/Installation/ClarolineSlideshowInstaller.php b/src/plugin/slideshow/Installation/ClarolineSlideshowInstaller.php index 26c8ae26c00..5f1255402c8 100644 --- a/src/plugin/slideshow/Installation/ClarolineSlideshowInstaller.php +++ b/src/plugin/slideshow/Installation/ClarolineSlideshowInstaller.php @@ -6,4 +6,8 @@ class ClarolineSlideshowInstaller extends AdditionalInstaller { + public function hasMigrations(): bool + { + return true; + } } diff --git a/src/plugin/tag/Installation/ClarolineTagInstaller.php b/src/plugin/tag/Installation/ClarolineTagInstaller.php index 0070850fdb4..f2416af92b3 100644 --- a/src/plugin/tag/Installation/ClarolineTagInstaller.php +++ b/src/plugin/tag/Installation/ClarolineTagInstaller.php @@ -6,4 +6,8 @@ class ClarolineTagInstaller extends AdditionalInstaller { + public function hasMigrations(): bool + { + return true; + } } diff --git a/src/plugin/url/Installation/HeVinciUrlInstaller.php b/src/plugin/url/Installation/HeVinciUrlInstaller.php index ad1927081bf..0aa70d4457a 100644 --- a/src/plugin/url/Installation/HeVinciUrlInstaller.php +++ b/src/plugin/url/Installation/HeVinciUrlInstaller.php @@ -6,4 +6,8 @@ class HeVinciUrlInstaller extends AdditionalInstaller { + public function hasMigrations(): bool + { + return true; + } } diff --git a/src/plugin/video-player/Installation/ClarolineVideoPlayerInstaller.php b/src/plugin/video-player/Installation/ClarolineVideoPlayerInstaller.php index ed1804867af..827cbd90d19 100644 --- a/src/plugin/video-player/Installation/ClarolineVideoPlayerInstaller.php +++ b/src/plugin/video-player/Installation/ClarolineVideoPlayerInstaller.php @@ -6,8 +6,4 @@ class ClarolineVideoPlayerInstaller extends AdditionalInstaller { - public function hasMigrations(): bool - { - return false; - } } diff --git a/src/plugin/wiki/Installation/IcapWikiInstaller.php b/src/plugin/wiki/Installation/IcapWikiInstaller.php index fc973e32e97..37277ad25f4 100644 --- a/src/plugin/wiki/Installation/IcapWikiInstaller.php +++ b/src/plugin/wiki/Installation/IcapWikiInstaller.php @@ -6,4 +6,8 @@ class IcapWikiInstaller extends AdditionalInstaller { + public function hasMigrations(): bool + { + return true; + } }