Skip to content

Commit 92acbb0

Browse files
authored
Merge pull request #45766 from nextcloud/feat/ooo-replacement
Feat: Allow users to select another user as their out-of-office replacement
2 parents 55f3e53 + a977474 commit 92acbb0

17 files changed

+321
-12
lines changed

apps/dav/appinfo/info.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
<name>WebDAV</name>
1111
<summary>WebDAV endpoint</summary>
1212
<description>WebDAV endpoint</description>
13-
<version>1.31.0</version>
13+
<version>1.31.1</version>
1414
<licence>agpl</licence>
1515
<author>owncloud.org</author>
1616
<namespace>DAV</namespace>

apps/dav/composer/composer/autoload_classmap.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -326,6 +326,7 @@
326326
'OCA\\DAV\\Migration\\Version1029Date20221114151721' => $baseDir . '/../lib/Migration/Version1029Date20221114151721.php',
327327
'OCA\\DAV\\Migration\\Version1029Date20231004091403' => $baseDir . '/../lib/Migration/Version1029Date20231004091403.php',
328328
'OCA\\DAV\\Migration\\Version1030Date20240205103243' => $baseDir . '/../lib/Migration/Version1030Date20240205103243.php',
329+
'OCA\\DAV\\Migration\\Version1031Date20240610134258' => $baseDir . '/../lib/Migration/Version1031Date20240610134258.php',
329330
'OCA\\DAV\\Profiler\\ProfilerPlugin' => $baseDir . '/../lib/Profiler/ProfilerPlugin.php',
330331
'OCA\\DAV\\Provisioning\\Apple\\AppleProvisioningNode' => $baseDir . '/../lib/Provisioning/Apple/AppleProvisioningNode.php',
331332
'OCA\\DAV\\Provisioning\\Apple\\AppleProvisioningPlugin' => $baseDir . '/../lib/Provisioning/Apple/AppleProvisioningPlugin.php',

apps/dav/composer/composer/autoload_static.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -341,6 +341,7 @@ class ComposerStaticInitDAV
341341
'OCA\\DAV\\Migration\\Version1029Date20221114151721' => __DIR__ . '/..' . '/../lib/Migration/Version1029Date20221114151721.php',
342342
'OCA\\DAV\\Migration\\Version1029Date20231004091403' => __DIR__ . '/..' . '/../lib/Migration/Version1029Date20231004091403.php',
343343
'OCA\\DAV\\Migration\\Version1030Date20240205103243' => __DIR__ . '/..' . '/../lib/Migration/Version1030Date20240205103243.php',
344+
'OCA\\DAV\\Migration\\Version1031Date20240610134258' => __DIR__ . '/..' . '/../lib/Migration/Version1031Date20240610134258.php',
344345
'OCA\\DAV\\Profiler\\ProfilerPlugin' => __DIR__ . '/..' . '/../lib/Profiler/ProfilerPlugin.php',
345346
'OCA\\DAV\\Provisioning\\Apple\\AppleProvisioningNode' => __DIR__ . '/..' . '/../lib/Provisioning/Apple/AppleProvisioningNode.php',
346347
'OCA\\DAV\\Provisioning\\Apple\\AppleProvisioningPlugin' => __DIR__ . '/..' . '/../lib/Provisioning/Apple/AppleProvisioningPlugin.php',

apps/dav/lib/Controller/OutOfOfficeController.php

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,8 @@ public function getOutOfOffice(string $userId): DataResponse {
9393
'lastDay' => $data->getLastDay(),
9494
'status' => $data->getStatus(),
9595
'message' => $data->getMessage(),
96+
'replacementUserId' => $data->getReplacementUserId(),
97+
'replacementUserDisplayName' => $data->getReplacementUserDisplayName(),
9698
]);
9799
}
98100

