WIP - Add document dummy code to add resources

- New datagrid bundle added (apy/datagrid-bundle)
- api_get_group_entity() added
- ResourceController and uploader fixed using new version of Resource
bundle.
- Add interface and trait to capture the course and session from the url
with a listener.
- Add new form type to manage Resource (Link, Node and Rights)
- Fix ResourceRepository with new changes
- New templates added for the document list (dummy code)
pull/2650/head
Julio Montoya 8 years ago
parent 3b87f8575e
commit 3f8b6c39f8
  1. 8
      app/Migrations/Schema/V200/Version20.php
  2. 10
      composer.json
  3. 1
      config/bundles.php
  4. 14
      config/packages/oneup_flysystem.yaml
  5. 11
      config/packages/oneup_uploader.yaml
  6. 20
      config/routes.yaml
  7. 19
      config/services.yaml
  8. 15
      main/inc/lib/api.lib.php
  9. 169
      src/CoreBundle/Controller/BaseController.php
  10. 4
      src/CoreBundle/Controller/EditorController.php
  11. 491
      src/CoreBundle/Controller/ResourceController.php
  12. 151
      src/CoreBundle/Controller/ResourceDownloadController.php
  13. 7
      src/CoreBundle/Entity/Listener/CourseListener.php
  14. 67
      src/CoreBundle/Entity/Resource/AbstractResource.php
  15. 25
      src/CoreBundle/Entity/Resource/ResourceInterface.php
  16. 22
      src/CoreBundle/Entity/Resource/ResourceLink.php
  17. 26
      src/CoreBundle/Entity/Resource/ResourceNode.php
  18. 16
      src/CoreBundle/Entity/ToolResourceRights.php
  19. 86
      src/CoreBundle/Form/Type/DocumentType.php
  20. 92
      src/CoreBundle/Form/Type/ResourceLinkType.php
  21. 51
      src/CoreBundle/Form/Type/ResourceNodeType.php
  22. 54
      src/CoreBundle/Form/Type/ResourceRightsType.php
  23. 43
      src/CoreBundle/Repository/ResourceRepository.php
  24. 12
      src/CoreBundle/Resources/config/routing.yml
  25. 197
      src/CoreBundle/Resources/views/Document/create.html.twig
  26. 21
      src/CoreBundle/Resources/views/Document/grid.html.twig
  27. 147
      src/CoreBundle/Resources/views/Document/index.html.twig
  28. 47
      src/CoreBundle/Resources/views/Document/show.html.twig
  29. 10
      src/CoreBundle/Resources/views/Document/update.html.twig
  30. 139
      src/CoreBundle/Resources/views/grid.html.twig
  31. 37
      src/CoreBundle/Security/Authorization/Voter/ResourceNodeVoter.php
  32. 11
      src/CourseBundle/Controller/CourseControllerInterface.php
  33. 55
      src/CourseBundle/Controller/CourseControllerTrait.php
  34. 216
      src/CourseBundle/Controller/ToolBaseController.php
  35. 46
      src/CourseBundle/Entity/CDocument.php
  36. 211
      src/CourseBundle/EventListener/CourseListener.php
  37. 19
      src/CourseBundle/Repository/CDocumentRepository.php

@ -555,7 +555,6 @@ class Version20 extends AbstractMigrationChamilo
$this->addSql('ALTER TABLE portfolio CHANGE title title LONGTEXT NOT NULL');
$this->addSql('ALTER TABLE portfolio_category CHANGE title title LONGTEXT NOT NULL');
$table = $schema->getTable('gradebook_category');
if (!$table->hasColumn('gradebooks_to_validate_in_dependence')) {
$this->addSql('ALTER TABLE gradebook_category ADD gradebooks_to_validate_in_dependence INT DEFAULT NULL');
@ -622,6 +621,13 @@ class Version20 extends AbstractMigrationChamilo
}
$this->addSql('ALTER TABLE c_group_info ADD CONSTRAINT FK_CE06532491D79BD3 FOREIGN KEY (c_id) REFERENCES course (id);');
$this->addSql('ALTER TABLE course_category CHANGE auth_course_child auth_course_child VARCHAR(40) DEFAULT NULL');
// WIP: Document - resource
$this->addSql('ALTER TABLE c_document ADD resource_node_id INT DEFAULT NULL');
$this->addSql('ALTER TABLE c_document ADD CONSTRAINT FK_C9FA0CBD1BAD783F FOREIGN KEY (resource_node_id) REFERENCES resource_node (id);');
$this->addSql('CREATE UNIQUE INDEX UNIQ_C9FA0CBD1BAD783F ON c_document (resource_node_id)');
}
/**

@ -55,7 +55,6 @@
"ezyang/htmlpurifier": "^4.10",
"sensio/framework-extra-bundle": "^5.0",
"sensiolabs/security-checker": "^4.1",
"symfony/asset": "^4.0",
"symfony/expression-language": "^4.0",
"symfony/flex": "^1.0",
@ -74,6 +73,8 @@
"symfony/apache-pack": "^1.0",
"symfony/var-dumper": "^4.0",
"apy/datagrid-bundle" : "dev-master",
"twig/extensions": "^1.5",
"white-october/pagerfanta-bundle": "^1.1",
"chamilo/settings-bundle": "dev-master",
@ -100,9 +101,8 @@
"stephpy/timeline-bundle": "~3.0",
"stof/doctrine-extensions-bundle": "~1.0",
"sunra/php-simple-html-dom-parser": "~1.5.0",
"sylius/resource-bundle": "~1.2",
"sylius/resource": "1.2.*",
"sylius/registry": "1.2.*",
"sylius/resource-bundle": "1.2.*",
"friendsofsymfony/jsrouting-bundle": "~2.0",
"gedmo/doctrine-extensions": "~2.4",
@ -188,10 +188,10 @@
"Chamilo\\CoreBundle\\Composer\\ScriptHandler::dumpCssFiles"
],
"auto-scripts": {
"cache:clear": "symfony-cmd",
"assets:install --symlink --relative %PUBLIC_DIR%": "symfony-cmd",
"security-checker security:check": "script",
"requirements-checker": "script",
"cache:clear": "symfony-cmd",
"assets:install %PUBLIC_DIR%": "symfony-cmd"
}
}

@ -70,4 +70,5 @@ return [
Lunetics\LocaleBundle\LuneticsLocaleBundle::class => ['all' => true],
Ivory\CKEditorBundle\IvoryCKEditorBundle::class => ['all' => true],
Oneup\UploaderBundle\OneupUploaderBundle::class => ['all' => true],
APY\DataGridBundle\APYDataGridBundle::class => ['all' => true],
];

@ -8,11 +8,10 @@ oneup_flysystem:
local:
directory: '%kernel.project_dir%/var/home'
# s3.adapter:
# awss3v3:
# client: s3_client # add service "s3_client"
# bucket: ~
# prefix: ~
upload_adapter:
local:
directory: '%kernel.project_dir%/var/upload'
filesystems:
courses:
adapter: courses_adapter
@ -24,4 +23,7 @@ oneup_flysystem:
home:
adapter: home_adapter
visibility: private
alias: home_filesystem
alias: home_filesystem
upload:
adapter: upload_adapter

@ -12,5 +12,16 @@ oneup_uploader:
custom_frontend:
class: Chamilo\CoreBundle\Controller\ResourceUploaderController
name: courses
upload:
#frontend: dropzone # or any uploader you use in the frontend
#frontend: blueimp
frontend: custom
storage:
type: flysystem
filesystem: oneup_flysystem.upload_filesystem
root_folder: true
custom_frontend:
class: Chamilo\CoreBundle\Controller\ResourceUploaderController
name: upload
# namer: oneup_uploader.namer.urlsafe

@ -18,6 +18,26 @@ sonata_admin_my_dashboard:
sonata_user_admin_security_logout:
path: /logout
app_document:
resource: |
alias: app.document
path: /resource/documents
form: Chamilo\CoreBundle\Form\Type\DocumentType
type: sylius.resource
app_document_index:
path: /resource/documents/
methods: [GET,POST]
defaults:
_controller: app.controller.document:indexAction
_sylius:
template: ChamiloCoreBundle:Document:show.html.twig # Use a custom template.
# repository:
# method: findForStore # Use a custom repository method.
# arguments: [$slug] # Pass the slug from the url to the repository.
# type: sylius.resource_api
#admin_dashboard:
# pattern: /administration/

@ -15,9 +15,16 @@ services:
exclude: '../src/CoreBundle/{Entity,Migrations,Tests,Admin,Block,Component,Repository,Security,EventListener}'
public: true
_instanceof:
Sylius\Bundle\ResourceBundle\Controller\ResourceController:
autowire: false
Chamilo\CoreBundle\Controller\ResourceUploaderController:
autowire: false
Chamilo\CoreBundle\Controller\ResourceController:
autowire: false
Chamilo\PageBundle\:
resource: '../src/PageBundle/*'
exclude: '../src/PageBundle/{Entity,Migrations,Tests}'
@ -34,6 +41,18 @@ services:
arguments:
$debug: '%kernel.debug%'
sylius_settings:
driver: doctrine/orm
sylius_resource:
resources:
app.document:
templates: ChamiloCoreBundle:Document
classes:
controller: Chamilo\CoreBundle\Controller\ResourceController
model: Chamilo\CourseBundle\Entity\CDocument
repository: Chamilo\CoreBundle\Repository\ResourceRepository
# Put parameters here that don't need to change on each machine where the app is deployed
# https://symfony.com/doc/current/best_practices/configuration.html#application-related-configuration
parameters:

@ -2094,6 +2094,21 @@ function api_get_session_entity($id = 0)
return Database::getManager()->getRepository('ChamiloCoreBundle:Session')->find($id);
}
/**
* @param int $id
*
* @return \Chamilo\CourseBundle\Entity\CGroupInfo
*/
function api_get_group_entity($id = 0)
{
if (empty($id)) {
$id = api_get_group_id();
}
return Database::getManager()->getRepository('ChamiloCourseBundle:CGroupInfo')->find($id);
}
/**
* @param int $id
*

@ -18,14 +18,6 @@ use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
*/
abstract class BaseController extends Controller
{
/**
* @return TwigEngine
*/
public function getTemplate()
{
return $this->container->get('templating');
}
/**
* @return NotFoundHttpException
*/
@ -34,43 +26,6 @@ abstract class BaseController extends Controller
return new NotFoundHttpException();
}
/**
* Converts string 'Chamilo\CoreBundle\Controller\Admin\QuestionManager' into
* 'admin/question_manager'.
*/
public function getTemplatePath()
{
$parts = $this->classParts;
$newPath = [];
foreach ($parts as $part) {
if (in_array($part, ['chamilo_lms', 'controller'])
//strpos($part, '_controller') > 0
) {
continue;
}
$newPath[] = $part;
}
$template = implode('/', $newPath);
return str_replace('_controller', '', $template);
}
/**
* Transforms 'QuestionManagerController' to 'question_manager.controller'.
*
* @return string
*/
public function getControllerAlias()
{
$parts = $this->classParts;
$parts = array_reverse($parts);
$alias = str_replace('_controller', '.controller', $parts[0]);
return $alias;
}
/**
* Translator shortcut.
*
@ -83,18 +38,6 @@ abstract class BaseController extends Controller
return $this->container->get('translator')->trans($variable);
}
/**
* Returns the class name label.
*
* @example RoleController -> Role
*
* @return string the class name label
*/
public function getClassNameLabel()
{
return $this->classNameLabel;
}
/**
* @return MenuFactoryInterface
*/
@ -103,62 +46,6 @@ abstract class BaseController extends Controller
return $this->container->get('knp_menu.factory');
}
/**
* @param $action
* @param MenuItemInterface $menu
*
* @return MenuItemInterface
*/
public function buildBreadcrumbs($action, MenuItemInterface $menu = null)
{
if (!$menu) {
$menu = $this->getHomeBreadCrumb();
}
$menu->addChild(
$this->trans($this->getClassnameLabel().'List'),
['uri' => $this->generateControllerUrl('listingAction')]
);
$action = str_replace(
[$this->getControllerAlias().':', 'Action'],
'',
$action
);
switch ($action) {
case 'add':
case 'edit':
$menu->addChild(
$this->trans($this->getClassnameLabel().ucfirst($action))
//array('uri' => $this->generateControllerUrl($action.'Action'))
);
break;
}
return $menu;
}
/**
* Renders the current controller template.
*
* @param string $name
* @param array $elements
*
* @return mixed
*/
public function renderTemplate($name, $elements = [])
{
$name = $this->getTemplatePath().'/'.$name;
$renderer = new ListRenderer(new \Knp\Menu\Matcher\Matcher());
$action = $this->getRequest()->get('_route');
$result = $renderer->render($this->getBreadcrumbs($action));
$elements['new_breadcrumb'] = $result;
return $this->getTemplate()->renderTemplate($name, $elements);
}
/**
* @return Course
*/
@ -166,60 +53,4 @@ abstract class BaseController extends Controller
{
return $this->getRequest()->getSession()->get('course');
}
/**
* @param string $action
*
* @return MenuItemInterface
*/
protected function getBreadcrumbs($action)
{
$breadcrumbs = $this->buildBreadcrumbs($action);
return $breadcrumbs;
}
/** Main home URL
* @return MenuItemInterface
*/
protected function getHomeBreadCrumb()
{
$menu = $this->getMenuFactory()->createItem(
'root',
[
'childrenAttributes' => [
'class' => 'breadcrumb',
'currentClass' => 'active',
],
]
);
$menu->addChild(
$this->trans('Home'),
['uri' => $this->generateUrl('home')]
);
return $menu;
}
/**
* @param array $breadCrumbList
*
* @return string
*/
protected function parseLegacyBreadCrumb($breadCrumbList = [])
{
$menu = $this->getHomeBreadCrumb();
foreach ($breadCrumbList as $item) {
$menu->addChild(
$this->trans($item['title']),
['uri' => $item['url']]
);
}
$renderer = new ListRenderer(new \Knp\Menu\Matcher\Matcher());
$result = $renderer->render($menu);
return $result;
}
}

