示例#1
0
 /**
  * Create method for this handler
  *
  * @return array of assets created
  **/
 public function create()
 {
     // Include needed files
     require_once dirname(dirname(__DIR__)) . DS . 'tables' . DS . 'asset.association.php';
     require_once dirname(dirname(__DIR__)) . DS . 'tables' . DS . 'asset.php';
     require_once dirname(__DIR__) . DS . 'asset.php';
     // Get the file
     if (isset($_FILES['files'])) {
         $file = $_FILES['files']['name'][0];
         $size = (int) $_FILES['files']['size'];
         // Get the file extension
         $pathinfo = pathinfo($file);
         $filename = $pathinfo['filename'];
         $ext = $pathinfo['extension'];
     } else {
         return array('error' => 'No files provided');
     }
     // @FIXME: should these come from the global settings, or should they be courses specific
     // Get config
     $config = Component::params('com_media');
     // Max upload size
     $sizeLimit = (int) $config->get('upload_maxsize');
     $sizeLimit = $sizeLimit * 1024 * 1024;
     // Check to make sure we have a file and its not too big
     if ($size == 0) {
         return array('error' => 'File is empty');
     }
     if ($size > $sizeLimit) {
         $max = preg_replace('/<abbr \\w+=\\"\\w+\\">(\\w{1,3})<\\/abbr>/', '$1', \Hubzero\Utility\Number::formatBytes($sizeLimit));
         return array('error' => "File is too large. Max file upload size is {$max}");
     }
     // Create our asset table object
     $assetObj = new Tables\Asset($this->db);
     $this->asset['title'] = $filename;
     $this->asset['type'] = !empty($this->asset['type']) ? $this->asset['type'] : 'file';
     $this->asset['subtype'] = !empty($this->asset['subtype']) ? $this->asset['subtype'] : 'file';
     $this->asset['url'] = $file;
     $this->asset['created'] = Date::toSql();
     $this->asset['created_by'] = App::get('authn')['user_id'];
     $this->asset['course_id'] = Request::getInt('course_id', 0);
     // Save the asset
     if (!$assetObj->save($this->asset)) {
         return array('error' => 'Asset save failed');
     }
     // Create asset assoc object
     $assocObj = new Tables\AssetAssociation($this->db);
     $this->assoc['asset_id'] = $assetObj->get('id');
     $this->assoc['scope'] = Request::getCmd('scope', 'asset_group');
     $this->assoc['scope_id'] = Request::getInt('scope_id', 0);
     // Save the asset association
     if (!$assocObj->save($this->assoc)) {
         return array('error' => 'Asset association save failed');
     }
     // Get courses config
     $cconfig = Component::params('com_courses');
     // Build the upload path if it doesn't exist
     $uploadDirectory = PATH_APP . DS . trim($cconfig->get('uploadpath', '/site/courses'), DS) . DS . $this->asset['course_id'] . DS . $this->assoc['asset_id'] . DS;
     // Make sure upload directory exists and is writable
     if (!is_dir($uploadDirectory)) {
         if (!Filesystem::makeDirectory($uploadDirectory, 0755, true)) {
             return array('error' => 'Server error. Unable to create upload directory');
         }
     }
     if (!is_writable($uploadDirectory)) {
         return array('error' => 'Server error. Upload directory isn\'t writable');
     }
     // Get the final file path
     $target_path = $uploadDirectory . $filename . '.' . $ext;
     // Move the file to the site folder
     set_time_limit(60);
     // Scan for viruses
     if (!Filesystem::isSafe($_FILES['files']['tmp_name'][0])) {
         // Scan failed, delete asset and association and return an error
         $assetObj->delete();
         $assocObj->delete();
         Filesystem::deleteDirectory($uploadDirectory);
         return array('error' => 'File rejected because the anti-virus scan failed.');
     }
     if (!($move = move_uploaded_file($_FILES['files']['tmp_name'][0], $target_path))) {
         // Move failed, delete asset and association and return an error
         $assetObj->delete();
         $assocObj->delete();
         Filesystem::deleteDirectory($uploadDirectory);
         return array('error' => 'Move file failed');
     }
     // Get the url to return to the page
     $course_id = Request::getInt('course_id', 0);
     $offering_alias = Request::getCmd('offering', '');
     $course = new \Components\Courses\Models\Course($course_id);
     $url = Route::url('index.php?option=com_courses&controller=offering&gid=' . $course->get('alias') . '&offering=' . $offering_alias . '&asset=' . $assetObj->get('id'));
     $url = rtrim(str_replace('/api', '', Request::root()), '/') . '/' . ltrim($url, '/');
     $return_info = array('asset_id' => $this->assoc['asset_id'], 'asset_title' => $this->asset['title'], 'asset_type' => $this->asset['type'], 'asset_subtype' => $this->asset['subtype'], 'asset_url' => $url, 'course_id' => $this->asset['course_id'], 'offering_alias' => Request::getCmd('offering', ''), 'scope_id' => $this->assoc['scope_id'], 'asset_ext' => $ext, 'upload_path' => $uploadDirectory, 'target_path' => $target_path);
     // Return info
     return array('assets' => $return_info);
 }
