Passed
Push — master ( 683685...5ed673 )
by Morris
13:18 queued 11s
created
apps/dav/lib/CalDAV/Activity/Provider/Event.php 2 patches
Indentation   +179 added lines, -179 removed lines patch added patch discarded remove patch
@@ -38,183 +38,183 @@
 block discarded – undo
38 38
 use OCP\L10N\IFactory;
39 39
 
40 40
 class Event extends Base {
41
-	public const SUBJECT_OBJECT_ADD = 'object_add';
42
-	public const SUBJECT_OBJECT_UPDATE = 'object_update';
43
-	public const SUBJECT_OBJECT_DELETE = 'object_delete';
44
-
45
-	/** @var IFactory */
46
-	protected $languageFactory;
47
-
48
-	/** @var IL10N */
49
-	protected $l;
50
-
51
-	/** @var IManager */
52
-	protected $activityManager;
53
-
54
-	/** @var IEventMerger */
55
-	protected $eventMerger;
56
-
57
-	/** @var IAppManager */
58
-	protected $appManager;
59
-
60
-	/**
61
-	 * @param IFactory $languageFactory
62
-	 * @param IURLGenerator $url
63
-	 * @param IManager $activityManager
64
-	 * @param IUserManager $userManager
65
-	 * @param IGroupManager $groupManager
66
-	 * @param IEventMerger $eventMerger
67
-	 * @param IAppManager $appManager
68
-	 */
69
-	public function __construct(IFactory $languageFactory, IURLGenerator $url, IManager $activityManager, IUserManager $userManager, IGroupManager $groupManager, IEventMerger $eventMerger, IAppManager $appManager) {
70
-		parent::__construct($userManager, $groupManager, $url);
71
-		$this->languageFactory = $languageFactory;
72
-		$this->activityManager = $activityManager;
73
-		$this->eventMerger = $eventMerger;
74
-		$this->appManager = $appManager;
75
-	}
76
-
77
-	/**
78
-	 * @param array $eventData
79
-	 * @return array
80
-	 */
81
-	protected function generateObjectParameter(array $eventData) {
82
-		if (!isset($eventData['id']) || !isset($eventData['name'])) {
83
-			throw new \InvalidArgumentException();
84
-		}
85
-
86
-		$params = [
87
-			'type' => 'calendar-event',
88
-			'id' => $eventData['id'],
89
-			'name' => $eventData['name'],
90
-
91
-		];
92
-		if (isset($eventData['link']) && is_array($eventData['link']) && $this->appManager->isEnabledForUser('calendar')) {
93
-			try {
94
-				// The calendar app needs to be manually loaded for the routes to be loaded
95
-				OC_App::loadApp('calendar');
96
-				$linkData = $eventData['link'];
97
-				$objectId = base64_encode('/remote.php/dav/calendars/' . $linkData['owner'] . '/' . $linkData['calendar_uri'] . '/' . $linkData['object_uri']);
98
-				$link = [
99
-					'view' => 'dayGridMonth',
100
-					'timeRange' => 'now',
101
-					'mode' => 'sidebar',
102
-					'objectId' => $objectId,
103
-					'recurrenceId' => 'next'
104
-				];
105
-				$params['link'] = $this->url->linkToRouteAbsolute('calendar.view.indexview.timerange.edit', $link);
106
-			} catch (\Exception $error) {
107
-				// Do nothing
108
-			}
109
-		}
110
-		return $params;
111
-	}
112
-
113
-	/**
114
-	 * @param string $language
115
-	 * @param IEvent $event
116
-	 * @param IEvent|null $previousEvent
117
-	 * @return IEvent
118
-	 * @throws \InvalidArgumentException
119
-	 * @since 11.0.0
120
-	 */
121
-	public function parse($language, IEvent $event, IEvent $previousEvent = null) {
122
-		if ($event->getApp() !== 'dav' || $event->getType() !== 'calendar_event') {
123
-			throw new \InvalidArgumentException();
124
-		}
125
-
126
-		$this->l = $this->languageFactory->get('dav', $language);
127
-
128
-		if ($this->activityManager->getRequirePNG()) {
129
-			$event->setIcon($this->url->getAbsoluteURL($this->url->imagePath('core', 'places/calendar-dark.png')));
130
-		} else {
131
-			$event->setIcon($this->url->getAbsoluteURL($this->url->imagePath('core', 'places/calendar.svg')));
132
-		}
133
-
134
-		if ($event->getSubject() === self::SUBJECT_OBJECT_ADD . '_event') {
135
-			$subject = $this->l->t('{actor} created event {event} in calendar {calendar}');
136
-		} elseif ($event->getSubject() === self::SUBJECT_OBJECT_ADD . '_event_self') {
137
-			$subject = $this->l->t('You created event {event} in calendar {calendar}');
138
-		} elseif ($event->getSubject() === self::SUBJECT_OBJECT_DELETE . '_event') {
139
-			$subject = $this->l->t('{actor} deleted event {event} from calendar {calendar}');
140
-		} elseif ($event->getSubject() === self::SUBJECT_OBJECT_DELETE . '_event_self') {
141
-			$subject = $this->l->t('You deleted event {event} from calendar {calendar}');
142
-		} elseif ($event->getSubject() === self::SUBJECT_OBJECT_UPDATE . '_event') {
143
-			$subject = $this->l->t('{actor} updated event {event} in calendar {calendar}');
144
-		} elseif ($event->getSubject() === self::SUBJECT_OBJECT_UPDATE . '_event_self') {
145
-			$subject = $this->l->t('You updated event {event} in calendar {calendar}');
146
-		} else {
147
-			throw new \InvalidArgumentException();
148
-		}
149
-
150
-		$parsedParameters = $this->getParameters($event);
151
-		$this->setSubjects($event, $subject, $parsedParameters);
152
-
153
-		$event = $this->eventMerger->mergeEvents('event', $event, $previousEvent);
154
-
155
-		return $event;
156
-	}
157
-
158
-	/**
159
-	 * @param IEvent $event
160
-	 * @return array
161
-	 */
162
-	protected function getParameters(IEvent $event) {
163
-		$subject = $event->getSubject();
164
-		$parameters = $event->getSubjectParameters();
165
-
166
-		// Nextcloud 13+
167
-		if (isset($parameters['calendar'])) {
168
-			switch ($subject) {
169
-				case self::SUBJECT_OBJECT_ADD . '_event':
170
-				case self::SUBJECT_OBJECT_DELETE . '_event':
171
-				case self::SUBJECT_OBJECT_UPDATE . '_event':
172
-					return [
173
-						'actor' => $this->generateUserParameter($parameters['actor']),
174
-						'calendar' => $this->generateCalendarParameter($parameters['calendar'], $this->l),
175
-						'event' => $this->generateClassifiedObjectParameter($parameters['object']),
176
-					];
177
-				case self::SUBJECT_OBJECT_ADD . '_event_self':
178
-				case self::SUBJECT_OBJECT_DELETE . '_event_self':
179
-				case self::SUBJECT_OBJECT_UPDATE . '_event_self':
180
-					return [
181
-						'calendar' => $this->generateCalendarParameter($parameters['calendar'], $this->l),
182
-						'event' => $this->generateClassifiedObjectParameter($parameters['object']),
183
-					];
184
-			}
185
-		}
186
-
187
-		// Legacy - Do NOT Remove unless necessary
188
-		// Removing this will break parsing of activities that were created on
189
-		// Nextcloud 12, so we should keep this as long as it's acceptable.
190
-		// Otherwise if people upgrade over multiple releases in a short period,
191
-		// they will get the dead entries in their stream.
192
-		switch ($subject) {
193
-			case self::SUBJECT_OBJECT_ADD . '_event':
194
-			case self::SUBJECT_OBJECT_DELETE . '_event':
195
-			case self::SUBJECT_OBJECT_UPDATE . '_event':
196
-				return [
197
-					'actor' => $this->generateUserParameter($parameters[0]),
198
-					'calendar' => $this->generateLegacyCalendarParameter($event->getObjectId(), $parameters[1]),
199
-					'event' => $this->generateObjectParameter($parameters[2]),
200
-				];
201
-			case self::SUBJECT_OBJECT_ADD . '_event_self':
202
-			case self::SUBJECT_OBJECT_DELETE . '_event_self':
203
-			case self::SUBJECT_OBJECT_UPDATE . '_event_self':
204
-				return [
205
-					'calendar' => $this->generateLegacyCalendarParameter($event->getObjectId(), $parameters[1]),
206
-					'event' => $this->generateObjectParameter($parameters[2]),
207
-				];
208
-		}
209
-
210
-		throw new \InvalidArgumentException();
211
-	}
212
-
213
-	private function generateClassifiedObjectParameter(array $eventData) {
214
-		$parameter = $this->generateObjectParameter($eventData);
215
-		if (!empty($eventData['classified'])) {
216
-			$parameter['name'] = $this->l->t('Busy');
217
-		}
218
-		return $parameter;
219
-	}
41
+    public const SUBJECT_OBJECT_ADD = 'object_add';
42
+    public const SUBJECT_OBJECT_UPDATE = 'object_update';
43
+    public const SUBJECT_OBJECT_DELETE = 'object_delete';
44
+
45
+    /** @var IFactory */
46
+    protected $languageFactory;
47
+
48
+    /** @var IL10N */
49
+    protected $l;
50
+
51
+    /** @var IManager */
52
+    protected $activityManager;
53
+
54
+    /** @var IEventMerger */
55
+    protected $eventMerger;
56
+
57
+    /** @var IAppManager */
58
+    protected $appManager;
59
+
60
+    /**
61
+     * @param IFactory $languageFactory
62
+     * @param IURLGenerator $url
63
+     * @param IManager $activityManager
64
+     * @param IUserManager $userManager
65
+     * @param IGroupManager $groupManager
66
+     * @param IEventMerger $eventMerger
67
+     * @param IAppManager $appManager
68
+     */
69
+    public function __construct(IFactory $languageFactory, IURLGenerator $url, IManager $activityManager, IUserManager $userManager, IGroupManager $groupManager, IEventMerger $eventMerger, IAppManager $appManager) {
70
+        parent::__construct($userManager, $groupManager, $url);
71
+        $this->languageFactory = $languageFactory;
72
+        $this->activityManager = $activityManager;
73
+        $this->eventMerger = $eventMerger;
74
+        $this->appManager = $appManager;
75
+    }
76
+
77
+    /**
78
+     * @param array $eventData
79
+     * @return array
80
+     */
81
+    protected function generateObjectParameter(array $eventData) {
82
+        if (!isset($eventData['id']) || !isset($eventData['name'])) {
83
+            throw new \InvalidArgumentException();
84
+        }
85
+
86
+        $params = [
87
+            'type' => 'calendar-event',
88
+            'id' => $eventData['id'],
89
+            'name' => $eventData['name'],
90
+
91
+        ];
92
+        if (isset($eventData['link']) && is_array($eventData['link']) && $this->appManager->isEnabledForUser('calendar')) {
93
+            try {
94
+                // The calendar app needs to be manually loaded for the routes to be loaded
95
+                OC_App::loadApp('calendar');
96
+                $linkData = $eventData['link'];
97
+                $objectId = base64_encode('/remote.php/dav/calendars/' . $linkData['owner'] . '/' . $linkData['calendar_uri'] . '/' . $linkData['object_uri']);
98
+                $link = [
99
+                    'view' => 'dayGridMonth',
100
+                    'timeRange' => 'now',
101
+                    'mode' => 'sidebar',
102
+                    'objectId' => $objectId,
103
+                    'recurrenceId' => 'next'
104
+                ];
105
+                $params['link'] = $this->url->linkToRouteAbsolute('calendar.view.indexview.timerange.edit', $link);
106
+            } catch (\Exception $error) {
107
+                // Do nothing
108
+            }
109
+        }
110
+        return $params;
111
+    }
112
+
113
+    /**
114
+     * @param string $language
115
+     * @param IEvent $event
116
+     * @param IEvent|null $previousEvent
117
+     * @return IEvent
118
+     * @throws \InvalidArgumentException
119
+     * @since 11.0.0
120
+     */
121
+    public function parse($language, IEvent $event, IEvent $previousEvent = null) {
122
+        if ($event->getApp() !== 'dav' || $event->getType() !== 'calendar_event') {
123
+            throw new \InvalidArgumentException();
124
+        }
125
+
126
+        $this->l = $this->languageFactory->get('dav', $language);
127
+
128
+        if ($this->activityManager->getRequirePNG()) {
129
+            $event->setIcon($this->url->getAbsoluteURL($this->url->imagePath('core', 'places/calendar-dark.png')));
130
+        } else {
131
+            $event->setIcon($this->url->getAbsoluteURL($this->url->imagePath('core', 'places/calendar.svg')));
132
+        }
133
+
134
+        if ($event->getSubject() === self::SUBJECT_OBJECT_ADD . '_event') {
135
+            $subject = $this->l->t('{actor} created event {event} in calendar {calendar}');
136
+        } elseif ($event->getSubject() === self::SUBJECT_OBJECT_ADD . '_event_self') {
137
+            $subject = $this->l->t('You created event {event} in calendar {calendar}');
138
+        } elseif ($event->getSubject() === self::SUBJECT_OBJECT_DELETE . '_event') {
139
+            $subject = $this->l->t('{actor} deleted event {event} from calendar {calendar}');
140
+        } elseif ($event->getSubject() === self::SUBJECT_OBJECT_DELETE . '_event_self') {
141
+            $subject = $this->l->t('You deleted event {event} from calendar {calendar}');
142
+        } elseif ($event->getSubject() === self::SUBJECT_OBJECT_UPDATE . '_event') {
143
+            $subject = $this->l->t('{actor} updated event {event} in calendar {calendar}');
144
+        } elseif ($event->getSubject() === self::SUBJECT_OBJECT_UPDATE . '_event_self') {
145
+            $subject = $this->l->t('You updated event {event} in calendar {calendar}');
146
+        } else {
147
+            throw new \InvalidArgumentException();
148
+        }
149
+
150
+        $parsedParameters = $this->getParameters($event);
151
+        $this->setSubjects($event, $subject, $parsedParameters);
152
+
153
+        $event = $this->eventMerger->mergeEvents('event', $event, $previousEvent);
154
+
155
+        return $event;
156
+    }
157
+
158
+    /**
159
+     * @param IEvent $event
160
+     * @return array
161
+     */
162
+    protected function getParameters(IEvent $event) {
163
+        $subject = $event->getSubject();
164
+        $parameters = $event->getSubjectParameters();
165
+
166
+        // Nextcloud 13+
167
+        if (isset($parameters['calendar'])) {
168
+            switch ($subject) {
169
+                case self::SUBJECT_OBJECT_ADD . '_event':
170
+                case self::SUBJECT_OBJECT_DELETE . '_event':
171
+                case self::SUBJECT_OBJECT_UPDATE . '_event':
172
+                    return [
173
+                        'actor' => $this->generateUserParameter($parameters['actor']),
174
+                        'calendar' => $this->generateCalendarParameter($parameters['calendar'], $this->l),
175
+                        'event' => $this->generateClassifiedObjectParameter($parameters['object']),
176
+                    ];
177
+                case self::SUBJECT_OBJECT_ADD . '_event_self':
178
+                case self::SUBJECT_OBJECT_DELETE . '_event_self':
179
+                case self::SUBJECT_OBJECT_UPDATE . '_event_self':
180
+                    return [
181
+                        'calendar' => $this->generateCalendarParameter($parameters['calendar'], $this->l),
182
+                        'event' => $this->generateClassifiedObjectParameter($parameters['object']),
183
+                    ];
184
+            }
185
+        }
186
+
187
+        // Legacy - Do NOT Remove unless necessary
188
+        // Removing this will break parsing of activities that were created on
189
+        // Nextcloud 12, so we should keep this as long as it's acceptable.
190
+        // Otherwise if people upgrade over multiple releases in a short period,
191
+        // they will get the dead entries in their stream.
192
+        switch ($subject) {
193
+            case self::SUBJECT_OBJECT_ADD . '_event':
194
+            case self::SUBJECT_OBJECT_DELETE . '_event':
195
+            case self::SUBJECT_OBJECT_UPDATE . '_event':
196
+                return [
197
+                    'actor' => $this->generateUserParameter($parameters[0]),
198
+                    'calendar' => $this->generateLegacyCalendarParameter($event->getObjectId(), $parameters[1]),
199
+                    'event' => $this->generateObjectParameter($parameters[2]),
200
+                ];
201
+            case self::SUBJECT_OBJECT_ADD . '_event_self':
202
+            case self::SUBJECT_OBJECT_DELETE . '_event_self':
203
+            case self::SUBJECT_OBJECT_UPDATE . '_event_self':
204
+                return [
205
+                    'calendar' => $this->generateLegacyCalendarParameter($event->getObjectId(), $parameters[1]),
206
+                    'event' => $this->generateObjectParameter($parameters[2]),
207
+                ];
208
+        }
209
+
210
+        throw new \InvalidArgumentException();
211
+    }
212
+
213
+    private function generateClassifiedObjectParameter(array $eventData) {
214
+        $parameter = $this->generateObjectParameter($eventData);
215
+        if (!empty($eventData['classified'])) {
216
+            $parameter['name'] = $this->l->t('Busy');
217
+        }
218
+        return $parameter;
219
+    }
220 220
 }
Please login to merge, or discard this patch.
Spacing   +19 added lines, -19 removed lines patch added patch discarded remove patch
@@ -94,7 +94,7 @@  discard block
 block discarded – undo
94 94
 				// The calendar app needs to be manually loaded for the routes to be loaded
95 95
 				OC_App::loadApp('calendar');
96 96
 				$linkData = $eventData['link'];
97
-				$objectId = base64_encode('/remote.php/dav/calendars/' . $linkData['owner'] . '/' . $linkData['calendar_uri'] . '/' . $linkData['object_uri']);
97
+				$objectId = base64_encode('/remote.php/dav/calendars/'.$linkData['owner'].'/'.$linkData['calendar_uri'].'/'.$linkData['object_uri']);
98 98
 				$link = [
99 99
 					'view' => 'dayGridMonth',
100 100
 					'timeRange' => 'now',
@@ -131,17 +131,17 @@  discard block
 block discarded – undo
131 131
 			$event->setIcon($this->url->getAbsoluteURL($this->url->imagePath('core', 'places/calendar.svg')));
132 132
 		}
133 133
 