@ -13,7 +13,7 @@ use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Request;
/**
* Class FrontController.
* Class EditorController.
*
* @Route("/front")
*
@ -21,7 +21,7 @@ use Symfony\Component\HttpFoundation\Request;
*
* @package Chamilo\CoreBundle\Controller
*/
class FrontController extends Controller
class EditorController extends Controller
{
/**
* Get templates (left column when creating a document).

@ -3,139 +3,468 @@
namespace Chamilo\CoreBundle\Controller;
use League\Flysystem\Adapter\Local;
use League\Flysystem\Filesystem;
use Symfony\Component\HttpFoundation\BinaryFileResponse;
use Symfony\Component\HttpFoundation\File\MimeType\FileinfoMimeTypeGuesser;
use APY\DataGridBundle\Grid\Export\CSVExport;
use APY\DataGridBundle\Grid\Export\ExcelExport;
use Chamilo\CoreBundle\Repository\ResourceRepository;
use Chamilo\CoreBundle\Entity\Resource\ResourceRights;
use Chamilo\CourseBundle\Controller\CourseControllerTrait;
use Chamilo\CourseBundle\Controller\CourseControllerInterface;
use Chamilo\CourseBundle\Repository\CDocumentRepository;
use APY\DataGridBundle\Grid\Action\MassAction;
use APY\DataGridBundle\Grid\Action\RowAction;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\ResponseHeaderBag;
use Symfony\Component\Routing\Annotation\Route;
use Sylius\Bundle\ResourceBundle\Controller\ResourceController as BaseResourceController;
use APY\DataGridBundle\Grid\Source\Entity;
use FOS\RestBundle\View\View;
use Sylius\Component\Resource\ResourceActions;
use Chamilo\CoreBundle\Security\Authorization\Voter\ResourceNodeVoter;
/**
* Class ResourceController.
*
* @author Julio Montoya <gugli100@gmail.com>.
*
* @Route("/resource")
*
* @package Chamilo\CoreBundle\Controller
*/
class ResourceController extends BaseController
class ResourceController extends BaseResourceController implements CourseControllerInterface
{
use CourseControllerTrait;
/**
* Upload form
* @Route("/upload/{type}/{id}", name="resource_upload", methods={"GET", "POST"}, options={"expose"=true})
* @param Request $request
*
* @return Response
*/
public function uploadFile($type, $id): Response
public function indexAction(Request $request): Response
{
//$helper = $this->container->get('oneup_uploader.templating.uploader_helper');
//$endpoint = $helper->endpoint('courses');
return $this->render(
'@ChamiloCore/Resource/upload.html.twig',
[
'identifier' => $id,
'type' => $type,
]
$source = new Entity('ChamiloCourseBundle:CDocument');
/* @var $grid \APY\DataGridBundle\Grid\Grid */
$grid = $this->get('grid');
/*$tableAlias = $source->getTableAlias();
$source->manipulateQuery(function (QueryBuilder $query) use ($tableAlias, $course) {
$query->andWhere($tableAlias . '.cId = '.$course->getId());
//$query->resetDQLPart('orderBy');
}
);*/
/** @var CDocumentRepository $repository */
$repository = $this->repository;
$course = $this->getCourse();
$tool = $repository->getTool('document');
$resources = $repository->getResourceByCourse($course, $tool);
$source->setData($resources);
$grid->setSource($source);
//$grid->hideFilters();
$grid->setLimits(5);
//$grid->isReadyForRedirect();
//$grid->setMaxResults(1);
//$grid->setLimits(2);
/*$grid->getColumn('id')->manipulateRenderCell(
function ($value, $row, $router) use ($course) {
//$router = $this->get('router');
return $router->generate(
'chamilo_notebook_show',
array('id' => $row->getField('id'), 'course' => $course)
);
}
);*/
if ($this->isGranted(ResourceNodeVoter::ROLE_CURRENT_COURSE_TEACHER)) {
$deleteMassAction = new MassAction(
'Delete',
'chamilo.controller.notebook:deleteMassAction',
true,
array('course' => $request->get('course'))
);
$grid->addMassAction($deleteMassAction);
}
$translation = $this->container->get('translator');
$myRowAction = new RowAction(
$translation->trans('View'),
'app_document_show',
false,
'_self',
['class' => 'btn btn-default']
);
$myRowAction->setRouteParameters(array('course' => $course, 'id'));
$grid->addRowAction($myRowAction);
if ($this->isGranted(ResourceNodeVoter::ROLE_CURRENT_COURSE_TEACHER)) {
$myRowAction = new RowAction(
$translation->trans('Edit'),
'app_document_update',
false,
'_self',
['class' => 'btn btn-info']
);
$myRowAction->setRouteParameters(array('course' => $course, 'id'));
$grid->addRowAction($myRowAction);
$myRowAction = new RowAction(
$translation->trans('Delete'),
'app_document_delete',
false,
'_self',
['class' => 'btn btn-danger', 'form_delete' => true]
);
$myRowAction->setRouteParameters(['course' => $course, 'id']);
$grid->addRowAction($myRowAction);
}
$grid->addExport(
new CSVExport(
$translation->trans('CSV Export'), 'export', ['course' => $course]
)
);
$grid->addExport(
new ExcelExport(
$translation->trans('Excel Export'),
'export',
['course' => $course]
)
);
return $grid->getGridResponse('ChamiloCoreBundle:Document:index.html.twig');
}
/**
* Downloads the file courses/MATHS/document/file.jpg to the user.
* @Route("/download/{course}/", name="resource_download", methods={"GET"}, options={"expose"=true})
* @todo check permissions
* @param Request $request
*
* @param string $course
*
* @return \Symfony\Component\HttpKernel\Exception\NotFoundHttpException
* @return RedirectResponse|Response
*/
public function downloadFileAction(Request $request, $course)
public function createAction(Request $request): Response
{
try {
/** @var Filesystem $fs */
$fs = $this->container->get('oneup_flysystem.courses_filesystem');
$file = $request->get('file');
$configuration = $this->requestConfigurationFactory->create($this->metadata, $request);
$this->isGrantedOr403($configuration, ResourceActions::CREATE);
$newResource = $this->newResourceFactory->create($configuration, $this->factory);
$form = $this->resourceFormFactory->create($configuration, $newResource);
$course = $this->getCourse();
$session = $this->getSession();
$newResource->setCId($course->getId());
$form->setData($newResource);
if ($request->isMethod('POST') && $form->handleRequest($request)->isValid()) {
/** @var \Chamilo\CourseBundle\Entity\CDocument $newResource */
$newResource = $form->getData();
$event = $this->eventDispatcher->dispatchPreEvent(ResourceActions::CREATE, $configuration, $newResource);
if ($event->isStopped() && !$configuration->isHtmlRequest()) {
throw new HttpException($event->getErrorCode(), $event->getMessage());
}
if ($event->isStopped()) {
$this->flashHelper->addFlashFromEvent($configuration, $event);
if ($event->hasResponse()) {
return $event->getResponse();
}
return $this->redirectHandler->redirectToIndex($configuration, $newResource);
}
if ($configuration->hasStateMachine()) {
$this->stateMachine->apply($configuration, $newResource);
}
$path = $course.'/document/'.$file;
//$newResource->setCId($request->get('c_id'));
$sharedType = $form->get('shared')->getData();
$shareList = array();
// Has folder
if (!$fs->has($course)) {
return $this->abort();
switch ($sharedType) {
case 'this_course':
if (empty($course)) {
break;
}
// Default Chamilo behaviour:
// Teachers can edit and students can see
$shareList = array(
array(
'sharing' => 'course',
'mask' => ResourceNodeVoter::getReaderMask(),
'role' => ResourceNodeVoter::ROLE_CURRENT_COURSE_STUDENT,
'search' => $course->getId(),
),
array(
'sharing' => 'course',
'mask' => ResourceNodeVoter::getEditorMask(),
'role' => ResourceNodeVoter::ROLE_CURRENT_COURSE_TEACHER,
'search' => $course->getId(),
),
);
break;
case 'shared':
$shareList = $form->get('rights')->getData();
break;
case 'only_me':
$shareList = array(
array(
'sharing' => 'user',
'only_me' => true,
),
);
break;
}
// Has file
if (!$fs->has($path)) {
return $this->abort();
error_log(print_r($shareList, 1));
/** @var ResourceRepository $repository */
$repository = $this->repository;
$resourceNode = $repository->addResourceNode($newResource, $this->getUser());
// Loops all sharing options
foreach ($shareList as $share) {
$idList = array();
if (isset($share['search'])) {
$idList = explode(',', $share['search']);
}
$resourceRight = null;
if (isset($share['mask'])) {
$resourceRight = new ResourceRights();
$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'])) {
error_log('only_me');
$repository->addResourceOnlyToMe($resourceNode);
} else {
error_log('others');
// To other users
$repository->addResourceToUserList($resourceNode, $idList);
}
break;
case 'group':
// @todo
break;
}
}
/** @var Local $adapter */
$adapter = $fs->getAdapter();
$filePath = $adapter->getPathPrefix().$path;
$newResource
->setCId($course->getId())
->setPath('/a')
->setFiletype('file')
->setSize('12')
//->setTitle($title)
//->setComment($comment)
->setReadonly(false)
->setSessionId(0)
->setResourceNode($resourceNode)
;
$response = new BinaryFileResponse($filePath);
$this->repository->add($newResource);
// To generate a file download, you need the mimetype of the file
$mimeTypeGuesser = new FileinfoMimeTypeGuesser();
$postEvent = $this->eventDispatcher->dispatchPostEvent(ResourceActions::CREATE, $configuration, $newResource);
// Set the mimetype with the guesser or manually
if ($mimeTypeGuesser->isSupported()) {
// Guess the mimetype of the file according to the extension of the file
$response->headers->set('Content-Type', $mimeTypeGuesser->guess($filePath));
} else {
// Set the mimetype of the file manually, in this case for a text file is text/plain
$response->headers->set('Content-Type', 'text/plain');
if (!$configuration->isHtmlRequest()) {
return $this->viewHandler->handle($configuration, View::create($newResource, Response::HTTP_CREATED));
}
$response->setContentDisposition(
ResponseHeaderBag::DISPOSITION_ATTACHMENT,
basename($filePath)
);
$this->addFlash('success', 'saved');
return $response;
//$this->flashHelper->addSuccessFlash($configuration, ResourceActions::CREATE, $newResource);
} catch (\InvalidArgumentException $e) {
return $this->abort();
if ($postEvent->hasResponse()) {
return $postEvent->getResponse();
}
return $this->redirectHandler->redirectToResource($configuration, $newResource);
}
if (!$configuration->isHtmlRequest()) {
return $this->viewHandler->handle($configuration, View::create($form, Response::HTTP_BAD_REQUEST));
}
$initializeEvent = $this->eventDispatcher->dispatchInitializeEvent(ResourceActions::CREATE, $configuration, $newResource);
if ($initializeEvent->hasResponse()) {
return $initializeEvent->getResponse();
}
$view = View::create()
->setData([
'configuration' => $configuration,
'metadata' => $this->metadata,
'resource' => $newResource,
$this->metadata->getName() => $newResource,
'form' => $form->createView(),
])
->setTemplate($configuration->getTemplate(ResourceActions::CREATE . '.html'))
;
return $this->viewHandler->handle($configuration, $view);
}
/**
* Gets a document in browser courses/MATHS/document/file.jpg to the user.
* @Route("/get/{course}/", name="resource_get", methods={"GET"}, options={"expose"=true})
* @todo check permissions
* @param Request $request
*
* @param string $course
* @return Response
*/
public function showAction(Request $request): Response
{
$configuration = $this->requestConfigurationFactory->create($this->metadata, $request);
$this->isGrantedOr403($configuration, ResourceActions::SHOW);
/** @var AbstractResource $resource */
$resource = $this->findOr404($configuration);
$resourceNode = $resource->getResourceNode();
$this->eventDispatcher->dispatch(ResourceActions::SHOW, $configuration, $resource);
$this->denyAccessUnlessGranted(
ResourceNodeVoter::VIEW,
$resourceNode,
'Unauthorised access to resource'
);
$view = View::create($resource);
if ($configuration->isHtmlRequest()) {
$view
->setTemplate($configuration->getTemplate(ResourceActions::SHOW . '.html'))
->setTemplateVar($this->metadata->getName())
->setData([
'configuration' => $configuration,
'metadata' => $this->metadata,
'resource' => $resource,
$this->metadata->getName() => $resource,
])
;
}
return $this->viewHandler->handle($configuration, $view);
}
/**
* @param Request $request
*
* @return \Symfony\Component\HttpKernel\Exception\NotFoundHttpException
* @return Response
*/
public function getFileAction(Request $request, $course)
public function updateAction(Request $request): Response
{
try {
/** @var Filesystem $fs */
$fs = $this->container->get('oneup_flysystem.courses_filesystem');
$file = $request->get('file');
$configuration = $this->requestConfigurationFactory->create($this->metadata, $request);
$path = $course.'/document/'.$file;
$this->isGrantedOr403($configuration, ResourceActions::UPDATE);
$resource = $this->findOr404($configuration);
$resourceNode = $resource->getResourceNode();
// Has folder
if (!$fs->has($course)) {
return $this->abort();
$this->denyAccessUnlessGranted(
ResourceNodeVoter::EDIT,
$resourceNode,
'Unauthorised access to resource'
);
$form = $this->resourceFormFactory->create($configuration, $resource);
if (in_array($request->getMethod(), ['POST', 'PUT', 'PATCH'], true) && $form->handleRequest($request)->isValid()) {
$resource = $form->getData();
/** @var ResourceControllerEvent $event */
$event = $this->eventDispatcher->dispatchPreEvent(ResourceActions::UPDATE, $configuration, $resource);
if ($event->isStopped() && !$configuration->isHtmlRequest()) {
throw new HttpException($event->getErrorCode(), $event->getMessage());
}
if ($event->isStopped()) {
$this->flashHelper->addFlashFromEvent($configuration, $event);
if ($event->hasResponse()) {
return $event->getResponse();
}
// Has file
if (!$fs->has($path)) {
return $this->abort();
return $this->redirectHandler->redirectToResource($configuration, $resource);
}
/** @var Local $adapter */
$adapter = $fs->getAdapter();
$filePath = $adapter->getPathPrefix().$path;
try {
$this->resourceUpdateHandler->handle($resource, $configuration, $this->manager);
} catch (UpdateHandlingException $exception) {
if (!$configuration->isHtmlRequest()) {
return $this->viewHandler->handle(
$configuration,
View::create($form, $exception->getApiResponseCode())
);
}
return $this->file($filePath, null, ResponseHeaderBag::DISPOSITION_INLINE);
$this->flashHelper->addErrorFlash($configuration, $exception->getFlash());
} catch (\InvalidArgumentException $e) {
return $this->abort();
return $this->redirectHandler->redirectToReferer($configuration);
}
$postEvent = $this->eventDispatcher->dispatchPostEvent(ResourceActions::UPDATE, $configuration, $resource);
if (!$configuration->isHtmlRequest()) {
$view = $configuration->getParameters()->get('return_content', false) ? View::create($resource, Response::HTTP_OK) : View::create(null, Response::HTTP_NO_CONTENT);
return $this->viewHandler->handle($configuration, $view);
}
$this->flashHelper->addSuccessFlash($configuration, ResourceActions::UPDATE, $resource);
if ($postEvent->hasResponse()) {
return $postEvent->getResponse();
}
return $this->redirectHandler->redirectToResource($configuration, $resource);
}
if (!$configuration->isHtmlRequest()) {
return $this->viewHandler->handle($configuration, View::create($form, Response::HTTP_BAD_REQUEST));
}
$initializeEvent = $this->eventDispatcher->dispatchInitializeEvent(ResourceActions::UPDATE, $configuration, $resource);
if ($initializeEvent->hasResponse()) {
return $initializeEvent->getResponse();
}
$view = View::create()
->setData([
'configuration' => $configuration,
'metadata' => $this->metadata,
'resource' => $resource,
$this->metadata->getName() => $resource,
'form' => $form->createView(),
])
->setTemplate($configuration->getTemplate(ResourceActions::UPDATE . '.html'))
;
return $this->viewHandler->handle($configuration, $view);
}
}

@ -0,0 +1,151 @@
<?php
/* For licensing terms, see /license.txt */
namespace Chamilo\CoreBundle\Controller;
use Chamilo\CoreBundle\Repository\ResourceRepository;
use Chamilo\CoreBundle\Entity\Resource\ResourceLink;
use Chamilo\CoreBundle\Entity\Resource\ResourceNode;
use Chamilo\CoreBundle\Entity\Resource\ResourceRights;
use League\Flysystem\Adapter\Local;
use League\Flysystem\Filesystem;
use APY\DataGridBundle\Grid\Action\MassAction;
use APY\DataGridBundle\Grid\Action\RowAction;
use Symfony\Component\HttpFoundation\BinaryFileResponse;
use Symfony\Component\HttpFoundation\File\MimeType\FileinfoMimeTypeGuesser;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\ResponseHeaderBag;
use Symfony\Component\Routing\Annotation\Route;
use APY\DataGridBundle\Grid\Source\Entity;
use FOS\RestBundle\View\View;
use Sylius\Component\Resource\ResourceActions;
use Chamilo\CoreBundle\Security\Authorization\Voter\ResourceNodeVoter;
/**
* Class ResourceController.
*
* @author Julio Montoya <gugli100@gmail.com>.
*
* @Route("/resource")
*
* @package Chamilo\CoreBundle\Controller
*/
class ResourceDownloadController extends BaseController
{
/**
* Upload form
* @Route("/upload/{type}/{id}", name="resource_upload", methods={"GET", "POST"}, options={"expose"=true})
*
* @return Response
*/
public function showUploadFormAction($type, $id): Response
{
//$helper = $this->container->get('oneup_uploader.templating.uploader_helper');
//$endpoint = $helper->endpoint('courses');
return $this->render(
'@ChamiloCore/Resource/upload.html.twig',
[
'identifier' => $id,
'type' => $type,
]
);
}
/**
* Downloads the file courses/MATHS/document/file.jpg to the user.
* @Route("/download/{course}/", name="resource_download", methods={"GET"}, options={"expose"=true})
* @todo check permissions
*
* @param string $course
*
* @return \Symfony\Component\HttpKernel\Exception\NotFoundHttpException
*/
public function downloadFileAction(Request $request, $course)
{
try {
/** @var Filesystem $fs */
$fs = $this->container->get('oneup_flysystem.courses_filesystem');
$file = $request->get('file');
$path = $course.'/document/'.$file;
// Has folder
if (!$fs->has($course)) {
return $this->abort();
}
// Has file
if (!$fs->has($path)) {
return $this->abort();
}
/** @var Local $adapter */
$adapter = $fs->getAdapter();
$filePath = $adapter->getPathPrefix().$path;
$response = new BinaryFileResponse($filePath);
// To generate a file download, you need the mimetype of the file
$mimeTypeGuesser = new FileinfoMimeTypeGuesser();
// Set the mimetype with the guesser or manually
if ($mimeTypeGuesser->isSupported()) {
// Guess the mimetype of the file according to the extension of the file
$response->headers->set('Content-Type', $mimeTypeGuesser->guess($filePath));
} else {
// Set the mimetype of the file manually, in this case for a text file is text/plain
$response->headers->set('Content-Type', 'text/plain');
}
$response->setContentDisposition(
ResponseHeaderBag::DISPOSITION_ATTACHMENT,
basename($filePath)
);
return $response;
} catch (\InvalidArgumentException $e) {
return $this->abort();
}
}
/**
* Gets a document in browser courses/MATHS/document/file.jpg to the user.
* @Route("/get/{course}/", name="resource_get", methods={"GET"}, options={"expose"=true})
* @todo check permissions
*
* @param string $course
*
* @return \Symfony\Component\HttpKernel\Exception\NotFoundHttpException
*/
public function getFileAction(Request $request, $course)
{
try {
/** @var Filesystem $fs */
$fs = $this->container->get('oneup_flysystem.courses_filesystem');
$file = $request->get('file');
$path = $course.'/document/'.$file;
// Has folder
if (!$fs->has($course)) {
return $this->abort();
}
// Has file
if (!$fs->has($path)) {
return $this->abort();
}
/** @var Local $adapter */
$adapter = $fs->getAdapter();
$filePath = $adapter->getPathPrefix().$path;
return $this->file($filePath, null, ResponseHeaderBag::DISPOSITION_INLINE);
} catch (\InvalidArgumentException $e) {
return $this->abort();
}
}
}

@ -22,8 +22,11 @@ class CourseListener
protected $toolChain;
protected $settingsManager;
/**
* @param ToolChain $toolChain
/***
* CourseListener constructor.
*
* @param ToolChain $toolChain
* @param SettingsManager $settingsManager
*/
public function __construct(ToolChain $toolChain, SettingsManager $settingsManager)
{

@ -4,72 +4,19 @@
namespace Chamilo\CoreBundle\Entity\Resource;
use Doctrine\ORM\Mapping as ORM;
use Sylius\Component\Resource\Model\ResourceInterface;
/**
* @ORM\MappedSuperclass
* @ORM\HasLifecycleCallbacks
*/
abstract class AbstractResource
abstract class AbstractResource implements ResourceInterface
{
/**
* @ORM\Id
* @ORM\Column(type="integer")
* @ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* @var string
*
* @ORM\Column(name="name", type="string", length=255, precision=0, scale=0, nullable=false, unique=false)
*/
protected $name;
/**
* @ORM\OneToOne(targetEntity="Chamilo\CoreBundle\Entity\Resource\ResourceNode", cascade={"remove"})
* @ORM\JoinColumn(name="resource_node_id")
* @ORM\JoinColumn(name="resource_node_id", referencedColumnName="id")
*/
protected $resourceNode;
/**
* Returns the resource id.
*
* @return int
*/
public function getId()
{
return $this->id;
}
/**
* Sets the resource id.
*
* @param int $id
*/
public function setId($id)
{
$this->id = $id;
}
/**
* Returns the resource name.
*
* @return string
*/
public function getName()
{
return $this->name;
}
/**
* Returns the resource name.
*
* @return string
*/
public function setName($name)
{
$this->name = $name;
}
public $resourceNode;
/**
* @ORM\PrePersist()
@ -88,10 +35,14 @@ abstract class AbstractResource
/**
* @param ResourceNode $resourceNode
*
* @return $this
*/
public function setResourceNode(ResourceNode $resourceNode)
public function setResourceNode(ResourceNode $resourceNode): self
{
$this->resourceNode = $resourceNode;
return $this;
}
/**

@ -0,0 +1,25 @@
<?php
/* For licensing terms, see /license.txt */
namespace Chamilo\CoreBundle\Entity\Resource;
/**
* Interface ResourceInterface.
*
* @package Chamilo\CoreBundle\Entity\Resource
*/
interface ResourceInterface
{
public function setResourceNode(ResourceNode $resourceNode);
public function getResourceNode();
/**
* Returns the resource id.
*
* @return int
*/
public function getResourceIdentifier(): int;
public function getResourceName(): string;
public function getToolName(): string;
//"getName()", "name()", "isName()", "hasName()", "__get()"
}

@ -223,24 +223,12 @@ class ResourceLink implements ResourceInterface
return $this->id;
}
/**
* @param int $id
*
* @return $this
*/
public function setId($id)
{
$this->id = $id;
return $this;
}
/**
* @param User $user
*
* @return $this
*/
public function setUser(User $user)
public function setUser(User $user = null)
{
$this->user = $user;
@ -252,7 +240,7 @@ class ResourceLink implements ResourceInterface
*
* @return $this
*/
public function setCourse(Course $course)
public function setCourse(Course $course = null)
{
$this->course = $course;
@ -264,7 +252,7 @@ class ResourceLink implements ResourceInterface
*
* @return $this
*/
public function setSession(Session $session)
public function setSession(Session $session = null)
{
$this->session = $session;
@ -284,7 +272,7 @@ class ResourceLink implements ResourceInterface
*
* @return $this
*/
public function setGroup(CGroupInfo $group)
public function setGroup(CGroupInfo $group = null)
{
$this->group = $group;
@ -304,7 +292,7 @@ class ResourceLink implements ResourceInterface
*
* @return $this
*/
public function setUserGroup(Usergroup $group)
public function setUserGroup(Usergroup $group = null)
{
$this->userGroup = $group;

@ -28,6 +28,13 @@ class ResourceNode
*/
protected $id;
/**
* @Gedmo\TreePathSource
* @ORM\Column()
* @Assert\NotBlank()
*/
protected $name;
/**
* @ORM\ManyToOne(targetEntity="Chamilo\CoreBundle\Entity\Tool")
* @ORM\JoinColumn(name="tool_id", referencedColumnName="id")
@ -55,13 +62,6 @@ class ResourceNode
*/
protected $creator;
/**
* @Gedmo\TreePathSource
* @ORM\Column()
* @Assert\NotBlank()
*/
protected $name;
/**
* @Gedmo\TreeParent
* @ORM\ManyToOne(
@ -146,21 +146,33 @@ class ResourceNode
return $this;
}
/**
* @param \DateTime|null $updatedAt
*/
public function setUpdatedAt(\DateTime $updatedAt = null)
{
$this->updatedAt = $updatedAt;
}
/**
* @return mixed
*/
public function getUpdatedAt()
{
return $this->updatedAt;
}
/**
* @param \DateTime|null $createdAt
*/
public function setCreatedAt(\DateTime $createdAt = null)
{
$this->createdAt = $createdAt;
}
/**
* @return mixed
*/
public function getCreatedAt()
{
return $this->createdAt;

@ -7,7 +7,7 @@ use Chamilo\CoreBundle\Security\Authorization\Voter\ResourceNodeVoter;
use Doctrine\ORM\Mapping as ORM;
/**
* Tool.
* ToolResourceRights.
*
* @ORM\Table(name="tool_resource_rights")
* @ORM\Entity
@ -115,7 +115,7 @@ class ToolResourceRights
*
* @return int
*/
public function getId()
public function getId(): int
{
return $this->id;
}
@ -123,25 +123,25 @@ class ToolResourceRights
/**
* @return array
*/
public static function getDefaultRoles()
public static function getDefaultRoles(): array
{
return [
'ROLE_STUDENT' => 'Students',
'ROLE_TEACHER' => 'Teachers',
'Students' => 'ROLE_STUDENT',
'Teachers'=> 'ROLE_TEACHER',
];
}
/**
* @return array
*/
public static function getMaskList()
public static function getMaskList(): array
{
$readerMask = ResourceNodeVoter::getReaderMask();
$editorMask = ResourceNodeVoter::getEditorMask();
return [
$readerMask => 'Can read',
$editorMask => 'Can edit',
'Can read' => $readerMask,
'Can edit' => $editorMask ,
];
}
}

@ -0,0 +1,86 @@
<?php
/* For licensing terms, see /license.txt */
namespace Chamilo\CoreBundle\Form\Type;
use Chamilo\CourseBundle\Entity\CDocument;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Symfony\Component\Form\Extension\Core\Type\HiddenType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
/**
* Class DocumentType
* @package Chamilo\NotebookBundle\Form\Type
*/
class DocumentType extends AbstractType
{
/**
* {@inheritdoc}
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('title')
->add('comment', 'ckeditor')
->add(
'shared',
ChoiceType::class,
array(
'choices' => array(
'This course' => 'this_course',
'Only me' => 'only_me',
'Shared' => 'shared',
),
'multiple' => false,
'expanded' => true,
'required' => true,
'mapped' => false,
)
)
->add(
'rights',
'collection',
array(
'entry_type' => ResourceLinkType::class,
'mapped' => false,
'allow_add' => true,
'by_reference' => false,
'allow_delete' => true,
)
)
->add('c_id', HiddenType::class)
/*->add(
'rights',
'collection',
array(
'type' => new ResourceRightsType(),
'mapped' => false,
'allow_add' => true,
)
)*/
//->add('resourceNode', new ResourceNodeType())
->add('save', 'submit');
}
/**
* {@inheritdoc}
*/
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(
array(
'data_class' => CDocument::class,
)
);
}
/**
* {@inheritdoc}
*/
public function getName()
{
return 'chamilo_document';
}
}

@ -0,0 +1,92 @@
<?php
/* For licensing terms, see /license.txt */
namespace Chamilo\CoreBundle\Form\Type;
use Chamilo\CoreBundle\Entity\ToolResourceRights;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
/**
* Class ResourceLinkType
* @package Chamilo\CoreBundle\Form\Type
*/
class ResourceLinkType extends AbstractType
{
/**
* {@inheritdoc}
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add(
'sharing',
ChoiceType::class,
array(
'choices' => array(
'everyone' => 'Everyone',
'course' => 'Course',
'user' => 'User',
'group' => 'Group',
),
'attr' => array('class' => 'sharing_options'),
'mapped' => false
)
)
->add(
'search',
'hidden',
array(
'attr' => array('class' => 'extra_hidden'),
'mapped' => false
)
)
->add(
'role',
ChoiceType::class,
array(
'choices' => ToolResourceRights::getDefaultRoles(),
'mapped' => false
)
)
->add(
'mask',
ChoiceType::class,
array(
'choices' => ToolResourceRights::getMaskList(),
'mapped' => false
)
)/*->add(
'rights',
'collection',
array(
'type' => new ResourceRightsType(),
'allow_add' => true,
)
)*/
;
}
/**
* {@inheritdoc}
*/
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(
array(
'data_class' => 'Chamilo\CoreBundle\Entity\Resource\ResourceLink',
)
);
}
/**
* {@inheritdoc}
*/
public function getName()
{
return 'chamilo_resource_link_type';
}
}

@ -0,0 +1,51 @@
<?php
/* For licensing terms, see /license.txt */
namespace Chamilo\CoreBundle\Form\Type;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
/**
* Class ResourceNodeType
* @package Chamilo\NotebookBundle\Form\Type
*/
class ResourceNodeType extends AbstractType
{
/**
* {@inheritdoc}
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('tool')
->add(
'links',
'collection',
array(
'type' => new ResourceLinkType(),
)
);
}
/**
* {@inheritdoc}
*/
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(
array(
'data_class' => 'Chamilo\CoreBundle\Entity\Resource\ResourceNode',
)
);
}
/**
* {@inheritdoc}
*/
public function getName()
{
return 'chamilo_resource_node_type';
}
}

@ -0,0 +1,54 @@
<?php
/* For licensing terms, see /license.txt */
namespace Chamilo\CoreBundle\Form\Type;
use Chamilo\CoreBundle\Entity\ToolResourceRights;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
/**
* Class ResourceRightsType
* @package Chamilo\NotebookBundle\Form\Type
*/
class ResourceRightsType extends AbstractType
{
/**
* {@inheritdoc}
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add(
'role',
'choice',
array('choices' => ToolResourceRights::getDefaultRoles())
)
->add(
'mask',
'choice',
array('choices' => ToolResourceRights::getMaskList())
);
}
/**
* {@inheritdoc}
*/
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(
array(
'data_class' => 'Chamilo\CoreBundle\Entity\Resource\ResourceRights',
)
);
}
/**
* {@inheritdoc}
*/
public function getName()
{
return 'chamilo_resource_rights_type';
}
}

@ -1,7 +1,7 @@
<?php
/* For licensing terms, see /license.txt */
namespace Chamilo\CoreBundle\Entity;
namespace Chamilo\CoreBundle\Repository;
use Chamilo\CoreBundle\Entity\Course;
use Chamilo\CoreBundle\Entity\Resource\ResourceLink;
@ -19,8 +19,9 @@ use Doctrine\Common\Collections\ArrayCollection;
use Sylius\Bundle\ResourceBundle\Doctrine\ORM\EntityRepository;
/**
* Class NotebookRepository
* @package Chamilo\NotebookBundle\Entity
* Class ResourceRepository.
*
* @package Chamilo\CoreBundle\Entity
*/
class ResourceRepository extends EntityRepository
{
@ -35,10 +36,13 @@ class ResourceRepository extends EntityRepository
public function addResourceNode(AbstractResource $resource, User $creator): ResourceNode
{
$resourceNode = new ResourceNode();
$tool = $this->getTool($resource->getToolName());
$resourceNode
->setName($resource->getName())
->setName($resource->getResourceName())
->setCreator($creator)
->setTool($this->getTool());
->setTool($tool);
$this->getEntityManager()->persist($resourceNode);
$this->getEntityManager()->flush();
@ -51,7 +55,7 @@ class ResourceRepository extends EntityRepository
*
* @return ResourceLink
*/
public function addResourceOnlyToMe(ResourceNode $resourceNode)
public function addResourceOnlyToMe(ResourceNode $resourceNode): ResourceLink
{
$resourceLink = new ResourceLink();
$resourceLink
@ -70,7 +74,7 @@ class ResourceRepository extends EntityRepository
*
* @return ResourceLink
*/
public function addResourceToEveryone(ResourceNode $resourceNode, ResourceRights $right)
public function addResourceToEveryone(ResourceNode $resourceNode, ResourceRights $right): ResourceLink
{
$resourceLink = new ResourceLink();
$resourceLink
@ -124,15 +128,14 @@ class ResourceRepository extends EntityRepository
*/
public function addResourceToUserList(ResourceNode $resourceNode, $userList)
{
$em = $this->getEntityManager();
if (!empty($userList)) {
foreach ($userList as $userId) {
$toUser = $this->getEntityManager()->getRepository('ChamiloUserBundle:User')->find($userId);
$toUser = $em->getRepository('ChamiloUserBundle:User')->find($userId);
$resourceLink = $this->addResourceNodeToUser(
$resourceNode,
$toUser
);
$this->getEntityManager()->persist($resourceLink);
$resourceLink = $this->addResourceNodeToUser($resourceNode, $toUser);
$em->persist($resourceLink);
}
}
}
@ -143,7 +146,7 @@ class ResourceRepository extends EntityRepository
*
* @return ResourceLink
*/
public function addResourceNodeToUser(ResourceNode $resourceNode, User $toUser)
public function addResourceNodeToUser(ResourceNode $resourceNode, User $toUser): ResourceLink
{
$resourceLink = new ResourceLink();
$resourceLink
@ -227,7 +230,7 @@ class ResourceRepository extends EntityRepository
* @param Course $course
* @return ResourceLink
*/
public function getResourceByCourse(Course $course)
public function getResourceByCourse(Course $course, Tool $tool)
{
$query = $this->getEntityManager()->createQueryBuilder()
->select('resource')
@ -241,7 +244,7 @@ class ResourceRepository extends EntityRepository
//->orderBy('node');
->setParameters(
array(
'tool' => $this->getTool(),
'tool' => $tool,
'course' => $course,
)
)
@ -267,13 +270,15 @@ class ResourceRepository extends EntityRepository
}
/**
* @return Tool
* @param $tool
*
* @return Tool|null
*/
public function getTool()
public function getTool($tool)
{
return $this
->getEntityManager()
->getRepository('ChamiloCoreBundle:Tool')
->findOneBy(['name' => $this->getToolName()]);
->findOneBy(['name' => $tool]);
}
}

@ -38,9 +38,9 @@ core_admin:
prefix: /admin
# Redirects /url/ to /url always located at the end
remove_trailing_slash:
path: /{url}
defaults: {_controller: 'ChamiloCoreBundle:Redirecting:removeTrailingSlash'}
requirements:
url: .*/$
_method: GET
#remove_trailing_slash:
# path: /{url}
# defaults: {_controller: 'ChamiloCoreBundle:Redirecting:removeTrailingSlash'}
# requirements:
# url: .*/$
# _method: GET

@ -0,0 +1,197 @@
{% extends "@ChamiloTheme/Layout/layout_one_col.html.twig" %}
{% block content %}
<script>
var $collectionHolder;
// setup an "add a tag" link
var $addTagLink = $('<a href="#" class="btn btn-success add_tag_link">Add</a>');
var $newLinkLi = $('<li></li>').append($addTagLink);
jQuery(document).ready(function () {
// Get the ul that holds the collection of tags
$collectionHolder = $('ul.tags');
// add a delete link to all of the existing tag form li elements
$collectionHolder.find('li').each(function () {
addTagFormDeleteLink($(this));
});
// add the "add a tag" anchor and li to the tags ul
$collectionHolder.append($newLinkLi);
// count the current form inputs we have (e.g. 2), use that as the new
// index when inserting a new item (e.g. 2)
$collectionHolder.data('index', $collectionHolder.find(':input').length);
$addTagLink.on('click', function (e) {
// prevent the link from creating a "#" on the URL
e.preventDefault();
// add a new tag form (see next code block)
addTagForm($collectionHolder, $newLinkLi);
});
// This course
$('#chamilo_notebook_notebook_shared_0').on('click', function () {
$('#rights').hide();
});
// Only me
$('#chamilo_notebook_notebook_shared_1').on('click', function () {
$('#rights').hide();
});
// Shared
$('#chamilo_notebook_notebook_shared_2').on('click', function () {
$('#rights').show();
});
});
function repoFormatResult(repo) {
console.log(repo);
var markup = '<div class="row-fluid">' +
'<div class="span2"><img src="' + repo.owner.avatar_url + '" /></div>' +
'<div class="span10">' +
'<div class="row-fluid">' +
'<div class="span6">' + repo.full_name + '</div>' +
'<div class="span3"><i class="fa fa-code-fork"></i> ' + repo.forks_count + '</div>' +
'<div class="span3"><i class="fa fa-star"></i> ' + repo.stargazers_count + '</div>' +
'</div>';
if (repo.description) {
markup += '<div>' + repo.description + '</div>';
}
markup += '</div></div>';
return markup;
}
function addTagFormDeleteLink($tagFormLi) {
var $removeFormA = $('<a href="#" class="btn btn-danger">Delete</a>');
$tagFormLi.append($removeFormA);
$removeFormA.on('click', function (e) {
// prevent the link from creating a "#" on the URL
e.preventDefault();
// remove the li for the tag form
$tagFormLi.remove();
});
}
function addTagForm($collectionHolder, $newLinkLi) {
// Get the data-prototype explained earlier
var prototype = $collectionHolder.data('prototype');
// get the new index
var index = $collectionHolder.data('index');
// Replace '__name__' in the prototype's HTML to
// instead be a number based on how many items we have
var newForm = prototype.replace(/__name__/g, index);
// increase the index with one for the next item
$collectionHolder.data('index', index + 1);
// Display the form in the page in an li, before the "Add a tag" link li
var $newFormLi = $('<li></li>').append(newForm);
$newLinkLi.before($newFormLi);
addTagFormDeleteLink($newFormLi);
$('.sharing_options').on('change', function () {
var inputId = this.id;
var hiddenInputId = inputId.replace("sharing", "search");
var roleId = inputId.replace("sharing", "role");
var selectRow = $('#' + hiddenInputId);
var select2 = $('#s2id_' + hiddenInputId);
var roleRow = $('#' + roleId).parent();
var url = '';
switch (this.value) {
case 'everyone':
roleRow.hide();
break;
case 'course':
selectRow.show();
select2.show();
roleRow.show();
url = Routing.generate('chamilo_core_user_user_mycourses');
break;
case 'user':
selectRow.show();
select2.show();
roleRow.hide();
url = Routing.generate('chamilo_core_user_user_mycourses');
break;
case 'group':
selectRow.show();
select2.show();
roleRow.hide();
url = Routing.generate('chamilo_core_user_user_mycourses');
break;
default:
selectRow.hide();
select2.hide();
break;
}
if (url != '') {
selectRow.select2({
tags: true,
tokenSeparators: [',', ' '],
ajax: {
url: url,
dataType: 'json',
type: "GET",
delay: 250,
data: function (params) {
return {
q: params.term, // search term
page: params.page
};
},
results: function (data, page) {
data = data.items;
return {
results: $.map(data, function (item) {
return {
text: item.title,
slug: item.title,
id: item.id
}
})
};
}
}
});
}
});
}
</script>
<div class="box box-primary">
<div class="box-header">
<h3 class="box-title">Create</h3>
</div>
<form method="post"
action="{{ path('app_document_create', {'c_id': course.id }) }}">
<div class="box-body">
{{ form_start(form) }}
{{ form_row(form.title) }}
{{ form_row(form.comment) }}
{{ form_row(form.c_id) }}
{{ form_row(form.shared) }}
<ul id="rights" class="tags"
data-prototype="{{ form_widget(form.rights.vars.prototype)|e }}">
</ul>
{{ form_end(form) }}
</div>
</form>
</div>
{% endblock %}

@ -0,0 +1,21 @@
{% extends 'ChamiloCoreBundle::grid.html.twig' %}
{% block grid_column_id_cell %}
<a href="{{ url('app_document_show', {'id': row.getField('id'), 'course': course }) }}">
{{ row.getField('id') }}
</a>
{% endblock %}
{% block grid_column_name_cell %}
<a href="{{ url('app_document_show', {'id': row.getField('id'), 'course': course }) }}">
{{ value }}
</a>
{% endblock %}
{#{% block grid_column_actions_cell %}#}
{#<div class="btn-group">#}
{#{{ parent() }}#}
{#</div>#}
{#{% endblock grid_column_actions_cell %}#}

@ -0,0 +1,147 @@
{% extends "@ChamiloTheme/Layout/layout_one_col.html.twig" %}
{% block content %}
<style>
.grid table
{
font-family: "Trebuchet MS", Arial, Helvetica, sans-serif;
border-collapse: collapse;
color: #555555;
font-size: 1em;
width: 100%;
}
.grid td, .grid th
{
border: 1px solid #D4E0EE;
padding: 3px 7px 2px 7px;
}
.grid th
{
background-color: #E6EDF5;
vertical-align: top;
}
.grid th a {
color: #4F76A3;
text-decoration: none;
}
.grid th a.grid-reset {
margin-left: 5px;
font-weight: normal;
}
.grid tr.even
{
background-color: #FCFDFE;
}
.grid tr.odd {
background-color: #F7F9FC;
}
.grid_header, .grid_footer {
margin: 5px 0;
}
/* Icons for order */
/* You can find this icons in the images directory of the docuementation */
th div {
height: 10px;
width: 20px;
float: right;
padding-top: 4px;
}
.grid th div.sort_up {
background: transparent url("data:image/gif;base64,R0lGODlhFwAKAIABAJCQkO/v7yH+EUNyZWF0ZWQgd2l0aCBHSU1QACH5BAEKAAEALAAAAAAXAAoAAAIajI+py+0GwGsxTmVDvlqe/YCQ52wmyaXqUQAAOw==") no-repeat bottom left;
}
.grid th div.sort_down {
background: transparent url("data:image/gif;base64,R0lGODlhFwAKAHAAACH5BAEAAAIALAAAAAAXAAoAgQAAAJCQkAAAAAAAAAIalI+py60RDpTRiZmwvdXozXkdKH6keKZqUwAAOw==") no-repeat bottom left;
}
/* Boolean column */
.grid .grid_boolean_true {
background: transparent url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAACl0lEQVR42q2T60uTYRiH/Tv2bnttAwlkRCGChFD7FCQSm2ZDMQ/L0nRnj7TNGDbTooychzFSSssstdqc8zB1anNrSpm47FVCzH3pQLVhdLBfzztoJlifvOEHz4fnuu7nGBe311XgOyLMnTmsz/akMBljB8OSEVFY4kpkJM5Efbp9v/C/cJ43VSrzJId0HhluBy3oW+mKpnOpGSWuExD30iFxDy3dFSZdpZkTSZHr80Y41/phe3UDpvnKaNixY60PjbNVOGTjRZJtvJ2SHE+KINOdtMHC7MSaQBkq/CXQzJ6DjqScpNp3HvY3D3B5ugIiC3dDdJMriAlk7iSDajwr2pmFWVDlPQPFTCEU0wVQTxfCvT4Ig1cJB5Hk9hxDwjWuISbIGBExncFmWINNqPAVQ/lUTsB8KKdIPPmYeOsCW6HIOtpeNMI234j4ei4TExy3J2w+Wr2L2oAGWm8RWckAlj4uQDVZiPH1oSj8c+sH2p5fgWGyGH3BTvCN1GZMIH5Ib/avdMPoV6HWr8Xnb5+i0Iev72KwZa4ealc29O6z6A92gF/zt6CHZm4tNKF98Sp0U3KYfdWIfP8Shbd+bcHy7BLKnFnQEEFLoA7tXjPoKmp7C6l3+Ab5QBrsq/dRPSmH2n0adTPlWH6/iLa5BpQOnoTCcQo6Zw7sr7uRbj0KupLaPsRkK09wgFyN2aPBY+YeKkfzoB3OgWpIBqWDDQtn48lyF4xDxeCrORu0mhLseAuJTVxpfAMVMbnL4CCS1oAZ+tEiXBiWo5VswU5gvbMIvFJOhMC7v8Z9DVwpbaJCkg4x2v1m9L60onfBCovXhLSWVPAVnBCt+gf8p+iLXCFtoPR0DcXwtZwwX8UJk44MiZ4upYR7/nt/A+w9sdKFchsrAAAAAElFTkSuQmCC") no-repeat bottom left;
display: inline-block;
text-indent: 16px;
width: 16px;
overflow: hidden;
}
.grid .grid_boolean_false {
background: transparent url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAACSElEQVR42q2Ty0vUURTHv/5SJ1SmUaGckUYdG5FyVdAicGMkFAXBtEl8gJseIP0FEVEtbNNiFm0iMMUgGKhVIUj0oqKFQ40N2TwwdewxOik6zcy953tbmD/HxFV9d/dwz+f7PXAO8I8q+bugb1xspjFdhuwlWUcSJL+SvEfhaPXgcHxbQOH6hYChCa6WlLvLm/eh1OkEAKjlJWSjUVjZpXlSBvbcehDaAshfOx8w5FB+t7eyosUPSU2DqWkAgOX2wvI0YPljFLmpD6sU6fPefhSyAbmr53wkXxTqvJ7KlhYUXo0BACou3wEArFzpB2hQ3t6JpcgkVqITKSHb/XefJCwAENHdWcux0WwMDI09GjUh2iA7/hjO1v0wVbUerVQ3AFgAoLXucfj9kNkkDA0oBkZzE4BKIAUin4hjV2sblFI9xYD6MpcLeiYJo2k7rksKhKi1ei4WR5mrBlrp+g2A0jBi7MZ1RzUV2RhB/YEIASG0VihKoOby6UVY7gY7qiji18txrDy8b7tTEaV7G5FNp6GVnitOMPwz8h47PI32Z1GEs/8Sqk6fBRUhmhAhHI0+fA+/g9Z62AYopUYKC6lUZjKCio7jNmQxeBMLwUGIrL1dJ07iRySMzMznlNZ6ZNMiTXZ3BCgy5DpwuLK6tQ25ZAK5WBzGGDiafHA0+ZCOhPHl9dgqyb6jTz+FtqzyxJkjASGDO2s87tq2g3C4qmEMkMss4tvEW2RmY/MkB449mwpte0xvTh1qJtlFYS8pm4+JHO18Hovjf+o3Xg+XX4ZLBPIAAAAASUVORK5CYII=") no-repeat bottom left;
display: inline-block;
text-indent: 16px;
width: 16px;
overflow: hidden;
}
/* Alignement */
.grid .align-left {
text-align: left;
}
.grid .align-center {
text-align: center;
}
.grid .align-right {
text-align: right;
}
/* Column filter */
.grid .grid-filter-operator select{
width: 70px;
}
.grid .grid-filter-input-query input, .grid .grid-filter-select-query select{
width: 50px;
}
.grid .grid-filter-input-query-to, .grid .grid-filter-select-query-to{
margin-left: 77px;
display: block;
}
/* Grid Search */
.grid-search {
border: 1px solid #D4E0EE;
padding: 10px;
}
.grid-search label{
width: 80px;
display: inline-block;
text-align: right;
}
.grid-search select, .grid-search .grid-filter-input-query input {
width: 150px;
}
</style>
{% if is_granted('ROLE_CURRENT_COURSE_TEACHER') %}
<div class="actions">
<a class="btn btn-default"
href="{{ url('app_document_create', { 'c_id': course.id }) }}">
{{ 'Add' | trans }}
</a>
</div>
{% endif %}
<div class="row">
{{ grid(grid, 'ChamiloCoreBundle:Document:grid.html.twig') }}
{{ grid_search(grid) }}
</div>
{# ajax #}
{#{{ grid_search(grid, 'APYDataGridBundle::blocks.html.twig') }}#}
{#{{ grid(grid, 'APYDataGridBundle::blocks_js.jquery.html.twig') }}#}
{% endblock %}

@ -0,0 +1,47 @@
{% extends "@ChamiloTheme/Layout/layout_one_col.html.twig" %}
{% block content %}
<h2>{{ resource.title }}</h2>
{{ resource.comment| raw }}
<div class="box box-solid">
<div class="box-header">
<i class="fa fa-info-circle"></i>
<h3 class="box-title">{{ 'Description' | trans }}</h3>
</div><!-- /.box-header -->
<div class="box-body">
<dl class="dl-horizontal">
<dt>{{ 'Creator' | trans }}</dt>
<dd>{{ resource.resourceNode.creator.username }}</dd>
<dt>{{ 'CreatedAt' | trans }}</dt>
<dd>{{ resource.resourceNode.createdAt | format_datetime }}</dd>
<dt>{{ 'UpdatedAt' | trans }}</dt>
<dd>{{ resource.resourceNode.updatedAt | format_datetime }}</dd>
<dt>{{ 'Shared' | trans }}</dt>
{% for link in resource.resourceNode.links %}
{% if link.private %}
<dd>Only with me</dd>
{% else %}
{% if link.course %}
<dd> {{ 'Course' | trans }} : {{ link.course.title }}
({{ link.course.code }})
</dd>
{% endif %}
{% if link.session %}
<dd> {{ 'Session' | trans }} : {{ link.session.title }}
({{ link.session.title }})
</dd>
{% endif %}
{% endif %}
{% for right in link.rights %}
{{ right.role }} - {{ right.mask }}
{% endfor %}
{% endfor %}
</dl>
</div><!-- /.box-body -->
</div>
{% endblock %}

@ -0,0 +1,10 @@
{% extends "@ChamiloTheme/Layout/layout_one_col.html.twig" %}
{% block content %}
<form method="post"
action="{{ path('app_document_update', {'c_id': course.id, 'id' : resource.iid } ) }}">
<input type="hidden" name="_method" value="PUT"/>
{{ form_widget(form) }}
</form>
{% endblock %}

@ -0,0 +1,139 @@
{% extends 'APYDataGridBundle::blocks.html.twig' %}
{% block grid_actions %}
<div class="mass-actions">
<div class="btn-group" role="group">
<span class="grid_massactions_helper">
<a class="btn btn-default" href="#"
onclick="return {{ grid.hash }}_markVisible(true);">{{ 'Select visible'|trans }}</a>
<a class="btn btn-default" href="#"
onclick="return {{ grid.hash }}_markVisible(false);">{{ 'Deselect visible'|trans }}</a>
<a class="btn btn-default" href="#"
onclick="return {{ grid.hash }}_markAll(true);">{{ 'Select all'|trans }}</a>
<a class="btn btn-default" href="#"
onclick="return {{ grid.hash }}_markAll(false);">{{ 'Deselect all'|trans }}</a>
<span class="mass-actions-selected"
id="{{ grid.hash }}_mass_action_selected"></span>
</span>
</div>
{% spaceless %}
<div style="float:right;" class="grid_massactions">
{{ 'Action'|trans }}
<input type="hidden" id="{{ grid.hash }}_mass_action_all"
name="{{ grid.hash }}[{{ constant('APY\\DataGridBundle\\Grid\\Grid::REQUEST_QUERY_MASS_ACTION_ALL_KEYS_SELECTED') }}]"
value="0"/>
<select name="{{ grid.hash }}[{{ constant('APY\\DataGridBundle\\Grid\\Grid::REQUEST_QUERY_MASS_ACTION') }}]">
<option value="-1"></option>
{% for key, massAction in grid.massActions %}
<option value="{{ key }}">{{ massAction.title|trans }}</option>
{% endfor %}
</select>
<input type="submit" value="{{ 'Submit Action'|trans }}"/>
</div>
{% endspaceless %}
</div>
{% endblock grid_actions %}
{# Bootstrap changes #}
{% block grid_column_actions_cell %}
{% set actions = column.getActionsToRender(row) %}
<div class="btn-group">
{% for action in actions %}
{% if action.attributes.form_delete is defined and action.attributes.form_delete %}
<div class="btn-group">
<form method="post" action="{{ url(action.route, column.routeParameters(row, action), false) }}">
<input type="hidden" name="_method" value="DELETE" />
<button type="submit" class="btn btn-danger">
{{ action.title|trans }}
</button>
</form>
</div>
{% else %}
<a class="btn btn-default"
href="{{ url(action.route, column.routeParameters(row, action), false) }}" target="{{ action.target }}"{% if action.confirm %} onclick="return confirm('{{ action.confirmMessage }}')"{% endif %}{% for name, value in action.attributes %} {{ name }}="{{ value }}" {% endfor %}>
{{ action.title|trans }}
</a>
{% endif %}
{% endfor %}
</div>
{% endblock grid_column_actions_cell %}
{% block grid %}
<div class="col-md-10">
<div class="box box-primary">
<div class="box-body table-responsive no-padding">
{% if grid.totalCount > 0 or grid.isFiltered or grid.noDataMessage is same as(false) %}
<form id="{{ grid.hash }}" action="{{ grid.routeUrl }}"
method="post">
<div class="grid_header">
{% if grid.massActions|length > 0 %}
{{ grid_actions(grid) }}
{% endif %}
</div>
<div class="grid_body">
<table class="table table-bordered table-striped">
{% if grid.isTitleSectionVisible %}
{{ grid_titles(grid) }}
{% endif %}
{% if grid.isFilterSectionVisible %}
{{ grid_filters(grid) }}
{% endif %}
{{ grid_rows(grid) }}
</table>
</div>
<div class="grid_footer">
{% if grid.isPagerSectionVisible %}
{{ grid_pager(grid) }}
{% endif %}
{% if grid.exports|length > 0 %}
{{ grid_exports(grid) }}
{% endif %}
{% if grid.tweaks|length > 0 %}
{{ grid_tweaks(grid) }}
{% endif %}
</div>
{% if withjs %}
{{ grid_scripts(grid) }}
{% endif %}
</form>
{% else %}
{{ grid_no_data(grid) }}
{% endif %}
</div>
</div>
</div>
{% endblock grid %}
{% block grid_search %}
{% if grid.isFilterSectionVisible %}
<div class="col-md-2">
<div class="box box-primary">
<div class="box-header">
<h4 class="box-title filter_legend inactive">Filters</h4>
</div>
<div class="box-body">
<form id="{{ grid.hash }}_search"
action="{{ grid.routeUrl }}" method="post">
{% for column in grid.columns %}
{% if column.isFilterable and column.type not in ['actions', 'massaction'] %}
{% set columnTitle = grid.prefixTitle ~ column.title %}
<div class="{{ cycle(['odd', 'even'], loop.index) }}">
<label>{{ columnTitle|trans }}</label>{{ grid_filter(column, grid, false)|raw }}
</div>
{% endif %}
{% endfor %}
<div class="grid-search-action"><input type="submit"
class="grid-search-submit"
value="{{ 'Search'|trans }}"/><input
type="button" class="grid-search-reset"
value="{{ 'Reset'|trans }}"
onclick="return {{ grid.hash }}_reset();"/>
</div>
</form>
</div>
</div>
</div>
{% endif %}
{% endblock grid_search %}

@ -7,6 +7,7 @@ use Chamilo\CoreBundle\Entity\Course;
use Chamilo\CoreBundle\Entity\Resource\ResourceLink;
use Chamilo\CoreBundle\Entity\Resource\ResourceNode;
use Chamilo\CoreBundle\Entity\Session;
use Symfony\Component\DependencyInjection\ContainerAwareTrait;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\Security\Acl\Permission\MaskBuilder;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
@ -31,9 +32,10 @@ class ResourceNodeVoter extends Voter
public const DELETE = 'DELETE';
public const EXPORT = 'EXPORT';
const ROLE_CURRENT_COURSE_TEACHER = 'ROLE_CURRENT_COURSE_TEACHER';
const ROLE_CURRENT_COURSE_STUDENT = 'ROLE_CURRENT_COURSE_STUDENT';
private $container;
public const ROLE_CURRENT_COURSE_TEACHER = 'ROLE_CURRENT_COURSE_TEACHER';
public const ROLE_CURRENT_COURSE_STUDENT = 'ROLE_CURRENT_COURSE_STUDENT';
protected $container;
/**
* Constructor.
@ -48,7 +50,7 @@ class ResourceNodeVoter extends Voter
/**
* @return int
*/
public static function getReaderMask()
public static function getReaderMask(): int
{
$builder = new MaskBuilder();
$builder
@ -61,7 +63,7 @@ class ResourceNodeVoter extends Voter
/**
* @return int
*/
public static function getEditorMask()
public static function getEditorMask(): int
{
$builder = new MaskBuilder();
$builder
@ -74,7 +76,7 @@ class ResourceNodeVoter extends Voter
/**
* {@inheritdoc}
*/
protected function supports($attribute, $subject)
protected function supports($attribute, $subject): bool
{
$options = [
self::VIEW,
@ -100,10 +102,9 @@ class ResourceNodeVoter extends Voter
/**
* {@inheritdoc}
*/
protected function voteOnAttribute($attribute, $resourceNode, TokenInterface $token)
protected function voteOnAttribute($attribute, $resourceNode, TokenInterface $token): bool
{
$user = $token->getUser();
// Make sure there is a user object (i.e. that the user is logged in)
if (!$user instanceof UserInterface) {
return false;
@ -114,16 +115,17 @@ class ResourceNodeVoter extends Voter
// Admins have access to everything
if ($authChecker->isGranted('ROLE_ADMIN')) {
// return true;
return true;
}
// Check if I'm the owner
/*$creator = $resourceNode->getCreator();
$creator = $resourceNode->getCreator();
if ($creator instanceof UserInterface &&
$user->getUsername() == $creator->getUsername()) {
$user->getUsername() === $creator->getUsername()) {
//return true;
}*/
return true;
}
// Checking possible links connected to this resource
$request = $this->container->get('request_stack')->getCurrentRequest();
@ -143,7 +145,7 @@ class ResourceNodeVoter extends Voter
// Check if resource was sent to the current user
if ($linkUser instanceof UserInterface &&
$linkUser->getUsername() == $creator->getUsername()
$linkUser->getUsername() === $creator->getUsername()
) {
$linkFound = true;
break;
@ -160,8 +162,8 @@ class ResourceNodeVoter extends Voter
$course = $this->container->get('chamilo_core.entity.manager.course_manager')->findOneByCode($courseCode);
if ($session instanceof Session &&
$course instanceof Course &&
$linkCourse->getCode() == $course->getCode() &&
$linkSession->getId() == $session->getId()
$linkCourse->getCode() === $course->getCode() &&
$linkSession->getId() === $session->getId()
) {
$linkFound = true;
break;
@ -172,7 +174,7 @@ class ResourceNodeVoter extends Voter
if ($linkCourse instanceof Course && !empty($courseCode)) {
$course = $this->container->get('chamilo_core.manager.course')->findOneByCode($courseCode);
if ($course instanceof Course &&
$linkCourse->getCode() == $course->getCode()
$linkCourse->getCode() === $course->getCode()
) {
$linkFound = true;
break;
@ -254,6 +256,7 @@ class ResourceNodeVoter extends Voter
foreach ($user->getRoles() as $role) {
if ($acl->isAllowed($role, $resource, $askedMask)) {
//dump('passed');
return true;
}

@ -1,4 +1,5 @@
<?php
/* For licensing terms, see /license.txt */
namespace Chamilo\CourseBundle\Controller;
@ -6,12 +7,16 @@ use Chamilo\CoreBundle\Entity\Course;
use Chamilo\CoreBundle\Entity\Session;
/**
* Interface ToolInterface
* This functions are loaded in the CourseListener.php.
* CourseControllerInterface.
* This interface provides getters and setters to a controller.
* This functions are loaded when the CourseListener.php fires when a c_id/cidReq/ or courses/XXX/ parameter and
* the controller implements this interface. See the ResourceController class as an example.
* is loaded in the URL.
*
*
* @package Chamilo\CourseBundle\Controller
*/
interface ToolInterface
interface CourseControllerInterface
{
/**
* @param Course $course

@ -0,0 +1,55 @@
<?php
/* For licensing terms, see /license.txt */
namespace Chamilo\CourseBundle\Controller;
use Chamilo\CoreBundle\Entity\Course;
use Chamilo\CoreBundle\Entity\Session;
/**
* Trait CourseControllerTrait.
* Implements the functions defined by the CourseControllerInterface
*
* @package Chamilo\CourseBundle\Controller
*/
trait CourseControllerTrait
{
protected $course;
protected $session;
/**
* @param Course $course
*
* @return mixed
*/
public function setCourse(Course $course)
{
$this->course = $course;
}
/**
* @param Session $session
*
* @return mixed
*/
public function setSession(Session $session)
{
$this->session = $session;
}
/**
* @return Course
*/
public function getCourse()
{
return $this->course;
}
/**
* @return Session
*/
public function getSession()
{
return $this->session;
}
}

@ -4,225 +4,13 @@
namespace Chamilo\CourseBundle\Controller;
use Chamilo\CoreBundle\Controller\BaseController;
use Chamilo\CoreBundle\Entity\Course;
use Chamilo\CoreBundle\Entity\Session;
use Knp\Menu\ItemInterface as MenuItemInterface;
use Symfony\Component\HttpFoundation\Request;
/**
* Each entity controller must extends this class.
*
* @abstract
*/
abstract class ToolBaseController extends BaseController implements ToolInterface
abstract class ToolBaseController extends BaseController implements CourseControllerInterface
{
protected $course;
protected $session;
/**
* {@inheritdoc}
*/
public function setCourse(Course $course)
{
$this->course = $course;
}
/**
* @return Course
*/
public function getCourse()
{
return $this->course;
}
/**
* {@inheritdoc}
*/
public function setSession(Session $session)
{
$this->session = $session;
}
/**
* @return Session
*/
public function getSession()
{
return $this->session;
}
/**
* @param $action
* @param MenuItemInterface $menu
*
* @return MenuItemInterface
*/
public function buildBreadcrumbs($action, MenuItemInterface $menu = null)
{
if (!$menu) {
$menu = $this->getHomeBreadCrumb();
}
// Tool home
$menu->addChild(
$this->trans($this->getClassnameLabel()),
[
'uri' => $this->generateControllerUrl(
'indexAction',
[
'courseCode' => $this->getCourse()->getCode(),
]
),
]
);
$action = str_replace(
[$this->getControllerAlias().':', 'Action'],
'',
$action
);
switch ($action) {
case 'add':
case 'edit':
$menu->addChild(
$this->trans($this->getClassnameLabel().ucfirst($action))
//array('uri' => $this->generateControllerUrl($action.'Action'))
);
break;
}
return $menu;
}
/**
* Converts string 'Chamilo\CourseBundle\Controller\CourseHome\CourseHomeController' into
* 'tool/course_home'.
*/
public function getTemplatePath()
{
$parts = $this->getClassParts();
$newPath = [];
foreach ($parts as $part) {
if (in_array($part, ['chamilo', 'controller']) ||
strpos($part, '_controller') > 0
) {
continue;
}
$newPath[] = $part;
}
$template = implode('/', $newPath);
return str_replace('_controller', '', $template);
}
/**
* Before middleware for the ToolBaseController.
*
* @param Request $request
*/
public function before(Request $request)
{
$cidReset = $this->get('cidReset');
$cidReq = $request->get('cidReq');
$sessionHandler = $request->getSession();
if (empty($cidReq)) {
$cidReq = $request->get('courseCode');
}
$sessionId = $request->get('id_session');
$groupId = $request->get('gidReq');
$tempCourseId = api_get_course_id();
$tempGroupId = api_get_group_id();
$tempSessionId = api_get_session_id();
$courseReset = false;
if ((!empty($cidReq) && $tempCourseId != $cidReq) || empty($tempCourseId) || empty($tempCourseId) == -1) {
$courseReset = true;
}
if (isset($cidReset) && $cidReset == 1) {
$courseReset = true;
}
$sessionHandler->set('courseReset', $courseReset);
$groupReset = false;
if ($tempGroupId != $groupId || empty($tempGroupId)) {
$groupReset = true;
}
$sessionReset = false;
if ($tempSessionId != $sessionId || empty($tempSessionId)) {
$sessionReset = true;
}
if ($courseReset) {
if (!empty($cidReq) && $cidReq != -1) {
$courseInfo = api_get_course_info($cidReq, true, true);
if (!empty($courseInfo)) {
$courseCode = $courseInfo['code'];
$courseId = $courseInfo['real_id'];
$sessionHandler->set('_real_cid', $courseId);
$sessionHandler->set('_cid', $courseCode);
//$sessionHandler->set('_course', $courseInfo);
} else {
$this->abort(404, $this->trans('Course not available'));
}
} else {
$sessionHandler->remove('_real_cid');
$sessionHandler->remove('_cid');
//$sessionHandler->remove('_course');
}
}
$courseCode = api_get_course_id();
if (!empty($courseCode) && $courseCode != -1) {
//$tbl_course = Database::get_main_table(TABLE_MAIN_COURSE);
$time = api_get_utc_datetime();
$sql = "UPDATE course SET last_visit= '$time' WHERE code='$courseCode'";
$this->getDatabase()->query($sql);
}
if ($sessionReset) {
$sessionHandler->remove('session_name');
$sessionHandler->remove('id_session');
if (!empty($sessionId)) {
$sessionInfo = api_get_session_info($sessionId);
if (empty($sessionInfo)) {
$this->abort(404, $this->trans('Session not available'));
} else {
$sessionHandler->set('id_session', $sessionId);
}
}
}
if ($groupReset) {
$sessionHandler->remove('_gid');
if (!empty($groupId)) {
$sessionHandler->set('_gid', $groupId);
}
}
}
/**
* @return \Symfony\Component\HttpFoundation\RedirectResponse
*/
public function redirectCourseHome()
{
$url = $this->generateUrl(
'course_home',
['course' => $this->getCourse()->getCode()]
);
return $this->redirect($url);
}
use CourseControllerTrait;
}

@ -3,6 +3,8 @@
namespace Chamilo\CourseBundle\Entity;
use Chamilo\CoreBundle\Entity\Resource\AbstractResource;
use Chamilo\CoreBundle\Entity\Resource\ResourceInterface;
use Doctrine\ORM\Mapping as ORM;
/**
@ -14,9 +16,9 @@ use Doctrine\ORM\Mapping as ORM;
* @ORM\Index(name="course", columns={"c_id"})
* }
* )
* @ORM\Entity
* @ORM\Entity(repositoryClass="Chamilo\CourseBundle\Repository\CDocumentRepository")
*/
class CDocument
class CDocument extends AbstractResource implements ResourceInterface
{
/**
* @var int
@ -321,15 +323,39 @@ class CDocument
return $this->iid;
}
/**
* @param int $iid
*
* @return CDocument
*/
public function setIid($iid)
// Resource classes
public function getResourceIdentifier(): int
{
$this->iid = $iid;
return $this->getIid();
}
return $this;
public function getResourceName(): string
{
return $this->getTitle();
}
public function getToolName(): string
{
return 'document';
}
public function getName()
{
}
public function name()
{
}
public function isName()
{
}
public function hasName() {
}
public function __get($a) {
}
}

@ -9,6 +9,7 @@ use Chamilo\CoreBundle\Framework\Container;
use Chamilo\CoreBundle\Security\Authorization\Voter\CourseVoter;
use Chamilo\CoreBundle\Security\Authorization\Voter\GroupVoter;
use Chamilo\CoreBundle\Security\Authorization\Voter\SessionVoter;
use Chamilo\CourseBundle\Controller\CourseControllerInterface;
use Chamilo\CourseBundle\Controller\ToolInterface;
use Chamilo\CourseBundle\Event\CourseAccess;
use Chamilo\CourseBundle\Event\SessionAccess;
@ -25,6 +26,7 @@ use Symfony\Component\Security\Core\Exception\AccessDeniedException;
/**
* Class CourseListener.
* Sets the course and session objects in the controller that implements the CourseControllerInterface.
*
* @package Chamilo\CourseBundle\EventListener
*/
@ -33,6 +35,7 @@ class CourseListener
use ContainerAwareTrait;
/**
* Get request from the URL cidReq, c_id or the "ABC" in the courses url (courses/ABC/index.php).
* @param GetResponseEvent $event
*/
public function onKernelRequest(GetResponseEvent $event)
@ -48,6 +51,15 @@ class CourseListener
return;
}
// Ignore debug
if ($request->attributes->get('_route') === '_wdt') {
return;
}
if ($request->attributes->get('_profiler') === '_wdt') {
return;
}
$sessionHandler = $request->getSession();
$container = $this->container;
@ -66,112 +78,116 @@ class CourseListener
}
}
$courseId = null;
if (empty($courseCode)) {
$courseId = $request->get('c_id');
}
/** @var EntityManager $em */
$em = $container->get('doctrine')->getManager();
$checker = $container->get('security.authorization_checker');
$alreadyVisited = $sessionHandler->get('course_already_visited');
$course = null;
if (!empty($courseCode)) {
/** @var Course $course */
$course = $em->getRepository('ChamiloCoreBundle:Course')->findOneByCode($courseCode);
if ($course === null) {
throw new NotFoundHttpException($translator->trans('Course does not exist'));
}
}
if ($course) {
$sessionHandler->set('courseObj', $course);
$courseInfo = api_get_course_info($courseCode);
$container->get('twig')->addGlobal('course', $course);
if ($course === null && !empty($courseId)) {
/** @var Course $course */
$course = $em->getRepository('ChamiloCoreBundle:Course')->find($courseId);
if ($course === null) {
throw new NotFoundHttpException($translator->trans('Course does not exist'));
}
}
$sessionHandler->set('_real_cid', $course->getId());
$sessionHandler->set('_cid', $course->getCode());
$sessionHandler->set('_course', $courseInfo);
if (!empty($course)) {
$sessionHandler->set('courseObj', $course);
$courseInfo = api_get_course_info($courseCode);
$container->get('twig')->addGlobal('course', $course);
// Session
$sessionId = (int) $request->get('id_session');
$session = null;
$sessionHandler->set('_real_cid', $course->getId());
$sessionHandler->set('_cid', $course->getCode());
$sessionHandler->set('_course', $courseInfo);
if (empty($sessionId)) {
// Check if user is allowed to this course
// See CourseVoter.php
if (false === $checker->isGranted(CourseVoter::VIEW, $course)) {
throw new AccessDeniedException(
$translator->trans(
'Unauthorised access to course!'
)
);
// Session
$sessionId = (int) $request->get('id_session');
$session = null;
if (empty($sessionId)) {
// Check if user is allowed to this course
// See CourseVoter.php
if (false === $checker->isGranted(CourseVoter::VIEW, $course)) {
throw new AccessDeniedException($translator->trans('Unauthorised access to course!'));
}
} else {
$session = $em->getRepository('ChamiloCoreBundle:Session')->find($sessionId);
if ($session) {
$sessionHandler->set('sessionObj', $session);
//$course->setCurrentSession($session);
$session->setCurrentCourse($course);
// Check if user is allowed to this course-session
// See SessionVoter.php
if (false === $checker->isGranted(
SessionVoter::VIEW,
$session
)
) {
throw new AccessDeniedException($translator->trans('Unauthorised access to session!'));
}
$sessionHandler->set('session_name', $session->getName());
$sessionHandler->set('id_session', $session->getId());
$sessionHandler->set('sessionObj', $session);
} else {
$session = $em->getRepository('ChamiloCoreBundle:Session')->find($sessionId);
if ($session) {
$sessionHandler->set('sessionObj', $session);
//$course->setCurrentSession($session);
$session->setCurrentCourse($course);
// Check if user is allowed to this course-session
// See SessionVoter.php
if (false === $checker->isGranted(
SessionVoter::VIEW,
$session
)
) {
throw new AccessDeniedException(
$translator->trans(
'Unauthorised access to session!'
)
);
}
$sessionHandler->set('session_name', $session->getName());
$sessionHandler->set('id_session', $session->getId());
$sessionHandler->set('sessionObj', $session);
} else {
throw new NotFoundHttpException(
$translator->trans('Session not found')
);
}
throw new NotFoundHttpException($translator->trans('Session not found'));
}
}
// Group
$groupId = (int) $request->get('gidReq');
// Group
$groupId = (int) $request->get('gidReq');
if (!empty($groupId)) {
$group = $em->getRepository('ChamiloCourseBundle:CGroupInfo')->find($groupId);
if (!empty($groupId)) {
$group = $em->getRepository('ChamiloCourseBundle:CGroupInfo')->find($groupId);
if (!$group) {
throw new NotFoundHttpException($translator->trans('Group not found'));
}
if ($course->hasGroup($group)) {
// Check if user is allowed to this course-group
// See GroupVoter.php
if (false === $checker->isGranted(GroupVoter::VIEW, $group)) {
throw new AccessDeniedException($translator->trans('Unauthorised access to group'));
}
$sessionHandler->set('_gid', $groupId);
} else {
throw new AccessDeniedException($translator->trans('Group does not exist in course'));
}
if (!$group) {
throw new NotFoundHttpException($translator->trans('Group not found'));
}
/*if (!$alreadyVisited ||
isset($alreadyVisited) && $alreadyVisited != $courseCode
) {
// Course access events
$dispatcher = $this->container->get('event_dispatcher');
if (empty($sessionId)) {
$dispatcher->dispatch('chamilo_course.course.access', new CourseAccess($user, $course));
} else {
$dispatcher->dispatch(
'chamilo_course.course.access',
new SessionAccess($user, $course, $session)
);
if ($course->hasGroup($group)) {
// Check if user is allowed to this course-group
// See GroupVoter.php
if (false === $checker->isGranted(GroupVoter::VIEW, $group)) {
throw new AccessDeniedException($translator->trans('Unauthorised access to group'));
}
$coursesAlreadyVisited[$course->getCode()] = 1;
$sessionHandler->set('course_already_visited', $courseCode);
}*/
} else {
throw new NotFoundHttpException($translator->trans('Course does not exist'));
$sessionHandler->set('_gid', $groupId);
} else {
throw new AccessDeniedException($translator->trans('Group does not exist in course'));
}
}
/*if (!$alreadyVisited ||
isset($alreadyVisited) && $alreadyVisited != $courseCode
) {
// Course access events
$dispatcher = $this->container->get('event_dispatcher');
if (empty($sessionId)) {
$dispatcher->dispatch('chamilo_course.course.access', new CourseAccess($user, $course));
} else {
$dispatcher->dispatch(
'chamilo_course.course.access',
new SessionAccess($user, $course, $session)
);
}
$coursesAlreadyVisited[$course->getCode()] = 1;
$sessionHandler->set('course_already_visited', $courseCode);
}*/
Container::setRequest($request);
Container::setContainer($container);
Container::setLegacyServices($container);
@ -186,6 +202,7 @@ class CourseListener
}
/**
* Once the onKernelRequest was fired, we check if the session object were set and we inject them in the controller.
* @param FilterControllerEvent $event
*/
public function onKernelController(FilterControllerEvent $event)
@ -202,19 +219,6 @@ class CourseListener
/** @var ContainerInterface $container */
$container = $this->container;
// Course
// The 'course' variable example "123" for this URL: courses/123/
$courseCode = $request->get('course');
// Detect if the course was set with a cidReq:
if (empty($courseCode)) {
$courseCodeFromRequest = $request->get('cidReq');
$courseCode = $courseCodeFromRequest;
}
/** @var Course $course */
$course = $sessionHandler->get('courseObj');
/*if ($course) {
$courseLanguage = $course->getCourseLanguage();
//error_log('onkernelcontroller request: '.$courseLanguage);
@ -232,9 +236,9 @@ class CourseListener
// This controller implements ToolInterface? Then set the course/session
if (is_array($controllerList) &&
(
$controllerList[0] instanceof ToolInterface ||
$controllerList[0] instanceof LegacyController
) && $cidReset == false
$controllerList[0] instanceof CourseControllerInterface
//|| $controllerList[0] instanceof LegacyController
) && $cidReset === false
) {
$controller = $controllerList[0];
@ -243,7 +247,6 @@ class CourseListener
// Sets the controller course/session in order to use:
// $this->getCourse() $this->getSession() in controllers
if ($course) {
$controller->setCourse($course);
@ -268,7 +271,7 @@ class CourseListener
$controllerNameParts = explode('.', $controllerActionParts[0]);
$controllerName = $controllerActionParts[0];
$toolName = null;
/*$toolName = null;
$toolAction = null;
if (isset($controllerNameParts[1]) &&
$controllerNameParts[1] == 'controller'
@ -276,13 +279,13 @@ class CourseListener
$toolName = $this->container->get($controllerName)->getToolName();
$action = str_replace('action', '', $controllerActionParts[1]);
$toolAction = $toolName.'.'.$action;
}
}*/
$container->get('twig')->addGlobal('tool.name', $toolName);
$container->get('twig')->addGlobal('tool.action', $toolAction);
//$container->get('twig')->addGlobal('tool.name', $toolName);
//$container->get('twig')->addGlobal('tool.action', $toolAction);
$sessionHandler->set('_gid', $groupId);
$sessionHandler->set('is_allowed_in_course', true);
//$sessionHandler->set('is_allowed_in_course', true);
$sessionHandler->set('id_session', $sessionId);
} else {
$ignore = [

@ -0,0 +1,19 @@
<?php
/* For licensing terms, see /license.txt */
namespace Chamilo\CourseBundle\Repository;
use Chamilo\CoreBundle\Entity\Course;
use Chamilo\CoreBundle\Repository\ResourceRepository;
use Chamilo\CoreBundle\Entity\Session;
use Chamilo\UserBundle\Entity\User;
/**
* Class CDocumentRepository.
*
* @package Chamilo\CourseBundle\Repository
*/
class CDocumentRepository extends ResourceRepository
{
}
Loading…
Cancel
Save