示例#2
0
 /**
  * Check whether or not the student is passing the course and has completed all items
  *
  * @param      int $member_id
  * @return     bool
  **/
 public function isEligibleForRecognition($member_id = null)
 {
     static $assets = null;
     static $grades = null;
     // Get a grade policy object
     $gradePolicy = new GradePolicies($this->course->offering()->section()->get('grade_policy_id'), $this->course->offering()->section()->get('id'));
     if (!isset($assets)) {
         // Get the graded assets
         $asset = new Tables\Asset(\App::get('db'));
         $assets = $asset->find(array('w' => array('course_id' => $this->course->get('id'), 'section_id' => $this->course->offering()->section()->get('id'), 'offering_id' => $this->course->offering()->get('id'), 'graded' => true, 'state' => 1, 'asset_scope' => 'asset_group'), 'order_by' => 'title', 'order_dir' => 'ASC'));
         // Get gradebook auxiliary assets
         $auxiliary = $asset->findByScope('offering', $this->course->offering()->get('id'), array('asset_type' => 'gradebook', 'asset_subtype' => 'auxiliary', 'graded' => true, 'state' => 1));
         $assets = array_merge($assets, $auxiliary);
     }
     // Get totals by type
     $totals = array('exam' => 0, 'quiz' => 0, 'homework' => 0);
     $counts = array();
     if ($assets && count($assets) > 0) {
         foreach ($assets as $asset) {
             ++$totals[$asset->grade_weight];
         }
     }
     if (!isset($grades)) {
         // Get count of graded items taken
         $filters = array('member_id' => $member_id, 'scope' => 'asset', 'graded' => true);
         $grades = $this->_grades($filters);
     }
     // Restructure data
     foreach ($grades as $g) {
         if (!is_null($g->score) || !is_null($g->override)) {
             if (isset($counts[$g->member_id][$g->grade_weight])) {
                 ++$counts[$g->member_id][$g->grade_weight];
             } else {
                 $counts[$g->member_id][$g->grade_weight] = 1;
             }
         }
     }
     // Get weights to determine what counts toward the final grade
     $exam_weight = $gradePolicy->get('exam_weight');
     $quiz_weight = $gradePolicy->get('quiz_weight');
     $homework_weight = $gradePolicy->get('homework_weight');
     $return = false;
     if (isset($counts)) {
         if (!is_null($member_id) && !is_array($member_id)) {
             $member_id = (array) $member_id;
         } else {
             $member_id = array();
             foreach ($this->course->offering()->section()->members() as $m) {
                 $member_id[] = $m->get('id');
             }
         }
         // Loop though the users
         foreach ($member_id as $m) {
             $passing = $this->passing(true, $m);
             // Now make sure they've taken all required exams/quizzes/homeworks, and that they passed
             if (($exam_weight == 0 || $exam_weight > 0 && isset($counts[$m]['exam']) && $totals['exam'] == $counts[$m]['exam']) && ($quiz_weight == 0 || $quiz_weight > 0 && isset($counts[$m]['quiz']) && $totals['quiz'] == $counts[$m]['quiz']) && ($homework_weight == 0 || $homework_weight > 0 && isset($counts[$m]['homework']) && $totals['homework'] == $counts[$m]['homework']) && $passing[$m]) {
                 $return[] = $m;
             }
         }
     }
     return $return;
 }