@@ -103,24 +105,37 @@ public function getOutOfOffice(string $userId): DataResponse {
103105
* @param string $lastDay Last day of the absence in format `YYYY-MM-DD`
104106
* @param string $status Short text that is set as user status during the absence
105107
* @param string $message Longer multiline message that is shown to others during the absence
106-
* @return DataResponse<Http::STATUS_OK, DAVOutOfOfficeData, array{}>|DataResponse<Http::STATUS_BAD_REQUEST, array{error: 'firstDay'}, array{}>|DataResponse<Http::STATUS_UNAUTHORIZED, null, array{}>
108+
* @param string $replacementUserId User id of the replacement user
109+
* @param string $replacementUserDisplayName Display name of the replacement user
110+
* @return DataResponse<Http::STATUS_OK, DAVOutOfOfficeData, array{}>|DataResponse<Http::STATUS_BAD_REQUEST, array{error: 'firstDay'}, array{}>|DataResponse<Http::STATUS_UNAUTHORIZED, null, array{}>|DataResponse<Http::STATUS_NOT_FOUND, null, array{}>
107111
*
108112
* 200: Absence data
109113
* 400: When the first day is not before the last day
110114
* 401: When the user is not logged in
115+
* 404: When the replacementUserId was provided but replacement user was not found
111116
*/
112117
#[NoAdminRequired]
113118
public function setOutOfOffice(
114119
string $firstDay,
115120
string $lastDay,
116121
string $status,
117122
string $message,
123+
string $replacementUserId = '',
124+
string $replacementUserDisplayName = ''
125+
118126
): DataResponse {
119127
$user = $this->userSession?->getUser();
120128
if ($user === null) {
121129
return new DataResponse(null, Http::STATUS_UNAUTHORIZED);
122130
}
123131

132+
if ($replacementUserId !== '') {
133+
$replacementUser = $this->userManager->get($replacementUserId);
134+
if ($replacementUser === null) {
135+
return new DataResponse(null, Http::STATUS_NOT_FOUND);
136+
}
137+
}
138+
124139
$parsedFirstDay = new DateTimeImmutable($firstDay);
125140
$parsedLastDay = new DateTimeImmutable($lastDay);
126141
if ($parsedFirstDay->getTimestamp() > $parsedLastDay->getTimestamp()) {
@@ -133,6 +148,8 @@ public function setOutOfOffice(
133148
$lastDay,
134149
$status,
135150
$message,
151+
$replacementUserId,
152+
$replacementUserDisplayName
136153
);
137154
$this->coordinator->clearCache($user->getUID());
138155

@@ -143,6 +160,8 @@ public function setOutOfOffice(
143160
'lastDay' => $data->getLastDay(),
144161
'status' => $data->getStatus(),
145162
'message' => $data->getMessage(),
163+
'replacementUserId' => $data->getReplacementUserId(),
164+
'replacementUserDisplayName' => $data->getReplacementUserDisplayName(),
146165
]);
147166
}
148167

apps/dav/lib/Db/Absence.php

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,10 @@
2929
* @method void setStatus(string $status)
3030
* @method string getMessage()
3131
* @method void setMessage(string $message)
32+
* @method string getReplacementUserId()
33+
* @method void setReplacementUserId(string $replacementUserId)
34+
* @method string getReplacementUserDisplayName()
35+
* @method void setReplacementUserDisplayName(string $replacementUserDisplayName)
3236
*/
3337
class Absence extends Entity implements JsonSerializable {
3438
protected string $userId = '';
@@ -43,12 +47,18 @@ class Absence extends Entity implements JsonSerializable {
4347

4448
protected string $message = '';
4549

50+
protected string $replacementUserId = '';
51+
52+
protected string $replacementUserDisplayName = '';
53+
4654
public function __construct() {
4755
$this->addType('userId', 'string');
4856
$this->addType('firstDay', 'string');
4957
$this->addType('lastDay', 'string');
5058
$this->addType('status', 'string');
5159
$this->addType('message', 'string');
60+
$this->addType('replacementUserId', 'string');
61+
$this->addType('replacementUserDisplayName', 'string');
5262
}
5363

5464
public function toOutOufOfficeData(IUser $user, string $timezone): IOutOfOfficeData {
@@ -70,6 +80,8 @@ public function toOutOufOfficeData(IUser $user, string $timezone): IOutOfOfficeD
7080
$endDate->getTimestamp(),
7181
$this->getStatus(),
7282
$this->getMessage(),
83+
$this->getReplacementUserId(),
84+
$this->getReplacementUserDisplayName(),
7385
);
7486
}
7587

@@ -80,6 +92,8 @@ public function jsonSerialize(): array {
8092
'lastDay' => $this->lastDay,
8193
'status' => $this->status,
8294
'message' => $this->message,
95+
'replacementUserId' => $this->replacementUserId,
96+
'replacementUserDisplayName' => $this->replacementUserDisplayName,
8397
];
8498
}
8599
}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
/**
6+
* SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
7+
* SPDX-License-Identifier: AGPL-3.0-or-later
8+
*/
9+
10+
namespace OCA\DAV\Migration;
11+
12+
use Closure;
13+
use OCP\DB\ISchemaWrapper;
14+
use OCP\DB\Types;
15+
use OCP\Migration\IOutput;
16+
use OCP\Migration\SimpleMigrationStep;
17+
18+
class Version1031Date20240610134258 extends SimpleMigrationStep {
19+
public function changeSchema(IOutput $output, Closure $schemaClosure, array $options): ?ISchemaWrapper {
20+
/** @var ISchemaWrapper $schema */
21+
$schema = $schemaClosure();
22+
23+
$tableDavAbsence = $schema->getTable('dav_absence');
24+
25+
if (!$tableDavAbsence->hasColumn('replacement_user_id')) {
26+
$tableDavAbsence->addColumn('replacement_user_id', Types::STRING, [
27+
'notnull' => false,
28+
'default' => '',
29+
'length' => 64,
30+
]);
31+
}
32+
33+
if (!$tableDavAbsence->hasColumn('replacement_user_display_name')) {
34+
$tableDavAbsence->addColumn('replacement_user_display_name', Types::STRING, [
35+
'notnull' => false,
36+
'default' => '',
37+
'length' => 64,
38+
]);
39+
}
40+
41+
return $schema;
42+
}
43+
44+
}

