Fix file upload + new folder and document redirect.

pull/3282/head
Julio Montoya 5 years ago
parent b1dbf8235b
commit 832895f897
  1. 4
      .env.test
  2. 4
      assets/vue/components/Toolbar.vue
  3. 7
      assets/vue/components/documents/Form.vue
  4. 86
      assets/vue/components/documents/FormUpload.vue
  5. 2
      assets/vue/mixins/CreateMixin.js
  6. 2
      assets/vue/views/documents/CreateFile.vue
  7. 34
      phpunit.xml.dist
  8. 6
      src/CoreBundle/Controller/CourseHomeController.php
  9. 22
      src/CoreBundle/Controller/CreateResourceNodeFileAction.php
  10. 6
      src/CoreBundle/Controller/IndexController.php
  11. 10
      src/CoreBundle/Entity/AbstractResource.php
  12. 2
      src/CoreBundle/Entity/Listener/ResourceListener.php
  13. 1
      src/CoreBundle/Entity/ResourceToCourseInterface.php
  14. 1
      src/CoreBundle/Entity/ResourceToRootInterface.php
  15. 2
      src/CoreBundle/Resources/config/tools.yml
  16. 4
      src/CoreBundle/Tool/Document.php
  17. 4
      src/CourseBundle/Entity/CDocument.php

@ -1,4 +0,0 @@
# define your env variables for the test env here
KERNEL_CLASS='Chamilo\Kernel'
APP_SECRET='s$cretf0rt3st'
SYMFONY_DEPRECATIONS_HELPER=999999

@ -47,11 +47,11 @@
<v-btn v-if="handleAdd" color="primary" rounded @click="addItem"> <v-btn v-if="handleAdd" color="primary" rounded @click="addItem">
<v-icon>mdi-plus-circle</v-icon> <v-icon>mdi-plus-circle</v-icon>
Add folder New folder
</v-btn> </v-btn>
<v-btn v-if="handleAddDocument" color="primary" rounded @click="addDocument"> <v-btn v-if="handleAddDocument" color="primary" rounded @click="addDocument">
Add document File upload
</v-btn> </v-btn>
</div> </div>

@ -11,7 +11,6 @@
@input="$v.item.title.$touch()" @input="$v.item.title.$touch()"
@blur="$v.item.title.$touch()" @blur="$v.item.title.$touch()"
/> />
<v-file-input v-if="typeIsFile" v-model="item.resourceFile" show-size label="File input"></v-file-input>
<input type="hidden" v-model="item.parentResourceNode" /> <input type="hidden" v-model="item.parentResourceNode" />
</v-col> </v-col>
</v-row> </v-row>
@ -52,7 +51,6 @@ export default {
return { return {
title: null, title: null,
parentResourceNode: null, parentResourceNode: null,
resourceFile: null
}; };
}, },
computed: { computed: {
@ -69,9 +67,6 @@ export default {
return errors; return errors;
}, },
typeIsFile() {
return this.type === 'file';
},
violations() { violations() {
return this.errors || {}; return this.errors || {};
} }
@ -85,8 +80,6 @@ export default {
}, },
parentResourceNode: { parentResourceNode: {
}, },
resourceFile: {
}
} }
} }
}; };

@ -0,0 +1,86 @@
<template>
<v-form>
<v-container fluid>
<v-row>
<v-col cols="12" sm="6" md="6">
<v-file-input v-if="typeIsFile" v-model="item.resourceFile" show-size label="File upload"></v-file-input>
<input type="hidden" v-model="item.parentResourceNode" />
</v-col>
</v-row>
</v-container>
</v-form>
</template>
<script>
import has from 'lodash/has';
import { validationMixin } from 'vuelidate';
import { required } from 'vuelidate/lib/validators';
import { mapActions } from 'vuex';
import { mapFields } from 'vuex-map-fields';
export default {
name: 'DocumentsFormUpload',
mixins: [validationMixin],
props: {
values: {
type: Object,
required: true
},
errors: {
type: Object,
default: () => {}
},
initialValues: {
type: Object,
default: () => {}
},
type: {
type: String,
}
},
created () {
},
data() {
return {
parentResourceNode: null,
resourceFile: null,
};
},
computed: {
// eslint-disable-next-line
item() {
return this.initialValues || this.values;
},
titleErrors() {
const errors = [];
console.log('errors');
if (this.typeIsFile) {
console.log('empty');
return errors;
}
if (!this.$v.item.title.$dirty) return errors;
has(this.violations, 'title') && errors.push(this.violations.title);
!this.$v.item.title.required && errors.push(this.$t('Field is required'));
return errors;
},
typeIsFile() {
return this.type === 'file';
},
violations() {
return this.errors || {};
}
},
methods: {
},
validations: {
item: {
parentResourceNode: {
},
resourceFile: {
}
}
}
};
</script>