示例#3
0
 /**
  * Get a list of assets for a unit
  *   Accepts an array of filters to apply to the list of assets
  *
  * @param   array $filters Filters to apply
  * @return  object \Components\Courses\Models\Iterator
  */
 public function assets($filters = array())
 {
     if (!isset($this->_assets) || !$this->_assets instanceof Iterator) {
         if (!isset($filters['asset_scope_id'])) {
             $filters['asset_scope_id'] = (int) $this->get('id');
         }
         if (!isset($filters['asset_scope'])) {
             $filters['asset_scope'] = 'unit';
         }
         if (!isset($filters['section_id'])) {
             $filters['section_id'] = (int) $this->get('section_id');
         }
         $tbl = new Tables\Asset($this->_db);
         if ($results = $tbl->find(array('w' => $filters))) {
             foreach ($results as $key => $result) {
                 $results[$key] = new Asset($result);
             }
         } else {
             $results = array();
         }
         $this->_assets = new Iterator($results);
     }
     return $this->_assets;
 }
示例#4
0
 /**
  * Deletes an asset
  *
  * @apiMethod POST
  * @apiUri    /courses/asset/delete
  * @apiParameter {
  * 		"name":        "asset_id",
  * 		"description": "ID of asset to delete",
  * 		"type":        "integer",
  * 		"required":    true,
  * 		"default":     null
  * }
  * @apiParameter {
  * 		"name":        "scope",
  * 		"description": "Asset scope",
  * 		"type":        "string",
  * 		"required":    true,
  * 		"default":     null
  * }
  * @apiParameter {
  * 		"name":        "scope_id",
  * 		"description": "Asset scope ID",
  * 		"type":        "integer",
  * 		"required":    true,
  * 		"default":     null
  * }
  * @return    void
  */
 public function deleteTask()
 {
     // Require authentication and authorization
     $this->authorizeOrFail();
     // First, delete the asset association
     $database = App::get('db');
     $assocObj = new AssetAssociation($database);
     // Get vars
     $asset_id = Request::getInt('asset_id', 0);
     $scope = Request::getCmd('scope', 'asset_group');
     $scope_id = Request::getInt('scope_id', 0);
     // Make sure we're not missing anything
     if (!$asset_id || !$scope || !$scope_id) {
         // Missing needed variables to identify asset association
         App::abort(404, 'Missing one of asset id, scope, or scope id');
     } else {
         // Try to load the association
         if (!$assocObj->loadByAssetScope($asset_id, $scope_id, $scope)) {
             App::abort(500, 'Loading asset association failed');
         } else {
             // Delete the association
             if (!$assocObj->delete()) {
                 App::abort(500, $assocObj->getError());
             }
         }
     }
     // Then, lookup whether or not there are other assocations connected to this asset
     $assetObj = new AssetTbl($database);
     if (!$assetObj->load($asset_id)) {
         App::abort(500, "Loading asset {$id} failed");
     }
     // See if the asset is orphaned
     if (!$assetObj->isOrphaned()) {
         // Asset isn't an orphan (i.e. it's still being used elsewhere), so we're done
         $this->send(['asset_id' => $assetObj->id]);
         return;
     }
     // If no other associations exist, we'll delete the asset file and folder on the file system
     $deleted = [];
     $params = Component::params('com_courses');
     $path = DS . trim($params->get('uploadpath', '/site/courses'), DS) . DS . $this->course_id . DS . $assetObj->id;
     // If the path exists, delete it!
     if (Filesystem::exists($path)) {
         $deleted = Filesystem::listFolderTree($path);
         Filesystem::deleteDirectory($path);
     }
     // Then we'll delete the asset entry itself
     if (!$assetObj->delete()) {
         App::abort(500, $assetObj->getError());
     }
     // Return message
     $this->send(['asset_id' => $assetObj->id, 'deleted' => $deleted]);
 }
