From 76d9df3f1d07fc2a3e74619eb94599d63277234a Mon Sep 17 00:00:00 2001 From: Sam Hemelryk Date: Mon, 2 Nov 2009 03:50:56 +0000 Subject: [PATCH] calendar MDL-20601 Conversion of calendar to mforms and new html editor + file API --- calendar/delete.php | 136 +++++++ calendar/event.php | 663 ++++++------------------------- calendar/event_delete.html | 55 --- calendar/event_edit.html | 109 ----- calendar/event_form.php | 178 +++++++++ calendar/event_new.html | 118 ------ calendar/event_select.html | 58 --- calendar/export_execute.php | 4 +- calendar/lib.php | 767 ++++++++++++++++++++++++++++++++++-- calendar/preferences.php | 2 +- calendar/view.php | 7 +- lang/en_utf8/calendar.php | 4 + lib/deprecatedlib.php | 91 +++++ lib/moodlelib.php | 153 ------- pluginfile.php | 94 ++++- 15 files changed, 1383 insertions(+), 1056 deletions(-) create mode 100644 calendar/delete.php delete mode 100644 calendar/event_delete.html delete mode 100644 calendar/event_edit.html create mode 100644 calendar/event_form.php delete mode 100644 calendar/event_new.html delete mode 100644 calendar/event_select.html diff --git a/calendar/delete.php b/calendar/delete.php new file mode 100644 index 0000000000..b42fc294bc --- /dev/null +++ b/calendar/delete.php @@ -0,0 +1,136 @@ +. + +/** + * This file is part of the Calendar section Moodle + * It is responsible for deleting a calendar entry + optionally its repeats + * + * @copyright 2009 Sam Hemelryk + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + * @package calendar + */ + +require_once('../config.php'); +require_once($CFG->dirroot.'/calendar/event_form.php'); +require_once($CFG->dirroot.'/calendar/lib.php'); +require_once($CFG->dirroot.'/course/lib.php'); + +$eventid = required_param('id', PARAM_INT); +$confirm = optional_param('confirm', false, PARAM_BOOL); +$repeats = optional_param('repeats', false, PARAM_BOOL); +$courseid = optional_param('course', 0, PARAM_INT); + +$PAGE->set_url(new moodle_url($CFG->wwwroot.'/calendar/delete.php', array('id'=>$eventid))); + +if(!$site = get_site()) { + redirect(new moodle_url($CFG->wwwroot.'/'.$CFG->admin.'/index.php')); +} + +$event = calendar_event::load($eventid); + +/** + * We are going to be picky here, and require that any event types other than + * group and site be associated with a course. This means any code that is using + * custom event types (and there are a few) will need to associate thier event with + * a course + */ +if ($event->eventtype !== 'user' && $event->eventtype !== 'site') { + if ($courseid !== $event->courseid) { + print_error('invalidcourse'); + } + require_login($event->courseid); +} else { + require_login(); +} + +// Check the user has the required capabilities to edit an event +if (!calendar_edit_event_allowed($event)) { + print_error('nopermissions'); +} + +// Count the repeats, do we need to consider the possibility of deleting repeats +$event->timedurationuntil = $event->timestart + $event->timeduration; +$event->count_repeats(); + +// Is used several times, and sometimes with modification if required +$viewcalendarurl = new moodle_url(CALENDAR_URL.'view.php', array('view'=>'upcoming')); +$viewcalendarurl->param('cal_y', date('Y', $event->timestart)); +$viewcalendarurl->param('cal_m', date('m', $event->timestart)); + +// If confirm is set (PARAM_BOOL) then we have confirmation of initention to delete +if ($confirm) { + // Confirm the session key to stop CSRF + if (!confirm_sesskey()) { + print_error('confirmsesskeybad'); + } + // Delete the event and possibly repeats + $event->delete($repeats); + // If the event has an associated course then we need to include it in the redirect link + if (!empty($event->courseid) && $event->courseid > 0) { + $viewcalendarurl->param('course', $event->courseid); + } + // And redirect + redirect($viewcalendarurl); +} + +// Prepare the page to show the confirmation form +$title = get_string('deleteevent', 'calendar'); +$strcalendar = get_string('calendar', 'calendar'); + +$PAGE->navbar->add($strcalendar, $viewcalendarurl); +$PAGE->navbar->add($title); +$PAGE->set_title($site->shortname.': '.$strcalendar.': '.$title); +$PAGE->set_heading($strcalendar); +$PAGE->set_headingmenu(user_login_string($site)); + +echo $OUTPUT->header(); +echo $OUTPUT->box_start('eventlist'); + +// Delete this event button is always shown +$deleteone = new html_form(); +$deleteone->button->text = get_string('delete'); +$deleteone->url = new moodle_url(CALENDAR_URL.'delete.php', array('id'=>$event->id, 'confirm'=>true)); +$buttons = $OUTPUT->button($deleteone); + +// If there are repeated events then add a Delete Repeated button +$repeatspan = ''; +if (!empty($event->eventrepeats) && $event->eventrepeats > 0) { + $deleteall = new html_form(); + $deleteall->button->text = get_string('deleteall'); + $deleteall->url = new moodle_url(CALENDAR_URL.'delete.php', array('id'=>$event->repeatid, 'confirm'=>true, 'repeats'=>true)); + $buttons .= $OUTPUT->button($deleteall); + $repeatspan = '

