Add security checks, finish download folder button.

pull/3064/head
Julio 6 years ago
parent 0fb2284b64
commit e7c063e770
  1. 145
      src/CoreBundle/Controller/ResourceController.php
  2. 33
      src/CoreBundle/Repository/ResourceRepository.php

@ -21,7 +21,6 @@ use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Criteria; use Doctrine\Common\Collections\Criteria;
use Doctrine\ORM\QueryBuilder; use Doctrine\ORM\QueryBuilder;
use FOS\CKEditorBundle\Form\Type\CKEditorType; use FOS\CKEditorBundle\Form\Type\CKEditorType;
use League\Flysystem\Filesystem;
use Symfony\Component\Filesystem\Exception\FileNotFoundException; use Symfony\Component\Filesystem\Exception\FileNotFoundException;
use Symfony\Component\HttpFoundation\File\UploadedFile; use Symfony\Component\HttpFoundation\File\UploadedFile;
use Symfony\Component\HttpFoundation\JsonResponse; use Symfony\Component\HttpFoundation\JsonResponse;
@ -39,7 +38,7 @@ use ZipStream\ZipStream;
/** /**
* Class ResourceController. * Class ResourceController.
* * @todo improve/refactor $this->denyAccessUnlessGranted
* @Route("/resources") * @Route("/resources")
* *
* @author Julio Montoya <gugli100@gmail.com>. * @author Julio Montoya <gugli100@gmail.com>.
@ -60,7 +59,8 @@ class ResourceController extends AbstractResourceController implements CourseCon
$tool = $request->get('tool'); $tool = $request->get('tool');
$type = $request->get('type'); $type = $request->get('type');
$grid = $this->getGrid($request, $grid); $course = $this->getCourse();
$grid = $this->getGrid($request, $grid, $course->getResourceNode()->getId());
$breadcrumb = $this->getBreadCrumb(); $breadcrumb = $this->getBreadCrumb();
$breadcrumb->addChild( $breadcrumb->addChild(
@ -80,11 +80,27 @@ class ResourceController extends AbstractResourceController implements CourseCon
} }
/** /**
* @param int $resourceNodeId * @Route("/{tool}/{type}/{id}/list", name="chamilo_core_resource_list")
* *
* @return Grid * If node has children show it
*/ */
public function getGrid(Request $request, Grid $grid, $resourceNodeId = 0) 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'); $tool = $request->get('tool');
$type = $request->get('type'); $type = $request->get('type');
@ -99,12 +115,15 @@ class ResourceController extends AbstractResourceController implements CourseCon
$course = $this->getCourse(); $course = $this->getCourse();
$session = $this->getSession(); $session = $this->getSession();
$parent = $course->getResourceNode(); $parentNode = $repository->getResourceNodeRepository()->find($resourceNodeId);
if (!empty($resourceNodeId)) {
$parent = $repository->getResourceNodeRepository()->find($resourceNodeId);
}
$qb = $repository->getResourcesByCourse($course, $session, null, $parent); $this->denyAccessUnlessGranted(
ResourceNodeVoter::VIEW,
$parentNode,
$this->trans('Unauthorised access to resource')
);
$qb = $repository->getResourcesByCourse($course, $session, null, $parentNode);
// 3. Set QueryBuilder to the source. // 3. Set QueryBuilder to the source.
$source->initQueryBuilder($qb); $source->initQueryBuilder($qb);
@ -124,9 +143,7 @@ class ResourceController extends AbstractResourceController implements CourseCon
//$grid->isReadyForRedirect(); //$grid->isReadyForRedirect();
//$grid->setMaxResults(1); //$grid->setMaxResults(1);
//$grid->setLimits(2); //$grid->setLimits(2);
//$grid->setColumns($columns); //$grid->setColumns($columns);
$routeParams = $courseParams; $routeParams = $courseParams;
$routeParams['tool'] = $tool; $routeParams['tool'] = $tool;
$routeParams['type'] = $type; $routeParams['type'] = $type;
@ -379,27 +396,6 @@ class ResourceController extends AbstractResourceController implements CourseCon
return $grid; return $grid;
} }
/**
* @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]
);
}
/** /**
* @Route("/{tool}/{type}/{id}/new_folder", methods={"GET", "POST"}, name="chamilo_core_resource_new_folder") * @Route("/{tool}/{type}/{id}/new_folder", methods={"GET", "POST"}, name="chamilo_core_resource_new_folder")
*/ */
@ -462,7 +458,7 @@ class ResourceController extends AbstractResourceController implements CourseCon
], ],
] ]
); );
$content = $repository->getResourceFileContent($resource); $content = $repository->getResourceNodeFileContent($resourceNode);
$form->get('content')->setData($content); $form->get('content')->setData($content);
} }
@ -732,7 +728,7 @@ class ResourceController extends AbstractResourceController implements CourseCon
*/ */
public function getDocumentAction(Request $request, Glide $glide): Response public function getDocumentAction(Request $request, Glide $glide): Response
{ {
$file = $request->get('file'); /*$file = $request->get('file');
$mode = $request->get('mode'); $mode = $request->get('mode');
// see list of filters in config/services.yaml // see list of filters in config/services.yaml
@ -752,13 +748,7 @@ class ResourceController extends AbstractResourceController implements CourseCon
throw new NotFoundHttpException(); throw new NotFoundHttpException();
} }
$this->denyAccessUnlessGranted( return $this->showFile($request, $resourceNode, $mode, $glide,$filter);*/
ResourceNodeVoter::VIEW,
$resourceNode,
$this->trans('Unauthorised access to resource')
);
return $this->showFile($request, $resourceNode, $mode, $glide,$filter);
} }
/** /**
@ -789,22 +779,20 @@ class ResourceController extends AbstractResourceController implements CourseCon
$this->trans('Unauthorised access to resource') $this->trans('Unauthorised access to resource')
); );
$zipName = $resourceNode->getSlug().'.zip'; // If resource node has a file just download it. Don't download the children.
$rootNodePath = $resourceNode->getPathForDisplay();
if ($resourceNode->hasResourceFile()) { if ($resourceNode->hasResourceFile()) {
// Redirect to download file // Redirect to download single file.
return $this->showFile($request, $resourceNode, 'download'); return $this->showFile($request, $resourceNode, 'download');
} }
/** @var Filesystem $fileSystem */ $zipName = $resourceNode->getSlug().'.zip';
//$fileSystem = $this->get('oneup_flysystem.resources_filesystem'); $rootNodePath = $resourceNode->getPathForDisplay();
$resourceNodeRepo = $repo->getResourceNodeRepository(); $resourceNodeRepo = $repo->getResourceNodeRepository();
$criteria = Criteria::create() $criteria = Criteria::create()
->where(Criteria::expr()->neq('resourceFile', null)) ->where(Criteria::expr()->neq('resourceFile', null)) // must have a file
->andWhere(Criteria::expr()->eq('resourceType', $type)) // ->andWhere(Criteria::expr()->eq('resourceType', $type))
; ;
/** @var ArrayCollection|ResourceNode[] $children */ /** @var ArrayCollection|ResourceNode[] $children */
@ -813,23 +801,7 @@ class ResourceController extends AbstractResourceController implements CourseCon
$qb->addCriteria($criteria); $qb->addCriteria($criteria);
$children = $qb->getQuery()->getResult(); $children = $qb->getQuery()->getResult();
/** @var ResourceNode $node */ $response = new StreamedResponse(function () use ($rootNodePath, $zipName, $children, $repo) {
foreach ($children as $node) {
/*if ($node->hasResourceFile()) {
$resourceFile = $node->getResourceFile();
$systemName = $resourceFile->getFile()->getPathname();
$stream = $fileSystem->readStream($systemName);
//error_log($node->getPathForDisplay());
$fileToDisplay = str_replace($rootNodePath, '', $node->getPathForDisplay());
var_dump($fileToDisplay);
}*/
var_dump($node->getPathForDisplay());
//var_dump($node['path']);
}
exit;
$response = new StreamedResponse(function () use ($rootNodePath, $zipName, $children, $fileSystem) {
// Define suitable options for ZipStream Archive. // Define suitable options for ZipStream Archive.
$options = new Archive(); $options = new Archive();
$options->setContentType('application/octet-stream'); $options->setContentType('application/octet-stream');
@ -840,13 +812,11 @@ class ResourceController extends AbstractResourceController implements CourseCon
foreach ($children as $node) { foreach ($children as $node) {
$resourceFile = $node->getResourceFile(); $resourceFile = $node->getResourceFile();
$systemName = $resourceFile->getFile()->getPathname(); $systemName = $resourceFile->getFile()->getPathname();
$stream = $fileSystem->readStream($systemName); $stream = $repo->getResourceNodeFileStream($node);
//error_log($node->getPathForDisplay()); //error_log($node->getPathForDisplay());
$fileToDisplay = str_replace($rootNodePath, '', $node->getPathForDisplay()); $fileToDisplay = str_replace($rootNodePath, '', $node->getPathForDisplay());
$zip->addFileFromStream($fileToDisplay, $stream); $zip->addFileFromStream($fileToDisplay, $stream);
} }
//$data = $repo->getDocumentContent($not_deleted_file['id']);
//$zip->addFile($not_deleted_file['path'], $data);
$zip->finish(); $zip->finish();
}); });
@ -974,13 +944,15 @@ class ResourceController extends AbstractResourceController implements CourseCon
* *
* @return mixed|StreamedResponse * @return mixed|StreamedResponse
*/ */
private function showFile(Request $request, ResourceNode $resourceNode, $mode = 'show', Glide $glide = null, $filter = '') private function showFile(Request $request, ResourceNode $resourceNode, string $mode = 'show', Glide $glide = null, $filter = '')
{ {
$this->denyAccessUnlessGranted( $this->denyAccessUnlessGranted(
ResourceNodeVoter::VIEW, ResourceNodeVoter::VIEW,
$resourceNode, $resourceNode,
$this->trans('Unauthorised access to resource') $this->trans('Unauthorised access to resource')
); );
$repo = $this->getRepositoryFromRequest($request);
$resourceFile = $resourceNode->getResourceFile(); $resourceFile = $resourceNode->getResourceFile();
if (!$resourceFile) { if (!$resourceFile) {
@ -1021,7 +993,9 @@ class ResourceController extends AbstractResourceController implements CourseCon
break; break;
} }
$stream = $this->fs->readStream($filePath); $stream = $repo->getResourceNodeFileStream($resourceNode);
//$stream = $this->fs->readStream($resourceNode);
$response = new StreamedResponse(function () use ($stream): void { $response = new StreamedResponse(function () use ($stream): void {
stream_copy_to_stream($stream, fopen('php://output', 'wb')); stream_copy_to_stream($stream, fopen('php://output', 'wb'));
}); });
@ -1048,6 +1022,22 @@ class ResourceController extends AbstractResourceController implements CourseCon
$resourceNodeParentId = $request->get('id'); $resourceNodeParentId = $request->get('id');
$repository = $this->getRepositoryFromRequest($request); $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')); $form = $repository->getForm($this->container->get('form.factory'));
$courseParams = $this->getCourseParams(); $courseParams = $this->getCourseParams();
@ -1071,15 +1061,6 @@ class ResourceController extends AbstractResourceController implements CourseCon
); );
} }
$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);
}
$form->handleRequest($request); $form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) { if ($form->isSubmitted() && $form->isValid()) {
$em = $this->getDoctrine()->getManager(); $em = $this->getDoctrine()->getManager();

@ -628,6 +628,39 @@ class ResourceRepository extends EntityRepository
} }
} }
public function getResourceNodeFileContent(ResourceNode $resourceNode): string
{
try {
if ($resourceNode->hasResourceFile()) {
$resourceFile = $resourceNode->getResourceFile();
$fileName = $resourceFile->getFile()->getPathname();
return $this->fs->read($fileName);
}
return '';
} catch (\Throwable $exception) {
throw new FileNotFoundException($resourceNode);
}
}
public function getResourceNodeFileStream(ResourceNode $resourceNode)
{
try {
if ($resourceNode->hasResourceFile()) {
$resourceFile = $resourceNode->getResourceFile();
$fileName = $resourceFile->getFile()->getPathname();
return $this->fs->readStream($fileName);
}
return '';
} catch (\Throwable $exception) {
throw new FileNotFoundException($resourceNode);
}
}
public function getResourceFileUrl(AbstractResource $resource, array $extraParams = []): string public function getResourceFileUrl(AbstractResource $resource, array $extraParams = []): string
{ {
try { try {

Loading…
Cancel
Save