Fix edit document, fix edit visibility using new resource system #2326

pull/2715/head
Julio Montoya 6 years ago
parent 60b40e65e3
commit 67cab2cc97
  1. 65
      main/document/document.php
  2. 85
      main/document/edit_document.php
  3. 31
      main/inc/lib/document.lib.php
  4. 68
      main/inc/lib/fileUpload.lib.php
  5. 7
      src/CoreBundle/Controller/ResourceController.php
  6. 13
      src/CoreBundle/Entity/Resource/ResourceLink.php
  7. 5
      src/CoreBundle/Entity/Resource/ResourceNode.php
  8. 54
      src/CoreBundle/Security/Authorization/Voter/ResourceNodeVoter.php
  9. 34
      src/CourseBundle/Entity/CDocument.php
  10. 11
      tests/scripts/migrate_item_property.php

@ -2,7 +2,9 @@
/* For licensing terms, see /license.txt */
use ChamiloSession as Session;
use Chamilo\CoreBundle\Entity\Resource\ResourceLink;
use Chamilo\CoreBundle\Entity\Resource\ResourceRight;
use Chamilo\CoreBundle\Security\Authorization\Voter\ResourceNodeVoter;
/**
* Homepage script for the documents tool.
*
@ -39,6 +41,7 @@ $lib_path = api_get_path(LIBRARY_PATH);
$actionsRight = '';
$action = isset($_REQUEST['action']) ? $_REQUEST['action'] : '';
$allowUseTool = false;
$em = Database::getManager();
if ($allowDownloadDocumentsByApiKey) {
try {
@ -1213,6 +1216,9 @@ if ($isAllowedToEdit ||
];
foreach ($files as $documentId) {
$data = DocumentManager::get_document_data_by_id($documentId, $courseInfo['code']);
/** @var \Chamilo\CourseBundle\Entity\CDocument $document */
$document = $em->getRepository('ChamiloCourseBundle:CDocument')->find($documentId);
if (in_array($data['path'], $items)) {
// exclude system directories (do not allow deletion)
continue;
@ -1220,6 +1226,9 @@ if ($isAllowedToEdit ||
switch ($_POST['action']) {
case 'set_invisible':
$visibilityCommand = 'invisible';
$links = $document->getResourceNode()->getResourceLinks();
exit;
if (api_item_property_update(
$courseInfo,
TOOL_DOCUMENT,
@ -1408,8 +1417,10 @@ if ($isAllowedToEdit) {
if ((isset($_GET['set_invisible']) && !empty($_GET['set_invisible'])) ||
(isset($_GET['set_visible']) && !empty($_GET['set_visible']))
) {
$defaultVisibility = ResourceLink::VISIBILITY_DRAFT;
// Make visible or invisible?
if (isset($_GET['set_visible'])) {
$defaultVisibility = ResourceLink::VISIBILITY_PUBLISHED;
$update_id = intval($_GET['set_visible']);
$visibility_command = 'visible';
} else {
@ -1428,28 +1439,39 @@ if ($isAllowedToEdit) {
}
}
// Update item_property to change visibility
if (api_item_property_update(
$courseInfo,
TOOL_DOCUMENT,
$update_id,
$visibility_command,
api_get_user_id(),
null,
null,
null,
null,
$sessionId
)
) {
Display::addFlash(
Display::return_message(get_lang('VisibilityChanged'), 'confirmation')
);
/** @var \Chamilo\CourseBundle\Entity\CDocument $document */
$document = $em->getRepository('ChamiloCourseBundle:CDocument')->find($update_id);
$link = $document->getCourseSessionResourceLink();
$link->setVisibility($defaultVisibility);
if ($defaultVisibility === ResourceLink::VISIBILITY_DRAFT) {
$editorMask = ResourceNodeVoter::getEditorMask();
$rights = [];
$resourceRight = new ResourceRight();
$resourceRight
->setMask($editorMask)
->setRole(ResourceNodeVoter::ROLE_CURRENT_COURSE_TEACHER)
->setResourceLink($link)
;
$rights[] = $resourceRight;
if (!empty($rights)) {
$link->setResourceRight($rights);
/*foreach ($rights as $right) {
$link->addResourceRight($right);
}*/
}
} else {
Display::addFlash(
Display::return_message(get_lang('ViModProb'), 'error')
);
$link->setResourceRight([]);
}
$em->persist($link);
$em->flush();
Display::addFlash(
Display::return_message(get_lang('VisibilityChanged'), 'confirmation')
);
header('Location: '.$currentUrl);
exit;
@ -1841,6 +1863,7 @@ if (!empty($documentAndFolders)) {
false,
$userIsSubscribed
);
$invisibility_span_open = ($is_visible == 0) ? '<span class="muted">' : '';
$invisibility_span_close = ($is_visible == 0) ? '</span>' : '';
$size = 1;

@ -2,6 +2,8 @@
/* For licensing terms, see /license.txt */
use ChamiloSession as Session;
use Chamilo\CoreBundle\Framework\Container;
use Chamilo\CourseBundle\Entity\CDocument;
/**
* This file allows editing documents.
@ -263,7 +265,10 @@ if (isset($_POST['comment'])) {
}
}
/* WYSIWYG HTML EDITOR - Program Logic */
$em = Database::getManager();
/** @var CDocument $document */
$document = $em->getRepository('ChamiloCourseBundle:CDocument')->find($document_data['iid']);
if ($is_allowed_to_edit) {
if (isset($_POST['formSent']) && $_POST['formSent'] == 1 && !empty($document_id)) {
$content = isset($_POST['content']) ? trim(str_replace(["\r", "\n"], '', stripslashes($_POST['content']))) : null;
@ -276,54 +281,33 @@ if ($is_allowed_to_edit) {
$read_only_flag = empty($read_only_flag) ? 0 : 1;
if ($file_type != 'link') {
$file_size = filesize($document_data['absolute_path']);
//$file_size = filesize($document_data['absolute_path']);
}
if ($read_only_flag == 0) {
if (!empty($content)) {
if ($fp = @fopen($document_data['absolute_path'], 'w')) {
// For flv player, change absolute path temporarily to prevent
// from erasing it in the following lines
$content = str_replace(['flv=h', 'flv=/'], ['flv=h|', 'flv=/|'], $content);
fputs($fp, $content);
fclose($fp);
$filepath = $document_data['absolute_parent_path'];
update_existing_document(
$_course,
$document_id,
$file_size,
$read_only_flag
);
api_item_property_update(
$_course,
TOOL_DOCUMENT,
$document_id,
'DocumentUpdated',
api_get_user_id(),
null,
null,
null,
null,
$sessionId
);
// Update parent folders
item_property_update_on_folder(
$_course,
$dir,
api_get_user_id()
);
} else {
Display::addFlash(Display::return_message(get_lang('Impossible'), 'warning'));
$node = $document->getResourceNode();
$file = $node->getResourceFile();
if ($file) {
$media = $node->getResourceFile()->getMedia();
$provider = Container::$container->get('sonata.media.pool')->getProvider($media->getProviderName());
$reference = $provider->getReferenceFile($media);
//$node->setUpdatedAt(new \DateTime());
$reference->setContent($content);
$media->setSize($reference->getSize());
$em->merge($media);
$em->merge($node);
$em->flush();
}
} else {
if ($document_id) {
update_existing_document($_course, $document_id, $file_size, $read_only_flag);
//update_existing_document($_course, $document_id, $file_size, $read_only_flag);
}
}
} else {
if ($document_id) {
update_existing_document($_course, $document_id, $file_size, $read_only_flag);
//update_existing_document($_course, $document_id, $file_size, $read_only_flag);
}
}
@ -336,17 +320,22 @@ if ($is_allowed_to_edit) {
$content = null;
$extension = null;
$filename = null;
if (file_exists($document_data['absolute_path'])) {
$path_info = pathinfo($document_data['absolute_path']);
$filename = $path_info['filename'];
if (is_file($document_data['absolute_path'])) {
$extension = $path_info['extension'];
if (in_array($extension, ['html', 'htm'])) {
$content = file($document_data['absolute_path']);
$content = implode('', $content);
}
$path_info = pathinfo($document_data['path']);
$filename = $path_info['filename'];
$extension = $path_info['extension'] ?? '';
if (in_array($extension, ['html', 'htm'])) {
$em = Database::getManager();
/** @var \Chamilo\CoreBundle\Entity\Resource\ResourceNode $node */
$node = $em->getRepository('ChamiloCoreBundle:Resource\ResourceNode')->find($document_data['resource_node_id']);
$file = $node->getResourceFile();
if ($file) {
$media = $node->getResourceFile()->getMedia();
$provider = Container::$container->get('sonata.media.pool')->getProvider($media->getProviderName());
$reference = $provider->getReferenceFile($media);
$content = $reference->getContent();
}
}

@ -1,6 +1,7 @@
<?php
/* For licensing terms, see /license.txt */
use Chamilo\CoreBundle\Entity\Resource\ResourceLink;
use Chamilo\UserBundle\Entity\User;
use ChamiloSession as Session;
@ -570,8 +571,8 @@ class DocumentManager
if (in_array(
$row['visibility'],
[
\Chamilo\CoreBundle\Entity\Resource\ResourceLink::VISIBILITY_DELETED,
\Chamilo\CoreBundle\Entity\Resource\ResourceLink::VISIBILITY_DRAFT,
ResourceLink::VISIBILITY_DELETED,
ResourceLink::VISIBILITY_DRAFT,
]
)) {
return false;
@ -1596,11 +1597,10 @@ class DocumentManager
}
}
$doc_id = intval($doc_id);
$session_id = intval($session_id);
//2. Course and Session visibility are handle in local.inc.php/global.inc.php
//3. Checking if user exist in course/session
$doc_id = (int) $doc_id;
$session_id = (int) $session_id;
// 2. Course and Session visibility are handle in local.inc.php/global.inc.php
// 3. Checking if user exist in course/session
if ($session_id == 0) {
if (is_null($userIsSubscribed)) {
$userIsSubscribed = CourseManager::is_user_subscribed_in_course(
@ -1639,10 +1639,23 @@ class DocumentManager
}
}
$em = Database::getManager();
// 4. Checking document visibility (i'm repeating the code in order to be more clear when reading ) - jm
if ($user_in_course) {
$repo = $em->getRepository('ChamiloCourseBundle:CDocument');
/** @var \Chamilo\CourseBundle\Entity\CDocument $document */
$document = $repo->find($doc_id);
// 4.1 Checking document visibility for a Course
if ($session_id == 0) {
$link = $document->getCourseSessionResourceLink();
if ($link->getVisibility() == ResourceLink::VISIBILITY_PUBLISHED) {
return true;
}
return false;
$item_info = api_get_item_property_info(
$course_info['real_id'],
'document',
@ -5084,12 +5097,12 @@ class DocumentManager
) {
$copy_myfiles_link = $filetype == 'file' ? api_get_self().'?'.$courseParams.'&action=copytomyfiles&id='.$document_data['id'] : api_get_self().'?'.$courseParams;
if ($filetype == 'file') {
$copyToMyFiles = '<a href="'.$copy_myfiles_link.'" style="float:right"'.$prevent_multiple_click.'>'.
/*$copyToMyFiles = '<a href="'.$copy_myfiles_link.'" style="float:right"'.$prevent_multiple_click.'>'.
Display::return_icon('briefcase.png', get_lang('CopyToMyFiles'), [], ICON_SIZE_SMALL).'&nbsp;&nbsp;</a>';
if (api_get_setting('allow_my_files') === 'false') {
$copyToMyFiles = '';
}
}*/
}
}

@ -1381,44 +1381,46 @@ function add_document(
$resourceNode = $documentRepo->addResourceNode($document, $userEntity);
$document->setResourceNode($resourceNode);
$mediaManager = \Chamilo\CoreBundle\Framework\Container::$container->get('sonata.media.manager.media');
/** @var \Chamilo\MediaBundle\Entity\Media $media */
$media = $mediaManager->create();
$media->setName($title);
$fileName = basename($path);
$extension = pathinfo($fileName, PATHINFO_EXTENSION);
//$media->setSize($fileSize);
$media->setContext('default');
$provider = 'sonata.media.provider.image';
if (!in_array($extension, ['jpeg', 'jpg', 'gif', 'png'])) {
$provider = 'sonata.media.provider.file';
}
if ($fileType === 'file') {
$mediaManager = \Chamilo\CoreBundle\Framework\Container::$container->get('sonata.media.manager.media');
/** @var \Chamilo\MediaBundle\Entity\Media $media */
$media = $mediaManager->create();
$media->setName($title);
$fileName = basename($path);
$extension = pathinfo($fileName, PATHINFO_EXTENSION);
$media->setContext('default');
$provider = 'sonata.media.provider.image';
if (!in_array($extension, ['jpeg', 'jpg', 'gif', 'png'])) {
$provider = 'sonata.media.provider.file';
}
$media->setProviderName($provider);
$media->setEnabled(true);
$media->setProviderName($provider);
$media->setEnabled(true);
if ($content instanceof UploadedFile) {
$file = $content;
} else {
$handle = tmpfile();
fwrite($handle, $content);
$file = new \Sonata\MediaBundle\Extra\ApiMediaFile($handle);
$file->setMimetype($media->getContentType());
}
if ($content instanceof UploadedFile) {
$file = $content;
$media->setSize($file->getSize());
} else {
$handle = tmpfile();
fwrite($handle, $content);
$file = new \Sonata\MediaBundle\Extra\ApiMediaFile($handle);
$file->setMimetype($media->getContentType());
}
$media->setBinaryContent($file);
$media->setBinaryContent($file);
$mediaManager->save($media, true);
$mediaManager->save($media, true);
$resourceFile = new \Chamilo\CoreBundle\Entity\Resource\ResourceFile();
$resourceFile->setMedia($media);
$resourceFile->setName($title);
$em->persist($resourceFile);
$resourceFile = new \Chamilo\CoreBundle\Entity\Resource\ResourceFile();
$resourceFile->setMedia($media);
$resourceFile->setName($title);
$em->persist($resourceFile);
$resourceNode->setResourceFile($resourceFile);
$em->persist($resourceNode);
$resourceNode->setResourceFile($resourceFile);
$em->persist($resourceNode);
}
$newVisibility = ResourceLink::VISIBILITY_PUBLISHED;
$link = new ResourceLink();
@ -1438,8 +1440,6 @@ function add_document(
}*/
$em->persist($link);
$em->persist($document);
$em->flush();

@ -442,16 +442,13 @@ class ResourceController extends BaseController implements CourseControllerInter
case 'show':
/** @var \Sonata\MediaBundle\Provider\ImageProvider $provider */
$provider = $this->get('sonata.media.pool')->getProvider($media->getProviderName());
$reference = $provider->getReferenceFile($media);
//$reference = $provider->getReferenceFile($media);
$filename = sprintf('%s/%s',
$provider->getFilesystem()->getAdapter()->getDirectory(),
$provider->generatePrivateUrl($media, $format)
);
//var_dump($provider->generatePublicUrl($media, $format));
//var_dump($filename);
return new BinaryFileResponse($filename);
exit;
return $this->render('@SonataMedia/Media/view.html.twig', [
@ -465,8 +462,6 @@ class ResourceController extends BaseController implements CourseControllerInter
$response = $provider->getDownloadResponse($media, $format, $this->get('sonata.media.pool')->getDownloadMode($media));
return $response;
break;
}
}

@ -67,7 +67,10 @@ class ResourceLink implements ResourceInterface
protected $userGroup;
/**
* @ORM\OneToMany(targetEntity="Chamilo\CoreBundle\Entity\Resource\ResourceRight", mappedBy="resourceLink", cascade={"persist", "remove"})
* @ORM\OneToMany(
* targetEntity="Chamilo\CoreBundle\Entity\Resource\ResourceRight",
* mappedBy="resourceLink", cascade={"persist", "remove"}, orphanRemoval=true
* )
*/
protected $resourceRight;
@ -149,13 +152,13 @@ class ResourceLink implements ResourceInterface
*
* @return $this
*/
public function setResourceRight(ArrayCollection $rights)
public function setResourceRight($rights)
{
$this->resourceRight = new ArrayCollection();
$this->resourceRight = $rights;
foreach ($rights as $right) {
/*foreach ($rights as $right) {
$this->addResourceRight($right);
}
}*/
return $this;
}

@ -5,6 +5,7 @@ namespace Chamilo\CoreBundle\Entity\Resource;
use Chamilo\UserBundle\Entity\User;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Criteria;
use Doctrine\ORM\Mapping as ORM;
use Gedmo\Mapping\Annotation as Gedmo;
use Symfony\Component\Validator\Constraints as Assert;
@ -182,6 +183,8 @@ class ResourceNode
/**
* @param \DateTime|null $createdAt
*
* @return $this
*/
public function setCreatedAt(\DateTime $createdAt = null)
{
@ -386,7 +389,7 @@ class ResourceNode
}
/**
* @return mixed
* @return ArrayCollection
*/
public function getResourceLinks()
{

@ -111,6 +111,7 @@ class ResourceNodeVoter extends Voter
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;
@ -141,6 +142,8 @@ class ResourceNodeVoter extends Voter
$links = $resourceNode->getResourceLinks();
$linkFound = false;
$courseManager = $this->container->get('chamilo_core.entity.manager.course_manager');
/** @var ResourceLink $link */
foreach ($links as $link) {
$linkUser = $link->getUser();
@ -148,7 +151,7 @@ class ResourceNodeVoter extends Voter
$linkSession = $link->getSession();
$linkUserGroup = $link->getUserGroup();
// Check if resource was sent to the current user
// Check if resource was sent to the current user.
if ($linkUser instanceof UserInterface &&
$linkUser->getUsername() === $creator->getUsername()
) {
@ -164,7 +167,7 @@ class ResourceNodeVoter extends Voter
$linkCourse instanceof Course && !empty($courseCode)
) {
$session = $this->container->get('chamilo_core.entity.manager.session_manager')->find($sessionId);
$course = $this->container->get('chamilo_core.entity.manager.course_manager')->findOneByCode($courseCode);
$course = $courseManager->findOneByCode($courseCode);
if ($session instanceof Session &&
$course instanceof Course &&
$linkCourse->getCode() === $course->getCode() &&
@ -177,7 +180,7 @@ class ResourceNodeVoter extends Voter
// Check if resource was sent to a course
if ($linkCourse instanceof Course && !empty($courseCode)) {
$course = $this->container->get('chamilo_core.entity.manager.course_manager')->findOneByCode($courseCode);
$course = $courseManager->findOneByCode($courseCode);
if ($course instanceof Course &&
$linkCourse->getCode() === $course->getCode()
) {
@ -228,42 +231,46 @@ class ResourceNodeVoter extends Voter
$mask->add($attribute);
$askedMask = $mask->get();
// Check all the right this link has.
$roles = [];
foreach ($rights as $right) {
$roles[$right->getMask()] = $right->getRole();
}
// Setting zend simple ACL
$acl = new Acl();
// Creating roles
// @todo move this in a service
$userRole = new Role('ROLE_USER');
$teacher = new Role(self::ROLE_CURRENT_COURSE_TEACHER);
$student = new Role(self::ROLE_CURRENT_COURSE_STUDENT);
$teacher = new Role('ROLE_TEACHER');
$student = new Role('ROLE_STUDENT');
$currentTeacher = new Role(self::ROLE_CURRENT_COURSE_TEACHER);
$currentStudent = new Role(self::ROLE_CURRENT_COURSE_STUDENT);
$superAdmin = new Role('ROLE_SUPER_ADMIN');
$admin = new Role('ROLE_ADMIN');
// Adding roles to the ACL
// User role
$acl->addRole($userRole);
// Adds role student
$acl->addRole($student);
// Adds teacher role, inherit student role
$acl->addRole($teacher, $student);
$acl->addRole($superAdmin);
$acl->addRole($admin);
$acl
->addRole($userRole)
->addRole($student)
->addRole($teacher)
->addRole($currentStudent)
->addRole($currentTeacher, self::ROLE_CURRENT_COURSE_STUDENT)
->addRole($superAdmin)
->addRole($admin)
;
// Adds a resource
$resource = new SecurityResource($link);
$acl->addResource($resource);
// Role and permissions settings
// Students can view
// Check all the right this link has.
// $roles = [];
// Set rights from the ResourceRight
foreach ($rights as $right) {
//$roles[$right->getMask()] = $right->getRole();
$acl->allow($right->getRole(), null, $right->getMask());
}
// var_dump($askedMask, $roles);
// Role and permissions settings
// Student can just view (read)
$acl->allow($student, null, self::getReaderMask());
//$acl->allow($student, null, self::getReaderMask());
// Teacher can view/edit
$acl->allow(
@ -280,14 +287,13 @@ class ResourceNodeVoter extends Voter
$acl->allow($superAdmin);
foreach ($user->getRoles() as $role) {
//var_dump($acl->isAllowed($role, $resource, $askedMask), $role);
if ($acl->isAllowed($role, $resource, $askedMask)) {
//dump('passed');
return true;
}
}
//dump('not allowed to '.$attribute);
return false;
}
}

@ -7,7 +7,9 @@ use APY\DataGridBundle\Grid\Mapping as GRID;
use Chamilo\CoreBundle\Entity\Course;
use Chamilo\CoreBundle\Entity\Resource\AbstractResource;
use Chamilo\CoreBundle\Entity\Resource\ResourceInterface;
use Chamilo\CoreBundle\Entity\Resource\ResourceLink;
use Chamilo\CoreBundle\Entity\Session;
use Doctrine\Common\Collections\Criteria;
use Doctrine\ORM\Event\LifecycleEventArgs;
use Doctrine\ORM\Mapping as ORM;
@ -113,10 +115,6 @@ class CDocument extends AbstractResource implements ResourceInterface
return (string) $this->title;
}
public function __get($a)
{
}
/**
* Set path.
*
@ -333,6 +331,21 @@ class CDocument extends AbstractResource implements ResourceInterface
return $this;
}
/**
* @return ResourceLink
*/
public function getCourseSessionResourceLink()
{
$criteria = Criteria::create();
$criteria
->where(Criteria::expr()->eq('course', $this->getCourse()))
->andWhere(
Criteria::expr()->eq('session', $this->getSession())
);
return $this->getResourceNode()->getResourceLinks()->matching($criteria)->first();
}
/**
* @ORM\PostPersist()
*
@ -347,18 +360,27 @@ class CDocument extends AbstractResource implements ResourceInterface
$em->flush($this);
}
// Resource classes
/**
* Resource identifier
*
* @return int
*/
public function getResourceIdentifier(): int
{
return $this->getIid();
}
/**
* @return string
*/
public function getResourceName(): string
{
return $this->getTitle();
}
/**
* @return string
*/
public function getToolName(): string
{
return 'document';

@ -148,8 +148,7 @@ while ($row = Database::fetch_array($result, 'ASSOC')) {
switch ($row['visibility']) {
case '0':
$newVisibility = ResourceLink::VISIBILITY_DRAFT;
$readerMask = ResourceNodeVoter::getReaderMask();
//$readerMask = ResourceNodeVoter::getReaderMask();
$editorMask = ResourceNodeVoter::getEditorMask();
$resourceRight = new ResourceRight();
@ -158,6 +157,14 @@ while ($row = Database::fetch_array($result, 'ASSOC')) {
->setRole(ResourceNodeVoter::ROLE_CURRENT_COURSE_TEACHER)
;
$rights[] = $resourceRight;
/*$resourceRight = new ResourceRight();
$resourceRight
->setMask($readerMask)
->setRole(ResourceNodeVoter::ROLE_CURRENT_COURSE_STUDENT)
;
$rights[] = $resourceRight;*/
break;
case '1':
$newVisibility = ResourceLink::VISIBILITY_PUBLISHED;

Loading…
Cancel
Save