@ -19,8 +19,8 @@ export default {
if (createForm.$v.item.parentResourceNode) { if (createForm.$v.item.parentResourceNode) {
let nodeId = this.$route.params.node; let nodeId = this.$route.params.node;
createForm.$v.item.$model.parentResourceNode = '/api/resource_nodes/' + nodeId; createForm.$v.item.$model.parentResourceNode = '/api/resource_nodes/' + nodeId;
console.log(createForm.$v.item.$model.parentResourceNode);
} }
if (!createForm.$v.$invalid) { if (!createForm.$v.$invalid) {
this.create(createForm.$v.item.$model); this.create(createForm.$v.item.$model);
} }

@ -9,7 +9,7 @@
<script> <script>
import { mapActions } from 'vuex'; import { mapActions } from 'vuex';
import { createHelpers } from 'vuex-map-fields'; import { createHelpers } from 'vuex-map-fields';
import DocumentsForm from '../../components/documents/Form'; import DocumentsForm from '../../components/documents/FormUpload';
import Loading from '../../components/Loading'; import Loading from '../../components/Loading';
import Toolbar from '../../components/Toolbar'; import Toolbar from '../../components/Toolbar';
import CreateMixin from '../../mixins/CreateMixin'; import CreateMixin from '../../mixins/CreateMixin';

@ -1,34 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- https://phpunit.readthedocs.io/en/latest/configuration.html -->
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="http://schema.phpunit.de/6.5/phpunit.xsd"
backupGlobals="false"
colors="true"
bootstrap="config/bootstrap.php"
>
<php>
<ini name="error_reporting" value="-1" />
<ini name="display_errors" value="true"/>
<server name="APP_ENV" value="test" force="true" />
<server name="SHELL_VERBOSITY" value="-1" />
<server name="SYMFONY_PHPUNIT_REMOVE" value="" />
<server name="SYMFONY_PHPUNIT_VERSION" value="7.5" />
</php>
<testsuites>
<testsuite name="Project Test Suite">
<directory>tests</directory>
</testsuite>
</testsuites>
<filter>
<whitelist>
<directory>src</directory>
</whitelist>
</filter>
<listeners>
<listener class="Symfony\Bridge\PhpUnit\SymfonyTestsListener" />
</listeners>
</phpunit>

@ -218,10 +218,14 @@ class CourseHomeController extends ToolBaseController
throw new NotFoundHttpException($this->trans('Tool not found')); throw new NotFoundHttpException($this->trans('Tool not found'));
} }
$nodeId = $this->getCourse()->getResourceNode()->getId();
/** @var AbstractTool $tool */ /** @var AbstractTool $tool */
$tool = $toolChain->getToolFromName($tool->getTool()->getName()); $tool = $toolChain->getToolFromName($tool->getTool()->getName());
$url = $tool->getLink().'?'.$this->getCourseUrlQuery(); $link = $tool->getLink();
$link = str_replace(':nodeId', $nodeId, $link);
$url = $link.'?'.$this->getCourseUrlQuery();
return $this->redirect($url); return $this->redirect($url);
} }

