See https://github.com/chamilo/chamilo-lms/pull/5045pull/5064/head
parent
770d043943
commit
3ebefc6ca9
@ -0,0 +1,17 @@ |
|||||||
|
<?php |
||||||
|
|
||||||
|
/* For licensing terms, see /license.txt */ |
||||||
|
|
||||||
|
declare(strict_types=1); |
||||||
|
|
||||||
|
namespace Chamilo\CoreBundle\ApiResource; |
||||||
|
|
||||||
|
use Symfony\Component\Serializer\Annotation\Groups; |
||||||
|
|
||||||
|
abstract class AbstractResource |
||||||
|
{ |
||||||
|
#[Groups([ |
||||||
|
'ctool:read', |
||||||
|
])] |
||||||
|
public ?string $illustrationUrl = null; |
||||||
|
} |
||||||
@ -0,0 +1,41 @@ |
|||||||
|
<?php |
||||||
|
|
||||||
|
/* For licensing terms, see /license.txt */ |
||||||
|
|
||||||
|
declare(strict_types=1); |
||||||
|
|
||||||
|
namespace Chamilo\CoreBundle\ApiResource; |
||||||
|
|
||||||
|
use Chamilo\CoreBundle\Entity\ResourceNode; |
||||||
|
use Chamilo\CoreBundle\Tool\AbstractTool; |
||||||
|
use Symfony\Component\Serializer\Annotation\Groups; |
||||||
|
|
||||||
|
class CourseTool extends AbstractResource |
||||||
|
{ |
||||||
|
#[Groups(['ctool:read'])] |
||||||
|
public ?int $iid = null; |
||||||
|
|
||||||
|
#[Groups(['ctool:read'])] |
||||||
|
public string $name; |
||||||
|
|
||||||
|
#[Groups(['ctool:read'])] |
||||||
|
public ?bool $visibility = null; |
||||||
|
|
||||||
|
#[Groups(['ctool:read'])] |
||||||
|
public AbstractTool $tool; |
||||||
|
|
||||||
|
#[Groups(['ctool:read'])] |
||||||
|
public ?ResourceNode $resourceNode = null; |
||||||
|
|
||||||
|
#[Groups(['ctool:read'])] |
||||||
|
public string $url; |
||||||
|
|
||||||
|
#[Groups(['ctool:read'])] |
||||||
|
public string $category = ''; |
||||||
|
|
||||||
|
#[Groups(['ctool:read'])] |
||||||
|
public function getNameToTranslate(): string |
||||||
|
{ |
||||||
|
return ucfirst(str_replace('_', ' ', $this->name)); |
||||||
|
} |
||||||
|
} |
||||||
@ -0,0 +1,46 @@ |
|||||||
|
<?php |
||||||
|
|
||||||
|
/* For licensing terms, see /license.txt */ |
||||||
|
|
||||||
|
declare(strict_types=1); |
||||||
|
|
||||||
|
namespace Chamilo\CoreBundle\DataProvider\Extension; |
||||||
|
|
||||||
|
use ApiPlatform\Doctrine\Orm\Extension\QueryCollectionExtensionInterface; |
||||||
|
use ApiPlatform\Doctrine\Orm\Util\QueryNameGeneratorInterface; |
||||||
|
use ApiPlatform\Metadata\Operation; |
||||||
|
use Chamilo\CoreBundle\Entity\ResourceLink; |
||||||
|
use Chamilo\CoreBundle\Traits\ControllerTrait; |
||||||
|
use Chamilo\CoreBundle\Traits\CourseControllerTrait; |
||||||
|
use Chamilo\CourseBundle\Entity\CTool; |
||||||
|
use Doctrine\ORM\QueryBuilder; |
||||||
|
|
||||||
|
class CToolExtension implements QueryCollectionExtensionInterface |
||||||
|
{ |
||||||
|
use ControllerTrait; |
||||||
|
use CourseControllerTrait; |
||||||
|
|
||||||
|
public function applyToCollection( |
||||||
|
QueryBuilder $queryBuilder, |
||||||
|
QueryNameGeneratorInterface $queryNameGenerator, |
||||||
|
string $resourceClass, |
||||||
|
Operation $operation = null, |
||||||
|
array $context = [] |
||||||
|
): void { |
||||||
|
if (CTool::class !== $resourceClass) { |
||||||
|
return; |
||||||
|
} |
||||||
|
|
||||||
|
$alias = $queryBuilder->getRootAliases()[0]; |
||||||
|
|
||||||
|
$queryBuilder |
||||||
|
->innerJoin("$alias.resourceNode", 'resource_node') |
||||||
|
->innerJoin('resource_node.resourceLinks', 'resource_links') |
||||||
|
->andWhere( |
||||||
|
$queryBuilder->expr()->notIn("$alias.name", ['course_tool', 'course_homepage']) |
||||||
|
) |
||||||
|
->andWhere('resource_links.visibility != :visibility_deleted') |
||||||
|
->setParameter('visibility_deleted', ResourceLink::VISIBILITY_DELETED) |
||||||
|
; |
||||||
|
} |
||||||
|
} |
||||||
@ -0,0 +1,74 @@ |
|||||||
|
<?php |
||||||
|
|
||||||
|
/* For licensing terms, see /license.txt */ |
||||||
|
|
||||||
|
declare(strict_types=1); |
||||||
|
|
||||||
|
namespace Chamilo\CoreBundle\DataTransformer; |
||||||
|
|
||||||
|
use ApiPlatform\Core\DataTransformer\DataTransformerInterface; |
||||||
|
use Chamilo\CoreBundle\ApiResource\CourseTool; |
||||||
|
use Chamilo\CoreBundle\Entity\Course; |
||||||
|
use Chamilo\CoreBundle\Tool\AbstractTool; |
||||||
|
use Chamilo\CoreBundle\Tool\ToolChain; |
||||||
|
use Chamilo\CoreBundle\Traits\CourseFromRequestTrait; |
||||||
|
use Chamilo\CourseBundle\Entity\CTool; |
||||||
|
use Doctrine\ORM\EntityManagerInterface; |
||||||
|
use Symfony\Component\HttpFoundation\RequestStack; |
||||||
|
|
||||||
|
class CourseToolDataTranformer implements DataTransformerInterface |
||||||
|
{ |
||||||
|
use CourseFromRequestTrait; |
||||||
|
|
||||||
|
public function __construct( |
||||||
|
protected RequestStack $requestStack, |
||||||
|
protected EntityManagerInterface $entityManager, |
||||||
|
protected readonly ToolChain $toolChain, |
||||||
|
) {} |
||||||
|
|
||||||
|
public function transform($object, string $to, array $context = []) |
||||||
|
{ |
||||||
|
\assert($object instanceof CTool); |
||||||
|
|
||||||
|
$tool = $object->getTool(); |
||||||
|
|
||||||
|
$toolModel = $this->toolChain->getToolFromName( |
||||||
|
$tool->getName() |
||||||
|
); |
||||||
|
|
||||||
|
$course = $this->getCourse(); |
||||||
|
|
||||||
|
$cTool = new CourseTool(); |
||||||
|
$cTool->iid = $object->getIid(); |
||||||
|
$cTool->name = $object->getName(); |
||||||
|
$cTool->visibility = $object->getVisibility(); |
||||||
|
$cTool->resourceNode = $object->resourceNode; |
||||||
|
$cTool->illustrationUrl = $object->illustrationUrl; |
||||||
|
$cTool->url = $this->generateToolUrl($toolModel, $course); |
||||||
|
$cTool->tool = $toolModel; |
||||||
|
|
||||||
|
return $cTool; |
||||||
|
} |
||||||
|
|
||||||
|
private function generateToolUrl(AbstractTool $tool, Course $course): string |
||||||
|
{ |
||||||
|
$link = $tool->getLink(); |
||||||
|
|
||||||
|
if (strpos($link, 'nodeId')) { |
||||||
|
$nodeId = (string) $course->getResourceNode()->getId(); |
||||||
|
$link = str_replace(':nodeId', $nodeId, $link); |
||||||
|
} |
||||||
|
|
||||||
|
return $link.'?' |
||||||
|
.http_build_query([ |
||||||
|
'cid' => $this->getCourse()->getId(), |
||||||
|
'sid' => $this->getSession()?->getId(), |
||||||
|
'gid' => 0, |
||||||
|
]); |
||||||
|
} |
||||||
|
|
||||||
|
public function supportsTransformation($data, string $to, array $context = []): bool |
||||||
|
{ |
||||||
|
return $data instanceof CTool && CourseTool::class === $to; |
||||||
|
} |
||||||
|
} |
||||||
@ -0,0 +1,69 @@ |
|||||||
|
<?php |
||||||
|
|
||||||
|
/* For licensing terms, see /license.txt */ |
||||||
|
|
||||||
|
declare(strict_types=1); |
||||||
|
|
||||||
|
namespace Chamilo\CoreBundle\Filter; |
||||||
|
|
||||||
|
use ApiPlatform\Doctrine\Orm\Filter\AbstractFilter; |
||||||
|
use ApiPlatform\Doctrine\Orm\Util\QueryNameGeneratorInterface; |
||||||
|
use ApiPlatform\Metadata\Operation; |
||||||
|
use Chamilo\CoreBundle\Traits\CourseFromRequestTrait; |
||||||
|
use Doctrine\ORM\EntityManagerInterface; |
||||||
|
use Doctrine\ORM\QueryBuilder; |
||||||
|
use Doctrine\Persistence\ManagerRegistry; |
||||||
|
use Psr\Log\LoggerInterface; |
||||||
|
use Symfony\Component\HttpFoundation\RequestStack; |
||||||
|
use Symfony\Component\Serializer\NameConverter\NameConverterInterface; |
||||||
|
|
||||||
|
class CidFilter extends AbstractFilter |
||||||
|
{ |
||||||
|
use CourseFromRequestTrait; |
||||||
|
|
||||||
|
public function __construct( |
||||||
|
protected RequestStack $requestStack, |
||||||
|
protected EntityManagerInterface $entityManager, |
||||||
|
ManagerRegistry $managerRegistry, |
||||||
|
LoggerInterface $logger = null, |
||||||
|
array $properties = null, |
||||||
|
NameConverterInterface $nameConverter = null, |
||||||
|
) { |
||||||
|
parent::__construct($managerRegistry, $logger, $properties, $nameConverter); |
||||||
|
} |
||||||
|
|
||||||
|
public function getDescription(string $resourceClass): array |
||||||
|
{ |
||||||
|
return [ |
||||||
|
'cid' => [ |
||||||
|
'property' => null, |
||||||
|
'type' => 'int', |
||||||
|
'required' => true, |
||||||
|
'description' => 'Course identifier', |
||||||
|
], |
||||||
|
]; |
||||||
|
} |
||||||
|
|
||||||
|
protected function filterProperty( |
||||||
|
string $property, |
||||||
|
$value, |
||||||
|
QueryBuilder $queryBuilder, |
||||||
|
QueryNameGeneratorInterface $queryNameGenerator, |
||||||
|
string $resourceClass, |
||||||
|
Operation $operation = null, |
||||||
|
array $context = [] |
||||||
|
): void { |
||||||
|
if ('cid' !== $property) { |
||||||
|
return; |
||||||
|
} |
||||||
|
|
||||||
|
$course = $this->getCourse(); |
||||||
|
|
||||||
|
$queryBuilder |
||||||
|
->andWhere( |
||||||
|
$queryBuilder->expr()->eq('resource_links.course', ':course') |
||||||
|
) |
||||||
|
->setParameter('course', $course->getId()) |
||||||
|
; |
||||||
|
} |
||||||
|
} |
||||||
@ -0,0 +1,105 @@ |
|||||||
|
<?php |
||||||
|
|
||||||
|
/* For licensing terms, see /license.txt */ |
||||||
|
|
||||||
|
declare(strict_types=1); |
||||||
|
|
||||||
|
namespace Chamilo\CoreBundle\Filter; |
||||||
|
|
||||||
|
use ApiPlatform\Doctrine\Orm\Filter\AbstractFilter; |
||||||
|
use ApiPlatform\Doctrine\Orm\Util\QueryNameGeneratorInterface; |
||||||
|
use ApiPlatform\Metadata\Operation; |
||||||
|
use Chamilo\CoreBundle\Entity\ResourceShowCourseResourcesInSessionInterface; |
||||||
|
use Chamilo\CoreBundle\Traits\CourseFromRequestTrait; |
||||||
|
use Doctrine\ORM\EntityManagerInterface; |
||||||
|
use Doctrine\ORM\QueryBuilder; |
||||||
|
use Doctrine\Persistence\ManagerRegistry; |
||||||
|
use Psr\Log\LoggerInterface; |
||||||
|
use ReflectionClass; |
||||||
|
use ReflectionException; |
||||||
|
use Symfony\Component\HttpFoundation\RequestStack; |
||||||
|
use Symfony\Component\Serializer\NameConverter\NameConverterInterface; |
||||||
|
|
||||||
|
class SidFilter extends AbstractFilter |
||||||
|
{ |
||||||
|
use CourseFromRequestTrait; |
||||||
|
|
||||||
|
public function __construct( |
||||||
|
protected RequestStack $requestStack, |
||||||
|
protected EntityManagerInterface $entityManager, |
||||||
|
ManagerRegistry $managerRegistry, |
||||||
|
LoggerInterface $logger = null, |
||||||
|
array $properties = null, |
||||||
|
NameConverterInterface $nameConverter = null |
||||||
|
) { |
||||||
|
parent::__construct($managerRegistry, $logger, $properties, $nameConverter); |
||||||
|
} |
||||||
|
|
||||||
|
public function getDescription(string $resourceClass): array |
||||||
|
{ |
||||||
|
return [ |
||||||
|
'sid' => [ |
||||||
|
'property' => null, |
||||||
|
'type' => 'string', |
||||||
|
'required' => false, |
||||||
|
'description' => 'Course identifier', |
||||||
|
], |
||||||
|
]; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* @param mixed $value |
||||||
|
* |
||||||
|
* @throws ReflectionException |
||||||
|
*/ |
||||||
|
protected function filterProperty( |
||||||
|
string $property, |
||||||
|
$value, |
||||||
|
QueryBuilder $queryBuilder, |
||||||
|
QueryNameGeneratorInterface $queryNameGenerator, |
||||||
|
string $resourceClass, |
||||||
|
Operation $operation = null, |
||||||
|
array $context = [] |
||||||
|
): void { |
||||||
|
if ('sid' !== $property) { |
||||||
|
return; |
||||||
|
} |
||||||
|
|
||||||
|
$reflection = new ReflectionClass($resourceClass); |
||||||
|
|
||||||
|
$loadBaseSessionContent = \in_array( |
||||||
|
ResourceShowCourseResourcesInSessionInterface::class, |
||||||
|
$reflection->getInterfaceNames(), |
||||||
|
true |
||||||
|
); |
||||||
|
|
||||||
|
// Session was set with a kernel request from CoreBundle\EventListener\CourseListener class |
||||||
|
$session = $this->getSession(); |
||||||
|
|
||||||
|
if (null === $session) { |
||||||
|
$queryBuilder->andWhere( |
||||||
|
$queryBuilder->expr()->orX( |
||||||
|
$queryBuilder->expr()->isNull('resource_links.session'), |
||||||
|
$queryBuilder->expr()->eq('resource_links.session', 0) |
||||||
|
) |
||||||
|
); |
||||||
|
} elseif ($loadBaseSessionContent) { |
||||||
|
$queryBuilder |
||||||
|
->andWhere( |
||||||
|
$queryBuilder->expr()->orX( |
||||||
|
$queryBuilder->expr()->eq('resource_links.session', ':session'), |
||||||
|
$queryBuilder->expr()->isNull('resource_links.session') |
||||||
|
) |
||||||
|
) |
||||||
|
->setParameter('session', $session?->getId()) |
||||||
|
; |
||||||
|
} else { |
||||||
|
$queryBuilder |
||||||
|
->andWhere( |
||||||
|
$queryBuilder->expr()->eq('resource_links.session', ':session') |
||||||
|
) |
||||||
|
->setParameter('session', $session?->getId()) |
||||||
|
; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
@ -0,0 +1,101 @@ |
|||||||
|
<?php |
||||||
|
|
||||||
|
/* For licensing terms, see /license.txt */ |
||||||
|
|
||||||
|
declare(strict_types=1); |
||||||
|
|
||||||
|
namespace Chamilo\CoreBundle\State; |
||||||
|
|
||||||
|
use ApiPlatform\Doctrine\Orm\State\CollectionProvider; |
||||||
|
use ApiPlatform\Metadata\Operation; |
||||||
|
use ApiPlatform\State\Pagination\PartialPaginatorInterface; |
||||||
|
use ApiPlatform\State\ProviderInterface; |
||||||
|
use Chamilo\CoreBundle\Entity\ResourceLink; |
||||||
|
use Chamilo\CoreBundle\Entity\User; |
||||||
|
use Chamilo\CoreBundle\Settings\SettingsManager; |
||||||
|
use Chamilo\CoreBundle\Tool\ToolChain; |
||||||
|
use Chamilo\CoreBundle\Traits\CourseFromRequestTrait; |
||||||
|
use Chamilo\CourseBundle\Entity\CTool; |
||||||
|
use Doctrine\ORM\EntityManagerInterface; |
||||||
|
use Symfony\Component\HttpFoundation\RequestStack; |
||||||
|
use Symfony\Component\Security\Core\Security; |
||||||
|
|
||||||
|
/** |
||||||
|
* @template-implements ProviderInterface<CTool> |
||||||
|
*/ |
||||||
|
class CToolProvider implements ProviderInterface |
||||||
|
{ |
||||||
|
use CourseFromRequestTrait; |
||||||
|
|
||||||
|
public function __construct( |
||||||
|
private readonly CollectionProvider $provider, |
||||||
|
protected EntityManagerInterface $entityManager, |
||||||
|
private readonly SettingsManager $settingsManager, |
||||||
|
private readonly Security $security, |
||||||
|
private readonly ToolChain $toolChain, |
||||||
|
protected RequestStack $requestStack, |
||||||
|
) {} |
||||||
|
|
||||||
|
public function provide(Operation $operation, array $uriVariables = [], array $context = []): array |
||||||
|
{ |
||||||
|
/** @var PartialPaginatorInterface $result */ |
||||||
|
$result = $this->provider->provide($operation, $uriVariables, $context); |
||||||
|
|
||||||
|
$request = $this->requestStack->getMainRequest(); |
||||||
|
|
||||||
|
$studentView = $request ? $request->getSession()->get('studentview') : 'studentview'; |
||||||
|
|
||||||
|
/** @var User|null $user */ |
||||||
|
$user = $this->security->getUser(); |
||||||
|
|
||||||
|
$isAllowToEdit = $user && ($user->hasRole('ROLE_ADMIN') || $user->hasRole('ROLE_CURRENT_COURSE_TEACHER')); |
||||||
|
$isAllowToEditBack = $user && ($user->hasRole('ROLE_ADMIN') || $user->hasRole('ROLE_CURRENT_COURSE_TEACHER')); |
||||||
|
$isAllowToSessionEdit = $user && ($user->hasRole('ROLE_ADMIN') || $user->hasRole('ROLE_CURRENT_COURSE_TEACHER') || $user->hasRole('ROLE_CURRENT_COURSE_SESSION_TEACHER')); |
||||||
|
|
||||||
|
$allowVisibilityInSession = $this->settingsManager->getSetting('course.allow_edit_tool_visibility_in_session'); |
||||||
|
$session = $this->getSession(); |
||||||
|
|
||||||
|
$results = []; |
||||||
|
|
||||||
|
/** @var CTool $cTool */ |
||||||
|
foreach ($result as $cTool) { |
||||||
|
$toolModel = $this->toolChain->getToolFromName( |
||||||
|
$cTool->getTool()->getName() |
||||||
|
); |
||||||
|
|
||||||
|
if (!$isAllowToEdit && 'admin' === $toolModel->getCategory()) { |
||||||
|
continue; |
||||||
|
} |
||||||
|
|
||||||
|
$resourceLinks = $cTool->getResourceNode()->getResourceLinks(); |
||||||
|
|
||||||
|
if ($session && $allowVisibilityInSession) { |
||||||
|
$sessionLink = $resourceLinks->findFirst( |
||||||
|
fn (int $key, ResourceLink $resourceLink): bool => $resourceLink->getSession()?->getId() === $session->getId() |
||||||
|
); |
||||||
|
|
||||||
|
if ($sessionLink) { |
||||||
|
// Set the session link as unique to include in repsonse |
||||||
|
$resourceLinks->clear(); |
||||||
|
$resourceLinks->add($sessionLink); |
||||||
|
|
||||||
|
$isAllowToEdit = $isAllowToSessionEdit; |
||||||
|
} else { |
||||||
|
$isAllowToEdit = $isAllowToEditBack; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
if (!$isAllowToEdit || 'studentview' === $studentView) { |
||||||
|
$notPublishedLink = ResourceLink::VISIBILITY_PUBLISHED !== $resourceLinks->first()->getVisibility(); |
||||||
|
|
||||||
|
if ($notPublishedLink) { |
||||||
|
continue; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
$results[] = $cTool; |
||||||
|
} |
||||||
|
|
||||||
|
return $results; |
||||||
|
} |
||||||
|
} |
||||||
@ -0,0 +1,54 @@ |
|||||||
|
<?php |
||||||
|
|
||||||
|
declare(strict_types=1); |
||||||
|
|
||||||
|
/* For licensing terms, see /license.txt */ |
||||||
|
|
||||||
|
namespace Chamilo\CoreBundle\Traits; |
||||||
|
|
||||||
|
use Chamilo\CoreBundle\Entity\Course; |
||||||
|
use Chamilo\CoreBundle\Entity\Session; |
||||||
|
use Doctrine\ORM\EntityManagerInterface; |
||||||
|
use Symfony\Component\HttpFoundation\Request; |
||||||
|
use Symfony\Component\HttpFoundation\RequestStack; |
||||||
|
|
||||||
|
trait CourseFromRequestTrait |
||||||
|
{ |
||||||
|
protected RequestStack $requestStack; |
||||||
|
protected EntityManagerInterface $entityManager; |
||||||
|
|
||||||
|
public function getRequest(): ?Request |
||||||
|
{ |
||||||
|
return $this->requestStack->getMainRequest(); |
||||||
|
} |
||||||
|
|
||||||
|
public function getCourse(): ?Course |
||||||
|
{ |
||||||
|
$request = $this->getRequest(); |
||||||
|
|
||||||
|
if ($request) { |
||||||
|
$courseId = $request->getSession()->get('cid', 0); |
||||||
|
} |
||||||
|
|
||||||
|
if (empty($courseId)) { |
||||||
|
return null; |
||||||
|
} |
||||||
|
|
||||||
|
return $this->entityManager->find(Course::class, $courseId); |
||||||
|
} |
||||||
|
|
||||||
|
public function getSession(): ?Session |
||||||
|
{ |
||||||
|
$request = $this->getRequest(); |
||||||
|
|
||||||
|
if ($request) { |
||||||
|
$sessionId = $request->getSession()->get('sid', 0); |
||||||
|
} |
||||||
|
|
||||||
|
if (empty($sessionId)) { |
||||||
|
return null; |
||||||
|
} |
||||||
|
|
||||||
|
return $this->entityManager->find(Session::class, $sessionId); |
||||||
|
} |
||||||
|
} |
||||||
Loading…
Reference in new issue