/** * Displays a list of courses * * @return void */ public function displayTask() { $course = Course::getInstance(Request::getVar('course', '')); $offering = $course->offering(Request::getVar('offering', '')); // Ensure the course exists if (!$course->exists() || !$offering->exists()) { App::redirect(Route::url('index.php?option=' . $this->_option . '&controller=courses'), Lang::txt('COM_COURSES_ERROR_COURSE_OR_OFFERING_NOT_FOUND'), 'error'); return; } // Ensure specified user is enrolled in the course //$student = $offering->member(User::get('id')); $student = Member::getInstance(User::get('id'), $course->get('id'), $offering->get('id'), null, 1); if (!$student->exists()) { App::redirect(Route::url('index.php?option=' . $this->_option . '&controller=courses'), Lang::txt('COM_COURSES_ERROR_STUDENT_RECORD_NOT_FOUND'), 'error'); return; } $certificate = $course->certificate(); if (!$certificate->exists() || !$certificate->hasFile()) { App::redirect(Route::url('index.php?option=' . $this->_option . '&controller=courses'), Lang::txt('COM_COURSES_ERROR_NO_CERTIFICATE_FOR_COURSE'), 'error'); return; } // Path and file name $dir = PATH_APP . DS . 'site' . DS . 'courses' . DS . 'certificates'; $file = $dir . DS . 'certificate_' . $course->get('id') . '_' . $offering->get('id') . '_' . User::get('id') . '.pdf'; // If the file exists and we want to force regenerate it if (is_file($file) && Request::getInt('regenerate', 0)) { if (!Filesystem::delete($file)) { throw new Exception(Lang::txt('UNABLE_TO_DELETE_FILE'), 500); } } // Does the file exist already? if (!is_file($file)) { // Create the upload directory if needed if (!is_dir($dir)) { if (!Filesystem::makeDirectory($dir)) { throw new Exception(Lang::txt('COM_COURSES_ERROR_FAILED_TO_CREATE_DIRECTORY'), 500); } } $certificate->render(User::getRoot(), $file); } // If file exists if (is_file($file)) { $student->token(); // Serve up the file $xserver = new Server(); $xserver->filename($file); $xserver->serve_attachment($file); // Firefox and Chrome fail if served inline exit; } // Output failure message $this->view->display(); }
/** * Up **/ public function up() { if (!$this->db->tableHasField('#__courses_members', 'token')) { $query = "ALTER TABLE `#__courses_members` ADD `token` VARCHAR(23) NOT NULL DEFAULT '';"; $this->db->setQuery($query); $this->db->query(); $path = PATH_APP . DS . 'site' . DS . 'courses' . DS . 'certificates'; if (is_dir($path)) { require_once PATH_CORE . DS . 'components' . DS . 'com_courses' . DS . 'models' . DS . 'course.php'; // Loop through all files and separate them into arrays of images, folders, and other $dirIterator = new DirectoryIterator($path); foreach ($dirIterator as $file) { if ($file->isDot()) { continue; } if ($file->isDir()) { continue; } if ($file->isFile()) { $name = $file->getFilename(); if ('cvs' == strtolower($name) || '.svn' == strtolower($name)) { continue; } $bits = explode('_', $name); if (count($bits) < 4) { continue; } $course = $bits[1]; $offering = $bits[2]; $user = strstr($bits[3], '.', true); $member = \Components\Courses\Models\Member::getInstance($user, $course, $offering, null); $member->token(); } } } } }
/** * Remove one or more user IDs or usernames to the managers list * * @param array $value List of IDs or usernames * @return void */ public function remove($data = array()) { if (!is_array($data)) { $data = array($data); } if (!$this->get('course_id')) { require_once __DIR__ . DS . 'offering.php'; $offering = Offering::getInstance($this->get('offering_id')); $this->set('course_id', $offering->get('course_id')); } foreach ($data as $result) { $user_id = $this->_userId($result); $model = Member::getInstance($user_id, $this->get('course_id'), $this->get('offering_id'), $this->get('id')); if (!$model->exists()) { $this->setError(Lang::txt('Entry for user #%s, course #%s, offering #%s, section #%s not found.', $user_id, $this->get('course_id'), $this->get('offering_id'), $this->get('id'))); continue; } if (!$model->delete()) { $this->setError($model->getError()); continue; } if (isset($this->_members[$user_id])) { unset($this->_members[$user_id]); } } }
/** * Remove one or more users from the course manager list * * @return void */ public function updateTask() { // Check for request forgeries Request::checkToken(); // Incoming member ID $id = Request::getInt('offering', 0); if (!$id) { $this->setError(Lang::txt('COM_COURSES_ERROR_NO_ID')); $this->displayTask(); return; } $section = Request::getInt('section', 0); $model = \Components\Courses\Models\Offering::getInstance($id); if ($section) { $model->section($section); } $entries = Request::getVar('entries', array(0), 'post'); foreach ($entries as $key => $data) { // Retrieve user's account info $member = \Components\Courses\Models\Member::getInstance($data['id'], null, null, null); if ($member->get('role_id') == $data['role_id']) { continue; } $member->set('role_id', $data['role_id']); if (!$member->store()) { $this->setError($member->getError()); } } // Push through to the hosts view $this->displayTask($model); }
/** * Passport badges. Placeholder for now. * * @apiMethod POST * @apiUri /courses/passport/badge * @apiParameter { * "name": "action", * "description": "Badge action", * "type": "string", * "required": true, * "default": null * } * @apiParameter { * "name": "badge_id", * "description": "Passport badge ID", * "type": "integer", * "required": true, * "default": null * } * @apiParameter { * "name": "user_email", * "description": "Email address to which the badge was asserted", * "type": "string", * "required": true, * "default": null * } * @return void */ public function badgeTask() { // Require authentication and authorization $this->authorizeOrFail(); $action = Request::getVar('action', ''); $badge_id = Request::getVar('badge_id', ''); $user_email = Request::getVar('user_email', ''); if (empty($action)) { App::abort(400, 'Please provide action'); } if ($action != 'accept' && $action != 'deny') { App::abort(400, 'Bad action. Must be either accept or deny'); } if (empty($badge_id)) { App::abort(400, 'Please provide badge ID'); } if (empty($user_email)) { App::abort(400, 'Please provide user email'); } // Find user by email $user = User::oneByEmail($user_email); if (!$user->get('id')) { App::abort(404, 'User was not found'); } $user_id = $user->get('id'); // Get section from provider badge id $section_badge = \Components\Courses\Models\Section\Badge::loadByProviderBadgeId($badge_id); // Check if there is a match if (!($section_id = $section_badge->get('section_id'))) { App::abort(400, 'No matching badge found'); } // Get member id via user id and section id $member = \Components\Courses\Models\Member::getInstance($user_id, 0, 0, $section_id); // Check if there is a match if (!$member->get('id')) { App::abort(400, 'Matching course member not found'); } // Now actually load the badge $member_badge = \Components\Courses\Models\MemberBadge::loadByMemberId($member->get('id')); // Check if there is a match if (!$member_badge->get('id')) { App::abort(400, 'This member does not have a matching badge entry'); } $now = Date::toSql(); $member_badge->set('action', $action); $member_badge->set('action_on', $now); $member_badge->store(); // Return message $this->send('Passport data saved.'); }
/** * Processes grade save from unity app * * @apiMethod POST * @apiUri /courses/unity/save * @apiParameter { * "name": "referrer", * "description": "Host page", * "type": "string", * "required": false, * "default": "$_SERVER['HTTP_REFERER']" * } * @apiParameter { * "name": "payload", * "description": "Score notes/content", * "type": "string", * "required": true, * "default": null * } * @return void */ public function saveTask() { // Require authentication and authorization $this->authorizeOrFail(); $user_id = App::get('authn')['user_id']; // Parse some things out of the referer $referer = !empty($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : Request::getVar('referrer'); preg_match('/\\/asset\\/([[:digit:]]*)/', $referer, $matches); if (!($asset_id = $matches[1])) { App::abort(400, 'Failed to get asset ID'); } // Get course info...this seems a little wonky preg_match('/\\/courses\\/([[:alnum:]\\-\\_]*)\\/([[:alnum:]\\:\\-\\_]*)/', $referer, $matches); $course_alias = $matches[1]; $offering_alias = $matches[2]; $section_alias = null; if (strpos($offering_alias, ":")) { $parts = explode(":", $offering_alias); $offering_alias = $parts[0]; $section_alias = $parts[1]; } $course = Course::getInstance($course_alias); $course->offering($offering_alias); $course->offering()->section($section_alias); $section_id = $course->offering()->section()->get('id'); $member = Member::getInstance($user_id, 0, 0, $section_id); if (!($member_id = $member->get('id'))) { App::abort(500, 'Failed to get course member ID'); } if (!($data = Request::getVar('payload', false))) { App::abort(400, 'Missing payload'); } // Get the key and IV - Trim the first xx characters from the payload for IV $key = $course->config()->get('unity_key', 0); $iv = substr($data, 0, 32); $data = substr($data, 32); $message = mcrypt_decrypt(MCRYPT_RIJNDAEL_256, $key, base64_decode($data), MCRYPT_MODE_CBC, $iv); $message = trim($message); $message = json_decode($message); if (!$message || !is_object($message)) { App::abort(500, 'Failed to decode message'); } // Get timestamp $now = Date::toSql(); // Save the unity details $unity = new AssetUnity($this->db); $unity->set('member_id', $member_id); $unity->set('asset_id', $asset_id); $unity->set('created', $now); $unity->set('passed', $message->passed ? 1 : 0); $unity->set('details', $message->details); if (!$unity->store()) { App::abort(500, $unity->getError()); } // Now set/update the gradebook item $gradebook = new GradeBook($this->db); $gradebook->loadByUserAndAssetId($member_id, $asset_id); // Score is either 100 or 0 $score = $message->passed ? 100 : 0; // See if gradebook entry already exists if ($gradebook->get('id')) { // Entry does exist, see if current score is better than previous score if ($score > $gradebook->get('score')) { $gradebook->set('score', $score); $gradebook->set('score_recorded', Date::toSql()); if (!$gradebook->store()) { App::abort(500, $gradebook->getError()); } } } else { $gradebook->set('member_id', $member_id); $gradebook->set('score', $score); $gradebook->set('scope', 'asset'); $gradebook->set('scope_id', $asset_id); $gradebook->set('score_recorded', Date::toSql()); if (!$gradebook->store()) { App::abort(500, $gradebook->getError()); } } // Return message $this->send(['success' => true]); }
/** * Add one or more user IDs or usernames to the managers list * * @param array $value List of IDs or usernames * @return void */ public function add($data = array(), $role_id = 'student') { if (!is_array($data)) { $data = array($data); } $role = new Tables\Role($this->_db); $role->load($role_id); if (is_string($role_id)) { $role_id = $role->get('id'); } foreach ($data as $result) { $user_id = (int) $this->_userId($result); $model = Member::getInstance($user_id, $this->get('course_id'), $this->get('id'), $this->section()->get('id')); $model->set('user_id', $user_id); $model->set('course_id', $this->get('course_id')); $model->set('offering_id', $this->get('id')); $model->set('section_id', $this->section()->get('id')); $model->set('role_id', $role_id); if ($role->get('alias') == 'student') { $model->set('student', 1); } if (!$model->store()) { $this->setError($model->getError()); continue; } $this->_managers[$user_id] = $model; } }
/** * Saves data to the database * * @return void */ public function saveTask($redirect = true) { // Check for request forgeries Request::checkToken(); // Incoming $fields = Request::getVar('fields', array(), 'post'); if (strstr($fields['user_id'], ',')) { $user_ids = explode(',', $fields['user_id']); $user_ids = array_map('trim', $user_ids); } else { $user_ids = array($fields['user_id']); } $offering = Request::getInt('offering', 0); if (!$offering && isset($fields['offering_id'])) { $offering = $fields['offering_id']; } $offeringObj = \Components\Courses\Models\Offering::getInstance($offering); $c = 0; foreach ($user_ids as $user_id) { if (!is_int($user_id)) { $user = User::getInstance($user_id); if (!is_object($user)) { \Notify::error(Lang::txt('COM_COURSES_ERROR_USER_NOTFOUND') . ' ' . $user_id); $this->editTask(); return; } $fields['user_id'] = $user->get('id'); } else { $fields['user_id'] = $user_id; } // Instantiate the model $fields['course_id'] = $offeringObj->get('course_id'); //$section_id = $offeringObj->section()->get('id'); //$model = \Components\Courses\Models\Member::getInstance($fields['user_id'], $fields['course_id'], $offering, $section_id); $model = \Components\Courses\Models\Member::getInstance($fields['user_id'], $fields['course_id'], null, null); // Is there an existing record and are they a student? if ($model->exists() && !$model->get('student')) { \Notify::error(Lang::txt('COM_COURSES_ERROR_ALREADY_COURSE_MANAGER', $user_id)); continue; } // If the section is the same if ($model->exists() && $model->get('section_id') == $fields['section_id']) { \Notify::warning(Lang::txt('COM_COURSES_ERROR_ALREADY_STUDENT', $user_id)); continue; } // Ensure it's a new record as the check above // could pull a record for another section $model->set('id', null); // Safe to proceed... // Bind posted data if (!$model->bind($fields)) { \Notify::error($model->getError()); $this->editTask($model); return; } // Store data if (!$model->store()) { \Notify::error($model->getError()); $this->editTask($model); return; } } if (count($user_ids) > 1) { $redirect = true; } // Are we redirecting? if ($redirect) { // Output messsage and redirect App::redirect(Route::url('index.php?option=' . $this->_option . '&controller=' . $this->_controller . '&offering=' . $fields['offering_id'] . '§ion=' . $fields['section_id'], false), $c > 0 ? Lang::txt('COM_COURSES_STUDENTS_SAVED', $c) : null); return; } // Display edit form with posted data $this->editTask($model); }