MDL-59495 moodlenet: move all moodlenet code into new namespace
[moodle.git] / lib / classes / hub / publication.php
1 <?php
2 // This file is part of Moodle - http://moodle.org/
3 //
4 // Moodle is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published by
6 // the Free Software Foundation, either version 3 of the License, or
7 // (at your option) any later version.
8 //
9 // Moodle is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 // GNU General Public License for more details.
13 //
14 // You should have received a copy of the GNU General Public License
15 // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
17 /**
18  * Class publication
19  *
20  * @package    core
21  * @copyright  2017 Marina Glancy
22  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
23  */
25 namespace core\hub;
26 defined('MOODLE_INTERNAL') || die();
28 use moodle_exception;
29 use moodle_url;
30 use context_user;
31 use stdClass;
32 use html_writer;
34 /**
35  * Methods to work with site registration on moodle.net
36  *
37  * @package    core
38  * @copyright  2017 Marina Glancy
39  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
40  */
41 class publication {
43     /** @var Audience: educators */
44     const HUB_AUDIENCE_EDUCATORS = 'educators';
46     /** @var Audience: students */
47     const HUB_AUDIENCE_STUDENTS = 'students';
49     /** @var Audience: admins */
50     const HUB_AUDIENCE_ADMINS = 'admins';
52     /** @var Educational level: primary */
53     const HUB_EDULEVEL_PRIMARY = 'primary';
55     /** @var Educational level: secondary */
56     const HUB_EDULEVEL_SECONDARY = 'secondary';
58     /** @var Educational level: tertiary */
59     const HUB_EDULEVEL_TERTIARY = 'tertiary';
61     /** @var Educational level: government */
62     const HUB_EDULEVEL_GOVERNMENT = 'government';
64     /** @var Educational level: association */
65     const HUB_EDULEVEL_ASSOCIATION = 'association';
67     /** @var Educational level: corporate */
68     const HUB_EDULEVEL_CORPORATE = 'corporate';
70     /** @var Educational level: other */
71     const HUB_EDULEVEL_OTHER = 'other';
74     /**
75      * Retrieve all the sorted course subjects
76      *
77      * @return array $subjects
78      */
79     public static function get_sorted_subjects() {
80         $subjects = get_string_manager()->load_component_strings('edufields', current_language());
82         // Sort the subjects.
83         $return  = [];
84         asort($subjects);
85         foreach ($subjects as $key => $option) {
86             $keylength = strlen($key);
87             if ($keylength == 12) {
88                 $return[$key] = $option; // We want only selectable categories.
89             }
90         }
91         return $return;
92     }
94     /**
95      * Get all publication for a course
96      *
97      * @param int $courseid local course id
98      * @return array of publication
99      */
100     public static function get_course_publications($courseid) {
101         global $DB;
102         $sql = 'SELECT cp.id, cp.status, cp.timechecked, cp.timepublished, rh.hubname,
103                        rh.huburl, cp.courseid, cp.enrollable, cp.hubcourseid
104                 FROM {course_published} cp, {registration_hubs} rh
105                 WHERE cp.huburl = rh.huburl and cp.courseid = :courseid and rh.huburl = :huburl
106                 ORDER BY cp.enrollable DESC, rh.hubname, cp.timepublished';
107         $params = array('courseid' => $courseid, 'huburl' => HUB_MOODLEORGHUBURL);
108         $records = $DB->get_records_sql($sql, $params);
110         // Add links for publications that are listed.
111         foreach ($records as $id => $record) {
112             if ($record->status) {
113                 $records[$id]->link = new moodle_url(HUB_MOODLEORGHUBURL, ['courseid' => $record->hubcourseid]);
114             }
115         }
116         return $records;
117     }
119     /**
120      * Load publication information from local db
121      *
122      * @param int $id
123      * @param int $courseid if specified publication will be checked that it is in the current course
124      * @param int $strictness
125      * @return stdClass
126      */
127     public static function get_publication($id, $courseid = 0, $strictness = IGNORE_MISSING) {
128         global $DB;
129         if (!$id && $strictness != MUST_EXIST) {
130             return false;
131         }
132         $params = ['id' => $id, 'huburl' => HUB_MOODLEORGHUBURL];
133         if ($courseid) {
134             $params['courseid'] = $courseid;
135         }
136         return $DB->get_record('course_published', $params, '*', $strictness);
137     }
139     /**
140      * Update a course publication
141      * @param stdClass $publication
142      */
143     protected static function update_publication($publication) {
144         global $DB;
145         $DB->update_record('course_published', $publication);
146     }
148     /**
149      * Check all courses published from this site if they have been approved
150      */
151     public static function request_status_update() {
152         global $DB;
154         list($sitecourses, $coursetotal) = api::get_courses('', 1, 1, ['allsitecourses' => 1]);
156         // Update status for all these course.
157         foreach ($sitecourses as $sitecourse) {
158             // Get the publication from the hub course id.
159             $publication = $DB->get_record('course_published', ['hubcourseid' => $sitecourse['id']]);
160             if (!empty($publication)) {
161                 $publication->status = $sitecourse['privacy'];
162                 $publication->timechecked = time();
163                 self::update_publication($publication);
164             } else {
165                 $msgparams = new stdClass();
166                 $msgparams->id = $sitecourse['id'];
167                 $msgparams->hubname = html_writer::tag('a', 'Moodle.net', array('href' => HUB_MOODLEORGHUBURL));
168                 \core\notification::add(get_string('detectednotexistingpublication', 'hub', $msgparams)); // TODO action?
169             }
170         }
172     }
174     /**
175      * Unpublish a course
176      *
177      * @param stdClass $publication
178      */
179     public static function unpublish($publication) {
180         global $DB;
181         // Unpublish the publication by web service.
182         api::unregister_courses($publication->hubcourseid);
184         // Delete the publication from the database.
185         $DB->delete_records('course_published', array('id' => $publication->id));
187         // Add confirmation message.
188         $course = get_course($publication->courseid);
189         $context = \context_course::instance($course->id);
190         $publication->courseshortname = format_string($course->shortname, true, ['context' => $context]);
191         $publication->hubname = 'Moodle.net';
192         \core\notification::add(get_string('courseunpublished', 'hub', $publication), \core\output\notification::NOTIFY_SUCCESS);
193     }
195     /**
196      * Publish a course
197      *
198      * @param \stdClass $courseinfo
199      * @param \stored_file[] $files
200      */
201     public static function publish_course($courseinfo, $files) {
202         global $DB;
204         // Register course and get id of the course on moodle.net ($hubcourseid).
205         $courseid = $courseinfo->sitecourseid;
206         try {
207             $hubcourseid = api::register_course($courseinfo);
208         } catch (Exception $e) {
209             throw new moodle_exception('errorcoursepublish', 'hub',
210                 new moodle_url('/course/view.php', array('id' => $courseid)), $e->getMessage());
211         }
213         // Insert/update publication record in the local DB.
214         $publication = $DB->get_record('course_published', array('hubcourseid' => $hubcourseid, 'huburl' => HUB_MOODLEORGHUBURL));
216         if ($publication) {
217             $DB->update_record('course_published', ['id' => $publication->id, 'timepublished' => time()]);
218         } else {
219             $publication = new stdClass();
220             $publication->huburl = HUB_MOODLEORGHUBURL;
221             $publication->courseid = $courseid;
222             $publication->hubcourseid = $hubcourseid;
223             $publication->enrollable = (int)$courseinfo->enrollable;
224             $publication->timepublished = time();
225             $publication->id = $DB->insert_record('course_published', $publication);
226         }
228         // Send screenshots.
229         if ($files) {
230             $screenshotnumber = $courseinfo->screenshots - count($files);
231             foreach ($files as $file) {
232                 $screenshotnumber++;
233                 api::add_screenshot($hubcourseid, $file, $screenshotnumber);
234             }
235         }
237         return $hubcourseid;
238     }
240     /**
241      * Delete all publications
242      *
243      * @param int $advertised search for advertised courses
244      * @param int $shared search for shared courses
245      * @throws moodle_exception
246      */
247     public static function delete_all_publications($advertised = true, $shared = true) {
248         global $DB;
250         if (!$advertised && !$shared) {
251             // Nothing to do.
252             return true;
253         }
255         $params = ['huburl' => HUB_MOODLEORGHUBURL];
256         if (!$advertised || !$shared) {
257             // Retrieve ONLY advertised or ONLY shared.
258             $params['enrollable'] = $advertised ? 1 : 0;
259         }
261         if (!$publications = $DB->get_records('course_published', $params)) {
262             // Nothing to unpublish.
263             return true;
264         }
266         foreach ($publications as $publication) {
267             $hubcourseids[] = $publication->hubcourseid;
268         }
270         api::unregister_courses($hubcourseids);
272         // Delete the published courses from local db.
273         $DB->delete_records('course_published', $params);
274         return true;
275     }
277     /**
278      * Get an array of all block instances for a given context
279      * @param int $contextid a context id
280      * @return array of block instances.
281      */
282     public static function get_block_instances_by_context($contextid) {
283         global $DB;
284         return $DB->get_records('block_instances', array('parentcontextid' => $contextid), 'blockname');
285     }
287     /**
288      * List of available educational levels
289      *
290      * @param bool $any add option for "Any" (for search forms)
291      * @return array
292      */
293     public static function educational_level_options($any = false) {
294         $options = array();
295         if ($any) {
296             $options['all'] = get_string('any');
297         }
298         $options[self::HUB_EDULEVEL_PRIMARY] = get_string('edulevelprimary', 'hub');
299         $options[self::HUB_EDULEVEL_SECONDARY] = get_string('edulevelsecondary', 'hub');
300         $options[self::HUB_EDULEVEL_TERTIARY] = get_string('eduleveltertiary', 'hub');
301         $options[self::HUB_EDULEVEL_GOVERNMENT] = get_string('edulevelgovernment', 'hub');
302         $options[self::HUB_EDULEVEL_ASSOCIATION] = get_string('edulevelassociation', 'hub');
303         $options[self::HUB_EDULEVEL_CORPORATE] = get_string('edulevelcorporate', 'hub');
304         $options[self::HUB_EDULEVEL_OTHER] = get_string('edulevelother', 'hub');
305         return $options;
306     }
308     /**
309      * List of available audience options
310      *
311      * @param bool $any add option for "Any" (for search forms)
312      * @return array
313      */
314     public static function audience_options($any = false) {
315         $options = array();
316         if ($any) {
317             $options['all'] = get_string('any');
318         }
319         $options[self::HUB_AUDIENCE_EDUCATORS] = get_string('audienceeducators', 'hub');
320         $options[self::HUB_AUDIENCE_STUDENTS] = get_string('audiencestudents', 'hub');
321         $options[self::HUB_AUDIENCE_ADMINS] = get_string('audienceadmins', 'hub');
322         return $options;
323     }
325     /**
326      * Search for courses
327      *
328      * For the list of fields returned for each course see {@link communication::get_courses}
329      *
330      * @param string $search search string
331      * @param bool $downloadable true - return downloadable courses, false - return enrollable courses
332      * @param array|\stdClass $options other options from the list of allowed options:
333      *              'ids', 'sitecourseids', 'coverage', 'licenceshortname', 'subject', 'audience',
334      *              'educationallevel', 'language', 'orderby', 'givememore', 'allsitecourses'
335      * @return array of two elements: [$courses, $coursetotal]
336      */
337     public static function search($search, $downloadable, $options) {
338         try {
339             return api::get_courses($search, $downloadable, !$downloadable, $options);
340         } catch (moodle_exception $e) {
341             \core\notification::add(get_string('errorcourselisting', 'block_community', $e->getMessage()),
342                 \core\output\notification::NOTIFY_ERROR);
343             return [[], 0];
344         }
345     }
347     /**
348      * Retrieves information about published course
349      *
350      * For the list of fields returned for the course see {@link communication::get_courses}
351      *
352      * @param stdClass $publication
353      * @return array|null
354      */
355     public static function get_published_course($publication) {
356         try {
357             list($courses, $unused) = api::get_courses('', !$publication->enrollable,
358                 $publication->enrollable, ['ids' => [$publication->hubcourseid], 'allsitecourses' => 1]);
359             return reset($courses);
360         } catch (\Exception $e) {
361             \core\notification::add(get_string('errorcourseinfo', 'hub', $e->getMessage()),
362                 \core\output\notification::NOTIFY_ERROR);
363         }
364         return null;
365     }
367     /**
368      * Downloads course backup and stores it in the user private files
369      *
370      * @param int $hubcourseid
371      * @param string $coursename
372      * @return array
373      */
374     public static function download_course_backup($hubcourseid, $coursename) {
375         global $CFG, $USER;
376         require_once($CFG->libdir . "/filelib.php");
378         make_temp_directory('backup');
379         $filename = md5(time() . '-' . $hubcourseid . '-'. $USER->id . '-'. random_string(20));
380         $path = $CFG->tempdir.'/backup/'.$filename.".mbz";
382         api::download_course_backup($hubcourseid, $path);
384         $fs = get_file_storage();
385         $record = new stdClass();
386         $record->contextid = context_user::instance($USER->id)->id;
387         $record->component = 'user';
388         $record->filearea = 'private';
389         $record->itemid = 0;
390         $record->filename = urlencode($coursename).'_'.time().".mbz";
391         $record->filepath = '/downloaded_backup/';
392         if (!$fs->file_exists($record->contextid, $record->component,
393             $record->filearea, 0, $record->filepath, $record->filename)) {
394             $fs->create_file_from_pathname($record, $path);
395         }
397         return [$record->filepath . $record->filename, $filename];
398     }
400     /**
401      * Uploads a course backup
402      *
403      * @param int $hubcourseid id of the published course on moodle.net, it must be published from this site
404      * @param \stored_file $backupfile
405      */
406     public static function upload_course_backup($hubcourseid, \stored_file $backupfile) {
407         api::upload_course_backup($hubcourseid, $backupfile);
408     }