Skip to content

Commit d9f231b

Browse files
ChristophWurstst3iny
authored andcommitted
feat: Add out-of-office message API
[skipci] Signed-off-by: Christoph Wurst <christoph@winzerhof-wurst.at> Signed-off-by: Richard Steinmetz <richard@steinmetz.cloud>
1 parent 1acc7c0 commit d9f231b

20 files changed

+1013
-1
lines changed

apps/dav/appinfo/routes.php

+1
Original file line numberDiff line numberDiff line change
@@ -35,5 +35,6 @@
3535
],
3636
'ocs' => [
3737
['name' => 'direct#getUrl', 'url' => '/api/v1/direct', 'verb' => 'POST'],
38+
['name' => 'out_of_office#getCurrentOutOfOfficeData', 'url' => '/api/v1/outOfOffice/{userId}', 'verb' => 'GET'],
3839
],
3940
];

apps/dav/composer/composer/autoload_classmap.php

+2
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,7 @@
192192
'OCA\\DAV\\Controller\\BirthdayCalendarController' => $baseDir . '/../lib/Controller/BirthdayCalendarController.php',
193193
'OCA\\DAV\\Controller\\DirectController' => $baseDir . '/../lib/Controller/DirectController.php',
194194
'OCA\\DAV\\Controller\\InvitationResponseController' => $baseDir . '/../lib/Controller/InvitationResponseController.php',
195+
'OCA\\DAV\\Controller\\OutOfOfficeController' => $baseDir . '/../lib/Controller/OutOfOfficeController.php',
195196
'OCA\\DAV\\DAV\\CustomPropertiesBackend' => $baseDir . '/../lib/DAV/CustomPropertiesBackend.php',
196197
'OCA\\DAV\\DAV\\GroupPrincipalBackend' => $baseDir . '/../lib/DAV/GroupPrincipalBackend.php',
197198
'OCA\\DAV\\DAV\\PublicAuth' => $baseDir . '/../lib/DAV/PublicAuth.php',
@@ -305,6 +306,7 @@
305306
'OCA\\DAV\\Profiler\\ProfilerPlugin' => $baseDir . '/../lib/Profiler/ProfilerPlugin.php',
306307
'OCA\\DAV\\Provisioning\\Apple\\AppleProvisioningNode' => $baseDir . '/../lib/Provisioning/Apple/AppleProvisioningNode.php',
307308
'OCA\\DAV\\Provisioning\\Apple\\AppleProvisioningPlugin' => $baseDir . '/../lib/Provisioning/Apple/AppleProvisioningPlugin.php',
309+
'OCA\\DAV\\ResponseDefinitions' => $baseDir . '/../lib/ResponseDefinitions.php',
308310
'OCA\\DAV\\RootCollection' => $baseDir . '/../lib/RootCollection.php',
309311
'OCA\\DAV\\Search\\ACalendarSearchProvider' => $baseDir . '/../lib/Search/ACalendarSearchProvider.php',
310312
'OCA\\DAV\\Search\\ContactsSearchProvider' => $baseDir . '/../lib/Search/ContactsSearchProvider.php',

apps/dav/composer/composer/autoload_static.php

