/** * Returns the ICAL data for a facetoface meeting. * * @param integer $method The method, @see {{MDL_F2F_INVITE}} * @return stdClass Object that contains a filename in dataroot directory and ical template */ function facetoface_get_ical_attachment($method, $facetoface, $session, $user) { global $CFG, $DB; // Get user object if only id is given $user = (is_object($user) ? $user : $DB->get_record('user', array('id' => $user))); // First, generate all the VEVENT blocks $VEVENTS = ''; foreach ($session->sessiondates as $date) { // Date that this representation of the calendar information was created - // we use the time the session was created // http://www.kanzaki.com/docs/ical/dtstamp.html $DTSTAMP = facetoface_ical_generate_timestamp($session->timecreated); // UIDs should be globally unique $urlbits = parse_url($CFG->wwwroot); $sql = "SELECT COUNT(*) FROM {facetoface_signups} su INNER JOIN {facetoface_signups_status} sus ON su.id = sus.signupid WHERE su.userid = ? AND su.sessionid = ? AND sus.superceded = 1 AND sus.statuscode = ? "; $params = array($user->id, $session->id, MDL_F2F_STATUS_USER_CANCELLED); $UID = $DTSTAMP . '-' . substr(md5($CFG->siteidentifier . $session->id . $date->id), -8) . // Unique identifier, salted with site identifier '-' . $DB->count_records_sql($sql, $params) . // New UID if this is a re-signup ;) '@' . $urlbits['host']; // Hostname for this moodle installation $DTSTART = facetoface_ical_generate_timestamp($date->timestart); $DTEND = facetoface_ical_generate_timestamp($date->timefinish); // FIXME: currently we are not sending updates if the times of the // sesion are changed. This is not ideal! $SEQUENCE = ($method & MDL_F2F_CANCEL) ? 1 : 0; $SUMMARY = str_replace("\\n", "\\n ", facetoface_ical_escape($facetoface->name, true)); $icaldescription = get_string('icaldescription', 'facetoface', $facetoface); if (!empty($session->details)) { $icaldescription .= $session->details; } $DESCRIPTION = facetoface_ical_escape($icaldescription, true); // Get the location data from custom fields if they exist $room = facetoface_get_session_room($session->id); $locationstring = ''; if (!empty($room->name)) { $locationstring .= $room->name; } if (!empty($room->building)) { if (!empty($locationstring)) { $locationstring .= "\n"; } $locationstring .= $room->building; } if (!empty($room->address)) { if (!empty($locationstring)) { $locationstring .= "\n"; } $locationstring .= $room->address; } // NOTE: Newlines are meant to be encoded with the literal sequence // '\n'. But evolution presents a single line text field for location, // and shows the newlines as [0x0A] junk. So we switch it for commas // here. Remember commas need to be escaped too. $LOCATION = str_replace('\n', '\, ', facetoface_ical_escape($locationstring)); $ORGANISEREMAIL = get_config(NULL, 'facetoface_fromaddress'); $ROLE = 'REQ-PARTICIPANT'; $CANCELSTATUS = ''; if ($method & MDL_F2F_CANCEL) { $ROLE = 'NON-PARTICIPANT'; $CANCELSTATUS = "\nSTATUS:CANCELLED"; } $icalmethod = ($method & MDL_F2F_INVITE) ? 'REQUEST' : 'CANCEL'; // FIXME: if the user has input their name in another language, we need // to set the LANGUAGE property parameter here $USERNAME = fullname($user); $MAILTO = $user->email; $VEVENTS .= "BEGIN:VEVENT\r\n"; $VEVENTS .= "ORGANIZER;CN={$ORGANISEREMAIL}:MAILTO:{$ORGANISEREMAIL}\r\n"; $VEVENTS .= "DTSTART:{$DTSTART}\r\n"; $VEVENTS .= "DTEND:{$DTEND}\r\n"; $VEVENTS .= "LOCATION:{$LOCATION}\r\n"; $VEVENTS .= "TRANSP:OPAQUE{$CANCELSTATUS}\r\n"; $VEVENTS .= "SEQUENCE:{$SEQUENCE}\r\n"; $VEVENTS .= "UID:{$UID}\r\n"; $VEVENTS .= "DTSTAMP:{$DTSTAMP}\r\n"; $VEVENTS .= "DESCRIPTION:{$DESCRIPTION}\r\n"; $VEVENTS .= "SUMMARY:{$SUMMARY}\r\n"; $VEVENTS .= "PRIORITY:5\r\n"; $VEVENTS .= "CLASS:PUBLIC\r\n"; $VEVENTS .= "ATTENDEE;CUTYPE=INDIVIDUAL;ROLE={$ROLE};PARTSTAT=NEEDS-ACTION;\r\n"; $VEVENTS .= " RSVP=FALSE;CN={$USERNAME};LANGUAGE=en:MAILTO:{$MAILTO}\r\n"; $VEVENTS .= "END:VEVENT\r\n"; } $template = "BEGIN:VCALENDAR\r\n"; $template .= "VERSION:2.0\r\n"; $template .= "PRODID:-//Moodle//NONSGML Facetoface//EN\r\n"; $template .= "METHOD:{$icalmethod}\r\n"; $template .= "{$VEVENTS}"; $template .= "END:VCALENDAR\r\n"; $tempfilename = md5($template); $tempfilepathname = $CFG->dataroot . '/' . $tempfilename; file_put_contents($tempfilepathname, $template); $ical = new stdClass(); $ical->file = $tempfilename; $ical->content = $template; return $ical; }
/** * Returns the ICAL data for a facetoface meeting. * * @param integer $method The method, @see {{MDL_F2F_INVITE}} * @param object $facetoface A face-to-face object containing activity details * @param object $session A session object containing session details * @return string Filename of the attachment in the temp directory */ function facetoface_get_ical_attachment($method, $facetoface, $session, $user) { global $CFG, $DB; // First, generate all the VEVENT blocks. $VEVENTS = ''; foreach ($session->sessiondates as $date) { /* * Date that this representation of the calendar information was created - * we use the time the session was created * http://www.kanzaki.com/docs/ical/dtstamp.html */ $DTSTAMP = facetoface_ical_generate_timestamp($session->timecreated); // UIDs should be globally unique. $urlbits = parse_url($CFG->wwwroot); $sql = "SELECT COUNT(*)\n FROM {facetoface_signups} su\n INNER JOIN {facetoface_signups_status} sus ON su.id = sus.signupid\n WHERE su.userid = ?\n AND su.sessionid = ?\n AND sus.superceded = 1\n AND sus.statuscode = ? "; $params = array($user->id, $session->id, MDL_F2F_STATUS_USER_CANCELLED); $UID = $DTSTAMP . '-' . substr(md5($CFG->siteidentifier . $session->id . $date->id), -8) . '-' . $DB->count_records_sql($sql, $params) . '@' . $urlbits['host']; // Hostname for this moodle installation. $DTSTART = facetoface_ical_generate_timestamp($date->timestart); $DTEND = facetoface_ical_generate_timestamp($date->timefinish); // FIXME: currently we are not sending updates if the times of the session are changed. This is not ideal! $SEQUENCE = $method & MDL_F2F_CANCEL ? 1 : 0; $SUMMARY = facetoface_ical_escape($facetoface->name); $DESCRIPTION = facetoface_ical_escape($session->details, true); // Get the location data from custom fields if they exist. $customfielddata = facetoface_get_customfielddata($session->id); $locationstring = ''; if (!empty($customfielddata['room'])) { $locationstring .= $customfielddata['room']->data; } if (!empty($customfielddata['venue'])) { if (!empty($locationstring)) { $locationstring .= "\n"; } $locationstring .= $customfielddata['venue']->data; } if (!empty($customfielddata['location'])) { if (!empty($locationstring)) { $locationstring .= "\n"; } $locationstring .= $customfielddata['location']->data; } /* * NOTE: Newlines are meant to be encoded with the literal sequence * '\n'. But evolution presents a single line text field for location, * and shows the newlines as [0x0A] junk. So we switch it for commas * here. Remember commas need to be escaped too. */ $LOCATION = str_replace('\\n', '\\, ', facetoface_ical_escape($locationstring)); $ORGANISEREMAIL = get_config(null, 'facetoface_fromaddress'); $ROLE = 'REQ-PARTICIPANT'; $CANCELSTATUS = ''; if ($method & MDL_F2F_CANCEL) { $ROLE = 'NON-PARTICIPANT'; $CANCELSTATUS = "\nSTATUS:CANCELLED"; } $icalmethod = $method & MDL_F2F_INVITE ? 'REQUEST' : 'CANCEL'; // FIXME: if the user has input their name in another language, we need to set the LANGUAGE property parameter here. $USERNAME = fullname($user); $MAILTO = $user->email; // The extra newline at the bottom is so multiple events start on their own lines. The very last one is trimmed outside the loop. $VEVENTS .= <<<EOF BEGIN:VEVENT UID:{$UID} DTSTAMP:{$DTSTAMP} DTSTART:{$DTSTART} DTEND:{$DTEND} SEQUENCE:{$SEQUENCE} SUMMARY:{$SUMMARY} LOCATION:{$LOCATION} DESCRIPTION:{$DESCRIPTION} CLASS:PRIVATE TRANSP:OPAQUE{$CANCELSTATUS} ORGANIZER;CN={$ORGANISEREMAIL}:MAILTO:{$ORGANISEREMAIL} ATTENDEE;CUTYPE=INDIVIDUAL;ROLE={$ROLE};PARTSTAT=NEEDS-ACTION; RSVP=FALSE;CN={$USERNAME};LANGUAGE=en:MAILTO:{$MAILTO} END:VEVENT EOF; } $VEVENTS = trim($VEVENTS); // TODO: remove the hard-coded timezone!. $template = <<<EOF BEGIN:VCALENDAR CALSCALE:GREGORIAN PRODID:-//Moodle//NONSGML Facetoface//EN VERSION:2.0 METHOD:{$icalmethod} BEGIN:VTIMEZONE TZID:/softwarestudio.org/Tzfile/Pacific/Auckland X-LIC-LOCATION:Pacific/Auckland BEGIN:STANDARD TZNAME:NZST DTSTART:19700405T020000 RRULE:FREQ=YEARLY;INTERVAL=1;BYDAY=1SU;BYMONTH=4 TZOFFSETFROM:+1300 TZOFFSETTO:+1200 END:STANDARD BEGIN:DAYLIGHT TZNAME:NZDT DTSTART:19700928T030000 RRULE:FREQ=YEARLY;INTERVAL=1;BYDAY=-1SU;BYMONTH=9 TZOFFSETFROM:+1200 TZOFFSETTO:+1300 END:DAYLIGHT END:VTIMEZONE {$VEVENTS} END:VCALENDAR EOF; $tempfilename = md5($template); $tempfilepathname = $CFG->dataroot . '/' . $tempfilename; file_put_contents($tempfilepathname, $template); return $tempfilename; }
function test_facetoface_ical_generate_timestamp() { // Test variables. $timenow = time(); $return = gmdate("Ymd\THis\Z", $timenow); //TODO check if this is the correct return value to compare // Test for valid case. $this->assertEquals(facetoface_ical_generate_timestamp($timenow), $return); $this->resetAfterTest(true); }