134
-		if ($event->getSubject() === self::SUBJECT_OBJECT_ADD . '_event') {
134
+		if ($event->getSubject() === self::SUBJECT_OBJECT_ADD.'_event') {
135 135
 			$subject = $this->l->t('{actor} created event {event} in calendar {calendar}');
136
-		} elseif ($event->getSubject() === self::SUBJECT_OBJECT_ADD . '_event_self') {
136
+		} elseif ($event->getSubject() === self::SUBJECT_OBJECT_ADD.'_event_self') {
137 137
 			$subject = $this->l->t('You created event {event} in calendar {calendar}');
138
-		} elseif ($event->getSubject() === self::SUBJECT_OBJECT_DELETE . '_event') {
138
+		} elseif ($event->getSubject() === self::SUBJECT_OBJECT_DELETE.'_event') {
139 139
 			$subject = $this->l->t('{actor} deleted event {event} from calendar {calendar}');
140
-		} elseif ($event->getSubject() === self::SUBJECT_OBJECT_DELETE . '_event_self') {
140
+		} elseif ($event->getSubject() === self::SUBJECT_OBJECT_DELETE.'_event_self') {
141 141
 			$subject = $this->l->t('You deleted event {event} from calendar {calendar}');
142
-		} elseif ($event->getSubject() === self::SUBJECT_OBJECT_UPDATE . '_event') {
142
+		} elseif ($event->getSubject() === self::SUBJECT_OBJECT_UPDATE.'_event') {
143 143
 			$subject = $this->l->t('{actor} updated event {event} in calendar {calendar}');
144
-		} elseif ($event->getSubject() === self::SUBJECT_OBJECT_UPDATE . '_event_self') {
144
+		} elseif ($event->getSubject() === self::SUBJECT_OBJECT_UPDATE.'_event_self') {
145 145
 			$subject = $this->l->t('You updated event {event} in calendar {calendar}');
146 146
 		} else {
147 147
 			throw new \InvalidArgumentException();
@@ -166,17 +166,17 @@  discard block
 block discarded – undo
166 166
 		// Nextcloud 13+
167 167
 		if (isset($parameters['calendar'])) {
168 168
 			switch ($subject) {
169
-				case self::SUBJECT_OBJECT_ADD . '_event':
170
-				case self::SUBJECT_OBJECT_DELETE . '_event':
171
-				case self::SUBJECT_OBJECT_UPDATE . '_event':
169
+				case self::SUBJECT_OBJECT_ADD.'_event':
170
+				case self::SUBJECT_OBJECT_DELETE.'_event':
171
+				case self::SUBJECT_OBJECT_UPDATE.'_event':
172 172
 					return [
173 173
 						'actor' => $this->generateUserParameter($parameters['actor']),
174 174
 						'calendar' => $this->generateCalendarParameter($parameters['calendar'], $this->l),
175 175
 						'event' => $this->generateClassifiedObjectParameter($parameters['object']),
176 176
 					];
177
-				case self::SUBJECT_OBJECT_ADD . '_event_self':
178
-				case self::SUBJECT_OBJECT_DELETE . '_event_self':
179
-				case self::SUBJECT_OBJECT_UPDATE . '_event_self':
177
+				case self::SUBJECT_OBJECT_ADD.'_event_self':
178
+				case self::SUBJECT_OBJECT_DELETE.'_event_self':
179
+				case self::SUBJECT_OBJECT_UPDATE.'_event_self':
180 180
 					return [
181 181
 						'calendar' => $this->generateCalendarParameter($parameters['calendar'], $this->l),
182 182
 						'event' => $this->generateClassifiedObjectParameter($parameters['object']),
@@ -190,17 +190,17 @@  discard block
 block discarded – undo
190 190
 		// Otherwise if people upgrade over multiple releases in a short period,
191 191
 		// they will get the dead entries in their stream.
192 192
 		switch ($subject) {
193
-			case self::SUBJECT_OBJECT_ADD . '_event':
194
-			case self::SUBJECT_OBJECT_DELETE . '_event':
195
-			case self::SUBJECT_OBJECT_UPDATE . '_event':
193
+			case self::SUBJECT_OBJECT_ADD.'_event':
194
+			case self::SUBJECT_OBJECT_DELETE.'_event':
195
+			case self::SUBJECT_OBJECT_UPDATE.'_event':
196 196
 				return [
197 197
 					'actor' => $this->generateUserParameter($parameters[0]),
198 198
 					'calendar' => $this->generateLegacyCalendarParameter($event->getObjectId(), $parameters[1]),
199 199
 					'event' => $this->generateObjectParameter($parameters[2]),
200 200
 				];
201
-			case self::SUBJECT_OBJECT_ADD . '_event_self':
202
-			case self::SUBJECT_OBJECT_DELETE . '_event_self':
203
-			case self::SUBJECT_OBJECT_UPDATE . '_event_self':
201
+			case self::SUBJECT_OBJECT_ADD.'_event_self':
202
+			case self::SUBJECT_OBJECT_DELETE.'_event_self':
203
+			case self::SUBJECT_OBJECT_UPDATE.'_event_self':
204 204
 				return [
205 205
 					'calendar' => $this->generateLegacyCalendarParameter($event->getObjectId(), $parameters[1]),
206 206
 					'event' => $this->generateObjectParameter($parameters[2]),
Please login to merge, or discard this patch.
apps/dav/lib/CalDAV/Activity/Provider/Todo.php 2 patches
Indentation   +105 added lines, -105 removed lines patch added patch discarded remove patch
@@ -28,119 +28,119 @@
 block discarded – undo
28 28
 
29 29
 class Todo extends Event {
30 30
 
31
-	/**
32
-	 * @param string $language
33
-	 * @param IEvent $event
34
-	 * @param IEvent|null $previousEvent
35
-	 * @return IEvent
36
-	 * @throws \InvalidArgumentException
37
-	 * @since 11.0.0
38
-	 */
39
-	public function parse($language, IEvent $event, IEvent $previousEvent = null) {
40
-		if ($event->getApp() !== 'dav' || $event->getType() !== 'calendar_todo') {
41
-			throw new \InvalidArgumentException();
42
-		}
31
+    /**
32
+     * @param string $language
33
+     * @param IEvent $event
34
+     * @param IEvent|null $previousEvent
35
+     * @return IEvent
36
+     * @throws \InvalidArgumentException
37
+     * @since 11.0.0
38
+     */
39
+    public function parse($language, IEvent $event, IEvent $previousEvent = null) {
40
+        if ($event->getApp() !== 'dav' || $event->getType() !== 'calendar_todo') {
41
+            throw new \InvalidArgumentException();
42
+        }
43 43
 
44
-		$this->l = $this->languageFactory->get('dav', $language);
44
+        $this->l = $this->languageFactory->get('dav', $language);
45 45
 
46
-		if ($this->activityManager->getRequirePNG()) {
47
-			$event->setIcon($this->url->getAbsoluteURL($this->url->imagePath('core', 'actions/checkmark.png')));
48
-		} else {
49
-			$event->setIcon($this->url->getAbsoluteURL($this->url->imagePath('core', 'actions/checkmark.svg')));
50
-		}
46
+        if ($this->activityManager->getRequirePNG()) {
47
+            $event->setIcon($this->url->getAbsoluteURL($this->url->imagePath('core', 'actions/checkmark.png')));
48
+        } else {
49
+            $event->setIcon($this->url->getAbsoluteURL($this->url->imagePath('core', 'actions/checkmark.svg')));
50
+        }
51 51
 
52
-		if ($event->getSubject() === self::SUBJECT_OBJECT_ADD . '_todo') {
53
-			$subject = $this->l->t('{actor} created todo {todo} in list {calendar}');
54
-		} elseif ($event->getSubject() === self::SUBJECT_OBJECT_ADD . '_todo_self') {
55
-			$subject = $this->l->t('You created todo {todo} in list {calendar}');
56
-		} elseif ($event->getSubject() === self::SUBJECT_OBJECT_DELETE . '_todo') {
57
-			$subject = $this->l->t('{actor} deleted todo {todo} from list {calendar}');
58
-		} elseif ($event->getSubject() === self::SUBJECT_OBJECT_DELETE . '_todo_self') {
59
-			$subject = $this->l->t('You deleted todo {todo} from list {calendar}');
60
-		} elseif ($event->getSubject() === self::SUBJECT_OBJECT_UPDATE . '_todo') {
61
-			$subject = $this->l->t('{actor} updated todo {todo} in list {calendar}');
62
-		} elseif ($event->getSubject() === self::SUBJECT_OBJECT_UPDATE . '_todo_self') {
63
-			$subject = $this->l->t('You updated todo {todo} in list {calendar}');
64
-		} elseif ($event->getSubject() === self::SUBJECT_OBJECT_UPDATE . '_todo_completed') {
65
-			$subject = $this->l->t('{actor} solved todo {todo} in list {calendar}');
66
-		} elseif ($event->getSubject() === self::SUBJECT_OBJECT_UPDATE . '_todo_completed_self') {
67
-			$subject = $this->l->t('You solved todo {todo} in list {calendar}');
68
-		} elseif ($event->getSubject() === self::SUBJECT_OBJECT_UPDATE . '_todo_needs_action') {
69
-			$subject = $this->l->t('{actor} reopened todo {todo} in list {calendar}');
70
-		} elseif ($event->getSubject() === self::SUBJECT_OBJECT_UPDATE . '_todo_needs_action_self') {
71
-			$subject = $this->l->t('You reopened todo {todo} in list {calendar}');
72
-		} else {
73
-			throw new \InvalidArgumentException();
74
-		}
52
+        if ($event->getSubject() === self::SUBJECT_OBJECT_ADD . '_todo') {
53
+            $subject = $this->l->t('{actor} created todo {todo} in list {calendar}');
54
+        } elseif ($event->getSubject() === self::SUBJECT_OBJECT_ADD . '_todo_self') {
55
+            $subject = $this->l->t('You created todo {todo} in list {calendar}');
56
+        } elseif ($event->getSubject() === self::SUBJECT_OBJECT_DELETE . '_todo') {
57
+            $subject = $this->l->t('{actor} deleted todo {todo} from list {calendar}');
58
+        } elseif ($event->getSubject() === self::SUBJECT_OBJECT_DELETE . '_todo_self') {
59
+            $subject = $this->l->t('You deleted todo {todo} from list {calendar}');
60
+        } elseif ($event->getSubject() === self::SUBJECT_OBJECT_UPDATE . '_todo') {
61
+            $subject = $this->l->t('{actor} updated todo {todo} in list {calendar}');
62
+        } elseif ($event->getSubject() === self::SUBJECT_OBJECT_UPDATE . '_todo_self') {
63
+            $subject = $this->l->t('You updated todo {todo} in list {calendar}');
64
+        } elseif ($event->getSubject() === self::SUBJECT_OBJECT_UPDATE . '_todo_completed') {
65
+            $subject = $this->l->t('{actor} solved todo {todo} in list {calendar}');
66
+        } elseif ($event->getSubject() === self::SUBJECT_OBJECT_UPDATE . '_todo_completed_self') {
67
+            $subject = $this->l->t('You solved todo {todo} in list {calendar}');
68
+        } elseif ($event->getSubject() === self::SUBJECT_OBJECT_UPDATE . '_todo_needs_action') {
69
+            $subject = $this->l->t('{actor} reopened todo {todo} in list {calendar}');
70
+        } elseif ($event->getSubject() === self::SUBJECT_OBJECT_UPDATE . '_todo_needs_action_self') {
71
+            $subject = $this->l->t('You reopened todo {todo} in list {calendar}');
72
+        } else {
73
+            throw new \InvalidArgumentException();
74
+        }
75 75
 
76
-		$parsedParameters = $this->getParameters($event);
77
-		$this->setSubjects($event, $subject, $parsedParameters);
76
+        $parsedParameters = $this->getParameters($event);
77
+        $this->setSubjects($event, $subject, $parsedParameters);
78 78
 
79
-		$event = $this->eventMerger->mergeEvents('todo', $event, $previousEvent);
79
+        $event = $this->eventMerger->mergeEvents('todo', $event, $previousEvent);
80 80
 
81
-		return $event;
82
-	}
81
+        return $event;
82
+    }
83 83
 
84
-	/**
85
-	 * @param IEvent $event
86
-	 * @return array
87
-	 */
88
-	protected function getParameters(IEvent $event) {
89
-		$subject = $event->getSubject();
90
-		$parameters = $event->getSubjectParameters();
84
+    /**
85
+     * @param IEvent $event
86
+     * @return array
87
+     */
88
+    protected function getParameters(IEvent $event) {
89
+        $subject = $event->getSubject();
90
+        $parameters = $event->getSubjectParameters();
91 91
 
92
-		// Nextcloud 13+
93
-		if (isset($parameters['calendar'])) {
94
-			switch ($subject) {
95
-				case self::SUBJECT_OBJECT_ADD . '_todo':
96
-				case self::SUBJECT_OBJECT_DELETE . '_todo':
97
-				case self::SUBJECT_OBJECT_UPDATE . '_todo':
98
-				case self::SUBJECT_OBJECT_UPDATE . '_todo_completed':
99
-				case self::SUBJECT_OBJECT_UPDATE . '_todo_needs_action':
100
-					return [
101
-						'actor' => $this->generateUserParameter($parameters['actor']),
102
-						'calendar' => $this->generateCalendarParameter($parameters['calendar'], $this->l),
103
-						'todo' => $this->generateObjectParameter($parameters['object']),
104
-					];
105
-				case self::SUBJECT_OBJECT_ADD . '_todo_self':
106
-				case self::SUBJECT_OBJECT_DELETE . '_todo_self':
107
-				case self::SUBJECT_OBJECT_UPDATE . '_todo_self':
108
-				case self::SUBJECT_OBJECT_UPDATE . '_todo_completed_self':
109
-				case self::SUBJECT_OBJECT_UPDATE . '_todo_needs_action_self':
110
-					return [
111
-						'calendar' => $this->generateCalendarParameter($parameters['calendar'], $this->l),
112
-						'todo' => $this->generateObjectParameter($parameters['object']),
113
-					];
114
-			}
115
-		}
92
+        // Nextcloud 13+
93
+        if (isset($parameters['calendar'])) {
94
+            switch ($subject) {
95
+                case self::SUBJECT_OBJECT_ADD . '_todo':
96
+                case self::SUBJECT_OBJECT_DELETE . '_todo':
97
+                case self::SUBJECT_OBJECT_UPDATE . '_todo':
98
+                case self::SUBJECT_OBJECT_UPDATE . '_todo_completed':
99
+                case self::SUBJECT_OBJECT_UPDATE . '_todo_needs_action':
100
+                    return [
101
+                        'actor' => $this->generateUserParameter($parameters['actor']),
102
+                        'calendar' => $this->generateCalendarParameter($parameters['calendar'], $this->l),
103
+                        'todo' => $this->generateObjectParameter($parameters['object']),
104
+                    ];
105
+                case self::SUBJECT_OBJECT_ADD . '_todo_self':
106
+                case self::SUBJECT_OBJECT_DELETE . '_todo_self':
107
+                case self::SUBJECT_OBJECT_UPDATE . '_todo_self':
108
+                case self::SUBJECT_OBJECT_UPDATE . '_todo_completed_self':
109
+                case self::SUBJECT_OBJECT_UPDATE . '_todo_needs_action_self':
110
+                    return [
111
+                        'calendar' => $this->generateCalendarParameter($parameters['calendar'], $this->l),
112
+                        'todo' => $this->generateObjectParameter($parameters['object']),
113
+                    ];
114
+            }
115
+        }
116 116
 
117
-		// Legacy - Do NOT Remove unless necessary
118
-		// Removing this will break parsing of activities that were created on
119
-		// Nextcloud 12, so we should keep this as long as it's acceptable.
120
-		// Otherwise if people upgrade over multiple releases in a short period,
121
-		// they will get the dead entries in their stream.
122
-		switch ($subject) {
123
-			case self::SUBJECT_OBJECT_ADD . '_todo':
124
-			case self::SUBJECT_OBJECT_DELETE . '_todo':
125
-			case self::SUBJECT_OBJECT_UPDATE . '_todo':
126
-			case self::SUBJECT_OBJECT_UPDATE . '_todo_completed':
127
-			case self::SUBJECT_OBJECT_UPDATE . '_todo_needs_action':
128
-				return [
129
-					'actor' => $this->generateUserParameter($parameters[0]),
130
-					'calendar' => $this->generateLegacyCalendarParameter($event->getObjectId(), $parameters[1]),
131
-					'todo' => $this->generateObjectParameter($parameters[2]),
132
-				];
133
-			case self::SUBJECT_OBJECT_ADD . '_todo_self':
134
-			case self::SUBJECT_OBJECT_DELETE . '_todo_self':
135
-			case self::SUBJECT_OBJECT_UPDATE . '_todo_self':
136
-			case self::SUBJECT_OBJECT_UPDATE . '_todo_completed_self':
137
-			case self::SUBJECT_OBJECT_UPDATE . '_todo_needs_action_self':
138
-				return [
139
-					'calendar' => $this->generateLegacyCalendarParameter($event->getObjectId(), $parameters[1]),
140
-					'todo' => $this->generateObjectParameter($parameters[2]),
141
-				];
142
-		}
117
+        // Legacy - Do NOT Remove unless necessary
118
+        // Removing this will break parsing of activities that were created on
119
+        // Nextcloud 12, so we should keep this as long as it's acceptable.
120
+        // Otherwise if people upgrade over multiple releases in a short period,
121
+        // they will get the dead entries in their stream.
122
+        switch ($subject) {
123
+            case self::SUBJECT_OBJECT_ADD . '_todo':
124
+            case self::SUBJECT_OBJECT_DELETE . '_todo':
125
+            case self::SUBJECT_OBJECT_UPDATE . '_todo':
126
+            case self::SUBJECT_OBJECT_UPDATE . '_todo_completed':
127
+            case self::SUBJECT_OBJECT_UPDATE . '_todo_needs_action':
128
+                return [
129
+                    'actor' => $this->generateUserParameter($parameters[0]),
130
+                    'calendar' => $this->generateLegacyCalendarParameter($event->getObjectId(), $parameters[1]),
131
+                    'todo' => $this->generateObjectParameter($parameters[2]),
132
+                ];
133
+            case self::SUBJECT_OBJECT_ADD . '_todo_self':
134
+            case self::SUBJECT_OBJECT_DELETE . '_todo_self':
135
+            case self::SUBJECT_OBJECT_UPDATE . '_todo_self':
136
+            case self::SUBJECT_OBJECT_UPDATE . '_todo_completed_self':
137
+            case self::SUBJECT_OBJECT_UPDATE . '_todo_needs_action_self':
138
+                return [
139
+                    'calendar' => $this->generateLegacyCalendarParameter($event->getObjectId(), $parameters[1]),
140
+                    'todo' => $this->generateObjectParameter($parameters[2]),
141
+                ];
142
+        }
143 143
 
144
-		throw new \InvalidArgumentException();
145
-	}
144
+        throw new \InvalidArgumentException();
145
+    }
146 146
 }
Please login to merge, or discard this patch.
Spacing   +30 added lines, -30 removed lines patch added patch discarded remove patch
@@ -49,25 +49,25 @@  discard block
 block discarded – undo
49 49
 			$event->setIcon($this->url->getAbsoluteURL($this->url->imagePath('core', 'actions/checkmark.svg')));
50 50
 		}
51 51
 
52
-		if ($event->getSubject() === self::SUBJECT_OBJECT_ADD . '_todo') {
52
+		if ($event->getSubject() === self::SUBJECT_OBJECT_ADD.'_todo') {
53 53
 			$subject = $this->l->t('{actor} created todo {todo} in list {calendar}');
54
-		} elseif ($event->getSubject() === self::SUBJECT_OBJECT_ADD . '_todo_self') {
54
+		} elseif ($event->getSubject() === self::SUBJECT_OBJECT_ADD.'_todo_self') {
55 55
 			$subject = $this->l->t('You created todo {todo} in list {calendar}');
56
-		} elseif ($event->getSubject() === self::SUBJECT_OBJECT_DELETE . '_todo') {
56
+		} elseif ($event->getSubject() === self::SUBJECT_OBJECT_DELETE.'_todo') {
57 57
 			$subject = $this->l->t('{actor} deleted todo {todo} from list {calendar}');
58
-		} elseif ($event->getSubject() === self::SUBJECT_OBJECT_DELETE . '_todo_self') {
58
+		} elseif ($event->getSubject() === self::SUBJECT_OBJECT_DELETE.'_todo_self') {
59 59
 			$subject = $this->l->t('You deleted todo {todo} from list {calendar}');
60
-		} elseif ($event->getSubject() === self::SUBJECT_OBJECT_UPDATE . '_todo') {
60
+		} elseif ($event->getSubject() === self::SUBJECT_OBJECT_UPDATE.'_todo') {
61 61
 			$subject = $this->l->t('{actor} updated todo {todo} in list {calendar}');
62
-		} elseif ($event->getSubject() === self::SUBJECT_OBJECT_UPDATE . '_todo_self') {
62
+		} elseif ($event->getSubject() === self::SUBJECT_OBJECT_UPDATE.'_todo_self') {
63 63
 			$subject = $this->l->t('You updated todo {todo} in list {calendar}');
64
-		} elseif ($event->getSubject() === self::SUBJECT_OBJECT_UPDATE . '_todo_completed') {
64
+		} elseif ($event->getSubject() === self::SUBJECT_OBJECT_UPDATE.'_todo_completed') {
65 65
 			$subject = $this->l->t('{actor} solved todo {todo} in list {calendar}');
66
-		} elseif ($event->getSubject() === self::SUBJECT_OBJECT_UPDATE . '_todo_completed_self') {
66
+		} elseif ($event->getSubject() === self::SUBJECT_OBJECT_UPDATE.'_todo_completed_self') {
67 67
 			$subject = $this->l->t('You solved todo {todo} in list {calendar}');
68
-		} elseif ($event->getSubject() === self::SUBJECT_OBJECT_UPDATE . '_todo_needs_action') {
68
+		} elseif ($event->getSubject() === self::SUBJECT_OBJECT_UPDATE.'_todo_needs_action') {
69 69
 			$subject = $this->l->t('{actor} reopened todo {todo} in list {calendar}');
70
-		} elseif ($event->getSubject() === self::SUBJECT_OBJECT_UPDATE . '_todo_needs_action_self') {
70
+		} elseif ($event->getSubject() === self::SUBJECT_OBJECT_UPDATE.'_todo_needs_action_self') {
71 71
 			$subject = $this->l->t('You reopened todo {todo} in list {calendar}');
72 72
 		} else {
73 73
 			throw new \InvalidArgumentException();
@@ -92,21 +92,21 @@  discard block
 block discarded – undo
92 92
 		// Nextcloud 13+
93 93
 		if (isset($parameters['calendar'])) {
94 94
 			switch ($subject) {
95
-				case self::SUBJECT_OBJECT_ADD . '_todo':
96
-				case self::SUBJECT_OBJECT_DELETE . '_todo':
97
-				case self::SUBJECT_OBJECT_UPDATE . '_todo':
98
-				case self::SUBJECT_OBJECT_UPDATE . '_todo_completed':
99
-				case self::SUBJECT_OBJECT_UPDATE . '_todo_needs_action':
95
+				case self::SUBJECT_OBJECT_ADD.'_todo':
96
+				case self::SUBJECT_OBJECT_DELETE.'_todo':
97
+				case self::SUBJECT_OBJECT_UPDATE.'_todo':
98
+				case self::SUBJECT_OBJECT_UPDATE.'_todo_completed':
99
+				case self::SUBJECT_OBJECT_UPDATE.'_todo_needs_action':
100 100
 					return [
101 101
 						'actor' => $this->generateUserParameter($parameters['actor']),
102 102
 						'calendar' => $this->generateCalendarParameter($parameters['calendar'], $this->l),
103 103
 						'todo' => $this->generateObjectParameter($parameters['object']),
104 104
 					];
105
-				case self::SUBJECT_OBJECT_ADD . '_todo_self':
106
-				case self::SUBJECT_OBJECT_DELETE . '_todo_self':
107
-				case self::SUBJECT_OBJECT_UPDATE . '_todo_self':
108
-				case self::SUBJECT_OBJECT_UPDATE . '_todo_completed_self':
109
-				case self::SUBJECT_OBJECT_UPDATE . '_todo_needs_action_self':
105
+				case self::SUBJECT_OBJECT_ADD.'_todo_self':
106
+				case self::SUBJECT_OBJECT_DELETE.'_todo_self':
107
+				case self::SUBJECT_OBJECT_UPDATE.'_todo_self':
108
+				case self::SUBJECT_OBJECT_UPDATE.'_todo_completed_self':
109
+				case self::SUBJECT_OBJECT_UPDATE.'_todo_needs_action_self':
110 110
 					return [
111 111
 						'calendar' => $this->generateCalendarParameter($parameters['calendar'], $this->l),
112 112
 						'todo' => $this->generateObjectParameter($parameters['object']),
@@ -120,21 +120,21 @@  discard block
 block discarded – undo
120 120
 		// Otherwise if people upgrade over multiple releases in a short period,
121 121
 		// they will get the dead entries in their stream.
122 122
 		switch ($subject) {
123
-			case self::SUBJECT_OBJECT_ADD . '_todo':
124
-			case self::SUBJECT_OBJECT_DELETE . '_todo':
125
-			case self::SUBJECT_OBJECT_UPDATE . '_todo':
126
-			case self::SUBJECT_OBJECT_UPDATE . '_todo_completed':
127
-			case self::SUBJECT_OBJECT_UPDATE . '_todo_needs_action':
123
+			case self::SUBJECT_OBJECT_ADD.'_todo':
124
+			case self::SUBJECT_OBJECT_DELETE.'_todo':
125
+			case self::SUBJECT_OBJECT_UPDATE.'_todo':
126
+			case self::SUBJECT_OBJECT_UPDATE.'_todo_completed':
127
+			case self::SUBJECT_OBJECT_UPDATE.'_todo_needs_action':
128 128
 				return [
129 129
 					'actor' => $this->generateUserParameter($parameters[0]),
130 130
 					'calendar' => $this->generateLegacyCalendarParameter($event->getObjectId(), $parameters[1]),
131 131
 					'todo' => $this->generateObjectParameter($parameters[2]),
132 132
 				];
133
-			case self::SUBJECT_OBJECT_ADD . '_todo_self':
134
-			case self::SUBJECT_OBJECT_DELETE . '_todo_self':
135
-			case self::SUBJECT_OBJECT_UPDATE . '_todo_self':
136
-			case self::SUBJECT_OBJECT_UPDATE . '_todo_completed_self':
137
-			case self::SUBJECT_OBJECT_UPDATE . '_todo_needs_action_self':
133
+			case self::SUBJECT_OBJECT_ADD.'_todo_self':
134
+			case self::SUBJECT_OBJECT_DELETE.'_todo_self':
135
+			case self::SUBJECT_OBJECT_UPDATE.'_todo_self':
136
+			case self::SUBJECT_OBJECT_UPDATE.'_todo_completed_self':
137
+			case self::SUBJECT_OBJECT_UPDATE.'_todo_needs_action_self':
138 138
 				return [
139 139
 					'calendar' => $this->generateLegacyCalendarParameter($event->getObjectId(), $parameters[1]),
140 140
 					'todo' => $this->generateObjectParameter($parameters[2]),
Please login to merge, or discard this patch.
apps/dav/lib/CalDAV/Activity/Provider/Calendar.php 2 patches
Indentation   +207 added lines, -207 removed lines patch added patch discarded remove patch
@@ -37,228 +37,228 @@
 block discarded – undo
37 37
 use OCP\L10N\IFactory;
38 38
 
39 39
 class Calendar extends Base {
40
-	public const SUBJECT_ADD = 'calendar_add';
41
-	public const SUBJECT_UPDATE = 'calendar_update';
42
-	public const SUBJECT_DELETE = 'calendar_delete';
43
-	public const SUBJECT_PUBLISH = 'calendar_publish';
44
-	public const SUBJECT_UNPUBLISH = 'calendar_unpublish';
45
-	public const SUBJECT_SHARE_USER = 'calendar_user_share';
46
-	public const SUBJECT_SHARE_GROUP = 'calendar_group_share';
47
-	public const SUBJECT_UNSHARE_USER = 'calendar_user_unshare';
48
-	public const SUBJECT_UNSHARE_GROUP = 'calendar_group_unshare';
40
+    public const SUBJECT_ADD = 'calendar_add';
41
+    public const SUBJECT_UPDATE = 'calendar_update';
42
+    public const SUBJECT_DELETE = 'calendar_delete';
43
+    public const SUBJECT_PUBLISH = 'calendar_publish';
44
+    public const SUBJECT_UNPUBLISH = 'calendar_unpublish';
45
+    public const SUBJECT_SHARE_USER = 'calendar_user_share';
46
+    public const SUBJECT_SHARE_GROUP = 'calendar_group_share';
47
+    public const SUBJECT_UNSHARE_USER = 'calendar_user_unshare';
48
+    public const SUBJECT_UNSHARE_GROUP = 'calendar_group_unshare';
49 49
 
50
-	/** @var IFactory */
51
-	protected $languageFactory;
50
+    /** @var IFactory */
51
+    protected $languageFactory;
52 52
 
53
-	/** @var IL10N */
54
-	protected $l;
53
+    /** @var IL10N */
54
+    protected $l;
55 55
 
56
-	/** @var IManager */
57
-	protected $activityManager;
56
+    /** @var IManager */
57
+    protected $activityManager;
58 58
 
59
-	/** @var IEventMerger */
60
-	protected $eventMerger;
59
+    /** @var IEventMerger */
60
+    protected $eventMerger;
61 61
 
62
-	/**
63
-	 * @param IFactory $languageFactory
64
-	 * @param IURLGenerator $url
65
-	 * @param IManager $activityManager
66
-	 * @param IUserManager $userManager
67
-	 * @param IGroupManager $groupManager
68
-	 * @param IEventMerger $eventMerger
69
-	 */
70
-	public function __construct(IFactory $languageFactory, IURLGenerator $url, IManager $activityManager, IUserManager $userManager, IGroupManager $groupManager, IEventMerger $eventMerger) {
71
-		parent::__construct($userManager, $groupManager, $url);
72
-		$this->languageFactory = $languageFactory;
73
-		$this->activityManager = $activityManager;
74
-		$this->eventMerger = $eventMerger;
75
-	}
62
+    /**
63
+     * @param IFactory $languageFactory
64
+     * @param IURLGenerator $url
65
+     * @param IManager $activityManager
66
+     * @param IUserManager $userManager
67
+     * @param IGroupManager $groupManager
68
+     * @param IEventMerger $eventMerger
69
+     */
70
+    public function __construct(IFactory $languageFactory, IURLGenerator $url, IManager $activityManager, IUserManager $userManager, IGroupManager $groupManager, IEventMerger $eventMerger) {
71
+        parent::__construct($userManager, $groupManager, $url);
72
+        $this->languageFactory = $languageFactory;
73
+        $this->activityManager = $activityManager;
74
+        $this->eventMerger = $eventMerger;
75
+    }
76 76
 
77
-	/**
78
-	 * @param string $language
79
-	 * @param IEvent $event
80
-	 * @param IEvent|null $previousEvent
81
-	 * @return IEvent
82
-	 * @throws \InvalidArgumentException
83
-	 * @since 11.0.0
84
-	 */
85
-	public function parse($language, IEvent $event, IEvent $previousEvent = null) {
86
-		if ($event->getApp() !== 'dav' || $event->getType() !== 'calendar') {
87
-			throw new \InvalidArgumentException();
88
-		}
77
+    /**
78
+     * @param string $language
79
+     * @param IEvent $event
80
+     * @param IEvent|null $previousEvent
81
+     * @return IEvent
82
+     * @throws \InvalidArgumentException
83
+     * @since 11.0.0
84
+     */
85
+    public function parse($language, IEvent $event, IEvent $previousEvent = null) {
86
+        if ($event->getApp() !== 'dav' || $event->getType() !== 'calendar') {
87
+            throw new \InvalidArgumentException();
88
+        }
89 89
 
90
-		$this->l = $this->languageFactory->get('dav', $language);
90
+        $this->l = $this->languageFactory->get('dav', $language);
91 91
 
92
-		if ($this->activityManager->getRequirePNG()) {
93
-			$event->setIcon($this->url->getAbsoluteURL($this->url->imagePath('core', 'places/calendar-dark.png')));
94
-		} else {
95
-			$event->setIcon($this->url->getAbsoluteURL($this->url->imagePath('core', 'places/calendar.svg')));
96
-		}
92
+        if ($this->activityManager->getRequirePNG()) {
93
+            $event->setIcon($this->url->getAbsoluteURL($this->url->imagePath('core', 'places/calendar-dark.png')));
94
+        } else {
95
+            $event->setIcon($this->url->getAbsoluteURL($this->url->imagePath('core', 'places/calendar.svg')));
96
+        }
97 97
 
98
-		if ($event->getSubject() === self::SUBJECT_ADD) {
99
-			$subject = $this->l->t('{actor} created calendar {calendar}');
100
-		} elseif ($event->getSubject() === self::SUBJECT_ADD . '_self') {
101
-			$subject = $this->l->t('You created calendar {calendar}');
102
-		} elseif ($event->getSubject() === self::SUBJECT_DELETE) {
103
-			$subject = $this->l->t('{actor} deleted calendar {calendar}');
104
-		} elseif ($event->getSubject() === self::SUBJECT_DELETE . '_self') {
105
-			$subject = $this->l->t('You deleted calendar {calendar}');
106
-		} elseif ($event->getSubject() === self::SUBJECT_UPDATE) {
107
-			$subject = $this->l->t('{actor} updated calendar {calendar}');
108
-		} elseif ($event->getSubject() === self::SUBJECT_UPDATE . '_self') {
109
-			$subject = $this->l->t('You updated calendar {calendar}');
110
-		} elseif ($event->getSubject() === self::SUBJECT_PUBLISH . '_self') {
111
-			$subject = $this->l->t('You shared calendar {calendar} as public link');
112
-		} elseif ($event->getSubject() === self::SUBJECT_UNPUBLISH . '_self') {
113
-			$subject = $this->l->t('You removed public link for calendar {calendar}');
114
-		} elseif ($event->getSubject() === self::SUBJECT_SHARE_USER) {
115
-			$subject = $this->l->t('{actor} shared calendar {calendar} with you');
116
-		} elseif ($event->getSubject() === self::SUBJECT_SHARE_USER . '_you') {
117
-			$subject = $this->l->t('You shared calendar {calendar} with {user}');
118
-		} elseif ($event->getSubject() === self::SUBJECT_SHARE_USER . '_by') {
119
-			$subject = $this->l->t('{actor} shared calendar {calendar} with {user}');
120
-		} elseif ($event->getSubject() === self::SUBJECT_UNSHARE_USER) {
121
-			$subject = $this->l->t('{actor} unshared calendar {calendar} from you');
122
-		} elseif ($event->getSubject() === self::SUBJECT_UNSHARE_USER . '_you') {
123
-			$subject = $this->l->t('You unshared calendar {calendar} from {user}');
124
-		} elseif ($event->getSubject() === self::SUBJECT_UNSHARE_USER . '_by') {
125
-			$subject = $this->l->t('{actor} unshared calendar {calendar} from {user}');
126
-		} elseif ($event->getSubject() === self::SUBJECT_UNSHARE_USER . '_self') {
127
-			$subject = $this->l->t('{actor} unshared calendar {calendar} from themselves');
128
-		} elseif ($event->getSubject() === self::SUBJECT_SHARE_GROUP . '_you') {
129
-			$subject = $this->l->t('You shared calendar {calendar} with group {group}');
130
-		} elseif ($event->getSubject() === self::SUBJECT_SHARE_GROUP . '_by') {
131
-			$subject = $this->l->t('{actor} shared calendar {calendar} with group {group}');
132
-		} elseif ($event->getSubject() === self::SUBJECT_UNSHARE_GROUP . '_you') {
133
-			$subject = $this->l->t('You unshared calendar {calendar} from group {group}');
134
-		} elseif ($event->getSubject() === self::SUBJECT_UNSHARE_GROUP . '_by') {
135
-			$subject = $this->l->t('{actor} unshared calendar {calendar} from group {group}');
136
-		} else {
137
-			throw new \InvalidArgumentException();
138
-		}
98
+        if ($event->getSubject() === self::SUBJECT_ADD) {
99
+            $subject = $this->l->t('{actor} created calendar {calendar}');
100
+        } elseif ($event->getSubject() === self::SUBJECT_ADD . '_self') {
101
+            $subject = $this->l->t('You created calendar {calendar}');
102
+        } elseif ($event->getSubject() === self::SUBJECT_DELETE) {
103
+            $subject = $this->l->t('{actor} deleted calendar {calendar}');
104
+        } elseif ($event->getSubject() === self::SUBJECT_DELETE . '_self') {
105
+            $subject = $this->l->t('You deleted calendar {calendar}');
106
+        } elseif ($event->getSubject() === self::SUBJECT_UPDATE) {
107
+            $subject = $this->l->t('{actor} updated calendar {calendar}');
108
+        } elseif ($event->getSubject() === self::SUBJECT_UPDATE . '_self') {
109
+            $subject = $this->l->t('You updated calendar {calendar}');
110
+        } elseif ($event->getSubject() === self::SUBJECT_PUBLISH . '_self') {
111
+            $subject = $this->l->t('You shared calendar {calendar} as public link');
112
+        } elseif ($event->getSubject() === self::SUBJECT_UNPUBLISH . '_self') {
113
+            $subject = $this->l->t('You removed public link for calendar {calendar}');
114
+        } elseif ($event->getSubject() === self::SUBJECT_SHARE_USER) {
115
+            $subject = $this->l->t('{actor} shared calendar {calendar} with you');
116
+        } elseif ($event->getSubject() === self::SUBJECT_SHARE_USER . '_you') {
117
+            $subject = $this->l->t('You shared calendar {calendar} with {user}');
118
+        } elseif ($event->getSubject() === self::SUBJECT_SHARE_USER . '_by') {
119
+            $subject = $this->l->t('{actor} shared calendar {calendar} with {user}');
120
+        } elseif ($event->getSubject() === self::SUBJECT_UNSHARE_USER) {
121
+            $subject = $this->l->t('{actor} unshared calendar {calendar} from you');
122
+        } elseif ($event->getSubject() === self::SUBJECT_UNSHARE_USER . '_you') {
123
+            $subject = $this->l->t('You unshared calendar {calendar} from {user}');
124
+        } elseif ($event->getSubject() === self::SUBJECT_UNSHARE_USER . '_by') {
125
+            $subject = $this->l->t('{actor} unshared calendar {calendar} from {user}');
126
+        } elseif ($event->getSubject() === self::SUBJECT_UNSHARE_USER . '_self') {
127
+            $subject = $this->l->t('{actor} unshared calendar {calendar} from themselves');
128
+        } elseif ($event->getSubject() === self::SUBJECT_SHARE_GROUP . '_you') {
129
+            $subject = $this->l->t('You shared calendar {calendar} with group {group}');
130
+        } elseif ($event->getSubject() === self::SUBJECT_SHARE_GROUP . '_by') {
131
+            $subject = $this->l->t('{actor} shared calendar {calendar} with group {group}');
132
+        } elseif ($event->getSubject() === self::SUBJECT_UNSHARE_GROUP . '_you') {
133
+            $subject = $this->l->t('You unshared calendar {calendar} from group {group}');
134
+        } elseif ($event->getSubject() === self::SUBJECT_UNSHARE_GROUP . '_by') {
135
+            $subject = $this->l->t('{actor} unshared calendar {calendar} from group {group}');
136
+        } else {
137
+            throw new \InvalidArgumentException();
138
+        }
139 139
 
140
-		$parsedParameters = $this->getParameters($event);
141
-		$this->setSubjects($event, $subject, $parsedParameters);
140
+        $parsedParameters = $this->getParameters($event);
141
+        $this->setSubjects($event, $subject, $parsedParameters);
142 142
 
143
-		$event = $this->eventMerger->mergeEvents('calendar', $event, $previousEvent);
143
+        $event = $this->eventMerger->mergeEvents('calendar', $event, $previousEvent);
144 144
 
145
-		if ($event->getChildEvent() === null) {
146
-			if (isset($parsedParameters['user'])) {
147
-				// Couldn't group by calendar, maybe we can group by users
148
-				$event = $this->eventMerger->mergeEvents('user', $event, $previousEvent);
149
-			} elseif (isset($parsedParameters['group'])) {
150
-				// Couldn't group by calendar, maybe we can group by groups
151
-				$event = $this->eventMerger->mergeEvents('group', $event, $previousEvent);
152
-			}
153
-		}
145
+        if ($event->getChildEvent() === null) {
146
+            if (isset($parsedParameters['user'])) {
147
+                // Couldn't group by calendar, maybe we can group by users
148
+                $event = $this->eventMerger->mergeEvents('user', $event, $previousEvent);
149
+            } elseif (isset($parsedParameters['group'])) {
150
+                // Couldn't group by calendar, maybe we can group by groups
151
+                $event = $this->eventMerger->mergeEvents('group', $event, $previousEvent);
152
+            }
153
+        }
154 154
 
155
-		return $event;
156
-	}
155
+        return $event;
156
+    }
157 157
 
158
-	/**
159
-	 * @param IEvent $event
160
-	 * @return array
161
-	 */
162
-	protected function getParameters(IEvent $event) {
163
-		$subject = $event->getSubject();
164
-		$parameters = $event->getSubjectParameters();
158
+    /**
159
+     * @param IEvent $event
160
+     * @return array
161
+     */
162
+    protected function getParameters(IEvent $event) {
163
+        $subject = $event->getSubject();
164
+        $parameters = $event->getSubjectParameters();
165 165
 
166
-		// Nextcloud 13+
167
-		if (isset($parameters['calendar'])) {
168
-			switch ($subject) {
169
-				case self::SUBJECT_ADD:
170
-				case self::SUBJECT_ADD . '_self':
171
-				case self::SUBJECT_DELETE:
172
-				case self::SUBJECT_DELETE . '_self':
173
-				case self::SUBJECT_UPDATE:
174
-				case self::SUBJECT_UPDATE . '_self':
175
-				case self::SUBJECT_PUBLISH . '_self':
176
-				case self::SUBJECT_UNPUBLISH . '_self':
177
-				case self::SUBJECT_SHARE_USER:
178
-				case self::SUBJECT_UNSHARE_USER:
179
-				case self::SUBJECT_UNSHARE_USER . '_self':
180
-					return [
181
-						'actor' => $this->generateUserParameter($parameters['actor']),
182
-						'calendar' => $this->generateCalendarParameter($parameters['calendar'], $this->l),
183
-					];
184
-				case self::SUBJECT_SHARE_USER . '_you':
185
-				case self::SUBJECT_UNSHARE_USER . '_you':
186
-					return [
187
-						'calendar' => $this->generateCalendarParameter($parameters['calendar'], $this->l),
188
-						'user' => $this->generateUserParameter($parameters['user']),
189
-					];
190
-				case self::SUBJECT_SHARE_USER . '_by':
191
-				case self::SUBJECT_UNSHARE_USER . '_by':
192
-					return [
193
-						'actor' => $this->generateUserParameter($parameters['actor']),
194
-						'calendar' => $this->generateCalendarParameter($parameters['calendar'], $this->l),
195
-						'user' => $this->generateUserParameter($parameters['user']),
196
-					];
197
-				case self::SUBJECT_SHARE_GROUP . '_you':
198
-				case self::SUBJECT_UNSHARE_GROUP . '_you':
199
-					return [
200
-						'calendar' => $this->generateCalendarParameter($parameters['calendar'], $this->l),
201
-						'group' => $this->generateGroupParameter($parameters['group']),
202
-					];
203
-				case self::SUBJECT_SHARE_GROUP . '_by':
204
-				case self::SUBJECT_UNSHARE_GROUP . '_by':
205
-					return [
206
-						'actor' => $this->generateUserParameter($parameters['actor']),
207
-						'calendar' => $this->generateCalendarParameter($parameters['calendar'], $this->l),
208
-						'group' => $this->generateGroupParameter($parameters['group']),
209
-					];
210
-			}
211
-		}
166
+        // Nextcloud 13+
167
+        if (isset($parameters['calendar'])) {
168
+            switch ($subject) {
169
+                case self::SUBJECT_ADD:
170
+                case self::SUBJECT_ADD . '_self':
171
+                case self::SUBJECT_DELETE:
172
+                case self::SUBJECT_DELETE . '_self':
173
+                case self::SUBJECT_UPDATE:
174
+                case self::SUBJECT_UPDATE . '_self':
175
+                case self::SUBJECT_PUBLISH . '_self':
176
+                case self::SUBJECT_UNPUBLISH . '_self':
177
+                case self::SUBJECT_SHARE_USER:
178
+                case self::SUBJECT_UNSHARE_USER:
179
+                case self::SUBJECT_UNSHARE_USER . '_self':
180
+                    return [
181
+                        'actor' => $this->generateUserParameter($parameters['actor']),
182
+                        'calendar' => $this->generateCalendarParameter($parameters['calendar'], $this->l),
183
+                    ];
184
+                case self::SUBJECT_SHARE_USER . '_you':
185
+                case self::SUBJECT_UNSHARE_USER . '_you':
186
+                    return [
187
+                        'calendar' => $this->generateCalendarParameter($parameters['calendar'], $this->l),
188
+                        'user' => $this->generateUserParameter($parameters['user']),
189
+                    ];
190
+                case self::SUBJECT_SHARE_USER . '_by':
191
+                case self::SUBJECT_UNSHARE_USER . '_by':
192
+                    return [
193
+                        'actor' => $this->generateUserParameter($parameters['actor']),
194
+                        'calendar' => $this->generateCalendarParameter($parameters['calendar'], $this->l),
195
+                        'user' => $this->generateUserParameter($parameters['user']),
196
+                    ];
197
+                case self::SUBJECT_SHARE_GROUP . '_you':
198
+                case self::SUBJECT_UNSHARE_GROUP . '_you':
199
+                    return [
200
+                        'calendar' => $this->generateCalendarParameter($parameters['calendar'], $this->l),
201
+                        'group' => $this->generateGroupParameter($parameters['group']),
202
+                    ];
203
+                case self::SUBJECT_SHARE_GROUP . '_by':
204
+                case self::SUBJECT_UNSHARE_GROUP . '_by':
205
+                    return [
206
+                        'actor' => $this->generateUserParameter($parameters['actor']),
207
+                        'calendar' => $this->generateCalendarParameter($parameters['calendar'], $this->l),
208
+                        'group' => $this->generateGroupParameter($parameters['group']),
209
+                    ];
210
+            }
211
+        }
212 212
 
213
-		// Legacy - Do NOT Remove unless necessary
214
-		// Removing this will break parsing of activities that were created on
215
-		// Nextcloud 12, so we should keep this as long as it's acceptable.
216
-		// Otherwise if people upgrade over multiple releases in a short period,
217
-		// they will get the dead entries in their stream.
218
-		switch ($subject) {
219
-			case self::SUBJECT_ADD:
220
-			case self::SUBJECT_ADD . '_self':
221
-			case self::SUBJECT_DELETE:
222
-			case self::SUBJECT_DELETE . '_self':
223
-			case self::SUBJECT_UPDATE:
224
-			case self::SUBJECT_UPDATE . '_self':
225
-			case self::SUBJECT_PUBLISH . '_self':
226
-			case self::SUBJECT_UNPUBLISH . '_self':
227
-			case self::SUBJECT_SHARE_USER:
228
-			case self::SUBJECT_UNSHARE_USER:
229
-			case self::SUBJECT_UNSHARE_USER . '_self':
230
-				return [
231
-					'actor' => $this->generateUserParameter($parameters[0]),
232
-					'calendar' => $this->generateLegacyCalendarParameter($event->getObjectId(), $parameters[1]),
233
-				];
234
-			case self::SUBJECT_SHARE_USER . '_you':
235
-			case self::SUBJECT_UNSHARE_USER . '_you':
236
-				return [
237
-					'user' => $this->generateUserParameter($parameters[0]),
238
-					'calendar' => $this->generateLegacyCalendarParameter($event->getObjectId(), $parameters[1]),
239
-				];
240
-			case self::SUBJECT_SHARE_USER . '_by':
241
-			case self::SUBJECT_UNSHARE_USER . '_by':
242
-				return [
243
-					'user' => $this->generateUserParameter($parameters[0]),
244
-					'calendar' => $this->generateLegacyCalendarParameter($event->getObjectId(), $parameters[1]),
245
-					'actor' => $this->generateUserParameter($parameters[2]),
246
-				];
247
-			case self::SUBJECT_SHARE_GROUP . '_you':
248
-			case self::SUBJECT_UNSHARE_GROUP . '_you':
249
-				return [
250
-					'group' => $this->generateGroupParameter($parameters[0]),
251
-					'calendar' => $this->generateLegacyCalendarParameter($event->getObjectId(), $parameters[1]),
252
-				];
253
-			case self::SUBJECT_SHARE_GROUP . '_by':
254
-			case self::SUBJECT_UNSHARE_GROUP . '_by':
255
-				return [
256
-					'group' => $this->generateGroupParameter($parameters[0]),
257
-					'calendar' => $this->generateLegacyCalendarParameter($event->getObjectId(), $parameters[1]),
258
-					'actor' => $this->generateUserParameter($parameters[2]),
259
-				];
260
-		}
213
+        // Legacy - Do NOT Remove unless necessary
214
+        // Removing this will break parsing of activities that were created on
215
+        // Nextcloud 12, so we should keep this as long as it's acceptable.
216
+        // Otherwise if people upgrade over multiple releases in a short period,
217
+        // they will get the dead entries in their stream.
218
+        switch ($subject) {
219
+            case self::SUBJECT_ADD:
220
+            case self::SUBJECT_ADD . '_self':
221
+            case self::SUBJECT_DELETE:
222
+            case self::SUBJECT_DELETE . '_self':
223
+            case self::SUBJECT_UPDATE:
224
+            case self::SUBJECT_UPDATE . '_self':
225
+            case self::SUBJECT_PUBLISH . '_self':
226
+            case self::SUBJECT_UNPUBLISH . '_self':
227
+            case self::SUBJECT_SHARE_USER:
228
+            case self::SUBJECT_UNSHARE_USER:
229
+            case self::SUBJECT_UNSHARE_USER . '_self':
230
+                return [
231
+                    'actor' => $this->generateUserParameter($parameters[0]),
232
+                    'calendar' => $this->generateLegacyCalendarParameter($event->getObjectId(), $parameters[1]),
233
+                ];
234
+            case self::SUBJECT_SHARE_USER . '_you':
235
+            case self::SUBJECT_UNSHARE_USER . '_you':
236
+                return [
237
+                    'user' => $this->generateUserParameter($parameters[0]),
238
+                    'calendar' => $this->generateLegacyCalendarParameter($event->getObjectId(), $parameters[1]),
239
+                ];
240
+            case self::SUBJECT_SHARE_USER . '_by':
241
+            case self::SUBJECT_UNSHARE_USER . '_by':
242
+                return [
243
+                    'user' => $this->generateUserParameter($parameters[0]),
244
+                    'calendar' => $this->generateLegacyCalendarParameter($event->getObjectId(), $parameters[1]),
245
+                    'actor' => $this->generateUserParameter($parameters[2]),
246
+                ];
247
+            case self::SUBJECT_SHARE_GROUP . '_you':
248
+            case self::SUBJECT_UNSHARE_GROUP . '_you':
249
+                return [
250
+                    'group' => $this->generateGroupParameter($parameters[0]),
251
+                    'calendar' => $this->generateLegacyCalendarParameter($event->getObjectId(), $parameters[1]),
252
+                ];
253
+            case self::SUBJECT_SHARE_GROUP . '_by':
254
+            case self::SUBJECT_UNSHARE_GROUP . '_by':
255
+                return [
256
+                    'group' => $this->generateGroupParameter($parameters[0]),
257
+                    'calendar' => $this->generateLegacyCalendarParameter($event->getObjectId(), $parameters[1]),
258
+                    'actor' => $this->generateUserParameter($parameters[2]),
259
+                ];
260
+        }
261 261
 
262
-		throw new \InvalidArgumentException();
263
-	}
262
+        throw new \InvalidArgumentException();
263
+    }
264 264
 }
Please login to merge, or discard this patch.
Spacing   +42 added lines, -42 removed lines patch added patch discarded remove patch
@@ -97,41 +97,41 @@  discard block
 block discarded – undo
97 97
 
98 98
 		if ($event->getSubject() === self::SUBJECT_ADD) {
99 99
 			$subject = $this->l->t('{actor} created calendar {calendar}');
100
-		} elseif ($event->getSubject() === self::SUBJECT_ADD . '_self') {
100
+		} elseif ($event->getSubject() === self::SUBJECT_ADD.'_self') {
101 101
 			$subject = $this->l->t('You created calendar {calendar}');
102 102
 		} elseif ($event->getSubject() === self::SUBJECT_DELETE) {
103 103
 			$subject = $this->l->t('{actor} deleted calendar {calendar}');
104
-		} elseif ($event->getSubject() === self::SUBJECT_DELETE . '_self') {
104
+		} elseif ($event->getSubject() === self::SUBJECT_DELETE.'_self') {
105 105
 			$subject = $this->l->t('You deleted calendar {calendar}');
106 106
 		} elseif ($event->getSubject() === self::SUBJECT_UPDATE) {
107 107
 			$subject = $this->l->t('{actor} updated calendar {calendar}');
108
-		} elseif ($event->getSubject() === self::SUBJECT_UPDATE . '_self') {
108
+		} elseif ($event->getSubject() === self::SUBJECT_UPDATE.'_self') {
109 109
 			$subject = $this->l->t('You updated calendar {calendar}');
110
-		} elseif ($event->getSubject() === self::SUBJECT_PUBLISH . '_self') {
110
+		} elseif ($event->getSubject() === self::SUBJECT_PUBLISH.'_self') {
111 111
 			$subject = $this->l->t('You shared calendar {calendar} as public link');
112
-		} elseif ($event->getSubject() === self::SUBJECT_UNPUBLISH . '_self') {
112
+		} elseif ($event->getSubject() === self::SUBJECT_UNPUBLISH.'_self') {
113 113
 			$subject = $this->l->t('You removed public link for calendar {calendar}');
114 114
 		} elseif ($event->getSubject() === self::SUBJECT_SHARE_USER) {
115 115
 			$subject = $this->l->t('{actor} shared calendar {calendar} with you');
116
-		} elseif ($event->getSubject() === self::SUBJECT_SHARE_USER . '_you') {
116
+		} elseif ($event->getSubject() === self::SUBJECT_SHARE_USER.'_you') {
117 117
 			$subject = $this->l->t('You shared calendar {calendar} with {user}');
118
-		} elseif ($event->getSubject() === self::SUBJECT_SHARE_USER . '_by') {
118
+		} elseif ($event->getSubject() === self::SUBJECT_SHARE_USER.'_by') {
119 119
 			$subject = $this->l->t('{actor} shared calendar {calendar} with {user}');
120 120
 		} elseif ($event->getSubject() === self::SUBJECT_UNSHARE_USER) {
121 121
 			$subject = $this->l->t('{actor} unshared calendar {calendar} from you');
122
-		} elseif ($event->getSubject() === self::SUBJECT_UNSHARE_USER . '_you') {
122
+		} elseif ($event->getSubject() === self::SUBJECT_UNSHARE_USER.'_you') {
123 123
 			$subject = $this->l->t('You unshared calendar {calendar} from {user}');
124
-		} elseif ($event->getSubject() === self::SUBJECT_UNSHARE_USER . '_by') {
124
+		} elseif ($event->getSubject() === self::SUBJECT_UNSHARE_USER.'_by') {
125 125
 			$subject = $this->l->t('{actor} unshared calendar {calendar} from {user}');
126
-		} elseif ($event->getSubject() === self::SUBJECT_UNSHARE_USER . '_self') {
126
+		} elseif ($event->getSubject() === self::SUBJECT_UNSHARE_USER.'_self') {
127 127
 			$subject = $this->l->t('{actor} unshared calendar {calendar} from themselves');
128
-		} elseif ($event->getSubject() === self::SUBJECT_SHARE_GROUP . '_you') {
128
+		} elseif ($event->getSubject() === self::SUBJECT_SHARE_GROUP.'_you') {
129 129
 			$subject = $this->l->t('You shared calendar {calendar} with group {group}');
130
-		} elseif ($event->getSubject() === self::SUBJECT_SHARE_GROUP . '_by') {
130
+		} elseif ($event->getSubject() === self::SUBJECT_SHARE_GROUP.'_by') {
131 131
 			$subject = $this->l->t('{actor} shared calendar {calendar} with group {group}');
132
-		} elseif ($event->getSubject() === self::SUBJECT_UNSHARE_GROUP . '_you') {
132
+		} elseif ($event->getSubject() === self::SUBJECT_UNSHARE_GROUP.'_you') {
133 133
 			$subject = $this->l->t('You unshared calendar {calendar} from group {group}');
134
-		} elseif ($event->getSubject() === self::SUBJECT_UNSHARE_GROUP . '_by') {
134
+		} elseif ($event->getSubject() === self::SUBJECT_UNSHARE_GROUP.'_by') {
135 135
 			$subject = $this->l->t('{actor} unshared calendar {calendar} from group {group}');
136 136
 		} else {
137 137
 			throw new \InvalidArgumentException();
@@ -167,41 +167,41 @@  discard block
 block discarded – undo
167 167
 		if (isset($parameters['calendar'])) {
168 168
 			switch ($subject) {
169 169
 				case self::SUBJECT_ADD:
170
-				case self::SUBJECT_ADD . '_self':
170
+				case self::SUBJECT_ADD.'_self':
171 171
 				case self::SUBJECT_DELETE:
172
-				case self::SUBJECT_DELETE . '_self':
172
+				case self::SUBJECT_DELETE.'_self':
173 173
 				case self::SUBJECT_UPDATE:
174
-				case self::SUBJECT_UPDATE . '_self':
175
-				case self::SUBJECT_PUBLISH . '_self':
176
-				case self::SUBJECT_UNPUBLISH . '_self':
174
+				case self::SUBJECT_UPDATE.'_self':
175
+				case self::SUBJECT_PUBLISH.'_self':
176
+				case self::SUBJECT_UNPUBLISH.'_self':
177 177
 				case self::SUBJECT_SHARE_USER:
178 178
 				case self::SUBJECT_UNSHARE_USER:
179
-				case self::SUBJECT_UNSHARE_USER . '_self':
179
+				case self::SUBJECT_UNSHARE_USER.'_self':
180 180
 					return [
181 181
 						'actor' => $this->generateUserParameter($parameters['actor']),
182 182
 						'calendar' => $this->generateCalendarParameter($parameters['calendar'], $this->l),
183 183
 					];
184
-				case self::SUBJECT_SHARE_USER . '_you':
185
-				case self::SUBJECT_UNSHARE_USER . '_you':
184
+				case self::SUBJECT_SHARE_USER.'_you':
185
+				case self::SUBJECT_UNSHARE_USER.'_you':
186 186
 					return [
187 187
 						'calendar' => $this->generateCalendarParameter($parameters['calendar'], $this->l),
188 188
 						'user' => $this->generateUserParameter($parameters['user']),
189 189
 					];
190
-				case self::SUBJECT_SHARE_USER . '_by':
191
-				case self::SUBJECT_UNSHARE_USER . '_by':
190
+				case self::SUBJECT_SHARE_USER.'_by':
191
+				case self::SUBJECT_UNSHARE_USER.'_by':
192 192
 					return [
193 193
 						'actor' => $this->generateUserParameter($parameters['actor']),
194 194
 						'calendar' => $this->generateCalendarParameter($parameters['calendar'], $this->l),
195 195
 						'user' => $this->generateUserParameter($parameters['user']),
196 196
 					];
197
-				case self::SUBJECT_SHARE_GROUP . '_you':
198
-				case self::SUBJECT_UNSHARE_GROUP . '_you':
197
+				case self::SUBJECT_SHARE_GROUP.'_you':
198
+				case self::SUBJECT_UNSHARE_GROUP.'_you':
199 199
 					return [
200 200
 						'calendar' => $this->generateCalendarParameter($parameters['calendar'], $this->l),
201 201
 						'group' => $this->generateGroupParameter($parameters['group']),
202 202
 					];
203
-				case self::SUBJECT_SHARE_GROUP . '_by':
204
-				case self::SUBJECT_UNSHARE_GROUP . '_by':
203
+				case self::SUBJECT_SHARE_GROUP.'_by':
204
+				case self::SUBJECT_UNSHARE_GROUP.'_by':
205 205
 					return [
206 206
 						'actor' => $this->generateUserParameter($parameters['actor']),
207 207
 						'calendar' => $this->generateCalendarParameter($parameters['calendar'], $this->l),
@@ -217,41 +217,41 @@  discard block
 block discarded – undo
217 217
 		// they will get the dead entries in their stream.
218 218
 		switch ($subject) {
219 219
 			case self::SUBJECT_ADD:
220
-			case self::SUBJECT_ADD . '_self':
220
+			case self::SUBJECT_ADD.'_self':
221 221
 			case self::SUBJECT_DELETE:
222
-			case self::SUBJECT_DELETE . '_self':
222
+			case self::SUBJECT_DELETE.'_self':
223 223
 			case self::SUBJECT_UPDATE:
224
-			case self::SUBJECT_UPDATE . '_self':
225
-			case self::SUBJECT_PUBLISH . '_self':
226
-			case self::SUBJECT_UNPUBLISH . '_self':
224
+			case self::SUBJECT_UPDATE.'_self':
225
+			case self::SUBJECT_PUBLISH.'_self':
226
+			case self::SUBJECT_UNPUBLISH.'_self':
227 227
 			case self::SUBJECT_SHARE_USER:
228 228
 			case self::SUBJECT_UNSHARE_USER:
229
-			case self::SUBJECT_UNSHARE_USER . '_self':
229
+			case self::SUBJECT_UNSHARE_USER.'_self':
230 230
 				return [
231 231
 					'actor' => $this->generateUserParameter($parameters[0]),
232 232
 					'calendar' => $this->generateLegacyCalendarParameter($event->getObjectId(), $parameters[1]),
233 233
 				];
234
-			case self::SUBJECT_SHARE_USER . '_you':
235
-			case self::SUBJECT_UNSHARE_USER . '_you':
234
+			case self::SUBJECT_SHARE_USER.'_you':
235
+			case self::SUBJECT_UNSHARE_USER.'_you':
236 236
 				return [
237 237
 					'user' => $this->generateUserParameter($parameters[0]),
238 238
 					'calendar' => $this->generateLegacyCalendarParameter($event->getObjectId(), $parameters[1]),
239 239
 				];
240
-			case self::SUBJECT_SHARE_USER . '_by':
241
-			case self::SUBJECT_UNSHARE_USER . '_by':
240
+			case self::SUBJECT_SHARE_USER.'_by':
241
+			case self::SUBJECT_UNSHARE_USER.'_by':
242 242
 				return [
243 243
 					'user' => $this->generateUserParameter($parameters[0]),
244 244
 					'calendar' => $this->generateLegacyCalendarParameter($event->getObjectId(), $parameters[1]),
245 245
 					'actor' => $this->generateUserParameter($parameters[2]),
246 246
 				];
247
-			case self::SUBJECT_SHARE_GROUP . '_you':
248
-			case self::SUBJECT_UNSHARE_GROUP . '_you':
247
+			case self::SUBJECT_SHARE_GROUP.'_you':
248
+			case self::SUBJECT_UNSHARE_GROUP.'_you':
249 249
 				return [
250 250
 					'group' => $this->generateGroupParameter($parameters[0]),
251 251
 					'calendar' => $this->generateLegacyCalendarParameter($event->getObjectId(), $parameters[1]),
252 252
 				];
253
-			case self::SUBJECT_SHARE_GROUP . '_by':
254
-			case self::SUBJECT_UNSHARE_GROUP . '_by':
253
+			case self::SUBJECT_SHARE_GROUP.'_by':
254
+			case self::SUBJECT_UNSHARE_GROUP.'_by':
255 255
 				return [
256 256
 					'group' => $this->generateGroupParameter($parameters[0]),
257 257
 					'calendar' => $this->generateLegacyCalendarParameter($event->getObjectId(), $parameters[1]),
Please login to merge, or discard this patch.
apps/files_sharing/lib/Controller/ShareesAPIController.php 1 patch
Indentation   +379 added lines, -379 removed lines patch added patch discarded remove patch
@@ -57,383 +57,383 @@
 block discarded – undo
57 57
 
58 58
 class ShareesAPIController extends OCSController {
59 59
 
60
-	/** @var string */
61
-	protected $userId;
62
-
63
-	/** @var IConfig */
64
-	protected $config;
65
-
66
-	/** @var IURLGenerator */
67
-	protected $urlGenerator;
68
-
69
-	/** @var IManager */
70
-	protected $shareManager;
71
-
72
-	/** @var int */
73
-	protected $offset = 0;
74
-
75
-	/** @var int */
76
-	protected $limit = 10;
77
-
78
-	/** @var array */
79
-	protected $result = [
80
-		'exact' => [
81
-			'users' => [],
82
-			'groups' => [],
83
-			'remotes' => [],
84
-			'remote_groups' => [],
85
-			'emails' => [],
86
-			'circles' => [],
87
-			'rooms' => [],
88
-			'deck' => [],
89
-		],
90
-		'users' => [],
91
-		'groups' => [],
92
-		'remotes' => [],
93
-		'remote_groups' => [],
94
-		'emails' => [],
95
-		'lookup' => [],
96
-		'circles' => [],
97
-		'rooms' => [],
98
-		'deck' => [],
99
-		'lookupEnabled' => false,
100
-	];
101
-
102
-	protected $reachedEndFor = [];
103
-	/** @var ISearch */
104
-	private $collaboratorSearch;
105
-
106
-	/**
107
-	 * @param string $UserId
108
-	 * @param string $appName
109
-	 * @param IRequest $request
110
-	 * @param IConfig $config
111
-	 * @param IURLGenerator $urlGenerator
112
-	 * @param IManager $shareManager
113
-	 * @param ISearch $collaboratorSearch
114
-	 */
115
-	public function __construct(
116
-		$UserId,
117
-		string $appName,
118
-		IRequest $request,
119
-		IConfig $config,
120
-		IURLGenerator $urlGenerator,
121
-		IManager $shareManager,
122
-		ISearch $collaboratorSearch
123
-	) {
124
-		parent::__construct($appName, $request);
125
-		$this->userId = $UserId;
126
-		$this->config = $config;
127
-		$this->urlGenerator = $urlGenerator;
128
-		$this->shareManager = $shareManager;
129
-		$this->collaboratorSearch = $collaboratorSearch;
130
-	}
131
-
132
-	/**
133
-	 * @NoAdminRequired
134
-	 *
135
-	 * @param string $search
136
-	 * @param string $itemType
137
-	 * @param int $page
138
-	 * @param int $perPage
139
-	 * @param int|int[] $shareType
140
-	 * @param bool $lookup
141
-	 * @return DataResponse
142
-	 * @throws OCSBadRequestException
143
-	 */
144
-	public function search(string $search = '', string $itemType = null, int $page = 1, int $perPage = 200, $shareType = null, bool $lookup = true): DataResponse {
145
-
146
-		// only search for string larger than a given threshold
147
-		$threshold = (int)$this->config->getSystemValue('sharing.minSearchStringLength', 0);
148
-		if (strlen($search) < $threshold) {
149
-			return new DataResponse($this->result);
150
-		}
151
-
152
-		// never return more than the max. number of results configured in the config.php
153
-		$maxResults = $this->config->getSystemValueInt('sharing.maxAutocompleteResults', Constants::SHARING_MAX_AUTOCOMPLETE_RESULTS_DEFAULT);
154
-		if ($maxResults > 0) {
155
-			$perPage = min($perPage, $maxResults);
156
-		}
157
-		if ($perPage <= 0) {
158
-			throw new OCSBadRequestException('Invalid perPage argument');
159
-		}
160
-		if ($page <= 0) {
161
-			throw new OCSBadRequestException('Invalid page');
162
-		}
163
-
164
-		$shareTypes = [
165
-			IShare::TYPE_USER,
166
-		];
167
-
168
-		if ($itemType === null) {
169
-			throw new OCSBadRequestException('Missing itemType');
170
-		} elseif ($itemType === 'file' || $itemType === 'folder') {
171
-			if ($this->shareManager->allowGroupSharing()) {
172
-				$shareTypes[] = IShare::TYPE_GROUP;
173
-			}
174
-
175
-			if ($this->isRemoteSharingAllowed($itemType)) {
176
-				$shareTypes[] = IShare::TYPE_REMOTE;
177
-			}
178
-
179
-			if ($this->isRemoteGroupSharingAllowed($itemType)) {
180
-				$shareTypes[] = IShare::TYPE_REMOTE_GROUP;
181
-			}
182
-
183
-			if ($this->shareManager->shareProviderExists(IShare::TYPE_EMAIL)) {
184
-				$shareTypes[] = IShare::TYPE_EMAIL;
185
-			}
186
-
187
-			if ($this->shareManager->shareProviderExists(IShare::TYPE_ROOM)) {
188
-				$shareTypes[] = IShare::TYPE_ROOM;
189
-			}
190
-
191
-			if ($this->shareManager->shareProviderExists(IShare::TYPE_DECK)) {
192
-				$shareTypes[] = IShare::TYPE_DECK;
193
-			}
194
-		} else {
195
-			$shareTypes[] = IShare::TYPE_GROUP;
196
-			$shareTypes[] = IShare::TYPE_EMAIL;
197
-		}
198
-
199
-		// FIXME: DI
200
-		if (\OC::$server->getAppManager()->isEnabledForUser('circles') && class_exists('\OCA\Circles\ShareByCircleProvider')) {
201
-			$shareTypes[] = IShare::TYPE_CIRCLE;
202
-		}
203
-
204
-		if ($this->shareManager->shareProviderExists(IShare::TYPE_DECK)) {
205
-			$shareTypes[] = IShare::TYPE_DECK;
206
-		}
207
-
208
-		if ($shareType !== null && is_array($shareType)) {
209
-			$shareTypes = array_intersect($shareTypes, $shareType);
210
-		} elseif (is_numeric($shareType)) {
211
-			$shareTypes = array_intersect($shareTypes, [(int) $shareType]);
212
-		}
213
-		sort($shareTypes);
214
-
215
-		$this->limit = $perPage;
216
-		$this->offset = $perPage * ($page - 1);
217
-
218
-		// In global scale mode we always search the loogup server
219
-		if ($this->config->getSystemValueBool('gs.enabled', false)) {
220
-			$lookup = true;
221
-			$this->result['lookupEnabled'] = true;
222
-		} else {
223
-			$this->result['lookupEnabled'] = $this->config->getAppValue('files_sharing', 'lookupServerEnabled', 'yes') === 'yes';
224
-		}
225
-
226
-		list($result, $hasMoreResults) = $this->collaboratorSearch->search($search, $shareTypes, $lookup, $this->limit, $this->offset);
227
-
228
-		// extra treatment for 'exact' subarray, with a single merge expected keys might be lost
229
-		if (isset($result['exact'])) {
230
-			$result['exact'] = array_merge($this->result['exact'], $result['exact']);
231
-		}
232
-		$this->result = array_merge($this->result, $result);
233
-		$response = new DataResponse($this->result);
234
-
235
-		if ($hasMoreResults) {
236
-			$response->addHeader('Link', $this->getPaginationLink($page, [
237
-				'search' => $search,
238
-				'itemType' => $itemType,
239
-				'shareType' => $shareTypes,
240
-				'perPage' => $perPage,
241
-			]));
242
-		}
243
-
244
-		return $response;
245
-	}
246
-
247
-	/**
248
-	 * @param string $user
249
-	 * @param int $shareType
250
-	 *
251
-	 * @return Generator<array<string>>
252
-	 */
253
-	private function getAllShareesByType(string $user, int $shareType): Generator {
254
-		$offset = 0;
255
-		$pageSize = 50;
256
-
257
-		while (count($page = $this->shareManager->getSharesBy(
258
-			$user,
259
-			$shareType,
260
-			null,
261
-			false,
262
-			$pageSize,
263
-			$offset
264
-		))) {
265
-			foreach ($page as $share) {
266
-				yield [$share->getSharedWith(), $share->getSharedWithDisplayName() ?? $share->getSharedWith()];
267
-			}
268
-
269
-			$offset += $pageSize;
270
-		}
271
-	}
272
-
273
-	private function sortShareesByFrequency(array $sharees): array {
274
-		usort($sharees, function (array $s1, array $s2) {
275
-			return $s2['count'] - $s1['count'];
276
-		});
277
-		return $sharees;
278
-	}
279
-
280
-	private $searchResultTypeMap = [
281
-		IShare::TYPE_USER => 'users',
282
-		IShare::TYPE_GROUP => 'groups',
283
-		IShare::TYPE_REMOTE => 'remotes',
284
-		IShare::TYPE_REMOTE_GROUP => 'remote_groups',
285
-		IShare::TYPE_EMAIL => 'emails',
286
-	];
287
-
288
-	private function getAllSharees(string $user, array $shareTypes): ISearchResult {
289
-		$result = [];
290
-		foreach ($shareTypes as $shareType) {
291
-			$sharees = $this->getAllShareesByType($user, $shareType);
292
-			$shareTypeResults = [];
293
-			foreach ($sharees as list($sharee, $displayname)) {
294
-				if (!isset($this->searchResultTypeMap[$shareType])) {
295
-					continue;
296
-				}
297
-
298
-				if (!isset($shareTypeResults[$sharee])) {
299
-					$shareTypeResults[$sharee] = [
300
-						'count' => 1,
301
-						'label' => $displayname,
302
-						'value' => [
303
-							'shareType' => $shareType,
304
-							'shareWith' => $sharee,
305
-						],
306
-					];
307
-				} else {
308
-					$shareTypeResults[$sharee]['count']++;
309
-				}
310
-			}
311
-			$result = array_merge($result, array_values($shareTypeResults));
312
-		}
313
-
314
-		$top5 = array_slice(
315
-			$this->sortShareesByFrequency($result),
316
-			0,
317
-			5
318
-		);
319
-
320
-		$searchResult = new SearchResult();
321
-		foreach ($this->searchResultTypeMap as $int => $str) {
322
-			$searchResult->addResultSet(new SearchResultType($str), [], []);
323
-			foreach ($top5 as $x) {
324
-				if ($x['value']['shareType'] === $int) {
325
-					$searchResult->addResultSet(new SearchResultType($str), [], [$x]);
326
-				}
327
-			}
328
-		}
329
-		return $searchResult;
330
-	}
331
-
332
-	/**
333
-	 * @NoAdminRequired
334
-	 *
335
-	 * @param string $itemType
336
-	 * @return DataResponse
337
-	 * @throws OCSBadRequestException
338
-	 */
339
-	public function findRecommended(string $itemType = null, $shareType = null): DataResponse {
340
-		$shareTypes = [
341
-			IShare::TYPE_USER,
342
-		];
343
-
344
-		if ($itemType === null) {
345
-			throw new OCSBadRequestException('Missing itemType');
346
-		} elseif ($itemType === 'file' || $itemType === 'folder') {
347
-			if ($this->shareManager->allowGroupSharing()) {
348
-				$shareTypes[] = IShare::TYPE_GROUP;
349
-			}
350
-
351
-			if ($this->isRemoteSharingAllowed($itemType)) {
352
-				$shareTypes[] = IShare::TYPE_REMOTE;
353
-			}
354
-
355
-			if ($this->isRemoteGroupSharingAllowed($itemType)) {
356
-				$shareTypes[] = IShare::TYPE_REMOTE_GROUP;
357
-			}
358
-
359
-			if ($this->shareManager->shareProviderExists(IShare::TYPE_EMAIL)) {
360
-				$shareTypes[] = IShare::TYPE_EMAIL;
361
-			}
362
-
363
-			if ($this->shareManager->shareProviderExists(IShare::TYPE_ROOM)) {
364
-				$shareTypes[] = IShare::TYPE_ROOM;
365
-			}
366
-		} else {
367
-			$shareTypes[] = IShare::TYPE_GROUP;
368
-			$shareTypes[] = IShare::TYPE_EMAIL;
369
-		}
370
-
371
-		// FIXME: DI
372
-		if (\OC::$server->getAppManager()->isEnabledForUser('circles') && class_exists('\OCA\Circles\ShareByCircleProvider')) {
373
-			$shareTypes[] = IShare::TYPE_CIRCLE;
374
-		}
375
-
376
-		if (isset($_GET['shareType']) && is_array($_GET['shareType'])) {
377
-			$shareTypes = array_intersect($shareTypes, $_GET['shareType']);
378
-			sort($shareTypes);
379
-		} elseif (is_numeric($shareType)) {
380
-			$shareTypes = array_intersect($shareTypes, [(int) $shareType]);
381
-			sort($shareTypes);
382
-		}
383
-
384
-		return new DataResponse(
385
-			$this->getAllSharees($this->userId, $shareTypes)->asArray()
386
-		);
387
-	}
388
-
389
-	/**
390
-	 * Method to get out the static call for better testing
391
-	 *
392
-	 * @param string $itemType
393
-	 * @return bool
394
-	 */
395
-	protected function isRemoteSharingAllowed(string $itemType): bool {
396
-		try {
397
-			// FIXME: static foo makes unit testing unnecessarily difficult
398
-			$backend = \OC\Share\Share::getBackend($itemType);
399
-			return $backend->isShareTypeAllowed(IShare::TYPE_REMOTE);
400
-		} catch (\Exception $e) {
401
-			return false;
402
-		}
403
-	}
404
-
405
-	protected function isRemoteGroupSharingAllowed(string $itemType): bool {
406
-		try {
407
-			// FIXME: static foo makes unit testing unnecessarily difficult
408
-			$backend = \OC\Share\Share::getBackend($itemType);
409
-			return $backend->isShareTypeAllowed(IShare::TYPE_REMOTE_GROUP);
410
-		} catch (\Exception $e) {
411
-			return false;
412
-		}
413
-	}
414
-
415
-
416
-	/**
417
-	 * Generates a bunch of pagination links for the current page
418
-	 *
419
-	 * @param int $page Current page
420
-	 * @param array $params Parameters for the URL
421
-	 * @return string
422
-	 */
423
-	protected function getPaginationLink(int $page, array $params): string {
424
-		if ($this->isV2()) {
425
-			$url = $this->urlGenerator->getAbsoluteURL('/ocs/v2.php/apps/files_sharing/api/v1/sharees') . '?';
426
-		} else {
427
-			$url = $this->urlGenerator->getAbsoluteURL('/ocs/v1.php/apps/files_sharing/api/v1/sharees') . '?';
428
-		}
429
-		$params['page'] = $page + 1;
430
-		return '<' . $url . http_build_query($params) . '>; rel="next"';
431
-	}
432
-
433
-	/**
434
-	 * @return bool
435
-	 */
436
-	protected function isV2(): bool {
437
-		return $this->request->getScriptName() === '/ocs/v2.php';
438
-	}
60
+    /** @var string */
61
+    protected $userId;
62
+
63
+    /** @var IConfig */
64
+    protected $config;
65
+
66
+    /** @var IURLGenerator */
67
+    protected $urlGenerator;
68
+
69
+    /** @var IManager */
70
+    protected $shareManager;
71
+
72
+    /** @var int */
73
+    protected $offset = 0;
74
+
75
+    /** @var int */
76
+    protected $limit = 10;
77
+
78
+    /** @var array */
79
+    protected $result = [
80
+        'exact' => [
81
+            'users' => [],
82
+            'groups' => [],
83
+            'remotes' => [],
84
+            'remote_groups' => [],
85
+            'emails' => [],
86
+            'circles' => [],
87
+            'rooms' => [],
88
+            'deck' => [],
89
+        ],
90
+        'users' => [],
91
+        'groups' => [],
92
+        'remotes' => [],
93
+        'remote_groups' => [],
94
+        'emails' => [],
95
+        'lookup' => [],
96
+        'circles' => [],
97
+        'rooms' => [],
98
+        'deck' => [],
99
+        'lookupEnabled' => false,
100
+    ];
101
+
102
+    protected $reachedEndFor = [];
103
+    /** @var ISearch */
104
+    private $collaboratorSearch;
105
+
106
+    /**
107
+     * @param string $UserId
108
+     * @param string $appName
109
+     * @param IRequest $request
110
+     * @param IConfig $config
111
+     * @param IURLGenerator $urlGenerator
112
+     * @param IManager $shareManager
113
+     * @param ISearch $collaboratorSearch
114
+     */
115
+    public function __construct(
116
+        $UserId,
117
+        string $appName,
118
+        IRequest $request,
119
+        IConfig $config,
120
+        IURLGenerator $urlGenerator,
121
+        IManager $shareManager,
122
+        ISearch $collaboratorSearch
123
+    ) {
124
+        parent::__construct($appName, $request);
125
+        $this->userId = $UserId;
126
+        $this->config = $config;
127
+        $this->urlGenerator = $urlGenerator;
128
+        $this->shareManager = $shareManager;
129
+        $this->collaboratorSearch = $collaboratorSearch;
130
+    }
131
+
132
+    /**
133
+     * @NoAdminRequired
134
+     *
135
+     * @param string $search
136
+     * @param string $itemType
137
+     * @param int $page
138
+     * @param int $perPage
139
+     * @param int|int[] $shareType
140
+     * @param bool $lookup
141
+     * @return DataResponse
142
+     * @throws OCSBadRequestException
143
+     */
144
+    public function search(string $search = '', string $itemType = null, int $page = 1, int $perPage = 200, $shareType = null, bool $lookup = true): DataResponse {
145
+
146
+        // only search for string larger than a given threshold
147
+        $threshold = (int)$this->config->getSystemValue('sharing.minSearchStringLength', 0);
148
+        if (strlen($search) < $threshold) {
149
+            return new DataResponse($this->result);
150
+        }
151
+
152
+        // never return more than the max. number of results configured in the config.php
153
+        $maxResults = $this->config->getSystemValueInt('sharing.maxAutocompleteResults', Constants::SHARING_MAX_AUTOCOMPLETE_RESULTS_DEFAULT);
154
+        if ($maxResults > 0) {
155
+            $perPage = min($perPage, $maxResults);
156
+        }
157
+        if ($perPage <= 0) {
158
+            throw new OCSBadRequestException('Invalid perPage argument');
159
+        }
160
+        if ($page <= 0) {
161
+            throw new OCSBadRequestException('Invalid page');
162
+        }
163
+
164
+        $shareTypes = [
165
+            IShare::TYPE_USER,
166
+        ];
167
+
168
+        if ($itemType === null) {
169
+            throw new OCSBadRequestException('Missing itemType');
170
+        } elseif ($itemType === 'file' || $itemType === 'folder') {
171
+            if ($this->shareManager->allowGroupSharing()) {
172
+                $shareTypes[] = IShare::TYPE_GROUP;
173
+            }
174
+
175
+            if ($this->isRemoteSharingAllowed($itemType)) {
176
+                $shareTypes[] = IShare::TYPE_REMOTE;
177
+            }
178
+
179
+            if ($this->isRemoteGroupSharingAllowed($itemType)) {
180
+                $shareTypes[] = IShare::TYPE_REMOTE_GROUP;
181
+            }
182
+
183
+            if ($this->shareManager->shareProviderExists(IShare::TYPE_EMAIL)) {
184
+                $shareTypes[] = IShare::TYPE_EMAIL;
185
+            }
186
+
187
+            if ($this->shareManager->shareProviderExists(IShare::TYPE_ROOM)) {
188
+                $shareTypes[] = IShare::TYPE_ROOM;
189
+            }
190
+
191
+            if ($this->shareManager->shareProviderExists(IShare::TYPE_DECK)) {
192
+                $shareTypes[] = IShare::TYPE_DECK;
193
+            }
194
+        } else {
195
+            $shareTypes[] = IShare::TYPE_GROUP;
196
+            $shareTypes[] = IShare::TYPE_EMAIL;
197
+        }
198
+
199
+        // FIXME: DI
200
+        if (\OC::$server->getAppManager()->isEnabledForUser('circles') && class_exists('\OCA\Circles\ShareByCircleProvider')) {
201
+            $shareTypes[] = IShare::TYPE_CIRCLE;
202
+        }
203
+
204
+        if ($this->shareManager->shareProviderExists(IShare::TYPE_DECK)) {
205
+            $shareTypes[] = IShare::TYPE_DECK;
206
+        }
207
+
208
+        if ($shareType !== null && is_array($shareType)) {
209
+            $shareTypes = array_intersect($shareTypes, $shareType);
210
+        } elseif (is_numeric($shareType)) {
211
+            $shareTypes = array_intersect($shareTypes, [(int) $shareType]);
212
+        }
213
+        sort($shareTypes);
214
+
215
+        $this->limit = $perPage;
216
+        $this->offset = $perPage * ($page - 1);
217
+
218
+        // In global scale mode we always search the loogup server
219
+        if ($this->config->getSystemValueBool('gs.enabled', false)) {
220
+            $lookup = true;
221
+            $this->result['lookupEnabled'] = true;
222
+        } else {
223
+            $this->result['lookupEnabled'] = $this->config->getAppValue('files_sharing', 'lookupServerEnabled', 'yes') === 'yes';
224
+        }
225
+
226
+        list($result, $hasMoreResults) = $this->collaboratorSearch->search($search, $shareTypes, $lookup, $this->limit, $this->offset);
227
+
228
+        // extra treatment for 'exact' subarray, with a single merge expected keys might be lost
229
+        if (isset($result['exact'])) {
230
+            $result['exact'] = array_merge($this->result['exact'], $result['exact']);
231
+        }
232
+        $this->result = array_merge($this->result, $result);
233
+        $response = new DataResponse($this->result);
234
+
235
+        if ($hasMoreResults) {
236
+            $response->addHeader('Link', $this->getPaginationLink($page, [
237
+                'search' => $search,
238
+                'itemType' => $itemType,
239
+                'shareType' => $shareTypes,
240
+                'perPage' => $perPage,
241
+            ]));
242
+        }
243
+
244
+        return $response;
245
+    }
246
+
247
+    /**
248
+     * @param string $user
249
+     * @param int $shareType
250
+     *
251
+     * @return Generator<array<string>>
252
+     */
253
+    private function getAllShareesByType(string $user, int $shareType): Generator {
254
+        $offset = 0;
255
+        $pageSize = 50;
256
+
257
+        while (count($page = $this->shareManager->getSharesBy(
258
+            $user,
259
+            $shareType,
260
+            null,
261
+            false,
262
+            $pageSize,
263
+            $offset
264
+        ))) {
265
+            foreach ($page as $share) {
266
+                yield [$share->getSharedWith(), $share->getSharedWithDisplayName() ?? $share->getSharedWith()];
267
+            }
268
+
269
+            $offset += $pageSize;
270
+        }
271
+    }
272
+
273
+    private function sortShareesByFrequency(array $sharees): array {
274
+        usort($sharees, function (array $s1, array $s2) {
275
+            return $s2['count'] - $s1['count'];
276
+        });
277
+        return $sharees;
278
+    }
279
+
280
+    private $searchResultTypeMap = [
281
+        IShare::TYPE_USER => 'users',
282
+        IShare::TYPE_GROUP => 'groups',
283
+        IShare::TYPE_REMOTE => 'remotes',
284
+        IShare::TYPE_REMOTE_GROUP => 'remote_groups',
285
+        IShare::TYPE_EMAIL => 'emails',
286
+    ];
287
+
288
+    private function getAllSharees(string $user, array $shareTypes): ISearchResult {
289
+        $result = [];
290
+        foreach ($shareTypes as $shareType) {
291
+            $sharees = $this->getAllShareesByType($user, $shareType);
292
+            $shareTypeResults = [];
293
+            foreach ($sharees as list($sharee, $displayname)) {
294
+                if (!isset($this->searchResultTypeMap[$shareType])) {
295
+                    continue;
296
+                }
297
+
298
+                if (!isset($shareTypeResults[$sharee])) {
299
+                    $shareTypeResults[$sharee] = [
300
+                        'count' => 1,
301
+                        'label' => $displayname,
302
+                        'value' => [
303
+                            'shareType' => $shareType,
304
+                            'shareWith' => $sharee,
305
+                        ],
306
+                    ];
307
+                } else {
308
+                    $shareTypeResults[$sharee]['count']++;
309
+                }
310
+            }
311
+            $result = array_merge($result, array_values($shareTypeResults));
312
+        }
313
+
314
+        $top5 = array_slice(
315
+            $this->sortShareesByFrequency($result),
316
+            0,
317
+            5
318
+        );
319
+
320
+        $searchResult = new SearchResult();
321
+        foreach ($this->searchResultTypeMap as $int => $str) {
322
+            $searchResult->addResultSet(new SearchResultType($str), [], []);
323
+            foreach ($top5 as $x) {
324
+                if ($x['value']['shareType'] === $int) {
325
+                    $searchResult->addResultSet(new SearchResultType($str), [], [$x]);
326
+                }
327
+            }
328
+        }
329
+        return $searchResult;
330
+    }
331
+
332
+    /**
333
+     * @NoAdminRequired
334
+     *
335
+     * @param string $itemType
336
+     * @return DataResponse
337
+     * @throws OCSBadRequestException
338
+     */
339
+    public function findRecommended(string $itemType = null, $shareType = null): DataResponse {
340
+        $shareTypes = [
341
+            IShare::TYPE_USER,
342
+        ];
343
+
344
+        if ($itemType === null) {
345
+            throw new OCSBadRequestException('Missing itemType');
346
+        } elseif ($itemType === 'file' || $itemType === 'folder') {
347
+            if ($this->shareManager->allowGroupSharing()) {
348
+                $shareTypes[] = IShare::TYPE_GROUP;
349
+            }
350
+
351
+            if ($this->isRemoteSharingAllowed($itemType)) {
352
+                $shareTypes[] = IShare::TYPE_REMOTE;
353
+            }
354
+
355
+            if ($this->isRemoteGroupSharingAllowed($itemType)) {
356
+                $shareTypes[] = IShare::TYPE_REMOTE_GROUP;
357
+            }
358
+
359
+            if ($this->shareManager->shareProviderExists(IShare::TYPE_EMAIL)) {
360
+                $shareTypes[] = IShare::TYPE_EMAIL;
361
+            }
362
+
363
+            if ($this->shareManager->shareProviderExists(IShare::TYPE_ROOM)) {
364
+                $shareTypes[] = IShare::TYPE_ROOM;
365
+            }
366
+        } else {
367
+            $shareTypes[] = IShare::TYPE_GROUP;
368
+            $shareTypes[] = IShare::TYPE_EMAIL;
369
+        }
370
+
371
+        // FIXME: DI
372
+        if (\OC::$server->getAppManager()->isEnabledForUser('circles') && class_exists('\OCA\Circles\ShareByCircleProvider')) {
373
+            $shareTypes[] = IShare::TYPE_CIRCLE;
374
+        }
375
+
376
+        if (isset($_GET['shareType']) && is_array($_GET['shareType'])) {
377
+            $shareTypes = array_intersect($shareTypes, $_GET['shareType']);
378
+            sort($shareTypes);
379
+        } elseif (is_numeric($shareType)) {
380
+            $shareTypes = array_intersect($shareTypes, [(int) $shareType]);
381
+            sort($shareTypes);
382
+        }
383
+
384
+        return new DataResponse(
385
+            $this->getAllSharees($this->userId, $shareTypes)->asArray()
386
+        );
387
+    }
388
+
389
+    /**
390
+     * Method to get out the static call for better testing
391
+     *
392
+     * @param string $itemType
393
+     * @return bool
394
+     */
395
+    protected function isRemoteSharingAllowed(string $itemType): bool {
396
+        try {
397
+            // FIXME: static foo makes unit testing unnecessarily difficult
398
+            $backend = \OC\Share\Share::getBackend($itemType);
399
+            return $backend->isShareTypeAllowed(IShare::TYPE_REMOTE);
400
+        } catch (\Exception $e) {
401
+            return false;
402
+        }
403
+    }
404
+
405
+    protected function isRemoteGroupSharingAllowed(string $itemType): bool {
406
+        try {
407
+            // FIXME: static foo makes unit testing unnecessarily difficult
408
+            $backend = \OC\Share\Share::getBackend($itemType);
409
+            return $backend->isShareTypeAllowed(IShare::TYPE_REMOTE_GROUP);
410
+        } catch (\Exception $e) {
411
+            return false;
412
+        }
413
+    }
414
+
415
+
416
+    /**
417
+     * Generates a bunch of pagination links for the current page
418
+     *
419
+     * @param int $page Current page
420
+     * @param array $params Parameters for the URL
421
+     * @return string
422
+     */
423
+    protected function getPaginationLink(int $page, array $params): string {
424
+        if ($this->isV2()) {
425
+            $url = $this->urlGenerator->getAbsoluteURL('/ocs/v2.php/apps/files_sharing/api/v1/sharees') . '?';
426
+        } else {
427
+            $url = $this->urlGenerator->getAbsoluteURL('/ocs/v1.php/apps/files_sharing/api/v1/sharees') . '?';
428
+        }
429
+        $params['page'] = $page + 1;
430
+        return '<' . $url . http_build_query($params) . '>; rel="next"';
431
+    }
432
+
433
+    /**
434
+     * @return bool
435
+     */
436
+    protected function isV2(): bool {
437
+        return $this->request->getScriptName() === '/ocs/v2.php';
438
+    }
439 439
 }
Please login to merge, or discard this patch.
apps/files_sharing/lib/Controller/ShareAPIController.php 1 patch
Indentation   +1696 added lines, -1696 removed lines patch added patch discarded remove patch
@@ -84,1703 +84,1703 @@
 block discarded – undo
84 84
  */
85 85
 class ShareAPIController extends OCSController {
86 86
 
87
-	/** @var IManager */
88
-	private $shareManager;
89
-	/** @var IGroupManager */
90
-	private $groupManager;
91
-	/** @var IUserManager */
92
-	private $userManager;
93
-	/** @var IRootFolder */
94
-	private $rootFolder;
95
-	/** @var IURLGenerator */
96
-	private $urlGenerator;
97
-	/** @var string */
98
-	private $currentUser;
99
-	/** @var IL10N */
100
-	private $l;
101
-	/** @var \OCP\Files\Node */
102
-	private $lockedNode;
103
-	/** @var IConfig */
104
-	private $config;
105
-	/** @var IAppManager */
106
-	private $appManager;
107
-	/** @var IServerContainer */
108
-	private $serverContainer;
109
-	/** @var IUserStatusManager */
110
-	private $userStatusManager;
111
-	/** @var IPreview */
112
-	private $previewManager;
113
-
114
-	/**
115
-	 * Share20OCS constructor.
116
-	 *
117
-	 * @param string $appName
118
-	 * @param IRequest $request
119
-	 * @param IManager $shareManager
120
-	 * @param IGroupManager $groupManager
121
-	 * @param IUserManager $userManager
122
-	 * @param IRootFolder $rootFolder
123
-	 * @param IURLGenerator $urlGenerator
124
-	 * @param string $userId
125
-	 * @param IL10N $l10n
126
-	 * @param IConfig $config
127
-	 * @param IAppManager $appManager
128
-	 * @param IServerContainer $serverContainer
129
-	 * @param IUserStatusManager $userStatusManager
130
-	 */
131
-	public function __construct(
132
-		string $appName,
133
-		IRequest $request,
134
-		IManager $shareManager,
135
-		IGroupManager $groupManager,
136
-		IUserManager $userManager,
137
-		IRootFolder $rootFolder,
138
-		IURLGenerator $urlGenerator,
139
-		string $userId = null,
140
-		IL10N $l10n,
141
-		IConfig $config,
142
-		IAppManager $appManager,
143
-		IServerContainer $serverContainer,
144
-		IUserStatusManager $userStatusManager,
145
-		IPreview $previewManager
146
-	) {
147
-		parent::__construct($appName, $request);
148
-
149
-		$this->shareManager = $shareManager;
150
-		$this->userManager = $userManager;
151
-		$this->groupManager = $groupManager;
152
-		$this->request = $request;
153
-		$this->rootFolder = $rootFolder;
154
-		$this->urlGenerator = $urlGenerator;
155
-		$this->currentUser = $userId;
156
-		$this->l = $l10n;
157
-		$this->config = $config;
158
-		$this->appManager = $appManager;
159
-		$this->serverContainer = $serverContainer;
160
-		$this->userStatusManager = $userStatusManager;
161
-		$this->previewManager = $previewManager;
162
-	}
163
-
164
-	/**
165
-	 * Convert an IShare to an array for OCS output
166
-	 *
167
-	 * @param \OCP\Share\IShare $share
168
-	 * @param Node|null $recipientNode
169
-	 * @return array
170
-	 * @throws NotFoundException In case the node can't be resolved.
171
-	 *
172
-	 * @suppress PhanUndeclaredClassMethod
173
-	 */
174
-	protected function formatShare(IShare $share, Node $recipientNode = null): array {
175
-		$sharedBy = $this->userManager->get($share->getSharedBy());
176
-		$shareOwner = $this->userManager->get($share->getShareOwner());
177
-
178
-		$result = [
179
-			'id' => $share->getId(),
180
-			'share_type' => $share->getShareType(),
181
-			'uid_owner' => $share->getSharedBy(),
182
-			'displayname_owner' => $sharedBy !== null ? $sharedBy->getDisplayName() : $share->getSharedBy(),
183
-			// recipient permissions
184
-			'permissions' => $share->getPermissions(),
185
-			// current user permissions on this share
186
-			'can_edit' => $this->canEditShare($share),
187
-			'can_delete' => $this->canDeleteShare($share),
188
-			'stime' => $share->getShareTime()->getTimestamp(),
189
-			'parent' => null,
190
-			'expiration' => null,
191
-			'token' => null,
192
-			'uid_file_owner' => $share->getShareOwner(),
193
-			'note' => $share->getNote(),
194
-			'label' => $share->getLabel(),
195
-			'displayname_file_owner' => $shareOwner !== null ? $shareOwner->getDisplayName() : $share->getShareOwner(),
196
-		];
197
-
198
-		$userFolder = $this->rootFolder->getUserFolder($this->currentUser);
199
-		if ($recipientNode) {
200
-			$node = $recipientNode;
201
-		} else {
202
-			$nodes = $userFolder->getById($share->getNodeId());
203
-			if (empty($nodes)) {
204
-				// fallback to guessing the path
205
-				$node = $userFolder->get($share->getTarget());
206
-				if ($node === null || $share->getTarget() === '') {
207
-					throw new NotFoundException();
208
-				}
209
-			} else {
210
-				$node = reset($nodes);
211
-			}
212
-		}
213
-
214
-		$result['path'] = $userFolder->getRelativePath($node->getPath());
215
-		if ($node instanceof Folder) {
216
-			$result['item_type'] = 'folder';
217
-		} else {
218
-			$result['item_type'] = 'file';
219
-		}
220
-
221
-		$result['mimetype'] = $node->getMimetype();
222
-		$result['has_preview'] = $this->previewManager->isAvailable($node);
223
-		$result['storage_id'] = $node->getStorage()->getId();
224
-		$result['storage'] = $node->getStorage()->getCache()->getNumericStorageId();
225
-		$result['item_source'] = $node->getId();
226
-		$result['file_source'] = $node->getId();
227
-		$result['file_parent'] = $node->getParent()->getId();
228
-		$result['file_target'] = $share->getTarget();
229
-
230
-		$expiration = $share->getExpirationDate();
231
-		if ($expiration !== null) {
232
-			$result['expiration'] = $expiration->format('Y-m-d 00:00:00');
233
-		}
234
-
235
-		if ($share->getShareType() === IShare::TYPE_USER) {
236
-			$sharedWith = $this->userManager->get($share->getSharedWith());
237
-			$result['share_with'] = $share->getSharedWith();
238
-			$result['share_with_displayname'] = $sharedWith !== null ? $sharedWith->getDisplayName() : $share->getSharedWith();
239
-			$result['share_with_displayname_unique'] = $sharedWith !== null ? (
240
-				 $sharedWith->getEMailAddress() !== '' ? $sharedWith->getEMailAddress() : $sharedWith->getUID()
241
-			) : $share->getSharedWith();
242
-			$result['status'] = [];
243
-
244
-			$userStatuses = $this->userStatusManager->getUserStatuses([$share->getSharedWith()]);
245
-			$userStatus = array_shift($userStatuses);
246
-			if ($userStatus) {
247
-				$result['status'] = [
248
-					'status' => $userStatus->getStatus(),
249
-					'message' => $userStatus->getMessage(),
250
-					'icon' => $userStatus->getIcon(),
251
-					'clearAt' => $userStatus->getClearAt()
252
-						? (int)$userStatus->getClearAt()->format('U')
253
-						: null,
254
-				];
255
-			}
256
-		} elseif ($share->getShareType() === IShare::TYPE_GROUP) {
257
-			$group = $this->groupManager->get($share->getSharedWith());
258
-			$result['share_with'] = $share->getSharedWith();
259
-			$result['share_with_displayname'] = $group !== null ? $group->getDisplayName() : $share->getSharedWith();
260
-		} elseif ($share->getShareType() === IShare::TYPE_LINK) {
261
-
262
-			// "share_with" and "share_with_displayname" for passwords of link
263
-			// shares was deprecated in Nextcloud 15, use "password" instead.
264
-			$result['share_with'] = $share->getPassword();
265
-			$result['share_with_displayname'] = '(' . $this->l->t('Shared link') . ')';
266
-
267
-			$result['password'] = $share->getPassword();
268
-
269
-			$result['send_password_by_talk'] = $share->getSendPasswordByTalk();
270
-
271
-			$result['token'] = $share->getToken();
272
-			$result['url'] = $this->urlGenerator->linkToRouteAbsolute('files_sharing.sharecontroller.showShare', ['token' => $share->getToken()]);
273
-		} elseif ($share->getShareType() === IShare::TYPE_REMOTE || $share->getShareType() === IShare::TYPE_REMOTE_GROUP) {
274
-			$result['share_with'] = $share->getSharedWith();
275
-			$result['share_with_displayname'] = $this->getDisplayNameFromAddressBook($share->getSharedWith(), 'CLOUD');
276
-			$result['token'] = $share->getToken();
277
-		} elseif ($share->getShareType() === IShare::TYPE_EMAIL) {
278
-			$result['share_with'] = $share->getSharedWith();
279
-			$result['password'] = $share->getPassword();
280
-			$result['send_password_by_talk'] = $share->getSendPasswordByTalk();
281
-			$result['share_with_displayname'] = $this->getDisplayNameFromAddressBook($share->getSharedWith(), 'EMAIL');
282
-			$result['token'] = $share->getToken();
283
-		} elseif ($share->getShareType() === IShare::TYPE_CIRCLE) {
284
-			// getSharedWith() returns either "name (type, owner)" or
285
-			// "name (type, owner) [id]", depending on the Circles app version.
286
-			$hasCircleId = (substr($share->getSharedWith(), -1) === ']');
287
-
288
-			$result['share_with_displayname'] = $share->getSharedWithDisplayName();
289
-			if (empty($result['share_with_displayname'])) {
290
-				$displayNameLength = ($hasCircleId ? strrpos($share->getSharedWith(), ' ') : strlen($share->getSharedWith()));
291
-				$result['share_with_displayname'] = substr($share->getSharedWith(), 0, $displayNameLength);
292
-			}
293
-
294
-			$result['share_with_avatar'] = $share->getSharedWithAvatar();
295
-
296
-			$shareWithStart = ($hasCircleId ? strrpos($share->getSharedWith(), '[') + 1 : 0);
297
-			$shareWithLength = ($hasCircleId ? -1 : strpos($share->getSharedWith(), ' '));
298
-			if (is_bool($shareWithLength)) {
299
-				$shareWithLength = -1;
300
-			}
301
-			$result['share_with'] = substr($share->getSharedWith(), $shareWithStart, $shareWithLength);
302
-		} elseif ($share->getShareType() === IShare::TYPE_ROOM) {
303
-			$result['share_with'] = $share->getSharedWith();
304
-			$result['share_with_displayname'] = '';
305
-
306
-			try {
307
-				$result = array_merge($result, $this->getRoomShareHelper()->formatShare($share));
308
-			} catch (QueryException $e) {
309
-			}
310
-		} elseif ($share->getShareType() === IShare::TYPE_DECK) {
311
-			$result['share_with'] = $share->getSharedWith();
312
-			$result['share_with_displayname'] = '';
313
-
314
-			try {
315
-				$result = array_merge($result, $this->getDeckShareHelper()->formatShare($share));
316
-			} catch (QueryException $e) {
317
-			}
318
-		}
319
-
320
-
321
-		$result['mail_send'] = $share->getMailSend() ? 1 : 0;
322
-		$result['hide_download'] = $share->getHideDownload() ? 1 : 0;
323
-
324
-		return $result;
325
-	}
326
-
327
-	/**
328
-	 * Check if one of the users address books knows the exact property, if
329
-	 * yes we return the full name.
330
-	 *
331
-	 * @param string $query
332
-	 * @param string $property
333
-	 * @return string
334
-	 */
335
-	private function getDisplayNameFromAddressBook(string $query, string $property): string {
336
-		// FIXME: If we inject the contacts manager it gets initialized bofore any address books are registered
337
-		$result = \OC::$server->getContactsManager()->search($query, [$property]);
338
-		foreach ($result as $r) {
339
-			foreach ($r[$property] as $value) {
340
-				if ($value === $query && $r['FN']) {
341
-					return $r['FN'];
342
-				}
343
-			}
344
-		}
345
-
346
-		return $query;
347
-	}
348
-
349
-	/**
350
-	 * Get a specific share by id
351
-	 *
352
-	 * @NoAdminRequired
353
-	 *
354
-	 * @param string $id
355
-	 * @return DataResponse
356
-	 * @throws OCSNotFoundException
357
-	 */
358
-	public function getShare(string $id): DataResponse {
359
-		try {
360
-			$share = $this->getShareById($id);
361
-		} catch (ShareNotFound $e) {
362
-			throw new OCSNotFoundException($this->l->t('Wrong share ID, share doesn\'t exist'));
363
-		}
364
-
365
-		try {
366
-			if ($this->canAccessShare($share)) {
367
-				$share = $this->formatShare($share);
368
-				return new DataResponse([$share]);
369
-			}
370
-		} catch (NotFoundException $e) {
371
-			// Fall trough
372
-		}
373
-
374
-		throw new OCSNotFoundException($this->l->t('Wrong share ID, share doesn\'t exist'));
375
-	}
376
-
377
-	/**
378
-	 * Delete a share
379
-	 *
380
-	 * @NoAdminRequired
381
-	 *
382
-	 * @param string $id
383
-	 * @return DataResponse
384
-	 * @throws OCSNotFoundException
385
-	 */
386
-	public function deleteShare(string $id): DataResponse {
387
-		try {
388
-			$share = $this->getShareById($id);
389
-		} catch (ShareNotFound $e) {
390
-			throw new OCSNotFoundException($this->l->t('Wrong share ID, share doesn\'t exist'));
391
-		}
392
-
393
-		try {
394
-			$this->lock($share->getNode());
395
-		} catch (LockedException $e) {
396
-			throw new OCSNotFoundException($this->l->t('Could not delete share'));
397
-		}
398
-
399
-		if (!$this->canAccessShare($share)) {
400
-			throw new OCSNotFoundException($this->l->t('Wrong share ID, share doesn\'t exist'));
401
-		}
402
-
403
-		// if it's a group share or a room share
404
-		// we don't delete the share, but only the
405
-		// mount point. Allowing it to be restored
406
-		// from the deleted shares
407
-		if ($this->canDeleteShareFromSelf($share)) {
408
-			$this->shareManager->deleteFromSelf($share, $this->currentUser);
409
-		} else {
410
-			if (!$this->canDeleteShare($share)) {
411
-				throw new OCSForbiddenException($this->l->t('Could not delete share'));
412
-			}
413
-
414
-			$this->shareManager->deleteShare($share);
415
-		}
416
-
417
-		return new DataResponse();
418
-	}
419
-
420
-	/**
421
-	 * @NoAdminRequired
422
-	 *
423
-	 * @param string $path
424
-	 * @param int $permissions
425
-	 * @param int $shareType
426
-	 * @param string $shareWith
427
-	 * @param string $publicUpload
428
-	 * @param string $password
429
-	 * @param string $sendPasswordByTalk
430
-	 * @param string $expireDate
431
-	 * @param string $label
432
-	 *
433
-	 * @return DataResponse
434
-	 * @throws NotFoundException
435
-	 * @throws OCSBadRequestException
436
-	 * @throws OCSException
437
-	 * @throws OCSForbiddenException
438
-	 * @throws OCSNotFoundException
439
-	 * @throws InvalidPathException
440
-	 * @suppress PhanUndeclaredClassMethod
441
-	 */
442
-	public function createShare(
443
-		string $path = null,
444
-		int $permissions = null,
445
-		int $shareType = -1,
446
-		string $shareWith = null,
447
-		string $publicUpload = 'false',
448
-		string $password = '',
449
-		string $sendPasswordByTalk = null,
450
-		string $expireDate = '',
451
-		string $label = ''
452
-	): DataResponse {
453
-		$share = $this->shareManager->newShare();
454
-
455
-		if ($permissions === null) {
456
-			$permissions = $this->config->getAppValue('core', 'shareapi_default_permissions', Constants::PERMISSION_ALL);
457
-		}
458
-
459
-		// Verify path
460
-		if ($path === null) {
461
-			throw new OCSNotFoundException($this->l->t('Please specify a file or folder path'));
462
-		}
463
-
464
-		$userFolder = $this->rootFolder->getUserFolder($this->currentUser);
465
-		try {
466
-			$path = $userFolder->get($path);
467
-		} catch (NotFoundException $e) {
468
-			throw new OCSNotFoundException($this->l->t('Wrong path, file/folder doesn\'t exist'));
469
-		}
470
-
471
-		$share->setNode($path);
472
-
473
-		try {
474
-			$this->lock($share->getNode());
475
-		} catch (LockedException $e) {
476
-			throw new OCSNotFoundException($this->l->t('Could not create share'));
477
-		}
478
-
479
-		if ($permissions < 0 || $permissions > Constants::PERMISSION_ALL) {
480
-			throw new OCSNotFoundException($this->l->t('invalid permissions'));
481
-		}
482
-
483
-		// Shares always require read permissions
484
-		$permissions |= Constants::PERMISSION_READ;
485
-
486
-		if ($path instanceof \OCP\Files\File) {
487
-			// Single file shares should never have delete or create permissions
488
-			$permissions &= ~Constants::PERMISSION_DELETE;
489
-			$permissions &= ~Constants::PERMISSION_CREATE;
490
-		}
491
-
492
-		/**
493
-		 * Hack for https://github.com/owncloud/core/issues/22587
494
-		 * We check the permissions via webdav. But the permissions of the mount point
495
-		 * do not equal the share permissions. Here we fix that for federated mounts.
496
-		 */
497
-		if ($path->getStorage()->instanceOfStorage(Storage::class)) {
498
-			$permissions &= ~($permissions & ~$path->getPermissions());
499
-		}
500
-
501
-		if ($shareType === IShare::TYPE_USER) {
502
-			// Valid user is required to share
503
-			if ($shareWith === null || !$this->userManager->userExists($shareWith)) {
504
-				throw new OCSNotFoundException($this->l->t('Please specify a valid user'));
505
-			}
506
-			$share->setSharedWith($shareWith);
507
-			$share->setPermissions($permissions);
508
-		} elseif ($shareType === IShare::TYPE_GROUP) {
509
-			if (!$this->shareManager->allowGroupSharing()) {
510
-				throw new OCSNotFoundException($this->l->t('Group sharing is disabled by the administrator'));
511
-			}
512
-
513
-			// Valid group is required to share
514
-			if ($shareWith === null || !$this->groupManager->groupExists($shareWith)) {
515
-				throw new OCSNotFoundException($this->l->t('Please specify a valid group'));
516
-			}
517
-			$share->setSharedWith($shareWith);
518
-			$share->setPermissions($permissions);
519
-		} elseif ($shareType === IShare::TYPE_LINK
520
-			|| $shareType === IShare::TYPE_EMAIL) {
521
-
522
-			// Can we even share links?
523
-			if (!$this->shareManager->shareApiAllowLinks()) {
524
-				throw new OCSNotFoundException($this->l->t('Public link sharing is disabled by the administrator'));
525
-			}
526
-
527
-			if ($publicUpload === 'true') {
528
-				// Check if public upload is allowed
529
-				if (!$this->shareManager->shareApiLinkAllowPublicUpload()) {
530
-					throw new OCSForbiddenException($this->l->t('Public upload disabled by the administrator'));
531
-				}
532
-
533
-				// Public upload can only be set for folders
534
-				if ($path instanceof \OCP\Files\File) {
535
-					throw new OCSNotFoundException($this->l->t('Public upload is only possible for publicly shared folders'));
536
-				}
537
-
538
-				$permissions = Constants::PERMISSION_READ |
539
-					Constants::PERMISSION_CREATE |
540
-					Constants::PERMISSION_UPDATE |
541
-					Constants::PERMISSION_DELETE;
542
-			} else {
543
-				$permissions = Constants::PERMISSION_READ;
544
-			}
545
-
546
-			// TODO: It might make sense to have a dedicated setting to allow/deny converting link shares into federated ones
547
-			if (($permissions & Constants::PERMISSION_READ) && $this->shareManager->outgoingServer2ServerSharesAllowed()) {
548
-				$permissions |= Constants::PERMISSION_SHARE;
549
-			}
550
-
551
-			$share->setPermissions($permissions);
552
-
553
-			// Set password
554
-			if ($password !== '') {
555
-				$share->setPassword($password);
556
-			}
557
-
558
-			// Only share by mail have a recipient
559
-			if ($shareType === IShare::TYPE_EMAIL) {
560
-				$share->setSharedWith($shareWith);
561
-			} else {
562
-				// Only link share have a label
563
-				if (!empty($label)) {
564
-					$share->setLabel($label);
565
-				}
566
-			}
567
-
568
-			if ($sendPasswordByTalk === 'true') {
569
-				if (!$this->appManager->isEnabledForUser('spreed')) {
570
-					throw new OCSForbiddenException($this->l->t('Sharing %s sending the password by Nextcloud Talk failed because Nextcloud Talk is not enabled', [$path->getPath()]));
571
-				}
572
-
573
-				$share->setSendPasswordByTalk(true);
574
-			}
575
-
576
-			//Expire date
577
-			if ($expireDate !== '') {
578
-				try {
579
-					$expireDate = $this->parseDate($expireDate);
580
-					$share->setExpirationDate($expireDate);
581
-				} catch (\Exception $e) {
582
-					throw new OCSNotFoundException($this->l->t('Invalid date, date format must be YYYY-MM-DD'));
583
-				}
584
-			}
585
-		} elseif ($shareType === IShare::TYPE_REMOTE) {
586
-			if (!$this->shareManager->outgoingServer2ServerSharesAllowed()) {
587
-				throw new OCSForbiddenException($this->l->t('Sharing %1$s failed because the back end does not allow shares from type %2$s', [$path->getPath(), $shareType]));
588
-			}
589
-
590
-			$share->setSharedWith($shareWith);
591
-			$share->setPermissions($permissions);
592
-		} elseif ($shareType === IShare::TYPE_REMOTE_GROUP) {
593
-			if (!$this->shareManager->outgoingServer2ServerGroupSharesAllowed()) {
594
-				throw new OCSForbiddenException($this->l->t('Sharing %1$s failed because the back end does not allow shares from type %2$s', [$path->getPath(), $shareType]));
595
-			}
596
-
597
-			$share->setSharedWith($shareWith);
598
-			$share->setPermissions($permissions);
599
-		} elseif ($shareType === IShare::TYPE_CIRCLE) {
600
-			if (!\OC::$server->getAppManager()->isEnabledForUser('circles') || !class_exists('\OCA\Circles\ShareByCircleProvider')) {
601
-				throw new OCSNotFoundException($this->l->t('You cannot share to a Circle if the app is not enabled'));
602
-			}
603
-
604
-			$circle = \OCA\Circles\Api\v1\Circles::detailsCircle($shareWith);
605
-
606
-			// Valid circle is required to share
607
-			if ($circle === null) {
608
-				throw new OCSNotFoundException($this->l->t('Please specify a valid circle'));
609
-			}
610
-			$share->setSharedWith($shareWith);
611
-			$share->setPermissions($permissions);
612
-		} elseif ($shareType === IShare::TYPE_ROOM) {
613
-			try {
614
-				$this->getRoomShareHelper()->createShare($share, $shareWith, $permissions, $expireDate);
615
-			} catch (QueryException $e) {
616
-				throw new OCSForbiddenException($this->l->t('Sharing %s failed because the back end does not support room shares', [$path->getPath()]));
617
-			}
618
-		} elseif ($shareType === IShare::TYPE_DECK) {
619
-			try {
620
-				$this->getDeckShareHelper()->createShare($share, $shareWith, $permissions, $expireDate);
621
-			} catch (QueryException $e) {
622
-				throw new OCSForbiddenException($this->l->t('Sharing %s failed because the back end does not support room shares', [$path->getPath()]));
623
-			}
624
-		} else {
625
-			throw new OCSBadRequestException($this->l->t('Unknown share type'));
626
-		}
627
-
628
-		$share->setShareType($shareType);
629
-		$share->setSharedBy($this->currentUser);
630
-
631
-		try {
632
-			$share = $this->shareManager->createShare($share);
633
-		} catch (GenericShareException $e) {
634
-			$code = $e->getCode() === 0 ? 403 : $e->getCode();
635
-			throw new OCSException($e->getHint(), $code);
636
-		} catch (\Exception $e) {
637
-			throw new OCSForbiddenException($e->getMessage(), $e);
638
-		}
639
-
640
-		$output = $this->formatShare($share);
641
-
642
-		return new DataResponse($output);
643
-	}
644
-
645
-	/**
646
-	 * @param null|Node $node
647
-	 * @param boolean $includeTags
648
-	 *
649
-	 * @return array
650
-	 */
651
-	private function getSharedWithMe($node, bool $includeTags): array {
652
-		$userShares = $this->shareManager->getSharedWith($this->currentUser, IShare::TYPE_USER, $node, -1, 0);
653
-		$groupShares = $this->shareManager->getSharedWith($this->currentUser, IShare::TYPE_GROUP, $node, -1, 0);
654
-		$circleShares = $this->shareManager->getSharedWith($this->currentUser, IShare::TYPE_CIRCLE, $node, -1, 0);
655
-		$roomShares = $this->shareManager->getSharedWith($this->currentUser, IShare::TYPE_ROOM, $node, -1, 0);
656
-		$deckShares = $this->shareManager->getSharedWith($this->currentUser, IShare::TYPE_DECK, $node, -1, 0);
657
-
658
-		$shares = array_merge($userShares, $groupShares, $circleShares, $roomShares, $deckShares);
659
-
660
-		$filteredShares = array_filter($shares, function (IShare $share) {
661
-			return $share->getShareOwner() !== $this->currentUser;
662
-		});
663
-
664
-		$formatted = [];
665
-		foreach ($filteredShares as $share) {
666
-			if ($this->canAccessShare($share)) {
667
-				try {
668
-					$formatted[] = $this->formatShare($share);
669
-				} catch (NotFoundException $e) {
670
-					// Ignore this share
671
-				}
672
-			}
673
-		}
674
-
675
-		if ($includeTags) {
676
-			$formatted = Helper::populateTags($formatted, 'file_source', \OC::$server->getTagManager());
677
-		}
678
-
679
-		return $formatted;
680
-	}
681
-
682
-	/**
683
-	 * @param \OCP\Files\Node $folder
684
-	 *
685
-	 * @return array
686
-	 * @throws OCSBadRequestException
687
-	 * @throws NotFoundException
688
-	 */
689
-	private function getSharesInDir(Node $folder): array {
690
-		if (!($folder instanceof \OCP\Files\Folder)) {
691
-			throw new OCSBadRequestException($this->l->t('Not a directory'));
692
-		}
693
-
694
-		$nodes = $folder->getDirectoryListing();
695
-
696
-		/** @var \OCP\Share\IShare[] $shares */
697
-		$shares = array_reduce($nodes, function ($carry, $node) {
698
-			$carry = array_merge($carry, $this->getAllShares($node, true));
699
-			return $carry;
700
-		}, []);
701
-
702
-		// filter out duplicate shares
703
-		$known = [];
704
-
705
-
706
-		$formatted = $miniFormatted = [];
707
-		$resharingRight = false;
708
-		$known = [];
709
-		foreach ($shares as $share) {
710
-			if (in_array($share->getId(), $known) || $share->getSharedWith() === $this->currentUser) {
711
-				continue;
712
-			}
713
-
714
-			try {
715
-				$format = $this->formatShare($share);
716
-
717
-				$known[] = $share->getId();
718
-				$formatted[] = $format;
719
-				if ($share->getSharedBy() === $this->currentUser) {
720
-					$miniFormatted[] = $format;
721
-				}
722
-				if (!$resharingRight && $this->shareProviderResharingRights($this->currentUser, $share, $folder)) {
723
-					$resharingRight = true;
724
-				}
725
-			} catch (\Exception $e) {
726
-				//Ignore this share
727
-			}
728
-		}
729
-
730
-		if (!$resharingRight) {
731
-			$formatted = $miniFormatted;
732
-		}
733
-
734
-		return $formatted;
735
-	}
736
-
737
-	/**
738
-	 * The getShares function.
739
-	 *
740
-	 * @NoAdminRequired
741
-	 *
742
-	 * @param string $shared_with_me
743
-	 * @param string $reshares
744
-	 * @param string $subfiles
745
-	 * @param string $path
746
-	 *
747
-	 * - Get shares by the current user
748
-	 * - Get shares by the current user and reshares (?reshares=true)
749
-	 * - Get shares with the current user (?shared_with_me=true)
750
-	 * - Get shares for a specific path (?path=...)
751
-	 * - Get all shares in a folder (?subfiles=true&path=..)
752
-	 *
753
-	 * @param string $include_tags
754
-	 *
755
-	 * @return DataResponse
756
-	 * @throws NotFoundException
757
-	 * @throws OCSBadRequestException
758
-	 * @throws OCSNotFoundException
759
-	 */
760
-	public function getShares(
761
-		string $shared_with_me = 'false',
762
-		string $reshares = 'false',
763
-		string $subfiles = 'false',
764
-		string $path = '',
765
-		string $include_tags = 'false'
766
-	): DataResponse {
767
-		$node = null;
768
-		if ($path !== '') {
769
-			$userFolder = $this->rootFolder->getUserFolder($this->currentUser);
770
-			try {
771
-				$node = $userFolder->get($path);
772
-				$this->lock($node);
773
-			} catch (NotFoundException $e) {
774
-				throw new OCSNotFoundException(
775
-					$this->l->t('Wrong path, file/folder doesn\'t exist')
776
-				);
777
-			} catch (LockedException $e) {
778
-				throw new OCSNotFoundException($this->l->t('Could not lock node'));
779
-			}
780
-		}
781
-
782
-		$shares = $this->getFormattedShares(
783
-			$this->currentUser,
784
-			$node,
785
-			($shared_with_me === 'true'),
786
-			($reshares === 'true'),
787
-			($subfiles === 'true'),
788
-			($include_tags === 'true')
789
-		);
790
-
791
-		return new DataResponse($shares);
792
-	}
793
-
794
-
795
-	/**
796
-	 * @param string $viewer
797
-	 * @param Node $node
798
-	 * @param bool $sharedWithMe
799
-	 * @param bool $reShares
800
-	 * @param bool $subFiles
801
-	 * @param bool $includeTags
802
-	 *
803
-	 * @return array
804
-	 * @throws NotFoundException
805
-	 * @throws OCSBadRequestException
806
-	 */
807
-	private function getFormattedShares(
808
-		string $viewer,
809
-		$node = null,
810
-		bool $sharedWithMe = false,
811
-		bool $reShares = false,
812
-		bool $subFiles = false,
813
-		bool $includeTags = false
814
-	): array {
815
-		if ($sharedWithMe) {
816
-			return $this->getSharedWithMe($node, $includeTags);
817
-		}
818
-
819
-		if ($subFiles) {
820
-			return $this->getSharesInDir($node);
821
-		}
822
-
823
-		$shares = $this->getSharesFromNode($viewer, $node, $reShares);
824
-
825
-		$known = $formatted = $miniFormatted = [];
826
-		$resharingRight = false;
827
-		foreach ($shares as $share) {
828
-			try {
829
-				$share->getNode();
830
-			} catch (NotFoundException $e) {
831
-				/*
87
+    /** @var IManager */
88
+    private $shareManager;
89
+    /** @var IGroupManager */
90
+    private $groupManager;
91
+    /** @var IUserManager */
92
+    private $userManager;
93
+    /** @var IRootFolder */
94
+    private $rootFolder;
95
+    /** @var IURLGenerator */
96
+    private $urlGenerator;
97
+    /** @var string */
98
+    private $currentUser;
99
+    /** @var IL10N */
100
+    private $l;
101
+    /** @var \OCP\Files\Node */
102
+    private $lockedNode;
103
+    /** @var IConfig */
104
+    private $config;
105
+    /** @var IAppManager */
106
+    private $appManager;
107
+    /** @var IServerContainer */
108
+    private $serverContainer;
109
+    /** @var IUserStatusManager */
110
+    private $userStatusManager;
111
+    /** @var IPreview */
112
+    private $previewManager;
113
+
114
+    /**
115
+     * Share20OCS constructor.
116
+     *
117
+     * @param string $appName
118
+     * @param IRequest $request
119
+     * @param IManager $shareManager
120
+     * @param IGroupManager $groupManager
121
+     * @param IUserManager $userManager
122
+     * @param IRootFolder $rootFolder
123
+     * @param IURLGenerator $urlGenerator
124
+     * @param string $userId
125
+     * @param IL10N $l10n
126
+     * @param IConfig $config
127
+     * @param IAppManager $appManager
128
+     * @param IServerContainer $serverContainer
129
+     * @param IUserStatusManager $userStatusManager
130
+     */
131
+    public function __construct(
132
+        string $appName,
133
+        IRequest $request,
134
+        IManager $shareManager,
135
+        IGroupManager $groupManager,
136
+        IUserManager $userManager,
137
+        IRootFolder $rootFolder,
138
+        IURLGenerator $urlGenerator,
139
+        string $userId = null,
140
+        IL10N $l10n,
141
+        IConfig $config,
142
+        IAppManager $appManager,
143
+        IServerContainer $serverContainer,
144
+        IUserStatusManager $userStatusManager,
145
+        IPreview $previewManager
146
+    ) {
147
+        parent::__construct($appName, $request);
148
+
149
+        $this->shareManager = $shareManager;
150
+        $this->userManager = $userManager;
151
+        $this->groupManager = $groupManager;
152
+        $this->request = $request;
153
+        $this->rootFolder = $rootFolder;
154
+        $this->urlGenerator = $urlGenerator;
155
+        $this->currentUser = $userId;
156
+        $this->l = $l10n;
157
+        $this->config = $config;
158
+        $this->appManager = $appManager;
159
+        $this->serverContainer = $serverContainer;
160
+        $this->userStatusManager = $userStatusManager;
161
+        $this->previewManager = $previewManager;
162
+    }
163
+
164
+    /**
165
+     * Convert an IShare to an array for OCS output
166
+     *
167
+     * @param \OCP\Share\IShare $share
168
+     * @param Node|null $recipientNode
169
+     * @return array
170
+     * @throws NotFoundException In case the node can't be resolved.
171
+     *
172
+     * @suppress PhanUndeclaredClassMethod
173
+     */
174
+    protected function formatShare(IShare $share, Node $recipientNode = null): array {
175
+        $sharedBy = $this->userManager->get($share->getSharedBy());
176
+        $shareOwner = $this->userManager->get($share->getShareOwner());
177
+
178
+        $result = [
179
+            'id' => $share->getId(),
180
+            'share_type' => $share->getShareType(),
181
+            'uid_owner' => $share->getSharedBy(),
182
+            'displayname_owner' => $sharedBy !== null ? $sharedBy->getDisplayName() : $share->getSharedBy(),
183
+            // recipient permissions
184
+            'permissions' => $share->getPermissions(),
185
+            // current user permissions on this share
186
+            'can_edit' => $this->canEditShare($share),
187
+            'can_delete' => $this->canDeleteShare($share),
188
+            'stime' => $share->getShareTime()->getTimestamp(),
189
+            'parent' => null,
190
+            'expiration' => null,
191
+            'token' => null,
192
+            'uid_file_owner' => $share->getShareOwner(),
193
+            'note' => $share->getNote(),
194
+            'label' => $share->getLabel(),
195
+            'displayname_file_owner' => $shareOwner !== null ? $shareOwner->getDisplayName() : $share->getShareOwner(),
196
+        ];
197
+
198
+        $userFolder = $this->rootFolder->getUserFolder($this->currentUser);
199
+        if ($recipientNode) {
200
+            $node = $recipientNode;
201
+        } else {
202
+            $nodes = $userFolder->getById($share->getNodeId());
203
+            if (empty($nodes)) {
204
+                // fallback to guessing the path
205
+                $node = $userFolder->get($share->getTarget());
206
+                if ($node === null || $share->getTarget() === '') {
207
+                    throw new NotFoundException();
208
+                }
209
+            } else {
210
+                $node = reset($nodes);
211
+            }
212
+        }
213
+
214
+        $result['path'] = $userFolder->getRelativePath($node->getPath());
215
+        if ($node instanceof Folder) {
216
+            $result['item_type'] = 'folder';
217
+        } else {
218
+            $result['item_type'] = 'file';
219
+        }
220
+
221
+        $result['mimetype'] = $node->getMimetype();
222
+        $result['has_preview'] = $this->previewManager->isAvailable($node);
223
+        $result['storage_id'] = $node->getStorage()->getId();
224
+        $result['storage'] = $node->getStorage()->getCache()->getNumericStorageId();
225
+        $result['item_source'] = $node->getId();
226
+        $result['file_source'] = $node->getId();
227
+        $result['file_parent'] = $node->getParent()->getId();
228
+        $result['file_target'] = $share->getTarget();
229
+
230
+        $expiration = $share->getExpirationDate();
231
+        if ($expiration !== null) {
232
+            $result['expiration'] = $expiration->format('Y-m-d 00:00:00');
233
+        }
234
+
235
+        if ($share->getShareType() === IShare::TYPE_USER) {
236
+            $sharedWith = $this->userManager->get($share->getSharedWith());
237
+            $result['share_with'] = $share->getSharedWith();
238
+            $result['share_with_displayname'] = $sharedWith !== null ? $sharedWith->getDisplayName() : $share->getSharedWith();
239
+            $result['share_with_displayname_unique'] = $sharedWith !== null ? (
240
+                    $sharedWith->getEMailAddress() !== '' ? $sharedWith->getEMailAddress() : $sharedWith->getUID()
241
+            ) : $share->getSharedWith();
242
+            $result['status'] = [];
243
+
244
+            $userStatuses = $this->userStatusManager->getUserStatuses([$share->getSharedWith()]);
245
+            $userStatus = array_shift($userStatuses);
246
+            if ($userStatus) {
247
+                $result['status'] = [
248
+                    'status' => $userStatus->getStatus(),
249
+                    'message' => $userStatus->getMessage(),
250
+                    'icon' => $userStatus->getIcon(),
251
+                    'clearAt' => $userStatus->getClearAt()
252
+                        ? (int)$userStatus->getClearAt()->format('U')
253
+                        : null,
254
+                ];
255
+            }
256
+        } elseif ($share->getShareType() === IShare::TYPE_GROUP) {
257
+            $group = $this->groupManager->get($share->getSharedWith());
258
+            $result['share_with'] = $share->getSharedWith();
259
+            $result['share_with_displayname'] = $group !== null ? $group->getDisplayName() : $share->getSharedWith();
260
+        } elseif ($share->getShareType() === IShare::TYPE_LINK) {
261
+
262
+            // "share_with" and "share_with_displayname" for passwords of link
263
+            // shares was deprecated in Nextcloud 15, use "password" instead.
264
+            $result['share_with'] = $share->getPassword();
265
+            $result['share_with_displayname'] = '(' . $this->l->t('Shared link') . ')';
266
+
267
+            $result['password'] = $share->getPassword();
268
+
269
+            $result['send_password_by_talk'] = $share->getSendPasswordByTalk();
270
+
271
+            $result['token'] = $share->getToken();
272
+            $result['url'] = $this->urlGenerator->linkToRouteAbsolute('files_sharing.sharecontroller.showShare', ['token' => $share->getToken()]);
273
+        } elseif ($share->getShareType() === IShare::TYPE_REMOTE || $share->getShareType() === IShare::TYPE_REMOTE_GROUP) {
274
+            $result['share_with'] = $share->getSharedWith();
275
+            $result['share_with_displayname'] = $this->getDisplayNameFromAddressBook($share->getSharedWith(), 'CLOUD');
276
+            $result['token'] = $share->getToken();
277
+        } elseif ($share->getShareType() === IShare::TYPE_EMAIL) {
278
+            $result['share_with'] = $share->getSharedWith();
279
+            $result['password'] = $share->getPassword();
280
+            $result['send_password_by_talk'] = $share->getSendPasswordByTalk();
281
+            $result['share_with_displayname'] = $this->getDisplayNameFromAddressBook($share->getSharedWith(), 'EMAIL');
282
+            $result['token'] = $share->getToken();
283
+        } elseif ($share->getShareType() === IShare::TYPE_CIRCLE) {
284
+            // getSharedWith() returns either "name (type, owner)" or
285
+            // "name (type, owner) [id]", depending on the Circles app version.
286
+            $hasCircleId = (substr($share->getSharedWith(), -1) === ']');
287
+
288
+            $result['share_with_displayname'] = $share->getSharedWithDisplayName();
289
+            if (empty($result['share_with_displayname'])) {
290
+                $displayNameLength = ($hasCircleId ? strrpos($share->getSharedWith(), ' ') : strlen($share->getSharedWith()));
291
+                $result['share_with_displayname'] = substr($share->getSharedWith(), 0, $displayNameLength);
292
+            }
293
+
294
+            $result['share_with_avatar'] = $share->getSharedWithAvatar();
295
+
296
+            $shareWithStart = ($hasCircleId ? strrpos($share->getSharedWith(), '[') + 1 : 0);
297
+            $shareWithLength = ($hasCircleId ? -1 : strpos($share->getSharedWith(), ' '));
298
+            if (is_bool($shareWithLength)) {
299
+                $shareWithLength = -1;
300
+            }
301
+            $result['share_with'] = substr($share->getSharedWith(), $shareWithStart, $shareWithLength);
302
+        } elseif ($share->getShareType() === IShare::TYPE_ROOM) {
303
+            $result['share_with'] = $share->getSharedWith();
304
+            $result['share_with_displayname'] = '';
305
+
306
+            try {
307
+                $result = array_merge($result, $this->getRoomShareHelper()->formatShare($share));
308
+            } catch (QueryException $e) {
309
+            }
310
+        } elseif ($share->getShareType() === IShare::TYPE_DECK) {
311
+            $result['share_with'] = $share->getSharedWith();
312
+            $result['share_with_displayname'] = '';
313
+
314
+            try {
315
+                $result = array_merge($result, $this->getDeckShareHelper()->formatShare($share));
316
+            } catch (QueryException $e) {
317
+            }
318
+        }
319
+
320
+
321
+        $result['mail_send'] = $share->getMailSend() ? 1 : 0;
322
+        $result['hide_download'] = $share->getHideDownload() ? 1 : 0;
323
+
324
+        return $result;
325
+    }
326
+
327
+    /**
328
+     * Check if one of the users address books knows the exact property, if
329
+     * yes we return the full name.
330
+     *
331
+     * @param string $query
332
+     * @param string $property
333
+     * @return string
334
+     */
335
+    private function getDisplayNameFromAddressBook(string $query, string $property): string {
336
+        // FIXME: If we inject the contacts manager it gets initialized bofore any address books are registered
337
+        $result = \OC::$server->getContactsManager()->search($query, [$property]);
338
+        foreach ($result as $r) {
339
+            foreach ($r[$property] as $value) {
340
+                if ($value === $query && $r['FN']) {
341
+                    return $r['FN'];
342
+                }
343
+            }
344
+        }
345
+
346
+        return $query;
347
+    }
348
+
349
+    /**
350
+     * Get a specific share by id
351
+     *
352
+     * @NoAdminRequired
353
+     *
354
+     * @param string $id
355
+     * @return DataResponse
356
+     * @throws OCSNotFoundException
357
+     */
358
+    public function getShare(string $id): DataResponse {
359
+        try {
360
+            $share = $this->getShareById($id);
361
+        } catch (ShareNotFound $e) {
362
+            throw new OCSNotFoundException($this->l->t('Wrong share ID, share doesn\'t exist'));
363
+        }
364
+
365
+        try {
366
+            if ($this->canAccessShare($share)) {
367
+                $share = $this->formatShare($share);
368
+                return new DataResponse([$share]);
369
+            }
370
+        } catch (NotFoundException $e) {
371
+            // Fall trough
372
+        }
373
+
374
+        throw new OCSNotFoundException($this->l->t('Wrong share ID, share doesn\'t exist'));
375
+    }
376
+
377
+    /**
378
+     * Delete a share
379
+     *
380
+     * @NoAdminRequired
381
+     *
382
+     * @param string $id
383
+     * @return DataResponse
384
+     * @throws OCSNotFoundException
385
+     */
386
+    public function deleteShare(string $id): DataResponse {
387
+        try {
388
+            $share = $this->getShareById($id);
389
+        } catch (ShareNotFound $e) {
390
+            throw new OCSNotFoundException($this->l->t('Wrong share ID, share doesn\'t exist'));
391
+        }
392
+
393
+        try {
394
+            $this->lock($share->getNode());
395
+        } catch (LockedException $e) {
396
+            throw new OCSNotFoundException($this->l->t('Could not delete share'));
397
+        }
398
+
399
+        if (!$this->canAccessShare($share)) {
400
+            throw new OCSNotFoundException($this->l->t('Wrong share ID, share doesn\'t exist'));
401
+        }
402
+
403
+        // if it's a group share or a room share
404
+        // we don't delete the share, but only the
405
+        // mount point. Allowing it to be restored
406
+        // from the deleted shares
407
+        if ($this->canDeleteShareFromSelf($share)) {
408
+            $this->shareManager->deleteFromSelf($share, $this->currentUser);
409
+        } else {
410
+            if (!$this->canDeleteShare($share)) {
411
+                throw new OCSForbiddenException($this->l->t('Could not delete share'));
412
+            }
413
+
414
+            $this->shareManager->deleteShare($share);
415
+        }
416
+
417
+        return new DataResponse();
418
+    }
419
+
420
+    /**
421
+     * @NoAdminRequired
422
+     *
423
+     * @param string $path
424
+     * @param int $permissions
425
+     * @param int $shareType
426
+     * @param string $shareWith
427
+     * @param string $publicUpload
428
+     * @param string $password
429
+     * @param string $sendPasswordByTalk
430
+     * @param string $expireDate
431
+     * @param string $label
432
+     *
433
+     * @return DataResponse
434
+     * @throws NotFoundException
435
+     * @throws OCSBadRequestException
436
+     * @throws OCSException
437
+     * @throws OCSForbiddenException
438
+     * @throws OCSNotFoundException
439
+     * @throws InvalidPathException
440
+     * @suppress PhanUndeclaredClassMethod
441
+     */
442
+    public function createShare(
443
+        string $path = null,
444
+        int $permissions = null,
445
+        int $shareType = -1,
446
+        string $shareWith = null,
447
+        string $publicUpload = 'false',
448
+        string $password = '',
449
+        string $sendPasswordByTalk = null,
450
+        string $expireDate = '',
451
+        string $label = ''
452
+    ): DataResponse {
453
+        $share = $this->shareManager->newShare();
454
+
455
+        if ($permissions === null) {
456
+            $permissions = $this->config->getAppValue('core', 'shareapi_default_permissions', Constants::PERMISSION_ALL);
457
+        }
458
+
459
+        // Verify path
460
+        if ($path === null) {
461
+            throw new OCSNotFoundException($this->l->t('Please specify a file or folder path'));
462
+        }
463
+
464
+        $userFolder = $this->rootFolder->getUserFolder($this->currentUser);
465
+        try {
466
+            $path = $userFolder->get($path);
467
+        } catch (NotFoundException $e) {
468
+            throw new OCSNotFoundException($this->l->t('Wrong path, file/folder doesn\'t exist'));
469
+        }
470
+
471
+        $share->setNode($path);
472
+
473
+        try {
474
+            $this->lock($share->getNode());
475
+        } catch (LockedException $e) {
476
+            throw new OCSNotFoundException($this->l->t('Could not create share'));
477
+        }
478
+
479
+        if ($permissions < 0 || $permissions > Constants::PERMISSION_ALL) {
480
+            throw new OCSNotFoundException($this->l->t('invalid permissions'));
481
+        }
482
+
483
+        // Shares always require read permissions
484
+        $permissions |= Constants::PERMISSION_READ;
485
+
486
+        if ($path instanceof \OCP\Files\File) {
487
+            // Single file shares should never have delete or create permissions
488
+            $permissions &= ~Constants::PERMISSION_DELETE;
489
+            $permissions &= ~Constants::PERMISSION_CREATE;
490
+        }
491
+
492
+        /**
493
+         * Hack for https://github.com/owncloud/core/issues/22587
494
+         * We check the permissions via webdav. But the permissions of the mount point
495
+         * do not equal the share permissions. Here we fix that for federated mounts.
496
+         */
497
+        if ($path->getStorage()->instanceOfStorage(Storage::class)) {
498
+            $permissions &= ~($permissions & ~$path->getPermissions());
499
+        }
500
+
501
+        if ($shareType === IShare::TYPE_USER) {
502
+            // Valid user is required to share
503
+            if ($shareWith === null || !$this->userManager->userExists($shareWith)) {
504
+                throw new OCSNotFoundException($this->l->t('Please specify a valid user'));
505
+            }
506
+            $share->setSharedWith($shareWith);
507
+            $share->setPermissions($permissions);
508
+        } elseif ($shareType === IShare::TYPE_GROUP) {
509
+            if (!$this->shareManager->allowGroupSharing()) {
510
+                throw new OCSNotFoundException($this->l->t('Group sharing is disabled by the administrator'));
511
+            }
512
+
513
+            // Valid group is required to share
514
+            if ($shareWith === null || !$this->groupManager->groupExists($shareWith)) {
515
+                throw new OCSNotFoundException($this->l->t('Please specify a valid group'));
516
+            }
517
+            $share->setSharedWith($shareWith);
518
+            $share->setPermissions($permissions);
519
+        } elseif ($shareType === IShare::TYPE_LINK
520
+            || $shareType === IShare::TYPE_EMAIL) {
521
+
522
+            // Can we even share links?
523
+            if (!$this->shareManager->shareApiAllowLinks()) {
524
+                throw new OCSNotFoundException($this->l->t('Public link sharing is disabled by the administrator'));
525
+            }
526
+
527
+            if ($publicUpload === 'true') {
528
+                // Check if public upload is allowed
529
+                if (!$this->shareManager->shareApiLinkAllowPublicUpload()) {
530
+                    throw new OCSForbiddenException($this->l->t('Public upload disabled by the administrator'));
531
+                }
532
+
533
+                // Public upload can only be set for folders
534
+                if ($path instanceof \OCP\Files\File) {
535
+                    throw new OCSNotFoundException($this->l->t('Public upload is only possible for publicly shared folders'));
536
+                }
537
+
538
+                $permissions = Constants::PERMISSION_READ |
539
+                    Constants::PERMISSION_CREATE |
540
+                    Constants::PERMISSION_UPDATE |
541
+                    Constants::PERMISSION_DELETE;
542
+            } else {
543
+                $permissions = Constants::PERMISSION_READ;
544
+            }
545
+
546
+            // TODO: It might make sense to have a dedicated setting to allow/deny converting link shares into federated ones
547
+            if (($permissions & Constants::PERMISSION_READ) && $this->shareManager->outgoingServer2ServerSharesAllowed()) {
548
+                $permissions |= Constants::PERMISSION_SHARE;
549
+            }
550
+
551
+            $share->setPermissions($permissions);
552
+
553
+            // Set password
554
+            if ($password !== '') {
555
+                $share->setPassword($password);
556
+            }
557
+
558
+            // Only share by mail have a recipient
559
+            if ($shareType === IShare::TYPE_EMAIL) {
560
+                $share->setSharedWith($shareWith);
561
+            } else {
562
+                // Only link share have a label
563
+                if (!empty($label)) {
564
+                    $share->setLabel($label);
565
+                }
566
+            }
567
+
568
+            if ($sendPasswordByTalk === 'true') {
569
+                if (!$this->appManager->isEnabledForUser('spreed')) {
570
+                    throw new OCSForbiddenException($this->l->t('Sharing %s sending the password by Nextcloud Talk failed because Nextcloud Talk is not enabled', [$path->getPath()]));
571
+                }
572
+
573
+                $share->setSendPasswordByTalk(true);
574
+            }
575
+
576
+            //Expire date
577
+            if ($expireDate !== '') {
578
+                try {
579
+                    $expireDate = $this->parseDate($expireDate);
580
+                    $share->setExpirationDate($expireDate);
581
+                } catch (\Exception $e) {
582
+                    throw new OCSNotFoundException($this->l->t('Invalid date, date format must be YYYY-MM-DD'));
583
+                }
584
+            }
585
+        } elseif ($shareType === IShare::TYPE_REMOTE) {
586
+            if (!$this->shareManager->outgoingServer2ServerSharesAllowed()) {
587
+                throw new OCSForbiddenException($this->l->t('Sharing %1$s failed because the back end does not allow shares from type %2$s', [$path->getPath(), $shareType]));
588
+            }
589
+
590
+            $share->setSharedWith($shareWith);
591
+            $share->setPermissions($permissions);
592
+        } elseif ($shareType === IShare::TYPE_REMOTE_GROUP) {
593
+            if (!$this->shareManager->outgoingServer2ServerGroupSharesAllowed()) {
594
+                throw new OCSForbiddenException($this->l->t('Sharing %1$s failed because the back end does not allow shares from type %2$s', [$path->getPath(), $shareType]));
595
+            }
596
+
597
+            $share->setSharedWith($shareWith);
598
+            $share->setPermissions($permissions);
599
+        } elseif ($shareType === IShare::TYPE_CIRCLE) {
600
+            if (!\OC::$server->getAppManager()->isEnabledForUser('circles') || !class_exists('\OCA\Circles\ShareByCircleProvider')) {
601
+                throw new OCSNotFoundException($this->l->t('You cannot share to a Circle if the app is not enabled'));
602
+            }
603
+
604
+            $circle = \OCA\Circles\Api\v1\Circles::detailsCircle($shareWith);
605
+
606
+            // Valid circle is required to share
607
+            if ($circle === null) {
608
+                throw new OCSNotFoundException($this->l->t('Please specify a valid circle'));
609
+            }
610
+            $share->setSharedWith($shareWith);
611
+            $share->setPermissions($permissions);
612
+        } elseif ($shareType === IShare::TYPE_ROOM) {
613
+            try {
614
+                $this->getRoomShareHelper()->createShare($share, $shareWith, $permissions, $expireDate);
615
+            } catch (QueryException $e) {
616
+                throw new OCSForbiddenException($this->l->t('Sharing %s failed because the back end does not support room shares', [$path->getPath()]));
617
+            }
618
+        } elseif ($shareType === IShare::TYPE_DECK) {
619
+            try {
620
+                $this->getDeckShareHelper()->createShare($share, $shareWith, $permissions, $expireDate);
621
+            } catch (QueryException $e) {
622
+                throw new OCSForbiddenException($this->l->t('Sharing %s failed because the back end does not support room shares', [$path->getPath()]));
623
+            }
624
+        } else {
625
+            throw new OCSBadRequestException($this->l->t('Unknown share type'));
626
+        }
627
+
628
+        $share->setShareType($shareType);
629
+        $share->setSharedBy($this->currentUser);
630
+
631
+        try {
632
+            $share = $this->shareManager->createShare($share);
633
+        } catch (GenericShareException $e) {
634
+            $code = $e->getCode() === 0 ? 403 : $e->getCode();
635
+            throw new OCSException($e->getHint(), $code);
636
+        } catch (\Exception $e) {
637
+            throw new OCSForbiddenException($e->getMessage(), $e);
638
+        }
639
+
640
+        $output = $this->formatShare($share);
641
+
642
+        return new DataResponse($output);
643
+    }
644
+
645
+    /**
646
+     * @param null|Node $node
647
+     * @param boolean $includeTags
648
+     *
649
+     * @return array
650
+     */
651
+    private function getSharedWithMe($node, bool $includeTags): array {
652
+        $userShares = $this->shareManager->getSharedWith($this->currentUser, IShare::TYPE_USER, $node, -1, 0);
653
+        $groupShares = $this->shareManager->getSharedWith($this->currentUser, IShare::TYPE_GROUP, $node, -1, 0);
654
+        $circleShares = $this->shareManager->getSharedWith($this->currentUser, IShare::TYPE_CIRCLE, $node, -1, 0);
655
+        $roomShares = $this->shareManager->getSharedWith($this->currentUser, IShare::TYPE_ROOM, $node, -1, 0);
656
+        $deckShares = $this->shareManager->getSharedWith($this->currentUser, IShare::TYPE_DECK, $node, -1, 0);
657
+
658
+        $shares = array_merge($userShares, $groupShares, $circleShares, $roomShares, $deckShares);
659
+
660
+        $filteredShares = array_filter($shares, function (IShare $share) {
661
+            return $share->getShareOwner() !== $this->currentUser;
662
+        });
663
+
664
+        $formatted = [];
665
+        foreach ($filteredShares as $share) {
666
+            if ($this->canAccessShare($share)) {
667
+                try {
668
+                    $formatted[] = $this->formatShare($share);
669
+                } catch (NotFoundException $e) {
670
+                    // Ignore this share
671
+                }
672
+            }
673
+        }
674
+
675
+        if ($includeTags) {
676
+            $formatted = Helper::populateTags($formatted, 'file_source', \OC::$server->getTagManager());
677
+        }
678
+
679
+        return $formatted;
680
+    }
681
+
682
+    /**
683
+     * @param \OCP\Files\Node $folder
684
+     *
685
+     * @return array
686
+     * @throws OCSBadRequestException
687
+     * @throws NotFoundException
688
+     */
689
+    private function getSharesInDir(Node $folder): array {
690
+        if (!($folder instanceof \OCP\Files\Folder)) {
691
+            throw new OCSBadRequestException($this->l->t('Not a directory'));
692
+        }
693
+
694
+        $nodes = $folder->getDirectoryListing();
695
+
696
+        /** @var \OCP\Share\IShare[] $shares */
697
+        $shares = array_reduce($nodes, function ($carry, $node) {
698
+            $carry = array_merge($carry, $this->getAllShares($node, true));
699
+            return $carry;
700
+        }, []);
701
+
702
+        // filter out duplicate shares
703
+        $known = [];
704
+
705
+
706
+        $formatted = $miniFormatted = [];
707
+        $resharingRight = false;
708
+        $known = [];
709
+        foreach ($shares as $share) {
710
+            if (in_array($share->getId(), $known) || $share->getSharedWith() === $this->currentUser) {
711
+                continue;
712
+            }
713
+
714
+            try {
715
+                $format = $this->formatShare($share);
716
+
717
+                $known[] = $share->getId();
718
+                $formatted[] = $format;
719
+                if ($share->getSharedBy() === $this->currentUser) {
720
+                    $miniFormatted[] = $format;
721
+                }
722
+                if (!$resharingRight && $this->shareProviderResharingRights($this->currentUser, $share, $folder)) {
723
+                    $resharingRight = true;
724
+                }
725
+            } catch (\Exception $e) {
726
+                //Ignore this share
727
+            }
728
+        }
729
+
730
+        if (!$resharingRight) {
731
+            $formatted = $miniFormatted;
732
+        }
733
+
734
+        return $formatted;
735
+    }
736
+
737
+    /**
738
+     * The getShares function.
739
+     *
740
+     * @NoAdminRequired
741
+     *
742
+     * @param string $shared_with_me
743
+     * @param string $reshares
744
+     * @param string $subfiles
745
+     * @param string $path
746
+     *
747
+     * - Get shares by the current user
748
+     * - Get shares by the current user and reshares (?reshares=true)
749
+     * - Get shares with the current user (?shared_with_me=true)
750
+     * - Get shares for a specific path (?path=...)
751
+     * - Get all shares in a folder (?subfiles=true&path=..)
752
+     *
753
+     * @param string $include_tags
754
+     *
755
+     * @return DataResponse
756
+     * @throws NotFoundException
757
+     * @throws OCSBadRequestException
758
+     * @throws OCSNotFoundException
759
+     */
760
+    public function getShares(
761
+        string $shared_with_me = 'false',
762
+        string $reshares = 'false',
763
+        string $subfiles = 'false',
764
+        string $path = '',
765
+        string $include_tags = 'false'
766
+    ): DataResponse {
767
+        $node = null;
768
+        if ($path !== '') {
769
+            $userFolder = $this->rootFolder->getUserFolder($this->currentUser);
770
+            try {
771
+                $node = $userFolder->get($path);
772
+                $this->lock($node);
773
+            } catch (NotFoundException $e) {
774
+                throw new OCSNotFoundException(
775
+                    $this->l->t('Wrong path, file/folder doesn\'t exist')
776
+                );
777
+            } catch (LockedException $e) {
778
+                throw new OCSNotFoundException($this->l->t('Could not lock node'));
779
+            }
780
+        }
781
+
782
+        $shares = $this->getFormattedShares(
783
+            $this->currentUser,
784
+            $node,
785
+            ($shared_with_me === 'true'),
786
+            ($reshares === 'true'),
787
+            ($subfiles === 'true'),
788
+            ($include_tags === 'true')
789
+        );
790
+
791
+        return new DataResponse($shares);
792
+    }
793
+
794
+
795
+    /**
796
+     * @param string $viewer
797
+     * @param Node $node
798
+     * @param bool $sharedWithMe
799
+     * @param bool $reShares
800
+     * @param bool $subFiles
801
+     * @param bool $includeTags
802
+     *
803
+     * @return array
804
+     * @throws NotFoundException
805
+     * @throws OCSBadRequestException
806
+     */
807
+    private function getFormattedShares(
808
+        string $viewer,
809
+        $node = null,
810
+        bool $sharedWithMe = false,
811
+        bool $reShares = false,
812
+        bool $subFiles = false,
813
+        bool $includeTags = false
814
+    ): array {
815
+        if ($sharedWithMe) {
816
+            return $this->getSharedWithMe($node, $includeTags);
817
+        }
818
+
819
+        if ($subFiles) {
820
+            return $this->getSharesInDir($node);
821
+        }
822
+
823
+        $shares = $this->getSharesFromNode($viewer, $node, $reShares);
824
+
825
+        $known = $formatted = $miniFormatted = [];
826
+        $resharingRight = false;
827
+        foreach ($shares as $share) {
828
+            try {
829
+                $share->getNode();
830
+            } catch (NotFoundException $e) {
831
+                /*
832 832
 				 * Ignore shares where we can't get the node
833 833
 				 * For example deleted shares
834 834
 				 */
835
-				continue;
836
-			}
837
-
838
-			if (in_array($share->getId(), $known)
839
-				|| ($share->getSharedWith() === $this->currentUser && $share->getShareType() === IShare::TYPE_USER)) {
840
-				continue;
841
-			}
842
-
843
-			$known[] = $share->getId();
844
-			try {
845
-				/** @var IShare $share */
846
-				$format = $this->formatShare($share, $node);
847
-				$formatted[] = $format;
848
-
849
-				// let's also build a list of shares created
850
-				// by the current user only, in case
851
-				// there is no resharing rights
852
-				if ($share->getSharedBy() === $this->currentUser) {
853
-					$miniFormatted[] = $format;
854
-				}
855
-
856
-				// check if one of those share is shared with me
857
-				// and if I have resharing rights on it
858
-				if (!$resharingRight && $this->shareProviderResharingRights($this->currentUser, $share, $node)) {
859
-					$resharingRight = true;
860
-				}
861
-			} catch (InvalidPathException | NotFoundException $e) {
862
-			}
863
-		}
864
-
865
-		if (!$resharingRight) {
866
-			$formatted = $miniFormatted;
867
-		}
868
-
869
-		if ($includeTags) {
870
-			$formatted =
871
-				Helper::populateTags($formatted, 'file_source', \OC::$server->getTagManager());
872
-		}
873
-
874
-		return $formatted;
875
-	}
876
-
877
-
878
-	/**
879
-	 * The getInheritedShares function.
880
-	 * returns all shares relative to a file, including parent folders shares rights.
881
-	 *
882
-	 * @NoAdminRequired
883
-	 *
884
-	 * @param string $path
885
-	 *
886
-	 * - Get shares by the current user
887
-	 * - Get shares by the current user and reshares (?reshares=true)
888
-	 * - Get shares with the current user (?shared_with_me=true)
889
-	 * - Get shares for a specific path (?path=...)
890
-	 * - Get all shares in a folder (?subfiles=true&path=..)
891
-	 *
892
-	 * @return DataResponse
893
-	 * @throws InvalidPathException
894
-	 * @throws NotFoundException
895
-	 * @throws OCSNotFoundException
896
-	 * @throws OCSBadRequestException
897
-	 * @throws SharingRightsException
898
-	 */
899
-	public function getInheritedShares(string $path): DataResponse {
900
-
901
-		// get Node from (string) path.
902
-		$userFolder = $this->rootFolder->getUserFolder($this->currentUser);
903
-		try {
904
-			$node = $userFolder->get($path);
905
-			$this->lock($node);
906
-		} catch (\OCP\Files\NotFoundException $e) {
907
-			throw new OCSNotFoundException($this->l->t('Wrong path, file/folder doesn\'t exist'));
908
-		} catch (LockedException $e) {
909
-			throw new OCSNotFoundException($this->l->t('Could not lock path'));
910
-		}
911
-
912
-		if (!($node->getPermissions() & Constants::PERMISSION_SHARE)) {
913
-			throw new SharingRightsException('no sharing rights on this item');
914
-		}
915
-
916
-		// The current top parent we have access to
917
-		$parent = $node;
918
-
919
-		// initiate real owner.
920
-		$owner = $node->getOwner()
921
-					  ->getUID();
922
-		if (!$this->userManager->userExists($owner)) {
923
-			return new DataResponse([]);
924
-		}
925
-
926
-		// get node based on the owner, fix owner in case of external storage
927
-		$userFolder = $this->rootFolder->getUserFolder($owner);
928
-		if ($node->getId() !== $userFolder->getId() && !$userFolder->isSubNode($node)) {
929
-			$owner = $node->getOwner()
930
-						  ->getUID();
931
-			$userFolder = $this->rootFolder->getUserFolder($owner);
932
-			$nodes = $userFolder->getById($node->getId());
933
-			$node = array_shift($nodes);
934
-		}
935
-		$basePath = $userFolder->getPath();
936
-
937
-		// generate node list for each parent folders
938
-		/** @var Node[] $nodes */
939
-		$nodes = [];
940
-		while ($node->getPath() !== $basePath) {
941
-			$node = $node->getParent();
942
-			$nodes[] = $node;
943
-		}
944
-
945
-		// The user that is requesting this list
946
-		$currentUserFolder = $this->rootFolder->getUserFolder($this->currentUser);
947
-
948
-		// for each nodes, retrieve shares.
949
-		$shares = [];
950
-
951
-		foreach ($nodes as $node) {
952
-			$getShares = $this->getFormattedShares($owner, $node, false, true);
953
-
954
-			$currentUserNodes = $currentUserFolder->getById($node->getId());
955
-			if (!empty($currentUserNodes)) {
956
-				$parent = array_pop($currentUserNodes);
957
-			}
958
-
959
-			$subPath = $currentUserFolder->getRelativePath($parent->getPath());
960
-			foreach ($getShares as &$share) {
961
-				$share['via_fileid'] = $parent->getId();
962
-				$share['via_path'] = $subPath;
963
-			}
964
-			$this->mergeFormattedShares($shares, $getShares);
965
-		}
966
-
967
-		return new DataResponse(array_values($shares));
968
-	}
969
-
970
-
971
-	/**
972
-	 * @NoAdminRequired
973
-	 *
974
-	 * @param string $id
975
-	 * @param int $permissions
976
-	 * @param string $password
977
-	 * @param string $sendPasswordByTalk
978
-	 * @param string $publicUpload
979
-	 * @param string $expireDate
980
-	 * @param string $note
981
-	 * @param string $label
982
-	 * @param string $hideDownload
983
-	 * @return DataResponse
984
-	 * @throws LockedException
985
-	 * @throws NotFoundException
986
-	 * @throws OCSBadRequestException
987
-	 * @throws OCSForbiddenException
988
-	 * @throws OCSNotFoundException
989
-	 */
990
-	public function updateShare(
991
-		string $id,
992
-		int $permissions = null,
993
-		string $password = null,
994
-		string $sendPasswordByTalk = null,
995
-		string $publicUpload = null,
996
-		string $expireDate = null,
997
-		string $note = null,
998
-		string $label = null,
999
-		string $hideDownload = null
1000
-	): DataResponse {
1001
-		try {
1002
-			$share = $this->getShareById($id);
1003
-		} catch (ShareNotFound $e) {
1004
-			throw new OCSNotFoundException($this->l->t('Wrong share ID, share doesn\'t exist'));
1005
-		}
1006
-
1007
-		$this->lock($share->getNode());
1008
-
1009
-		if (!$this->canAccessShare($share, false)) {
1010
-			throw new OCSNotFoundException($this->l->t('Wrong share ID, share doesn\'t exist'));
1011
-		}
1012
-
1013
-		if (!$this->canEditShare($share)) {
1014
-			throw new OCSForbiddenException('You are not allowed to edit incoming shares');
1015
-		}
1016
-
1017
-		if (
1018
-			$permissions === null &&
1019
-			$password === null &&
1020
-			$sendPasswordByTalk === null &&
1021
-			$publicUpload === null &&
1022
-			$expireDate === null &&
1023
-			$note === null &&
1024
-			$label === null &&
1025
-			$hideDownload === null
1026
-		) {
1027
-			throw new OCSBadRequestException($this->l->t('Wrong or no update parameter given'));
1028
-		}
1029
-
1030
-		if ($note !== null) {
1031
-			$share->setNote($note);
1032
-		}
1033
-
1034
-		/**
1035
-		 * expirationdate, password and publicUpload only make sense for link shares
1036
-		 */
1037
-		if ($share->getShareType() === IShare::TYPE_LINK
1038
-			|| $share->getShareType() === IShare::TYPE_EMAIL) {
1039
-
1040
-			/**
1041
-			 * We do not allow editing link shares that the current user
1042
-			 * doesn't own. This is confusing and lead to errors when
1043
-			 * someone else edit a password or expiration date without
1044
-			 * the share owner knowing about it.
1045
-			 * We only allow deletion
1046
-			 */
1047
-
1048
-			if ($share->getSharedBy() !== $this->currentUser) {
1049
-				throw new OCSForbiddenException('You are not allowed to edit link shares that you don\'t own');
1050
-			}
1051
-
1052
-			// Update hide download state
1053
-			if ($hideDownload === 'true') {
1054
-				$share->setHideDownload(true);
1055
-			} elseif ($hideDownload === 'false') {
1056
-				$share->setHideDownload(false);
1057
-			}
1058
-
1059
-			$newPermissions = null;
1060
-			if ($publicUpload === 'true') {
1061
-				$newPermissions = Constants::PERMISSION_READ | Constants::PERMISSION_CREATE | Constants::PERMISSION_UPDATE | Constants::PERMISSION_DELETE;
1062
-			} elseif ($publicUpload === 'false') {
1063
-				$newPermissions = Constants::PERMISSION_READ;
1064
-			}
1065
-
1066
-			if ($permissions !== null) {
1067
-				$newPermissions = $permissions;
1068
-				$newPermissions = $newPermissions & ~Constants::PERMISSION_SHARE;
1069
-			}
1070
-
1071
-			if ($newPermissions !== null &&
1072
-				!in_array($newPermissions, [
1073
-					Constants::PERMISSION_READ,
1074
-					Constants::PERMISSION_READ | Constants::PERMISSION_CREATE | Constants::PERMISSION_UPDATE, // legacy
1075
-					Constants::PERMISSION_READ | Constants::PERMISSION_CREATE | Constants::PERMISSION_UPDATE | Constants::PERMISSION_DELETE, // correct
1076
-					Constants::PERMISSION_CREATE, // hidden file list
1077
-					Constants::PERMISSION_READ | Constants::PERMISSION_UPDATE, // allow to edit single files
1078
-				], true)
1079
-			) {
1080
-				throw new OCSBadRequestException($this->l->t('Can\'t change permissions for public share links'));
1081
-			}
1082
-
1083
-			if (
1084
-				// legacy
1085
-				$newPermissions === (Constants::PERMISSION_READ | Constants::PERMISSION_CREATE | Constants::PERMISSION_UPDATE) ||
1086
-				// correct
1087
-				$newPermissions === (Constants::PERMISSION_READ | Constants::PERMISSION_CREATE | Constants::PERMISSION_UPDATE | Constants::PERMISSION_DELETE)
1088
-			) {
1089
-				if (!$this->shareManager->shareApiLinkAllowPublicUpload()) {
1090
-					throw new OCSForbiddenException($this->l->t('Public upload disabled by the administrator'));
1091
-				}
1092
-
1093
-				if (!($share->getNode() instanceof \OCP\Files\Folder)) {
1094
-					throw new OCSBadRequestException($this->l->t('Public upload is only possible for publicly shared folders'));
1095
-				}
1096
-
1097
-				// normalize to correct public upload permissions
1098
-				$newPermissions = Constants::PERMISSION_READ | Constants::PERMISSION_CREATE | Constants::PERMISSION_UPDATE | Constants::PERMISSION_DELETE;
1099
-			}
1100
-
1101
-			if ($newPermissions !== null) {
1102
-				// TODO: It might make sense to have a dedicated setting to allow/deny converting link shares into federated ones
1103
-				if (($newPermissions & Constants::PERMISSION_READ) && $this->shareManager->outgoingServer2ServerSharesAllowed()) {
1104
-					$newPermissions |= Constants::PERMISSION_SHARE;
1105
-				}
1106
-
1107
-				$share->setPermissions($newPermissions);
1108
-				$permissions = $newPermissions;
1109
-			}
1110
-
1111
-			if ($expireDate === '') {
1112
-				$share->setExpirationDate(null);
1113
-			} elseif ($expireDate !== null) {
1114
-				try {
1115
-					$expireDate = $this->parseDate($expireDate);
1116
-				} catch (\Exception $e) {
1117
-					throw new OCSBadRequestException($e->getMessage(), $e);
1118
-				}
1119
-				$share->setExpirationDate($expireDate);
1120
-			}
1121
-
1122
-			if ($password === '') {
1123
-				$share->setPassword(null);
1124
-			} elseif ($password !== null) {
1125
-				$share->setPassword($password);
1126
-			}
1127
-
1128
-			// only link shares have labels
1129
-			if ($share->getShareType() === IShare::TYPE_LINK && $label !== null) {
1130
-				if (strlen($label) > 255) {
1131
-					throw new OCSBadRequestException("Maxmimum label length is 255");
1132
-				}
1133
-				$share->setLabel($label);
1134
-			}
1135
-
1136
-			if ($sendPasswordByTalk === 'true') {
1137
-				if (!$this->appManager->isEnabledForUser('spreed')) {
1138
-					throw new OCSForbiddenException($this->l->t('Sharing sending the password by Nextcloud Talk failed because Nextcloud Talk is not enabled'));
1139
-				}
1140
-
1141
-				$share->setSendPasswordByTalk(true);
1142
-			} elseif ($sendPasswordByTalk !== null) {
1143
-				$share->setSendPasswordByTalk(false);
1144
-			}
1145
-		}
1146
-
1147
-		// NOT A LINK SHARE
1148
-		else {
1149
-			if ($permissions !== null) {
1150
-				$share->setPermissions($permissions);
1151
-			}
1152
-
1153
-			if ($expireDate === '') {
1154
-				$share->setExpirationDate(null);
1155
-			} elseif ($expireDate !== null) {
1156
-				try {
1157
-					$expireDate = $this->parseDate($expireDate);
1158
-				} catch (\Exception $e) {
1159
-					throw new OCSBadRequestException($e->getMessage(), $e);
1160
-				}
1161
-				$share->setExpirationDate($expireDate);
1162
-			}
1163
-		}
1164
-
1165
-		try {
1166
-			$share = $this->shareManager->updateShare($share);
1167
-		} catch (GenericShareException $e) {
1168
-			$code = $e->getCode() === 0 ? 403 : $e->getCode();
1169
-			throw new OCSException($e->getHint(), $code);
1170
-		} catch (\Exception $e) {
1171
-			throw new OCSBadRequestException($e->getMessage(), $e);
1172
-		}
1173
-
1174
-		return new DataResponse($this->formatShare($share));
1175
-	}
1176
-
1177
-	/**
1178
-	 * @NoAdminRequired
1179
-	 */
1180
-	public function pendingShares(): DataResponse {
1181
-		$pendingShares = [];
1182
-
1183
-		$shareTypes = [
1184
-			IShare::TYPE_USER,
1185
-			IShare::TYPE_GROUP
1186
-		];
1187
-
1188
-		foreach ($shareTypes as $shareType) {
1189
-			$shares = $this->shareManager->getSharedWith($this->currentUser, $shareType, null, -1, 0);
1190
-
1191
-			foreach ($shares as $share) {
1192
-				if ($share->getStatus() === IShare::STATUS_PENDING || $share->getStatus() === IShare::STATUS_REJECTED) {
1193
-					$pendingShares[] = $share;
1194
-				}
1195
-			}
1196
-		}
1197
-
1198
-		$result = array_filter(array_map(function (IShare $share) {
1199
-			$userFolder = $this->rootFolder->getUserFolder($share->getSharedBy());
1200
-			$nodes = $userFolder->getById($share->getNodeId());
1201
-			if (empty($nodes)) {
1202
-				// fallback to guessing the path
1203
-				$node = $userFolder->get($share->getTarget());
1204
-				if ($node === null || $share->getTarget() === '') {
1205
-					return null;
1206
-				}
1207
-			} else {
1208
-				$node = $nodes[0];
1209
-			}
1210
-
1211
-			try {
1212
-				$formattedShare = $this->formatShare($share, $node);
1213
-				$formattedShare['status'] = $share->getStatus();
1214
-				$formattedShare['path'] = $share->getNode()->getName();
1215
-				$formattedShare['permissions'] = 0;
1216
-				return $formattedShare;
1217
-			} catch (NotFoundException $e) {
1218
-				return null;
1219
-			}
1220
-		}, $pendingShares), function ($entry) {
1221
-			return $entry !== null;
1222
-		});
1223
-
1224
-		return new DataResponse($result);
1225
-	}
1226
-
1227
-	/**
1228
-	 * @NoAdminRequired
1229
-	 *
1230
-	 * @param string $id
1231
-	 * @return DataResponse
1232
-	 * @throws OCSNotFoundException
1233
-	 * @throws OCSException
1234
-	 * @throws OCSBadRequestException
1235
-	 */
1236
-	public function acceptShare(string $id): DataResponse {
1237
-		try {
1238
-			$share = $this->getShareById($id);
1239
-		} catch (ShareNotFound $e) {
1240
-			throw new OCSNotFoundException($this->l->t('Wrong share ID, share doesn\'t exist'));
1241
-		}
1242
-
1243
-		if (!$this->canAccessShare($share)) {
1244
-			throw new OCSNotFoundException($this->l->t('Wrong share ID, share doesn\'t exist'));
1245
-		}
1246
-
1247
-		try {
1248
-			$this->shareManager->acceptShare($share, $this->currentUser);
1249
-		} catch (GenericShareException $e) {
1250
-			$code = $e->getCode() === 0 ? 403 : $e->getCode();
1251
-			throw new OCSException($e->getHint(), $code);
1252
-		} catch (\Exception $e) {
1253
-			throw new OCSBadRequestException($e->getMessage(), $e);
1254
-		}
1255
-
1256
-		return new DataResponse();
1257
-	}
1258
-
1259
-	/**
1260
-	 * Does the user have read permission on the share
1261
-	 *
1262
-	 * @param \OCP\Share\IShare $share the share to check
1263
-	 * @param boolean $checkGroups check groups as well?
1264
-	 * @return boolean
1265
-	 * @throws NotFoundException
1266
-	 *
1267
-	 * @suppress PhanUndeclaredClassMethod
1268
-	 */
1269
-	protected function canAccessShare(\OCP\Share\IShare $share, bool $checkGroups = true): bool {
1270
-		// A file with permissions 0 can't be accessed by us. So Don't show it
1271
-		if ($share->getPermissions() === 0) {
1272
-			return false;
1273
-		}
1274
-
1275
-		// Owner of the file and the sharer of the file can always get share
1276
-		if ($share->getShareOwner() === $this->currentUser
1277
-			|| $share->getSharedBy() === $this->currentUser) {
1278
-			return true;
1279
-		}
1280
-
1281
-		// If the share is shared with you, you can access it!
1282
-		if ($share->getShareType() === IShare::TYPE_USER
1283
-			&& $share->getSharedWith() === $this->currentUser) {
1284
-			return true;
1285
-		}
1286
-
1287
-		// Have reshare rights on the shared file/folder ?
1288
-		// Does the currentUser have access to the shared file?
1289
-		$userFolder = $this->rootFolder->getUserFolder($this->currentUser);
1290
-		$files = $userFolder->getById($share->getNodeId());
1291
-		if (!empty($files) && $this->shareProviderResharingRights($this->currentUser, $share, $files[0])) {
1292
-			return true;
1293
-		}
1294
-
1295
-		// If in the recipient group, you can see the share
1296
-		if ($checkGroups && $share->getShareType() === IShare::TYPE_GROUP) {
1297
-			$sharedWith = $this->groupManager->get($share->getSharedWith());
1298
-			$user = $this->userManager->get($this->currentUser);
1299
-			if ($user !== null && $sharedWith !== null && $sharedWith->inGroup($user)) {
1300
-				return true;
1301
-			}
1302
-		}
1303
-
1304
-		if ($share->getShareType() === IShare::TYPE_CIRCLE) {
1305
-			// TODO: have a sanity check like above?
1306
-			return true;
1307
-		}
1308
-
1309
-		if ($share->getShareType() === IShare::TYPE_ROOM) {
1310
-			try {
1311
-				return $this->getRoomShareHelper()->canAccessShare($share, $this->currentUser);
1312
-			} catch (QueryException $e) {
1313
-				return false;
1314
-			}
1315
-		}
1316
-
1317
-		if ($share->getShareType() === IShare::TYPE_DECK) {
1318
-			try {
1319
-				return $this->getDeckShareHelper()->canAccessShare($share, $this->currentUser);
1320
-			} catch (QueryException $e) {
1321
-				return false;
1322
-			}
1323
-		}
1324
-
1325
-		return false;
1326
-	}
1327
-
1328
-	/**
1329
-	 * Does the user have edit permission on the share
1330
-	 *
1331
-	 * @param \OCP\Share\IShare $share the share to check
1332
-	 * @return boolean
1333
-	 */
1334
-	protected function canEditShare(\OCP\Share\IShare $share): bool {
1335
-		// A file with permissions 0 can't be accessed by us. So Don't show it
1336
-		if ($share->getPermissions() === 0) {
1337
-			return false;
1338
-		}
1339
-
1340
-		// The owner of the file and the creator of the share
1341
-		// can always edit the share
1342
-		if ($share->getShareOwner() === $this->currentUser ||
1343
-			$share->getSharedBy() === $this->currentUser
1344
-		) {
1345
-			return true;
1346
-		}
1347
-
1348
-		//! we do NOT support some kind of `admin` in groups.
1349
-		//! You cannot edit shares shared to a group you're
1350
-		//! a member of if you're not the share owner or the file owner!
1351
-
1352
-		return false;
1353
-	}
1354
-
1355
-	/**
1356
-	 * Does the user have delete permission on the share
1357
-	 *
1358
-	 * @param \OCP\Share\IShare $share the share to check
1359
-	 * @return boolean
1360
-	 */
1361
-	protected function canDeleteShare(\OCP\Share\IShare $share): bool {
1362
-		// A file with permissions 0 can't be accessed by us. So Don't show it
1363
-		if ($share->getPermissions() === 0) {
1364
-			return false;
1365
-		}
1366
-
1367
-		// if the user is the recipient, i can unshare
1368
-		// the share with self
1369
-		if ($share->getShareType() === IShare::TYPE_USER &&
1370
-			$share->getSharedWith() === $this->currentUser
1371
-		) {
1372
-			return true;
1373
-		}
1374
-
1375
-		// The owner of the file and the creator of the share
1376
-		// can always delete the share
1377
-		if ($share->getShareOwner() === $this->currentUser ||
1378
-			$share->getSharedBy() === $this->currentUser
1379
-		) {
1380
-			return true;
1381
-		}
1382
-
1383
-		return false;
1384
-	}
1385
-
1386
-	/**
1387
-	 * Does the user have delete permission on the share
1388
-	 * This differs from the canDeleteShare function as it only
1389
-	 * remove the share for the current user. It does NOT
1390
-	 * completely delete the share but only the mount point.
1391
-	 * It can then be restored from the deleted shares section.
1392
-	 *
1393
-	 * @param \OCP\Share\IShare $share the share to check
1394
-	 * @return boolean
1395
-	 *
1396
-	 * @suppress PhanUndeclaredClassMethod
1397
-	 */
1398
-	protected function canDeleteShareFromSelf(\OCP\Share\IShare $share): bool {
1399
-		if ($share->getShareType() !== IShare::TYPE_GROUP &&
1400
-			$share->getShareType() !== IShare::TYPE_ROOM &&
1401
-			$share->getShareType() !== IShare::TYPE_DECK
1402
-		) {
1403
-			return false;
1404
-		}
1405
-
1406
-		if ($share->getShareOwner() === $this->currentUser ||
1407
-			$share->getSharedBy() === $this->currentUser
1408
-		) {
1409
-			// Delete the whole share, not just for self
1410
-			return false;
1411
-		}
1412
-
1413
-		// If in the recipient group, you can delete the share from self
1414
-		if ($share->getShareType() === IShare::TYPE_GROUP) {
1415
-			$sharedWith = $this->groupManager->get($share->getSharedWith());
1416
-			$user = $this->userManager->get($this->currentUser);
1417
-			if ($user !== null && $sharedWith !== null && $sharedWith->inGroup($user)) {
1418
-				return true;
1419
-			}
1420
-		}
1421
-
1422
-		if ($share->getShareType() === IShare::TYPE_ROOM) {
1423
-			try {
1424
-				return $this->getRoomShareHelper()->canAccessShare($share, $this->currentUser);
1425
-			} catch (QueryException $e) {
1426
-				return false;
1427
-			}
1428
-		}
1429
-
1430
-		if ($share->getShareType() === IShare::TYPE_DECK) {
1431
-			try {
1432
-				return $this->getDeckShareHelper()->canAccessShare($share, $this->currentUser);
1433
-			} catch (QueryException $e) {
1434
-				return false;
1435
-			}
1436
-		}
1437
-
1438
-		return false;
1439
-	}
1440
-
1441
-	/**
1442
-	 * Make sure that the passed date is valid ISO 8601
1443
-	 * So YYYY-MM-DD
1444
-	 * If not throw an exception
1445
-	 *
1446
-	 * @param string $expireDate
1447
-	 *
1448
-	 * @throws \Exception
1449
-	 * @return \DateTime
1450
-	 */
1451
-	private function parseDate(string $expireDate): \DateTime {
1452
-		try {
1453
-			$date = new \DateTime($expireDate);
1454
-		} catch (\Exception $e) {
1455
-			throw new \Exception('Invalid date. Format must be YYYY-MM-DD');
1456
-		}
1457
-
1458
-		if ($date === false) {
1459
-			throw new \Exception('Invalid date. Format must be YYYY-MM-DD');
1460
-		}
1461
-
1462
-		$date->setTime(0, 0, 0);
1463
-
1464
-		return $date;
1465
-	}
1466
-
1467
-	/**
1468
-	 * Since we have multiple providers but the OCS Share API v1 does
1469
-	 * not support this we need to check all backends.
1470
-	 *
1471
-	 * @param string $id
1472
-	 * @return \OCP\Share\IShare
1473
-	 * @throws ShareNotFound
1474
-	 */
1475
-	private function getShareById(string $id): IShare {
1476
-		$share = null;
1477
-
1478
-		// First check if it is an internal share.
1479
-		try {
1480
-			$share = $this->shareManager->getShareById('ocinternal:' . $id, $this->currentUser);
1481
-			return $share;
1482
-		} catch (ShareNotFound $e) {
1483
-			// Do nothing, just try the other share type
1484
-		}
1485
-
1486
-
1487
-		try {
1488
-			if ($this->shareManager->shareProviderExists(IShare::TYPE_CIRCLE)) {
1489
-				$share = $this->shareManager->getShareById('ocCircleShare:' . $id, $this->currentUser);
1490
-				return $share;
1491
-			}
1492
-		} catch (ShareNotFound $e) {
1493
-			// Do nothing, just try the other share type
1494
-		}
1495
-
1496
-		try {
1497
-			if ($this->shareManager->shareProviderExists(IShare::TYPE_EMAIL)) {
1498
-				$share = $this->shareManager->getShareById('ocMailShare:' . $id, $this->currentUser);
1499
-				return $share;
1500
-			}
1501
-		} catch (ShareNotFound $e) {
1502
-			// Do nothing, just try the other share type
1503
-		}
1504
-
1505
-		try {
1506
-			$share = $this->shareManager->getShareById('ocRoomShare:' . $id, $this->currentUser);
1507
-			return $share;
1508
-		} catch (ShareNotFound $e) {
1509
-			// Do nothing, just try the other share type
1510
-		}
1511
-
1512
-		try {
1513
-			if ($this->shareManager->shareProviderExists(IShare::TYPE_DECK)) {
1514
-				$share = $this->shareManager->getShareById('deck:' . $id, $this->currentUser);
1515
-				return $share;
1516
-			}
1517
-		} catch (ShareNotFound $e) {
1518
-			// Do nothing, just try the other share type
1519
-		}
1520
-
1521
-		if (!$this->shareManager->outgoingServer2ServerSharesAllowed()) {
1522
-			throw new ShareNotFound();
1523
-		}
1524
-		$share = $this->shareManager->getShareById('ocFederatedSharing:' . $id, $this->currentUser);
1525
-
1526
-		return $share;
1527
-	}
1528
-
1529
-	/**
1530
-	 * Lock a Node
1531
-	 *
1532
-	 * @param \OCP\Files\Node $node
1533
-	 * @throws LockedException
1534
-	 */
1535
-	private function lock(\OCP\Files\Node $node) {
1536
-		$node->lock(ILockingProvider::LOCK_SHARED);
1537
-		$this->lockedNode = $node;
1538
-	}
1539
-
1540
-	/**
1541
-	 * Cleanup the remaining locks
1542
-	 * @throws LockedException
1543
-	 */
1544
-	public function cleanup() {
1545
-		if ($this->lockedNode !== null) {
1546
-			$this->lockedNode->unlock(ILockingProvider::LOCK_SHARED);
1547
-		}
1548
-	}
1549
-
1550
-	/**
1551
-	 * Returns the helper of ShareAPIController for room shares.
1552
-	 *
1553
-	 * If the Talk application is not enabled or the helper is not available
1554
-	 * a QueryException is thrown instead.
1555
-	 *
1556
-	 * @return \OCA\Talk\Share\Helper\ShareAPIController
1557
-	 * @throws QueryException
1558
-	 */
1559
-	private function getRoomShareHelper() {
1560
-		if (!$this->appManager->isEnabledForUser('spreed')) {
1561
-			throw new QueryException();
1562
-		}
1563
-
1564
-		return $this->serverContainer->get('\OCA\Talk\Share\Helper\ShareAPIController');
1565
-	}
1566
-
1567
-	/**
1568
-	 * Returns the helper of ShareAPIHelper for deck shares.
1569
-	 *
1570
-	 * If the Deck application is not enabled or the helper is not available
1571
-	 * a QueryException is thrown instead.
1572
-	 *
1573
-	 * @return \OCA\Deck\Sharing\ShareAPIHelper
1574
-	 * @throws QueryException
1575
-	 */
1576
-	private function getDeckShareHelper() {
1577
-		if (!$this->appManager->isEnabledForUser('deck')) {
1578
-			throw new QueryException();
1579
-		}
1580
-
1581
-		return $this->serverContainer->get('\OCA\Deck\Sharing\ShareAPIHelper');
1582
-	}
1583
-
1584
-	/**
1585
-	 * @param string $viewer
1586
-	 * @param Node $node
1587
-	 * @param bool $reShares
1588
-	 *
1589
-	 * @return IShare[]
1590
-	 */
1591
-	private function getSharesFromNode(string $viewer, $node, bool $reShares): array {
1592
-		$providers = [
1593
-			IShare::TYPE_USER,
1594
-			IShare::TYPE_GROUP,
1595
-			IShare::TYPE_LINK,
1596
-			IShare::TYPE_EMAIL,
1597
-			IShare::TYPE_EMAIL,
1598
-			IShare::TYPE_CIRCLE,
1599
-			IShare::TYPE_ROOM,
1600
-			IShare::TYPE_DECK
1601
-		];
1602
-
1603
-		// Should we assume that the (currentUser) viewer is the owner of the node !?
1604
-		$shares = [];
1605
-		foreach ($providers as $provider) {
1606
-			if (!$this->shareManager->shareProviderExists($provider)) {
1607
-				continue;
1608
-			}
1609
-
1610
-			$providerShares =
1611
-				$this->shareManager->getSharesBy($viewer, $provider, $node, $reShares, -1, 0);
1612
-			$shares = array_merge($shares, $providerShares);
1613
-		}
1614
-
1615
-		if ($this->shareManager->outgoingServer2ServerSharesAllowed()) {
1616
-			$federatedShares = $this->shareManager->getSharesBy(
1617
-				$this->currentUser, IShare::TYPE_REMOTE, $node, $reShares, -1, 0
1618
-			);
1619
-			$shares = array_merge($shares, $federatedShares);
1620
-		}
1621
-
1622
-		if ($this->shareManager->outgoingServer2ServerGroupSharesAllowed()) {
1623
-			$federatedShares = $this->shareManager->getSharesBy(
1624
-				$this->currentUser, IShare::TYPE_REMOTE_GROUP, $node, $reShares, -1, 0
1625
-			);
1626
-			$shares = array_merge($shares, $federatedShares);
1627
-		}
1628
-
1629
-		return $shares;
1630
-	}
1631
-
1632
-
1633
-	/**
1634
-	 * @param Node $node
1635
-	 *
1636
-	 * @throws SharingRightsException
1637
-	 */
1638
-	private function confirmSharingRights(Node $node): void {
1639
-		if (!$this->hasResharingRights($this->currentUser, $node)) {
1640
-			throw new SharingRightsException('no sharing rights on this item');
1641
-		}
1642
-	}
1643
-
1644
-
1645
-	/**
1646
-	 * @param string $viewer
1647
-	 * @param Node $node
1648
-	 *
1649
-	 * @return bool
1650
-	 */
1651
-	private function hasResharingRights($viewer, $node): bool {
1652
-		if ($viewer === $node->getOwner()->getUID()) {
1653
-			return true;
1654
-		}
1655
-
1656
-		foreach ([$node, $node->getParent()] as $node) {
1657
-			$shares = $this->getSharesFromNode($viewer, $node, true);
1658
-			foreach ($shares as $share) {
1659
-				try {
1660
-					if ($this->shareProviderResharingRights($viewer, $share, $node)) {
1661
-						return true;
1662
-					}
1663
-				} catch (InvalidPathException | NotFoundException $e) {
1664
-				}
1665
-			}
1666
-		}
1667
-
1668
-		return false;
1669
-	}
1670
-
1671
-
1672
-	/**
1673
-	 * Returns if we can find resharing rights in an IShare object for a specific user.
1674
-	 *
1675
-	 * @suppress PhanUndeclaredClassMethod
1676
-	 *
1677
-	 * @param string $userId
1678
-	 * @param IShare $share
1679
-	 * @param Node $node
1680
-	 *
1681
-	 * @return bool
1682
-	 * @throws NotFoundException
1683
-	 * @throws InvalidPathException
1684
-	 */
1685
-	private function shareProviderResharingRights(string $userId, IShare $share, $node): bool {
1686
-		if ($share->getShareOwner() === $userId) {
1687
-			return true;
1688
-		}
1689
-
1690
-		// we check that current user have parent resharing rights on the current file
1691
-		if ($node !== null && ($node->getPermissions() & Constants::PERMISSION_SHARE) !== 0) {
1692
-			return true;
1693
-		}
1694
-
1695
-		if ((\OCP\Constants::PERMISSION_SHARE & $share->getPermissions()) === 0) {
1696
-			return false;
1697
-		}
1698
-
1699
-		if ($share->getShareType() === IShare::TYPE_USER && $share->getSharedWith() === $userId) {
1700
-			return true;
1701
-		}
1702
-
1703
-		if ($share->getShareType() === IShare::TYPE_GROUP && $this->groupManager->isInGroup($userId, $share->getSharedWith())) {
1704
-			return true;
1705
-		}
1706
-
1707
-		if ($share->getShareType() === IShare::TYPE_CIRCLE && \OC::$server->getAppManager()->isEnabledForUser('circles')
1708
-			&& class_exists('\OCA\Circles\Api\v1\Circles')) {
1709
-			$hasCircleId = (substr($share->getSharedWith(), -1) === ']');
1710
-			$shareWithStart = ($hasCircleId ? strrpos($share->getSharedWith(), '[') + 1 : 0);
1711
-			$shareWithLength = ($hasCircleId ? -1 : strpos($share->getSharedWith(), ' '));
1712
-			if ($shareWithLength === false) {
1713
-				$sharedWith = substr($share->getSharedWith(), $shareWithStart);
1714
-			} else {
1715
-				$sharedWith = substr($share->getSharedWith(), $shareWithStart, $shareWithLength);
1716
-			}
1717
-			try {
1718
-				$member = \OCA\Circles\Api\v1\Circles::getMember($sharedWith, $userId, 1);
1719
-				if ($member->getLevel() >= 4) {
1720
-					return true;
1721
-				}
1722
-				return false;
1723
-			} catch (QueryException $e) {
1724
-				return false;
1725
-			}
1726
-		}
1727
-
1728
-		return false;
1729
-	}
1730
-
1731
-	/**
1732
-	 * Get all the shares for the current user
1733
-	 *
1734
-	 * @param Node|null $path
1735
-	 * @param boolean $reshares
1736
-	 * @return IShare[]
1737
-	 */
1738
-	private function getAllShares(?Node $path = null, bool $reshares = false) {
1739
-		// Get all shares
1740
-		$userShares = $this->shareManager->getSharesBy($this->currentUser, IShare::TYPE_USER, $path, $reshares, -1, 0);
1741
-		$groupShares = $this->shareManager->getSharesBy($this->currentUser, IShare::TYPE_GROUP, $path, $reshares, -1, 0);
1742
-		$linkShares = $this->shareManager->getSharesBy($this->currentUser, IShare::TYPE_LINK, $path, $reshares, -1, 0);
1743
-
1744
-		// EMAIL SHARES
1745
-		$mailShares = $this->shareManager->getSharesBy($this->currentUser, IShare::TYPE_EMAIL, $path, $reshares, -1, 0);
1746
-
1747
-		// CIRCLE SHARES
1748
-		$circleShares = $this->shareManager->getSharesBy($this->currentUser, IShare::TYPE_CIRCLE, $path, $reshares, -1, 0);
1749
-
1750
-		// TALK SHARES
1751
-		$roomShares = $this->shareManager->getSharesBy($this->currentUser, IShare::TYPE_ROOM, $path, $reshares, -1, 0);
1752
-
1753
-		$deckShares = $this->shareManager->getSharesBy($this->currentUser, IShare::TYPE_DECK, $path, $reshares, -1, 0);
1754
-
1755
-		// FEDERATION
1756
-		if ($this->shareManager->outgoingServer2ServerSharesAllowed()) {
1757
-			$federatedShares = $this->shareManager->getSharesBy($this->currentUser, IShare::TYPE_REMOTE, $path, $reshares, -1, 0);
1758
-		} else {
1759
-			$federatedShares = [];
1760
-		}
1761
-		if ($this->shareManager->outgoingServer2ServerGroupSharesAllowed()) {
1762
-			$federatedGroupShares = $this->shareManager->getSharesBy($this->currentUser, IShare::TYPE_REMOTE_GROUP, $path, $reshares, -1, 0);
1763
-		} else {
1764
-			$federatedGroupShares = [];
1765
-		}
1766
-
1767
-		return array_merge($userShares, $groupShares, $linkShares, $mailShares, $circleShares, $roomShares, $deckShares, $federatedShares, $federatedGroupShares);
1768
-	}
1769
-
1770
-
1771
-	/**
1772
-	 * merging already formatted shares.
1773
-	 * We'll make an associative array to easily detect duplicate Ids.
1774
-	 * Keys _needs_ to be removed after all shares are retrieved and merged.
1775
-	 *
1776
-	 * @param array $shares
1777
-	 * @param array $newShares
1778
-	 */
1779
-	private function mergeFormattedShares(array &$shares, array $newShares) {
1780
-		foreach ($newShares as $newShare) {
1781
-			if (!array_key_exists($newShare['id'], $shares)) {
1782
-				$shares[$newShare['id']] = $newShare;
1783
-			}
1784
-		}
1785
-	}
835
+                continue;
836
+            }
837
+
838
+            if (in_array($share->getId(), $known)
839
+                || ($share->getSharedWith() === $this->currentUser && $share->getShareType() === IShare::TYPE_USER)) {
840
+                continue;
841
+            }
842
+
843
+            $known[] = $share->getId();
844
+            try {
845
+                /** @var IShare $share */
846
+                $format = $this->formatShare($share, $node);
847
+                $formatted[] = $format;
848
+
849
+                // let's also build a list of shares created
850
+                // by the current user only, in case
851
+                // there is no resharing rights
852
+                if ($share->getSharedBy() === $this->currentUser) {
853
+                    $miniFormatted[] = $format;
854
+                }
855
+
856
+                // check if one of those share is shared with me
857
+                // and if I have resharing rights on it
858
+                if (!$resharingRight && $this->shareProviderResharingRights($this->currentUser, $share, $node)) {
859
+                    $resharingRight = true;
860
+                }
861
+            } catch (InvalidPathException | NotFoundException $e) {
862
+            }
863
+        }
864
+
865
+        if (!$resharingRight) {
866
+            $formatted = $miniFormatted;
867
+        }
868
+
869
+        if ($includeTags) {
870
+            $formatted =
871
+                Helper::populateTags($formatted, 'file_source', \OC::$server->getTagManager());
872
+        }
873
+
874
+        return $formatted;
875
+    }
876
+
877
+
878
+    /**
879
+     * The getInheritedShares function.
880
+     * returns all shares relative to a file, including parent folders shares rights.
881
+     *
882
+     * @NoAdminRequired
883
+     *
884
+     * @param string $path
885
+     *
886
+     * - Get shares by the current user
887
+     * - Get shares by the current user and reshares (?reshares=true)
888
+     * - Get shares with the current user (?shared_with_me=true)
889
+     * - Get shares for a specific path (?path=...)
890
+     * - Get all shares in a folder (?subfiles=true&path=..)
891
+     *
892
+     * @return DataResponse
893
+     * @throws InvalidPathException
894
+     * @throws NotFoundException
895
+     * @throws OCSNotFoundException
896
+     * @throws OCSBadRequestException
897
+     * @throws SharingRightsException
898
+     */
899
+    public function getInheritedShares(string $path): DataResponse {
900
+
901
+        // get Node from (string) path.
902
+        $userFolder = $this->rootFolder->getUserFolder($this->currentUser);
903
+        try {
904
+            $node = $userFolder->get($path);
905
+            $this->lock($node);
906
+        } catch (\OCP\Files\NotFoundException $e) {
907
+            throw new OCSNotFoundException($this->l->t('Wrong path, file/folder doesn\'t exist'));
908
+        } catch (LockedException $e) {
909
+            throw new OCSNotFoundException($this->l->t('Could not lock path'));
910
+        }
911
+
912
+        if (!($node->getPermissions() & Constants::PERMISSION_SHARE)) {
913
+            throw new SharingRightsException('no sharing rights on this item');
914
+        }
915
+
916
+        // The current top parent we have access to
917
+        $parent = $node;
918
+
919
+        // initiate real owner.
920
+        $owner = $node->getOwner()
921
+                        ->getUID();
922
+        if (!$this->userManager->userExists($owner)) {
923
+            return new DataResponse([]);
924
+        }
925
+
926
+        // get node based on the owner, fix owner in case of external storage
927
+        $userFolder = $this->rootFolder->getUserFolder($owner);
928
+        if ($node->getId() !== $userFolder->getId() && !$userFolder->isSubNode($node)) {
929
+            $owner = $node->getOwner()
930
+                            ->getUID();
931
+            $userFolder = $this->rootFolder->getUserFolder($owner);
932
+            $nodes = $userFolder->getById($node->getId());
933
+            $node = array_shift($nodes);
934
+        }
935
+        $basePath = $userFolder->getPath();
936
+
937
+        // generate node list for each parent folders
938
+        /** @var Node[] $nodes */
939
+        $nodes = [];
940
+        while ($node->getPath() !== $basePath) {
941
+            $node = $node->getParent();
942
+            $nodes[] = $node;
943
+        }
944
+
945
+        // The user that is requesting this list
946
+        $currentUserFolder = $this->rootFolder->getUserFolder($this->currentUser);
947
+
948
+        // for each nodes, retrieve shares.
949
+        $shares = [];
950
+
951
+        foreach ($nodes as $node) {
952
+            $getShares = $this->getFormattedShares($owner, $node, false, true);
953
+
954
+            $currentUserNodes = $currentUserFolder->getById($node->getId());
955
+            if (!empty($currentUserNodes)) {
956
+                $parent = array_pop($currentUserNodes);
957
+            }
958
+
959
+            $subPath = $currentUserFolder->getRelativePath($parent->getPath());
960
+            foreach ($getShares as &$share) {
961
+                $share['via_fileid'] = $parent->getId();
962
+                $share['via_path'] = $subPath;
963
+            }
964
+            $this->mergeFormattedShares($shares, $getShares);
965
+        }
966
+
967
+        return new DataResponse(array_values($shares));
968
+    }
969
+
970
+
971
+    /**
972
+     * @NoAdminRequired
973
+     *
974
+     * @param string $id
975
+     * @param int $permissions
976
+     * @param string $password
977
+     * @param string $sendPasswordByTalk
978
+     * @param string $publicUpload
979
+     * @param string $expireDate
980
+     * @param string $note
981
+     * @param string $label
982
+     * @param string $hideDownload
983
+     * @return DataResponse
984
+     * @throws LockedException
985
+     * @throws NotFoundException
986
+     * @throws OCSBadRequestException
987
+     * @throws OCSForbiddenException
988
+     * @throws OCSNotFoundException
989
+     */
990
+    public function updateShare(
991
+        string $id,
992
+        int $permissions = null,
993
+        string $password = null,
994
+        string $sendPasswordByTalk = null,
995
+        string $publicUpload = null,
996
+        string $expireDate = null,
997
+        string $note = null,
998
+        string $label = null,
999
+        string $hideDownload = null
1000
+    ): DataResponse {
1001
+        try {
1002
+            $share = $this->getShareById($id);
1003
+        } catch (ShareNotFound $e) {
1004
+            throw new OCSNotFoundException($this->l->t('Wrong share ID, share doesn\'t exist'));
1005
+        }
1006
+
1007
+        $this->lock($share->getNode());
1008
+
1009
+        if (!$this->canAccessShare($share, false)) {
1010
+            throw new OCSNotFoundException($this->l->t('Wrong share ID, share doesn\'t exist'));
1011
+        }
1012
+
1013
+        if (!$this->canEditShare($share)) {
1014
+            throw new OCSForbiddenException('You are not allowed to edit incoming shares');
1015
+        }
1016
+
1017
+        if (
1018
+            $permissions === null &&
1019
+            $password === null &&
1020
+            $sendPasswordByTalk === null &&
1021
+            $publicUpload === null &&
1022
+            $expireDate === null &&
1023
+            $note === null &&
1024
+            $label === null &&
1025
+            $hideDownload === null
1026
+        ) {
1027
+            throw new OCSBadRequestException($this->l->t('Wrong or no update parameter given'));
1028
+        }
1029
+
1030
+        if ($note !== null) {
1031
+            $share->setNote($note);
1032
+        }
1033
+
1034
+        /**
1035
+         * expirationdate, password and publicUpload only make sense for link shares
1036
+         */
1037
+        if ($share->getShareType() === IShare::TYPE_LINK
1038
+            || $share->getShareType() === IShare::TYPE_EMAIL) {
1039
+
1040
+            /**
1041
+             * We do not allow editing link shares that the current user
1042
+             * doesn't own. This is confusing and lead to errors when
1043
+             * someone else edit a password or expiration date without
1044
+             * the share owner knowing about it.
1045
+             * We only allow deletion
1046
+             */
1047
+
1048
+            if ($share->getSharedBy() !== $this->currentUser) {
1049
+                throw new OCSForbiddenException('You are not allowed to edit link shares that you don\'t own');
1050
+            }
1051
+
1052
+            // Update hide download state
1053
+            if ($hideDownload === 'true') {
1054
+                $share->setHideDownload(true);
1055
+            } elseif ($hideDownload === 'false') {
1056
+                $share->setHideDownload(false);
1057
+            }
1058
+
1059
+            $newPermissions = null;
1060
+            if ($publicUpload === 'true') {
1061
+                $newPermissions = Constants::PERMISSION_READ | Constants::PERMISSION_CREATE | Constants::PERMISSION_UPDATE | Constants::PERMISSION_DELETE;
1062
+            } elseif ($publicUpload === 'false') {
1063
+                $newPermissions = Constants::PERMISSION_READ;
1064
+            }
1065
+
1066
+            if ($permissions !== null) {
1067
+                $newPermissions = $permissions;
1068
+                $newPermissions = $newPermissions & ~Constants::PERMISSION_SHARE;
1069
+            }
1070
+
1071
+            if ($newPermissions !== null &&
1072
+                !in_array($newPermissions, [
1073
+                    Constants::PERMISSION_READ,
1074
+                    Constants::PERMISSION_READ | Constants::PERMISSION_CREATE | Constants::PERMISSION_UPDATE, // legacy
1075
+                    Constants::PERMISSION_READ | Constants::PERMISSION_CREATE | Constants::PERMISSION_UPDATE | Constants::PERMISSION_DELETE, // correct
1076
+                    Constants::PERMISSION_CREATE, // hidden file list
1077
+                    Constants::PERMISSION_READ | Constants::PERMISSION_UPDATE, // allow to edit single files
1078
+                ], true)
1079
+            ) {
1080
+                throw new OCSBadRequestException($this->l->t('Can\'t change permissions for public share links'));
1081
+            }
1082
+
1083
+            if (
1084
+                // legacy
1085
+                $newPermissions === (Constants::PERMISSION_READ | Constants::PERMISSION_CREATE | Constants::PERMISSION_UPDATE) ||
1086
+                // correct
1087
+                $newPermissions === (Constants::PERMISSION_READ | Constants::PERMISSION_CREATE | Constants::PERMISSION_UPDATE | Constants::PERMISSION_DELETE)
1088
+            ) {
1089
+                if (!$this->shareManager->shareApiLinkAllowPublicUpload()) {
1090
+                    throw new OCSForbiddenException($this->l->t('Public upload disabled by the administrator'));
1091
+                }
1092
+
1093
+                if (!($share->getNode() instanceof \OCP\Files\Folder)) {
1094
+                    throw new OCSBadRequestException($this->l->t('Public upload is only possible for publicly shared folders'));
1095
+                }
1096
+
1097
+                // normalize to correct public upload permissions
1098
+                $newPermissions = Constants::PERMISSION_READ | Constants::PERMISSION_CREATE | Constants::PERMISSION_UPDATE | Constants::PERMISSION_DELETE;
1099
+            }
1100
+
1101
+            if ($newPermissions !== null) {
1102
+                // TODO: It might make sense to have a dedicated setting to allow/deny converting link shares into federated ones
1103
+                if (($newPermissions & Constants::PERMISSION_READ) && $this->shareManager->outgoingServer2ServerSharesAllowed()) {
1104
+                    $newPermissions |= Constants::PERMISSION_SHARE;
1105
+                }
1106
+
1107
+                $share->setPermissions($newPermissions);
1108
+                $permissions = $newPermissions;
1109
+            }
1110
+
1111
+            if ($expireDate === '') {
1112
+                $share->setExpirationDate(null);
1113
+            } elseif ($expireDate !== null) {
1114
+                try {
1115
+                    $expireDate = $this->parseDate($expireDate);
1116
+                } catch (\Exception $e) {
1117
+                    throw new OCSBadRequestException($e->getMessage(), $e);
1118
+                }
1119
+                $share->setExpirationDate($expireDate);
1120
+            }
1121
+
1122
+            if ($password === '') {
1123
+                $share->setPassword(null);
1124
+            } elseif ($password !== null) {
1125
+                $share->setPassword($password);
1126
+            }
1127
+
1128
+            // only link shares have labels
1129
+            if ($share->getShareType() === IShare::TYPE_LINK && $label !== null) {
1130
+                if (strlen($label) > 255) {
1131
+                    throw new OCSBadRequestException("Maxmimum label length is 255");
1132
+                }
1133
+                $share->setLabel($label);
1134
+            }
1135
+
1136
+            if ($sendPasswordByTalk === 'true') {
1137
+                if (!$this->appManager->isEnabledForUser('spreed')) {
1138
+                    throw new OCSForbiddenException($this->l->t('Sharing sending the password by Nextcloud Talk failed because Nextcloud Talk is not enabled'));
1139
+                }
1140
+
1141
+                $share->setSendPasswordByTalk(true);
1142
+            } elseif ($sendPasswordByTalk !== null) {
1143
+                $share->setSendPasswordByTalk(false);
1144
+            }
1145
+        }
1146
+
1147
+        // NOT A LINK SHARE
1148
+        else {
1149
+            if ($permissions !== null) {
1150
+                $share->setPermissions($permissions);
1151
+            }
1152
+
1153
+            if ($expireDate === '') {
1154
+                $share->setExpirationDate(null);
1155
+            } elseif ($expireDate !== null) {
1156
+                try {
1157
+                    $expireDate = $this->parseDate($expireDate);
1158
+                } catch (\Exception $e) {
1159
+                    throw new OCSBadRequestException($e->getMessage(), $e);
1160
+                }
1161
+                $share->setExpirationDate($expireDate);
1162
+            }
1163
+        }
1164
+
1165
+        try {
1166
+            $share = $this->shareManager->updateShare($share);
1167
+        } catch (GenericShareException $e) {
1168
+            $code = $e->getCode() === 0 ? 403 : $e->getCode();
1169
+            throw new OCSException($e->getHint(), $code);
1170
+        } catch (\Exception $e) {
1171
+            throw new OCSBadRequestException($e->getMessage(), $e);
1172
+        }
1173
+
1174
+        return new DataResponse($this->formatShare($share));
1175
+    }
1176
+
1177
+    /**
1178
+     * @NoAdminRequired
1179
+     */
1180
+    public function pendingShares(): DataResponse {
1181
+        $pendingShares = [];
1182
+
1183
+        $shareTypes = [
1184
+            IShare::TYPE_USER,
1185
+            IShare::TYPE_GROUP
1186
+        ];
1187
+
1188
+        foreach ($shareTypes as $shareType) {
1189
+            $shares = $this->shareManager->getSharedWith($this->currentUser, $shareType, null, -1, 0);
1190
+
1191
+            foreach ($shares as $share) {
1192
+                if ($share->getStatus() === IShare::STATUS_PENDING || $share->getStatus() === IShare::STATUS_REJECTED) {
1193
+                    $pendingShares[] = $share;
1194
+                }
1195
+            }
1196
+        }
1197
+
1198
+        $result = array_filter(array_map(function (IShare $share) {
1199
+            $userFolder = $this->rootFolder->getUserFolder($share->getSharedBy());
1200
+            $nodes = $userFolder->getById($share->getNodeId());
1201
+            if (empty($nodes)) {
1202
+                // fallback to guessing the path
1203
+                $node = $userFolder->get($share->getTarget());
1204
+                if ($node === null || $share->getTarget() === '') {
1205
+                    return null;
1206
+                }
1207
+            } else {
1208
+                $node = $nodes[0];
1209
+            }
1210
+
1211
+            try {
1212
+                $formattedShare = $this->formatShare($share, $node);
1213
+                $formattedShare['status'] = $share->getStatus();
1214
+                $formattedShare['path'] = $share->getNode()->getName();
1215
+                $formattedShare['permissions'] = 0;
1216
+                return $formattedShare;
1217
+            } catch (NotFoundException $e) {
1218
+                return null;
1219
+            }
1220
+        }, $pendingShares), function ($entry) {
1221
+            return $entry !== null;
1222
+        });
1223
+
1224
+        return new DataResponse($result);
1225
+    }
1226
+
1227
+    /**
1228
+     * @NoAdminRequired
1229
+     *
1230
+     * @param string $id
1231
+     * @return DataResponse
1232
+     * @throws OCSNotFoundException
1233
+     * @throws OCSException
1234
+     * @throws OCSBadRequestException
1235
+     */
1236
+    public function acceptShare(string $id): DataResponse {
1237
+        try {
1238
+            $share = $this->getShareById($id);
1239
+        } catch (ShareNotFound $e) {
1240
+            throw new OCSNotFoundException($this->l->t('Wrong share ID, share doesn\'t exist'));
1241
+        }
1242
+
1243
+        if (!$this->canAccessShare($share)) {
1244
+            throw new OCSNotFoundException($this->l->t('Wrong share ID, share doesn\'t exist'));
1245
+        }
1246
+
1247
+        try {
1248
+            $this->shareManager->acceptShare($share, $this->currentUser);
1249
+        } catch (GenericShareException $e) {
1250
+            $code = $e->getCode() === 0 ? 403 : $e->getCode();
1251
+            throw new OCSException($e->getHint(), $code);
1252
+        } catch (\Exception $e) {
1253
+            throw new OCSBadRequestException($e->getMessage(), $e);
1254
+        }
1255
+
1256
+        return new DataResponse();
1257
+    }
1258
+
1259
+    /**
1260
+     * Does the user have read permission on the share
1261
+     *
1262
+     * @param \OCP\Share\IShare $share the share to check
1263
+     * @param boolean $checkGroups check groups as well?
1264
+     * @return boolean
1265
+     * @throws NotFoundException
1266
+     *
1267
+     * @suppress PhanUndeclaredClassMethod
1268
+     */
1269
+    protected function canAccessShare(\OCP\Share\IShare $share, bool $checkGroups = true): bool {
1270
+        // A file with permissions 0 can't be accessed by us. So Don't show it
1271
+        if ($share->getPermissions() === 0) {
1272
+            return false;
1273
+        }
1274
+
1275
+        // Owner of the file and the sharer of the file can always get share
1276
+        if ($share->getShareOwner() === $this->currentUser
1277
+            || $share->getSharedBy() === $this->currentUser) {
1278
+            return true;
1279
+        }
1280
+
1281
+        // If the share is shared with you, you can access it!
1282
+        if ($share->getShareType() === IShare::TYPE_USER
1283
+            && $share->getSharedWith() === $this->currentUser) {
1284
+            return true;
1285
+        }
1286
+
1287
+        // Have reshare rights on the shared file/folder ?
1288
+        // Does the currentUser have access to the shared file?
1289
+        $userFolder = $this->rootFolder->getUserFolder($this->currentUser);
1290
+        $files = $userFolder->getById($share->getNodeId());
1291
+        if (!empty($files) && $this->shareProviderResharingRights($this->currentUser, $share, $files[0])) {
1292
+            return true;
1293
+        }
1294
+
1295
+        // If in the recipient group, you can see the share
1296
+        if ($checkGroups && $share->getShareType() === IShare::TYPE_GROUP) {
1297
+            $sharedWith = $this->groupManager->get($share->getSharedWith());
1298
+            $user = $this->userManager->get($this->currentUser);
1299
+            if ($user !== null && $sharedWith !== null && $sharedWith->inGroup($user)) {
1300
+                return true;
1301
+            }
1302
+        }
1303
+
1304
+        if ($share->getShareType() === IShare::TYPE_CIRCLE) {
1305
+            // TODO: have a sanity check like above?
1306
+            return true;
1307
+        }
1308
+
1309
+        if ($share->getShareType() === IShare::TYPE_ROOM) {
1310
+            try {
1311
+                return $this->getRoomShareHelper()->canAccessShare($share, $this->currentUser);
1312
+            } catch (QueryException $e) {
1313
+                return false;
1314
+            }
1315
+        }
1316
+
1317
+        if ($share->getShareType() === IShare::TYPE_DECK) {
1318
+            try {
1319
+                return $this->getDeckShareHelper()->canAccessShare($share, $this->currentUser);
1320
+            } catch (QueryException $e) {
1321
+                return false;
1322
+            }
1323
+        }
1324
+
1325
+        return false;
1326
+    }
1327
+
1328
+    /**
1329
+     * Does the user have edit permission on the share
1330
+     *
1331
+     * @param \OCP\Share\IShare $share the share to check
1332
+     * @return boolean
1333
+     */
1334
+    protected function canEditShare(\OCP\Share\IShare $share): bool {
1335
+        // A file with permissions 0 can't be accessed by us. So Don't show it
1336
+        if ($share->getPermissions() === 0) {
1337
+            return false;
1338
+        }
1339
+
1340
+        // The owner of the file and the creator of the share
1341
+        // can always edit the share
1342
+        if ($share->getShareOwner() === $this->currentUser ||
1343
+            $share->getSharedBy() === $this->currentUser
1344
+        ) {
1345
+            return true;
1346
+        }
1347
+
1348
+        //! we do NOT support some kind of `admin` in groups.
1349
+        //! You cannot edit shares shared to a group you're
1350
+        //! a member of if you're not the share owner or the file owner!
1351
+
1352
+        return false;
1353
+    }
1354
+
1355
+    /**
1356
+     * Does the user have delete permission on the share
1357
+     *
1358
+     * @param \OCP\Share\IShare $share the share to check
1359
+     * @return boolean
1360
+     */
1361
+    protected function canDeleteShare(\OCP\Share\IShare $share): bool {
1362
+        // A file with permissions 0 can't be accessed by us. So Don't show it
1363
+        if ($share->getPermissions() === 0) {
1364
+            return false;
1365
+        }
1366
+
1367
+        // if the user is the recipient, i can unshare
1368
+        // the share with self
1369
+        if ($share->getShareType() === IShare::TYPE_USER &&
1370
+            $share->getSharedWith() === $this->currentUser
1371
+        ) {
1372
+            return true;
1373
+        }
1374
+
1375
+        // The owner of the file and the creator of the share
1376
+        // can always delete the share
1377
+        if ($share->getShareOwner() === $this->currentUser ||
1378
+            $share->getSharedBy() === $this->currentUser
1379
+        ) {
1380
+            return true;
1381
+        }
1382
+
1383
+        return false;
1384
+    }
1385
+
1386
+    /**
1387
+     * Does the user have delete permission on the share
1388
+     * This differs from the canDeleteShare function as it only
1389
+     * remove the share for the current user. It does NOT
1390
+     * completely delete the share but only the mount point.
1391
+     * It can then be restored from the deleted shares section.
1392
+     *
1393
+     * @param \OCP\Share\IShare $share the share to check
1394
+     * @return boolean
1395
+     *
1396
+     * @suppress PhanUndeclaredClassMethod
1397
+     */
1398
+    protected function canDeleteShareFromSelf(\OCP\Share\IShare $share): bool {
1399
+        if ($share->getShareType() !== IShare::TYPE_GROUP &&
1400
+            $share->getShareType() !== IShare::TYPE_ROOM &&
1401
+            $share->getShareType() !== IShare::TYPE_DECK
1402
+        ) {
1403
+            return false;
1404
+        }
1405
+
1406
+        if ($share->getShareOwner() === $this->currentUser ||
1407
+            $share->getSharedBy() === $this->currentUser
1408
+        ) {
1409
+            // Delete the whole share, not just for self
1410
+            return false;
1411
+        }
1412
+
1413
+        // If in the recipient group, you can delete the share from self
1414
+        if ($share->getShareType() === IShare::TYPE_GROUP) {
1415
+            $sharedWith = $this->groupManager->get($share->getSharedWith());
1416
+            $user = $this->userManager->get($this->currentUser);
1417
+            if ($user !== null && $sharedWith !== null && $sharedWith->inGroup($user)) {
1418
+                return true;
1419
+            }
1420
+        }
1421
+
1422
+        if ($share->getShareType() === IShare::TYPE_ROOM) {
1423
+            try {
1424
+                return $this->getRoomShareHelper()->canAccessShare($share, $this->currentUser);
1425
+            } catch (QueryException $e) {
1426
+                return false;
1427
+            }
1428
+        }
1429
+
1430
+        if ($share->getShareType() === IShare::TYPE_DECK) {
1431
+            try {
1432
+                return $this->getDeckShareHelper()->canAccessShare($share, $this->currentUser);
1433
+            } catch (QueryException $e) {
1434
+                return false;
1435
+            }
1436
+        }
1437
+
1438
+        return false;
1439
+    }
1440
+
1441
+    /**
1442
+     * Make sure that the passed date is valid ISO 8601
1443
+     * So YYYY-MM-DD
1444
+     * If not throw an exception
1445
+     *
1446
+     * @param string $expireDate
1447
+     *
1448
+     * @throws \Exception
1449
+     * @return \DateTime
1450
+     */
1451
+    private function parseDate(string $expireDate): \DateTime {
1452
+        try {
1453
+            $date = new \DateTime($expireDate);
1454
+        } catch (\Exception $e) {
1455
+            throw new \Exception('Invalid date. Format must be YYYY-MM-DD');
1456
+        }
1457
+
1458
+        if ($date === false) {
1459
+            throw new \Exception('Invalid date. Format must be YYYY-MM-DD');
1460
+        }
1461
+
1462
+        $date->setTime(0, 0, 0);
1463
+
1464
+        return $date;
1465
+    }
1466
+
1467
+    /**
1468
+     * Since we have multiple providers but the OCS Share API v1 does
1469
+     * not support this we need to check all backends.
1470
+     *
1471
+     * @param string $id
1472
+     * @return \OCP\Share\IShare
1473
+     * @throws ShareNotFound
1474
+     */
1475
+    private function getShareById(string $id): IShare {
1476
+        $share = null;
1477
+
1478
+        // First check if it is an internal share.
1479
+        try {
1480
+            $share = $this->shareManager->getShareById('ocinternal:' . $id, $this->currentUser);
1481
+            return $share;
1482
+        } catch (ShareNotFound $e) {
1483
+            // Do nothing, just try the other share type
1484
+        }
1485
+
1486
+
1487
+        try {
1488
+            if ($this->shareManager->shareProviderExists(IShare::TYPE_CIRCLE)) {
1489
+                $share = $this->shareManager->getShareById('ocCircleShare:' . $id, $this->currentUser);
1490
+                return $share;
1491
+            }
1492
+        } catch (ShareNotFound $e) {
1493
+            // Do nothing, just try the other share type
1494
+        }
1495
+
1496
+        try {
1497
+            if ($this->shareManager->shareProviderExists(IShare::TYPE_EMAIL)) {
1498
+                $share = $this->shareManager->getShareById('ocMailShare:' . $id, $this->currentUser);
1499
+                return $share;
1500
+            }
1501
+        } catch (ShareNotFound $e) {
1502
+            // Do nothing, just try the other share type
1503
+        }
1504
+
1505
+        try {
1506
+            $share = $this->shareManager->getShareById('ocRoomShare:' . $id, $this->currentUser);
1507
+            return $share;
1508
+        } catch (ShareNotFound $e) {
1509
+            // Do nothing, just try the other share type
1510
+        }
1511
+
1512
+        try {
1513
+            if ($this->shareManager->shareProviderExists(IShare::TYPE_DECK)) {
1514
+                $share = $this->shareManager->getShareById('deck:' . $id, $this->currentUser);
1515
+                return $share;
1516
+            }
1517
+        } catch (ShareNotFound $e) {
1518
+            // Do nothing, just try the other share type
1519
+        }
1520
+
1521
+        if (!$this->shareManager->outgoingServer2ServerSharesAllowed()) {
1522
+            throw new ShareNotFound();
1523
+        }
1524
+        $share = $this->shareManager->getShareById('ocFederatedSharing:' . $id, $this->currentUser);
1525
+
1526
+        return $share;
1527
+    }
1528
+
1529
+    /**
1530
+     * Lock a Node
1531
+     *
1532
+     * @param \OCP\Files\Node $node
1533
+     * @throws LockedException
1534
+     */
1535
+    private function lock(\OCP\Files\Node $node) {
1536
+        $node->lock(ILockingProvider::LOCK_SHARED);
1537
+        $this->lockedNode = $node;
1538
+    }
1539
+
1540
+    /**
1541
+     * Cleanup the remaining locks
1542
+     * @throws LockedException
1543
+     */
1544
+    public function cleanup() {
1545
+        if ($this->lockedNode !== null) {
1546
+            $this->lockedNode->unlock(ILockingProvider::LOCK_SHARED);
1547
+        }
1548
+    }
1549
+
1550
+    /**
1551
+     * Returns the helper of ShareAPIController for room shares.
1552
+     *
1553
+     * If the Talk application is not enabled or the helper is not available
1554
+     * a QueryException is thrown instead.
1555
+     *
1556
+     * @return \OCA\Talk\Share\Helper\ShareAPIController
1557
+     * @throws QueryException
1558
+     */
1559
+    private function getRoomShareHelper() {
1560
+        if (!$this->appManager->isEnabledForUser('spreed')) {
1561
+            throw new QueryException();
1562
+        }
1563
+
1564
+        return $this->serverContainer->get('\OCA\Talk\Share\Helper\ShareAPIController');
1565
+    }
1566
+
1567
+    /**
1568
+     * Returns the helper of ShareAPIHelper for deck shares.
1569
+     *
1570
+     * If the Deck application is not enabled or the helper is not available
1571
+     * a QueryException is thrown instead.
1572
+     *
1573
+     * @return \OCA\Deck\Sharing\ShareAPIHelper
1574
+     * @throws QueryException
1575
+     */
1576
+    private function getDeckShareHelper() {
1577
+        if (!$this->appManager->isEnabledForUser('deck')) {
1578
+            throw new QueryException();
1579
+        }
1580
+
1581
+        return $this->serverContainer->get('\OCA\Deck\Sharing\ShareAPIHelper');
1582
+    }
1583
+
1584
+    /**
1585
+     * @param string $viewer
1586
+     * @param Node $node
1587
+     * @param bool $reShares
1588
+     *
1589
+     * @return IShare[]
1590
+     */
1591
+    private function getSharesFromNode(string $viewer, $node, bool $reShares): array {
1592
+        $providers = [
1593
+            IShare::TYPE_USER,
1594
+            IShare::TYPE_GROUP,
1595
+            IShare::TYPE_LINK,
1596
+            IShare::TYPE_EMAIL,
1597
+            IShare::TYPE_EMAIL,
1598
+            IShare::TYPE_CIRCLE,
1599
+            IShare::TYPE_ROOM,
1600
+            IShare::TYPE_DECK
1601
+        ];
1602
+
1603
+        // Should we assume that the (currentUser) viewer is the owner of the node !?
1604
+        $shares = [];
1605
+        foreach ($providers as $provider) {
1606
+            if (!$this->shareManager->shareProviderExists($provider)) {
1607
+                continue;
1608
+            }
1609
+
1610
+            $providerShares =
1611
+                $this->shareManager->getSharesBy($viewer, $provider, $node, $reShares, -1, 0);
1612
+            $shares = array_merge($shares, $providerShares);
1613
+        }
1614
+
1615
+        if ($this->shareManager->outgoingServer2ServerSharesAllowed()) {
1616
+            $federatedShares = $this->shareManager->getSharesBy(
1617
+                $this->currentUser, IShare::TYPE_REMOTE, $node, $reShares, -1, 0
1618
+            );
1619
+            $shares = array_merge($shares, $federatedShares);
1620
+        }
1621
+
1622
+        if ($this->shareManager->outgoingServer2ServerGroupSharesAllowed()) {
1623
+            $federatedShares = $this->shareManager->getSharesBy(
1624
+                $this->currentUser, IShare::TYPE_REMOTE_GROUP, $node, $reShares, -1, 0
1625
+            );
1626
+            $shares = array_merge($shares, $federatedShares);
1627
+        }
1628
+
1629
+        return $shares;
1630
+    }
1631
+
1632
+
1633
+    /**
1634
+     * @param Node $node
1635
+     *
1636
+     * @throws SharingRightsException
1637
+     */
1638
+    private function confirmSharingRights(Node $node): void {
1639
+        if (!$this->hasResharingRights($this->currentUser, $node)) {
1640
+            throw new SharingRightsException('no sharing rights on this item');
1641
+        }
1642
+    }
1643
+
1644
+
1645
+    /**
1646
+     * @param string $viewer
1647
+     * @param Node $node
1648
+     *
1649
+     * @return bool
1650
+     */
1651
+    private function hasResharingRights($viewer, $node): bool {
1652
+        if ($viewer === $node->getOwner()->getUID()) {
1653
+            return true;
1654
+        }
1655
+
1656
+        foreach ([$node, $node->getParent()] as $node) {
1657
+            $shares = $this->getSharesFromNode($viewer, $node, true);
1658
+            foreach ($shares as $share) {
1659
+                try {
1660
+                    if ($this->shareProviderResharingRights($viewer, $share, $node)) {
1661
+                        return true;
1662
+                    }
1663
+                } catch (InvalidPathException | NotFoundException $e) {
1664
+                }
1665
+            }
1666
+        }
1667
+
1668
+        return false;
1669
+    }
1670
+
1671
+
1672
+    /**
1673
+     * Returns if we can find resharing rights in an IShare object for a specific user.
1674
+     *
1675
+     * @suppress PhanUndeclaredClassMethod
1676
+     *
1677
+     * @param string $userId
1678
+     * @param IShare $share
1679
+     * @param Node $node
1680
+     *
1681
+     * @return bool
1682
+     * @throws NotFoundException
1683
+     * @throws InvalidPathException
1684
+     */
1685
+    private function shareProviderResharingRights(string $userId, IShare $share, $node): bool {
1686
+        if ($share->getShareOwner() === $userId) {
1687
+            return true;
1688
+        }
1689
+
1690
+        // we check that current user have parent resharing rights on the current file
1691
+        if ($node !== null && ($node->getPermissions() & Constants::PERMISSION_SHARE) !== 0) {
1692
+            return true;
1693
+        }
1694
+
1695
+        if ((\OCP\Constants::PERMISSION_SHARE & $share->getPermissions()) === 0) {
1696
+            return false;
1697
+        }
1698
+
1699
+        if ($share->getShareType() === IShare::TYPE_USER && $share->getSharedWith() === $userId) {
1700
+            return true;
1701
+        }
1702
+
1703
+        if ($share->getShareType() === IShare::TYPE_GROUP && $this->groupManager->isInGroup($userId, $share->getSharedWith())) {
1704
+            return true;
1705
+        }
1706
+
1707
+        if ($share->getShareType() === IShare::TYPE_CIRCLE && \OC::$server->getAppManager()->isEnabledForUser('circles')
1708
+            && class_exists('\OCA\Circles\Api\v1\Circles')) {
1709
+            $hasCircleId = (substr($share->getSharedWith(), -1) === ']');
1710
+            $shareWithStart = ($hasCircleId ? strrpos($share->getSharedWith(), '[') + 1 : 0);
1711
+            $shareWithLength = ($hasCircleId ? -1 : strpos($share->getSharedWith(), ' '));
1712
+            if ($shareWithLength === false) {
1713
+                $sharedWith = substr($share->getSharedWith(), $shareWithStart);
1714
+            } else {
1715
+                $sharedWith = substr($share->getSharedWith(), $shareWithStart, $shareWithLength);
1716
+            }
1717
+            try {
1718
+                $member = \OCA\Circles\Api\v1\Circles::getMember($sharedWith, $userId, 1);
1719
+                if ($member->getLevel() >= 4) {
1720
+                    return true;
1721
+                }
1722
+                return false;
1723
+            } catch (QueryException $e) {
1724
+                return false;
1725
+            }
1726
+        }
1727
+
1728
+        return false;
1729
+    }
1730
+
1731
+    /**
1732
+     * Get all the shares for the current user
1733
+     *
1734
+     * @param Node|null $path
1735
+     * @param boolean $reshares
1736
+     * @return IShare[]
1737
+     */
1738
+    private function getAllShares(?Node $path = null, bool $reshares = false) {
1739
+        // Get all shares
1740
+        $userShares = $this->shareManager->getSharesBy($this->currentUser, IShare::TYPE_USER, $path, $reshares, -1, 0);
1741
+        $groupShares = $this->shareManager->getSharesBy($this->currentUser, IShare::TYPE_GROUP, $path, $reshares, -1, 0);
1742
+        $linkShares = $this->shareManager->getSharesBy($this->currentUser, IShare::TYPE_LINK, $path, $reshares, -1, 0);
1743
+
1744
+        // EMAIL SHARES
1745
+        $mailShares = $this->shareManager->getSharesBy($this->currentUser, IShare::TYPE_EMAIL, $path, $reshares, -1, 0);
1746
+
1747
+        // CIRCLE SHARES
1748
+        $circleShares = $this->shareManager->getSharesBy($this->currentUser, IShare::TYPE_CIRCLE, $path, $reshares, -1, 0);
1749
+
1750
+        // TALK SHARES
1751
+        $roomShares = $this->shareManager->getSharesBy($this->currentUser, IShare::TYPE_ROOM, $path, $reshares, -1, 0);
1752
+
1753
+        $deckShares = $this->shareManager->getSharesBy($this->currentUser, IShare::TYPE_DECK, $path, $reshares, -1, 0);
1754
+
1755
+        // FEDERATION
1756
+        if ($this->shareManager->outgoingServer2ServerSharesAllowed()) {
1757
+            $federatedShares = $this->shareManager->getSharesBy($this->currentUser, IShare::TYPE_REMOTE, $path, $reshares, -1, 0);
1758
+        } else {
1759
+            $federatedShares = [];
1760
+        }
1761
+        if ($this->shareManager->outgoingServer2ServerGroupSharesAllowed()) {
1762
+            $federatedGroupShares = $this->shareManager->getSharesBy($this->currentUser, IShare::TYPE_REMOTE_GROUP, $path, $reshares, -1, 0);
1763
+        } else {
1764
+            $federatedGroupShares = [];
1765
+        }
1766
+
1767
+        return array_merge($userShares, $groupShares, $linkShares, $mailShares, $circleShares, $roomShares, $deckShares, $federatedShares, $federatedGroupShares);
1768
+    }
1769
+
1770
+
1771
+    /**
1772
+     * merging already formatted shares.
1773
+     * We'll make an associative array to easily detect duplicate Ids.
1774
+     * Keys _needs_ to be removed after all shares are retrieved and merged.
1775
+     *
1776
+     * @param array $shares
1777
+     * @param array $newShares
1778
+     */
1779
+    private function mergeFormattedShares(array &$shares, array $newShares) {
1780
+        foreach ($newShares as $newShare) {
1781
+            if (!array_key_exists($newShare['id'], $shares)) {
1782
+                $shares[$newShare['id']] = $newShare;
1783
+            }
1784
+        }
1785
+    }
1786 1786
 }
Please login to merge, or discard this patch.
apps/encryption/lib/Controller/SettingsController.php 1 patch
Indentation   +123 added lines, -123 removed lines patch added patch discarded remove patch
@@ -38,128 +38,128 @@
 block discarded – undo
38 38
 
39 39
 class SettingsController extends Controller {
40 40
 
41
-	/** @var IL10N */
42
-	private $l;
43
-
44
-	/** @var IUserManager */
45
-	private $userManager;
46
-
47
-	/** @var IUserSession */
48
-	private $userSession;
49
-
50
-	/** @var KeyManager */
51
-	private $keyManager;
52
-
53
-	/** @var Crypt */
54
-	private $crypt;
55
-
56
-	/** @var Session */
57
-	private $session;
58
-
59
-	/** @var ISession  */
60
-	private $ocSession;
61
-
62
-	/** @var  Util */
63
-	private $util;
64
-
65
-	/**
66
-	 * @param string $AppName
67
-	 * @param IRequest $request
68
-	 * @param IL10N $l10n
69
-	 * @param IUserManager $userManager
70
-	 * @param IUserSession $userSession
71
-	 * @param KeyManager $keyManager
72
-	 * @param Crypt $crypt
73
-	 * @param Session $session
74
-	 * @param ISession $ocSession
75
-	 * @param Util $util
76
-	 */
77
-	public function __construct($AppName,
78
-								IRequest $request,
79
-								IL10N $l10n,
80
-								IUserManager $userManager,
81
-								IUserSession $userSession,
82
-								KeyManager $keyManager,
83
-								Crypt $crypt,
84
-								Session $session,
85
-								ISession $ocSession,
86
-								Util $util
41
+    /** @var IL10N */
42
+    private $l;
43
+
44
+    /** @var IUserManager */
45
+    private $userManager;
46
+
47
+    /** @var IUserSession */
48
+    private $userSession;
49
+
50
+    /** @var KeyManager */
51
+    private $keyManager;
52
+
53
+    /** @var Crypt */
54
+    private $crypt;
55
+
56
+    /** @var Session */
57
+    private $session;
58
+
59
+    /** @var ISession  */
60
+    private $ocSession;
61
+
62
+    /** @var  Util */
63
+    private $util;
64
+
65
+    /**
66
+     * @param string $AppName
67
+     * @param IRequest $request
68
+     * @param IL10N $l10n
69
+     * @param IUserManager $userManager
70
+     * @param IUserSession $userSession
71
+     * @param KeyManager $keyManager
72
+     * @param Crypt $crypt
73
+     * @param Session $session
74
+     * @param ISession $ocSession
75
+     * @param Util $util
76
+     */
77
+    public function __construct($AppName,
78
+                                IRequest $request,
79
+                                IL10N $l10n,
80
+                                IUserManager $userManager,
81
+                                IUserSession $userSession,
82
+                                KeyManager $keyManager,
83
+                                Crypt $crypt,
84
+                                Session $session,
85
+                                ISession $ocSession,
86
+                                Util $util
87 87
 ) {
88
-		parent::__construct($AppName, $request);
89
-		$this->l = $l10n;
90
-		$this->userSession = $userSession;
91
-		$this->userManager = $userManager;
92
-		$this->keyManager = $keyManager;
93
-		$this->crypt = $crypt;
94
-		$this->session = $session;
95
-		$this->ocSession = $ocSession;
96
-		$this->util = $util;
97
-	}
98
-
99
-
100
-	/**
101
-	 * @NoAdminRequired
102
-	 * @UseSession
103
-	 *
104
-	 * @param string $oldPassword
105
-	 * @param string $newPassword
106
-	 * @return DataResponse
107
-	 */
108
-	public function updatePrivateKeyPassword($oldPassword, $newPassword) {
109
-		$result = false;
110
-		$uid = $this->userSession->getUser()->getUID();
111
-		$errorMessage = $this->l->t('Could not update the private key password.');
112
-
113
-		//check if password is correct
114
-		$passwordCorrect = $this->userManager->checkPassword($uid, $newPassword);
115
-		if ($passwordCorrect === false) {
116
-			// if check with uid fails we need to check the password with the login name
117
-			// e.g. in the ldap case. For local user we need to check the password with
118
-			// the uid because in this case the login name is case insensitive
119
-			$loginName = $this->ocSession->get('loginname');
120
-			$passwordCorrect = $this->userManager->checkPassword($loginName, $newPassword);
121
-		}
122
-
123
-		if ($passwordCorrect !== false) {
124
-			$encryptedKey = $this->keyManager->getPrivateKey($uid);
125
-			$decryptedKey = $this->crypt->decryptPrivateKey($encryptedKey, $oldPassword, $uid);
126
-
127
-			if ($decryptedKey) {
128
-				$encryptedKey = $this->crypt->encryptPrivateKey($decryptedKey, $newPassword, $uid);
129
-				$header = $this->crypt->generateHeader();
130
-				if ($encryptedKey) {
131
-					$this->keyManager->setPrivateKey($uid, $header . $encryptedKey);
132
-					$this->session->setPrivateKey($decryptedKey);
133
-					$result = true;
134
-				}
135
-			} else {
136
-				$errorMessage = $this->l->t('The old password was not correct, please try again.');
137
-			}
138
-		} else {
139
-			$errorMessage = $this->l->t('The current log-in password was not correct, please try again.');
140
-		}
141
-
142
-		if ($result === true) {
143
-			$this->session->setStatus(Session::INIT_SUCCESSFUL);
144
-			return new DataResponse(
145
-				['message' => $this->l->t('Private key password successfully updated.')]
146
-			);
147
-		} else {
148
-			return new DataResponse(
149
-				['message' => $errorMessage],
150
-				Http::STATUS_BAD_REQUEST
151
-			);
152
-		}
153
-	}
154
-
155
-	/**
156
-	 * @UseSession
157
-	 *
158
-	 * @param bool $encryptHomeStorage
159
-	 * @return DataResponse
160
-	 */
161
-	public function setEncryptHomeStorage($encryptHomeStorage) {
162
-		$this->util->setEncryptHomeStorage($encryptHomeStorage);
163
-		return new DataResponse();
164
-	}
88
+        parent::__construct($AppName, $request);
89
+        $this->l = $l10n;
90
+        $this->userSession = $userSession;
91
+        $this->userManager = $userManager;
92
+        $this->keyManager = $keyManager;
93
+        $this->crypt = $crypt;
94
+        $this->session = $session;
95
+        $this->ocSession = $ocSession;
96
+        $this->util = $util;
97
+    }
98
+
99
+
100
+    /**
101
+     * @NoAdminRequired
102
+     * @UseSession
103
+     *
104
+     * @param string $oldPassword
105
+     * @param string $newPassword
106
+     * @return DataResponse
107
+     */
108
+    public function updatePrivateKeyPassword($oldPassword, $newPassword) {
109
+        $result = false;
110
+        $uid = $this->userSession->getUser()->getUID();
111
+        $errorMessage = $this->l->t('Could not update the private key password.');
112
+
113
+        //check if password is correct
114
+        $passwordCorrect = $this->userManager->checkPassword($uid, $newPassword);
115
+        if ($passwordCorrect === false) {
116
+            // if check with uid fails we need to check the password with the login name
117
+            // e.g. in the ldap case. For local user we need to check the password with
118
+            // the uid because in this case the login name is case insensitive
119
+            $loginName = $this->ocSession->get('loginname');
120
+            $passwordCorrect = $this->userManager->checkPassword($loginName, $newPassword);
121
+        }
122
+
123
+        if ($passwordCorrect !== false) {
124
+            $encryptedKey = $this->keyManager->getPrivateKey($uid);
125
+            $decryptedKey = $this->crypt->decryptPrivateKey($encryptedKey, $oldPassword, $uid);
126
+
127
+            if ($decryptedKey) {
128
+                $encryptedKey = $this->crypt->encryptPrivateKey($decryptedKey, $newPassword, $uid);
129
+                $header = $this->crypt->generateHeader();
130
+                if ($encryptedKey) {
131
+                    $this->keyManager->setPrivateKey($uid, $header . $encryptedKey);
132
+                    $this->session->setPrivateKey($decryptedKey);
133
+                    $result = true;
134
+                }
135
+            } else {
136
+                $errorMessage = $this->l->t('The old password was not correct, please try again.');
137
+            }
138
+        } else {
139
+            $errorMessage = $this->l->t('The current log-in password was not correct, please try again.');
140
+        }
141
+
142
+        if ($result === true) {
143
+            $this->session->setStatus(Session::INIT_SUCCESSFUL);
144
+            return new DataResponse(
145
+                ['message' => $this->l->t('Private key password successfully updated.')]
146
+            );
147
+        } else {
148
+            return new DataResponse(
149
+                ['message' => $errorMessage],
150
+                Http::STATUS_BAD_REQUEST
151
+            );
152
+        }
153
+    }
154
+
155
+    /**
156
+     * @UseSession
157
+     *
158
+     * @param bool $encryptHomeStorage
159
+     * @return DataResponse
160
+     */
161
+    public function setEncryptHomeStorage($encryptHomeStorage) {
162
+        $this->util->setEncryptHomeStorage($encryptHomeStorage);
163
+        return new DataResponse();
164
+    }
165 165
 }
Please login to merge, or discard this patch.
apps/encryption/lib/Controller/StatusController.php 1 patch
Indentation   +62 added lines, -62 removed lines patch added patch discarded remove patch
@@ -35,71 +35,71 @@
 block discarded – undo
35 35
 
36 36
 class StatusController extends Controller {
37 37
 
38
-	/** @var IL10N */
39
-	private $l;
38
+    /** @var IL10N */
39
+    private $l;
40 40
 
41
-	/** @var Session */
42
-	private $session;
41
+    /** @var Session */
42
+    private $session;
43 43
 
44
-	/** @var IManager */
45
-	private $encryptionManager;
44
+    /** @var IManager */
45
+    private $encryptionManager;
46 46
 
47
-	/**
48
-	 * @param string $AppName
49
-	 * @param IRequest $request
50
-	 * @param IL10N $l10n
51
-	 * @param Session $session
52
-	 * @param IManager $encryptionManager
53
-	 */
54
-	public function __construct($AppName,
55
-								IRequest $request,
56
-								IL10N $l10n,
57
-								Session $session,
58
-								IManager $encryptionManager
59
-								) {
60
-		parent::__construct($AppName, $request);
61
-		$this->l = $l10n;
62
-		$this->session = $session;
63
-		$this->encryptionManager = $encryptionManager;
64
-	}
47
+    /**
48
+     * @param string $AppName
49
+     * @param IRequest $request
50
+     * @param IL10N $l10n
51
+     * @param Session $session
52
+     * @param IManager $encryptionManager
53
+     */
54
+    public function __construct($AppName,
55
+                                IRequest $request,
56
+                                IL10N $l10n,
57
+                                Session $session,
58
+                                IManager $encryptionManager
59
+                                ) {
60
+        parent::__construct($AppName, $request);
61
+        $this->l = $l10n;
62
+        $this->session = $session;
63
+        $this->encryptionManager = $encryptionManager;
64
+    }
65 65
 
66
-	/**
67
-	 * @NoAdminRequired
68
-	 * @return DataResponse
69
-	 */
70
-	public function getStatus() {
71
-		$status = 'error';
72
-		$message = 'no valid init status';
73
-		switch ($this->session->getStatus()) {
74
-			case Session::INIT_EXECUTED:
75
-				$status = 'interactionNeeded';
76
-				$message = $this->l->t(
77
-					'Invalid private key for encryption app. Please update your private key password in your personal settings to recover access to your encrypted files.'
78
-				);
79
-				break;
80
-			case Session::NOT_INITIALIZED:
81
-				$status = 'interactionNeeded';
82
-				if ($this->encryptionManager->isEnabled()) {
83
-					$message = $this->l->t(
84
-						'Encryption App is enabled, but your keys are not initialized. Please log-out and log-in again.'
85
-					);
86
-				} else {
87
-					$message = $this->l->t(
88
-						'Please enable server side encryption in the admin settings in order to use the encryption module.'
89
-					);
90
-				}
91
-				break;
92
-			case Session::INIT_SUCCESSFUL:
93
-				$status = 'success';
94
-				$message = $this->l->t('Encryption app is enabled and ready');
95
-		}
66
+    /**
67
+     * @NoAdminRequired
68
+     * @return DataResponse
69
+     */
70
+    public function getStatus() {
71
+        $status = 'error';
72
+        $message = 'no valid init status';
73
+        switch ($this->session->getStatus()) {
74
+            case Session::INIT_EXECUTED:
75
+                $status = 'interactionNeeded';
76
+                $message = $this->l->t(
77
+                    'Invalid private key for encryption app. Please update your private key password in your personal settings to recover access to your encrypted files.'
78
+                );
79
+                break;
80
+            case Session::NOT_INITIALIZED:
81
+                $status = 'interactionNeeded';
82
+                if ($this->encryptionManager->isEnabled()) {
83
+                    $message = $this->l->t(
84
+                        'Encryption App is enabled, but your keys are not initialized. Please log-out and log-in again.'
85
+                    );
86
+                } else {
87
+                    $message = $this->l->t(
88
+                        'Please enable server side encryption in the admin settings in order to use the encryption module.'
89
+                    );
90
+                }
91
+                break;
92
+            case Session::INIT_SUCCESSFUL:
93
+                $status = 'success';
94
+                $message = $this->l->t('Encryption app is enabled and ready');
95
+        }
96 96
 
97
-		return new DataResponse(
98
-			[
99
-				'status' => $status,
100
-				'data' => [
101
-					'message' => $message]
102
-			]
103
-		);
104
-	}
97
+        return new DataResponse(
98
+            [
99
+                'status' => $status,
100
+                'data' => [
101
+                    'message' => $message]
102
+            ]
103
+        );
104
+    }
105 105
 }
Please login to merge, or discard this patch.
apps/encryption/lib/Controller/RecoveryController.php 1 patch
Indentation   +153 added lines, -153 removed lines patch added patch discarded remove patch
@@ -35,157 +35,157 @@
 block discarded – undo
35 35
 use OCP\IRequest;
36 36
 
37 37
 class RecoveryController extends Controller {
38
-	/**
39
-	 * @var IConfig
40
-	 */
41
-	private $config;
42
-	/**
43
-	 * @var IL10N
44
-	 */
45
-	private $l;
46
-	/**
47
-	 * @var Recovery
48
-	 */
49
-	private $recovery;
50
-
51
-	/**
52
-	 * @param string $AppName
53
-	 * @param IRequest $request
54
-	 * @param IConfig $config
55
-	 * @param IL10N $l10n
56
-	 * @param Recovery $recovery
57
-	 */
58
-	public function __construct($AppName,
59
-								IRequest $request,
60
-								IConfig $config,
61
-								IL10N $l10n,
62
-								Recovery $recovery) {
63
-		parent::__construct($AppName, $request);
64
-		$this->config = $config;
65
-		$this->l = $l10n;
66
-		$this->recovery = $recovery;
67
-	}
68
-
69
-	/**
70
-	 * @param string $recoveryPassword
71
-	 * @param string $confirmPassword
72
-	 * @param string $adminEnableRecovery
73
-	 * @return DataResponse
74
-	 */
75
-	public function adminRecovery($recoveryPassword, $confirmPassword, $adminEnableRecovery) {
76
-		// Check if both passwords are the same
77
-		if (empty($recoveryPassword)) {
78
-			$errorMessage = $this->l->t('Missing recovery key password');
79
-			return new DataResponse(['data' => ['message' => $errorMessage]],
80
-				Http::STATUS_BAD_REQUEST);
81
-		}
82
-
83
-		if (empty($confirmPassword)) {
84
-			$errorMessage = $this->l->t('Please repeat the recovery key password');
85
-			return new DataResponse(['data' => ['message' => $errorMessage]],
86
-				Http::STATUS_BAD_REQUEST);
87
-		}
88
-
89
-		if ($recoveryPassword !== $confirmPassword) {
90
-			$errorMessage = $this->l->t('Repeated recovery key password does not match the provided recovery key password');
91
-			return new DataResponse(['data' => ['message' => $errorMessage]],
92
-				Http::STATUS_BAD_REQUEST);
93
-		}
94
-
95
-		if (isset($adminEnableRecovery) && $adminEnableRecovery === '1') {
96
-			if ($this->recovery->enableAdminRecovery($recoveryPassword)) {
97
-				return new DataResponse(['data' => ['message' => $this->l->t('Recovery key successfully enabled')]]);
98
-			}
99
-			return new DataResponse(['data' => ['message' => $this->l->t('Could not enable recovery key. Please check your recovery key password!')]], Http::STATUS_BAD_REQUEST);
100
-		} elseif (isset($adminEnableRecovery) && $adminEnableRecovery === '0') {
101
-			if ($this->recovery->disableAdminRecovery($recoveryPassword)) {
102
-				return new DataResponse(['data' => ['message' => $this->l->t('Recovery key successfully disabled')]]);
103
-			}
104
-			return new DataResponse(['data' => ['message' => $this->l->t('Could not disable recovery key. Please check your recovery key password!')]], Http::STATUS_BAD_REQUEST);
105
-		}
106
-		// this response should never be sent but just in case.
107
-		return new DataResponse(['data' => ['message' => $this->l->t('Missing parameters')]], Http::STATUS_BAD_REQUEST);
108
-	}
109
-
110
-	/**
111
-	 * @param string $newPassword
112
-	 * @param string $oldPassword
113
-	 * @param string $confirmPassword
114
-	 * @return DataResponse
115
-	 */
116
-	public function changeRecoveryPassword($newPassword, $oldPassword, $confirmPassword) {
117
-		//check if both passwords are the same
118
-		if (empty($oldPassword)) {
119
-			$errorMessage = $this->l->t('Please provide the old recovery password');
120
-			return new DataResponse(['data' => ['message' => $errorMessage]], Http::STATUS_BAD_REQUEST);
121
-		}
122
-
123
-		if (empty($newPassword)) {
124
-			$errorMessage = $this->l->t('Please provide a new recovery password');
125
-			return new DataResponse(['data' => ['message' => $errorMessage]], Http::STATUS_BAD_REQUEST);
126
-		}
127
-
128
-		if (empty($confirmPassword)) {
129
-			$errorMessage = $this->l->t('Please repeat the new recovery password');
130
-			return new DataResponse(['data' => ['message' => $errorMessage]], Http::STATUS_BAD_REQUEST);
131
-		}
132
-
133
-		if ($newPassword !== $confirmPassword) {
134
-			$errorMessage = $this->l->t('Repeated recovery key password does not match the provided recovery key password');
135
-			return new DataResponse(['data' => ['message' => $errorMessage]], Http::STATUS_BAD_REQUEST);
136
-		}
137
-
138
-		$result = $this->recovery->changeRecoveryKeyPassword($newPassword,
139
-			$oldPassword);
140
-
141
-		if ($result) {
142
-			return new DataResponse(
143
-				[
144
-					'data' => [
145
-						'message' => $this->l->t('Password successfully changed.')]
146
-				]
147
-			);
148
-		}
149
-		return new DataResponse(
150
-			[
151
-				'data' => [
152
-					'message' => $this->l->t('Could not change the password. Maybe the old password was not correct.')
153
-				]
154
-			], Http::STATUS_BAD_REQUEST);
155
-	}
156
-
157
-	/**
158
-	 * @NoAdminRequired
159
-	 *
160
-	 * @param string $userEnableRecovery
161
-	 * @return DataResponse
162
-	 */
163
-	public function userSetRecovery($userEnableRecovery) {
164
-		if ($userEnableRecovery === '0' || $userEnableRecovery === '1') {
165
-			$result = $this->recovery->setRecoveryForUser($userEnableRecovery);
166
-
167
-			if ($result) {
168
-				if ($userEnableRecovery === '0') {
169
-					return new DataResponse(
170
-						[
171
-							'data' => [
172
-								'message' => $this->l->t('Recovery Key disabled')]
173
-						]
174
-					);
175
-				}
176
-				return new DataResponse(
177
-					[
178
-						'data' => [
179
-							'message' => $this->l->t('Recovery Key enabled')]
180
-					]
181
-				);
182
-			}
183
-		}
184
-		return new DataResponse(
185
-			[
186
-				'data' => [
187
-					'message' => $this->l->t('Could not enable the recovery key, please try again or contact your administrator')
188
-				]
189
-			], Http::STATUS_BAD_REQUEST);
190
-	}
38
+    /**
39
+     * @var IConfig
40
+     */
41
+    private $config;
42
+    /**
43
+     * @var IL10N
44
+     */
45
+    private $l;
46
+    /**
47
+     * @var Recovery
48
+     */
49
+    private $recovery;
50
+
51
+    /**
52
+     * @param string $AppName
53
+     * @param IRequest $request
54
+     * @param IConfig $config
55
+     * @param IL10N $l10n
56
+     * @param Recovery $recovery
57
+     */
58
+    public function __construct($AppName,
59
+                                IRequest $request,
60
+                                IConfig $config,
61
+                                IL10N $l10n,
62
+                                Recovery $recovery) {
63
+        parent::__construct($AppName, $request);
64
+        $this->config = $config;
65
+        $this->l = $l10n;
66
+        $this->recovery = $recovery;
67
+    }
68
+
69
+    /**
70
+     * @param string $recoveryPassword
71
+     * @param string $confirmPassword
72
+     * @param string $adminEnableRecovery
73
+     * @return DataResponse
74
+     */
75
+    public function adminRecovery($recoveryPassword, $confirmPassword, $adminEnableRecovery) {
76
+        // Check if both passwords are the same
77
+        if (empty($recoveryPassword)) {
78
+            $errorMessage = $this->l->t('Missing recovery key password');
79
+            return new DataResponse(['data' => ['message' => $errorMessage]],
80
+                Http::STATUS_BAD_REQUEST);
81
+        }
82
+
83
+        if (empty($confirmPassword)) {
84
+            $errorMessage = $this->l->t('Please repeat the recovery key password');
85
+            return new DataResponse(['data' => ['message' => $errorMessage]],
86
+                Http::STATUS_BAD_REQUEST);
87
+        }
88
+
89
+        if ($recoveryPassword !== $confirmPassword) {
90
+            $errorMessage = $this->l->t('Repeated recovery key password does not match the provided recovery key password');
91
+            return new DataResponse(['data' => ['message' => $errorMessage]],
92
+                Http::STATUS_BAD_REQUEST);
93
+        }
94
+
95
+        if (isset($adminEnableRecovery) && $adminEnableRecovery === '1') {
96
+            if ($this->recovery->enableAdminRecovery($recoveryPassword)) {
97
+                return new DataResponse(['data' => ['message' => $this->l->t('Recovery key successfully enabled')]]);
98
+            }
99
+            return new DataResponse(['data' => ['message' => $this->l->t('Could not enable recovery key. Please check your recovery key password!')]], Http::STATUS_BAD_REQUEST);
100
+        } elseif (isset($adminEnableRecovery) && $adminEnableRecovery === '0') {
101
+            if ($this->recovery->disableAdminRecovery($recoveryPassword)) {
102
+                return new DataResponse(['data' => ['message' => $this->l->t('Recovery key successfully disabled')]]);
103
+            }
104
+            return new DataResponse(['data' => ['message' => $this->l->t('Could not disable recovery key. Please check your recovery key password!')]], Http::STATUS_BAD_REQUEST);
105
+        }
106
+        // this response should never be sent but just in case.
107
+        return new DataResponse(['data' => ['message' => $this->l->t('Missing parameters')]], Http::STATUS_BAD_REQUEST);
108
+    }
109
+
110
+    /**
111
+     * @param string $newPassword
112
+     * @param string $oldPassword
113
+     * @param string $confirmPassword
114
+     * @return DataResponse
115
+     */
116
+    public function changeRecoveryPassword($newPassword, $oldPassword, $confirmPassword) {
117
+        //check if both passwords are the same
118
+        if (empty($oldPassword)) {
119
+            $errorMessage = $this->l->t('Please provide the old recovery password');
120
+            return new DataResponse(['data' => ['message' => $errorMessage]], Http::STATUS_BAD_REQUEST);
121
+        }
122
+
123
+        if (empty($newPassword)) {
124
+            $errorMessage = $this->l->t('Please provide a new recovery password');
125
+            return new DataResponse(['data' => ['message' => $errorMessage]], Http::STATUS_BAD_REQUEST);
126
+        }
127
+
128
+        if (empty($confirmPassword)) {
129
+            $errorMessage = $this->l->t('Please repeat the new recovery password');
130
+            return new DataResponse(['data' => ['message' => $errorMessage]], Http::STATUS_BAD_REQUEST);
131
+        }
132
+
133
+        if ($newPassword !== $confirmPassword) {
134
+            $errorMessage = $this->l->t('Repeated recovery key password does not match the provided recovery key password');
135
+            return new DataResponse(['data' => ['message' => $errorMessage]], Http::STATUS_BAD_REQUEST);
136
+        }
137
+
138
+        $result = $this->recovery->changeRecoveryKeyPassword($newPassword,
139
+            $oldPassword);
140
+
141
+        if ($result) {
142
+            return new DataResponse(
143
+                [
144
+                    'data' => [
145
+                        'message' => $this->l->t('Password successfully changed.')]
146
+                ]
147
+            );
148
+        }
149
+        return new DataResponse(
150
+            [
151
+                'data' => [
152
+                    'message' => $this->l->t('Could not change the password. Maybe the old password was not correct.')
153
+                ]
154
+            ], Http::STATUS_BAD_REQUEST);
155
+    }
156
+
157
+    /**
158
+     * @NoAdminRequired
159
+     *
160
+     * @param string $userEnableRecovery
161
+     * @return DataResponse
162
+     */
163
+    public function userSetRecovery($userEnableRecovery) {
164
+        if ($userEnableRecovery === '0' || $userEnableRecovery === '1') {
165
+            $result = $this->recovery->setRecoveryForUser($userEnableRecovery);
166
+
167
+            if ($result) {
168
+                if ($userEnableRecovery === '0') {
169
+                    return new DataResponse(
170
+                        [
171
+                            'data' => [
172
+                                'message' => $this->l->t('Recovery Key disabled')]
173
+                        ]
174
+                    );
175
+                }
176
+                return new DataResponse(
177
+                    [
178
+                        'data' => [
179
+                            'message' => $this->l->t('Recovery Key enabled')]
180
+                    ]
181
+                );
182
+            }
183
+        }
184
+        return new DataResponse(
185
+            [
186
+                'data' => [
187
+                    'message' => $this->l->t('Could not enable the recovery key, please try again or contact your administrator')
188
+                ]
189
+            ], Http::STATUS_BAD_REQUEST);
190
+    }
191 191
 }
Please login to merge, or discard this patch.
apps/encryption/lib/Crypto/EncryptAll.php 2 patches
Indentation   +430 added lines, -430 removed lines patch added patch discarded remove patch
@@ -47,434 +47,434 @@
 block discarded – undo
47 47
 
48 48
 class EncryptAll {
49 49
 
50
-	/** @var Setup */
51
-	protected $userSetup;
52
-
53
-	/** @var IUserManager */
54
-	protected $userManager;
55
-
56
-	/** @var View */
57
-	protected $rootView;
58
-
59
-	/** @var KeyManager */
60
-	protected $keyManager;
61
-
62
-	/** @var Util */
63
-	protected $util;
64
-
65
-	/** @var array  */
66
-	protected $userPasswords;
67
-
68
-	/** @var  IConfig */
69
-	protected $config;
70
-
71
-	/** @var IMailer */
72
-	protected $mailer;
73
-
74
-	/** @var  IL10N */
75
-	protected $l;
76
-
77
-	/** @var  QuestionHelper */
78
-	protected $questionHelper;
79
-
80
-	/** @var  OutputInterface */
81
-	protected $output;
82
-
83
-	/** @var  InputInterface */
84
-	protected $input;
85
-
86
-	/** @var ISecureRandom */
87
-	protected $secureRandom;
88
-
89
-	/**
90
-	 * @param Setup $userSetup
91
-	 * @param IUserManager $userManager
92
-	 * @param View $rootView
93
-	 * @param KeyManager $keyManager
94
-	 * @param Util $util
95
-	 * @param IConfig $config
96
-	 * @param IMailer $mailer
97
-	 * @param IL10N $l
98
-	 * @param QuestionHelper $questionHelper
99
-	 * @param ISecureRandom $secureRandom
100
-	 */
101
-	public function __construct(
102
-		Setup $userSetup,
103
-		IUserManager $userManager,
104
-		View $rootView,
105
-		KeyManager $keyManager,
106
-		Util $util,
107
-		IConfig $config,
108
-		IMailer $mailer,
109
-		IL10N $l,
110
-		QuestionHelper $questionHelper,
111
-		ISecureRandom $secureRandom
112
-	) {
113
-		$this->userSetup = $userSetup;
114
-		$this->userManager = $userManager;
115
-		$this->rootView = $rootView;
116
-		$this->keyManager = $keyManager;
117
-		$this->util = $util;
118
-		$this->config = $config;
119
-		$this->mailer = $mailer;
120
-		$this->l = $l;
121
-		$this->questionHelper = $questionHelper;
122
-		$this->secureRandom = $secureRandom;
123
-		// store one time passwords for the users
124
-		$this->userPasswords = [];
125
-	}
126
-
127
-	/**
128
-	 * start to encrypt all files
129
-	 *
130
-	 * @param InputInterface $input
131
-	 * @param OutputInterface $output
132
-	 */
133
-	public function encryptAll(InputInterface $input, OutputInterface $output) {
134
-		$this->input = $input;
135
-		$this->output = $output;
136
-
137
-		$headline = 'Encrypt all files with the ' . Encryption::DISPLAY_NAME;
138
-		$this->output->writeln("\n");
139
-		$this->output->writeln($headline);
140
-		$this->output->writeln(str_pad('', strlen($headline), '='));
141
-		$this->output->writeln("\n");
142
-
143
-		if ($this->util->isMasterKeyEnabled()) {
144
-			$this->output->writeln('Use master key to encrypt all files.');
145
-			$this->keyManager->validateMasterKey();
146
-		} else {
147
-			//create private/public keys for each user and store the private key password
148
-			$this->output->writeln('Create key-pair for every user');
149
-			$this->output->writeln('------------------------------');
150
-			$this->output->writeln('');
151
-			$this->output->writeln('This module will encrypt all files in the users files folder initially.');
152
-			$this->output->writeln('Already existing versions and files in the trash bin will not be encrypted.');
153
-			$this->output->writeln('');
154
-			$this->createKeyPairs();
155
-		}
156
-
157
-
158
-		// output generated encryption key passwords
159
-		if ($this->util->isMasterKeyEnabled() === false) {
160
-			//send-out or display password list and write it to a file
161
-			$this->output->writeln("\n");
162
-			$this->output->writeln('Generated encryption key passwords');
163
-			$this->output->writeln('----------------------------------');
164
-			$this->output->writeln('');
165
-			$this->outputPasswords();
166
-		}
167
-
168
-		//setup users file system and encrypt all files one by one (take should encrypt setting of storage into account)
169
-		$this->output->writeln("\n");
170
-		$this->output->writeln('Start to encrypt users files');
171
-		$this->output->writeln('----------------------------');
172
-		$this->output->writeln('');
173
-		$this->encryptAllUsersFiles();
174
-		$this->output->writeln("\n");
175
-	}
176
-
177
-	/**
178
-	 * create key-pair for every user
179
-	 */
180
-	protected function createKeyPairs() {
181
-		$this->output->writeln("\n");
182
-		$progress = new ProgressBar($this->output);
183
-		$progress->setFormat(" %message% \n [%bar%]");
184
-		$progress->start();
185
-
186
-		foreach ($this->userManager->getBackends() as $backend) {
187
-			$limit = 500;
188
-			$offset = 0;
189
-			do {
190
-				$users = $backend->getUsers('', $limit, $offset);
191
-				foreach ($users as $user) {
192
-					if ($this->keyManager->userHasKeys($user) === false) {
193
-						$progress->setMessage('Create key-pair for ' . $user);
194
-						$progress->advance();
195
-						$this->setupUserFS($user);
196
-						$password = $this->generateOneTimePassword($user);
197
-						$this->userSetup->setupUser($user, $password);
198
-					} else {
199
-						// users which already have a key-pair will be stored with a
200
-						// empty password and filtered out later
201
-						$this->userPasswords[$user] = '';
202
-					}
203
-				}
204
-				$offset += $limit;
205
-			} while (count($users) >= $limit);
206
-		}
207
-
208
-		$progress->setMessage('Key-pair created for all users');
209
-		$progress->finish();
210
-	}
211
-
212
-	/**
213
-	 * iterate over all user and encrypt their files
214
-	 */
215
-	protected function encryptAllUsersFiles() {
216
-		$this->output->writeln("\n");
217
-		$progress = new ProgressBar($this->output);
218
-		$progress->setFormat(" %message% \n [%bar%]");
219
-		$progress->start();
220
-		$numberOfUsers = count($this->userPasswords);
221
-		$userNo = 1;
222
-		if ($this->util->isMasterKeyEnabled()) {
223
-			$this->encryptAllUserFilesWithMasterKey($progress);
224
-		} else {
225
-			foreach ($this->userPasswords as $uid => $password) {
226
-				$userCount = "$uid ($userNo of $numberOfUsers)";
227
-				$this->encryptUsersFiles($uid, $progress, $userCount);
228
-				$userNo++;
229
-			}
230
-		}
231
-		$progress->setMessage("all files encrypted");
232
-		$progress->finish();
233
-	}
234
-
235
-	/**
236
-	 * encrypt all user files with the master key
237
-	 *
238
-	 * @param ProgressBar $progress
239
-	 */
240
-	protected function encryptAllUserFilesWithMasterKey(ProgressBar $progress) {
241
-		$userNo = 1;
242
-		foreach ($this->userManager->getBackends() as $backend) {
243
-			$limit = 500;
244
-			$offset = 0;
245
-			do {
246
-				$users = $backend->getUsers('', $limit, $offset);
247
-				foreach ($users as $user) {
248
-					$userCount = "$user ($userNo)";
249
-					$this->encryptUsersFiles($user, $progress, $userCount);
250
-					$userNo++;
251
-				}
252
-				$offset += $limit;
253
-			} while (count($users) >= $limit);
254
-		}
255
-	}
256
-
257
-	/**
258
-	 * encrypt files from the given user
259
-	 *
260
-	 * @param string $uid
261
-	 * @param ProgressBar $progress
262
-	 * @param string $userCount
263
-	 */
264
-	protected function encryptUsersFiles($uid, ProgressBar $progress, $userCount) {
265
-		$this->setupUserFS($uid);
266
-		$directories = [];
267
-		$directories[] = '/' . $uid . '/files';
268
-
269
-		while ($root = array_pop($directories)) {
270
-			$content = $this->rootView->getDirectoryContent($root);
271
-			foreach ($content as $file) {
272
-				$path = $root . '/' . $file['name'];
273
-				if ($this->rootView->is_dir($path)) {
274
-					$directories[] = $path;
275
-					continue;
276
-				} else {
277
-					$progress->setMessage("encrypt files for user $userCount: $path");
278
-					$progress->advance();
279
-					if ($this->encryptFile($path) === false) {
280
-						$progress->setMessage("encrypt files for user $userCount: $path (already encrypted)");
281
-						$progress->advance();
282
-					}
283
-				}
284
-			}
285
-		}
286
-	}
287
-
288
-	/**
289
-	 * encrypt file
290
-	 *
291
-	 * @param string $path
292
-	 * @return bool
293
-	 */
294
-	protected function encryptFile($path) {
295
-
296
-		// skip already encrypted files
297
-		$fileInfo = $this->rootView->getFileInfo($path);
298
-		if ($fileInfo !== false && $fileInfo->isEncrypted()) {
299
-			return true;
300
-		}
301
-
302
-		$source = $path;
303
-		$target = $path . '.encrypted.' . time();
304
-
305
-		try {
306
-			$this->rootView->copy($source, $target);
307
-			$this->rootView->rename($target, $source);
308
-		} catch (DecryptionFailedException $e) {
309
-			if ($this->rootView->file_exists($target)) {
310
-				$this->rootView->unlink($target);
311
-			}
312
-			return false;
313
-		}
314
-
315
-		return true;
316
-	}
317
-
318
-	/**
319
-	 * output one-time encryption passwords
320
-	 */
321
-	protected function outputPasswords() {
322
-		$table = new Table($this->output);
323
-		$table->setHeaders(['Username', 'Private key password']);
324
-
325
-		//create rows
326
-		$newPasswords = [];
327
-		$unchangedPasswords = [];
328
-		foreach ($this->userPasswords as $uid => $password) {
329
-			if (empty($password)) {
330
-				$unchangedPasswords[] = $uid;
331
-			} else {
332
-				$newPasswords[] = [$uid, $password];
333
-			}
334
-		}
335
-
336
-		if (empty($newPasswords)) {
337
-			$this->output->writeln("\nAll users already had a key-pair, no further action needed.\n");
338
-			return;
339
-		}
340
-
341
-		$table->setRows($newPasswords);
342
-		$table->render();
343
-
344
-		if (!empty($unchangedPasswords)) {
345
-			$this->output->writeln("\nThe following users already had a key-pair which was reused without setting a new password:\n");
346
-			foreach ($unchangedPasswords as $uid) {
347
-				$this->output->writeln("    $uid");
348
-			}
349
-		}
350
-
351
-		$this->writePasswordsToFile($newPasswords);
352
-
353
-		$this->output->writeln('');
354
-		$question = new ConfirmationQuestion('Do you want to send the passwords directly to the users by mail? (y/n) ', false);
355
-		if ($this->questionHelper->ask($this->input, $this->output, $question)) {
356
-			$this->sendPasswordsByMail();
357
-		}
358
-	}
359
-
360
-	/**
361
-	 * write one-time encryption passwords to a csv file
362
-	 *
363
-	 * @param array $passwords
364
-	 */
365
-	protected function writePasswordsToFile(array $passwords) {
366
-		$fp = $this->rootView->fopen('oneTimeEncryptionPasswords.csv', 'w');
367
-		foreach ($passwords as $pwd) {
368
-			fputcsv($fp, $pwd);
369
-		}
370
-		fclose($fp);
371
-		$this->output->writeln("\n");
372
-		$this->output->writeln('A list of all newly created passwords was written to data/oneTimeEncryptionPasswords.csv');
373
-		$this->output->writeln('');
374
-		$this->output->writeln('Each of these users need to login to the web interface, go to the');
375
-		$this->output->writeln('personal settings section "basic encryption module" and');
376
-		$this->output->writeln('update the private key password to match the login password again by');
377
-		$this->output->writeln('entering the one-time password into the "old log-in password" field');
378
-		$this->output->writeln('and their current login password');
379
-	}
380
-
381
-	/**
382
-	 * setup user file system
383
-	 *
384
-	 * @param string $uid
385
-	 */
386
-	protected function setupUserFS($uid) {
387
-		\OC_Util::tearDownFS();
388
-		\OC_Util::setupFS($uid);
389
-	}
390
-
391
-	/**
392
-	 * generate one time password for the user and store it in a array
393
-	 *
394
-	 * @param string $uid
395
-	 * @return string password
396
-	 */
397
-	protected function generateOneTimePassword($uid) {
398
-		$password = $this->secureRandom->generate(8);
399
-		$this->userPasswords[$uid] = $password;
400
-		return $password;
401
-	}
402
-
403
-	/**
404
-	 * send encryption key passwords to the users by mail
405
-	 */
406
-	protected function sendPasswordsByMail() {
407
-		$noMail = [];
408
-
409
-		$this->output->writeln('');
410
-		$progress = new ProgressBar($this->output, count($this->userPasswords));
411
-		$progress->start();
412
-
413
-		foreach ($this->userPasswords as $uid => $password) {
414
-			$progress->advance();
415
-			if (!empty($password)) {
416
-				$recipient = $this->userManager->get($uid);
417
-				$recipientDisplayName = $recipient->getDisplayName();
418
-				$to = $recipient->getEMailAddress();
419
-
420
-				if ($to === '') {
421
-					$noMail[] = $uid;
422
-					continue;
423
-				}
424
-
425
-				$subject = $this->l->t('one-time password for server-side-encryption');
426
-				list($htmlBody, $textBody) = $this->createMailBody($password);
427
-
428
-				// send it out now
429
-				try {
430
-					$message = $this->mailer->createMessage();
431
-					$message->setSubject($subject);
432
-					$message->setTo([$to => $recipientDisplayName]);
433
-					$message->setHtmlBody($htmlBody);
434
-					$message->setPlainBody($textBody);
435
-					$message->setFrom([
436
-						\OCP\Util::getDefaultEmailAddress('admin-noreply')
437
-					]);
438
-
439
-					$this->mailer->send($message);
440
-				} catch (\Exception $e) {
441
-					$noMail[] = $uid;
442
-				}
443
-			}
444
-		}
445
-
446
-		$progress->finish();
447
-
448
-		if (empty($noMail)) {
449
-			$this->output->writeln("\n\nPassword successfully send to all users");
450
-		} else {
451
-			$table = new Table($this->output);
452
-			$table->setHeaders(['Username', 'Private key password']);
453
-			$this->output->writeln("\n\nCould not send password to following users:\n");
454
-			$rows = [];
455
-			foreach ($noMail as $uid) {
456
-				$rows[] = [$uid, $this->userPasswords[$uid]];
457
-			}
458
-			$table->setRows($rows);
459
-			$table->render();
460
-		}
461
-	}
462
-
463
-	/**
464
-	 * create mail body for plain text and html mail
465
-	 *
466
-	 * @param string $password one-time encryption password
467
-	 * @return array an array of the html mail body and the plain text mail body
468
-	 */
469
-	protected function createMailBody($password) {
470
-		$html = new \OC_Template("encryption", "mail", "");
471
-		$html->assign('password', $password);
472
-		$htmlMail = $html->fetchPage();
473
-
474
-		$plainText = new \OC_Template("encryption", "altmail", "");
475
-		$plainText->assign('password', $password);
476
-		$plainTextMail = $plainText->fetchPage();
477
-
478
-		return [$htmlMail, $plainTextMail];
479
-	}
50
+    /** @var Setup */
51
+    protected $userSetup;
52
+
53
+    /** @var IUserManager */
54
+    protected $userManager;
55
+
56
+    /** @var View */
57
+    protected $rootView;
58
+
59
+    /** @var KeyManager */
60
+    protected $keyManager;
61
+
62
+    /** @var Util */
63
+    protected $util;
64
+
65
+    /** @var array  */
66
+    protected $userPasswords;
67
+
68
+    /** @var  IConfig */
69
+    protected $config;
70
+
71
+    /** @var IMailer */
72
+    protected $mailer;
73
+
74
+    /** @var  IL10N */
75
+    protected $l;
76
+
77
+    /** @var  QuestionHelper */
78
+    protected $questionHelper;
79
+
80
+    /** @var  OutputInterface */
81
+    protected $output;
82
+
83
+    /** @var  InputInterface */
84
+    protected $input;
85
+
86
+    /** @var ISecureRandom */
87
+    protected $secureRandom;
88
+
89
+    /**
90
+     * @param Setup $userSetup
91
+     * @param IUserManager $userManager
92
+     * @param View $rootView
93
+     * @param KeyManager $keyManager
94
+     * @param Util $util
95
+     * @param IConfig $config
96
+     * @param IMailer $mailer
97
+     * @param IL10N $l
98
+     * @param QuestionHelper $questionHelper
99
+     * @param ISecureRandom $secureRandom
100
+     */
101
+    public function __construct(
102
+        Setup $userSetup,
103
+        IUserManager $userManager,
104
+        View $rootView,
105
+        KeyManager $keyManager,
106
+        Util $util,
107
+        IConfig $config,
108
+        IMailer $mailer,
109
+        IL10N $l,
110
+        QuestionHelper $questionHelper,
111
+        ISecureRandom $secureRandom
112
+    ) {
113
+        $this->userSetup = $userSetup;
114
+        $this->userManager = $userManager;
115
+        $this->rootView = $rootView;
116
+        $this->keyManager = $keyManager;
117
+        $this->util = $util;
118
+        $this->config = $config;
119
+        $this->mailer = $mailer;
120
+        $this->l = $l;
121
+        $this->questionHelper = $questionHelper;
122
+        $this->secureRandom = $secureRandom;
123
+        // store one time passwords for the users
124
+        $this->userPasswords = [];
125
+    }
126
+
127
+    /**
128
+     * start to encrypt all files
129
+     *
130
+     * @param InputInterface $input
131
+     * @param OutputInterface $output
132
+     */
133
+    public function encryptAll(InputInterface $input, OutputInterface $output) {
134
+        $this->input = $input;
135
+        $this->output = $output;
136
+
137
+        $headline = 'Encrypt all files with the ' . Encryption::DISPLAY_NAME;
138
+        $this->output->writeln("\n");
139
+        $this->output->writeln($headline);
140
+        $this->output->writeln(str_pad('', strlen($headline), '='));
141
+        $this->output->writeln("\n");
142
+
143
+        if ($this->util->isMasterKeyEnabled()) {
144
+            $this->output->writeln('Use master key to encrypt all files.');
145
+            $this->keyManager->validateMasterKey();
146
+        } else {
147
+            //create private/public keys for each user and store the private key password
148
+            $this->output->writeln('Create key-pair for every user');
149
+            $this->output->writeln('------------------------------');
150
+            $this->output->writeln('');
151
+            $this->output->writeln('This module will encrypt all files in the users files folder initially.');
152
+            $this->output->writeln('Already existing versions and files in the trash bin will not be encrypted.');
153
+            $this->output->writeln('');
154
+            $this->createKeyPairs();
155
+        }
156
+
157
+
158
+        // output generated encryption key passwords
159
+        if ($this->util->isMasterKeyEnabled() === false) {
160
+            //send-out or display password list and write it to a file
161
+            $this->output->writeln("\n");
162
+            $this->output->writeln('Generated encryption key passwords');
163
+            $this->output->writeln('----------------------------------');
164
+            $this->output->writeln('');
165
+            $this->outputPasswords();
166
+        }
167
+
168
+        //setup users file system and encrypt all files one by one (take should encrypt setting of storage into account)
169
+        $this->output->writeln("\n");
170
+        $this->output->writeln('Start to encrypt users files');
171
+        $this->output->writeln('----------------------------');
172
+        $this->output->writeln('');
173
+        $this->encryptAllUsersFiles();
174
+        $this->output->writeln("\n");
175
+    }
176
+
177
+    /**
178
+     * create key-pair for every user
179
+     */
180
+    protected function createKeyPairs() {
181
+        $this->output->writeln("\n");
182
+        $progress = new ProgressBar($this->output);
183
+        $progress->setFormat(" %message% \n [%bar%]");
184
+        $progress->start();
185
+
186
+        foreach ($this->userManager->getBackends() as $backend) {
187
+            $limit = 500;
188
+            $offset = 0;
189
+            do {
190
+                $users = $backend->getUsers('', $limit, $offset);
191
+                foreach ($users as $user) {
192
+                    if ($this->keyManager->userHasKeys($user) === false) {
193
+                        $progress->setMessage('Create key-pair for ' . $user);
194
+                        $progress->advance();
195
+                        $this->setupUserFS($user);
196
+                        $password = $this->generateOneTimePassword($user);
197
+                        $this->userSetup->setupUser($user, $password);
198
+                    } else {
199
+                        // users which already have a key-pair will be stored with a
200
+                        // empty password and filtered out later
201
+                        $this->userPasswords[$user] = '';
202
+                    }
203
+                }
204
+                $offset += $limit;
205
+            } while (count($users) >= $limit);
206
+        }
207
+
208
+        $progress->setMessage('Key-pair created for all users');
209
+        $progress->finish();
210
+    }
211
+
212
+    /**
213
+     * iterate over all user and encrypt their files
214
+     */
215
+    protected function encryptAllUsersFiles() {
216
+        $this->output->writeln("\n");
217
+        $progress = new ProgressBar($this->output);
218
+        $progress->setFormat(" %message% \n [%bar%]");
219
+        $progress->start();
220
+        $numberOfUsers = count($this->userPasswords);
221
+        $userNo = 1;
222
+        if ($this->util->isMasterKeyEnabled()) {
223
+            $this->encryptAllUserFilesWithMasterKey($progress);
224
+        } else {
225
+            foreach ($this->userPasswords as $uid => $password) {
226
+                $userCount = "$uid ($userNo of $numberOfUsers)";
227
+                $this->encryptUsersFiles($uid, $progress, $userCount);
228
+                $userNo++;
229
+            }
230
+        }
231
+        $progress->setMessage("all files encrypted");
232
+        $progress->finish();
233
+    }
234
+
235
+    /**
236
+     * encrypt all user files with the master key
237
+     *
238
+     * @param ProgressBar $progress
239
+     */
240
+    protected function encryptAllUserFilesWithMasterKey(ProgressBar $progress) {
241
+        $userNo = 1;
242
+        foreach ($this->userManager->getBackends() as $backend) {
243
+            $limit = 500;
244
+            $offset = 0;
245
+            do {
246
+                $users = $backend->getUsers('', $limit, $offset);
247
+                foreach ($users as $user) {
248
+                    $userCount = "$user ($userNo)";
249
+                    $this->encryptUsersFiles($user, $progress, $userCount);
250
+                    $userNo++;
251
+                }
252
+                $offset += $limit;
253
+            } while (count($users) >= $limit);
254
+        }
255
+    }
256
+
257
+    /**
258
+     * encrypt files from the given user
259
+     *
260
+     * @param string $uid
261
+     * @param ProgressBar $progress
262
+     * @param string $userCount
263
+     */
264
+    protected function encryptUsersFiles($uid, ProgressBar $progress, $userCount) {
265
+        $this->setupUserFS($uid);
266
+        $directories = [];
267
+        $directories[] = '/' . $uid . '/files';
268
+
269
+        while ($root = array_pop($directories)) {
270
+            $content = $this->rootView->getDirectoryContent($root);
271
+            foreach ($content as $file) {
272
+                $path = $root . '/' . $file['name'];
273
+                if ($this->rootView->is_dir($path)) {
274
+                    $directories[] = $path;
275
+                    continue;
276
+                } else {
277
+                    $progress->setMessage("encrypt files for user $userCount: $path");
278
+                    $progress->advance();
279
+                    if ($this->encryptFile($path) === false) {
280
+                        $progress->setMessage("encrypt files for user $userCount: $path (already encrypted)");
281
+                        $progress->advance();
282
+                    }
283
+                }
284
+            }
285
+        }
286
+    }
287
+
288
+    /**
289
+     * encrypt file
290
+     *
291
+     * @param string $path
292
+     * @return bool
293
+     */
294
+    protected function encryptFile($path) {
295
+
296
+        // skip already encrypted files
297
+        $fileInfo = $this->rootView->getFileInfo($path);
298
+        if ($fileInfo !== false && $fileInfo->isEncrypted()) {
299
+            return true;
300
+        }
301
+
302
+        $source = $path;
303
+        $target = $path . '.encrypted.' . time();
304
+
305
+        try {
306
+            $this->rootView->copy($source, $target);
307
+            $this->rootView->rename($target, $source);
308
+        } catch (DecryptionFailedException $e) {
309
+            if ($this->rootView->file_exists($target)) {
310
+                $this->rootView->unlink($target);
311
+            }
312
+            return false;
313
+        }
314
+
315
+        return true;
316
+    }
317
+
318
+    /**
319
+     * output one-time encryption passwords
320
+     */
321
+    protected function outputPasswords() {
322
+        $table = new Table($this->output);
323
+        $table->setHeaders(['Username', 'Private key password']);
324
+
325
+        //create rows
326
+        $newPasswords = [];
327
+        $unchangedPasswords = [];
328
+        foreach ($this->userPasswords as $uid => $password) {
329
+            if (empty($password)) {
330
+                $unchangedPasswords[] = $uid;
331
+            } else {
332
+                $newPasswords[] = [$uid, $password];
333
+            }
334
+        }
335
+
336
+        if (empty($newPasswords)) {
337
+            $this->output->writeln("\nAll users already had a key-pair, no further action needed.\n");
338
+            return;
339
+        }
340
+
341
+        $table->setRows($newPasswords);
342
+        $table->render();
343
+
344
+        if (!empty($unchangedPasswords)) {
345
+            $this->output->writeln("\nThe following users already had a key-pair which was reused without setting a new password:\n");
346
+            foreach ($unchangedPasswords as $uid) {
347
+                $this->output->writeln("    $uid");
348
+            }
349
+        }
350
+
351
+        $this->writePasswordsToFile($newPasswords);
352
+
353
+        $this->output->writeln('');
354
+        $question = new ConfirmationQuestion('Do you want to send the passwords directly to the users by mail? (y/n) ', false);
355
+        if ($this->questionHelper->ask($this->input, $this->output, $question)) {
356
+            $this->sendPasswordsByMail();
357
+        }
358
+    }
359
+
360
+    /**
361
+     * write one-time encryption passwords to a csv file
362
+     *
363
+     * @param array $passwords
364
+     */
365
+    protected function writePasswordsToFile(array $passwords) {
366
+        $fp = $this->rootView->fopen('oneTimeEncryptionPasswords.csv', 'w');
367
+        foreach ($passwords as $pwd) {
368
+            fputcsv($fp, $pwd);
369
+        }
370
+        fclose($fp);
371
+        $this->output->writeln("\n");
372
+        $this->output->writeln('A list of all newly created passwords was written to data/oneTimeEncryptionPasswords.csv');
373
+        $this->output->writeln('');
374
+        $this->output->writeln('Each of these users need to login to the web interface, go to the');
375
+        $this->output->writeln('personal settings section "basic encryption module" and');
376
+        $this->output->writeln('update the private key password to match the login password again by');
377
+        $this->output->writeln('entering the one-time password into the "old log-in password" field');
378
+        $this->output->writeln('and their current login password');
379
+    }
380
+
381
+    /**
382
+     * setup user file system
383
+     *
384
+     * @param string $uid
385
+     */
386
+    protected function setupUserFS($uid) {
387
+        \OC_Util::tearDownFS();
388
+        \OC_Util::setupFS($uid);
389
+    }
390
+
391
+    /**
392
+     * generate one time password for the user and store it in a array
393
+     *
394
+     * @param string $uid
395
+     * @return string password
396
+     */
397
+    protected function generateOneTimePassword($uid) {
398
+        $password = $this->secureRandom->generate(8);
399
+        $this->userPasswords[$uid] = $password;
400
+        return $password;
401
+    }
402
+
403
+    /**
404
+     * send encryption key passwords to the users by mail
405
+     */
406
+    protected function sendPasswordsByMail() {
407
+        $noMail = [];
408
+
409
+        $this->output->writeln('');
410
+        $progress = new ProgressBar($this->output, count($this->userPasswords));
411
+        $progress->start();
412
+
413
+        foreach ($this->userPasswords as $uid => $password) {
414
+            $progress->advance();
415
+            if (!empty($password)) {
416
+                $recipient = $this->userManager->get($uid);
417
+                $recipientDisplayName = $recipient->getDisplayName();
418
+                $to = $recipient->getEMailAddress();
419
+
420
+                if ($to === '') {
421
+                    $noMail[] = $uid;
422
+                    continue;
423
+                }
424
+
425
+                $subject = $this->l->t('one-time password for server-side-encryption');
426
+                list($htmlBody, $textBody) = $this->createMailBody($password);
427
+
428
+                // send it out now
429
+                try {
430
+                    $message = $this->mailer->createMessage();
431
+                    $message->setSubject($subject);
432
+                    $message->setTo([$to => $recipientDisplayName]);
433
+                    $message->setHtmlBody($htmlBody);
434
+                    $message->setPlainBody($textBody);
435
+                    $message->setFrom([
436
+                        \OCP\Util::getDefaultEmailAddress('admin-noreply')
437
+                    ]);
438
+
439
+                    $this->mailer->send($message);
440
+                } catch (\Exception $e) {
441
+                    $noMail[] = $uid;
442
+                }
443
+            }
444
+        }
445
+
446
+        $progress->finish();
447
+
448
+        if (empty($noMail)) {
449
+            $this->output->writeln("\n\nPassword successfully send to all users");
450
+        } else {
451
+            $table = new Table($this->output);
452
+            $table->setHeaders(['Username', 'Private key password']);
453
+            $this->output->writeln("\n\nCould not send password to following users:\n");
454
+            $rows = [];
455
+            foreach ($noMail as $uid) {
456
+                $rows[] = [$uid, $this->userPasswords[$uid]];
457
+            }
458
+            $table->setRows($rows);
459
+            $table->render();
460
+        }
461
+    }
462
+
463
+    /**
464
+     * create mail body for plain text and html mail
465
+     *
466
+     * @param string $password one-time encryption password
467
+     * @return array an array of the html mail body and the plain text mail body
468
+     */
469
+    protected function createMailBody($password) {
470
+        $html = new \OC_Template("encryption", "mail", "");
471
+        $html->assign('password', $password);
472
+        $htmlMail = $html->fetchPage();
473
+
474
+        $plainText = new \OC_Template("encryption", "altmail", "");
475
+        $plainText->assign('password', $password);
476
+        $plainTextMail = $plainText->fetchPage();
477
+
478
+        return [$htmlMail, $plainTextMail];
479
+    }
480 480
 }
Please login to merge, or discard this patch.
Spacing   +5 added lines, -5 removed lines patch added patch discarded remove patch
@@ -134,7 +134,7 @@  discard block
 block discarded – undo
134 134
 		$this->input = $input;
135 135
 		$this->output = $output;
136 136
 
137
-		$headline = 'Encrypt all files with the ' . Encryption::DISPLAY_NAME;
137
+		$headline = 'Encrypt all files with the '.Encryption::DISPLAY_NAME;
138 138
 		$this->output->writeln("\n");
139 139
 		$this->output->writeln($headline);
140 140
 		$this->output->writeln(str_pad('', strlen($headline), '='));
@@ -190,7 +190,7 @@  discard block
 block discarded – undo
190 190
 				$users = $backend->getUsers('', $limit, $offset);
191 191
 				foreach ($users as $user) {
192 192
 					if ($this->keyManager->userHasKeys($user) === false) {
193
-						$progress->setMessage('Create key-pair for ' . $user);
193
+						$progress->setMessage('Create key-pair for '.$user);
194 194
 						$progress->advance();
195 195
 						$this->setupUserFS($user);
196 196
 						$password = $this->generateOneTimePassword($user);
@@ -264,12 +264,12 @@  discard block
 block discarded – undo
264 264
 	protected function encryptUsersFiles($uid, ProgressBar $progress, $userCount) {
265 265
 		$this->setupUserFS($uid);
266 266
 		$directories = [];
267
-		$directories[] = '/' . $uid . '/files';
267
+		$directories[] = '/'.$uid.'/files';
268 268
 
269 269
 		while ($root = array_pop($directories)) {
270 270
 			$content = $this->rootView->getDirectoryContent($root);
271 271
 			foreach ($content as $file) {
272
-				$path = $root . '/' . $file['name'];
272
+				$path = $root.'/'.$file['name'];
273 273
 				if ($this->rootView->is_dir($path)) {
274 274
 					$directories[] = $path;
275 275
 					continue;
@@ -300,7 +300,7 @@  discard block
 block discarded – undo
300 300
 		}
301 301
 
302 302
 		$source = $path;
303
-		$target = $path . '.encrypted.' . time();
303
+		$target = $path.'.encrypted.'.time();
304 304
 
305 305
 		try {
306 306
 			$this->rootView->copy($source, $target);
Please login to merge, or discard this patch.