'.$OUTPUT->span(get_string('youcandeleteallrepeats', 'calendar')); +} + +// And add the cancel button +$cancel = new html_form(); +$cancel->button->text = get_string('cancel'); +$cancel->url = $viewcalendarurl; +$buttons .= $OUTPUT->button($cancel); + +// And show the buttons and notes +echo $OUTPUT->box_start('generalbox', 'notice'); +echo $OUTPUT->box(get_string('confirmeventdelete', 'calendar').$repeatspan); +echo $OUTPUT->box($buttons, 'buttons'); +echo $OUTPUT->box_end(); + +// Print the event so that people can visually confirm they have the correct event +$event->time = calendar_format_event_time($event, time(), '', false); +calendar_print_event($event, false); + +echo $OUTPUT->box_end(); +echo $OUTPUT->footer(); \ No newline at end of file diff --git a/calendar/event.php b/calendar/event.php index 95183df398..7c2fda74af 100644 --- a/calendar/event.php +++ b/calendar/event.php @@ -39,7 +39,7 @@ ///////////////////////////////////////////////////////////////////////////// /** - * This file is part of the User section Moodle + * This file is part of the Calendar section Moodle * * @copyright 2003-2004 Jon Papaioannou (pj@moodle.org) * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v2 or later @@ -47,613 +47,208 @@ */ require_once('../config.php'); +require_once($CFG->dirroot.'/calendar/event_form.php'); require_once($CFG->dirroot.'/calendar/lib.php'); require_once($CFG->dirroot.'/course/lib.php'); -require_once($CFG->dirroot.'/mod/forum/lib.php'); require_login(); -$action = required_param('action', PARAM_ALPHA); +$action = optional_param('action', 'new', PARAM_ALPHA); $eventid = optional_param('id', 0, PARAM_INT); -$eventtype = optional_param('type', 'select', PARAM_ALPHA); -$urlcourse = optional_param('course', 0, PARAM_INT); +$courseid = optional_param('courseid', 0, PARAM_INT); $cal_y = optional_param('cal_y', 0, PARAM_INT); $cal_m = optional_param('cal_m', 0, PARAM_INT); $cal_d = optional_param('cal_d', 0, PARAM_INT); +if ($courseid === 0) { + $courseid = optional_param('course', 0, PARAM_INT); +} + $url = new moodle_url($CFG->wwwroot.'/calendar/event.php', array('action'=>$action)); if ($eventid !== 0) $url->param('id', $eventid); -if ($eventtype !== 'select') $url->param('type', $eventtype); -if ($urlcourse !== 0) $url->param('course', $urlcourse); +if ($courseid !== 0) $url->param('course', $courseid); if ($cal_y !== 0) $url->param('cal_y', $cal_y); if ($cal_m !== 0) $url->param('cal_m', $cal_m); if ($cal_d !== 0) $url->param('cal_d', $cal_d); $PAGE->set_url($url); -if (has_capability('moodle/legacy:guest', get_context_instance(CONTEXT_SYSTEM), 0, false)) { +if ($action === 'delete' && $eventid>0) { + $deleteurl = new moodle_url($CFG->wwwroot.'/calendar/delete.php', array('id'=>$eventid)); + if ($courseid > 0) { + $deleteurl->param('course', $courseid); + } + redirect($deleteurl); +} + +$viewcalendarurl = new moodle_url(CALENDAR_URL.'view.php'); +$viewcalendarurl->params($PAGE->url->params()); +$viewcalendarurl->remove_params(array('id','action')); + +$now = usergetdate(time()); + +if (isguestuser()) { // Guests cannot do anything with events - redirect(CALENDAR_URL.'view.php?view=upcoming&course='.$urlcourse); + redirect(new moodle_url(CALENDAR_URL.'view.php', array('view'=>'upcoming', 'course'=>$courseid))); } $focus = ''; $site = get_site(); -$strcalendar = get_string('calendar', 'calendar'); - -// Initialize the session variables calendar_session_vars(); -$now = usergetdate(time()); - -$day = intval($now['mday']); -$mon = intval($now['mon']); -$yr = intval($now['year']); - -if ($usehtmleditor = can_use_html_editor()) { - $defaultformat = FORMAT_HTML; -} else { - $defaultformat = FORMAT_MOODLE; -} - // If a course has been supplied in the URL, change the filters to show that one -if($urlcourse > 0 && $DB->record_exists('course', array('id'=>$urlcourse))) { - require_login($urlcourse, false); - - if($urlcourse == SITEID) { +$courseexists = false; +if ($courseid > 0) { + if ($courseid == SITEID) { // If coming from the site page, show all courses $SESSION->cal_courses_shown = calendar_get_default_courses(true); calendar_set_referring_course(0); - } - else { + } else if ($DB->record_exists('course', array('id'=>$courseid))) { + $courseexists = true; // Otherwise show just this one - $SESSION->cal_courses_shown = $urlcourse; + $SESSION->cal_courses_shown = $courseid; calendar_set_referring_course($SESSION->cal_courses_shown); } } -switch($action) { - case 'delete': - $title = get_string('deleteevent', 'calendar'); - $event = $DB->get_record('event', array('id'=>$eventid)); - if($event === false) { - print_error('invalidevent'); - } - if(!calendar_edit_event_allowed($event)) { - print_error('nopermissions'); - } - break; - - case 'edit': - $title = get_string('editevent', 'calendar'); - $event = $DB->get_record('event', array('id'=>$eventid)); - $repeats = optional_param('repeats', 0, PARAM_INT); - - if ($event === false) { - print_error('invalidevent'); - } - if (!calendar_edit_event_allowed($event)) { - print_error('nopermissions'); - } - - if($form = data_submitted()) { - - $form->name = clean_param(strip_tags($form->name,''), PARAM_CLEAN); - - // To avoid double slashes - $form->name = $form->name; - $form->description = $form->description; - - $form->timestart = make_timestamp($form->startyr, $form->startmon, $form->startday, $form->starthr, $form->startmin); - if($form->duration == 1) { - $form->timeduration = make_timestamp($form->endyr, $form->endmon, $form->endday, $form->endhr, $form->endmin) - $form->timestart; - if($form->timeduration < 0) { - $form->timeduration = 0; - } - } - else if($form->duration == 2) { - $form->timeduration = $form->minutes * MINSECS; - } - else { - $form->timeduration = 0; - } - - validate_form($form, $err); - - if (count($err) == 0) { - - if($event->repeatid && $repeats) { - // Update all - if($form->timestart >= $event->timestart) { - $timestartoffset = 'timestart + '.($form->timestart - $event->timestart); - } - else { - $timestartoffset = 'timestart - '.($event->timestart - $form->timestart); - } - - $sql = "UPDATE {event} - SET name = ?, - description = ?, - timestart = ?, - timeduration = ?, - timemodified = ? - WHERE repeatid = ?"; - $params = array($form->name, $form->description, $timestartoffset, $form->timeduration, time(), $event->repeatid); - - $DB->execute($sql, $params); - - /// Log the event update. - add_to_log($form->courseid, 'calendar', 'edit all', 'event.php?action=edit&id='.$form->id, $form->name); - } - - else { - // Update this - $form->timemodified = time(); - $DB->update_record('event', $form); - - /// Log the event update. - add_to_log($form->courseid, 'calendar', 'edit', 'event.php?action=edit&id='.$form->id, $form->name); - } - - // OK, now redirect to day view - redirect(CALENDAR_URL.'view.php?view=day&course='.$urlcourse.'&cal_d='.$form->startday.'&cal_m='.$form->startmon.'&cal_y='.$form->startyr); - } - else { - foreach ($err as $key => $value) { - $focus = 'form.'.$key; - } - } - } - break; - - case 'new': - $title = get_string('newevent', 'calendar'); - $form = data_submitted(); - if(!empty($form) && !empty($form->name)) { - - $form->name = clean_text(strip_tags($form->name, '')); - - $form->timestart = make_timestamp($form->startyr, $form->startmon, $form->startday, $form->starthr, $form->startmin); - if($form->duration == 1) { - $form->timeduration = make_timestamp($form->endyr, $form->endmon, $form->endday, $form->endhr, $form->endmin) - $form->timestart; - if($form->timeduration < 0) { - $form->timeduration = 0; - } - } - else if ($form->duration == 2) { - $form->timeduration = $form->minutes * MINSECS; - } - else { - $form->timeduration = 0; - } - if(!calendar_add_event_allowed($form)) { - print_error('nopermissions'); - } - validate_form($form, $err); - if (count($err) == 0) { - $form->timemodified = time(); - - /// Get the event id for the log record. - $eventid = $DB->insert_record('event', $form); - - /// Use the event id as the repeatid to link repeat entries together - if ($form->repeat) { - $form->repeatid = $form->id = $eventid; - $DB->update_record('event', $form); // update the row, to set its repeatid - } - - /// Log the event entry. - add_to_log($form->courseid, 'calendar', 'add', 'event.php?action=edit&id='.$eventid, $form->name); - - if ($form->repeat) { - for($i = 1; $i < $form->repeats; $i++) { - // What's the DST offset for the previous repeat? - $dst_offset_prev = dst_offset_on($form->timestart); - - $form->timestart += WEEKSECS; - - // If the offset has changed in the meantime, update this repeat accordingly - $form->timestart += $dst_offset_prev - dst_offset_on($form->timestart); - - /// Get the event id for the log record. - $eventid = $DB->insert_record('event', $form); - - /// Log the event entry. - add_to_log($form->courseid, 'calendar', 'add', 'event.php?action=edit&id='.$eventid, $form->name); - } - } - // OK, now redirect to day view - redirect(CALENDAR_URL.'view.php?view=day&course='.$urlcourse.'&cal_d='.$form->startday.'&cal_m='.$form->startmon.'&cal_y='.$form->startyr); - } - else { - foreach ($err as $key => $value) { - $focus = 'form.'.$key; - } - } - } - break; - default: // no action - $title=''; - break; -} - - if (!empty($SESSION->cal_course_referer)) { // TODO: This is part of the Great $course Hack in Moodle. Replace it at some point. $course = $DB->get_record('course', array('id'=>$SESSION->cal_course_referer)); } else { $course = $site; } -require_login($course, false); - -$link = calendar_get_link_href(CALENDAR_URL.'view.php?view=upcoming&course='.$urlcourse.'&', - $now['mday'], $now['mon'], $now['year']); - -$PAGE->requires->yui_lib('animation'); -$PAGE->requires->js('calendar/calendar.js'); -$PAGE->navbar->add($strcalendar, new moodle_url($link)); -$PAGE->navbar->add($title); -$PAGE->set_title($site->shortname.': '.$strcalendar.': '.$title); -$PAGE->set_heading($strcalendar); -$PAGE->set_headingmenu(user_login_string($site)); -$PAGE->set_focuscontrol('eventform.name'); +require_login($course, false); -echo $OUTPUT->header(); +$strcalendar = get_string('calendar', 'calendar'); +$link = clone($viewcalendarurl); +$link->param('view', 'upcoming'); -echo ''; -echo '
'; +$formoptions = new stdClass; -switch ($action) { - case 'delete': - $confirm = optional_param('confirm', 0, PARAM_INT); - $repeats = optional_param('repeats', 0, PARAM_INT); - if ($confirm) { - // Kill it and redirect to day view - if(($event = $DB->get_record('event', array('id'=>$eventid))) !== false) { - - if ($event->repeatid && $repeats) { - $DB->delete_records('event', array('repeatid'=>$event->repeatid)); - add_to_log($event->courseid, 'calendar', 'delete all', '', $event->name); - } else { - $DB->delete_records('event', array('id'=>$eventid)); - add_to_log($event->courseid, 'calendar', 'delete', '', $event->name); +if ($eventid !== 0) { + $title = get_string('editevent', 'calendar'); + $event = calendar_event::load($eventid); + if (!calendar_edit_event_allowed($event)) { + print_error('nopermissions'); } - } - - echo '
'; - redirect(CALENDAR_URL.'view.php?view=day&course='.$urlcourse.'&cal_d='.$_REQUEST['d'].'&cal_m='.$_REQUEST['m'].'&cal_y='.$_REQUEST['y']); + $event->action = $action; + $event->course = $courseid; + $event->timedurationuntil = $event->timestart + $event->timeduration; + $event->count_repeats(); + if (!calendar_add_event_allowed($event)) { + print_error('nopermissions'); } - else { - $eventtime = usergetdate($event->timestart); - $m = $eventtime['mon']; - $d = $eventtime['mday']; - $y = $eventtime['year']; - - if ($event->repeatid) { - $repeatcount = $DB->count_records('event', array('repeatid'=>$event->repeatid)); } else { - $repeatcount = 0; - } - - // Display confirmation form - echo '
'.get_string('deleteevent', 'calendar').': '.$event->name.'
'; - echo '

'.get_string('confirmeventdelete', 'calendar').'

'; - if($repeatcount > 1) { - echo '

'.get_string('youcandeleteallrepeats', 'calendar', $repeatcount).'

'; - } - echo '
'; - $event->time = calendar_format_event_time($event, time(), '', false); - calendar_print_event($event); - echo '
'; - include('event_delete.html'); - } - break; - - case 'edit': - if(empty($form)) { - $form->name = $event->name; - $form->courseid = $event->courseid; // Not to update, but for date validation - $form->description = $event->description; - $form->timestart = $event->timestart; - $form->timeduration = $event->timeduration; - $form->id = $event->id; - $form->format = $defaultformat; - if($event->timeduration > HOURSECS) { - // More than one hour, so default to normal duration mode - $form->duration = 1; - $form->minutes = ''; - } - else if($event->timeduration) { - // Up to one hour, "minutes" mode probably is better here - $form->duration = 2; - $form->minutes = $event->timeduration / MINSECS; - } - else { - // No duration - $form->duration = 0; - $form->minutes = ''; - } - } - - if (!empty($form->courseid)) { - // TODO: This is part of the Great $course Hack in Moodle. Replace it at some point. - $course = $DB->get_record('course', array('id'=>$form->courseid)); + $title = get_string('newevent', 'calendar'); + calendar_get_allowed_types($formoptions->eventtypes, $USER->id); + $event = new calendar_event(); + $event->action = $action; + $event->course = $courseid; + $event->timeduration = 0; + if ($formoptions->eventtypes->courses) { + if ($courseexists) { + $event->courseid = $courseid; + $event->eventtype = 'course'; } else { - $course = $site; + unset($formoptions->eventtypes->courses); + unset($formoptions->eventtypes->groups); } - - if ($event->repeatid) { - $repeatcount = $DB->count_records('event', array('repeatid'=>$event->repeatid)); - $repeatcount = $fetch->repeatcount; - } else { - $repeatcount = 0; } - echo '
'.get_string('editevent', 'calendar').'
'; - include('event_edit.html'); - break; - - case 'new': if($cal_y && $cal_m && $cal_d && checkdate($cal_m, $cal_d, $cal_y)) { - $form->timestart = make_timestamp($cal_y, $cal_m, $cal_d, 0, 0, 0); - } - else if($cal_y && $cal_m && checkdate($cal_m, 1, $cal_y)) { + $event->timestart = make_timestamp($cal_y, $cal_m, $cal_d, 0, 0, 0); + } else if($cal_y && $cal_m && checkdate($cal_m, 1, $cal_y)) { if($cal_y == $now['year'] && $cal_m == $now['mon']) { - $form->timestart = make_timestamp($cal_y, $cal_m, $now['mday'], 0, 0, 0); + $event->timestart = make_timestamp($cal_y, $cal_m, $now['mday'], 0, 0, 0); + } else { + $event->timestart = make_timestamp($cal_y, $cal_m, 1, 0, 0, 0); } - else { - $form->timestart = make_timestamp($cal_y, $cal_m, 1, 0, 0, 0); } + + if (!calendar_add_event_allowed($event)) { + print_error('nopermissions'); } - if(!isset($form->timestart) or $form->timestart < 0) { - $form->timestart = time(); } - calendar_get_allowed_types($allowed); - if(!$allowed->groups && !$allowed->courses && !$allowed->site) { - // Take the shortcut - $eventtype = 'user'; +$properties = $event->properties(true); +$formoptions->event = $event; +$formoptions->hasduration = ($event->timeduration > 0); +$mform = new event_form(null, $formoptions); +$mform->set_data($properties); +$data = $mform->get_data(); +if ($data) { + if ($data->duration == 1) { + $data->timeduration = $data->timedurationuntil- $data->timestart; + } else if ($data->duration == 2) { + $data->timeduration = $data->timedurationminutes * MINSECS; + } else { + $data->timeduration = 0; } - $header = ''; - - switch($eventtype) { - case 'user': - $form->name = ''; - $form->description = ''; - $form->courseid = 0; - $form->groupid = 0; - $form->userid = $USER->id; - $form->modulename = ''; - $form->eventtype = ''; - $form->instance = 0; - $form->timeduration = 0; - $form->duration = 0; - $form->repeat = 0; - $form->repeats = ''; - $form->minutes = ''; - $form->type = 'user'; - $header = get_string('typeuser', 'calendar'); - break; - case 'group': - $groupid = optional_param('groupid', 0, PARAM_INT); - if (! ($group = groups_get_group($groupid))) { //TODO:check. - calendar_get_allowed_types($allowed); - $eventtype = 'select'; - } - else { - $form->name = ''; - $form->description = ''; - $form->courseid = $group->courseid; - $form->groupid = $group->id; - $form->userid = $USER->id; - $form->modulename = ''; - $form->eventtype = ''; - $form->instance = 0; - $form->timeduration = 0; - $form->duration = 0; - $form->repeat = 0; - $form->repeats = ''; - $form->minutes = ''; - $form->type = 'group'; - $header = get_string('typegroup', 'calendar'); + $event->update($data); + $eventurl = new moodle_url(CALENDAR_URL.'view.php', array('view'=>'day')); + if (!empty($event->courseid)) { + $eventurl->param('course', $event->courseid); } - break; - case 'course': - $courseid = optional_param('courseid', 0, PARAM_INT); - if (!$DB->record_exists('course', array('id'=>$courseid))) { - calendar_get_allowed_types($allowed); - $eventtype = 'select'; + $eventurl->param('cal_d', date('j', $event->timestart)); + $eventurl->param('cal_m', date('n', $event->timestart)); + $eventurl->param('cal_y', date('Y', $event->timestart)); + $eventurl->set_anchor('event_'.$event->id); + redirect($eventurl); } - else { - $form->name = ''; - $form->description = ''; - $form->courseid = $courseid; - $form->groupid = 0; - $form->userid = $USER->id; - $form->modulename = ''; - $form->eventtype = ''; - $form->instance = 0; - $form->timeduration = 0; - $form->duration = 0; - $form->repeat = 0; - $form->repeats = ''; - $form->minutes = ''; - $form->type = 'course'; - $header = get_string('typecourse', 'calendar'); - } - break; - case 'site': - $form->name = ''; - $form->description = ''; - $form->courseid = SITEID; - $form->groupid = 0; - $form->userid = $USER->id; - $form->modulename = ''; - $form->eventtype = ''; - $form->instance = 0; - $form->timeduration = 0; - $form->duration = 0; - $form->repeat = 0; - $form->repeats = ''; - $form->minutes = ''; - $form->type = 'site'; - $header = get_string('typesite', 'calendar'); - break; - case 'select': - break; - default: - print_error('unsupportedevent'); - } - $form->format = $defaultformat; - if(!empty($header)) { - $header = ' ('.$header.')'; - } - - echo '
'.get_string('newevent', 'calendar').$header.'
'; +$PAGE->requires->yui_lib('animation'); +$PAGE->requires->js('calendar/calendar.js'); - if($eventtype == 'select') { - $courseid = optional_param('courseid', $SESSION->cal_course_referer, PARAM_INT); - if ($courseid == 0) { // workaround by Dan for bug #6130 - $courseid = SITEID; - } - if (!$course = $DB->get_record('course', array('id'=>$courseid))) { - print_error('invalidcourse'); - } +$PAGE->navbar->add($strcalendar, $link); +$PAGE->navbar->add($title); +$PAGE->set_title($site->shortname.': '.$strcalendar.': '.$title); +$PAGE->set_heading($strcalendar); +$PAGE->set_headingmenu(user_login_string($site)); - $groupid = groups_get_course_group($course); +echo $OUTPUT->header(); - echo '

