<?php // This file is part of Moodle - http://moodle.org/ // // Moodle is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // Moodle is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with Moodle. If not, see <http://www.gnu.org/licenses/>. /** * Library of useful functions * * @copyright 1999 Martin Dougiamas http://dougiamas.com * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later * @package core_course */ defined('MOODLE_INTERNAL') || die; require_once($CFG->libdir . '/moodlelib.php'); /** * This class pertains to course requests and contains methods associated with * create, approving, and removing course requests. * * Please note we do not allow embedded images here because there is no context * to store them with proper access control. * * @copyright 2009 Sam Hemelryk * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later * @since Moodle 2.0 * * @property-read int $id * @property-read string $fullname * @property-read string $shortname * @property-read string $summary * @property-read int $summaryformat * @property-read int $summarytrust * @property-read string $reason * @property-read int $requester */ class course_request_hsh { /** * This is the stdClass that stores the properties for the course request * and is externally accessed through the __get magic method * @var stdClass */ protected $properties; /** * An array of options for the summary editor used by course request forms. * This is initially set by {@link summary_editor_options()} * @var array * @static */ protected static $summaryeditoroptions; /** * Static function to prepare the summary editor for working with a course * request. * * @static * @param null|stdClass $data Optional, an object containing the default values * for the form, these may be modified when preparing the * editor so this should be called before creating the form * @return stdClass An object that can be used to set the default values for * an mforms form */ public static function prepare($data = null) { if ($data === null) { $data = new stdClass; } $data = file_prepare_standard_editor($data, 'summary', self::summary_editor_options()); return $data; } /** * Static function to create a new course request when passed an array of properties * for it. * * This function also handles saving any files that may have been used in the editor * * @static * @param stdClass $data * @return course_request_hsh The newly created course request */ public static function create($data) { global $USER, $DB, $CFG; $data->requester = $USER->id; // Setting the default category if none set. if (empty($data->category) || !empty($CFG->lockrequestcategory)) { $data->category = $CFG->defaultrequestcategory; } // Summary is a required field so copy the text over $data->summary = $data->summary_editor['text']; $data->summaryformat = $data->summary_editor['format']; // > HsH $data->fullname = \course_request_hsh::get_hsh_name( $data->fullname, $data->teachername, $data->customfield_semester, false ); $data->shortname = \course_request_hsh::get_hsh_name( $data->shortname, $data->teachername, $data->customfield_semester, true ); if (isset($data->consult)) { $data->reason .= '</br> ' . get_string('elcconsult', 'local_hsh'); } // < HsH $data->id = $DB->insert_record('local_hsh_course_request', $data); // Create a new course_request object and return it $request = new course_request_hsh($data); // Notify the admin if required. if ($users = get_users_from_config($CFG->courserequestnotify, 'moodle/site:approvecourse')) { $data->user = fullname($USER); $data->link = $CFG->wwwroot . "/local/hsh/pending.php"; $data->email = $USER->email; $cats = \core_course_category::make_categories_list('', 0, ' / '); $data->category = $cats[$data->category]; $subject = get_string('courserequest', 'local_hsh'); $message = get_string('courserequestnotifyemail', 'local_hsh', $data); foreach ($users as $user) { $request->notify('moodle', $user, $USER, 'courserequested', $subject, $message); } } return $request; } /** * Returns an array of options to use with a summary editor * * @return array An array of options to use with the editor * @uses course_request_hsh::$summaryeditoroptions */ public static function summary_editor_options() { global $CFG; if (self::$summaryeditoroptions === null) { self::$summaryeditoroptions = array('maxfiles' => 0, 'maxbytes' => 0); } return self::$summaryeditoroptions; } /** * Loads the properties for this course request object. Id is required and if * only id is provided then we load the rest of the properties from the database * * @param stdClass|int $properties Either an object containing properties * or the course_request id to load */ public function __construct($properties) { global $DB; if (empty($properties->id)) { if (empty($properties)) { throw new coding_exception('You must provide a course request id when creating a course_request object'); } $id = $properties; $properties = new stdClass; $properties->id = (int)$id; unset($id); } if (empty($properties->requester)) { if (!($this->properties = $DB->get_record('local_hsh_course_request', array('id' => $properties->id)))) { throw new \moodle_exception('unknowncourserequest'); } } else { $this->properties = $properties; } $this->properties->collision = null; } /** * Returns the requested property * * @param string $key * @return mixed */ public function __get($key) { return $this->properties->$key; } /** * Override this to ensure empty($request->blah) calls return a reliable answer... * * This is required because we define the __get method * * @param mixed $key * @return bool True is it not empty, false otherwise */ public function __isset($key) { return (!empty($this->properties->$key)); } /** * Returns the user who requested this course * * Uses a static var to cache the results and cut down the number of db queries * * @staticvar array $requesters An array of cached users * @return stdClass The user who requested the course */ public function get_requester() { global $DB; static $requesters = array(); if (!array_key_exists($this->properties->requester, $requesters)) { $requesters[$this->properties->requester] = $DB->get_record('user', array('id' => $this->properties->requester)); } return $requesters[$this->properties->requester]; } /** * Checks that the shortname used by the course does not conflict with any other * courses that exist * * @param string|null $shortnamemark The string to append to the requests shortname * should a conflict be found * @return bool true is there is a conflict, false otherwise */ public function check_shortname_collision($shortnamemark = '[*]') { global $DB; if ($this->properties->collision !== null) { return $this->properties->collision; } if (empty($this->properties->shortname)) { debugging('Attempting to check a course request shortname before it has been set', DEBUG_DEVELOPER); $this->properties->collision = false; } else if ($DB->record_exists('course', array('shortname' => $this->properties->shortname))) { if (!empty($shortnamemark)) { $this->properties->shortname .= ' ' . $shortnamemark; } $this->properties->collision = true; } else { $this->properties->collision = false; } return $this->properties->collision; } /** * Checks user capability to approve a requested course * * If course was requested without category for some reason (might happen if $CFG->defaultrequestcategory is * misconfigured), we check capabilities 'moodle/site:approvecourse' and 'moodle/course:changecategory'. * * @return bool */ public function can_approve() { global $CFG; $category = null; if ($this->properties->category) { $category = core_course_category::get($this->properties->category, IGNORE_MISSING); } else if ($CFG->defaultrequestcategory) { $category = core_course_category::get($CFG->defaultrequestcategory, IGNORE_MISSING); } if ($category) { return has_capability('moodle/site:approvecourse', $category->get_context()); } // We can not determine the context where the course should be created. The approver should have // both capabilities to approve courses and change course category in the system context. return has_all_capabilities(['moodle/site:approvecourse', 'moodle/course:changecategory'], context_system::instance()); } /** * Returns the category where this course request should be created * * Note that we don't check here that user has a capability to view * hidden categories if he has capabilities 'moodle/site:approvecourse' and * 'moodle/course:changecategory' * * @return core_course_category */ public function get_category() { global $CFG; if ($this->properties->category && ($category = core_course_category::get($this->properties->category, IGNORE_MISSING))) { return $category; } else if ($CFG->defaultrequestcategory && ($category = core_course_category::get($CFG->defaultrequestcategory, IGNORE_MISSING))) { return $category; } else { return core_course_category::get_default(); } } /** * This function approves the request turning it into a course * * This function converts the course request into a course, at the same time * transferring any files used in the summary to the new course and then removing * the course request and the files associated with it. * * @return int The id of the course that was created from this request */ public function approve() { global $CFG, $DB, $USER; require_once($CFG->dirroot . '/backup/util/includes/restore_includes.php'); $user = $DB->get_record('user', array('id' => $this->properties->requester, 'deleted' => 0), '*', MUST_EXIST); $courseconfig = get_config('moodlecourse'); // Transfer appropriate settings $data = clone($this->properties); unset($data->id); unset($data->reason); unset($data->requester); // Set category $category = $this->get_category(); $data->category = $category->id; // Set misc settings $data->requested = 1; // Apply course default settings $data->format = $courseconfig->format; $data->newsitems = $courseconfig->newsitems; $data->showgrades = $courseconfig->showgrades; $data->showreports = $courseconfig->showreports; $data->maxbytes = $courseconfig->maxbytes; $data->groupmode = $courseconfig->groupmode; $data->groupmodeforce = $courseconfig->groupmodeforce; $data->visible = $courseconfig->visible; $data->visibleold = $data->visible; $data->lang = $courseconfig->lang; $data->enablecompletion = $courseconfig->enablecompletion; $data->numsections = $courseconfig->numsections; $data->startdate = usergetmidnight(time()); if ($courseconfig->courseenddateenabled) { $data->enddate = usergetmidnight(time()) + $courseconfig->courseduration; } list($data->fullname, $data->shortname) = restore_dbops::calculate_course_names(0, $data->fullname, $data->shortname); $course = create_course($data); $context = context_course::instance($course->id, MUST_EXIST); // add enrol instances if (!$DB->record_exists('enrol', array('courseid' => $course->id, 'enrol' => 'manual'))) { if ($manual = enrol_get_plugin('manual')) { $manual->add_default_instance($course); } } // > HsH peter werner - set password for self enrolment from request.php if (!empty($data->password)) { if ($self = $DB->get_record('enrol', array('courseid' => $course->id, 'enrol' => 'self', 'status' => 0))) { $self->password = $data->password; $DB->update_record('enrol', $self); } } // < HsH // enrol default roles from plugin config settings $default_roles=get_config('local_hsh', 'defaultrole'); if (!empty($default_roles) && !isguestuser($user) && !is_enrolled($context, $user, 'moodle/role:assign')) { $roles = explode(',', $default_roles); foreach($roles as $role) { enrol_try_internal_enrol($course->id, $user->id, $role); } } elseif (!empty($CFG->creatornewroleid) && !isguestuser($user) && !is_enrolled($context, $user, 'moodle/role:assign')) { enrol_try_internal_enrol($course->id, $user->id, $CFG->creatornewroleid); } // enrol the requester as teacher if necessary $this->delete(); $a = new stdClass(); $a->coursename = format_string($course->fullname, true, array('context' => context_course::instance($course->id))); $a->url = $CFG->wwwroot . '/course/view.php?id=' . $course->id; $a->responser = fullname($USER); $a->email = $USER->email; $a->telefon = $USER->phone1; $a->fullname = fullname($user); $messageplain = $this->get_message_plain($a); $this->notify( 'local_hsh', $user, $USER, 'courserequestapproved_hsh', get_string('courseapprovedsubject', 'local_hsh', $a), $messageplain, $course->id ); return $course->id; } /** * Reject a course request * * This function rejects a course request, emailing the requesting user the * provided notice and then removing the request from the database * * @param string $notice The message to display to the user */ public function reject($notice) { global $USER, $DB; $user = $DB->get_record('user', array('id' => $this->properties->requester), '*', MUST_EXIST); $this->notify( 'local_hsh', $user, $USER, 'courserequestrejected_hsh', get_string('courserejectsubject', 'local_hsh'), get_string('courserejectemail', 'local_hsh', $notice) ); $this->delete(); } /** * Deletes the course request and any associated files */ public function delete() { global $DB; $DB->delete_records('local_hsh_course_request', array('id' => $this->properties->id)); } /** * Send a message from one user to another using events_trigger * * @param object $touser * @param object $fromuser * @param string $name * @param string $subject * @param string $message * @param int|null $courseid */ protected function notify($component, $touser, $fromuser, $name, $subject, $message, $courseid = null) { $eventdata = new \core\message\message(); $eventdata->courseid = empty($courseid) ? SITEID : $courseid; $eventdata->component = $component; $eventdata->name = $name; $eventdata->userfrom = $fromuser; $eventdata->userto = $touser; $eventdata->subject = $subject; $eventdata->fullmessage = $message; $eventdata->fullmessageformat = FORMAT_PLAIN; $eventdata->fullmessagehtml = ''; $eventdata->smallmessage = ''; $eventdata->notification = 1; message_send($eventdata); } /** * Checks if current user can request a course in this context * * @param context $context * @return bool */ public static function can_request(context $context) { global $CFG; if (empty($CFG->enablecourserequests)) { return false; } if (has_capability('moodle/course:create', $context)) { return false; } if ($context instanceof context_system) { $defaultcontext = context_coursecat::instance($CFG->defaultrequestcategory, IGNORE_MISSING); return $defaultcontext && has_capability('local/hsh:request', $defaultcontext); } else if ($context instanceof context_coursecat) { if (!$CFG->lockrequestcategory || $CFG->defaultrequestcategory == $context->instanceid) { return has_capability('local/hsh:request', $context); } } return false; } /** * * @param type $coursename short or fullname * @param type $teacher * @param type $semesterValue intvalue from db * @return type */ public static function get_hsh_name($coursename, $teacher, $semesterValue, $short = true) { $semesterName = \customfield_semester\data_controller::get_name_for_semester((int)$semesterValue); if ($semesterValue == 1) { return $coursename . ", " . $teacher; } else { if ($short) { $exploded = explode(" ", $semesterName); return $coursename . ", " . $exploded[1] . ", " . $teacher; } return $coursename . ", " . $semesterName . ", " . $teacher; } } /** * replaces coursecategory items * @static * @return array */ public static function get_short_categories_list() { $courselist = \core_course_category::make_categories_list('', 0, '$$$'); foreach ($courselist as &$actCourse) { $actCourseArr = explode('$$$', $actCourse); $actCourseSize = sizeof($actCourseArr); if ($actCourseSize > 1) { $actCourse = ''; for ($i = 0; $i < $actCourseSize - 1; $i++) { $actCourse .= '../ '; } $actCourse .= $actCourseArr[$actCourseSize - 1]; } } return $courselist; } protected function get_message_plain($a) { $message = get_string('address', 'local_hsh', $a) . "\r\n"; $message .= "\r\n"; $message .= get_string('courseapproved', 'local_hsh', $a) . "\r\n"; $message .= "\r\n"; $message .= get_string('tocourse_plain', 'local_hsh', $a) . "\r\n"; $message .= "\r\n"; if (!empty($this->properties->coursecopyurl)) { $message .= get_string('coursecopyinform', 'local_hsh', $a) . "\r\n"; $message .= "\r\n"; } // $message .= get_string('questionhint', 'local_hsh') . ' ' . get_string('questionhintmail', 'local_hsh') . "." . "\r\n"; $message .= get_string('questionhint1', 'local_hsh') . "\r\n"; // $message .= get_string('questionhint2', 'local_hsh') . "\r\n"; // $message .= get_string('questionhint3', 'local_hsh') . "\r\n"; $message .= "\r\n"; // $message .= get_string('consultinghint', 'local_hsh') . "\r\n"; $message .= "\r\n"; $message .= get_string('greetings', 'local_hsh') . "\r\n"; // $message .= "\r\n"; $message .= "Servicezentrum Lehre" . "\r\n"; // $message .= $a->email . "\r\n"; // $message .= $a->telefon . "\r\n"; $message .= "\r\n"; $message .= "\r\n"; $message .= get_string('institute1', 'local_hsh') . "\r\n"; // $message .= get_string('institute2', 'local_hsh') . "\r\n"; $message .= get_string('ou1', 'local_hsh') . "\r\n"; $message .= get_string('ou2', 'local_hsh') . "\r\n"; // $message .= get_string('street', 'local_hsh') . "\r\n"; // $message .= get_string('place', 'local_hsh') . "\r\n"; $message .= "\r\n"; $message .= get_string('email', 'local_hsh') . ': ' . get_string('elcmailaddress', 'local_hsh') . "\r\n"; $message .= get_string('elcphone', 'local_hsh'); return $message; } } // End HsH