+2
Original file line numberDiff line numberDiff line change
@@ -207,6 +207,7 @@ class ComposerStaticInitDAV
207207
'OCA\\DAV\\Controller\\BirthdayCalendarController' => __DIR__ . '/..' . '/../lib/Controller/BirthdayCalendarController.php',
208208
'OCA\\DAV\\Controller\\DirectController' => __DIR__ . '/..' . '/../lib/Controller/DirectController.php',
209209
'OCA\\DAV\\Controller\\InvitationResponseController' => __DIR__ . '/..' . '/../lib/Controller/InvitationResponseController.php',
210+
'OCA\\DAV\\Controller\\OutOfOfficeController' => __DIR__ . '/..' . '/../lib/Controller/OutOfOfficeController.php',
210211
'OCA\\DAV\\DAV\\CustomPropertiesBackend' => __DIR__ . '/..' . '/../lib/DAV/CustomPropertiesBackend.php',
211212
'OCA\\DAV\\DAV\\GroupPrincipalBackend' => __DIR__ . '/..' . '/../lib/DAV/GroupPrincipalBackend.php',
212213
'OCA\\DAV\\DAV\\PublicAuth' => __DIR__ . '/..' . '/../lib/DAV/PublicAuth.php',
@@ -320,6 +321,7 @@ class ComposerStaticInitDAV
320321
'OCA\\DAV\\Profiler\\ProfilerPlugin' => __DIR__ . '/..' . '/../lib/Profiler/ProfilerPlugin.php',
321322
'OCA\\DAV\\Provisioning\\Apple\\AppleProvisioningNode' => __DIR__ . '/..' . '/../lib/Provisioning/Apple/AppleProvisioningNode.php',
322323
'OCA\\DAV\\Provisioning\\Apple\\AppleProvisioningPlugin' => __DIR__ . '/..' . '/../lib/Provisioning/Apple/AppleProvisioningPlugin.php',
324+
'OCA\\DAV\\ResponseDefinitions' => __DIR__ . '/..' . '/../lib/ResponseDefinitions.php',
323325
'OCA\\DAV\\RootCollection' => __DIR__ . '/..' . '/../lib/RootCollection.php',
324326
'OCA\\DAV\\Search\\ACalendarSearchProvider' => __DIR__ . '/..' . '/../lib/Search/ACalendarSearchProvider.php',
325327
'OCA\\DAV\\Search\\ContactsSearchProvider' => __DIR__ . '/..' . '/../lib/Search/ContactsSearchProvider.php',
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
/**
6+
* @copyright Copyright (c) 2023 Richard Steinmetz <richard@steinmetz.cloud>
7+
*
8+
* @author Richard Steinmetz <richard@steinmetz.cloud>
9+
*
10+
* @license AGPL-3.0-or-later
11+
*
12+
* This program is free software: you can redistribute it and/or modify
13+
* it under the terms of the GNU General Public License as published by
14+
* the Free Software Foundation, either version 3 of the License, or
15+
* (at your option) any later version.
16+
*
17+
* This program is distributed in the hope that it will be useful,
18+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
19+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20+
* GNU General Public License for more details.
21+
*
22+
* You should have received a copy of the GNU General Public License
23+
* along with this program. If not, see <http://www.gnu.org/licenses/>.
24+
*
25+
*/
26+
27+
namespace OCA\DAV\Controller;
28+
29+
use OCA\DAV\Db\AbsenceMapper;
30+
use OCA\DAV\ResponseDefinitions;
31+
use OCP\AppFramework\Db\DoesNotExistException;
32+
use OCP\AppFramework\Http;
33+
use OCP\AppFramework\Http\DataResponse;
34+
use OCP\AppFramework\OCSController;
35+
use OCP\IRequest;
36+
37+
/**
38+
* @psalm-import-type DAVOutOfOfficeData from ResponseDefinitions
39+
*/
40+
class OutOfOfficeController extends OCSController {
41+
42+
public function __construct(
43+
string $appName,
44+
IRequest $request,
45+
private AbsenceMapper $absenceMapper,
46+
) {
47+
parent::__construct($appName, $request);
48+
}
49+
50+
/**
51+
* Get the currently configured out-of-office data of a user.
52+
*
53+
* @NoAdminRequired
54+
* @NoCSRFRequired
55+
*
56+
* @param string $userId The user id to get out-of-office data for.
57+
* @return DataResponse<Http::STATUS_OK|Http::STATUS_NOT_FOUND, ?DAVOutOfOfficeData, array{}>
58+
*
59+
* 200: Out-of-office data
60+
* 404: No out-of-office data was found
61+
*/
62+
public function getCurrentOutOfOfficeData(string $userId): DataResponse {
63+
try {
64+
$data = $this->absenceMapper->findByUserId($userId);
65+
} catch (DoesNotExistException) {
66+
return new DataResponse(null, Http::STATUS_NOT_FOUND);
67+
}
68+
69+
return new DataResponse([
70+
'id' => $data->getId(),
71+
'userId' => $data->getUserId(),
72+
'firstDay' => $data->getFirstDay(),
73+
'lastDay' => $data->getLastDay(),
74+
'status' => $data->getStatus(),
75+
'message' => $data->getMessage(),
76+
]);
77+
}
78+
}

apps/dav/lib/Db/Absence.php

+28
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,13 @@
2626

2727
namespace OCA\DAV\Db;
2828

29+
use DateTimeImmutable;
30+
use InvalidArgumentException;
2931
use JsonSerializable;
32+
use OC\User\OutOfOfficeData;
3033
use OCP\AppFramework\Db\Entity;
34+
use OCP\IUser;
35+
use OCP\User\IOutOfOfficeData;
3136

