Skip to content

Commit

Permalink
Merge pull request #40653 from nextcloud/feat/ooo-api
Browse files Browse the repository at this point in the history
feat: Add out-of-office message API
  • Loading branch information
ChristophWurst authored Nov 9, 2023
2 parents 1aa24c0 + ab1a1d6 commit 5183ba2
Show file tree
Hide file tree
Showing 18 changed files with 942 additions and 1 deletion.
1 change: 1 addition & 0 deletions apps/dav/appinfo/routes.php
Original file line number Diff line number Diff line change
Expand Up @@ -35,5 +35,6 @@
],
'ocs' => [
['name' => 'direct#getUrl', 'url' => '/api/v1/direct', 'verb' => 'POST'],
['name' => 'out_of_office#getCurrentOutOfOfficeData', 'url' => '/api/v1/outOfOffice/{userId}', 'verb' => 'GET'],
],
];
2 changes: 2 additions & 0 deletions apps/dav/composer/composer/autoload_classmap.php
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,7 @@
'OCA\\DAV\\Controller\\BirthdayCalendarController' => $baseDir . '/../lib/Controller/BirthdayCalendarController.php',
'OCA\\DAV\\Controller\\DirectController' => $baseDir . '/../lib/Controller/DirectController.php',
'OCA\\DAV\\Controller\\InvitationResponseController' => $baseDir . '/../lib/Controller/InvitationResponseController.php',
'OCA\\DAV\\Controller\\OutOfOfficeController' => $baseDir . '/../lib/Controller/OutOfOfficeController.php',
'OCA\\DAV\\DAV\\CustomPropertiesBackend' => $baseDir . '/../lib/DAV/CustomPropertiesBackend.php',
'OCA\\DAV\\DAV\\GroupPrincipalBackend' => $baseDir . '/../lib/DAV/GroupPrincipalBackend.php',
'OCA\\DAV\\DAV\\PublicAuth' => $baseDir . '/../lib/DAV/PublicAuth.php',
Expand Down Expand Up @@ -305,6 +306,7 @@
'OCA\\DAV\\Profiler\\ProfilerPlugin' => $baseDir . '/../lib/Profiler/ProfilerPlugin.php',
'OCA\\DAV\\Provisioning\\Apple\\AppleProvisioningNode' => $baseDir . '/../lib/Provisioning/Apple/AppleProvisioningNode.php',
'OCA\\DAV\\Provisioning\\Apple\\AppleProvisioningPlugin' => $baseDir . '/../lib/Provisioning/Apple/AppleProvisioningPlugin.php',
'OCA\\DAV\\ResponseDefinitions' => $baseDir . '/../lib/ResponseDefinitions.php',
'OCA\\DAV\\RootCollection' => $baseDir . '/../lib/RootCollection.php',
'OCA\\DAV\\Search\\ACalendarSearchProvider' => $baseDir . '/../lib/Search/ACalendarSearchProvider.php',
'OCA\\DAV\\Search\\ContactsSearchProvider' => $baseDir . '/../lib/Search/ContactsSearchProvider.php',
Expand Down
2 changes: 2 additions & 0 deletions apps/dav/composer/composer/autoload_static.php
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,7 @@ class ComposerStaticInitDAV
'OCA\\DAV\\Controller\\BirthdayCalendarController' => __DIR__ . '/..' . '/../lib/Controller/BirthdayCalendarController.php',
'OCA\\DAV\\Controller\\DirectController' => __DIR__ . '/..' . '/../lib/Controller/DirectController.php',
'OCA\\DAV\\Controller\\InvitationResponseController' => __DIR__ . '/..' . '/../lib/Controller/InvitationResponseController.php',
'OCA\\DAV\\Controller\\OutOfOfficeController' => __DIR__ . '/..' . '/../lib/Controller/OutOfOfficeController.php',
'OCA\\DAV\\DAV\\CustomPropertiesBackend' => __DIR__ . '/..' . '/../lib/DAV/CustomPropertiesBackend.php',
'OCA\\DAV\\DAV\\GroupPrincipalBackend' => __DIR__ . '/..' . '/../lib/DAV/GroupPrincipalBackend.php',
'OCA\\DAV\\DAV\\PublicAuth' => __DIR__ . '/..' . '/../lib/DAV/PublicAuth.php',
Expand Down Expand Up @@ -320,6 +321,7 @@ class ComposerStaticInitDAV
'OCA\\DAV\\Profiler\\ProfilerPlugin' => __DIR__ . '/..' . '/../lib/Profiler/ProfilerPlugin.php',
'OCA\\DAV\\Provisioning\\Apple\\AppleProvisioningNode' => __DIR__ . '/..' . '/../lib/Provisioning/Apple/AppleProvisioningNode.php',
'OCA\\DAV\\Provisioning\\Apple\\AppleProvisioningPlugin' => __DIR__ . '/..' . '/../lib/Provisioning/Apple/AppleProvisioningPlugin.php',
'OCA\\DAV\\ResponseDefinitions' => __DIR__ . '/..' . '/../lib/ResponseDefinitions.php',
'OCA\\DAV\\RootCollection' => __DIR__ . '/..' . '/../lib/RootCollection.php',
'OCA\\DAV\\Search\\ACalendarSearchProvider' => __DIR__ . '/..' . '/../lib/Search/ACalendarSearchProvider.php',
'OCA\\DAV\\Search\\ContactsSearchProvider' => __DIR__ . '/..' . '/../lib/Search/ContactsSearchProvider.php',
Expand Down
78 changes: 78 additions & 0 deletions apps/dav/lib/Controller/OutOfOfficeController.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
<?php