'.get_string('eventkind', 'calendar').':

'; - echo '
'; - include('event_select.html'); - echo '
'; - } - else { - include('event_new.html'); - } - break; -} +echo ''; +echo ''; -// START: Last column (3-month display) - -$defaultcourses = calendar_get_default_courses(); -//calendar_set_filters($courses, $groups, $users, $defaultcourses, $defaultcourses); - -// when adding an event you can not be a guest, so I think it's reasonalbe to ignore defaultcourses -// MDL-10353 +// when adding an event you can not be a guest, so it's reasonalbe to ignore defaultcourses MDL-10353 calendar_set_filters($courses, $groups, $users); -list($prevmon, $prevyr) = calendar_sub_month($mon, $yr); -list($nextmon, $nextyr) = calendar_add_month($mon, $yr); +list($prevmon, $prevyr) = calendar_sub_month((int)$now['mon'], (int)$now['year']); +list($nextmon, $nextyr) = calendar_add_month((int)$now['mon'], (int)$now['year']); echo ''; -echo '
'; +echo $OUTPUT->heading($title); +$mform->display(); echo ''; -echo '
'; -echo '

'.get_string('eventskey', 'calendar').'

'; -echo '
'; -echo calendar_filter_controls('event', 'action='.$action.'&type='.$eventtype.'&id='.$eventid); -echo '
'; -echo '
'; - -echo '
'; -echo '

'.get_string('monthlyview', 'calendar').'

'; -echo '
'; -echo calendar_top_controls('display', array('id' => $urlcourse, 'm' => $prevmon, 'y' => $prevyr)); -echo calendar_get_mini($courses, $groups, $users, $prevmon, $prevyr); -echo '
'; -echo calendar_top_controls('display', array('id' => $urlcourse, 'm' => $mon, 'y' => $yr)); -echo calendar_get_mini($courses, $groups, $users, $mon, $yr); -echo '
'; -echo calendar_top_controls('display', array('id' => $urlcourse, 'm' => $nextmon, 'y' => $nextyr)); -echo calendar_get_mini($courses, $groups, $users, $nextmon, $nextyr); -echo '
'; -echo '
'; -echo '
'; +$sideblock = $OUTPUT->box_start('sideblock'); +$sideblock .= $OUTPUT->box($OUTPUT->heading(get_string('eventskey', 'calendar')), 'header'); +$sideblock .= $OUTPUT->box(calendar_filter_controls('event', 'action='.$action.'&id='.$event->id), 'filters content'); +$sideblock .= $OUTPUT->box_end(); +$sideblock .= $OUTPUT->box_start('sideblock'); +$sideblock .= $OUTPUT->box($OUTPUT->heading(get_string('monthlyview', 'calendar')), 'header'); +$sideblock .= $OUTPUT->box_start('content'); +$sideblock .= $OUTPUT->box_start('minicalendarblock minicalendartop'); +$sideblock .= calendar_top_controls('display', array('id' => $courseid, 'm' => $prevmon, 'y' => $prevyr)); +$sideblock .= calendar_get_mini($courses, $groups, $users, $prevmon, $prevyr); +$sideblock .= $OUTPUT->box_end(); +$sideblock .= $OUTPUT->box_start('minicalendarblock'); +$sideblock .= calendar_top_controls('display', array('id' => $courseid, 'm' => (int)$now['mon'], 'y' => (int)$now['year'])); +$sideblock .= calendar_get_mini($courses, $groups, $users, (int)$now['mon'], (int)$now['year']); +$sideblock .= $OUTPUT->box_end(); +$sideblock .= $OUTPUT->box_start('minicalendarblock'); +$sideblock .= calendar_top_controls('display', array('id' => $courseid, 'm' => $nextmon, 'y' => $nextyr)); +$sideblock .= calendar_get_mini($courses, $groups, $users, $nextmon, $nextyr); +$sideblock .= $OUTPUT->box_end(); +$sideblock .= $OUTPUT->box_end(); +$sideblock .= $OUTPUT->box_end(); +echo $sideblock; + +echo ''; +echo ''; echo $OUTPUT->footer(); - - -function validate_form(&$form, &$err) { - global $DB; - - $form->name = trim($form->name); - $form->description = trim($form->description); - - if(empty($form->name)) { - $err['name'] = get_string('errornoeventname', 'calendar'); - } -/* Allow events without a description - if(empty($form->description)) { - $err['description'] = get_string('errornodescription', 'calendar'); - } -*/ - if(!checkdate($form->startmon, $form->startday, $form->startyr)) { - $err['timestart'] = get_string('errorinvaliddate', 'calendar'); - } - if($form->duration == 2 and !checkdate($form->endmon, $form->endday, $form->endyr)) { - $err['timeduration'] = get_string('errorinvaliddate', 'calendar'); - } - if($form->duration == 2 and !($form->minutes > 0 and $form->minutes < 1000)) { - $err['minutes'] = get_string('errorinvalidminutes', 'calendar'); - } - if (!empty($form->repeat) and !($form->repeats > 1 and $form->repeats < 100)) { - $err['repeats'] = get_string('errorinvalidrepeats', 'calendar'); - } - if(!empty($form->courseid)) { - // Timestamps must be >= course startdate - $course = $DB->get_record('course', array('id'=>$form->courseid)); - if($course === false) { - print_error('invalidcourse'); - } - else if($form->timestart < $course->startdate) { - $err['timestart'] = get_string('errorbeforecoursestart', 'calendar'); - } - } -} - -function calendar_add_event_allowed($event) { - global $USER, $DB; - - // can not be using guest account - if (empty($USER->id) or $USER->username == 'guest') { - return false; - } - - $sitecontext = get_context_instance(CONTEXT_SYSTEM); - // if user has manageentries at site level, always return true - if (has_capability('moodle/calendar:manageentries', $sitecontext)) { - return true; - } - - switch ($event->type) { - case 'course': - return has_capability('moodle/calendar:manageentries', get_context_instance(CONTEXT_COURSE, $event->courseid)); - - case 'group': - // Allow users to add/edit group events if: - // 1) They have manageentries (= entries for whole course) - // 2) They have managegroupentries AND are in the group - $group = $DB->get_record('groups', array('id'=>$event->groupid)); - return $group && ( - has_capability('moodle/calendar:manageentries', get_context_instance(CONTEXT_COURSE, $group->courseid)) || - (has_capability('moodle/calendar:managegroupentries', get_context_instance(CONTEXT_COURSE, $group->courseid)) - && groups_is_member($event->groupid))); - - case 'user': - if ($event->userid == $USER->id) { - return (has_capability('moodle/calendar:manageownentries', $sitecontext)); - } - //there is no 'break;' intentionally - - case 'site': - return has_capability('moodle/calendar:manageentries', get_context_instance(CONTEXT_COURSE, SITEID)); - - default: - return false; - } -} diff --git a/calendar/event_delete.html b/calendar/event_delete.html deleted file mode 100644 index 8d013ba942..0000000000 --- a/calendar/event_delete.html +++ /dev/null @@ -1,55 +0,0 @@ - - - - 1) { ?> - - - - -
-
-

-   - - - - - - - - - -   -

-
-
-
-

-   - - - - - - - - - -   -

-
-
-
-

-   - - - - - - -   -

