function definition() { global $DB, $USER; $mform = & $this->_form; $ret = array('locations' => array('course' => 'course')); $sql = 'SELECT i.name, i.typeid, r.type FROM {repository} r, {repository_instances} i WHERE r.type=? AND i.typeid=r.id'; $repository = $DB->get_record_sql($sql, array('elisfiles')); if ($repository) { try { $repo = new repository_elisfiles('elisfiles', context_user::instance($USER->id), array( 'ajax' => false, 'name' => $repository->name, 'type' => 'elisfiles') ); if (!empty($repo)) { $ret = $repo->get_listing(); } } catch (Exception $e) { $repo = null; } } // ob_start(); // var_dump($ret); // $tmp = ob_get_contents(); // ob_end_clean(); // error_log("alfresco_filemanager::test_form:: ret = {$tmp}"); $fm_options = array('maxfiles' => -1, 'maxbytes' => 1000000000, 'sesskey' => sesskey(), 'locations' => $ret['locations'] // TBD ); $attrs = null; // TBD $this->afm_elem = $mform->createElement('alfresco_filemanager', 'files_filemanager', // NOTE: ^^^ element name MUST be 'files_filemanager' '<b>Alfresco File Manager Form Element</b>', $attrs, array_merge($fm_options, $this->_customdata['options'])); $mform->addElement($this->afm_elem); $mform->addElement('hidden', 'returnurl', $this->_customdata['data']->returnurl); $mform->setType('returnurl', PARAM_URL); $this->add_action_buttons(true, get_string('savechanges')); $this->set_data($this->_customdata['data']); }
/** * Test that searching for folders does not return results * @uses $CFG, $DB */ public function test_folder_search() { $this->resetAfterTest(true); $this->setup_test_data_xml(); $data = null; $listing = null; $options = array( 'ajax' => false, 'name' => 'elis files phpunit test', 'type' => 'elisfiles' ); if (!$repo = new repository_elisfiles('elisfiles', context_system::instance(), $options)) { $this->markTestSkipped('Repository not configured or enabled'); } $parentfolderuuid = $repo->elis_files->get_root()->uuid; $folder = FOLDER_NAME_PREFIX.'1'; $repo->elis_files->create_dir($folder, $parentfolderuuid, '', true); $result = $repo->search($folder); $this->assertEmpty($result['list']); }
/** * Prepares list of files before passing it to AJAX, makes sure data is in the correct * format and stores formatted values. * * @param array|stdClass $listing result of get_listing() or search() or file_get_drafarea_files() * @param string $parent encoded path of parent folder * @uses $CFG * @uses $OUTPUT * @return list((array)listing, count) */ public function prepare_fm_listing($listing, $parent = '') { global $CFG, $OUTPUT; $locations = null; if (is_array($listing) && !empty($listing['locations'])) { $locations = &$listing['locations']; } else if (is_object($listing) && !empty($listing->locations)) { $locations = &$listing->locations; } if (is_array($listing) && !empty($listing['parent']) && !empty($listing['parent']->uuid)) { $parent = repository_elisfiles::build_encodedpath($listing['parent']->uuid); } else if (is_object($listing) && !empty($listing->parent) && !empty($listing->parent->uuid)) { $parent = repository_elisfiles::build_encodedpath($listing->parent->uuid); } $defaultfoldericon = $OUTPUT->pix_url(file_folder_icon(64))->out(false); // prepare $listing['path'] or $listing->path if (is_array($listing) && isset($listing['path']) && is_array($listing['path'])) { $path = &$listing['path']; } else if (is_object($listing) && isset($listing->path) && is_array($listing->path)) { $path = &$listing->path; } $elisfilesfolder = array(); $companyhomefolder = array(); $textpath = ''; $lastpathvalue = 0; if (isset($path)) { $len = count($path); for ($i = 0; $i < $len; $i++) { $pathname = false; $pathvalue = false; if (is_array($path[$i])) { if (!isset($path[$i]['icon'])) { $path[$i]['icon'] = $defaultfoldericon; } if (!empty($path[$i]['name'])) { $pathname = $path[$i]['name']; } if (!empty($path[$i]['path'])) { $pathvalue = $path[$i]['path']; } } else if (is_object($path[$i])) { if (!isset($path[$i]->icon)) { $path[$i]->icon = $defaultfoldericon; } if (!empty($path[$i]->name)) { $pathname = $path[$i]->name; } if (!empty($path[$i]->path)) { $pathvalue = $path[$i]->path; } } if ($pathname == $this->elis_files->get_root()->title) { $pathname = get_string('repository', 'repository_elisfiles'); if (is_array($path[$i])) { $path[$i]['name'] = $pathname; } else { $path[$i]->name = $pathname; } $companyhomefolder['filepath'] = $pathvalue; $companyhomefolder['textpath'] = $pathname; $companyhomefolder['fullname'] = $pathname; $companyhomefolder['id'] = $pathvalue; // TBD $companyhomefolder['sortorder'] = 0; // TBD $companyhomefolder['children'] = array(); } $textpath .= (!empty($textpath) ? '/' : '') . $pathname; } } // prepare $listing['list'] or $listing->list if (is_array($listing) && isset($listing['list']) && is_array($listing['list'])) { $listing['list'] = array_values($listing['list']); // convert to array $files = &$listing['list']; } else if (is_object($listing) && isset($listing->list) && is_array($listing->list)) { $listing->list = array_values($listing->list); // convert to array $files = &$listing->list; } else { return array($listing, 0); // TBD } $len = count($files); for ($i = 0; $i < $len; $i++) { if (is_object($files[$i])) { $file = (array)$files[$i]; $converttoobject = true; } else { $file = & $files[$i]; $converttoobject = false; } if (!empty($parent)) { $file['parent'] = $parent; } if (isset($file['size'])) { // TBD $file['size'] = (int)$file['size']; $file['size_f'] = display_size($file['size']); } if (isset($file['license']) && get_string_manager()->string_exists($file['license'], 'license')) { $file['license_f'] = get_string($file['license'], 'license'); } if (isset($file['image_width']) && isset($file['image_height'])) { $a = array('width' => $file['image_width'], 'height' => $file['image_height']); $file['dimensions'] = get_string('imagesize', 'repository', (object)$a); } // Map date fields foreach (array('datemodified', 'datecreated' ) as $key) { if (!isset($file[$key]) && isset($file['date'])) { $file[$key] = userdate($file['date']); } if (isset($file[$key])) { $file[$key.'_f'] = userdate($file[$key], get_string('strftimedatetime', 'langconfig')); $file[$key.'_f_s'] = userdate($file[$key], get_string('strftimedatetimeshort', 'langconfig')); } } // Map other fields foreach (array('author' => 'author', 'path' => 'filepath' // TBD ) as $key => $value) { if (isset($file[$key])) { $file[$value] = $file[$key]; } else { $file[$value] = ''; // TBD } } $isfolder = (array_key_exists('children', $file) || (isset($file['type']) && $file['type'] == 'folder')); if (!isset($file['type'])) { $file['type'] = $isfolder ? 'folder' : 'file'; } $filename = null; if (isset($file['title'])) { $filename = $file['title']; } else if (isset($file['fullname'])) { $filename = $file['fullname']; } if ($filename) { $file['filename'] = $filename; $file['fullname'] = $filename; } if (isset($file['source'])) { $file['url'] = $this->get_link($file['source']); } //error_log("/repository/elisfiles/lib.php::prepare_listing(): filepath = {$textpath}"); $file['textpath'] = $textpath; // TBD if (!isset($file['mimetype']) && !$isfolder && $filename) { $file['mimetype'] = get_mimetype_description(array('filename' => $filename)); } if (!isset($file['icon'])) { if ($isfolder) { $file['icon'] = $defaultfoldericon; } else if ($filename) { $file['icon'] = $OUTPUT->pix_url(file_extension_icon($filename, 90))->out(false); } } if ($converttoobject) { $files[$i] = (object)$file; } } // Now build the entire folder tree, respecting "create" permissions ... $folders = elis_files_folder_structure(true); $foldertree = array(); $this->folder_tree_to_fm($foldertree, $folders, $companyhomefolder['textpath']); // Must add missing 'ELIS Files' & 'Company Home' locations to tree // if permissions allow // For this, we care about the "root" node $root_uuid = $this->elis_files->get_root()->uuid; // Validate whether the current user has proper "site-level create" permissions $access_permitted = $this->check_editing_permissions(SITEID, 0, 0, $root_uuid, 0); if (!empty($companyhomefolder) && $access_permitted) { // We have access to 'Company Home' $companyhomefolder['children'] = $foldertree; $foldertree = array($companyhomefolder); } if (ELIS_FILES_DEBUG_TRACE) { ob_start(); var_dump($folders); $tmp = ob_get_contents(); ob_end_clean(); error_log("/repository/elisfiles/lib.php::prepare_fm_listing(): folders = {$tmp}"); ob_start(); var_dump($foldertree); $tmp = ob_get_contents(); ob_end_clean(); error_log("/repository/elisfiles/lib.php::prepare_fm_listing(): foldertree = {$tmp}"); } if (is_array($listing)) { $listing['tree'] = array('children' => $foldertree); } else { $treeelm = new stdClass; $treeelm->children = $foldertree; $listing->tree = $treeelm; } return array($listing, $len); }
/** * Test times for get_parent using recursive get_parent alfresco calls * @uses $CFG, $DB */ public function test_get_parent_path_tree() { global $CFG, $DB; $this->resetAfterTest(true); $this->setup_test_data_xml(); $options = array( 'ajax' => false, 'name' => 'elis files phpunit test', 'type' => 'elisfiles' ); $repo = new repository_elisfiles('elisfiles', context_system::instance(), $options); // Make sure we connected to the repository successfully. if (empty($repo->elis_files)) { $this->markTestSkipped('Repository not configured or enabled'); } // set up the storage for the full path of the path's UUIDs to validate against $expectedpath = array(); // create folder, get uuid, get path via get_parent_path and elis_files_folder structure // for first folder, create under moodle, then create under the previous folder... $parentfolderuuid = $repo->elis_files->get_root()->uuid; $times = array(); for ($i = 1; $i <= 20; $i++) { $currentfolder = FOLDER_NAME_PREFIX.$i; $currentfolderuuid = $repo->elis_files->create_dir($currentfolder, $parentfolderuuid, '', true); // add the parent folder to our expected sequence of UUIDs $expectedpath[] = repository_elisfiles::build_encodedpath($parentfolderuuid); // elis_files_folder_structure get_parent_path test $starttime = microtime(); $folders = elis_files_folder_structure(); $altrecursivepath = array(); $repo->get_parent_path($currentfolderuuid, $altrecursivepath, 0, 0, 0, 0, 'tree'); $endtime = time(); $structuretime = microtime_diff($starttime, microtime()); // validate the count $this->assertEquals($i, count($altrecursivepath)); // validate the encoded folder UUIDs // look over the expected path parts foreach ($expectedpath as $pathindex => $expectedpart) { // obtain the matching part from the actual return value $resultpart = $altrecursivepath[$pathindex]; $this->assertEquals($expectedpart, $resultpart['path']); } // NOTE: add this back in if we are testing performance $times[] = $times[] = "Folder: $currentfolder and time: $structuretime"; // or nested folders $parentfolderuuid = $currentfolderuuid; } }
/** * Obtain the current (i.e. "default") path for the provided course, depending * on the configured default browse location * * @param int $courseid The id of the course whose file picker view we are currently * on, or SITEID if we are viewing private files * @param bool $default True if desire default browsing location * @return string The encoded path corresponding to the current location */ function elis_files_get_current_path_for_course($courseid, $default = false) { global $CFG, $DB, $USER; require_once($CFG->dirroot.'/repository/elisfiles/lib.php'); // Default to the Moodle area $currentpath = '/'; // Determine if the ELIS Files repository is enabled $sql = 'SELECT i.name, i.typeid, r.type FROM {repository} r JOIN {repository_instances} i WHERE r.type = ? AND i.typeid = r.id'; $repository = $DB->get_record_sql($sql, array('elisfiles'), IGNORE_MISSING); if ($repository) { // Initialize repository plugin try { $ctx = context_user::instance($USER->id); $options = array( 'ajax' => false, 'name' => $repository->name, 'type' => 'elisfiles' ); $repo = new repository_elisfiles('elisfiles', $ctx, $options); if (!empty($repo->elis_files)) { // TBD: Is the following required??? //$listing = (object)$repo->get_listing(true); $uuid = ($courseid == SITEID) ? false // No Site course folder, use default location : $repo->elis_files->get_course_store($courseid); // Determine the default browsing location $cid = $courseid; $uid = 0; $shared = false; $oid = 0; if ($default || empty($uuid)) { $uuid = $repo->elis_files->get_default_browsing_location($cid, $uid, $shared, $oid); } if ($uuid != false) { // Encode the UUID $currentpath = repository_elisfiles::build_encodedpath($uuid, $uid, $cid, $oid, $shared); } } } catch (Exception $e) { // The parent "repository" class may throw exceptions // error_log("/repository/elisfiles/lib/lib.php::elis_files_get_current_path_for_course({$courseid}): Exception: ". $e->getMessage()); } } return $currentpath; }
/** * Check for valid permissions given the storage context for a file, also taking * into account the location where the file was included within Moodle. * * @uses $CFG * @uses $USER * @param string $uuid Unique identifier for a node. * @param int $uid The user ID (optional). * @param bool $useurl Check the referring URL for Moodle-based permissions (default: true). * @param object $repo ELIS Files repo object to use (only for unit testing) * @return bool True if the user has permission to access the file, False otherwise. */ function permission_check($uuid, $uid = 0, $useurl = true, $repo = NULL) { global $CFG, $DB, $USER; require_once($CFG->dirroot .'/repository/elisfiles/lib.php'); // error_log("/repository/elisfiles/lib/lib.php::permission_check({$uuid}, {$uid}, {$useurl})"); if (ELIS_FILES_DEBUG_TRACE) mtrace('permission_check(' . $uuid . ', ' . $uid . ', ' . ($useurl === true ? 'true' : 'false') . ')'); if ($repo === NULL) { $repo = new repository_elisfiles('elisfiles', context_system::instance(), array('ajax' => false, 'type' => 'elisfiles')); } $repo->get_parent_path($uuid, $result, 0, 0, 0, 0); if (!empty($this->config->root_folder)) { $moodleroot = $this->config->root_folder; } else { $moodleroot = '/moodle'; } // get the flags for uid, cid, oid and shared $uid = 0; $cid = 0; $oid = 0; $shared = false; $parent_node = $this->get_parent($uuid); $prev_node = $this->get_info($uuid); do { $check_uuid = !empty($parent_node->uuid) ? $parent_node->uuid : 0; $folder_name = !empty($prev_node->title) ? $prev_node->title : ''; if ($check_uuid == $this->cuuid) { $cid = $DB->get_field('repository_elisfiles_course', 'courseid', array('uuid' => $prev_node->uuid)); } else if ($check_uuid == $this->ouuid) { $oid = $DB->get_field('repository_elisfiles_userset', 'usersetid', array('uuid' => $prev_node->uuid)); } else if ($check_uuid == $this->suuid) { $shared = true; } else if (!empty($prev_node->uuid) && $prev_node->uuid == $this->uuuid) { $uid = elis_files_folder_to_userid($folder_name); } $prev_node = $parent_node; } while (!$uid && !$cid && !$oid && !$shared && ($parent_node = $this->get_parent($check_uuid)) && !empty($parent_node->uuid)); if (!empty($cid)) { $cid = $DB->get_field('course', 'id', array('id' => $cid), IGNORE_MULTIPLE); // This is a server file. if ($cid == SITEID) { $context = context_system::instance(); } // This is a course file. if (!empty($cid)) { $context = context_course::instance($cid); } } // This is a shared file. if ($shared) { $context = context_system::instance(); } // This is a user file. if (!empty($uid)) { $info = $this->get_info($this->uuuid); if (isset($info->title)) { $username = str_replace('_AT_', '@', $info->title); //error_log("preg_match('/\/User\sHomes\/([-_a-zA-Z0-9\s]+)\//', {$path}, = {$tmp}) => username = {$username}"); $context = context_system::instance(); } } /// This is a userset file. if (!empty($oid)) { $cluster_context = \local_elisprogram\context\userset::instance($oid); } /// Default to the root of the Alfresco repository (requires system-level repository access). if (!isset($context)) { $context = context_system::instance(); } /// Attempt to determine where the file open request came from to determine if the current user /// has permission to access that file in Moodle (this overrides the current user's Alfresco /// permissions. $referer = $this->get_referer(); if ($useurl && !empty($referer)) { $fromplugin = strpos($referer, $CFG->wwwroot.'/pluginfile.php') !== false; $frommodule = strpos($referer, $CFG->wwwroot . '/mod/') !== false; $fromblock = strpos($referer, $CFG->wwwroot . '/blocks/') !== false; $frommodedit = strpos($referer, '/course/modedit.php') !== false; $fromeditor = strpos($referer, '/lib/editor/htmlarea/blank.html') !== false; $fromcourse = strpos($referer, '/course/view.php') !== false; $fromsite = ($referer == $CFG->wwwroot . '/' || $referer == $CFG->wwwroot || $referer == $CFG->wwwroot . '/index.php'); // error_log("ELIS_files::permissions_check(): fromplugin={$fromplugin}, frommodule={$frommodule}, fromblock={$fromblock}" // .", frommodedit={$frommodedit}, fromeditor={$fromeditor}, fromcourse={$fromcourse}, fromsite={$fromsite}"); /// If this access is coming from something inside of the mod or blocks directory, then allow access. if ($frommodule || $fromblock || $fromeditor) { return true; } if (!empty($referer) && ($frommodedit || $fromcourse || $fromsite || $fromplugin)) { if ($fromsite) { return true; } else if ($frommodedit) { /// Look for the CM ID from editing a module. preg_match('/.+?update=([0-9]+)/', $referer, $matches); if (count($matches) == 2) { $sql = "SELECT cm.*, m.name as modname FROM {$CFG->prefix}course_modules cm INNER JOIN {$CFG->prefix}modules m ON m.id = cm.module WHERE cm.id = " . $matches[1]; if ($cm = $DB->get_record_sql($sql)) { require_login($cm->course, false, $cm, false); } } } else if ($fromcourse) { /// Look for the course ID. preg_match('/.+?id=([0-9]+)/', $referer, $matches); if (count($matches) == 2) { require_login($matches[1], false, false, false); } } else if ($fromplugin) { // Look for module contextid preg_match('/pluginfile.php\/([0-9]+)\/mod/', $referer, $matches); if (count($matches) != 2 && !$CFG->slasharguments) { // Look for 'file' url parameter in referer preg_match('/file=\/([0-9]+)\/mod/', $referer, $matches); } if (count($matches) == 2 && ($instanceid = $DB->get_field('context', 'instanceid', array('id' => $matches[1]))) !== false && ($cm = $DB->get_record('course_modules', array('id' => $instanceid)))) { // error_log("ELIS_files::permissions_check(): pluginfile instanceid = {$instanceid}"); require_login($cm->course, false, $cm, false); } } } /// This file didn't come from somewhere within Moodle that we know about so access has /// to be determined based on the Alfresco capabilities the current user has. } else { // Get the non context based permissions $capabilities = array( 'repository/elisfiles:viewowncontent' => false, 'repository/elisfiles:createowncontent' => false, 'repository/elisfiles:viewsharedcontent' => false, 'repository/elisfiles:createsharedcontent' => false ); $this->get_other_capabilities($USER, $capabilities); // Determine if the user has "site files" permissions $syscontext = context_system::instance(); $allowsitefiles = has_capability('repository/elisfiles:viewsitecontent', $syscontext) || has_capability('repository/elisfiles:createsitecontent', $syscontext); if ($uid) { /// If the current user is not the user who owns this file and we can't access anything in the /// repository, don't allow access. if ($USER->username != $username && !has_capability('repository/elisfiles:viewsitecontent', $context)) { return false; } /// This repository location is not tied to a specific Moodle context, so we need to look for the /// specific capability anywhere within the user's role assignments. $hascap = $allowsitefiles || $capabilities['repository/elisfiles:viewowncontent'] || $capabilities['repository/elisfiles:createowncontent']; if (!$hascap) { return false; } } else if ($cid) { /// This file belongs to a course, make sure the current user can access that course's repository /// content. $hascap = $allowsitefiles || has_capability('repository/elisfiles:viewcoursecontent', $context) || has_capability('repository/elisfiles:createcoursecontent', $context); if (!$hascap) { return false; } } else if ($oid) { /// This file belongs to a course, make sure the current user can access that course's repository /// content. $hascap = $allowsitefiles || has_capability('repository/elisfiles:viewusersetcontent', $cluster_context) || has_capability('repository/elisfiles:createusersetcontent', $cluster_context); if (!$hascap) { return false; } } else if ($shared) { /// This repository location is not tied to a specific Moodle context, so we need to look for the /// specific capability anywhere within the user's role assignments. $hascap = $allowsitefiles || $capabilities['repository/elisfiles:viewsharedcontent'] || $capabilities['repository/elisfiles:createsharedcontent']; if (!$hascap) { return false; } } else { /// This file is not part of a standard Moodle storage area thus requiring full repository access. if (!$allowsitefiles) { return false; } } } return true; }
/** * Validate that the "check_editing_permissions" method respects site files * capabilities assigned at the system level * @uses $USER, $DB * @param boolean $course True if checking permissions on course files * @param boolean $shared True if checking permissions on shared files * @param boolean $userset True if checking permissions on userset files * @param boolean $own True if checking permissions on own (personal) files * @dataProvider node_flag_provider */ public function test_check_editing_permissions_respects_site_files($course, $shared, $userset, $own) { if (!class_exists('elispm')) { $this->markTestSkipped('elis_program needed for test'); return false; } $this->resetAfterTest(true); $this->setup_test_data_xml(); global $USER, $DB; // Make sure the test user is not mistaken for a site admin or guest set_config('siteadmins', ''); set_config('siteguest', ''); // Setup $this->setUser(100); $roleid = $this->assign_role_capability('repository/elisfiles:createsitecontent'); // Assign the test role to the test user $context = context_system::instance(); role_assign($roleid, $USER->id, $context->id); // Determine the correct set of parameters $id = SITEID; // Note: shared left as-is $oid = false; $userid = 0; // Note: UUID is not currently used in the method we are testing $uuid = false; // RL: ELIS files: Alfresco $data = null; $listing = null; $options = array( 'ajax' => false, 'name' => 'elis files phpunit test', 'type' => 'elisfiles' ); try { $repo = new repository_elisfiles('elisfiles', context_system::instance(), $options); } catch (Exception $e) { $this->markTestSkipped('Exception when creating repository_elisfiles object: '.$e->getMessage()); } if ($course) { $id = 99; $mapping = new stdClass; $mapping->courseid = $id; $mapping->uuid = 'testuuid'; $DB->insert_record('repository_elisfiles_course', $mapping); } if ($userset) { require_once(elispm::lib('data/userset.class.php')); $userset = new userset(array( 'name' => 'testusersetname' )); $userset->save(); $mapping = new stdClass; $oid = $mapping->usersetid = $userset->id; $uuid = $mapping->uuid = 'testuuid'; $DB->insert_record('repository_elisfiles_userset', $mapping); } if ($own) { $userid = $USER->id; } // Run the permission check method $haspermission = $repo->check_editing_permissions($id, $shared, $oid, $uuid, $userid); // Validation $this->assertTrue($haspermission); }