aboutsummaryrefslogtreecommitdiffstats
path: root/apps/dav
diff options
context:
space:
mode:
authorChristoph Wurst <christoph@winzerhof-wurst.at>2023-09-27 11:41:20 +0200
committerRichard Steinmetz <richard@steinmetz.cloud>2023-11-09 10:36:11 +0100
commitab1a1d688df76fb5c10b8bc431b928a2db1675bd (patch)
tree0147377303eccd1f6d22569fdf604d726ab8ca45 /apps/dav
parent1acc7c04684a05f024f4c83a8665d4732c2fc5f6 (diff)
downloadnextcloud-server-ab1a1d688df76fb5c10b8bc431b928a2db1675bd.tar.gz
nextcloud-server-ab1a1d688df76fb5c10b8bc431b928a2db1675bd.zip
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>
Diffstat (limited to 'apps/dav')
-rw-r--r--apps/dav/appinfo/routes.php1
-rw-r--r--apps/dav/composer/composer/autoload_classmap.php2
-rw-r--r--apps/dav/composer/composer/autoload_static.php2
-rw-r--r--apps/dav/lib/Controller/OutOfOfficeController.php78
-rw-r--r--apps/dav/lib/Db/Absence.php28
-rw-r--r--apps/dav/lib/ResponseDefinitions.php40
-rw-r--r--apps/dav/lib/Service/AbsenceService.php37
-rw-r--r--apps/dav/openapi.json134
8 files changed, 321 insertions, 1 deletions
diff --git a/apps/dav/appinfo/routes.php b/apps/dav/appinfo/routes.php
index 3236c0642af..1b2fa0094bf 100644
--- a/apps/dav/appinfo/routes.php
+++ b/apps/dav/appinfo/routes.php
@@ -35,5 +35,6 @@ return [
],
'ocs' => [
['name' => 'direct#getUrl', 'url' => '/api/v1/direct', 'verb' => 'POST'],
+ ['name' => 'out_of_office#getCurrentOutOfOfficeData', 'url' => '/api/v1/outOfOffice/{userId}', 'verb' => 'GET'],
],
];
diff --git a/apps/dav/composer/composer/autoload_classmap.php b/apps/dav/composer/composer/autoload_classmap.php
index e0c3e20dc6b..bb424e47787 100644
--- a/apps/dav/composer/composer/autoload_classmap.php
+++ b/apps/dav/composer/composer/autoload_classmap.php
@@ -192,6 +192,7 @@ return array(
'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',
@@ -305,6 +306,7 @@ return array(
'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',
diff --git a/apps/dav/composer/composer/autoload_static.php b/apps/dav/composer/composer/autoload_static.php
index 9292731af98..ef040e79674 100644
--- a/apps/dav/composer/composer/autoload_static.php
+++ b/apps/dav/composer/composer/autoload_static.php
@@ -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',
@@ -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',
diff --git a/apps/dav/lib/Controller/OutOfOfficeController.php b/apps/dav/lib/Controller/OutOfOfficeController.php
new file mode 100644
index 00000000000..fe4200ee1b5
--- /dev/null
+++ b/apps/dav/lib/Controller/OutOfOfficeController.php
@@ -0,0 +1,78 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * @copyright Copyright (c) 2023 Richard Steinmetz <richard@steinmetz.cloud>
+ *
+ * @author Richard Steinmetz <richard@steinmetz.cloud>
+ *
+ * @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(),
+ ]);
+ }
+}
diff --git a/apps/dav/lib/Db/Absence.php b/apps/dav/lib/Db/Absence.php
index f705b99ef30..e9ce1d2ea64 100644
--- a/apps/dav/lib/Db/Absence.php
+++ b/apps/dav/lib/Db/Absence.php
@@ -26,8 +26,13 @@ declare(strict_types=1);
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()
@@ -43,8 +48,13 @@ use OCP\AppFramework\Db\Entity;
*/
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 = '';
@@ -56,6 +66,24 @@ class Absence extends Entity implements JsonSerializable {
$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,
diff --git a/apps/dav/lib/ResponseDefinitions.php b/apps/dav/lib/ResponseDefinitions.php
new file mode 100644
index 00000000000..97bd8e9efe9
--- /dev/null
+++ b/apps/dav/lib/ResponseDefinitions.php
@@ -0,0 +1,40 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * @copyright Copyright (c) 2023 Richard Steinmetz <richard@steinmetz.cloud>
+ *
+ * @author Richard Steinmetz <richard@steinmetz.cloud>
+ *
+ * @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 {
+}
diff --git a/apps/dav/lib/Service/AbsenceService.php b/apps/dav/lib/Service/AbsenceService.php
index 228007b3af1..69dee1bd8cc 100644
--- a/apps/dav/lib/Service/AbsenceService.php
+++ b/apps/dav/lib/Service/AbsenceService.php
@@ -26,18 +26,30 @@ declare(strict_types=1);
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,
@@ -58,9 +70,19 @@ class AbsenceService {
$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);
}
@@ -68,7 +90,20 @@ class AbsenceService {
* @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));
}
}
diff --git a/apps/dav/openapi.json b/apps/dav/openapi.json
index 09da0c19ff3..994d0cde11d 100644
--- a/apps/dav/openapi.json
+++ b/apps/dav/openapi.json
@@ -65,6 +65,38 @@
"type": "string"
}
}
+ },
+ "OutOfOfficeData": {
+ "type": "object",
+ "required": [
+ "id",
+ "userId",
+ "firstDay",
+ "lastDay",
+ "status",
+ "message"
+ ],
+ "properties": {
+ "id": {
+ "type": "integer",
+ "format": "int64"
+ },
+ "userId": {
+ "type": "string"
+ },
+ "firstDay": {
+ "type": "string"
+ },
+ "lastDay": {
+ "type": "string"
+ },
+ "status": {
+ "type": "string"
+ },
+ "message": {
+ "type": "string"
+ }
+ }
}
}
},
@@ -186,6 +218,108 @@
}
}
}
+ },
+ "/ocs/v2.php/apps/dav/api/v1/outOfOffice/{userId}": {
+ "get": {
+ "operationId": "out_of_office-get-current-out-of-office-data",
+ "summary": "Get the currently configured out-of-office data of a user.",
+ "tags": [
+ "out_of_office"
+ ],
+ "security": [
+ {
+ "bearer_auth": []
+ },
+ {
+ "basic_auth": []
+ }
+ ],
+ "parameters": [
+ {
+ "name": "userId",
+ "in": "path",
+ "description": "The user id to get out-of-office data for.",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ },
+ {
+ "name": "OCS-APIRequest",
+ "in": "header",
+ "description": "Required to be true for the API request to pass",
+ "required": true,
+ "schema": {
+ "type": "boolean",
+ "default": true
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Out-of-office data",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "required": [
+ "ocs"
+ ],
+ "properties": {
+ "ocs": {
+ "type": "object",
+ "required": [
+ "meta",
+ "data"
+ ],
+ "properties": {
+ "meta": {
+ "$ref": "#/components/schemas/OCSMeta"
+ },
+ "data": {
+ "$ref": "#/components/schemas/OutOfOfficeData",
+ "nullable": true
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "404": {
+ "description": "No out-of-office data was found",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "required": [
+ "ocs"
+ ],
+ "properties": {
+ "ocs": {
+ "type": "object",
+ "required": [
+ "meta",
+ "data"
+ ],
+ "properties": {
+ "meta": {
+ "$ref": "#/components/schemas/OCSMeta"
+ },
+ "data": {
+ "$ref": "#/components/schemas/OutOfOfficeData",
+ "nullable": true
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
}
},
"tags": []