示例#5
0
 /**
  * Save a course page
  *
  * @return  void
  */
 public function saveTask()
 {
     // Check for request forgeries
     Request::checkToken();
     // load the request vars
     $fields = Request::getVar('fields', array(), 'post', 'none', 2);
     $tmpl = Request::getVar('tmpl', '');
     // instatiate course page object for saving
     $row = new Tables\Asset($this->database);
     if (!$row->bind($fields)) {
         $this->setError($row->getError());
         $this->editTask($row);
         return;
     }
     if (!$row->check()) {
         $this->setError($row->getError());
         $this->editTask($row);
         return;
     }
     if (!$row->store()) {
         $this->setError($row->getError());
         $this->editTask($row);
         return;
     }
     $fields['asset_id'] = $row->get('id');
     $row2 = new Tables\AssetAssociation($this->database);
     $row2->loadByAssetScope($fields['asset_id'], $fields['scope_id'], $fields['scope']);
     if (!$row2->id) {
         if (!$row2->bind($fields)) {
             $this->setError($row2->getError());
             $this->editTask($row);
             return;
         }
         if (!$row2->check()) {
             $this->setError($row2->getError());
             $this->editTask($row);
             return;
         }
         if (!$row2->store()) {
             $this->setError($row2->getError());
             $this->editTask($row);
             return;
         }
     }
     // Rename the temporary upload directory if it exist
     $lid = $fields['lid'];
     if ($lid != $row->get('id')) {
         $path = PATH_APP . DS . trim($this->config->get('uploadpath', '/site/courses'), DS) . DS . $fields['course_id'];
         if (is_dir($path . DS . $lid)) {
             if (!Filesystem::move($path . DS . $lid, $path . DS . $row->get('id'))) {
                 $this->setError(Lang::txt('UNABLE_TO_MOVE_PATH'));
             }
         }
     }
     // Incoming file
     /*$file = Request::getVar('upload', '', 'files', 'array');
     		if ($file['name'])
     		{
     			$path = PATH_APP . DS . trim($this->config->get('uploadpath', '/site/courses'), DS) . DS . $fields['course_id'] . DS . $row->id;
     			// Make sure the upload path exist
     			if (!is_dir($path))
     			{
     				if (!\Filesystem::makeDirectory($path))
     				{
     					$this->setError(Lang::txt('UNABLE_TO_CREATE_UPLOAD_PATH').' '.$path);
     					$this->editTask($row);
     					return;
     				}
     			}
     
     			// Make the filename safe
     			$file['name'] = Filesystem::clean($file['name']);
     			// Ensure file names fit.
     			$ext = Filesystem::extension($file['name']);
     			$file['name'] = str_replace(' ', '_', $file['name']);
     			if (strlen($file['name']) > 230)
     			{
     				$file['name'] = substr($file['name'], 0, 230);
     				$file['name'] .= '.' . $ext;
     			}
     
     			// Perform the upload
     			if (!\Filesystem::upload($file['tmp_name'], $path . DS . $file['name']))
     			{
     				$this->setError(Lang::txt('ERROR_UPLOADING'));
     			}
     			else
     			{
     				if (strtolower($ext) == 'zip')
     				{
     					require_once(PATH_CORE . DS . 'includes' . DS . 'pcl' . DS . 'pclzip.lib.php');
     
     					if (!extension_loaded('zlib'))
     					{
     						$this->setError(Lang::txt('ZLIB_PACKAGE_REQUIRED'));
     					}
     					else
     					{
     						$zip = new PclZip($path . DS . $file['name']);
     
     						// unzip the file
     						if (!($do = $zip->extract($path)))
     						{
     							$this->setError(Lang::txt('UNABLE_TO_EXTRACT_PACKAGE'));
     						}
     						else
     						{
     							@unlink($path . DS . $file['name']);
     							$file['name'] = 'presentation.json';
     						}
     					}
     				}
     
     				// Set the url
     				$row->set('url', $file['name']);
     				$row->store();
     			}
     		}*/
     if ($tmpl == 'component') {
         if ($this->getError()) {
             echo '<p class="error">' . $this->getError() . '</p>';
         } else {
             echo '<p class="message">' . Lang::txt('COM_COURSES_ITEM_SAVED') . '</p>';
         }
         return;
     }
     App::redirect(Route::url('index.php?option=' . $this->_option . '&controller=' . $this->_controller . '&tmpl=' . $tmpl . '&scope=' . $fields['scope'] . '&scope_id=' . $fields['scope_id'] . '&course_id=' . $fields['course_id'], false));
 }