-
-
- diff --git a/calendar/event_edit.html b/calendar/event_edit.html deleted file mode 100644 index 2abf510e3b..0000000000 --- a/calendar/event_edit.html +++ /dev/null @@ -1,109 +0,0 @@ - 'startday', - 'months' => 'startmon', - 'years' => 'startyr', - 'hours' => 'starthr', - 'minutes' => 'startmin'), $form->timestart); - -$endselectors = html_select::make_time_selectors(array( - 'days' => 'endday', - 'months' => 'endmon', - 'years' => 'endyr', - 'hours' => 'endhr', - 'minutes' => 'endmin'), $form->timestart + $form->timeduration); -?> -
- - - - - - - - - - - - - - - - - - 1) { ?> - - - - - - - - -
- : - - - error_text($err['name']); ?> -
- : - - description); - if (isset($err['description'])) echo $OUTPUT->error_text($err['description']); - ?> -
: - select($startselectors[0]) . $OUTPUT->select($startselectors[1]) . $OUTPUT->select($startselectors[2]);?> - - select($startselectors[3]) . $OUTPUT->select($startselectors[4]);?> - error_text($err['timestart']); ?> -
- : - -
- duration == 0) echo 'checked="checked"'; ?>/> - -
-
- duration == 1) echo 'checked="checked"'; ?>/> - - select($endselectors[0]) . $OUTPUT->select($endselectors[1]) . $OUTPUT->select($endselectors[2]);?> - - select($endselectors[3]) . $OUTPUT->select($endselectors[4]);?> - error_text($err['timeduration']); ?> -
-
- duration == 2) echo 'checked="checked"'; ?>/> - - - error_text($err['minutes']); ?> -
-
- : - -
- - -
-
- - -
-

-

- - - - - -

-
- diff --git a/calendar/event_form.php b/calendar/event_form.php new file mode 100644 index 0000000000..890439253f --- /dev/null +++ b/calendar/event_form.php @@ -0,0 +1,178 @@ +. + +/** + * The mform for creating and editing a calendar event + * + * @copyright 2009 Sam Hemelryk + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + * @package calendar + */ + + /** + * Always include formslib + */ +require_once($CFG->dirroot.'/lib/formslib.php'); + +/** + * The mform class for creating and editing a calendar + * + * @copyright 2009 Sam Hemelryk + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class event_form extends moodleform { + /** + * The form definition + */ + function definition () { + global $CFG, $USER, $OUTPUT; + $mform = $this->_form; + $newevent = (empty($this->_customdata->event) || empty($this->_customdata->event->id)); + $repeatedevents = (!empty($this->_customdata->event->eventrepeats) && $this->_customdata->event->eventrepeats>0); + $hasduration = (!empty($this->_customdata->hasduration) && $this->_customdata->hasduration); + + if ($newevent) { + $eventtypes = $this->_customdata->eventtypes; + $options = array(); + if (!empty($eventtypes->user)) { + $options['user'] = get_string('user'); + } + if (!empty($eventtypes->groups) && is_array($eventtypes->groups)) { + $options['group'] = get_string('group'); + } + if (!empty($eventtypes->courses)) { + $options['course'] = get_string('course'); + } + if (!empty($eventtypes->site)) { + $options['site'] = get_string('site'); + } + + $mform->addElement('select', 'eventtype', get_string('eventkind', 'calendar'), $options); + $mform->addRule('eventtype', get_string('required'), 'required'); + + if (!empty($eventtypes->groups) && is_array($eventtypes->groups)) { + $groupoptions = array(); + foreach ($eventtypes->groups as $group) { + $groupoptions[$group->id] = $group->name; + } + $mform->addElement('select', 'groupid', get_string('typegroup', 'calendar'), $groupoptions); + $mform->disabledIf('groupid', 'eventtype', 'noteq', 'group'); + } + } + + // Add some hidden fields + $mform->addElement('hidden', 'id'); + $mform->setType('id', PARAM_INT); + $mform->setDefault('id', 0); + + $mform->addElement('hidden', 'courseid'); + $mform->setType('courseid', PARAM_INT); + + $mform->addElement('hidden', 'userid'); + $mform->setType('userid', PARAM_INT); + $mform->setDefault('userid', $USER->id); + + $mform->addElement('hidden', 'modulename'); + $mform->setType('modulename', PARAM_INT); + $mform->setDefault('modulename', ''); + + $mform->addElement('hidden', 'instance'); + $mform->setType('instance', PARAM_INT); + $mform->setDefault('instance', 0); + + $mform->addElement('hidden', 'action'); + $mform->setType('action', PARAM_INT); + + // Normal fields + $mform->addElement('text', 'name', get_string('eventname','calendar'), 'size="50"'); + $mform->addRule('name', get_string('required'), 'required'); + $mform->setType('name', PARAM_TEXT); + + $mform->addElement('editor', 'description', get_string('eventdescription','calendar'), null, $this->_customdata->event->editoroptions); + $mform->setType('description', PARAM_RAW); + + $mform->addElement('date_time_selector', 'timestart', get_string('date')); + $mform->addRule('timestart', get_string('required'), 'required'); + + $mform->addElement('radio', 'duration', get_string('eventduration', 'calendar'), get_string('durationnone', 'calendar'), 0); + + $mform->addElement('radio', 'duration', null, get_string('durationuntil', 'calendar'), 1); + $mform->addElement('date_time_selector', 'timedurationuntil', null); + $mform->disabledIf('timedurationuntil','duration','noteq', 1); + + $mform->addElement('radio', 'duration', null, get_string('durationminutes', 'calendar'), 2); + $mform->addElement('text', 'timedurationminutes', null); + $mform->setType('timedurationminutes', PARAM_INT); + $mform->disabledIf('timedurationminutes','duration','noteq', 2); + + $mform->setDefault('duration', ($hasduration)?1:0); + + if ($newevent) { + + $mform->addElement('checkbox', 'repeat', get_string('repeatevent', 'calendar'), null, 'repeat'); + $mform->addElement('text', 'repeats', get_string('repeatweeksl', 'calendar'), 'maxlength="10" size="10"'); + $mform->setType('repeats', PARAM_INT); + $mform->setDefault('repeats', 1); + $mform->disabledIf('repeats','repeat','notchecked'); + + } else if ($repeatedevents > 0) { + + $mform->addElement('hidden', 'repeatid'); + $mform->setType('repeatid', PARAM_INT); + + $mform->addElement('header', 'repeatedevents', get_string('repeatedevents', 'calendar')); + $mform->addElement('checkbox', 'repeateditall', null, get_string('repeateditall', 'calendar', $repeatedevents), 'repeat'); + $mform->setDefault('repeateditall', 'checked'); + + } + + $this->add_action_buttons(false, get_string('savechanges')); + } + + /** + * A bit of custom validation for this form + * + * @param array $data An assoc array of field=>value + * @param array $files An array of files + * @return array + */ + function validation($data, $files) { + global $DB, $CFG; + + $errors = parent::validation($data, $files); + + if ($data['courseid'] > 0) { + if ($course = $DB->get_record('course', array('id'=>$data['courseid']))) { + if ($data['timestart'] < $course->startdate) { + $errors['timestart'] = get_string('errorbeforecoursestart', 'calendar'); + } + } else { + $errors['courseid'] = get_string('invalidcourse', 'error'); + } + + } + + if ($data['duration'] == 1 && $data['timestart'] > $data['timedurationuntil']) { + $errors['timedurationuntil'] = get_string('invalidtimedurationuntil', 'calendar'); + } else if ($data['duration'] == 2 && (trim($data['timedurationminutes']) == '' || $data['timedurationminutes'] < 1)) { + $errors['timedurationminutes'] = get_string('invalidtimedurationminutes', 'calendar'); + } + + return $errors; + } + +} \ No newline at end of file diff --git a/calendar/event_new.html b/calendar/event_new.html deleted file mode 100644 index 9309e31d2e..0000000000 --- a/calendar/event_new.html +++ /dev/null @@ -1,118 +0,0 @@ -get_record('course', array('id'=>($form->courseid ? $form->courseid : $site->id))); - $startselectors = html_select::make_time_selectors(array( - 'days' => 'startday', - 'months' => 'startmon', - 'years' => 'startyr', - 'hours' => 'starthr', - 'minutes' => 'startmin'), (int) $form->timestart); - - $endselectors = html_select::make_time_selectors(array( - 'days' => 'endday', - 'months' => 'endmon', - 'years' => 'endyr', - 'hours' => 'endhr', - 'minutes' => 'endmin'), $form->timestart + $form->timeduration); -?> -
- - - - - - - - - - - - - - - - - - - - - - - - - - -
- - error_text($err['name']); ?> -
- description); - if (isset($err['description'])) echo $OUTPUT->error_text($err['description']); - ?> -
- : - - select($startselectors[0]) . $OUTPUT->select($startselectors[1]) . $OUTPUT->select($startselectors[2]);?> - - select($startselectors[3]) . $OUTPUT->select($startselectors[4]);?> - error_text($err['timestart']); ?> -
- : - -
- duration == 0) echo 'checked="checked"'; ?>/> - -
-
- duration == 1) echo 'checked="checked"'; ?>/> - - select($endselectors[0]) . $OUTPUT->select($endselectors[1]) . $OUTPUT->select($endselectors[2]);?> - - select($endselectors[3]) . $OUTPUT->select($endselectors[4]);?> - error_text($err['timeduration']); ?> -
-
- duration == 2) echo 'checked="checked"'; ?>/> - - - error_text($err['minutes']); ?> - -
-
- : - -
- repeat == 0) echo 'checked="checked"'; ?>/> - -
-
- repeat == 1) echo 'checked="checked"'; ?>/> - - - - error_text($err['repeats']); ?> -
-

-

- - - - - - - - - - -

