Browse Source

Adding "elfinder chamilo connector" as a controller, in order to not modified the elfinder default files. This way we can update elfinder and ckeditor in any moment.
No custom modifications were added directly in those libraries. The elfinder.html file is render by the javascript/elfinder.tpl file

Julio Montoya 12 years ago
parent
commit
98ba3d104e

+ 2 - 0
main/inc/lib/template.lib.php

@@ -430,9 +430,11 @@ class Template
             //'jquery-ui/jquery.ui.touch-punch.js',
             'thickbox.js',
             'ckeditor/ckeditor.js',
+            //'tinymce/tinymce.min.js',
             'bootstrap/bootstrap.js',
         );
 
+
         if (api_is_global_chat_enabled()) {
             //Do not include the global chat in LP
             if ($this->show_learnpath == false && $this->show_footer == true && $this->app['template.hide_global_chat'] == false) {

+ 9 - 0
main/inc/routes.php

@@ -510,3 +510,12 @@ $app->get('/admin/questionmanager/questions/get-questions-by-category/{categoryI
     ->before($adminAndQuestionManagerCondition)
     ->bind('admin_get_questions_by_category');
 
+/** Editor */
+$app->match('/editor/filemanager', 'editor.controller:filemanagerAction', 'GET|POST')
+    ->assert('type', '.+')
+    ->bind('filemanager');
+
+$app->match('/editor/connector', 'editor.controller:connectorAction', 'GET|POST')
+    ->assert('type', '.+')
+    ->bind('editor_connector');
+

+ 18 - 0
main/inc/services.php

@@ -224,6 +224,12 @@ if (isset($app['configuration']['main_database'])) {
                     "type" => "annotation",
                     "namespace" => "Entity",
                     "path" => api_get_path(INCLUDE_PATH).'Entity',
+                ),
+                array(
+                    'use_simple_annotation_reader' => false,
+                    "type" => "annotation",
+                    "namespace" => "Gedmo",
+                    "path" => api_get_path(SYS_PATH).'vendors/gedmo/doctrine-extensions/lib/Gedmo',
                 )
             ),
         ),
@@ -239,6 +245,9 @@ if (isset($app['configuration']['main_database'])) {
     $tree = new Gedmo\Mapping\Annotation\TreeRight(array());
     $tree = new Gedmo\Mapping\Annotation\TreeRoot(array());
     $tree = new Gedmo\Mapping\Annotation\TreeLevel(array());
+    $tree = new Gedmo\Mapping\Annotation\Versioned(array());
+    $tree = new Gedmo\Mapping\Annotation\Loggable(array());
+    $tree = new Gedmo\Loggable\Entity\LogEntry();
 
     // Setting Doctrine2 extensions
     $timestampableListener = new \Gedmo\Timestampable\TimestampableListener();
@@ -253,6 +262,9 @@ if (isset($app['configuration']['main_database'])) {
     $treeListener = new \Gedmo\Tree\TreeListener();
     //$treeListener->setAnnotationReader($cachedAnnotationReader);
     $app['db.event_manager']->addEventSubscriber($treeListener);
+
+    $loggableListener = new \Gedmo\Loggable\LoggableListener();
+    $app['db.event_manager']->addEventSubscriber($loggableListener);
 }
 
 // Setting Twig as a service provider
@@ -458,6 +470,12 @@ $app['news.controller'] = $app->share(
     }
 );
 
+$app['editor.controller'] = $app->share(
+    function () use ($app) {
+        return new ChamiloLMS\Controller\EditorController();
+    }
+);
+
 $app['question_manager.controller'] = $app->share(
     function () use ($app) {
         return new ChamiloLMS\Controller\Admin\QuestionManager\QuestionManagerController();

+ 47 - 0
main/template/default/javascript/elfinder.tpl

@@ -0,0 +1,47 @@
+{% extends app.template_style ~ "/layout/no_layout.tpl" %}
+
+{% block body %}
+
+    <!-- elFinder CSS (REQUIRED) -->
+    <link rel="stylesheet" type="text/css" media="screen" href="{{ _p.web_lib }}elfinder/css/elfinder.min.css">
+    <link rel="stylesheet" type="text/css" media="screen" href="{{ _p.web_lib }}elfinder/css/theme.css">
+
+    <!-- elFinder JS (REQUIRED) -->
+    <script type="text/javascript" src="{{ _p.web_lib }}elfinder/js/elfinder.min.js"></script>
+
+    <!-- elFinder translation (OPTIONAL) -->
+    <script type="text/javascript" src="{{ _p.web_lib }}elfinder/js/i18n/elfinder.ru.js"></script>
+
+    <script type="text/javascript" charset="utf-8">
+        $().ready(function() {
+            var elf = $('#elfinder').elfinder({
+                url : '{{ url('editor_connector') }}'  // connector URL (REQUIRED)
+                // lang: 'ru',             // language (OPTIONAL)
+            }).elfinder('instance');
+        });
+    </script>
+    <script type="text/javascript" charset="utf-8">
+      // Helper function to get parameters from the query string.
+      function getUrlParam(paramName) {
+          var reParam = new RegExp('(?:[\?&]|&amp;)' + paramName + '=([^&]+)', 'i') ;
+          var match = window.location.search.match(reParam) ;
+          return (match && match.length > 1) ? match[1] : '' ;
+      }
+
+      $().ready(function() {
+          var funcNum = getUrlParam('CKEditorFuncNum');
+          var elf = $('#elfinder').elfinder({
+              url : 'php/connectorChamilo.php',
+              getFileCallback : function(file) {
+                  window.opener.CKEDITOR.tools.callFunction(funcNum, file);
+                  window.close();
+              },
+              resizable: false
+          }).elfinder('instance');
+      });
+  </script>
+
+    <div id="elfinder"></div>
+
+
+{% endblock %}

+ 289 - 0
src/ChamiloLMS/Component/Editor/Connector.php

@@ -0,0 +1,289 @@
+<?php
+
+namespace ChamiloLMS\Component\Editor;
+
+/**
+ * Class Connector
+ * @package ChamiloLMS\Component\Editor
+ */
+class Connector
+{
+    /**
+     *
+     */
+    public function __construct()
+    {
+
+    }
+
+    /**
+     * Simple function to demonstrate how to control file access using "accessControl" callback.
+     * This method will disable accessing files/folders starting from  '.' (dot)
+     *
+     * @param  string  $attr  attribute name (read|write|locked|hidden)
+     * @param  string  $path  file path relative to volume root directory started with directory separator
+     * @return bool|null
+     **/
+    function access($attr, $path, $data, $volume) {
+        //error_log($path); error_log($attr);
+    	return strpos(basename($path), '.') === 0       // if file/folder begins with '.' (dot)
+    		? !($attr == 'read' || $attr == 'write')    // set read+write to false, other (locked+hidden) set to true
+    		:  null;                                    // else elFinder decide it itself
+    }
+
+    /**
+     * Simple callback catcher
+     *
+     * @param  string   $cmd       command name
+     * @param  array    $result    command result
+     * @param  array    $args      command arguments from client
+     * @param  \elFinder   $elfinder  elFinder instance
+     * @return void|true
+     **/
+    function logger($cmd, $result, $args, $elfinder) {
+        // do something here
+        //echo $cmd;
+
+        $courseInfo = api_get_course_info();
+
+        error_log($cmd);
+        error_log(print_r($result,1));
+        //error_log(print_r($args,1));
+        //error_log(print_r($elfinder,1));
+
+        switch($cmd) {
+            case 'mkdir':
+                break;
+            case 'mkfile':
+                break;
+            case 'rename':
+                break;
+            case 'duplicate':
+                break;
+            case 'upload':
+                // Files added
+                if (isset($result['added'])) {
+                    foreach ($result['added'] as $file) {
+                        $name = $file['name'];
+                        $webalized = \URLify::filter($file['name'], 80);
+                        error_log($webalized);
+                        if (strcmp($name, $webalized) != 0) {
+                            $arg = array('target' => $file['hash'], 'name' => $webalized);
+                            $elfinder->exec('rename', $arg);
+                        }
+
+                        $realPath = $elfinder->realpath($file['hash']);
+
+                        error_log($realPath);
+                        if (!empty($realPath)) {
+                            // Getting file info
+                            $info = $elfinder->exec('file', array('target' => $file['hash']));
+                            /** @var elFinderVolumeLocalFileSystem $volume */
+                            $volume = $info['volume'];
+                            $root = $volume->root();
+                            //var/www/chamilogits/data/courses/NEWONE/document
+                            $realPathRoot = $elfinder->realpath($root);
+                            /*
+                            $defaultPath = $volume->defaultPath();
+                            error_log($defaultPath);
+                            $driverId= $volume->driverId();
+                            error_log($root);
+                            error_log($driverId);*/
+
+                            //error_log(print_r($info, 1));
+                            //error_log($realPathRoot);
+                            //error_log($realPath);
+                            // Removing course path
+                            $realPath = str_replace($realPathRoot, '', $realPath);
+                            \FileManager::add_document($courseInfo, $realPath, 'file', intval($file['size']), $file['name']);
+                        }
+                    }
+                }
+                break;
+            case 'rm':
+                if (isset($result['removed'])) {
+                    foreach ($result['removed'] as $file) {
+                        $realFilePath = $file['realpath'];
+                        $filePath = str_replace($courseInfo['course_sys_data'].'document', '', $realFilePath);
+                        /*error_log($filePath);
+                        error_log($courseInfo['course_sys_data'].'document');*/
+
+                        /*
+                        $info = $elfinder->exec('file', array('target' => $file['phash']));
+                        error_log(print_r($info,1));
+
+                        $volume = $info['volume'];
+                        $root = $volume->root();
+                        //var/www/chamilogits/data/courses/NEWONE/document
+                        $realPathRoot = $elfinder->realpath($root);
+                        error_log($realPathRoot);
+
+                        $realPath = $file['realpath'];
+                        $realPath = str_replace($realPathRoot, '', $realPath);
+                        error_log($realPath);
+                        error_log($realPathRoot);*/
+                        \DocumentManager::delete_document($courseInfo, $filePath, $courseInfo['course_sys_data'].'document');
+                    }
+                }
+                break;
+            case 'paste':
+                break;
+        }
+    }
+
+    function getOperations() {
+        $opts = array(
+            //'debug' => true,
+            'bind' => array(
+                'mkdir mkfile rename duplicate upload rm paste' => array($this, 'logger')
+                //'mkdir mkfile rename duplicate upload rm paste' => 'chamilo'
+            )
+        );
+
+        $courseInfo = api_get_course_info();
+        $userId = api_get_user_id();
+
+        $commonAttributes = array(
+            // hide dangerous files
+            array(
+                'pattern' => '/\.(php|py|pl|sh|xml)$/i',
+                'read' => false,
+                'write' => false,
+                'hidden' => true,
+                'locked' => false
+            ),
+            // Hide _DELETED_ files
+            array(
+                'pattern' => '/_DELETED_/',
+                'read' => false,
+                'write' => false,
+                'hidden' => true,
+                'locked' => false
+            )
+        );
+
+        /*
+
+        var defaultCommands = [
+            'open', 'reload', 'home', 'up', 'back', 'forward', 'getfile', 'quicklook',
+            'download', 'rm', 'duplicate', 'rename', 'mkdir', 'mkfile', 'upload', 'copy',
+            'cut', 'paste', 'edit', 'extract', 'archive', 'search', 'info', 'view', 'help',
+            'resize', 'sort'
+        ];
+        */
+
+        // for more options: https://github.com/Studio-42/elFinder/wiki/Connector-configuration-options
+        $commonSettings = array(
+            'uploadOverwrite' => false, // Replace files on upload or give them new name if the same file was uploaded
+            //'acceptedName' =>
+            'uploadAllow' => array(
+                'image',
+                'audio',
+                'video',
+                'text/html',
+                'application/pdf',
+                'application/postscript',
+                'application/vnd.ms-word',
+                'application/vnd.ms-excel',
+                'application/vnd.ms-powerpoint',
+                'application/vnd.ms-powerpoint',
+                'application/pdf',
+                'application/xml',
+                'application/vnd.oasis.opendocument.text',
+                'application/x-shockwave-flash'
+            ), # allow files
+            //'uploadDeny' => array('text/x-php'),
+            'uploadOrder' => array('allow'), // only executes allow
+            'disabled' => array (
+                'duplicate','rename', 'mkdir', 'mkfile', 'copy', 'cut', 'paste', 'edit', 'extract', 'archive', 'help', 'resize'
+            )
+        );
+
+        if (!empty($courseInfo)) {
+
+            // Adding course driver
+            $opts['roots'][] = array(
+                'driver'     => 'LocalFileSystem',
+                'path'       => api_get_path(SYS_DATA_PATH).'courses/'.$courseInfo['path'].'/document',
+                'startPath'  => '/',
+                'URL' => api_get_path(REL_COURSE_PATH).$courseInfo['path'].'/document',
+                //'alias' => $courseInfo['code'].' documents',
+                'accessControl' => array($this, 'access'),
+                'attributes' => array(
+                    // Hide shared_folder
+                    array(
+                        'pattern' => '/shared_folder/',
+                        'read' => false,
+                        'write' => false,
+                        'hidden' => true,
+                        'locked' => false
+                    ),
+                )
+            );
+
+            // Adding course user file driver
+
+            if (!empty($userId)) {
+                $opts['roots'][] = array(
+                    'driver'     => 'LocalFileSystem',
+                    'path'       => api_get_path(SYS_DATA_PATH).'courses/'.$courseInfo['path'].'/document/shared_folder/sf_user_'.$userId,
+                    'startPath'  => '/',
+                    //'alias' => $courseInfo['code'].' personal documents',
+                    'URL' => api_get_path(REL_COURSE_PATH).$courseInfo['path'].'/document/shared_folder/sf_user_'.$userId,
+                    'accessControl' => 'access'
+                );
+
+                // Adding user personal files
+
+                $dir = \UserManager::get_user_picture_path_by_id($userId, 'system');
+                $dirWeb = \UserManager::get_user_picture_path_by_id($userId, 'web');
+
+                $opts['roots'][] = array(
+                    'driver'     => 'LocalFileSystem',
+                    'path'       => $dir['dir'].'my_files',
+                    'startPath'  => '/',
+                    //'alias' => 'Personal documents',
+                    'URL' => $dirWeb['dir'].'my_files',
+                    'accessControl' => 'access'
+                );
+            }
+        } else {
+            // Adding user personal files
+
+            $dir = \UserManager::get_user_picture_path_by_id($userId, 'system');
+            $dirWeb = \UserManager::get_user_picture_path_by_id($userId, 'web');
+
+            $opts['roots'][] = array(
+                'driver'     => 'LocalFileSystem',
+                'path'       => $dir['dir'].'my_files',
+                'startPath'  => '/',
+                'URL' => $dirWeb['dir'].'my_files',
+                'accessControl' => 'access'
+            );
+        }
+
+        // Add home portal
+        if (api_is_platform_admin()) {
+            $home = api_get_path(SYS_DATA_PATH).'home';
+            $opts['roots'][] = array(
+                'driver'     => 'LocalFileSystem',
+                'path'       => $home,
+                'startPath'  => '/',
+                'URL' => api_get_path(WEB_DATA_PATH).'home',
+                'accessControl' => 'access'
+            );
+        }
+
+        // Injecting common file filters
+        foreach ($opts['roots'] as &$driver) {
+            $driver = array_merge($driver, $commonSettings);
+            if (isset($driver['attributes'])) {
+                $driver['attributes']  = array_merge($driver['attributes'], $commonAttributes);
+            } else {
+                $driver['attributes']  = $commonAttributes;
+            }
+        }
+
+        return $opts;
+    }
+}

+ 11 - 10
src/ChamiloLMS/Component/Editor/Editor.php

@@ -1,4 +1,5 @@
 <?php
+
 namespace ChamiloLMS\Component\Editor;
 
 class Editor
@@ -80,14 +81,15 @@ class Editor
     {
         $Html = '<textarea id="'.$this->InstanceName.'" name="'.$this->InstanceName.'" class="ckeditor" >'.$this->Value.'</textarea>';
         $Html .= $this->ckeditorReplace();
+
         return $Html;
     }
 
     public function ckeditorReplace()
     {
-        $toolbar = new Toolbar\Basic($this->ToolbarSet);
-        $config  = $toolbar->getConfig();
-        $js = $this->to_js($config);
+        $toolbar  = new Toolbar\Basic($this->ToolbarSet);
+        $config   = $toolbar->getConfig();
+        $js       = $this->to_js($config);
         $settings = null;
 
         $Html = "<script>
@@ -167,19 +169,19 @@ class Editor
     private function to_js($var)
     {
         switch (gettype($var)) {
-            case 'boolean' :
+            case 'boolean':
                 return $var ? 'true' : 'false'; // Lowercase necessary!
-            case 'integer' :
-            case 'double' :
+            case 'integer':
+            case 'double':
                 return (string)$var;
-            case 'resource' :
-            case 'string' :
+            case 'resource':
+            case 'string':
                 return '"'.str_replace(
                     array("\r", "\n", "<", ">", "&"),
                     array('\r', '\n', '\x3c', '\x3e', '\x26'),
                     addslashes($var)
                 ).'"';
-            case 'array' :
+            case 'array':
                 // Arrays in JSON can't be associative. If the array is empty or if it
                 // has sequential whole number keys starting with 0, it's not associative
                 // so we can go ahead and convert it as an array.
@@ -197,7 +199,6 @@ class Editor
                 foreach ($var as $k => $v) {
                     $output[] = $this->to_js(strval($k)).': '.$this->to_js($v);
                 }
-
                 return '{ '.implode(', ', $output).' }';
             default:
                 return 'null';

+ 1 - 1
src/ChamiloLMS/Component/Editor/Toolbar/Basic.php

@@ -60,7 +60,7 @@ class Basic
         // file manager (elfinder)
 
         // http://docs.cksource.com/ckeditor_api/symbols/CKEDITOR.config.html
-        $config['filebrowserBrowseUrl'] = api_get_path(WEB_CODE_PATH).'inc/lib/elfinder/elfinder.html';
+        $config['filebrowserBrowseUrl'] = api_get_path(WEB_PUBLIC_PATH).'editor/filemanager';
 
         /*filebrowserFlashBrowseUrl
         filebrowserFlashUploadUrl

+ 46 - 0
src/ChamiloLMS/Controller/EditorController.php

@@ -0,0 +1,46 @@
+<?php
+/* For licensing terms, see /license.txt */
+
+namespace ChamiloLMS\Controller;
+
+use Silex\Application;
+use Symfony\Component\HttpFoundation\Response;
+use Symfony\Component\HttpFoundation\Request;
+use Symfony\Component\HttpKernel\HttpKernelInterface;
+use ChamiloLMS\Component\Editor\Connector;
+
+/**
+ * @package ChamiloLMS.Controller
+ * @author Julio Montoya <gugli100@gmail.com>
+ */
+class EditorController
+{
+    /**
+     * @param Application $app
+     */
+    public function filemanagerAction(Application $app)
+    {
+        //$response = $app['template']->render_layout('javascript/elfinder.tpl');
+        $response = $app['template']->render_template('javascript/elfinder.tpl');
+
+        //return new Response($response, 200, array('Cache-Control' => 's-maxage=3600, public'));
+        return new Response($response, 200, array());
+    }
+
+    public function connectorAction(Application $app)
+    {
+        $chamiloConnector = new Connector();
+        $opts = $chamiloConnector->getOperations();
+
+        error_reporting(0); // Set E_ALL for debuging
+
+        include_once api_get_path(LIBRARY_PATH).'elfinder/php/elFinderConnector.class.php';
+        include_once api_get_path(LIBRARY_PATH).'elfinder/php/elFinder.class.php';
+        include_once api_get_path(LIBRARY_PATH).'elfinder/php/elFinderVolumeDriver.class.php';
+        include_once api_get_path(LIBRARY_PATH).'elfinder/php/elFinderVolumeLocalFileSystem.class.php';
+
+        // run elFinder
+        $connector = new \elFinderConnector(new \elFinder($opts));
+        $connector->run();
+    }
+}