|
1
|
|
|
<?php |
|
2
|
|
|
declare(strict_types=1); |
|
3
|
|
|
|
|
4
|
|
|
/** |
|
5
|
|
|
* @copyright 2023 Ferdinand Thiessen <[email protected]> |
|
6
|
|
|
* |
|
7
|
|
|
* @author Ferdinand Thiessen <[email protected]> |
|
8
|
|
|
* |
|
9
|
|
|
* @license AGPL-3.0-or-later |
|
10
|
|
|
* |
|
11
|
|
|
* This program is free software: you can redistribute it and/or modify |
|
12
|
|
|
* it under the terms of the GNU Affero General Public License as |
|
13
|
|
|
* published by the Free Software Foundation, either version 3 of the |
|
14
|
|
|
* License, or (at your option) any later version. |
|
15
|
|
|
* |
|
16
|
|
|
* This program is distributed in the hope that it will be useful, |
|
17
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
18
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
19
|
|
|
* GNU Affero General Public License for more details. |
|
20
|
|
|
* |
|
21
|
|
|
* You should have received a copy of the GNU Affero General Public License |
|
22
|
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>. |
|
23
|
|
|
* |
|
24
|
|
|
*/ |
|
25
|
|
|
|
|
26
|
|
|
namespace OCA\DAV\CalDAV\AppCalendar; |
|
27
|
|
|
|
|
28
|
|
|
use OCP\Calendar\ICalendar; |
|
29
|
|
|
use OCP\Calendar\ICreateFromString; |
|
30
|
|
|
use OCP\Constants; |
|
31
|
|
|
use Sabre\CalDAV\ICalendarObject; |
|
32
|
|
|
use Sabre\DAV\Exception\Forbidden; |
|
33
|
|
|
use Sabre\DAV\Exception\NotFound; |
|
34
|
|
|
use Sabre\DAVACL\IACL; |
|
35
|
|
|
use Sabre\VObject\Component\VCalendar; |
|
36
|
|
|
use Sabre\VObject\Property\ICalendar\DateTime; |
|
37
|
|
|
|
|
38
|
|
|
class CalendarObject implements ICalendarObject, IACL { |
|
39
|
|
|
private VCalendar $vobject; |
|
40
|
|
|
private AppCalendar $calendar; |
|
41
|
|
|
private ICalendar|ICreateFromString $backend; |
|
42
|
|
|
|
|
43
|
|
|
public function __construct(AppCalendar $calendar, ICalendar $backend, VCalendar $vobject) { |
|
44
|
|
|
$this->backend = $backend; |
|
45
|
|
|
$this->calendar = $calendar; |
|
46
|
|
|
$this->vobject = $vobject; |
|
47
|
|
|
} |
|
48
|
|
|
|
|
49
|
|
|
public function getOwner() { |
|
50
|
|
|
return $this->calendar->getOwner(); |
|
51
|
|
|
} |
|
52
|
|
|
|
|
53
|
|
|
public function getGroup() { |
|
54
|
|
|
return $this->calendar->getGroup(); |
|
|
|
|
|
|
55
|
|
|
} |
|
56
|
|
|
|
|
57
|
|
|
public function getACL(): array { |
|
58
|
|
|
$acl = [ |
|
59
|
|
|
[ |
|
60
|
|
|
'privilege' => '{DAV:}read', |
|
61
|
|
|
'principal' => $this->getOwner(), |
|
62
|
|
|
'protected' => true, |
|
63
|
|
|
] |
|
64
|
|
|
]; |
|
65
|
|
|
if ($this->calendar->getPermissions() & Constants::PERMISSION_UPDATE) { |
|
66
|
|
|
$acl[] = [ |
|
67
|
|
|
'privilege' => '{DAV:}write-content', |
|
68
|
|
|
'principal' => $this->getOwner(), |
|
69
|
|
|
'protected' => true, |
|
70
|
|
|
]; |
|
71
|
|
|
} |
|
72
|
|
|
return $acl; |
|
73
|
|
|
} |
|
74
|
|
|
|
|
75
|
|
|
public function setACL(array $acl): void { |
|
76
|
|
|
throw new Forbidden('Setting ACL is not supported on this node'); |
|
77
|
|
|
} |
|
78
|
|
|
|
|
79
|
|
|
public function getSupportedPrivilegeSet(): ?array { |
|
80
|
|
|
return null; |
|
81
|
|
|
} |
|
82
|
|
|
|
|
83
|
|
|
public function put($data): void { |
|
84
|
|
|
if ($this->backend instanceof ICreateFromString && $this->calendar->getPermissions() & Constants::PERMISSION_UPDATE) { |
|
85
|
|
|
if (is_resource($data)) { |
|
86
|
|
|
$data = stream_get_contents($data) ?: ''; |
|
87
|
|
|
} |
|
88
|
|
|
$this->backend->createFromString($this->getName(), $data); |
|
89
|
|
|
} else { |
|
90
|
|
|
throw new Forbidden('This calendar-object is read-only'); |
|
91
|
|
|
} |
|
92
|
|
|
} |
|
93
|
|
|
|
|
94
|
|
|
public function get(): string { |
|
95
|
|
|
return $this->vobject->serialize(); |
|
96
|
|
|
} |
|
97
|
|
|
|
|
98
|
|
|
public function getContentType(): string { |
|
99
|
|
|
return 'text/calendar; charset=utf-8'; |
|
100
|
|
|
} |
|
101
|
|
|
|
|
102
|
|
|
public function getETag(): ?string { |
|
103
|
|
|
return null; |
|
104
|
|
|
} |
|
105
|
|
|
|
|
106
|
|
|
public function getSize() { |
|
107
|
|
|
return mb_strlen($this->vobject->serialize()); |
|
108
|
|
|
} |
|
109
|
|
|
|
|
110
|
|
|
public function delete(): void { |
|
111
|
|
|
if ($this->backend instanceof ICreateFromString && $this->calendar->getPermissions() & Constants::PERMISSION_DELETE) { |
|
112
|
|
|
/** @var \Sabre\VObject\Component[] */ |
|
113
|
|
|
$components = $this->vobject->getBaseComponents(); |
|
114
|
|
|
foreach ($components as $key => $component) { |
|
115
|
|
|
$components[$key]->STATUS = 'CANCELLED'; |
|
116
|
|
|
$components[$key]->SEQUENCE = isset($component->SEQUENCE) ? ((int)$component->SEQUENCE->getValue()) + 1 : 1; |
|
|
|
|
|
|
117
|
|
|
if ($component->name === 'VEVENT') { |
|
118
|
|
|
$components[$key]->METHOD = 'CANCEL'; |
|
119
|
|
|
} |
|
120
|
|
|
} |
|
121
|
|
|
$this->backend->createFromString($this->getName(), (new VCalendar($components))->serialize()); |
|
122
|
|
|
} else { |
|
123
|
|
|
throw new Forbidden('This calendar-object is read-only'); |
|
124
|
|
|
} |
|
125
|
|
|
} |
|
126
|
|
|
|
|
127
|
|
|
public function getName(): string { |
|
128
|
|
|
// Every object is required to have an UID |
|
129
|
|
|
$base = $this->vobject->getBaseComponent(); |
|
130
|
|
|
// This should never happen except the app provides invalid calendars (VEvent, VTodo... all require UID to be present) |
|
131
|
|
|
if ($base === null) { |
|
132
|
|
|
throw new NotFound('Invalid node'); |
|
133
|
|
|
} |
|
134
|
|
|
if (isset($base->{'X-FILENAME'})) { |
|
135
|
|
|
return (string)$base->{'X-FILENAME'}; |
|
136
|
|
|
} |
|
137
|
|
|
return (string)$base->UID . '.ics'; |
|
138
|
|
|
} |
|
139
|
|
|
|
|
140
|
|
|
public function setName($name): void { |
|
141
|
|
|
throw new Forbidden('This calendar-object is read-only'); |
|
142
|
|
|
} |
|
143
|
|
|
|
|
144
|
|
|
public function getLastModified(): ?int { |
|
145
|
|
|
$base = $this->vobject->getBaseComponent(); |
|
146
|
|
|
if ($base !== null && $this->vobject->getBaseComponent()->{'LAST-MODIFIED'}) { |
|
147
|
|
|
/** @var DateTime */ |
|
148
|
|
|
$lastModified = $this->vobject->getBaseComponent()->{'LAST-MODIFIED'}; |
|
149
|
|
|
return $lastModified->getDateTime()->getTimestamp(); |
|
150
|
|
|
} |
|
151
|
|
|
return null; |
|
152
|
|
|
} |
|
153
|
|
|
} |
|
154
|
|
|
|
This check looks for function or method calls that always return null and whose return value is used.
The method
getObject()can return nothing but null, so it makes no sense to use the return value.The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.