<?php
class CourseBackend_HisInOne extends CourseBackend
{
private $location;
private $verifyHostname = true;
private $verifyCert = true;
/**
* @var bool|resource
*/
private $curlHandle = false;
public function setCredentialsInternal($data)
{
if (empty($data['baseUrl'])) {
$this->addError("No url is given", true);
return false;
}
$this->location = $this->mangleProperty('baseUrl', $data['baseUrl']);
$this->verifyHostname = $data['verifyHostname'];
$this->verifyCert = $data['verifyCert'];
return true;
}
public function getCredentialDefinitions()
{
return [
new BackendProperty('baseUrl', 'string'),
new BackendProperty('verifyCert', 'bool', true),
new BackendProperty('verifyHostname', 'bool', true)
];
}
public function mangleProperty($prop, $value)
{
if ($prop === 'baseUrl') {
// Update form SOAP to iCal url
if (preg_match(',^(http.*?)/qisserver,', $value, $out)) {
$value = $out[1] . '/qisserver/pages/cm/exa/timetable/roomScheduleCalendarExport.faces?roomId=';
} elseif (preg_match(',(.*[/=])\d*$', $value, $out)) {
$value = $out[1];
} elseif (substr_count($value, '/') <= 3) {
if (substr($value, -1) !== '/') {
$value .= '/';
}
$value .= 'qisserver/pages/cm/exa/timetable/roomScheduleCalendarExport.faces?roomId=';
}
}
return $value;
}
public function checkConnection()
{
if (empty($this->location)) {
$this->addError("Credentials are not set", true);
return false;
}
// Unfortunately HisInOne returns an internal server error if you pass an invalid roomId.
// So we just try a bunch and see if anything works. Even if this fails, using
// the backend should work, given the URL is actually correct.
foreach ([60, 100, 5, 10, 50, 110, 200, 210, 250, 300, 333, 500, 1000, 2000] as $roomId) {
if ($this->downloadIcal($roomId) !== null)
return true;
}
return false;
}
/**
* @param int $roomId room id
* @return ICalEvent[]|null all events for this room in the range -7 days to +7 days, or NULL on error
*/
private function downloadIcal($roomId)
{
if ($this->curlHandle === false) {
$this->curlHandle = curl_init();
}
$ical = new ICalParser(['filterDaysBefore' => 7, 'filterDaysAfter' => 7]);
$options = array(
CURLOPT_WRITEFUNCTION => function ($ch, $data) use ($ical) {
$ical->feedData($data);
return strlen($data);
},
CURLOPT_FOLLOWLOCATION => true,
CURLOPT_SSL_VERIFYHOST => $this->verifyHostname ? 2 : 0,
CURLOPT_SSL_VERIFYPEER => $this->verifyCert ? 1 : 0,
CURLOPT_URL => $this->location . $roomId,
CURLOPT_TIMEOUT => 60,
CURLOPT_CONNECTTIMEOUT => 4,
);
curl_setopt_array($this->curlHandle, $options);
if (!curl_exec($this->curlHandle)) {
$this->addError('Curl error: ' . curl_error($this->curlHandle), false);
}
$ical->finish();
if (!$ical->isValid()) {
error_log('Did not find a VCALENDAR in returned data');
return null;
}
return $ical->events();
}
public function getCacheTime()
{
return 30 * 60;
}
public function getRefreshTime()
{
return 60 * 60;
}
public function getDisplayName()
{
return "HisInOne";
}
public function fetchSchedulesInternal($requestedRoomIds)
{
if (empty($requestedRoomIds)) {
return array();
}
$tTables = [];
foreach ($requestedRoomIds as $roomId) {
$data = $this->downloadIcal($roomId);
if ($data === null) {
$this->addError("Downloading ical for $roomId failed", false);
continue;
}
foreach ($data as $event) {
$tTables[$roomId][] = array(
'title' => $this->toTitle($event),
'start' => $event->dtstart,
'end' => $event->dtend,
'cancelled' => false, // ??? How
);
}
}
return $tTables;
}
/**
* Get a usable title from either SUMMARY or DESCRIPTION
* @param ICalEvent $event
*/
private function toTitle($event)
{
$title = $event->summary;
if (empty($title)) {
$title = $event->description;
}
if (empty($title)) {
$title = 'Unknown';
}
return preg_replace([',(\s*<br\s*/?>\s*|\r|\n|\\\r|\\\n)+,', '/\\\\([,;:])/'], ["\n", '$1'], $title);
}
public function __destruct()
{
if ($this->curlHandle !== false) {
curl_close($this->curlHandle);
}
}
}