218 lines
6.9 KiB
PHP
218 lines
6.9 KiB
PHP
<?php
|
|
|
|
/**
|
|
* Nextcloud API for the Calendar plugin.
|
|
*
|
|
* @author Aleksander Machniak <machniak@apheleia-it.ch>
|
|
*
|
|
* Copyright (C) Apheleia IT AG <contact@apheleia-it.ch>
|
|
*
|
|
* This program is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU Affero General Public License as
|
|
* published by the Free Software Foundation, either version 3 of the
|
|
* License, or (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU Affero General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Affero General Public License
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
class calendar_nextcloud_api
|
|
{
|
|
|
|
const PARTICIPANT_OWNER = 1;
|
|
const PARTICIPANT_MODERATOR = 2;
|
|
const PARTICIPANT_USER = 3;
|
|
const PARTICIPANT_GUEST = 4;
|
|
const PARTICIPANT_PUBLIC = 5;
|
|
const PARTICIPANT_GUEST_MODERATOR = 6;
|
|
|
|
|
|
/**
|
|
* Make a request to the Nextcloud API
|
|
*
|
|
* @return false|array Response data or False on failure
|
|
*/
|
|
protected function request($path, $method = 'GET', $params = [])
|
|
{
|
|
$rcmail = rcube::get_instance();
|
|
|
|
$url = unslashify($rcmail->config->get('calendar_nextcloud_url'));
|
|
$url .= "/ocs/v2.php/$path";
|
|
|
|
try {
|
|
$request_config = [
|
|
'store_body' => true,
|
|
'follow_redirects' => true,
|
|
];
|
|
|
|
$request = libkolab::http_request($url, $method, $request_config);
|
|
|
|
// Authentication
|
|
$request->setAuth(
|
|
$rcmail->user->get_username(),
|
|
$rcmail->decrypt($_SESSION['password'])
|
|
);
|
|
|
|
// Disable CSRF prevention, and enable JSON responses
|
|
$request->setHeader([
|
|
'OCS-APIRequest' => 'true',
|
|
'Accept' => 'application/json',
|
|
]);
|
|
|
|
if (!empty($params)) {
|
|
if ($method == 'POST') {
|
|
$request->addPostParameter($params);
|
|
}
|
|
else {
|
|
$request->setUrl($url . '?' . http_build_query($params));
|
|
}
|
|
}
|
|
|
|
// rcube::console($method . ": " . (string) $request->getUrl());
|
|
|
|
// Send the request
|
|
$response = $request->send();
|
|
|
|
$body = $response->getBody();
|
|
$code = $response->getStatus();
|
|
|
|
// rcube::console($code, $body);
|
|
|
|
if ($code < 400) {
|
|
return json_decode($body, true);
|
|
}
|
|
|
|
if (strpos($body, '<?xml') === 0) {
|
|
$doc = new DOMDocument();
|
|
$doc->loadXML($body);
|
|
$code = $doc->getElementsByTagName('statuscode')->item(0)->textContent;
|
|
$msg = $doc->getElementsByTagName('message')->item(0)->textContent;
|
|
}
|
|
else {
|
|
$msg = 'Unknown error';
|
|
}
|
|
|
|
throw new Exception("Nextcloud API Error: [$code] $msg");
|
|
}
|
|
catch (Exception $e) {
|
|
rcube::raise_error($e, true, false);
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Find user by email address
|
|
*/
|
|
protected function findUserByEmail($email)
|
|
{
|
|
$email = strtolower($email);
|
|
$params = [
|
|
'search' => $email,
|
|
'itemType' => 'call',
|
|
'itemId' => ' ',
|
|
'shareTypes' => [0, 1, 7, 4],
|
|
];
|
|
|
|
// FIXME: Is this the only way to find a user by his email address?
|
|
$response = $this->request("core/autocomplete/get", 'GET', $params);
|
|
|
|
if (!empty($response['ocs']['data'])) {
|
|
foreach ($response['ocs']['data'] as $user) {
|
|
// FIXME: This is the only field that contains email address?
|
|
// Note: A Nextcloud contact (the "emails" source) will have an email address in
|
|
// the 'id' attribute instead in 'shareWithDisplayNameUnique'.
|
|
// Another option might be to parse 'label' attribute
|
|
if (strtolower($user['shareWithDisplayNameUnique']) == $email) {
|
|
return $user;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Create a Talk room
|
|
*
|
|
* @param string $name Room name
|
|
*
|
|
* @return string|false Room URL
|
|
*/
|
|
public function talk_room_create($name = '')
|
|
{
|
|
$rcmail = rcube::get_instance();
|
|
|
|
$params = [
|
|
'roomType' => 3,
|
|
'roomName' => $name ?: $rcmail->gettext('calendar.talkroomname'),
|
|
];
|
|
|
|
$response = $this->request('apps/spreed/api/v4/room', 'POST', $params);
|
|
|
|
if (is_array($response) && !empty($response['ocs']['data']['token'])) {
|
|
$token = $response['ocs']['data']['token'];
|
|
$url = unslashify($rcmail->config->get('calendar_nextcloud_url'));
|
|
|
|
return $url . '/call/' . $token;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Update a Talk room
|
|
*
|
|
* @param string $room Room ID (or url)
|
|
* @param array $participants Room participants' email addresses (extept the owner)
|
|
*
|
|
* @return bool
|
|
*/
|
|
public function talk_room_update($room = '', $participants = [])
|
|
{
|
|
if (preg_match('|https?://|', $room)) {
|
|
$arr = explode('/', $room);
|
|
$room = $arr[count($arr) - 1];
|
|
}
|
|
|
|
// Get existing room participants
|
|
$response = $this->request("apps/spreed/api/v4/room/{$room}/participants", 'GET');
|
|
|
|
if ($response === false) {
|
|
return false;
|
|
}
|
|
|
|
$attendees = [];
|
|
foreach ($response['ocs']['data'] as $attendee) {
|
|
if ($attendee['participantType'] != self::PARTICIPANT_OWNER) {
|
|
$attendees[$attendee['actorId']] = $attendee['attendeeId'];
|
|
}
|
|
}
|
|
|
|
foreach ($participants as $email) {
|
|
if ($user = $this->findUserByEmail($email)) {
|
|
// Participant already exists, skip
|
|
// Note: We're dealing with 'users' source here for now, 'emails' source
|
|
// will have an email address in 'actorId'
|
|
if (isset($attendees[$user['id']])) {
|
|
unset($attendees[$user['id']]);
|
|
continue;
|
|
}
|
|
|
|
// Register the participant
|
|
$params = ['newParticipant' => $user['id'], 'source' => $user['source']];
|
|
$response = $this->request("apps/spreed/api/v4/room/{$room}/participants", 'POST', $params);
|
|
}
|
|
}
|
|
|
|
// Remove participants not in the event anymore
|
|
foreach ($attendees as $attendeeId) {
|
|
$params = ['attendeeId' => $attendeeId];
|
|
$response = $this->request("apps/spreed/api/v4/room/{$room}/attendees", 'DELETE', $params);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
}
|