Chamilo is a learning management system focused on ease of use and accessibility
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 
chamilo-lms/src/CoreBundle/Controller/ResourceController.php

1195 lines
40 KiB

<?php
/* For licensing terms, see /license.txt */
namespace Chamilo\CoreBundle\Controller;
use APY\DataGridBundle\Grid\Action\MassAction;
use APY\DataGridBundle\Grid\Action\RowAction;
use APY\DataGridBundle\Grid\Export\CSVExport;
use APY\DataGridBundle\Grid\Export\ExcelExport;
use APY\DataGridBundle\Grid\Grid;
use APY\DataGridBundle\Grid\Row;
use APY\DataGridBundle\Grid\Source\Entity;
use Chamilo\CoreBundle\Component\Utils\Glide;
use Chamilo\CoreBundle\Entity\Resource\AbstractResource;
use Chamilo\CoreBundle\Entity\Resource\ResourceLink;
use Chamilo\CoreBundle\Entity\Resource\ResourceNode;
use Chamilo\CoreBundle\Security\Authorization\Voter\ResourceNodeVoter;
use Chamilo\CourseBundle\Controller\CourseControllerInterface;
use Chamilo\CourseBundle\Controller\CourseControllerTrait;
use Chamilo\UserBundle\Entity\User;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Criteria;
use Doctrine\ORM\QueryBuilder;
use FOS\CKEditorBundle\Form\Type\CKEditorType;
use Symfony\Component\Filesystem\Exception\FileNotFoundException;
use Symfony\Component\HttpFoundation\File\UploadedFile;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\ResponseHeaderBag;
use Symfony\Component\HttpFoundation\StreamedResponse;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Routing\Router;
use Vich\UploaderBundle\Util\Transliterator;
use ZipStream\Option\Archive;
use ZipStream\ZipStream;
/**
* Class ResourceController.
* @todo improve/refactor $this->denyAccessUnlessGranted
* @Route("/resources")
*
* @author Julio Montoya <gugli100@gmail.com>.
*/
class ResourceController extends AbstractResourceController implements CourseControllerInterface
{
use CourseControllerTrait;
/**
* @Route("/{tool}/{type}", name="chamilo_core_resource_index")
*
* Example: /document/files (See the 'tool' and the 'resource_type' DB tables.)
* For the tool value check the Tool entity.
* For the type value check the ResourceType entity.
*/
public function indexAction(Request $request, Grid $grid): Response
{
$tool = $request->get('tool');
$type = $request->get('type');
$repository = $this->getRepositoryFromRequest($request);
$entityName = $repository->getResourceType()->getEntityName();
$parentResource = $this->getCourse();
if (null === $parentResource) {
/** @var User $user */
$parentResource = $this->getUser();
}
$grid = $this->getGrid($request, $grid, $parentResource->getResourceNode()->getId());
$breadcrumb = $this->getBreadCrumb();
$breadcrumb->addChild(
$this->trans($tool),
[
'uri' => '#',
]
);
// The base resource node is the course.
$id = $this->getCourse()->getResourceNode()->getId();
return $grid->getGridResponse(
'@ChamiloTheme/Resource/index.html.twig',
['tool' => $tool, 'type' => $type, 'id' => $id]
);
}
/**
* @Route("/{tool}/{type}/{id}/list", name="chamilo_core_resource_list")
*
* If node has children show it
*/
public function listAction(Request $request, Grid $grid): Response
{
$tool = $request->get('tool');
$type = $request->get('type');
$resourceNodeId = $request->get('id');
$grid = $this->getGrid($request, $grid, $resourceNodeId);
$this->setBreadCrumb($request);
return $grid->getGridResponse(
'@ChamiloTheme/Resource/index.html.twig',
['parent_id' => $resourceNodeId, 'tool' => $tool, 'type' => $type, 'id' => $resourceNodeId]
);
}
public function getGrid(Request $request, Grid $grid, $resourceNodeId): Grid
{
$tool = $request->get('tool');
$type = $request->get('type');
$id = (int) $request->get('id');
$repository = $this->getRepositoryFromRequest($request);
$class = $repository->getRepository()->getClassName();
// The group 'resource' is set in the @GRID\Source annotation in the entity.
$source = new Entity($class, 'resource');
$course = $this->getCourse();
$session = $this->getSession();
$parentNode = $repository->getResourceNodeRepository()->find($resourceNodeId);
$this->denyAccessUnlessGranted(
ResourceNodeVoter::VIEW,
$parentNode,
$this->trans('Unauthorised access to resource')
);
$qb = $repository->getResourcesByCourse($course, $session, null, $parentNode);
// 3. Set QueryBuilder to the source.
$source->initQueryBuilder($qb);
$grid->setSource($source);
$courseParams = $this->getCourseParams();
$params = $courseParams;
$params['tool'] = $tool;
$params['type'] = $type;
$params['id'] = $id;
$grid->setRouteUrl($this->generateUrl('chamilo_core_resource_list', $params));
//$grid->hideFilters();
//$grid->setLimits(20);
//$grid->isReadyForRedirect();
//$grid->setMaxResults(1);
//$grid->setLimits(2);
//$grid->setColumns($columns);
$routeParams = $courseParams;
$routeParams['tool'] = $tool;
$routeParams['type'] = $type;
$routeParams['id'] = null;
$titleColumn = $repository->getTitleColumn($grid);
$titleColumn->setSafe(false); // allows links in the title
// Title link.
$titleColumn->setTitle($this->trans('Name'));
//$repository->formatGrid();
/*if ($grid->hasColumn('filetype')) {
$grid->getColumn('filetype')->setTitle($this->trans('Type'));
}*/
$titleColumn->manipulateRenderCell(
function ($value, Row $row, $router) use ($routeParams) {
/** @var Router $router */
/** @var AbstractResource $entity */
$entity = $row->getEntity();
$resourceNode = $entity->getResourceNode();
$id = $resourceNode->getId();
$myParams = $routeParams;
$myParams['id'] = $id;
unset($myParams[0]);
$icon = $resourceNode->getIcon().' &nbsp;';
if ($resourceNode->hasResourceFile()) {
/*$url = $router->generate(
'chamilo_core_resource_show',
$myParams
);*/
if ($resourceNode->isResourceFileAnImage()) {
$url = $router->generate(
'chamilo_core_resource_view',
$myParams
);
return $icon.'<a data-fancybox="gallery" href="'.$url.'">'.$value.'</a>';
}
if ($resourceNode->isResourceFileAVideo()) {
$url = $router->generate(
'chamilo_core_resource_view',
$myParams
);
return '
<video width="640" height="320" controls id="video'.$id.'" controls preload="metadata" style="display:none;">
<source src="'.$url.'" type="video/mp4">
Your browser doesn\'t support HTML5 video tag.
</video>
'.$icon.' <a data-fancybox="gallery" data-width="640" data-height="360" href="#video'.$id.'">'.$value.'</a>';
}
$url = $router->generate(
'chamilo_core_resource_preview',
$myParams
);
return $icon.'<a data-fancybox="gallery" data-type="iframe" data-src="'.$url.'" href="javascript:;" >'.$value.'</a>';
} else {
$url = $router->generate(
'chamilo_core_resource_list',
$myParams
);
return $icon.'<a href="'.$url.'">'.$value.'</a>';
}
}
);
if ($grid->hasColumn('filetype')) {
$grid->getColumn('filetype')->manipulateRenderCell(
function ($value, Row $row, $router) use ($routeParams) {
/** @var AbstractResource $entity */
$entity = $row->getEntity();
$resourceNode = $entity->getResourceNode();
if ($resourceNode->hasResourceFile()) {
$file = $resourceNode->getResourceFile();
return $file->getMimeType();
}
return $this->trans('Folder');
}
);
}
if ($grid->hasColumn('iid')) {
$grid->setHiddenColumns(['iid']);
}
// Delete mass action.
if ($this->isGranted(ResourceNodeVoter::DELETE, $this->getCourse())) {
$deleteMassAction = new MassAction(
'Delete',
'ChamiloCoreBundle:Resource:deleteMass',
true,
$routeParams
);
$grid->addMassAction($deleteMassAction);
}
// Info action.
$myRowAction = new RowAction(
$this->trans('Info'),
'chamilo_core_resource_info',
false,
'_self',
[
'class' => 'btn btn-secondary info_action',
'icon' => 'fa-info-circle',
'iframe' => false,
]
);
$setNodeParameters = function (RowAction $action, Row $row) use ($routeParams) {
$id = $row->getEntity()->getResourceNode()->getId();
$routeParams['id'] = $id;
$action->setRouteParameters($routeParams);
$attributes = $action->getAttributes();
$attributes['data-action'] = $action->getRoute();
$attributes['data-action-id'] = $action->getRoute().'_'.$id;
$attributes['data-node-id'] = $id;
$action->setAttributes($attributes);
return $action;
};
$myRowAction->addManipulateRender($setNodeParameters);
$grid->addRowAction($myRowAction);
// Download action
$myRowAction = new RowAction(
$this->trans('Download'),
'chamilo_core_resource_download',
false,
'_self',
[
'class' => 'btn btn-secondary download_action',
'icon' => 'fa-download',
]
);
$setNodeParameters = function (RowAction $action, Row $row) use ($routeParams) {
$id = $row->getEntity()->getResourceNode()->getId();
$routeParams['id'] = $id;
$action->setRouteParameters($routeParams);
$attributes = $action->getAttributes();
//$attributes['data-action'] = $action->getRoute();
//$attributes['data-action-id'] = $action->getRoute().'_'.$id;
//$attributes['data-node-id'] = $id;
$action->setAttributes($attributes);
return $action;
};
$myRowAction->addManipulateRender($setNodeParameters);
$grid->addRowAction($myRowAction);
if ($this->isGranted(ResourceNodeVoter::EDIT, $this->getCourse())) {
// Enable/Disable
$myRowAction = new RowAction(
'',
'chamilo_core_resource_change_visibility',
false,
'_self'
);
$setVisibleParameters = function (RowAction $action, Row $row) use ($routeParams) {
/** @var AbstractResource $resource */
$resource = $row->getEntity();
$id = $resource->getResourceNode()->getId();
$icon = 'fa-eye-slash';
$link = $resource->getCourseSessionResourceLink($this->getCourse(), $this->getSession());
if ($link === null) {
return null;
}
if ($link->getVisibility() === ResourceLink::VISIBILITY_PUBLISHED) {
$icon = 'fa-eye';
}
$routeParams['id'] = $id;
$action->setRouteParameters($routeParams);
$attributes = [
'class' => 'btn btn-secondary change_visibility',
'data-id' => $id,
'icon' => $icon,
];
$action->setAttributes($attributes);
return $action;
};
$myRowAction->addManipulateRender($setVisibleParameters);
$grid->addRowAction($myRowAction);
// Edit action.
$myRowAction = new RowAction(
$this->trans('Edit'),
'chamilo_core_resource_edit',
false,
'_self',
['class' => 'btn btn-secondary', 'icon' => 'fa fa-pen']
);
$myRowAction->addManipulateRender($setNodeParameters);
$grid->addRowAction($myRowAction);
// More action.
$myRowAction = new RowAction(
$this->trans('More'),
'chamilo_core_resource_preview',
false,
'_self',
['class' => 'btn btn-secondary edit_resource', 'icon' => 'fa fa-ellipsis-h']
);
$myRowAction->addManipulateRender($setNodeParameters);
$grid->addRowAction($myRowAction);
// Delete action.
$myRowAction = new RowAction(
$this->trans('Delete'),
'chamilo_core_resource_delete',
true,
'_self',
['class' => 'btn btn-danger', 'data_hidden' => true]
);
$myRowAction->addManipulateRender($setNodeParameters);
$grid->addRowAction($myRowAction);
}
/*$grid->addExport(new CSVExport($this->trans('CSV export'), 'export', ['course' => $courseIdentifier]));
$grid->addExport(
new ExcelExport(
$this->trans('Excel export'),
'export',
['course' => $courseIdentifier]
)
);*/
return $grid;
}
/**
* @Route("/{tool}/{type}/{id}/new_folder", methods={"GET", "POST"}, name="chamilo_core_resource_new_folder")
*/
public function newFolderAction(Request $request): Response
{
$this->setBreadCrumb($request);
return $this->createResource($request, 'folder');
}
/**
* @Route("/{tool}/{type}/{id}/new", methods={"GET", "POST"}, name="chamilo_core_resource_new")
*/
public function newAction(Request $request): Response
{
$this->setBreadCrumb($request);
return $this->createResource($request, 'file');
}
/**
* @Route("/{tool}/{type}/{id}/edit", methods={"GET", "POST"})
*/
public function editAction(Request $request): Response
{
$tool = $request->get('tool');
$type = $request->get('type');
$resourceNodeId = $request->get('id');
$this->setBreadCrumb($request);
$repository = $this->getRepositoryFromRequest($request);
/** @var AbstractResource $resource */
$resource = $repository->getRepository()->findOneBy(['resourceNode' => $resourceNodeId]);
$resourceNode = $resource->getResourceNode();
$this->denyAccessUnlessGranted(
ResourceNodeVoter::EDIT,
$resourceNode,
$this->trans('Unauthorised access to resource')
);
$resourceNodeParentId = $resourceNode->getId();
$routeParams = $this->getCourseParams();
$routeParams['tool'] = $tool;
$routeParams['type'] = $type;
$routeParams['id'] = $resourceNodeParentId;
$form = $repository->getForm($this->container->get('form.factory'), $resource);
if ($resourceNode->hasEditableContent()) {
$form->add(
'content',
CKEditorType::class,
[
'mapped' => false,
'config' => [
'filebrowserImageBrowseRoute' => 'resources_filemanager',
'filebrowserImageBrowseRouteParameters' => $routeParams,
],
]
);
$content = $repository->getResourceNodeFileContent($resourceNode);
$form->get('content')->setData($content);
}
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
/** @var AbstractResource $newResource */
$newResource = $form->getData();
if ($form->has('content')) {
$data = $form->get('content')->getData();
$repository->updateResourceFileContent($newResource, $data);
}
//$newResource->setTitle($form->get('title')->getData()); // already set in $form->getData()
$repository->updateNodeForResource($newResource);
$this->addFlash('success', $this->trans('Updated'));
if ($newResource->getResourceNode()->hasResourceFile()) {
//$resourceNodeParentId = $newResource->getResourceNode()->getParent()->getId();
}
return $this->redirectToRoute('chamilo_core_resource_list', $routeParams);
}
return $this->render(
'@ChamiloTheme/Resource/edit.html.twig',
[
'form' => $form->createView(),
'parent' => $resourceNodeParentId,
]
);
}
/**
* Shows a resource information.
*
* @Route("/{tool}/{type}/{id}/info", methods={"GET"}, name="chamilo_core_resource_info")
*/
public function infoAction(Request $request): Response
{
$this->setBreadCrumb($request);
$nodeId = $request->get('id');
$repository = $this->getRepositoryFromRequest($request);
/** @var AbstractResource $resource */
$resource = $repository->getRepository()->findOneBy(['resourceNode' => $nodeId]);
if (null === $resource) {
throw new NotFoundHttpException();
}
$resourceNode = $resource->getResourceNode();
if (null === $resourceNode) {
throw new NotFoundHttpException();
}
$this->denyAccessUnlessGranted(
ResourceNodeVoter::VIEW,
$resourceNode,
$this->trans('Unauthorised access to resource')
);
$tool = $request->get('tool');
$type = $request->get('type');
$params = [
'resource' => $resource,
'tool' => $tool,
'type' => $type,
];
return $this->render('@ChamiloTheme/Resource/show.html.twig', $params);
}
/**
* Preview a file. Mostly used when using a modal.
*
* @Route("/{tool}/{type}/{id}/preview", methods={"GET"}, name="chamilo_core_resource_preview")
*/
public function previewAction(Request $request): Response
{
$this->setBreadCrumb($request);
$nodeId = $request->get('id');
$repository = $this->getRepositoryFromRequest($request);
/** @var AbstractResource $resource */
$resource = $repository->getRepository()->findOneBy(['resourceNode' => $nodeId]);
if (null === $resource) {
throw new NotFoundHttpException();
}
$resourceNode = $resource->getResourceNode();
if (null === $resourceNode) {
throw new NotFoundHttpException();
}
$this->denyAccessUnlessGranted(
ResourceNodeVoter::VIEW,
$resourceNode,
$this->trans('Unauthorised access to resource')
);
$tool = $request->get('tool');
$type = $request->get('type');
$params = [
'resource' => $resource,
'tool' => $tool,
'type' => $type,
];
return $this->render('@ChamiloTheme/Resource/preview.html.twig', $params);
}
/**
* @Route("/{tool}/{type}/{id}/change_visibility", name="chamilo_core_resource_change_visibility")
*/
public function changeVisibilityAction(Request $request): Response
{
$id = $request->get('id');
$repository = $this->getRepositoryFromRequest($request);
/** @var AbstractResource $resource */
$resource = $repository->getRepository()->findOneBy(['resourceNode' => $id]);
if (null === $resource) {
throw new NotFoundHttpException();
}
$resourceNode = $resource->getResourceNode();
$this->denyAccessUnlessGranted(
ResourceNodeVoter::EDIT,
$resourceNode,
$this->trans('Unauthorised access to resource')
);
/** @var ResourceLink $link */
$link = $resource->getCourseSessionResourceLink($this->getCourse(), $this->getSession());
$icon = 'fa-eye';
// Use repository to change settings easily.
if ($link && $link->getVisibility() === ResourceLink::VISIBILITY_PUBLISHED) {
$repository->setVisibilityDraft($resource);
$icon = 'fa-eye-slash';
} else {
$repository->setVisibilityPublished($resource);
}
$result = ['icon' => $icon];
return new JsonResponse($result);
}
/**
* @Route("/{tool}/{type}/{id}", name="chamilo_core_resource_delete")
*/
public function deleteAction(Request $request): Response
{
$tool = $request->get('tool');
$type = $request->get('type');
$em = $this->getDoctrine()->getManager();
$id = $request->get('id');
$resourceNode = $this->getDoctrine()->getRepository('ChamiloCoreBundle:Resource\ResourceNode')->find($id);
$parentId = $resourceNode->getParent()->getId();
if (null === $resourceNode) {
throw new NotFoundHttpException();
}
$this->denyAccessUnlessGranted(
ResourceNodeVoter::DELETE,
$resourceNode,
$this->trans('Unauthorised access to resource')
);
$em->remove($resourceNode);
$this->addFlash('success', $this->trans('Deleted'));
$em->flush();
$routeParams = $this->getCourseParams();
$routeParams['tool'] = $tool;
$routeParams['type'] = $type;
$routeParams['id'] = $parentId;
return $this->redirectToRoute(
'chamilo_core_resource_list',
$routeParams
);
}
/**
* @Route("/{tool}/{type}/{id}", methods={"DELETE"}, name="chamilo_core_resource_delete_mass")
*/
public function deleteMassAction($primaryKeys, $allPrimaryKeys, Request $request): Response
{
$tool = $request->get('tool');
$type = $request->get('type');
$em = $this->getDoctrine()->getManager();
$repo = $this->getRepositoryFromRequest($request);
$parentId = 0;
foreach ($primaryKeys as $id) {
$resource = $repo->find($id);
$resourceNode = $resource->getResourceNode();
if (null === $resourceNode) {
continue;
}
$this->denyAccessUnlessGranted(
ResourceNodeVoter::DELETE,
$resourceNode,
$this->trans('Unauthorised access to resource')
);
$parentId = $resourceNode->getParent()->getId();
$em->remove($resource);
}
$this->addFlash('success', $this->trans('Deleted'));
$em->flush();
$routeParams = $this->getCourseParams();
$routeParams['tool'] = $tool;
$routeParams['type'] = $type;
$routeParams['id'] = $parentId;
return $this->redirectToRoute('chamilo_core_resource_list', $routeParams);
}
/**
* Shows the associated resource file.
*
* @Route("/{tool}/{type}/{id}/view", methods={"GET"}, name="chamilo_core_resource_view")
*/
public function viewAction(Request $request, Glide $glide): Response
{
$id = $request->get('id');
$filter = $request->get('filter');
$mode = $request->get('mode');
$em = $this->getDoctrine();
$resourceNode = $em->getRepository('ChamiloCoreBundle:Resource\ResourceNode')->find($id);
if ($resourceNode === null) {
throw new FileNotFoundException('Resource not found');
}
return $this->showFile($request, $resourceNode, $mode, $glide, $filter);
}
/**
* Gets a document when calling route resources_document_get_file
* @deprecated
*
* @throws \League\Flysystem\FileNotFoundException
*/
public function getDocumentAction(Request $request, Glide $glide): Response
{
/*$file = $request->get('file');
$mode = $request->get('mode');
// see list of filters in config/services.yaml
$filter = $request->get('filter');
$mode = !empty($mode) ? $mode : 'show';
$repository = $this->getRepository('document', 'files');
$nodeRepository = $repository->getResourceNodeRepository();
$title = basename($file);
// @todo improve criteria to avoid giving the wrong file.
$criteria = ['slug' => $title];
$resourceNode = $nodeRepository->findOneBy($criteria);
if (null === $resourceNode) {
throw new NotFoundHttpException();
}
return $this->showFile($request, $resourceNode, $mode, $glide,$filter);*/
}
/**
* @Route("/{tool}/{type}/{id}/download", methods={"GET"}, name="chamilo_core_resource_download")
*/
public function downloadAction(Request $request)
{
$resourceNodeId = (int) $request->get('id');
$courseNode = $this->getCourse()->getResourceNode();
$repo = $this->getRepositoryFromRequest($request);
if (empty($resourceNodeId)) {
$resourceNode = $courseNode;
} else {
$resourceNode = $repo->getResourceNodeRepository()->find($resourceNodeId);
}
$type = $repo->getResourceType();
if (null === $resourceNode) {
throw new NotFoundHttpException();
}
$this->denyAccessUnlessGranted(
ResourceNodeVoter::VIEW,
$resourceNode,
$this->trans('Unauthorised access to resource')
);
// If resource node has a file just download it. Don't download the children.
if ($resourceNode->hasResourceFile()) {
// Redirect to download single file.
return $this->showFile($request, $resourceNode, 'download');
}
$zipName = $resourceNode->getSlug().'.zip';
$rootNodePath = $resourceNode->getPathForDisplay();
$resourceNodeRepo = $repo->getResourceNodeRepository();
$criteria = Criteria::create()
->where(Criteria::expr()->neq('resourceFile', null)) // must have a file
// ->andWhere(Criteria::expr()->eq('resourceType', $type))
;
/** @var ArrayCollection|ResourceNode[] $children */
/** @var QueryBuilder $children */
$qb = $resourceNodeRepo->getChildrenQueryBuilder($resourceNode);
$qb->addCriteria($criteria);
$children = $qb->getQuery()->getResult();
$response = new StreamedResponse(function () use ($rootNodePath, $zipName, $children, $repo) {
// Define suitable options for ZipStream Archive.
$options = new Archive();
$options->setContentType('application/octet-stream');
//initialise zipstream with output zip filename and options.
$zip = new ZipStream($zipName, $options);
/** @var ResourceNode $node */
foreach ($children as $node) {
$resourceFile = $node->getResourceFile();
$systemName = $resourceFile->getFile()->getPathname();
$stream = $repo->getResourceNodeFileStream($node);
//error_log($node->getPathForDisplay());
$fileToDisplay = str_replace($rootNodePath, '', $node->getPathForDisplay());
$zip->addFileFromStream($fileToDisplay, $stream);
}
$zip->finish();
});
$disposition = $response->headers->makeDisposition(
ResponseHeaderBag::DISPOSITION_ATTACHMENT,
Transliterator::transliterate($zipName)
);
$response->headers->set('Content-Disposition', $disposition);
$response->headers->set('Content-Type', 'application/octet-stream');
return $response;
}
/**
* Upload form.
*
* @Route("/{tool}/{type}/{id}/upload", name="chamilo_core_resource_upload", methods={"GET", "POST"},
* options={"expose"=true})
*/
public function uploadAction(Request $request, $tool, $type, $id): Response
{
$repository = $this->getRepositoryFromRequest($request);
$resourceNode = $repository->getResourceNodeRepository()->find($id);
$this->denyAccessUnlessGranted(
ResourceNodeVoter::EDIT,
$resourceNode,
$this->trans('Unauthorised access to resource')
);
$this->setBreadCrumb($request);
$routeParams = $this->getCourseParams();
$routeParams['tool'] = $tool;
$routeParams['type'] = $type;
$routeParams['id'] = $id;
return $this->render(
'@ChamiloTheme/Resource/upload.html.twig',
$routeParams
);
}
public function setBreadCrumb(Request $request)
{
$tool = $request->get('tool');
$type = $request->get('type');
$resourceNodeId = $request->get('id');
$routeParams = $this->getCourseParams();
$routeParams['tool'] = $tool;
$routeParams['type'] = $type;
if (!empty($resourceNodeId)) {
$breadcrumb = $this->getBreadCrumb();
// Root tool link
$breadcrumb->addChild(
$this->trans($tool),
[
'uri' => $this->generateUrl(
'chamilo_core_resource_index',
$routeParams
),
]
);
$repo = $this->getRepositoryFromRequest($request);
/** @var AbstractResource $parent */
$originalResource = $repo->findOneBy(['resourceNode' => $resourceNodeId]);
if ($originalResource === null) {
return;
}
$parent = $originalParent = $originalResource->getResourceNode();
$parentList = [];
while ($parent !== null) {
if ($type !== $parent->getResourceType()->getName()) {
break;
}
$parent = $parent->getParent();
if ($parent) {
$resource = $repo->findOneBy(['resourceNode' => $parent->getId()]);
if ($resource) {
$parentList[] = $resource;
}
}
}
$parentList = array_reverse($parentList);
/** @var AbstractResource $item */
foreach ($parentList as $item) {
$params = $routeParams;
$params['id'] = $item->getResourceNode()->getId();
$breadcrumb->addChild(
$item->getResourceName(),
[
'uri' => $this->generateUrl(
'chamilo_core_resource_list',
$params
),
]
);
}
$params = $routeParams;
$params['id'] = $originalParent->getId();
$breadcrumb->addChild(
$originalResource->getResourceName(),
[
'uri' => $this->generateUrl(
'chamilo_core_resource_list',
$params
),
]
);
}
}
/**
* @param Request $request
* @param ResourceNode $resourceNode
* @param string $mode
* @param Glide|null $glide
* @param string $filter
*
* @return mixed|StreamedResponse
*/
private function showFile(Request $request, ResourceNode $resourceNode, $mode = 'show', Glide $glide = null, $filter = '')
{
$this->denyAccessUnlessGranted(
ResourceNodeVoter::VIEW,
$resourceNode,
$this->trans('Unauthorised access to resource')
);
$repo = $this->getRepositoryFromRequest($request);
$resourceFile = $resourceNode->getResourceFile();
if (!$resourceFile) {
throw new NotFoundHttpException();
}
//$fileName = $resourceFile->getOriginalName();
$fileName = $resourceNode->getSlug();
$filePath = $resourceFile->getFile()->getPathname();
$mimeType = $resourceFile->getMimeType();
switch ($mode) {
case 'download':
$forceDownload = true;
break;
case 'show':
default:
$forceDownload = false;
// If it's an image then send it to Glide.
if (strpos($mimeType, 'image') !== false) {
$server = $glide->getServer();
$params = $request->query->all();
// The filter overwrites the params from get
if (!empty($filter)) {
$params = $glide->getFilters()[$filter] ?? [];
}
// The image was cropped manually by the user, so we force to render this version,
// no matter other crop parameters.
$crop = $resourceFile->getCrop();
if (!empty($crop)) {
$params['crop'] = $crop;
}
return $server->getImageResponse($filePath, $params);
}
break;
}
$stream = $repo->getResourceNodeFileStream($resourceNode);
//$stream = $this->fs->readStream($resourceNode);
$response = new StreamedResponse(function () use ($stream): void {
stream_copy_to_stream($stream, fopen('php://output', 'wb'));
});
$disposition = $response->headers->makeDisposition(
$forceDownload ? ResponseHeaderBag::DISPOSITION_ATTACHMENT : ResponseHeaderBag::DISPOSITION_INLINE,
$fileName
//Transliterator::transliterate($fileName)
);
$response->headers->set('Content-Disposition', $disposition);
$response->headers->set('Content-Type', $mimeType ?: 'application/octet-stream');
return $response;
}
/**
* @param string $fileType
*
* @return RedirectResponse|Response
*/
private function createResource(Request $request, $fileType = 'file')
{
$tool = $request->get('tool');
$type = $request->get('type');
$resourceNodeParentId = $request->get('id');
$repository = $this->getRepositoryFromRequest($request);
$course = $this->getCourse();
$session = $this->getSession();
// Default parent node is course.
$parentNode = $course->getResourceNode();
if (!empty($resourceNodeParentId)) {
// Get parent node.
$parentNode = $repository->getResourceNodeRepository()->find($resourceNodeParentId);
}
$this->denyAccessUnlessGranted(
ResourceNodeVoter::CREATE,
$parentNode,
$this->trans('Unauthorised access to resource')
);
$form = $repository->getForm($this->container->get('form.factory'));
$courseParams = $this->getCourseParams();
if ($fileType === 'file') {
$params = $courseParams;
$params['tool'] = $tool;
$params['type'] = $type;
$params['id'] = $resourceNodeParentId;
$form->add(
'content',
CKEditorType::class,
[
'mapped' => false,
'config' => [
'filebrowserImageBrowseRoute' => 'resources_filemanager',
'filebrowserImageBrowseRouteParameters' => $params,
],
]
);
}
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$em = $this->getDoctrine()->getManager();
/** @var AbstractResource $newResource */
$newResource = $repository->saveResource($form, $course, $session, $fileType);
$file = null;
if ($fileType === 'file') {
$content = $form->get('content')->getViewData();
$newResource->setTitle($newResource->getTitle().'.html');
$fileName = $newResource->getTitle();
$handle = tmpfile();
fwrite($handle, $content);
$meta = stream_get_meta_data($handle);
$file = new UploadedFile($meta['uri'], $fileName, null, null, true);
$em->persist($newResource);
}
$resourceNode = $repository->createNodeForResource($newResource, $this->getUser(), $parentNode, $file);
$em->persist($resourceNode);
$repository->addResourceNodeToCourse(
$resourceNode,
ResourceLink::VISIBILITY_PUBLISHED,
$course,
$session,
null
);
$em->flush();
// Loops all sharing options
/*foreach ($shareList as $share) {
$idList = [];
if (isset($share['search'])) {
$idList = explode(',', $share['search']);
}
$resourceRight = null;
if (isset($share['mask'])) {
$resourceRight = new ResourceRight();
$resourceRight
->setMask($share['mask'])
->setRole($share['role'])
;
}
// Build links
switch ($share['sharing']) {
case 'everyone':
$repository->addResourceToEveryone(
$resourceNode,
$resourceRight
);
break;
case 'course':
$repository->addResourceToCourse(
$resourceNode,
$course,
$resourceRight
);
break;
case 'session':
$repository->addResourceToSession(
$resourceNode,
$course,
$session,
$resourceRight
);
break;
case 'user':
// Only for me
if (isset($share['only_me'])) {
$repository->addResourceOnlyToMe($resourceNode);
} else {
// To other users
$repository->addResourceToUserList($resourceNode, $idList);
}
break;
case 'group':
// @todo
break;
}*/
//}
$em->flush();
$this->addFlash('success', $this->trans('Saved'));
$params = $this->getCourseParams();
$params['tool'] = $tool;
$params['type'] = $type;
$params['id'] = $resourceNodeParentId;
return $this->redirectToRoute(
'chamilo_core_resource_list',
$params
);
}
switch ($fileType) {
case 'folder':
$template = '@ChamiloTheme/Resource/new_folder.html.twig';
break;
case 'file':
$template = '@ChamiloTheme/Resource/new.html.twig';
break;
}
return $this->render(
$template,
[
'form' => $form->createView(),
'parent' => $resourceNodeParentId,
'file_type' => $fileType,
]
);
}
}