-
- diff --git a/calendar/event_select.html b/calendar/event_select.html deleted file mode 100644 index 7fd1b565c2..0000000000 --- a/calendar/event_select.html +++ /dev/null @@ -1,58 +0,0 @@ -
- - - - - - - -
- -user)) { ?> -
- - -
- - -groups) && is_array($allowed->groups)) { ?> -
- - - -
- - -courses)) { ?> -
- - - -
- - -site)) { ?> -
- - -
- -
- - -
-

- - - -

-
diff --git a/calendar/export_execute.php b/calendar/export_execute.php index f0bee0c28b..757dc34a84 100644 --- a/calendar/export_execute.php +++ b/calendar/export_execute.php @@ -54,7 +54,7 @@ if(!empty($what) && !empty($time)) { switch($time) { case 'weeknow': - $startweekday = get_user_preferences('calendar_startwday', CALENDAR_STARTING_WEEKDAY); + $startweekday = get_user_preferences('calendar_startwday', calendar_get_starting_weekday()); $startmonthday = find_day_in_month($now['mday'] - 6, $startweekday, $now['mon'], $now['year']); $startmonth = $now['mon']; $startyear = $now['year']; @@ -73,7 +73,7 @@ if(!empty($what) && !empty($time)) { $timeend = make_timestamp($endyear, $endmonth, $endmonthday) - 1; break; case 'weeknext': - $startweekday = get_user_preferences('calendar_startwday', CALENDAR_STARTING_WEEKDAY); + $startweekday = get_user_preferences('calendar_startwday', calendar_get_starting_weekday()); $startmonthday = find_day_in_month($now['mday'] + 1, $startweekday, $now['mon'], $now['year']); $startmonth = $now['mon']; $startyear = $now['year']; diff --git a/calendar/lib.php b/calendar/lib.php index e1f66bf74b..281b019fe9 100644 --- a/calendar/lib.php +++ b/calendar/lib.php @@ -45,34 +45,49 @@ define('CALENDAR_DEFAULT_STARTING_WEEKDAY', 1); // This is a packed bitfield: day X is "weekend" if $field & (1 << X) is true // Default value = 65 = 64 + 1 = 2^6 + 2^0 = Saturday & Sunday define('CALENDAR_DEFAULT_WEEKEND', 65); +define('CALENDAR_UPCOMING_DAYS', isset($CFG->calendar_lookahead) ? intval($CFG->calendar_lookahead) : CALENDAR_DEFAULT_UPCOMING_LOOKAHEAD); +define('CALENDAR_UPCOMING_MAXEVENTS', isset($CFG->calendar_maxevents) ? intval($CFG->calendar_maxevents) : CALENDAR_DEFAULT_UPCOMING_MAXEVENTS); +define('CALENDAR_WEEKEND', isset($CFG->calendar_weekend) ? intval($CFG->calendar_weekend) : CALENDAR_DEFAULT_WEEKEND); +define('CALENDAR_URL', $CFG->wwwroot.'/calendar/'); +define('CALENDAR_TF_24', '%H:%M'); +define('CALENDAR_TF_12', '%I:%M %p'); -//TODO: fix this ehm "not nice code at all" - -// Fetch the correct values from admin settings/lang pack -// If no such settings found, use the above defaults -$firstday = isset($CFG->calendar_startwday) ? $CFG->calendar_startwday : get_string('firstdayofweek'); -if(!is_numeric($firstday)) { - define ('CALENDAR_STARTING_WEEKDAY', CALENDAR_DEFAULT_STARTING_WEEKDAY); -} -else { - define ('CALENDAR_STARTING_WEEKDAY', intval($firstday) % 7); -} -define ('CALENDAR_UPCOMING_DAYS', isset($CFG->calendar_lookahead) ? intval($CFG->calendar_lookahead) : CALENDAR_DEFAULT_UPCOMING_LOOKAHEAD); -define ('CALENDAR_UPCOMING_MAXEVENTS', isset($CFG->calendar_maxevents) ? intval($CFG->calendar_maxevents) : CALENDAR_DEFAULT_UPCOMING_MAXEVENTS); -define ('CALENDAR_WEEKEND', isset($CFG->calendar_weekend) ? intval($CFG->calendar_weekend) : CALENDAR_DEFAULT_WEEKEND); -define ('CALENDAR_URL', $CFG->wwwroot.'/calendar/'); -define ('CALENDAR_TF_24', '%H:%M'); -define ('CALENDAR_TF_12', '%I:%M %p'); +/** + * CALENDAR_STARTING_WEEKDAY has since been deprecated please call calendar_get_starting_weekday() instead + * @deprecated + */ +define('CALENDAR_STARTING_WEEKDAY', CALENDAR_DEFAULT_STARTING_WEEKDAY); $CALENDARDAYS = array('sunday','monday','tuesday','wednesday','thursday','friday','saturday'); +/** + * Gets the first day of the week + * + * Used to be define('CALENDAR_STARTING_WEEKDAY', blah); + * + * @return int + */ +function calendar_get_starting_weekday() { + global $CFG; + if (isset($CFG->calendar_startwday)) { + $firstday = $CFG->calendar_startwday; + } else { + $firstday = get_string('firstdayofweek'); + } + + if(!is_numeric($firstday)) { + return CALENDAR_DEFAULT_STARTING_WEEKDAY; + } else { + return intval($firstday) % 7; + } +} function calendar_get_mini($courses, $groups, $users, $cal_month = false, $cal_year = false) { global $CFG, $USER, $OUTPUT; $display = new stdClass; - $display->minwday = get_user_preferences('calendar_startwday', CALENDAR_STARTING_WEEKDAY); + $display->minwday = get_user_preferences('calendar_startwday', calendar_get_starting_weekday()); $display->maxwday = $display->minwday + 6; $content = ''; @@ -516,7 +531,7 @@ function calendar_add_event_metadata($event) { return $event; } -function calendar_print_event($event) { +function calendar_print_event($event, $showactions=true) { global $CFG, $USER, $OUTPUT; static $strftimetime; @@ -557,7 +572,7 @@ function calendar_print_event($event) { echo ''; } echo format_text($event->description, FORMAT_HTML); - if (calendar_edit_event_allowed($event)) { + if (calendar_edit_event_allowed($event) && $showactions) { echo '
'; $calendarcourseid = ''; if (!empty($event->calendarcourseid)) { @@ -565,7 +580,7 @@ function calendar_print_event($event) { } if (empty($event->cmid)) { $editlink = CALENDAR_URL.'event.php?action=edit&id='.$event->id.$calendarcourseid; - $deletelink = CALENDAR_URL.'event.php?action=delete&id='.$event->id.$calendarcourseid; + $deletelink = CALENDAR_URL.'delete.php?id='.$event->id.$calendarcourseid; } else { $editlink = $CFG->wwwroot.'/course/mod.php?update='.$event->cmid.'&return=true&sesskey='.sesskey(); $deletelink = ''; // deleting activities directly from calendar is dangerous/confusing - see MDL-11843 @@ -1168,7 +1183,7 @@ function calendar_session_vars($course=null) { if(!isset($SESSION->cal_show_user)) { $SESSION->cal_show_user = true; } - if (isset($course)) { + if ($course !== null) { // speedup hack for calendar related blocks $SESSION->cal_courses_shown = array($course->id => $course); } else { @@ -1179,8 +1194,7 @@ function calendar_session_vars($course=null) { // as it will automatically change to the user's id when the user first logs // in. With !isset(), it would never do that. $SESSION->cal_users_shown = !empty($USER->id) ? $USER->id : false; - } - else if(is_numeric($SESSION->cal_users_shown) && !empty($USER->id) && $SESSION->cal_users_shown != $USER->id) { + } else if(is_numeric($SESSION->cal_users_shown) && !empty($USER->id) && $SESSION->cal_users_shown != $USER->id) { // Follow the white rabbit, for example if a teacher logs in as a student $SESSION->cal_users_shown = $USER->id; } @@ -1595,3 +1609,708 @@ function calendar_user_can_add_event() { calendar_get_allowed_types($allowed); return (bool)($allowed->user || $allowed->groups || $allowed->courses || $allowed->site); } + +/** + * Check wether the current user is permitted to add events + * + * @param object $event + * @return bool + */ +function calendar_add_event_allowed($event) { + global $USER, $DB; + + // can not be using guest account + if (empty($USER->id) or $USER->username == 'guest') { + return false; + } + + $sitecontext = get_context_instance(CONTEXT_SYSTEM); + // if user has manageentries at site level, always return true + if (has_capability('moodle/calendar:manageentries', $sitecontext)) { + return true; + } + + switch ($event->eventtype) { + case 'course': + return has_capability('moodle/calendar:manageentries', get_context_instance(CONTEXT_COURSE, $event->courseid)); + + case 'group': + // Allow users to add/edit group events if: + // 1) They have manageentries (= entries for whole course) + // 2) They have managegroupentries AND are in the group + $group = $DB->get_record('groups', array('id'=>$event->groupid)); + return $group && ( + has_capability('moodle/calendar:manageentries', get_context_instance(CONTEXT_COURSE, $group->courseid)) || + (has_capability('moodle/calendar:managegroupentries', get_context_instance(CONTEXT_COURSE, $group->courseid)) + && groups_is_member($event->groupid))); + + case 'user': + if ($event->userid == $USER->id) { + return (has_capability('moodle/calendar:manageownentries', $sitecontext)); + } + //there is no 'break;' intentionally + + case 'site': + return has_capability('moodle/calendar:manageentries', get_context_instance(CONTEXT_COURSE, SITEID)); + + default: + return false; + } +} + +/** + * A class to manage calendar events + * + * This class provides the required functionality in order to manage calendar events. + * It was introduced as part of Moodle 2.0 and was created in order to provide a + * better framework for dealing with calendar events in particular regard to file + * handling through the new file API + * + * @property int $id The id within the event table + * @property string $name The name of the event + * @property string $description The description of the event + * @property int $format The format of the description FORMAT_? + * @property int $courseid The course the event is associated with (0 if none) + * @property int $groupid The group the event is associated with (0 if none) + * @property int $userid The user the event is associated with (0 if none) + * @property int $repeatid If this is a repeated event this will be set to the + * id of the original + * @property string $modulename If added by a module this will be the module name + * @property int $instance If added by a module this will be the module instance + * @property string $eventtype The event type + * @property int $timestart The start time as a timestamp + * @property int $timeduration The duration of the event in seconds + * @property int $visible 1 if the event is visible + * @property int $uuid ? + * @property int $sequence ? + * @property int $timemodified The time last modified as a timestamp + */ +class calendar_event { + + /** + * An object containing the event properties can be accessed via the + * magic __get/set methods + * @var array + */ + protected $properties = null; + /** + * The converted event discription with file paths resolved + * This gets populated when someone requests description for the first time + * @var string + */ + protected $_description = null; + /** + * The filearea to use with this event + * @var string + */ + protected static $filearea = 'calendar_event_description'; + /** + * The options to use with this description editor + * @var array + */ + protected $editoroptions = array( + 'subdirs'=>false, + 'forcehttps'=>false, + 'maxfiles'=>EDITOR_UNLIMITED_FILES, + 'maxbytes'=>null, + 'trusttext'=>false); + /** + * The context to use with the description editor + * @var object + */ + protected $editorcontext = null; + + /** + * Instantiates a new event and optionally populates its properties with the + * data provided + * + * @param stdClass $data Optional. An object containing the properties to for + * an event + */ + public function __construct($data=null) { + global $CFG; + + // First convert to object if it is not already (should either be object or assoc array) + if (!is_object($data)) { + $data = (object)$data; + } + + $this->editoroptions['maxbytes'] = $CFG->maxbytes; + + $data->eventrepeats = 0; + + if (empty($data->id)) { + $data->id = null; + } + + if (!empty($data->timeduration) && is_array($data->timeduration)) { + $data->timeduration = make_timestamp($data->timeduration['year'], $data->timeduration['month'], $data->timeduration['day'], $data->timeduration['hour'], $data->timeduration['minute']) - $data->timestart; + } + if (!empty($data->description) && is_array($data->description)) { + $data->format = $data->description['format']; + $data->description = $data->description['text']; + } else if (empty($data->description)) { + $data->description = ''; + } + + if (empty($data->format)) { + if (can_use_html_editor()) { + $data->format = FORMAT_HTML; + } else { + $data->format = FORMAT_MOODLE; + } + } + + $this->properties = $data; + } + + /** + * Magic property method + * + * Attempts to call a set_$key method if one exists otherwise falls back + * to simply set the property + * + * @param string $key + * @param mixed $value + */ + public function __set($key, $value) { + if (method_exists($this, 'set_'.$key)) { + $this->{'set_'.$key}($value); + } + $this->properties->{$key} = $value; + } + + /** + * Magic get method + * + * Attempts to call a get_$key method to return the property and ralls over + * to return the raw property + * + * @param str $key + * @return mixed + */ + public function __get($key) { + if (method_exists($this, 'get_'.$key)) { + return $this->{'get_'.$key}(); + } + return $this->properties->{$key}; + } + + /** + * Stupid PHP needs an isset magic method if you use the get magic method and + * still want empty calls to work.... blah ~! + * + * @param string $key + * @return bool + */ + public function __isset($key) { + return !empty($this->properties->{$key}); + } + + /** + * Returns an array of editoroptions for this event: Called by __get + * Please use $blah = $event->editoroptions; + * @return array + */ + protected function get_editoroptions() { + return $this->editoroptions; + } + + /** + * Returns an event description: Called by __get + * Please use $blah = $event->description; + * + * @return string + */ + protected function get_description() { + global $USER; + if ($this->_description === null) { + // Check if we have already resolved the context for this event + if ($this->editorcontext === null) { + // Switch on the event type to decide upon the appropriate context + // to use for this event + switch ($this->properties->eventtype) { + case 'course': + case 'group': + // Course and group event files are served from the course context + // and there are checks in plugin.php to ensure permissions are + // followed + $this->editorcontext = get_context_instance(CONTEXT_COURSE, $this->properties->courseid); + break; + case 'user': + // User context + $this->editorcontext = get_context_instance(CONTEXT_USER, $USER->id); + break; + case 'site': + // Site context + $this->editorcontext = get_context_instance(CONTEXT_SYSTEM); + break; + default: + // Hmmmm some modules use custom eventtype strings, if that is the + // case we are going to abandon using files. Anything that uses a + // custom type is being added manually through code + return clean_text($this->properties->description, $this->properties->format); + break; + } + } + + // Work out the item id for the editor, if this is a repeated event then the files will + // be associated with the original + if (!empty($this->properties->repeatid) && $this->properties->repeatid > 0) { + $itemid = $this->properties->repeatid; + } else { + $itemid = $this->properties->id; + } + + // Convert file paths in the description so that things display correctly + $this->_description = file_rewrite_pluginfile_urls($this->properties->description, 'pluginfile.php', $this->editorcontext->id, self::$filearea, $itemid); + // Clean the text so no nasties get through + $this->_description = clean_text($this->_description, $this->properties->format); + } + // Finally return the description + return $this->_description; + } + + /** + * Return the number of repeat events there are in this events series + * + * @return int + */ + public function count_repeats() { + global $DB; + if (!empty($this->properties->repeatid)) { + $this->properties->eventrepeats = $DB->count_records('event', array('repeatid'=>$this->properties->repeatid)); + // We don't want to count ourselves + $this->properties->eventrepeats--; + } + return $this->properties->eventrepeats; + } + + /** + * Update or create an event within the database + * + * Pass in a object containing the event properties and this function will + * insert it into the database and deal with any associated files + * + * @see add_event() + * @see update_event() + * + * @param stdClass $data + */ + public function update($data) { + global $CFG, $DB, $USER; + + $this->properties = (object)$data; + $this->properties->timemodified = time(); + $usingeditor = (!empty($this->properties->description) && is_array($this->properties->description)); + + if (empty($this->properties->id) || $this->properties->id < 1) { + + if (!calendar_add_event_allowed($this->properties)) { + print_error('nopermissions'); + } + + if ($usingeditor) { + switch ($this->properties->eventtype) { + case 'user': + $this->editorcontext = get_context_instance(CONTEXT_USER, $USER->id); + $this->properties->courseid = 0; + $this->properties->groupid = 0; + $this->properties->userid = $USER->id; + break; + case 'site': + $this->editorcontext = get_context_instance(CONTEXT_SYSTEM); + $this->properties->courseid = SITEID; + $this->properties->groupid = 0; + $this->properties->userid = $USER->id; + break; + case 'course': + $this->editorcontext = get_context_instance(CONTEXT_COURSE, $this->properties->courseid); + $this->properties->groupid = 0; + $this->properties->userid = $USER->id; + break; + case 'group': + $this->editorcontext = get_context_instance(CONTEXT_COURSE, $this->properties->courseid); + $this->properties->groupid = 0; + $this->properties->userid = $USER->id; + break; + default: + // Ewww we should NEVER get here, but just incase we do lets + // fail gracefully + $usingeditor = false; + break; + } + + $editor = $this->properties->description; + $this->properties->format = $this->properties->description['format']; + $this->properties->description = $this->properties->description['text']; + } + + // Insert the event into the database + $this->properties->id = $DB->insert_record('event', $this->properties); + + if ($usingeditor) { + $this->properties->description = file_save_draft_area_files( + $editor['itemid'], + $this->editorcontext->id, + self::$filearea, + $this->properties->id, + $this->editoroptions, + $editor['text'], + $this->editoroptions['forcehttps']); + + $DB->set_field('event', 'description', $this->properties->description, array('id'=>$this->properties->id)); + } + + // Log the event entry. + add_to_log($this->properties->courseid, 'calendar', 'add', 'event.php?action=edit&id='.$this->properties->id, $this->properties->name); + + $repeatedids = array(); + + if (!empty($this->properties->repeat)) { + $this->properties->repeatid = $this->properties->id; + $DB->set_field('event', 'repeatid', $this->properties->repeatid, array('id'=>$this->properties->id)); + + $eventcopy = clone($this->properties); + unset($eventcopy->id); + + for($i = 1; $i < $eventcopy->repeats; $i++) { + + $eventcopy->timestart = ($eventcopy->timestart+WEEKSECS) + dst_offset_on($eventcopy->timestart) - dst_offset_on($eventcopy->timestart+WEEKSECS); + + // Get the event id for the log record. + $eventcopyid = $DB->insert_record('event', $eventcopy); + + // If the context has been set delete all associated files + if ($usingeditor) { + $fs = get_file_storage(); + $files = $fs->get_area_files($this->editorcontext->id, self::$filearea, $this->properties->id); + foreach ($files as $file) { + $fs->create_file_from_storedfile(array('itemid'=>$eventcopyid), $file); + } + } + + $repeatedids[] = $eventcopyid; + // Log the event entry. + add_to_log($eventcopy->courseid, 'calendar', 'add', 'event.php?action=edit&id='.$eventcopyid, $eventcopy->name); + } + } + + // Hook for tracking added events + self::calendar_event_hook('add_event', array($this->properties, $repeatedids)); + return true; + } else { + + if(!calendar_edit_event_allowed($this->properties)) { + print_error('nopermissions'); + } + + if ($usingeditor) { + if ($this->editorcontext !== null) { + $this->properties->description = file_save_draft_area_files( + $this->properties->description['itemid'], + $this->editorcontext->id, + self::$filearea, + $this->properties->id, + $this->editoroptions, + $this->properties->description['text'], + $this->editoroptions['forcehttps']); + } else { + $this->properties->format = $this->properties->description['format']; + $this->properties->description = $this->properties->description['text']; + } + } + + $event = $DB->get_record('event', array('id'=>$this->properties->id)); + + $updaterepeated = (!empty($this->properties->repeatid) && !empty($this->properties->repeateditall)); + + if ($updaterepeated) { + // Update all + if ($this->properties->timestart != $event->timestart) { + $timestartoffset = $this->properties->timestart - $event->timestart; + $sql = "UPDATE {event} + SET name = ?, + description = ?, + timestart = timestart + ?, + timeduration = ?, + timemodified = ? + WHERE repeatid = ?"; + $params = array($this->properties->name, $this->properties->description, $timestartoffset, $this->properties->timeduration, time(), $event->repeatid); + } else { + $sql = "UPDATE {event} SET name = ?, description = ?, timeduration = ?, timemodified = ? WHERE repeatid = ?"; + $params = array($this->properties->name, $this->properties->description, $this->properties->timeduration, time(), $event->repeatid); + } + $DB->execute($sql, $params); + + // Log the event update. + add_to_log($this->properties->courseid, 'calendar', 'edit all', 'event.php?action=edit&id='.$this->properties->id, $this->properties->name); + } else { + $DB->update_record('event', $this->properties); + add_to_log($this->properties->courseid, 'calendar', 'edit', 'event.php?action=edit&id='.$this->properties->id, $this->properties->name); + } + + // Hook for tracking event updates + self::calendar_event_hook('update_event', array($this->properties, $updaterepeated)); + return true; + } + } + + /** + * Deletes an event and if selected an repeated events in the same series + * + * This function deletes an event, any associated events if $deleterepeated=true, + * and cleans up any files associated with the events. + * + * @see delete_event() + * + * @param bool $deleterepeated + * @return bool + */ + public function delete($deleterepeated=false) { + global $DB, $USER, $CFG; + + // If $this->properties->id is not set then something is wrong + if (empty($this->properties->id)) { + debugging('Attempting to delete an event before it has been loaded', DEBUG_DEVELOPER); + return false; + } + + // Delete the event + $DB->delete_records('event', array('id'=>$this->properties->id)); + + // If the editor context hasn't already been set then set it now + if ($this->editorcontext === null) { + switch ($this->properties->eventtype) { + case 'course': + case 'group': + $this->editorcontext = get_context_instance(CONTEXT_COURSE, $this->properties->courseid); + break; + case 'user': + $this->editorcontext = get_context_instance(CONTEXT_USER, $USER->id); + break; + case 'site': + $this->editorcontext = get_context_instance(CONTEXT_SYSTEM); + break; + default: + // There is a chance we can get here as some modules use there own + // eventtype strings. In this case the event has been added by code + // and we don't need to worry about it anyway + break; + } + } + + // If the context has been set delete all associated files + if ($this->editorcontext !== null) { + $fs = get_file_storage(); + $files = $fs->get_area_files($this->editorcontext->id, self::$filearea, $this->properties->id); + foreach ($files as $file) { + $file->delete(); + } + } + + // Fire the event deleted hook + self::calendar_event_hook('delete_event', array($this->properties->id, $deleterepeated)); + + // If we need to delete repeated events then we will fetch them all and delete one by one + if ($deleterepeated && !empty($this->properties->repeatid) && $this->properties->repeatid > 0) { + // Get all records where the repeatid is the same as the event being removed + $events = $DB->get_records('event', array('repeatid'=>$this->properties->repeatid)); + // For each of the returned events populate a calendar_event object and call delete + // make sure the arg passed is false as we are already deleting all repeats + foreach ($events as $event) { + $event = new calendar_event($event); + $event->delete(false); + } + } + + return true; + } + + /** + * Fetch all event properties + * + * This function returns all of the events properties as an object and optionally + * can prepare an editor for the description field at the same time. This is + * designed to work when the properties are going to be used to set the default + * values of a moodle forms form. + * + * @param bool $prepareeditor If set to true a editor is prepared for use with + * the mforms editor element. (for description) + * @return stdClass Object containing event properties + */ + public function properties($prepareeditor=false) { + global $USER, $CFG, $DB; + + // First take a copy of the properties. We don't want to actually change the + // properties or we'd forever be converting back and forwards between an + // editor formatted description and not + $properties = clone($this->properties); + // Clean the description here + $properties->description = clean_text($properties->description, $properties->format); + + // If set to true we need to prepare the properties for use with an editor + // and prepare the file area + if ($prepareeditor) { + + // We may or may not have a property id. If we do then we need to work + // out the context so we can copy the existing files to the draft area + if (!empty($properties->id)) { + + if ($properties->eventtype === 'site') { + // Site context + $this->editorcontext = get_context_instance(CONTEXT_SYSTEM); + } else if ($properties->eventtype === 'user') { + // User context + $this->editorcontext = get_context_instance(CONTEXT_USER, $USER->id); + } else if ($properties->eventtype === 'group' || $properties->eventtype === 'course') { + // First check the course is valid + $course = $DB->get_record('course', array('id'=>$properties->courseid)); + if (!$course) { + print_error('invalidcourse'); + } + // Course context + $this->editorcontext = get_context_instance(CONTEXT_COURSE, $course->id); + // We have a course and are within the course context so we had + // better use the courses max bytes value + $this->editoroptions['maxbytes'] = $course->maxbytes; + } else { + // If we get here we have a custom event type as used by some + // modules. In this case the event will have been added by + // code and we won't need the editor + $this->editoroptions['maxbytes'] = 0; + $this->editoroptions['maxfiles'] = 0; + } + + if (empty($this->editorcontext) || empty($this->editorcontext->id)) { + $contextid = false; + } else { + // Get the context id that is what we really want + $contextid = $this->editorcontext->id; + } + } else { + + // If we get here then this is a new event in which case we don't need a + // context as there is no existing files to copy to the draft area. + $contextid = null; + } + + // If the contextid === false we don't support files so no preparing + // a draft area + if ($contextid !== false) { + // Just encase it has already been submitted + $draftiddescription = file_get_submitted_draft_itemid('description'); + // Prepare the draft area, this copies existing files to the draft area as well + $properties->description = file_prepare_draft_area($draftiddescription, $contextid, self::$filearea, $properties->id, $this->editoroptions, $properties->description); + } else { + $draftiddescription = 0; + } + + // Structure the description field as the editor requires + $properties->description = array('text'=>$properties->description, 'format'=>$properties->format, 'itemid'=>$draftiddescription); + } + + // Finally return the properties + return $properties; + } + + /** + * Toggles the visibility of an event + * + * @param null|bool $force If it is left null the events visibility is flipped, + * If it is false the event is made hidden, if it is true it + * is made visible. + */ + public function toggle_visibility($force=null) { + global $CFG, $DB; + + // Set visible to the default if it is not already set + if (empty($this->properties->visible)) { + $this->properties->visible = 1; + } + + if ($force === true || ($force !== false && $this->properties->visible == 0)) { + // Make this event visible + $this->properties->visible = 1; + // Fire the hook + self::calendar_event_hook('show_event', array($this->properties)); + } else { + // Make this event hidden + $this->properties->visible = 0; + // Fire the hook + self::calendar_event_hook('hide_event', array($this->properties)); + } + + // Update the database to reflect this change + return $DB->set_field('event', 'visible', $this->properties->visible, array('id'=>$this->properties->id)); + } + + /** + * Attempts to call the hook for the specified action should a calendar type + * by set $CFG->calendar, and the appopriate function defined + * + * @static + * @staticvar bool $extcalendarinc Used to track the inclusion of the calendar lib + * @param string $action One of `update_event`, `add_event`, `delete_event`, `show_event`, `hide_event` + * @param array $args The args to pass to the hook, usually the event is the first element + * @return bool + */ + public static function calendar_event_hook($action, array $args) { + global $CFG; + static $extcalendarinc; + if ($extcalendarinc === null) { + if (!empty($CFG->calendar) && file_exists($CFG->dirroot .'/calendar/'. $CFG->calendar .'/lib.php')) { + include_once($CFG->dirroot .'/calendar/'. $CFG->calendar .'/lib.php'); + $extcalendarinc = true; + } else { + $extcalendarinc = false; + } + } + if($extcalendarinc === false) { + return false; + } + $hook = $CFG->dirroot .'_'.$action; + if (function_exists($hook)) { + call_user_func_array($hook, $args); + return true; + } + return false; + } + + /** + * Returns a calendar_event object when provided with an event id + * + * This function makes use of MUST_EXIST, if the event id passed in is invalid + * it will result in an exception being thrown + * + * @param int $id + * @return calendar_event|false + */ + public static function load($id) { + global $DB; + $event = $DB->get_record('event', array('id'=>$id), '*', MUST_EXIST); + $event = new calendar_event($event); + return $event; + } + + /** + * Creates a new event and returns a calendar_event object + * + * @param object|array $properties An object containing event properties + * @return calendar_event|false The event object or false if it failed + */ + public static function create($properties) { + if (is_array($properties)) { + $properties = (object)$properties; + } + if (!is_object($properties)) { + throw new coding_exception('When creating an event properties should be either an object or an assoc array'); + } + $event = new calendar_event(); + if ($event->update($properties)) { + return $event; + } else { + return false; + } + } +} diff --git a/calendar/preferences.php b/calendar/preferences.php index b27e59951b..bd806941c7 100644 --- a/calendar/preferences.php +++ b/calendar/preferences.php @@ -77,7 +77,7 @@ echo $OUTPUT->heading($strpreferences); echo $OUTPUT->box_start('generalbox boxaligncenter'); $prefs->timeformat = get_user_preferences('calendar_timeformat', ''); -$prefs->startwday = get_user_preferences('calendar_startwday', CALENDAR_STARTING_WEEKDAY); +$prefs->startwday = get_user_preferences('calendar_startwday', calendar_get_starting_weekday()); $prefs->maxevents = get_user_preferences('calendar_maxevents', CALENDAR_UPCOMING_MAXEVENTS); $prefs->lookahead = get_user_preferences('calendar_lookahead', CALENDAR_UPCOMING_DAYS); $prefs->persistflt = get_user_preferences('calendar_persistflt', 0); diff --git a/calendar/view.php b/calendar/view.php index 2dfa38af58..e02dc60729 100644 --- a/calendar/view.php +++ b/calendar/view.php @@ -293,6 +293,7 @@ function calendar_show_day($d, $m, $y, $courses, $groups, $users, $courseid) { // First, print details about events that start today foreach ($events as $event) { + $event = new calendar_event($event); $event->calendarcourseid = $courseid; if ($event->timestart >= $starttime && $event->timestart <= $endtime) { // Print it now @@ -336,7 +337,7 @@ function calendar_show_month_detailed($m, $y, $courses, $groups, $users, $course $getvars = 'from=month&cal_d='.$day.'&cal_m='.$mon.'&cal_y='.$yr; // For filtering $display = new stdClass; - $display->minwday = get_user_preferences('calendar_startwday', CALENDAR_STARTING_WEEKDAY); + $display->minwday = get_user_preferences('calendar_startwday', calendar_get_starting_weekday()); $display->maxwday = $display->minwday + 6; if(!empty($m) && !empty($y)) { @@ -389,6 +390,7 @@ function calendar_show_month_detailed($m, $y, $courses, $groups, $users, $course $events = calendar_get_events(usertime($display->tstart), usertime($display->tend), $users, $groups, $courses); if (!empty($events)) { foreach($events as $eventid => $event) { + $event = new calendar_event($event); if (!empty($event->modulename)) { $cm = get_coursemodule_from_instance($event->modulename, $event->instance); if (!groups_course_module_visible($cm)) { @@ -617,6 +619,9 @@ function calendar_show_upcoming_events($courses, $groups, $users, $futuredays, $ echo '
'; foreach ($events as $event) { + // Convert to calendar_event object so that we transform description + // accordingly + $event = new calendar_event($event); $event->calendarcourseid = $courseid; calendar_print_event($event); } diff --git a/lang/en_utf8/calendar.php b/lang/en_utf8/calendar.php index 43928ff427..22c3d313b6 100644 --- a/lang/en_utf8/calendar.php +++ b/lang/en_utf8/calendar.php @@ -69,6 +69,8 @@ $string['groupevents'] = 'Group events'; $string['hidden'] = 'hidden'; $string['ical'] = 'iCal'; $string['iwanttoexport'] = 'Export'; +$string['invalidtimedurationuntil'] = 'The date and time you selected for duration until is before the start time of the event. Please correct this before proceeding.'; +$string['invalidtimedurationminutes'] = 'The duration in minutes you have entered in invalid please enter the duration in minutes greater than 0 or select no duration.'; $string['manyevents'] = '$a events'; $string['mon'] = 'Mon'; $string['monday'] = 'Monday'; @@ -87,8 +89,10 @@ $string['preferences'] = 'Preferences'; $string['preferences_available'] = 'Your personal preferences'; $string['quickdownloadcalendar'] = 'Quick download / subscribe to calendar'; $string['recentupcoming'] = 'Recent and next 60 days'; +$string['repeatedevents'] = 'Repeated events'; $string['repeateditall'] = 'Apply changes to all $a events in this repeat series'; $string['repeateditthis'] = 'Apply changes to this event only'; +$string['repeatevent'] = 'Repeat this event'; $string['repeatnone'] = 'No repeats'; $string['repeatweeksl'] = 'Repeat weekly, creating altogether'; $string['repeatweeksr'] = 'events'; diff --git a/lib/deprecatedlib.php b/lib/deprecatedlib.php index 04377c2040..2258612b4c 100644 --- a/lib/deprecatedlib.php +++ b/lib/deprecatedlib.php @@ -3709,3 +3709,94 @@ function navmenu($course, $cm=NULL, $targetwindow='self') { return ''; } + +/// CALENDAR MANAGEMENT //////////////////////////////////////////////////////////////// + + +/** + * Call this function to add an event to the calendar table and to call any calendar plugins + * + * @param object $event An object representing an event from the calendar table. + * The event will be identified by the id field. The object event should include the following: + *
    + *
  • $event->name - Name for the event + *
  • $event->description - Description of the event (defaults to '') + *
  • $event->format - Format for the description (using formatting types defined at the top of weblib.php) + *
  • $event->courseid - The id of the course this event belongs to (0 = all courses) + *
  • $event->groupid - The id of the group this event belongs to (0 = no group) + *
  • $event->userid - The id of the user this event belongs to (0 = no user) + *
  • $event->modulename - Name of the module that creates this event + *
  • $event->instance - Instance of the module that owns this event + *
  • $event->eventtype - The type info together with the module info could + * be used by calendar plugins to decide how to display event + *
  • $event->timestart- Timestamp for start of event + *
  • $event->timeduration - Duration (defaults to zero) + *
  • $event->visible - 0 if the event should be hidden (e.g. because the activity that created it is hidden) + *
+ * @return int|false The id number of the resulting record or false if failed + */ + function add_event($event) { + global $CFG; + require_once($CFG->dirroot.'/calendar/lib.php'); + $event = calendar_event::create($event); + if ($event !== false) { + return $event->id; + } + return false; +} + +/** + * Call this function to update an event in the calendar table + * the event will be identified by the id field of the $event object. + * + * @param object $event An object representing an event from the calendar table. The event will be identified by the id field. + * @return bool Success + */ +function update_event($event) { + global $CFG; + require_once($CFG->dirroot.'/calendar/lib.php'); + $event = (object)$event; + $calendarevent = calendar_event::load($event->id); + return $calendarevent->update($event); +} + +/** + * Call this function to delete the event with id $id from calendar table. + * + * @param int $id The id of an event from the 'event' table. + * @return bool + */ +function delete_event($id) { + global $CFG; + require_once($CFG->dirroot.'/calendar/lib.php'); + $event = calendar_event::load($id); + return $event->delete(); +} + +/** + * Call this function to hide an event in the calendar table + * the event will be identified by the id field of the $event object. + * + * @param object $event An object representing an event from the calendar table. The event will be identified by the id field. + * @return true + */ +function hide_event($event) { + global $CFG; + require_once($CFG->dirroot.'/calendar/lib.php'); + $event = new calendar_event($event); + return $event->toggle_visibility(false); +} + +/** + * Call this function to unhide an event in the calendar table + * the event will be identified by the id field of the $event object. + * + * @param object $event An object representing an event from the calendar table. The event will be identified by the id field. + * @return true + */ +function show_event($event) { + global $CFG; + require_once($CFG->dirroot.'/calendar/lib.php'); + $event = new calendar_event($event); + return $event->toggle_visibility(true); +} \ No newline at end of file diff --git a/lib/moodlelib.php b/lib/moodlelib.php index 17ce57b53d..ebd0b34922 100644 --- a/lib/moodlelib.php +++ b/lib/moodlelib.php @@ -6644,159 +6644,6 @@ function endecrypt ($pwd, $data, $case) { return $cipher; } - -/// CALENDAR MANAGEMENT //////////////////////////////////////////////////////////////// - - -/** - * Call this function to add an event to the calendar table - * and to call any calendar plugins - * - * @global object - * @global object - * @param array $event An associative array representing an event from the calendar table. - * The event will be identified by the id field. The object event should include the following: - *
    - *
  • $event->name - Name for the event - *
  • $event->description - Description of the event (defaults to '') - *
  • $event->format - Format for the description (using formatting types defined at the top of weblib.php) - *
  • $event->courseid - The id of the course this event belongs to (0 = all courses) - *
  • $event->groupid - The id of the group this event belongs to (0 = no group) - *
  • $event->userid - The id of the user this event belongs to (0 = no user) - *
  • $event->modulename - Name of the module that creates this event - *
  • $event->instance - Instance of the module that owns this event - *
  • $event->eventtype - The type info together with the module info could - * be used by calendar plugins to decide how to display event - *
  • $event->timestart- Timestamp for start of event - *
  • $event->timeduration - Duration (defaults to zero) - *
  • $event->visible - 0 if the event should be hidden (e.g. because the activity that created it is hidden) - *
- * @return mixed The id number of the resulting record or false if failed - */ - function add_event($event) { - global $CFG, $DB; - - $event->timemodified = time(); - - $event->id = $DB->insert_record('event', $event); - - if (!empty($CFG->calendar)) { // call the add_event function of the selected calendar - if (file_exists($CFG->dirroot .'/calendar/'. $CFG->calendar .'/lib.php')) { - include_once($CFG->dirroot .'/calendar/'. $CFG->calendar .'/lib.php'); - $calendar_add_event = $CFG->calendar.'_add_event'; - if (function_exists($calendar_add_event)) { - $calendar_add_event($event); - } - } - } - - return $event->id; -} - -/** - * Call this function to update an event in the calendar table - * the event will be identified by the id field of the $event object. - * - * @global object - * @global object - * @param array $event An associative array representing an event from the calendar table. The event will be identified by the id field. - * @return bool Success - */ -function update_event($event) { - global $CFG, $DB; - - $event->timemodified = time(); - - if (!empty($CFG->calendar)) { // call the update_event function of the selected calendar - if (file_exists($CFG->dirroot .'/calendar/'. $CFG->calendar .'/lib.php')) { - include_once($CFG->dirroot .'/calendar/'. $CFG->calendar .'/lib.php'); - $calendar_update_event = $CFG->calendar.'_update_event'; - if (function_exists($calendar_update_event)) { - $calendar_update_event($event); - } - } - } - return $DB->update_record('event', $event); -} - -/** - * Call this function to delete the event with id $id from calendar table. - * - * @todo Verify return type - * - * @global object - * @global object - * @param int $id The id of an event from the 'calendar' table. - * @return array An associative array with the results from the SQL call. - */ -function delete_event($id) { - global $CFG, $DB; - - if (!empty($CFG->calendar)) { // call the delete_event function of the selected calendar - if (file_exists($CFG->dirroot .'/calendar/'. $CFG->calendar .'/lib.php')) { - include_once($CFG->dirroot .'/calendar/'. $CFG->calendar .'/lib.php'); - $calendar_delete_event = $CFG->calendar.'_delete_event'; - if (function_exists($calendar_delete_event)) { - $calendar_delete_event($id); - } - } - } - return $DB->delete_records('event', array('id'=>$id)); -} - -/** - * Call this function to hide an event in the calendar table - * the event will be identified by the id field of the $event object. - * - * @todo Verify return type - * - * @global object - * @global object - * @param array $event An associative array representing an event from the calendar table. The event will be identified by the id field. - * @return array An associative array with the results from the SQL call. - */ -function hide_event($event) { - global $CFG, $DB; - - if (!empty($CFG->calendar)) { // call the update_event function of the selected calendar - if (file_exists($CFG->dirroot .'/calendar/'. $CFG->calendar .'/lib.php')) { - include_once($CFG->dirroot .'/calendar/'. $CFG->calendar .'/lib.php'); - $calendar_hide_event = $CFG->calendar.'_hide_event'; - if (function_exists($calendar_hide_event)) { - $calendar_hide_event($event); - } - } - } - return $DB->set_field('event', 'visible', 0, array('id'=>$event->id)); -} - -/** - * Call this function to unhide an event in the calendar table - * the event will be identified by the id field of the $event object. - * - * @todo Verify return type - * - * @global object - * @global object - * @param array $event An associative array representing an event from the calendar table. The event will be identified by the id field. - * @return array An associative array with the results from the SQL call. - */ -function show_event($event) { - global $CFG, $DB; - - if (!empty($CFG->calendar)) { // call the update_event function of the selected calendar - if (file_exists($CFG->dirroot .'/calendar/'. $CFG->calendar .'/lib.php')) { - include_once($CFG->dirroot .'/calendar/'. $CFG->calendar .'/lib.php'); - $calendar_show_event = $CFG->calendar.'_show_event'; - if (function_exists($calendar_show_event)) { - $calendar_show_event($event); - } - } - } - return $DB->set_field('event', 'visible', 1, array('id'=>$event->id)); -} - - /// ENVIRONMENT CHECKING //////////////////////////////////////////////////////////// /** diff --git a/pluginfile.php b/pluginfile.php index d47b5c4730..4869525c55 100644 --- a/pluginfile.php +++ b/pluginfile.php @@ -102,13 +102,61 @@ if ($context->contextlevel == CONTEXT_SYSTEM) { } send_stored_file($file, 10*60, 0, true); // download MUST be forced - security! + } else if ($filearea === 'calendar_event_description') { // CONTEXT_SYSTEM + + // All events here are public the one requirement is that we respect forcelogin + if ($CFG->forcelogin) { + require_login(); + } + + $fullpath = $context->id.$filearea.implode('/', $args); + + if (!$file = $fs->get_file_by_hash(sha1($fullpath)) or $file->is_directory()) { + send_file_not_found(); + } + + session_get_instance()->write_close(); // unlock session during fileserving + send_stored_file($file, 60*60, 0, $forcedownload); // TODO: change timeout? } else { send_file_not_found(); } - } else if ($context->contextlevel == CONTEXT_USER) { + + if ($filearea === 'calendar_event_description') { // CONTEXT_USER + + // Must be logged in, if they are not then they obviously can't be this user + require_login(); + + // Don't want guests here, potentially saves a DB call + if (isguestuser()) { + send_file_not_found(); + } + + // Get the event if from the args array + $eventid = array_shift($args); + if ((int)$eventid <= 0) { + send_file_not_found(); + } + + // Load the event from the database + $event = $DB->get_record('event', array('id'=>(int)$eventid)); + // Check that we got an event and that it's userid is that of the user + if (!$event || $event->userid !== $USER->id) { + send_file_not_found(); + } + + // Get the file and serve if succesfull + $fullpath = $context->id.$filearea.$eventid.'/'.implode('/', $args); + if (!$file = $fs->get_file_by_hash(sha1($fullpath)) or $file->is_directory()) { + send_file_not_found(); + } + + session_get_instance()->write_close(); // unlock session during fileserving + send_stored_file($file, 60*60, 0, $forcedownload); // TODO: change timeout? + } + send_file_not_found(); @@ -167,6 +215,50 @@ if ($context->contextlevel == CONTEXT_SYSTEM) { session_get_instance()->write_close(); // unlock session during fileserving send_stored_file($file, 60*60, 0, false); // TODO: change timeout? + } else if ($filearea === 'calendar_event_description') { // CONTEXT_COURSE + + // This is for content used in course and group events + + // Respect forcelogin and require login unless this is the site.... it probably + // should NEVER be the site + if ($CFG->forcelogin || $course->id !== SITEID) { + require_login($course); + } + + // Must be able to at least view the course + if (!has_capability('moodle/course:view', $context)) { + send_file_not_found(); + } + + // Get the event id + $eventid = array_shift($args); + if ((int)$eventid <= 0) { + send_file_not_found(); + } + + // Load the event from the database we need to check whether it is + // a) valid + // b) a group event + // Group events use the course context (there is no group context) + $event = $DB->get_record('event', array('id'=>(int)$eventid)); + if (!$event || $event->userid !== $USER->id) { + send_file_not_found(); + } + + // If its a group event require either membership of manage groups capability + if ($event->eventtype === 'group' && !has_capability('moodle/course:managegroups', $context) && !groups_is_member($event->groupid, $USER->id)) { + send_file_not_found(); + } + + // If we get this far we can serve the file + $fullpath = $context->id.$filearea.$eventid.'/'.implode('/', $args); + if (!$file = $fs->get_file_by_hash(sha1($fullpath)) or $file->is_directory()) { + send_file_not_found(); + } + + session_get_instance()->write_close(); // unlock session during fileserving + send_stored_file($file, 60*60, 0, $forcedownload); // TODO: change timeout? + } else if ($filearea === 'course_section') { if ($CFG->forcelogin) { require_login($course); -- 2.39.5