3237
/**
3338
* @method string getUserId()
@@ -43,8 +48,13 @@
4348
*/
4449
class Absence extends Entity implements JsonSerializable {
4550
protected string $userId = '';
51+
52+
/** Inclusive, formatted as YYYY-MM-DD */
4653
protected string $firstDay = '';
54+
55+
/** Inclusive, formatted as YYYY-MM-DD */
4756
protected string $lastDay = '';
57+
4858
protected string $status = '';
4959
protected string $message = '';
5060

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

69+
public function toOutOufOfficeData(IUser $user): IOutOfOfficeData {
70+
if ($user->getUID() !== $this->getUserId()) {
71+
throw new InvalidArgumentException("The user doesn't match the user id of this absence! Expected " . $this->getUserId() . ", got " . $user->getUID());
72+
}
73+
74+
//$user = $userManager->get($this->getUserId());
75+
$startDate = new DateTimeImmutable($this->getFirstDay());
76+
$endDate = new DateTimeImmutable($this->getLastDay());
77+
return new OutOfOfficeData(
78+
(string)$this->getId(),
79+
$user,
80+
$startDate->getTimestamp(),
81+
$endDate->getTimestamp(),
82+
$this->getStatus(),
83+
$this->getMessage(),
84+
);
85+
}
86+
5987
public function jsonSerialize(): array {
6088
return [
6189
'userId' => $this->userId,

apps/dav/lib/ResponseDefinitions.php

+40
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
/**
6+
* @copyright Copyright (c) 2023 Richard Steinmetz <richard@steinmetz.cloud>
7+
*
8+
* @author Richard Steinmetz <richard@steinmetz.cloud>
9+
*
10+
* @license AGPL-3.0-or-later
11+
*
12+
* This program is free software: you can redistribute it and/or modify
13+
* it under the terms of the GNU General Public License as published by
14+
* the Free Software Foundation, either version 3 of the License, or
15+
* (at your option) any later version.
16+
*
17+
* This program is distributed in the hope that it will be useful,
18+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
19+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20+
* GNU General Public License for more details.
21+
*
22+
* You should have received a copy of the GNU General Public License
23+
* along with this program. If not, see <http://www.gnu.org/licenses/>.
24+
*
25+
*/
26+
27+
namespace OCA\DAV;
28+
29+
/**
30+
* @psalm-type DAVOutOfOfficeData = array{
31+
* id: int,
32+
* userId: string,
33+
* firstDay: string,
34+
* lastDay: string,
35+
* status: string,
36+
* message: string,
37+
* }
38+
*/
39+
class ResponseDefinitions {
40+
}

apps/dav/lib/Service/AbsenceService.php

+36-1
Original file line numberDiff line numberDiff line change
@@ -26,18 +26,30 @@
2626

2727
namespace OCA\DAV\Service;
2828

29+
use InvalidArgumentException;
2930
use OCA\DAV\Db\Absence;
3031
use OCA\DAV\Db\AbsenceMapper;
3132
use OCP\AppFramework\Db\DoesNotExistException;
33+
use OCP\EventDispatcher\IEventDispatcher;
34+
use OCP\IUserManager;
35+
use OCP\User\Events\OutOfOfficeChangedEvent;
36+
use OCP\User\Events\OutOfOfficeClearedEvent;
37+
use OCP\User\Events\OutOfOfficeScheduledEvent;
3238

3339
class AbsenceService {
3440
public function __construct(
3541
private AbsenceMapper $absenceMapper,
42+
private IEventDispatcher $eventDispatcher,
43+
private IUserManager $userManager,
3644
) {
3745
}
3846

3947
/**
48+
* @param string $firstDay The first day (inclusive) of the absence formatted as YYYY-MM-DD.
49+
* @param string $lastDay The last day (inclusive) of the absence formatted as YYYY-MM-DD.
50+
*
4051
* @throws \OCP\DB\Exception
52+
* @throws InvalidArgumentException If no user with the given user id exists.
4153
*/
4254
public function createOrUpdateAbsence(
4355
string $userId,
@@ -58,17 +70,40 @@ public function createOrUpdateAbsence(
5870
$absence->setStatus($status);
5971
$absence->setMessage($message);
6072

73+
// TODO: this method should probably just take a IUser instance
74+
$user = $this->userManager->get($userId);
75+
if ($user === null) {
76+
throw new InvalidArgumentException("User $userId does not exist");
77+
}
78+
$eventData = $absence->toOutOufOfficeData($user);
79+
6180
if ($absence->getId() === null) {
81+
$this->eventDispatcher->dispatchTyped(new OutOfOfficeScheduledEvent($eventData));
6282
return $this->absenceMapper->insert($absence);
6383
}
84+
85+
$this->eventDispatcher->dispatchTyped(new OutOfOfficeChangedEvent($eventData));
6486
return $this->absenceMapper->update($absence);
6587
}
6688

6789
/**
6890
* @throws \OCP\DB\Exception
6991
*/
7092
public function clearAbsence(string $userId): void {
71-
$this->absenceMapper->deleteByUserId($userId);
93+
try {
94+
$absence = $this->absenceMapper->findByUserId($userId);
95+
} catch (DoesNotExistException $e) {
96+
// Nothing to clear
97+
return;
98+
}
99+
$this->absenceMapper->delete($absence);
100+
// TODO: this method should probably just take a IUser instance
101+
$user = $this->userManager->get($userId);
102+
if ($user === null) {
103+
throw new InvalidArgumentException("User $userId does not exist");
104+
}
105+
$eventData = $absence->toOutOufOfficeData($user);
106+
$this->eventDispatcher->dispatchTyped(new OutOfOfficeClearedEvent($eventData));
72107
}
73108
}
74109

0 commit comments

Comments
 (0)