declare(strict_types=1);

/**
* @copyright Copyright (c) 2023 Richard Steinmetz <[email protected]>
*
* @author Richard Steinmetz <[email protected]>
*
* @license AGPL-3.0-or-later
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/

namespace OCA\DAV\Controller;

use OCA\DAV\Db\AbsenceMapper;
use OCA\DAV\ResponseDefinitions;
use OCP\AppFramework\Db\DoesNotExistException;
use OCP\AppFramework\Http;
use OCP\AppFramework\Http\DataResponse;
use OCP\AppFramework\OCSController;
use OCP\IRequest;

/**
* @psalm-import-type DAVOutOfOfficeData from ResponseDefinitions
*/
class OutOfOfficeController extends OCSController {

public function __construct(
string $appName,
IRequest $request,
private AbsenceMapper $absenceMapper,
) {
parent::__construct($appName, $request);
}

/**
* Get the currently configured out-of-office data of a user.
*
* @NoAdminRequired
* @NoCSRFRequired
*
* @param string $userId The user id to get out-of-office data for.
* @return DataResponse<Http::STATUS_OK|Http::STATUS_NOT_FOUND, ?DAVOutOfOfficeData, array{}>
*
* 200: Out-of-office data
* 404: No out-of-office data was found
*/
public function getCurrentOutOfOfficeData(string $userId): DataResponse {
try {
$data = $this->absenceMapper->findByUserId($userId);
} catch (DoesNotExistException) {
return new DataResponse(null, Http::STATUS_NOT_FOUND);
}

return new DataResponse([
'id' => $data->getId(),
'userId' => $data->getUserId(),
'firstDay' => $data->getFirstDay(),
'lastDay' => $data->getLastDay(),
'status' => $data->getStatus(),
'message' => $data->getMessage(),
]);
}
}
28 changes: 28 additions & 0 deletions apps/dav/lib/Db/Absence.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,13 @@

namespace OCA\DAV\Db;

use DateTimeImmutable;
use InvalidArgumentException;
use JsonSerializable;
use OC\User\OutOfOfficeData;
use OCP\AppFramework\Db\Entity;
use OCP\IUser;
use OCP\User\IOutOfOfficeData;