@ -4,7 +4,6 @@
namespace Chamilo\CoreBundle\Controller; namespace Chamilo\CoreBundle\Controller;
use Chamilo\CoreBundle\Entity\ResourceFile;
use Chamilo\CourseBundle\Entity\CDocument; use Chamilo\CourseBundle\Entity\CDocument;
use Symfony\Component\HttpFoundation\File\UploadedFile; use Symfony\Component\HttpFoundation\File\UploadedFile;
use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Request;
@ -14,17 +13,26 @@ class CreateResourceNodeFileAction
{ {
public function __invoke(Request $request): CDocument public function __invoke(Request $request): CDocument
{ {
$uploadedFile = null;
/** @var UploadedFile $uploadedFile */ /** @var UploadedFile $uploadedFile */
$uploadedFile = $request->files->get('resourceFile'); if ($request->files->count() > 0) {
if (!$uploadedFile) { $uploadedFile = $request->files->get('resourceFile');
throw new BadRequestHttpException('"resourceFile" is required'); if (!$uploadedFile) {
throw new BadRequestHttpException('"resourceFile" is required');
}
} }
$document = new CDocument(); $document = new CDocument();
$document->setTitle($request->get('title')); $title = $request->get('title');
if (empty($title) && $uploadedFile) {
$title = $uploadedFile->getClientOriginalName();
}
$document->setTitle($title);
$document->setComment($request->get('comment')); $document->setComment($request->get('comment'));
$nodeId = (int) str_replace('/api/resource_nodes/','',$request->get('parentResourceNode')); $nodeId = (int) str_replace('/api/resource_nodes/', '', $request->get('parentResourceNode'));
$document->setParentResourceNode($nodeId); $document->setParentResourceNode($nodeId);
$document->setResourceFile($uploadedFile); if ($uploadedFile) {
$document->setResourceFile($uploadedFile);
}
return $document; return $document;
} }

@ -8,7 +8,6 @@ use Sensio\Bundle\FrameworkExtraBundle\Configuration\Security;
use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route; use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Serializer\SerializerInterface;
/** /**
* Class IndexController * Class IndexController
@ -20,8 +19,9 @@ class IndexController extends BaseController
* The Chamilo index home page. * The Chamilo index home page.
* *
* @Route("/", name="home", methods={"GET", "POST"}, options={"expose"=true}) * @Route("/", name="home", methods={"GET", "POST"}, options={"expose"=true})
* @Route("/login", name="login", methods={"GET", "POST"}, options={"expose"=true})
*/ */
public function indexAction(SerializerInterface $serializer): Response public function indexAction(): Response
{ {
return $this->render( return $this->render(
'@ChamiloCore/Index/vue.html.twig', '@ChamiloCore/Index/vue.html.twig',
@ -31,7 +31,7 @@ class IndexController extends BaseController
); );
} }
public function resources(SerializerInterface $serializer): Response public function resources(): Response
{ {
return $this->render( return $this->render(
'@ChamiloCore/Index/vue.html.twig', '@ChamiloCore/Index/vue.html.twig',

@ -32,7 +32,11 @@ abstract class AbstractResource
* @ApiSubresource() * @ApiSubresource()
* @Groups({"resource_node:read", "resource_node:write"}) * @Groups({"resource_node:read", "resource_node:write"})
* @GRID\Column(field="resourceNode.createdAt", title="Date added", type="datetime") * @GRID\Column(field="resourceNode.createdAt", title="Date added", type="datetime")
* @ORM\OneToOne(targetEntity="Chamilo\CoreBundle\Entity\ResourceNode", cascade={"persist", "remove"}, orphanRemoval=true) * @ORM\OneToOne(
* targetEntity="Chamilo\CoreBundle\Entity\ResourceNode",
* cascade={"persist", "remove"},
* orphanRemoval=true
* )
* @ORM\JoinColumn(name="resource_node_id", referencedColumnName="id", onDelete="CASCADE") * @ORM\JoinColumn(name="resource_node_id", referencedColumnName="id", onDelete="CASCADE")
*/ */
public $resourceNode; public $resourceNode;
@ -78,12 +82,10 @@ abstract class AbstractResource
public function setResourceFile($file) public function setResourceFile($file)
{ {
$this->resourceFile = $file; $this->resourceFile = $file;
return $this; return $this;
} }
public function setResourceNode(ResourceNode $resourceNode): self public function setResourceNode(ResourceNode $resourceNode): self
{ {
$this->resourceNode = $resourceNode; $this->resourceNode = $resourceNode;

@ -5,13 +5,11 @@
namespace Chamilo\CoreBundle\Entity\Listener; namespace Chamilo\CoreBundle\Entity\Listener;
use Chamilo\CoreBundle\Entity\AbstractResource; use Chamilo\CoreBundle\Entity\AbstractResource;
use Chamilo\CoreBundle\Entity\Course;
use Chamilo\CoreBundle\Entity\ResourceFile; use Chamilo\CoreBundle\Entity\ResourceFile;
use Chamilo\CoreBundle\Entity\ResourceNode; use Chamilo\CoreBundle\Entity\ResourceNode;
use Chamilo\CoreBundle\Entity\ResourceToCourseInterface; use Chamilo\CoreBundle\Entity\ResourceToCourseInterface;
use Chamilo\CoreBundle\Entity\ResourceToRootInterface; use Chamilo\CoreBundle\Entity\ResourceToRootInterface;
use Chamilo\CoreBundle\Entity\ResourceWithUrlInterface; use Chamilo\CoreBundle\Entity\ResourceWithUrlInterface;
use Chamilo\CoreBundle\Entity\UrlResourceInterface;
use Chamilo\CoreBundle\ToolChain; use Chamilo\CoreBundle\ToolChain;
use Cocur\Slugify\SlugifyInterface; use Cocur\Slugify\SlugifyInterface;
use Doctrine\ORM\Event\LifecycleEventArgs; use Doctrine\ORM\Event\LifecycleEventArgs;

@ -7,4 +7,3 @@ namespace Chamilo\CoreBundle\Entity;
interface ResourceToCourseInterface interface ResourceToCourseInterface
{ {
} }

@ -7,4 +7,3 @@ namespace Chamilo\CoreBundle\Entity;
interface ResourceToRootInterface interface ResourceToRootInterface
{ {
} }

@ -175,7 +175,7 @@ services:
arguments: arguments:
- 'document' - 'document'
- 'authoring' - 'authoring'
- '/resources/document/files' - '/resources/document/'
- '@chamilo_course.settings.document' - '@chamilo_course.settings.document'
- -
files: files:

@ -9,4 +9,8 @@ namespace Chamilo\CoreBundle\Tool;
*/ */
class Document extends AbstractTool class Document extends AbstractTool
{ {
public function getLink()
{
return $this->link.':nodeId/';
}
} }

@ -9,12 +9,12 @@ use ApiPlatform\Core\Annotation\ApiResource;
use ApiPlatform\Core\Bridge\Doctrine\Orm\Filter\OrderFilter; use ApiPlatform\Core\Bridge\Doctrine\Orm\Filter\OrderFilter;
use ApiPlatform\Core\Bridge\Doctrine\Orm\Filter\SearchFilter; use ApiPlatform\Core\Bridge\Doctrine\Orm\Filter\SearchFilter;
use APY\DataGridBundle\Grid\Mapping as GRID; use APY\DataGridBundle\Grid\Mapping as GRID;
use Chamilo\CoreBundle\Controller\CreateResourceNodeFileAction;
use Chamilo\CoreBundle\Entity\AbstractResource; use Chamilo\CoreBundle\Entity\AbstractResource;
use Chamilo\CoreBundle\Entity\Course; use Chamilo\CoreBundle\Entity\Course;
use Chamilo\CoreBundle\Entity\ResourceInterface; use Chamilo\CoreBundle\Entity\ResourceInterface;
use Chamilo\CoreBundle\Entity\ResourceToCourseInterface; use Chamilo\CoreBundle\Entity\ResourceToCourseInterface;
use Chamilo\CoreBundle\Entity\Session; use Chamilo\CoreBundle\Entity\Session;
use Chamilo\CoreBundle\Controller\CreateResourceNodeFileAction;
use Chamilo\CourseBundle\Traits\ShowCourseResourcesInSessionTrait; use Chamilo\CourseBundle\Traits\ShowCourseResourcesInSessionTrait;
use Doctrine\ORM\Event\LifecycleEventArgs; use Doctrine\ORM\Event\LifecycleEventArgs;
use Doctrine\ORM\Mapping as ORM; use Doctrine\ORM\Mapping as ORM;
@ -49,7 +49,7 @@ use Symfony\Component\Serializer\Annotation\Groups;
* "comment"={ * "comment"={
* "type"="string", * "type"="string",
* }, * },
* "parentResourceNode"={ * "parentResourceNode"={
* "type"="object", * "type"="object",
* }, * },
* } * }

Loading…
Cancel
Save