apps/dav/lib/ResponseDefinitions.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@
1313
* @psalm-type DAVOutOfOfficeDataCommon = array{
1414
* userId: string,
1515
* message: string,
16+
* replacementUserId: string,
17+
* replacementUserDisplayName: string,
1618
* }
1719
*
1820
* @psalm-type DAVOutOfOfficeData = DAVOutOfOfficeDataCommon&array{

apps/dav/lib/Service/AbsenceService.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,8 @@ public function createOrUpdateAbsence(
4747
string $lastDay,
4848
string $status,
4949
string $message,
50+
?string $replacementUserId = null,
51+
?string $replacementUserDisplayName = null,
5052
): Absence {
5153
try {
5254
$absence = $this->absenceMapper->findByUserId($user->getUID());
@@ -59,6 +61,8 @@ public function createOrUpdateAbsence(
5961
$absence->setLastDay($lastDay);
6062
$absence->setStatus($status);
6163
$absence->setMessage($message);
64+
$absence->setReplacementUserId($replacementUserId ?? '');
65+
$absence->setReplacementUserDisplayName($replacementUserDisplayName ?? '');
6266

6367
if ($absence->getId() === null) {
6468
$absence = $this->absenceMapper->insert($absence);

apps/dav/openapi.json

Lines changed: 57 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -133,14 +133,22 @@
133133
"type": "object",
134134
"required": [
135135
"userId",
136-
"message"
136+
"message",
137+
"replacementUserId",
138+
"replacementUserDisplayName"
137139
],
138140
"properties": {
139141
"userId": {
140142
"type": "string"
141143
},
142144
"message": {
143145
"type": "string"
146+
},
147+
"replacementUserId": {
148+
"type": "string"
149+
},
150+
"replacementUserDisplayName": {
151+
"type": "string"
144152
}
145153
}
146154
}
@@ -570,6 +578,24 @@
570578
"type": "string"
571579
}
572580
},
581+
{
582+
"name": "replacementUserId",
583+
"in": "query",
584+
"description": "User id of the replacement user",
585+
"schema": {
586+
"type": "string",
587+
"default": ""
588+
}
589+
},
590+
{
591+
"name": "replacementUserDisplayName",
592+
"in": "query",
593+
"description": "Display name of the replacement user",
594+
"schema": {
595+
"type": "string",
596+
"default": ""
597+
}
598+
},
573599
{
574600
"name": "userId",
575601
"in": "path",
@@ -690,6 +716,36 @@
690716
}
691717
}
692718
}
719+
},
720+
"404": {
721+
"description": "When the replacementUserId was provided but replacement user was not found",
722+
"content": {
723+
"application/json": {
724+
"schema": {
725+
"type": "object",
726+
"required": [
727+
"ocs"
728+
],
729+
"properties": {
730+
"ocs": {
731+
"type": "object",
732+
"required": [
733+
"meta",
734+
"data"
735+
],
736+
"properties": {
737+
"meta": {
738+
"$ref": "#/components/schemas/OCSMeta"
739+
},
740+
"data": {
741+
"nullable": true
742+
}
743+
}
744+
}
745+
}
746+
}
747+
}
748+
}
693749
}
694750
}
695751
},

0 commit comments

Comments
 (0)