/**
* @method string getUserId()
Expand All @@ -43,8 +48,13 @@
*/
class Absence extends Entity implements JsonSerializable {
protected string $userId = '';

/** Inclusive, formatted as YYYY-MM-DD */
protected string $firstDay = '';

/** Inclusive, formatted as YYYY-MM-DD */
protected string $lastDay = '';

protected string $status = '';
protected string $message = '';

Expand All @@ -56,6 +66,24 @@ public function __construct() {
$this->addType('message', 'string');
}

public function toOutOufOfficeData(IUser $user): IOutOfOfficeData {
if ($user->getUID() !== $this->getUserId()) {
throw new InvalidArgumentException("The user doesn't match the user id of this absence! Expected " . $this->getUserId() . ", got " . $user->getUID());
}

//$user = $userManager->get($this->getUserId());
$startDate = new DateTimeImmutable($this->getFirstDay());
$endDate = new DateTimeImmutable($this->getLastDay());
return new OutOfOfficeData(
(string)$this->getId(),
$user,
$startDate->getTimestamp(),
$endDate->getTimestamp(),
$this->getStatus(),
$this->getMessage(),
);
}

public function jsonSerialize(): array {
return [
'userId' => $this->userId,
Expand Down
40 changes: 40 additions & 0 deletions apps/dav/lib/ResponseDefinitions.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
<?php

declare(strict_types=1);

/**
* @copyright Copyright (c) 2023 Richard Steinmetz <[email protected]>
*
* @author Richard Steinmetz <[email protected]>
*
* @license AGPL-3.0-or-later
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/

namespace OCA\DAV;

/**
* @psalm-type DAVOutOfOfficeData = array{
* id: int,
* userId: string,
* firstDay: string,
* lastDay: string,
* status: string,
* message: string,
* }
*/
class ResponseDefinitions {
}
37 changes: 36 additions & 1 deletion apps/dav/lib/Service/AbsenceService.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,18 +26,30 @@

namespace OCA\DAV\Service;

use InvalidArgumentException;
use OCA\DAV\Db\Absence;
use OCA\DAV\Db\AbsenceMapper;
use OCP\AppFramework\Db\DoesNotExistException;
use OCP\EventDispatcher\IEventDispatcher;
use OCP\IUserManager;
use OCP\User\Events\OutOfOfficeChangedEvent;
use OCP\User\Events\OutOfOfficeClearedEvent;
use OCP\User\Events\OutOfOfficeScheduledEvent;

class AbsenceService {
public function __construct(
private AbsenceMapper $absenceMapper,
private IEventDispatcher $eventDispatcher,
private IUserManager $userManager,
) {
}

/**
* @param string $firstDay The first day (inclusive) of the absence formatted as YYYY-MM-DD.
* @param string $lastDay The last day (inclusive) of the absence formatted as YYYY-MM-DD.
*
* @throws \OCP\DB\Exception
* @throws InvalidArgumentException If no user with the given user id exists.
*/
public function createOrUpdateAbsence(
string $userId,
Expand All @@ -58,17 +70,40 @@ public function createOrUpdateAbsence(
$absence->setStatus($status);
$absence->setMessage($message);

// TODO: this method should probably just take a IUser instance
$user = $this->userManager->get($userId);
if ($user === null) {
throw new InvalidArgumentException("User $userId does not exist");
}
$eventData = $absence->toOutOufOfficeData($user);

if ($absence->getId() === null) {
$this->eventDispatcher->dispatchTyped(new OutOfOfficeScheduledEvent($eventData));
return $this->absenceMapper->insert($absence);
}

$this->eventDispatcher->dispatchTyped(new OutOfOfficeChangedEvent($eventData));
return $this->absenceMapper->update($absence);
}

/**
* @throws \OCP\DB\Exception
*/
public function clearAbsence(string $userId): void {
$this->absenceMapper->deleteByUserId($userId);
try {
$absence = $this->absenceMapper->findByUserId($userId);
} catch (DoesNotExistException $e) {
// Nothing to clear
return;
}
$this->absenceMapper->delete($absence);
// TODO: this method should probably just take a IUser instance
$user = $this->userManager->get($userId);
if ($user === null) {
throw new InvalidArgumentException("User $userId does not exist");
}
$eventData = $absence->toOutOufOfficeData($user);
$this->eventDispatcher->dispatchTyped(new OutOfOfficeClearedEvent($eventData));
}
}

Loading

0 comments on commit 5183ba2

Please sign in to comment.