示例#6
0
 /**
  * Create method for this handler
  *
  * @return array of assets created
  **/
 public function create()
 {
     // Include needed files
     require_once dirname(dirname(__DIR__)) . DS . 'tables' . DS . 'asset.association.php';
     require_once dirname(dirname(__DIR__)) . DS . 'tables' . DS . 'asset.php';
     require_once dirname(__DIR__) . DS . 'asset.php';
     // Get the file
     if (isset($_FILES['files'])) {
         $file = $_FILES['files']['name'][0];
         $size = (int) $_FILES['files']['size'];
         // Get the file extension
         $pathinfo = pathinfo($file);
         $filename = $pathinfo['filename'];
         $ext = $pathinfo['extension'];
     } else {
         return array('error' => 'No files provided');
     }
     // @FIXME: should these come from the global settings, or should they be courses specific
     // Get config
     $config = Component::params('com_media');
     // Max upload size
     $sizeLimit = (int) $config->get('upload_maxsize');
     $sizeLimit = $sizeLimit * 1024 * 1024;
     // Check to make sure we have a file and its not too big
     if ($size == 0) {
         return array('error' => 'File is empty');
     }
     if ($size > $sizeLimit) {
         $max = preg_replace('/<abbr \\w+=\\"\\w+\\">(\\w{1,3})<\\/abbr>/', '$1', \Hubzero\Utility\Number::formatBytes($sizeLimit));
         return array('error' => "File is too large. Max file upload size is {$max}");
     }
     // get request vars
     $course_id = Request::getInt('course_id', 0);
     $offering_alias = Request::getCmd('offering', '');
     $scope = Request::getCmd('scope', 'asset_group');
     $scope_id = Request::getInt('scope_id', 0);
     // get all assets in group
     $assetGroup = new \Components\Courses\Models\Assetgroup($scope_id);
     $assets = $assetGroup->assets();
     // check to see if any of our assets are html5?
     $hubpresenter = null;
     foreach ($assets as $asset) {
         if ($asset->get('type') == 'video' && $asset->get('subtype') == 'video' && in_array($asset->get('state'), array(0, 1)) && strpos($asset->get('url'), 'zip')) {
             $hubpresenter = $asset;
             break;
         }
     }
     // make sure we have asset
     if ($hubpresenter === null) {
         return array('error' => 'Unable to locate html5 video or hubpresenter asset to attach subtitle file to.');
     }
     // build path to asset
     $pathToAsset = $hubpresenter->path($course_id);
     $pathToAssetFolder = trim(dirname($pathToAsset), DS);
     // build target path
     $target_path = PATH_APP . DS . $pathToAssetFolder . DS . $filename . '.' . $ext;
     // Move the file to the site folder
     set_time_limit(60);
     // Scan for viruses
     if (!Filesystem::isSafe($_FILES['files']['tmp_name'][0])) {
         // Scan failed, return an error
         return array('error' => 'File rejected because the anti-virus scan failed.');
     }
     // move file
     if (!($move = move_uploaded_file($_FILES['files']['tmp_name'][0], $target_path))) {
         // Move failed, delete asset and association and return an error
         return array('error' => 'Move file failed');
     }
     // get json file
     $jsonFile = $pathToAssetFolder . DS . 'presentation.json';
     // get manifest
     $manifest = file_get_contents(PATH_APP . DS . $jsonFile);
     $manifest = json_decode($manifest);
     // make sure we have a subtitles section
     $currentSubtitles = array();
     if (!isset($manifest->presentation->subtitles)) {
         $manifest->presentation->subtitles = array();
     } else {
         foreach ($manifest->presentation->subtitles as $subtitle) {
             $currentSubtitles[] = $subtitle->source;
         }
     }
     // create subtitle details based on filename
     $info = pathinfo($file);
     $name = str_replace('-auto', '', $info['filename']);
     $autoplay = strstr($info['filename'], '-auto') ? 1 : 0;
     $source = $file;
     // use only the last segment from name (ex. ThisIsATest.English => English)
     $nameParts = explode('.', $name);
     $name = array_pop($nameParts);
     // add subtitle
     $subtitle = new stdClass();
     $subtitle->type = 'SRT';
     $subtitle->name = ucfirst($name);
     $subtitle->source = $source;
     $subtitle->autoplay = $autoplay;
     // only add sub if we dont already have it
     if (!in_array($subtitle->source, $currentSubtitles)) {
         $manifest->presentation->subtitles[] = $subtitle;
     }
     // update json file
     file_put_contents(PATH_APP . DS . $jsonFile, json_encode($manifest, JSON_PRETTY_PRINT));
     //parse subtitle file
     $lines = self::_parseSubtitleFile($target_path);
     // make transcript file
     $transcript = '';
     foreach ($lines as $line) {
         $transcript .= ' ' . trim($line->text);
     }
     // trim transcript and replace add slide markers
     $transcript = str_replace(array("\r\n", "\n"), array('', ''), $transcript);
     $transcript = preg_replace("/\\[([^\\]]*)\\]/ux", "\n\n[\$1]", $transcript);
     // add title to transcript
     $transcript = $manifest->presentation->title . PHP_EOL . str_repeat('==', 20) . PHP_EOL . ltrim($transcript, PHP_EOL);
     // Create our asset table object
     $assetObj = new Tables\Asset($this->db);
     $this->asset['title'] = 'Video Transcript';
     $this->asset['type'] = 'file';
     $this->asset['subtype'] = 'file';
     $this->asset['url'] = $info['filename'] . '.txt';
     $this->asset['created'] = Date::toSql();
     $this->asset['created_by'] = App::get('authn')['user_id'];
     $this->asset['course_id'] = $course_id;
     // Save the asset
     if (!$assetObj->save($this->asset)) {
         return array('error' => 'Asset save failed');
     }
     // Create asset assoc object
     $assocObj = new Tables\AssetAssociation($this->db);
     $this->assoc['asset_id'] = $assetObj->get('id');
     $this->assoc['scope'] = $scope;
     $this->assoc['scope_id'] = $scope_id;
     // Save the asset association
     if (!$assocObj->save($this->assoc)) {
         return array('error' => 'Asset association save failed');
     }
     // Get courses config
     $cconfig = Component::params('com_courses');
     // Build the upload path if it doesn't exist
     $uploadDirectory = PATH_APP . DS . trim($cconfig->get('uploadpath', '/site/courses'), DS) . DS . $this->asset['course_id'] . DS . $this->assoc['asset_id'] . DS;
     // Make sure upload directory exists and is writable
     if (!is_dir($uploadDirectory)) {
         if (!Filesystem::makeDirectory($uploadDirectory)) {
             return array('error' => 'Server error. Unable to create upload directory');
         }
     }
     if (!is_writable($uploadDirectory)) {
         return array('error' => 'Server error. Upload directory isn\'t writable');
     }
     // Get the final file path
     $transcript_target_path = $uploadDirectory . $this->asset['url'];
     // make transcript file
     file_put_contents($transcript_target_path, $transcript);
     // Get the url to return to the page
     $course_id = Request::getInt('course_id', 0);
     $offering_alias = Request::getCmd('offering', '');
     $course = new \Components\Courses\Models\Course($course_id);
     $url = Route::url('index.php?option=com_courses&controller=offering&gid=' . $course->get('alias') . '&offering=' . $offering_alias . '&asset=' . $assetObj->get('id'));
     // build return info
     $return_info = array('asset_id' => $this->assoc['asset_id'], 'asset_title' => $this->asset['title'], 'asset_type' => $this->asset['type'], 'asset_subtype' => $this->asset['subtype'], 'asset_url' => $url, 'course_id' => $this->asset['course_id'], 'offering_alias' => Request::getCmd('offering', ''), 'scope_id' => $this->assoc['scope_id'], 'asset_ext' => 'txt', 'upload_path' => $uploadDirectory, 'target_path' => $transcript_target_path);
     // Return info
     return array('assets' => $return_info);
 }