@@ -60,494 +60,494 @@ |
||
60 | 60 | */ |
61 | 61 | class IMipPlugin extends SabreIMipPlugin { |
62 | 62 | |
63 | - /** @var string */ |
|
64 | - private $userId; |
|
65 | - |
|
66 | - /** @var IConfig */ |
|
67 | - private $config; |
|
68 | - |
|
69 | - /** @var IMailer */ |
|
70 | - private $mailer; |
|
71 | - |
|
72 | - /** @var ILogger */ |
|
73 | - private $logger; |
|
74 | - |
|
75 | - /** @var ITimeFactory */ |
|
76 | - private $timeFactory; |
|
77 | - |
|
78 | - /** @var L10NFactory */ |
|
79 | - private $l10nFactory; |
|
80 | - |
|
81 | - /** @var IURLGenerator */ |
|
82 | - private $urlGenerator; |
|
83 | - |
|
84 | - /** @var ISecureRandom */ |
|
85 | - private $random; |
|
86 | - |
|
87 | - /** @var IDBConnection */ |
|
88 | - private $db; |
|
89 | - |
|
90 | - /** @var Defaults */ |
|
91 | - private $defaults; |
|
92 | - |
|
93 | - const MAX_DATE = '2038-01-01'; |
|
94 | - |
|
95 | - const METHOD_REQUEST = 'request'; |
|
96 | - const METHOD_REPLY = 'reply'; |
|
97 | - const METHOD_CANCEL = 'cancel'; |
|
98 | - |
|
99 | - /** |
|
100 | - * @param IConfig $config |
|
101 | - * @param IMailer $mailer |
|
102 | - * @param ILogger $logger |
|
103 | - * @param ITimeFactory $timeFactory |
|
104 | - * @param L10NFactory $l10nFactory |
|
105 | - * @param IUrlGenerator $urlGenerator |
|
106 | - * @param Defaults $defaults |
|
107 | - * @param ISecureRandom $random |
|
108 | - * @param IDBConnection $db |
|
109 | - * @param string $userId |
|
110 | - */ |
|
111 | - public function __construct(IConfig $config, IMailer $mailer, ILogger $logger, |
|
112 | - ITimeFactory $timeFactory, L10NFactory $l10nFactory, |
|
113 | - IURLGenerator $urlGenerator, Defaults $defaults, |
|
114 | - ISecureRandom $random, IDBConnection $db, $userId) { |
|
115 | - parent::__construct(''); |
|
116 | - $this->userId = $userId; |
|
117 | - $this->config = $config; |
|
118 | - $this->mailer = $mailer; |
|
119 | - $this->logger = $logger; |
|
120 | - $this->timeFactory = $timeFactory; |
|
121 | - $this->l10nFactory = $l10nFactory; |
|
122 | - $this->urlGenerator = $urlGenerator; |
|
123 | - $this->random = $random; |
|
124 | - $this->db = $db; |
|
125 | - $this->defaults = $defaults; |
|
126 | - } |
|
127 | - |
|
128 | - /** |
|
129 | - * Event handler for the 'schedule' event. |
|
130 | - * |
|
131 | - * @param Message $iTipMessage |
|
132 | - * @return void |
|
133 | - */ |
|
134 | - public function schedule(Message $iTipMessage) { |
|
135 | - |
|
136 | - // Not sending any emails if the system considers the update |
|
137 | - // insignificant. |
|
138 | - if (!$iTipMessage->significantChange) { |
|
139 | - if (!$iTipMessage->scheduleStatus) { |
|
140 | - $iTipMessage->scheduleStatus = '1.0;We got the message, but it\'s not significant enough to warrant an email'; |
|
141 | - } |
|
142 | - return; |
|
143 | - } |
|
144 | - |
|
145 | - $summary = $iTipMessage->message->VEVENT->SUMMARY; |
|
146 | - |
|
147 | - if (parse_url($iTipMessage->sender, PHP_URL_SCHEME) !== 'mailto') { |
|
148 | - return; |
|
149 | - } |
|
150 | - |
|
151 | - if (parse_url($iTipMessage->recipient, PHP_URL_SCHEME) !== 'mailto') { |
|
152 | - return; |
|
153 | - } |
|
154 | - |
|
155 | - // don't send out mails for events that already took place |
|
156 | - $lastOccurrence = $this->getLastOccurrence($iTipMessage->message); |
|
157 | - $currentTime = $this->timeFactory->getTime(); |
|
158 | - if ($lastOccurrence < $currentTime) { |
|
159 | - return; |
|
160 | - } |
|
161 | - |
|
162 | - // Strip off mailto: |
|
163 | - $sender = substr($iTipMessage->sender, 7); |
|
164 | - $recipient = substr($iTipMessage->recipient, 7); |
|
165 | - |
|
166 | - $senderName = $iTipMessage->senderName ?: null; |
|
167 | - $recipientName = $iTipMessage->recipientName ?: null; |
|
168 | - |
|
169 | - /** @var VEvent $vevent */ |
|
170 | - $vevent = $iTipMessage->message->VEVENT; |
|
171 | - |
|
172 | - $attendee = $this->getCurrentAttendee($iTipMessage); |
|
173 | - $defaultLang = $this->config->getUserValue($this->userId, 'core', 'lang', $this->l10nFactory->findLanguage()); |
|
174 | - $lang = $this->getAttendeeLangOrDefault($defaultLang, $attendee); |
|
175 | - $l10n = $this->l10nFactory->get('dav', $lang); |
|
176 | - |
|
177 | - $meetingAttendeeName = $recipientName ?: $recipient; |
|
178 | - $meetingInviteeName = $senderName ?: $sender; |
|
179 | - |
|
180 | - $meetingTitle = $vevent->SUMMARY; |
|
181 | - $meetingDescription = $vevent->DESCRIPTION; |
|
182 | - |
|
183 | - $start = $vevent->DTSTART; |
|
184 | - if (isset($vevent->DTEND)) { |
|
185 | - $end = $vevent->DTEND; |
|
186 | - } elseif (isset($vevent->DURATION)) { |
|
187 | - $isFloating = $vevent->DTSTART->isFloating(); |
|
188 | - $end = clone $vevent->DTSTART; |
|
189 | - $endDateTime = $end->getDateTime(); |
|
190 | - $endDateTime = $endDateTime->add(DateTimeParser::parse($vevent->DURATION->getValue())); |
|
191 | - $end->setDateTime($endDateTime, $isFloating); |
|
192 | - } elseif (!$vevent->DTSTART->hasTime()) { |
|
193 | - $isFloating = $vevent->DTSTART->isFloating(); |
|
194 | - $end = clone $vevent->DTSTART; |
|
195 | - $endDateTime = $end->getDateTime(); |
|
196 | - $endDateTime = $endDateTime->modify('+1 day'); |
|
197 | - $end->setDateTime($endDateTime, $isFloating); |
|
198 | - } else { |
|
199 | - $end = clone $vevent->DTSTART; |
|
200 | - } |
|
201 | - |
|
202 | - $meetingWhen = $this->generateWhenString($l10n, $start, $end); |
|
203 | - |
|
204 | - $meetingUrl = $vevent->URL; |
|
205 | - $meetingLocation = $vevent->LOCATION; |
|
206 | - |
|
207 | - $defaultVal = '--'; |
|
208 | - |
|
209 | - $method = self::METHOD_REQUEST; |
|
210 | - switch (strtolower($iTipMessage->method)) { |
|
211 | - case self::METHOD_REPLY: |
|
212 | - $method = self::METHOD_REPLY; |
|
213 | - break; |
|
214 | - case self::METHOD_CANCEL: |
|
215 | - $method = self::METHOD_CANCEL; |
|
216 | - break; |
|
217 | - } |
|
218 | - |
|
219 | - $data = array( |
|
220 | - 'attendee_name' => (string)$meetingAttendeeName ?: $defaultVal, |
|
221 | - 'invitee_name' => (string)$meetingInviteeName ?: $defaultVal, |
|
222 | - 'meeting_title' => (string)$meetingTitle ?: $defaultVal, |
|
223 | - 'meeting_description' => (string)$meetingDescription ?: $defaultVal, |
|
224 | - 'meeting_url' => (string)$meetingUrl ?: $defaultVal, |
|
225 | - ); |
|
226 | - |
|
227 | - $fromEMail = \OCP\Util::getDefaultEmailAddress('invitations-noreply'); |
|
228 | - $fromName = $l10n->t('%1$s via %2$s', [$senderName, $this->defaults->getName()]); |
|
229 | - |
|
230 | - $message = $this->mailer->createMessage() |
|
231 | - ->setFrom([$fromEMail => $fromName]) |
|
232 | - ->setReplyTo([$sender => $senderName]) |
|
233 | - ->setTo([$recipient => $recipientName]); |
|
234 | - |
|
235 | - $template = $this->mailer->createEMailTemplate('dav.calendarInvite.' . $method, $data); |
|
236 | - $template->addHeader(); |
|
237 | - |
|
238 | - $this->addSubjectAndHeading($template, $l10n, $method, $summary, |
|
239 | - $meetingAttendeeName, $meetingInviteeName); |
|
240 | - $this->addBulletList($template, $l10n, $meetingWhen, $meetingLocation, |
|
241 | - $meetingDescription, $meetingUrl); |
|
242 | - $this->addResponseButtons($template, $l10n, $iTipMessage, $lastOccurrence); |
|
243 | - |
|
244 | - $template->addFooter(); |
|
245 | - $message->useTemplate($template); |
|
246 | - |
|
247 | - $attachment = $this->mailer->createAttachment( |
|
248 | - $iTipMessage->message->serialize(), |
|
249 | - 'event.ics',// TODO(leon): Make file name unique, e.g. add event id |
|
250 | - 'text/calendar; method=' . $iTipMessage->method |
|
251 | - ); |
|
252 | - $message->attach($attachment); |
|
253 | - |
|
254 | - try { |
|
255 | - $failed = $this->mailer->send($message); |
|
256 | - $iTipMessage->scheduleStatus = '1.1; Scheduling message is sent via iMip'; |
|
257 | - if ($failed) { |
|
258 | - $this->logger->error('Unable to deliver message to {failed}', ['app' => 'dav', 'failed' => implode(', ', $failed)]); |
|
259 | - $iTipMessage->scheduleStatus = '5.0; EMail delivery failed'; |
|
260 | - } |
|
261 | - } catch(\Exception $ex) { |
|
262 | - $this->logger->logException($ex, ['app' => 'dav']); |
|
263 | - $iTipMessage->scheduleStatus = '5.0; EMail delivery failed'; |
|
264 | - } |
|
265 | - } |
|
266 | - |
|
267 | - /** |
|
268 | - * check if event took place in the past already |
|
269 | - * @param VCalendar $vObject |
|
270 | - * @return int |
|
271 | - */ |
|
272 | - private function getLastOccurrence(VCalendar $vObject) { |
|
273 | - /** @var VEvent $component */ |
|
274 | - $component = $vObject->VEVENT; |
|
275 | - |
|
276 | - $firstOccurrence = $component->DTSTART->getDateTime()->getTimeStamp(); |
|
277 | - // Finding the last occurrence is a bit harder |
|
278 | - if (!isset($component->RRULE)) { |
|
279 | - if (isset($component->DTEND)) { |
|
280 | - $lastOccurrence = $component->DTEND->getDateTime()->getTimeStamp(); |
|
281 | - } elseif (isset($component->DURATION)) { |
|
282 | - /** @var \DateTime $endDate */ |
|
283 | - $endDate = clone $component->DTSTART->getDateTime(); |
|
284 | - // $component->DTEND->getDateTime() returns DateTimeImmutable |
|
285 | - $endDate = $endDate->add(DateTimeParser::parse($component->DURATION->getValue())); |
|
286 | - $lastOccurrence = $endDate->getTimestamp(); |
|
287 | - } elseif (!$component->DTSTART->hasTime()) { |
|
288 | - /** @var \DateTime $endDate */ |
|
289 | - $endDate = clone $component->DTSTART->getDateTime(); |
|
290 | - // $component->DTSTART->getDateTime() returns DateTimeImmutable |
|
291 | - $endDate = $endDate->modify('+1 day'); |
|
292 | - $lastOccurrence = $endDate->getTimestamp(); |
|
293 | - } else { |
|
294 | - $lastOccurrence = $firstOccurrence; |
|
295 | - } |
|
296 | - } else { |
|
297 | - $it = new EventIterator($vObject, (string)$component->UID); |
|
298 | - $maxDate = new \DateTime(self::MAX_DATE); |
|
299 | - if ($it->isInfinite()) { |
|
300 | - $lastOccurrence = $maxDate->getTimestamp(); |
|
301 | - } else { |
|
302 | - $end = $it->getDtEnd(); |
|
303 | - while($it->valid() && $end < $maxDate) { |
|
304 | - $end = $it->getDtEnd(); |
|
305 | - $it->next(); |
|
306 | - |
|
307 | - } |
|
308 | - $lastOccurrence = $end->getTimestamp(); |
|
309 | - } |
|
310 | - } |
|
311 | - |
|
312 | - return $lastOccurrence; |
|
313 | - } |
|
314 | - |
|
315 | - |
|
316 | - /** |
|
317 | - * @param Message $iTipMessage |
|
318 | - * @return null|Property |
|
319 | - */ |
|
320 | - private function getCurrentAttendee(Message $iTipMessage) { |
|
321 | - /** @var VEvent $vevent */ |
|
322 | - $vevent = $iTipMessage->message->VEVENT; |
|
323 | - $attendees = $vevent->select('ATTENDEE'); |
|
324 | - foreach ($attendees as $attendee) { |
|
325 | - /** @var Property $attendee */ |
|
326 | - if (strcasecmp($attendee->getValue(), $iTipMessage->recipient) === 0) { |
|
327 | - return $attendee; |
|
328 | - } |
|
329 | - } |
|
330 | - return null; |
|
331 | - } |
|
332 | - |
|
333 | - /** |
|
334 | - * @param string $default |
|
335 | - * @param Property|null $attendee |
|
336 | - * @return string |
|
337 | - */ |
|
338 | - private function getAttendeeLangOrDefault($default, Property $attendee = null) { |
|
339 | - if ($attendee !== null) { |
|
340 | - $lang = $attendee->offsetGet('LANGUAGE'); |
|
341 | - if ($lang instanceof Parameter) { |
|
342 | - return $lang->getValue(); |
|
343 | - } |
|
344 | - } |
|
345 | - return $default; |
|
346 | - } |
|
347 | - |
|
348 | - /** |
|
349 | - * @param IL10N $l10n |
|
350 | - * @param Property $dtstart |
|
351 | - * @param Property $dtend |
|
352 | - */ |
|
353 | - private function generateWhenString(IL10N $l10n, Property $dtstart, Property $dtend) { |
|
354 | - $isAllDay = $dtstart instanceof Property\ICalendar\Date; |
|
355 | - |
|
356 | - /** @var Property\ICalendar\Date | Property\ICalendar\DateTime $dtstart */ |
|
357 | - /** @var Property\ICalendar\Date | Property\ICalendar\DateTime $dtend */ |
|
358 | - /** @var \DateTimeImmutable $dtstartDt */ |
|
359 | - $dtstartDt = $dtstart->getDateTime(); |
|
360 | - /** @var \DateTimeImmutable $dtendDt */ |
|
361 | - $dtendDt = $dtend->getDateTime(); |
|
362 | - |
|
363 | - $diff = $dtstartDt->diff($dtendDt); |
|
364 | - |
|
365 | - $dtstartDt = new \DateTime($dtstartDt->format(\DateTime::ATOM)); |
|
366 | - $dtendDt = new \DateTime($dtendDt->format(\DateTime::ATOM)); |
|
367 | - |
|
368 | - if ($isAllDay) { |
|
369 | - // One day event |
|
370 | - if ($diff->days === 1) { |
|
371 | - return $l10n->l('date', $dtstartDt, ['width' => 'medium']); |
|
372 | - } |
|
373 | - |
|
374 | - //event that spans over multiple days |
|
375 | - $localeStart = $l10n->l('date', $dtstartDt, ['width' => 'medium']); |
|
376 | - $localeEnd = $l10n->l('date', $dtendDt, ['width' => 'medium']); |
|
377 | - |
|
378 | - return $localeStart . ' - ' . $localeEnd; |
|
379 | - } |
|
380 | - |
|
381 | - /** @var Property\ICalendar\DateTime $dtstart */ |
|
382 | - /** @var Property\ICalendar\DateTime $dtend */ |
|
383 | - $isFloating = $dtstart->isFloating(); |
|
384 | - $startTimezone = $endTimezone = null; |
|
385 | - if (!$isFloating) { |
|
386 | - $prop = $dtstart->offsetGet('TZID'); |
|
387 | - if ($prop instanceof Parameter) { |
|
388 | - $startTimezone = $prop->getValue(); |
|
389 | - } |
|
390 | - |
|
391 | - $prop = $dtend->offsetGet('TZID'); |
|
392 | - if ($prop instanceof Parameter) { |
|
393 | - $endTimezone = $prop->getValue(); |
|
394 | - } |
|
395 | - } |
|
396 | - |
|
397 | - $localeStart = $l10n->l('weekdayName', $dtstartDt, ['width' => 'abbreviated']) . ', ' . |
|
398 | - $l10n->l('datetime', $dtstartDt, ['width' => 'medium|short']); |
|
399 | - |
|
400 | - // always show full date with timezone if timezones are different |
|
401 | - if ($startTimezone !== $endTimezone) { |
|
402 | - $localeEnd = $l10n->l('datetime', $dtendDt, ['width' => 'medium|short']); |
|
403 | - |
|
404 | - return $localeStart . ' (' . $startTimezone . ') - ' . |
|
405 | - $localeEnd . ' (' . $endTimezone . ')'; |
|
406 | - } |
|
407 | - |
|
408 | - // show only end time if date is the same |
|
409 | - if ($this->isDayEqual($dtstartDt, $dtendDt)) { |
|
410 | - $localeEnd = $l10n->l('time', $dtendDt, ['width' => 'short']); |
|
411 | - } else { |
|
412 | - $localeEnd = $l10n->l('weekdayName', $dtendDt, ['width' => 'abbreviated']) . ', ' . |
|
413 | - $l10n->l('datetime', $dtendDt, ['width' => 'medium|short']); |
|
414 | - } |
|
415 | - |
|
416 | - return $localeStart . ' - ' . $localeEnd . ' (' . $startTimezone . ')'; |
|
417 | - } |
|
418 | - |
|
419 | - /** |
|
420 | - * @param \DateTime $dtStart |
|
421 | - * @param \DateTime $dtEnd |
|
422 | - * @return bool |
|
423 | - */ |
|
424 | - private function isDayEqual(\DateTime $dtStart, \DateTime $dtEnd) { |
|
425 | - return $dtStart->format('Y-m-d') === $dtEnd->format('Y-m-d'); |
|
426 | - } |
|
427 | - |
|
428 | - /** |
|
429 | - * @param IEMailTemplate $template |
|
430 | - * @param IL10N $l10n |
|
431 | - * @param string $method |
|
432 | - * @param string $summary |
|
433 | - * @param string $attendeeName |
|
434 | - * @param string $inviteeName |
|
435 | - */ |
|
436 | - private function addSubjectAndHeading(IEMailTemplate $template, IL10N $l10n, |
|
437 | - $method, $summary, $attendeeName, $inviteeName) { |
|
438 | - if ($method === self::METHOD_CANCEL) { |
|
439 | - $template->setSubject('Cancelled: ' . $summary); |
|
440 | - $template->addHeading($l10n->t('Invitation canceled'), $l10n->t('Hello %s,', [$attendeeName])); |
|
441 | - $template->addBodyText($l10n->t('The meeting »%1$s« with %2$s was canceled.', [$summary, $inviteeName])); |
|
442 | - } else if ($method === self::METHOD_REPLY) { |
|
443 | - $template->setSubject('Re: ' . $summary); |
|
444 | - $template->addHeading($l10n->t('Invitation updated'), $l10n->t('Hello %s,', [$attendeeName])); |
|
445 | - $template->addBodyText($l10n->t('The meeting »%1$s« with %2$s was updated.', [$summary, $inviteeName])); |
|
446 | - } else { |
|
447 | - $template->setSubject('Invitation: ' . $summary); |
|
448 | - $template->addHeading($l10n->t('%1$s invited you to »%2$s«', [$inviteeName, $summary]), $l10n->t('Hello %s,', [$attendeeName])); |
|
449 | - } |
|
450 | - |
|
451 | - } |
|
452 | - |
|
453 | - /** |
|
454 | - * @param IEMailTemplate $template |
|
455 | - * @param IL10N $l10n |
|
456 | - * @param string $time |
|
457 | - * @param string $location |
|
458 | - * @param string $description |
|
459 | - * @param string $url |
|
460 | - */ |
|
461 | - private function addBulletList(IEMailTemplate $template, IL10N $l10n, $time, $location, $description, $url) { |
|
462 | - $template->addBodyListItem($time, $l10n->t('When:'), |
|
463 | - $this->getAbsoluteImagePath('filetypes/text-calendar.svg')); |
|
464 | - |
|
465 | - if ($location) { |
|
466 | - $template->addBodyListItem($location, $l10n->t('Where:'), |
|
467 | - $this->getAbsoluteImagePath('filetypes/location.svg')); |
|
468 | - } |
|
469 | - if ($description) { |
|
470 | - $template->addBodyListItem((string)$description, $l10n->t('Description:'), |
|
471 | - $this->getAbsoluteImagePath('filetypes/text.svg')); |
|
472 | - } |
|
473 | - if ($url) { |
|
474 | - $template->addBodyListItem((string)$url, $l10n->t('Link:'), |
|
475 | - $this->getAbsoluteImagePath('filetypes/link.svg')); |
|
476 | - } |
|
477 | - } |
|
478 | - |
|
479 | - /** |
|
480 | - * @param IEMailTemplate $template |
|
481 | - * @param IL10N $l10n |
|
482 | - * @param Message $iTipMessage |
|
483 | - * @param int $lastOccurrence |
|
484 | - */ |
|
485 | - private function addResponseButtons(IEMailTemplate $template, IL10N $l10n, |
|
486 | - Message $iTipMessage, $lastOccurrence) { |
|
487 | - $token = $this->createInvitationToken($iTipMessage, $lastOccurrence); |
|
488 | - |
|
489 | - $template->addBodyButtonGroup( |
|
490 | - $l10n->t('Accept'), |
|
491 | - $this->urlGenerator->linkToRouteAbsolute('dav.invitation_response.accept', [ |
|
492 | - 'token' => $token, |
|
493 | - ]), |
|
494 | - $l10n->t('Decline'), |
|
495 | - $this->urlGenerator->linkToRouteAbsolute('dav.invitation_response.decline', [ |
|
496 | - 'token' => $token, |
|
497 | - ]) |
|
498 | - ); |
|
499 | - |
|
500 | - $moreOptionsURL = $this->urlGenerator->linkToRouteAbsolute('dav.invitation_response.options', [ |
|
501 | - 'token' => $token, |
|
502 | - ]); |
|
503 | - $html = vsprintf('<small><a href="%s">%s</a></small>', [ |
|
504 | - $moreOptionsURL, $l10n->t('More options …') |
|
505 | - ]); |
|
506 | - $text = $l10n->t('More options at %s', [$moreOptionsURL]); |
|
63 | + /** @var string */ |
|
64 | + private $userId; |
|
65 | + |
|
66 | + /** @var IConfig */ |
|
67 | + private $config; |
|
68 | + |
|
69 | + /** @var IMailer */ |
|
70 | + private $mailer; |
|
71 | + |
|
72 | + /** @var ILogger */ |
|
73 | + private $logger; |
|
74 | + |
|
75 | + /** @var ITimeFactory */ |
|
76 | + private $timeFactory; |
|
77 | + |
|
78 | + /** @var L10NFactory */ |
|
79 | + private $l10nFactory; |
|
80 | + |
|
81 | + /** @var IURLGenerator */ |
|
82 | + private $urlGenerator; |
|
83 | + |
|
84 | + /** @var ISecureRandom */ |
|
85 | + private $random; |
|
86 | + |
|
87 | + /** @var IDBConnection */ |
|
88 | + private $db; |
|
89 | + |
|
90 | + /** @var Defaults */ |
|
91 | + private $defaults; |
|
92 | + |
|
93 | + const MAX_DATE = '2038-01-01'; |
|
94 | + |
|
95 | + const METHOD_REQUEST = 'request'; |
|
96 | + const METHOD_REPLY = 'reply'; |
|
97 | + const METHOD_CANCEL = 'cancel'; |
|
98 | + |
|
99 | + /** |
|
100 | + * @param IConfig $config |
|
101 | + * @param IMailer $mailer |
|
102 | + * @param ILogger $logger |
|
103 | + * @param ITimeFactory $timeFactory |
|
104 | + * @param L10NFactory $l10nFactory |
|
105 | + * @param IUrlGenerator $urlGenerator |
|
106 | + * @param Defaults $defaults |
|
107 | + * @param ISecureRandom $random |
|
108 | + * @param IDBConnection $db |
|
109 | + * @param string $userId |
|
110 | + */ |
|
111 | + public function __construct(IConfig $config, IMailer $mailer, ILogger $logger, |
|
112 | + ITimeFactory $timeFactory, L10NFactory $l10nFactory, |
|
113 | + IURLGenerator $urlGenerator, Defaults $defaults, |
|
114 | + ISecureRandom $random, IDBConnection $db, $userId) { |
|
115 | + parent::__construct(''); |
|
116 | + $this->userId = $userId; |
|
117 | + $this->config = $config; |
|
118 | + $this->mailer = $mailer; |
|
119 | + $this->logger = $logger; |
|
120 | + $this->timeFactory = $timeFactory; |
|
121 | + $this->l10nFactory = $l10nFactory; |
|
122 | + $this->urlGenerator = $urlGenerator; |
|
123 | + $this->random = $random; |
|
124 | + $this->db = $db; |
|
125 | + $this->defaults = $defaults; |
|
126 | + } |
|
127 | + |
|
128 | + /** |
|
129 | + * Event handler for the 'schedule' event. |
|
130 | + * |
|
131 | + * @param Message $iTipMessage |
|
132 | + * @return void |
|
133 | + */ |
|
134 | + public function schedule(Message $iTipMessage) { |
|
135 | + |
|
136 | + // Not sending any emails if the system considers the update |
|
137 | + // insignificant. |
|
138 | + if (!$iTipMessage->significantChange) { |
|
139 | + if (!$iTipMessage->scheduleStatus) { |
|
140 | + $iTipMessage->scheduleStatus = '1.0;We got the message, but it\'s not significant enough to warrant an email'; |
|
141 | + } |
|
142 | + return; |
|
143 | + } |
|
144 | + |
|
145 | + $summary = $iTipMessage->message->VEVENT->SUMMARY; |
|
146 | + |
|
147 | + if (parse_url($iTipMessage->sender, PHP_URL_SCHEME) !== 'mailto') { |
|
148 | + return; |
|
149 | + } |
|
150 | + |
|
151 | + if (parse_url($iTipMessage->recipient, PHP_URL_SCHEME) !== 'mailto') { |
|
152 | + return; |
|
153 | + } |
|
154 | + |
|
155 | + // don't send out mails for events that already took place |
|
156 | + $lastOccurrence = $this->getLastOccurrence($iTipMessage->message); |
|
157 | + $currentTime = $this->timeFactory->getTime(); |
|
158 | + if ($lastOccurrence < $currentTime) { |
|
159 | + return; |
|
160 | + } |
|
161 | + |
|
162 | + // Strip off mailto: |
|
163 | + $sender = substr($iTipMessage->sender, 7); |
|
164 | + $recipient = substr($iTipMessage->recipient, 7); |
|
165 | + |
|
166 | + $senderName = $iTipMessage->senderName ?: null; |
|
167 | + $recipientName = $iTipMessage->recipientName ?: null; |
|
168 | + |
|
169 | + /** @var VEvent $vevent */ |
|
170 | + $vevent = $iTipMessage->message->VEVENT; |
|
171 | + |
|
172 | + $attendee = $this->getCurrentAttendee($iTipMessage); |
|
173 | + $defaultLang = $this->config->getUserValue($this->userId, 'core', 'lang', $this->l10nFactory->findLanguage()); |
|
174 | + $lang = $this->getAttendeeLangOrDefault($defaultLang, $attendee); |
|
175 | + $l10n = $this->l10nFactory->get('dav', $lang); |
|
176 | + |
|
177 | + $meetingAttendeeName = $recipientName ?: $recipient; |
|
178 | + $meetingInviteeName = $senderName ?: $sender; |
|
179 | + |
|
180 | + $meetingTitle = $vevent->SUMMARY; |
|
181 | + $meetingDescription = $vevent->DESCRIPTION; |
|
182 | + |
|
183 | + $start = $vevent->DTSTART; |
|
184 | + if (isset($vevent->DTEND)) { |
|
185 | + $end = $vevent->DTEND; |
|
186 | + } elseif (isset($vevent->DURATION)) { |
|
187 | + $isFloating = $vevent->DTSTART->isFloating(); |
|
188 | + $end = clone $vevent->DTSTART; |
|
189 | + $endDateTime = $end->getDateTime(); |
|
190 | + $endDateTime = $endDateTime->add(DateTimeParser::parse($vevent->DURATION->getValue())); |
|
191 | + $end->setDateTime($endDateTime, $isFloating); |
|
192 | + } elseif (!$vevent->DTSTART->hasTime()) { |
|
193 | + $isFloating = $vevent->DTSTART->isFloating(); |
|
194 | + $end = clone $vevent->DTSTART; |
|
195 | + $endDateTime = $end->getDateTime(); |
|
196 | + $endDateTime = $endDateTime->modify('+1 day'); |
|
197 | + $end->setDateTime($endDateTime, $isFloating); |
|
198 | + } else { |
|
199 | + $end = clone $vevent->DTSTART; |
|
200 | + } |
|
201 | + |
|
202 | + $meetingWhen = $this->generateWhenString($l10n, $start, $end); |
|
203 | + |
|
204 | + $meetingUrl = $vevent->URL; |
|
205 | + $meetingLocation = $vevent->LOCATION; |
|
206 | + |
|
207 | + $defaultVal = '--'; |
|
208 | + |
|
209 | + $method = self::METHOD_REQUEST; |
|
210 | + switch (strtolower($iTipMessage->method)) { |
|
211 | + case self::METHOD_REPLY: |
|
212 | + $method = self::METHOD_REPLY; |
|
213 | + break; |
|
214 | + case self::METHOD_CANCEL: |
|
215 | + $method = self::METHOD_CANCEL; |
|
216 | + break; |
|
217 | + } |
|
218 | + |
|
219 | + $data = array( |
|
220 | + 'attendee_name' => (string)$meetingAttendeeName ?: $defaultVal, |
|
221 | + 'invitee_name' => (string)$meetingInviteeName ?: $defaultVal, |
|
222 | + 'meeting_title' => (string)$meetingTitle ?: $defaultVal, |
|
223 | + 'meeting_description' => (string)$meetingDescription ?: $defaultVal, |
|
224 | + 'meeting_url' => (string)$meetingUrl ?: $defaultVal, |
|
225 | + ); |
|
226 | + |
|
227 | + $fromEMail = \OCP\Util::getDefaultEmailAddress('invitations-noreply'); |
|
228 | + $fromName = $l10n->t('%1$s via %2$s', [$senderName, $this->defaults->getName()]); |
|
229 | + |
|
230 | + $message = $this->mailer->createMessage() |
|
231 | + ->setFrom([$fromEMail => $fromName]) |
|
232 | + ->setReplyTo([$sender => $senderName]) |
|
233 | + ->setTo([$recipient => $recipientName]); |
|
234 | + |
|
235 | + $template = $this->mailer->createEMailTemplate('dav.calendarInvite.' . $method, $data); |
|
236 | + $template->addHeader(); |
|
237 | + |
|
238 | + $this->addSubjectAndHeading($template, $l10n, $method, $summary, |
|
239 | + $meetingAttendeeName, $meetingInviteeName); |
|
240 | + $this->addBulletList($template, $l10n, $meetingWhen, $meetingLocation, |
|
241 | + $meetingDescription, $meetingUrl); |
|
242 | + $this->addResponseButtons($template, $l10n, $iTipMessage, $lastOccurrence); |
|
243 | + |
|
244 | + $template->addFooter(); |
|
245 | + $message->useTemplate($template); |
|
246 | + |
|
247 | + $attachment = $this->mailer->createAttachment( |
|
248 | + $iTipMessage->message->serialize(), |
|
249 | + 'event.ics',// TODO(leon): Make file name unique, e.g. add event id |
|
250 | + 'text/calendar; method=' . $iTipMessage->method |
|
251 | + ); |
|
252 | + $message->attach($attachment); |
|
253 | + |
|
254 | + try { |
|
255 | + $failed = $this->mailer->send($message); |
|
256 | + $iTipMessage->scheduleStatus = '1.1; Scheduling message is sent via iMip'; |
|
257 | + if ($failed) { |
|
258 | + $this->logger->error('Unable to deliver message to {failed}', ['app' => 'dav', 'failed' => implode(', ', $failed)]); |
|
259 | + $iTipMessage->scheduleStatus = '5.0; EMail delivery failed'; |
|
260 | + } |
|
261 | + } catch(\Exception $ex) { |
|
262 | + $this->logger->logException($ex, ['app' => 'dav']); |
|
263 | + $iTipMessage->scheduleStatus = '5.0; EMail delivery failed'; |
|
264 | + } |
|
265 | + } |
|
266 | + |
|
267 | + /** |
|
268 | + * check if event took place in the past already |
|
269 | + * @param VCalendar $vObject |
|
270 | + * @return int |
|
271 | + */ |
|
272 | + private function getLastOccurrence(VCalendar $vObject) { |
|
273 | + /** @var VEvent $component */ |
|
274 | + $component = $vObject->VEVENT; |
|
275 | + |
|
276 | + $firstOccurrence = $component->DTSTART->getDateTime()->getTimeStamp(); |
|
277 | + // Finding the last occurrence is a bit harder |
|
278 | + if (!isset($component->RRULE)) { |
|
279 | + if (isset($component->DTEND)) { |
|
280 | + $lastOccurrence = $component->DTEND->getDateTime()->getTimeStamp(); |
|
281 | + } elseif (isset($component->DURATION)) { |
|
282 | + /** @var \DateTime $endDate */ |
|
283 | + $endDate = clone $component->DTSTART->getDateTime(); |
|
284 | + // $component->DTEND->getDateTime() returns DateTimeImmutable |
|
285 | + $endDate = $endDate->add(DateTimeParser::parse($component->DURATION->getValue())); |
|
286 | + $lastOccurrence = $endDate->getTimestamp(); |
|
287 | + } elseif (!$component->DTSTART->hasTime()) { |
|
288 | + /** @var \DateTime $endDate */ |
|
289 | + $endDate = clone $component->DTSTART->getDateTime(); |
|
290 | + // $component->DTSTART->getDateTime() returns DateTimeImmutable |
|
291 | + $endDate = $endDate->modify('+1 day'); |
|
292 | + $lastOccurrence = $endDate->getTimestamp(); |
|
293 | + } else { |
|
294 | + $lastOccurrence = $firstOccurrence; |
|
295 | + } |
|
296 | + } else { |
|
297 | + $it = new EventIterator($vObject, (string)$component->UID); |
|
298 | + $maxDate = new \DateTime(self::MAX_DATE); |
|
299 | + if ($it->isInfinite()) { |
|
300 | + $lastOccurrence = $maxDate->getTimestamp(); |
|
301 | + } else { |
|
302 | + $end = $it->getDtEnd(); |
|
303 | + while($it->valid() && $end < $maxDate) { |
|
304 | + $end = $it->getDtEnd(); |
|
305 | + $it->next(); |
|
306 | + |
|
307 | + } |
|
308 | + $lastOccurrence = $end->getTimestamp(); |
|
309 | + } |
|
310 | + } |
|
311 | + |
|
312 | + return $lastOccurrence; |
|
313 | + } |
|
314 | + |
|
315 | + |
|
316 | + /** |
|
317 | + * @param Message $iTipMessage |
|
318 | + * @return null|Property |
|
319 | + */ |
|
320 | + private function getCurrentAttendee(Message $iTipMessage) { |
|
321 | + /** @var VEvent $vevent */ |
|
322 | + $vevent = $iTipMessage->message->VEVENT; |
|
323 | + $attendees = $vevent->select('ATTENDEE'); |
|
324 | + foreach ($attendees as $attendee) { |
|
325 | + /** @var Property $attendee */ |
|
326 | + if (strcasecmp($attendee->getValue(), $iTipMessage->recipient) === 0) { |
|
327 | + return $attendee; |
|
328 | + } |
|
329 | + } |
|
330 | + return null; |
|
331 | + } |
|
332 | + |
|
333 | + /** |
|
334 | + * @param string $default |
|
335 | + * @param Property|null $attendee |
|
336 | + * @return string |
|
337 | + */ |
|
338 | + private function getAttendeeLangOrDefault($default, Property $attendee = null) { |
|
339 | + if ($attendee !== null) { |
|
340 | + $lang = $attendee->offsetGet('LANGUAGE'); |
|
341 | + if ($lang instanceof Parameter) { |
|
342 | + return $lang->getValue(); |
|
343 | + } |
|
344 | + } |
|
345 | + return $default; |
|
346 | + } |
|
347 | + |
|
348 | + /** |
|
349 | + * @param IL10N $l10n |
|
350 | + * @param Property $dtstart |
|
351 | + * @param Property $dtend |
|
352 | + */ |
|
353 | + private function generateWhenString(IL10N $l10n, Property $dtstart, Property $dtend) { |
|
354 | + $isAllDay = $dtstart instanceof Property\ICalendar\Date; |
|
355 | + |
|
356 | + /** @var Property\ICalendar\Date | Property\ICalendar\DateTime $dtstart */ |
|
357 | + /** @var Property\ICalendar\Date | Property\ICalendar\DateTime $dtend */ |
|
358 | + /** @var \DateTimeImmutable $dtstartDt */ |
|
359 | + $dtstartDt = $dtstart->getDateTime(); |
|
360 | + /** @var \DateTimeImmutable $dtendDt */ |
|
361 | + $dtendDt = $dtend->getDateTime(); |
|
362 | + |
|
363 | + $diff = $dtstartDt->diff($dtendDt); |
|
364 | + |
|
365 | + $dtstartDt = new \DateTime($dtstartDt->format(\DateTime::ATOM)); |
|
366 | + $dtendDt = new \DateTime($dtendDt->format(\DateTime::ATOM)); |
|
367 | + |
|
368 | + if ($isAllDay) { |
|
369 | + // One day event |
|
370 | + if ($diff->days === 1) { |
|
371 | + return $l10n->l('date', $dtstartDt, ['width' => 'medium']); |
|
372 | + } |
|
373 | + |
|
374 | + //event that spans over multiple days |
|
375 | + $localeStart = $l10n->l('date', $dtstartDt, ['width' => 'medium']); |
|
376 | + $localeEnd = $l10n->l('date', $dtendDt, ['width' => 'medium']); |
|
377 | + |
|
378 | + return $localeStart . ' - ' . $localeEnd; |
|
379 | + } |
|
380 | + |
|
381 | + /** @var Property\ICalendar\DateTime $dtstart */ |
|
382 | + /** @var Property\ICalendar\DateTime $dtend */ |
|
383 | + $isFloating = $dtstart->isFloating(); |
|
384 | + $startTimezone = $endTimezone = null; |
|
385 | + if (!$isFloating) { |
|
386 | + $prop = $dtstart->offsetGet('TZID'); |
|
387 | + if ($prop instanceof Parameter) { |
|
388 | + $startTimezone = $prop->getValue(); |
|
389 | + } |
|
390 | + |
|
391 | + $prop = $dtend->offsetGet('TZID'); |
|
392 | + if ($prop instanceof Parameter) { |
|
393 | + $endTimezone = $prop->getValue(); |
|
394 | + } |
|
395 | + } |
|
396 | + |
|
397 | + $localeStart = $l10n->l('weekdayName', $dtstartDt, ['width' => 'abbreviated']) . ', ' . |
|
398 | + $l10n->l('datetime', $dtstartDt, ['width' => 'medium|short']); |
|
399 | + |
|
400 | + // always show full date with timezone if timezones are different |
|
401 | + if ($startTimezone !== $endTimezone) { |
|
402 | + $localeEnd = $l10n->l('datetime', $dtendDt, ['width' => 'medium|short']); |
|
403 | + |
|
404 | + return $localeStart . ' (' . $startTimezone . ') - ' . |
|
405 | + $localeEnd . ' (' . $endTimezone . ')'; |
|
406 | + } |
|
407 | + |
|
408 | + // show only end time if date is the same |
|
409 | + if ($this->isDayEqual($dtstartDt, $dtendDt)) { |
|
410 | + $localeEnd = $l10n->l('time', $dtendDt, ['width' => 'short']); |
|
411 | + } else { |
|
412 | + $localeEnd = $l10n->l('weekdayName', $dtendDt, ['width' => 'abbreviated']) . ', ' . |
|
413 | + $l10n->l('datetime', $dtendDt, ['width' => 'medium|short']); |
|
414 | + } |
|
415 | + |
|
416 | + return $localeStart . ' - ' . $localeEnd . ' (' . $startTimezone . ')'; |
|
417 | + } |
|
418 | + |
|
419 | + /** |
|
420 | + * @param \DateTime $dtStart |
|
421 | + * @param \DateTime $dtEnd |
|
422 | + * @return bool |
|
423 | + */ |
|
424 | + private function isDayEqual(\DateTime $dtStart, \DateTime $dtEnd) { |
|
425 | + return $dtStart->format('Y-m-d') === $dtEnd->format('Y-m-d'); |
|
426 | + } |
|
427 | + |
|
428 | + /** |
|
429 | + * @param IEMailTemplate $template |
|
430 | + * @param IL10N $l10n |
|
431 | + * @param string $method |
|
432 | + * @param string $summary |
|
433 | + * @param string $attendeeName |
|
434 | + * @param string $inviteeName |
|
435 | + */ |
|
436 | + private function addSubjectAndHeading(IEMailTemplate $template, IL10N $l10n, |
|
437 | + $method, $summary, $attendeeName, $inviteeName) { |
|
438 | + if ($method === self::METHOD_CANCEL) { |
|
439 | + $template->setSubject('Cancelled: ' . $summary); |
|
440 | + $template->addHeading($l10n->t('Invitation canceled'), $l10n->t('Hello %s,', [$attendeeName])); |
|
441 | + $template->addBodyText($l10n->t('The meeting »%1$s« with %2$s was canceled.', [$summary, $inviteeName])); |
|
442 | + } else if ($method === self::METHOD_REPLY) { |
|
443 | + $template->setSubject('Re: ' . $summary); |
|
444 | + $template->addHeading($l10n->t('Invitation updated'), $l10n->t('Hello %s,', [$attendeeName])); |
|
445 | + $template->addBodyText($l10n->t('The meeting »%1$s« with %2$s was updated.', [$summary, $inviteeName])); |
|
446 | + } else { |
|
447 | + $template->setSubject('Invitation: ' . $summary); |
|
448 | + $template->addHeading($l10n->t('%1$s invited you to »%2$s«', [$inviteeName, $summary]), $l10n->t('Hello %s,', [$attendeeName])); |
|
449 | + } |
|
450 | + |
|
451 | + } |
|
452 | + |
|
453 | + /** |
|
454 | + * @param IEMailTemplate $template |
|
455 | + * @param IL10N $l10n |
|
456 | + * @param string $time |
|
457 | + * @param string $location |
|
458 | + * @param string $description |
|
459 | + * @param string $url |
|
460 | + */ |
|
461 | + private function addBulletList(IEMailTemplate $template, IL10N $l10n, $time, $location, $description, $url) { |
|
462 | + $template->addBodyListItem($time, $l10n->t('When:'), |
|
463 | + $this->getAbsoluteImagePath('filetypes/text-calendar.svg')); |
|
464 | + |
|
465 | + if ($location) { |
|
466 | + $template->addBodyListItem($location, $l10n->t('Where:'), |
|
467 | + $this->getAbsoluteImagePath('filetypes/location.svg')); |
|
468 | + } |
|
469 | + if ($description) { |
|
470 | + $template->addBodyListItem((string)$description, $l10n->t('Description:'), |
|
471 | + $this->getAbsoluteImagePath('filetypes/text.svg')); |
|
472 | + } |
|
473 | + if ($url) { |
|
474 | + $template->addBodyListItem((string)$url, $l10n->t('Link:'), |
|
475 | + $this->getAbsoluteImagePath('filetypes/link.svg')); |
|
476 | + } |
|
477 | + } |
|
478 | + |
|
479 | + /** |
|
480 | + * @param IEMailTemplate $template |
|
481 | + * @param IL10N $l10n |
|
482 | + * @param Message $iTipMessage |
|
483 | + * @param int $lastOccurrence |
|
484 | + */ |
|
485 | + private function addResponseButtons(IEMailTemplate $template, IL10N $l10n, |
|
486 | + Message $iTipMessage, $lastOccurrence) { |
|
487 | + $token = $this->createInvitationToken($iTipMessage, $lastOccurrence); |
|
488 | + |
|
489 | + $template->addBodyButtonGroup( |
|
490 | + $l10n->t('Accept'), |
|
491 | + $this->urlGenerator->linkToRouteAbsolute('dav.invitation_response.accept', [ |
|
492 | + 'token' => $token, |
|
493 | + ]), |
|
494 | + $l10n->t('Decline'), |
|
495 | + $this->urlGenerator->linkToRouteAbsolute('dav.invitation_response.decline', [ |
|
496 | + 'token' => $token, |
|
497 | + ]) |
|
498 | + ); |
|
499 | + |
|
500 | + $moreOptionsURL = $this->urlGenerator->linkToRouteAbsolute('dav.invitation_response.options', [ |
|
501 | + 'token' => $token, |
|
502 | + ]); |
|
503 | + $html = vsprintf('<small><a href="%s">%s</a></small>', [ |
|
504 | + $moreOptionsURL, $l10n->t('More options …') |
|
505 | + ]); |
|
506 | + $text = $l10n->t('More options at %s', [$moreOptionsURL]); |
|
507 | 507 | |
508 | - $template->addBodyText($html, $text); |
|
509 | - } |
|
510 | - |
|
511 | - /** |
|
512 | - * @param string $path |
|
513 | - * @return string |
|
514 | - */ |
|
515 | - private function getAbsoluteImagePath($path) { |
|
516 | - return $this->urlGenerator->getAbsoluteURL( |
|
517 | - $this->urlGenerator->imagePath('core', $path) |
|
518 | - ); |
|
519 | - } |
|
520 | - |
|
521 | - /** |
|
522 | - * @param Message $iTipMessage |
|
523 | - * @param int $lastOccurrence |
|
524 | - * @return string |
|
525 | - */ |
|
526 | - private function createInvitationToken(Message $iTipMessage, $lastOccurrence):string { |
|
527 | - $token = $this->random->generate(60, ISecureRandom::CHAR_UPPER . ISecureRandom::CHAR_LOWER . ISecureRandom::CHAR_DIGITS); |
|
528 | - |
|
529 | - /** @var VEvent $vevent */ |
|
530 | - $vevent = $iTipMessage->message->VEVENT; |
|
531 | - $attendee = $iTipMessage->recipient; |
|
532 | - $organizer = $iTipMessage->sender; |
|
533 | - $sequence = $iTipMessage->sequence; |
|
534 | - $recurrenceId = isset($vevent->{'RECURRENCE-ID'}) ? |
|
535 | - $vevent->{'RECURRENCE-ID'}->serialize() : null; |
|
536 | - $uid = $vevent->{'UID'}; |
|
537 | - |
|
538 | - $query = $this->db->getQueryBuilder(); |
|
539 | - $query->insert('calendar_invitations') |
|
540 | - ->values([ |
|
541 | - 'token' => $query->createNamedParameter($token), |
|
542 | - 'attendee' => $query->createNamedParameter($attendee), |
|
543 | - 'organizer' => $query->createNamedParameter($organizer), |
|
544 | - 'sequence' => $query->createNamedParameter($sequence), |
|
545 | - 'recurrenceid' => $query->createNamedParameter($recurrenceId), |
|
546 | - 'expiration' => $query->createNamedParameter($lastOccurrence), |
|
547 | - 'uid' => $query->createNamedParameter($uid) |
|
548 | - ]) |
|
549 | - ->execute(); |
|
550 | - |
|
551 | - return $token; |
|
552 | - } |
|
508 | + $template->addBodyText($html, $text); |
|
509 | + } |
|
510 | + |
|
511 | + /** |
|
512 | + * @param string $path |
|
513 | + * @return string |
|
514 | + */ |
|
515 | + private function getAbsoluteImagePath($path) { |
|
516 | + return $this->urlGenerator->getAbsoluteURL( |
|
517 | + $this->urlGenerator->imagePath('core', $path) |
|
518 | + ); |
|
519 | + } |
|
520 | + |
|
521 | + /** |
|
522 | + * @param Message $iTipMessage |
|
523 | + * @param int $lastOccurrence |
|
524 | + * @return string |
|
525 | + */ |
|
526 | + private function createInvitationToken(Message $iTipMessage, $lastOccurrence):string { |
|
527 | + $token = $this->random->generate(60, ISecureRandom::CHAR_UPPER . ISecureRandom::CHAR_LOWER . ISecureRandom::CHAR_DIGITS); |
|
528 | + |
|
529 | + /** @var VEvent $vevent */ |
|
530 | + $vevent = $iTipMessage->message->VEVENT; |
|
531 | + $attendee = $iTipMessage->recipient; |
|
532 | + $organizer = $iTipMessage->sender; |
|
533 | + $sequence = $iTipMessage->sequence; |
|
534 | + $recurrenceId = isset($vevent->{'RECURRENCE-ID'}) ? |
|
535 | + $vevent->{'RECURRENCE-ID'}->serialize() : null; |
|
536 | + $uid = $vevent->{'UID'}; |
|
537 | + |
|
538 | + $query = $this->db->getQueryBuilder(); |
|
539 | + $query->insert('calendar_invitations') |
|
540 | + ->values([ |
|
541 | + 'token' => $query->createNamedParameter($token), |
|
542 | + 'attendee' => $query->createNamedParameter($attendee), |
|
543 | + 'organizer' => $query->createNamedParameter($organizer), |
|
544 | + 'sequence' => $query->createNamedParameter($sequence), |
|
545 | + 'recurrenceid' => $query->createNamedParameter($recurrenceId), |
|
546 | + 'expiration' => $query->createNamedParameter($lastOccurrence), |
|
547 | + 'uid' => $query->createNamedParameter($uid) |
|
548 | + ]) |
|
549 | + ->execute(); |
|
550 | + |
|
551 | + return $token; |
|
552 | + } |
|
553 | 553 | } |
@@ -217,11 +217,11 @@ discard block |
||
217 | 217 | } |
218 | 218 | |
219 | 219 | $data = array( |
220 | - 'attendee_name' => (string)$meetingAttendeeName ?: $defaultVal, |
|
221 | - 'invitee_name' => (string)$meetingInviteeName ?: $defaultVal, |
|
222 | - 'meeting_title' => (string)$meetingTitle ?: $defaultVal, |
|
223 | - 'meeting_description' => (string)$meetingDescription ?: $defaultVal, |
|
224 | - 'meeting_url' => (string)$meetingUrl ?: $defaultVal, |
|
220 | + 'attendee_name' => (string) $meetingAttendeeName ?: $defaultVal, |
|
221 | + 'invitee_name' => (string) $meetingInviteeName ?: $defaultVal, |
|
222 | + 'meeting_title' => (string) $meetingTitle ?: $defaultVal, |
|
223 | + 'meeting_description' => (string) $meetingDescription ?: $defaultVal, |
|
224 | + 'meeting_url' => (string) $meetingUrl ?: $defaultVal, |
|
225 | 225 | ); |
226 | 226 | |
227 | 227 | $fromEMail = \OCP\Util::getDefaultEmailAddress('invitations-noreply'); |
@@ -232,7 +232,7 @@ discard block |
||
232 | 232 | ->setReplyTo([$sender => $senderName]) |
233 | 233 | ->setTo([$recipient => $recipientName]); |
234 | 234 | |
235 | - $template = $this->mailer->createEMailTemplate('dav.calendarInvite.' . $method, $data); |
|
235 | + $template = $this->mailer->createEMailTemplate('dav.calendarInvite.'.$method, $data); |
|
236 | 236 | $template->addHeader(); |
237 | 237 | |
238 | 238 | $this->addSubjectAndHeading($template, $l10n, $method, $summary, |
@@ -246,8 +246,8 @@ discard block |
||
246 | 246 | |
247 | 247 | $attachment = $this->mailer->createAttachment( |
248 | 248 | $iTipMessage->message->serialize(), |
249 | - 'event.ics',// TODO(leon): Make file name unique, e.g. add event id |
|
250 | - 'text/calendar; method=' . $iTipMessage->method |
|
249 | + 'event.ics', // TODO(leon): Make file name unique, e.g. add event id |
|
250 | + 'text/calendar; method='.$iTipMessage->method |
|
251 | 251 | ); |
252 | 252 | $message->attach($attachment); |
253 | 253 | |
@@ -258,7 +258,7 @@ discard block |
||
258 | 258 | $this->logger->error('Unable to deliver message to {failed}', ['app' => 'dav', 'failed' => implode(', ', $failed)]); |
259 | 259 | $iTipMessage->scheduleStatus = '5.0; EMail delivery failed'; |
260 | 260 | } |
261 | - } catch(\Exception $ex) { |
|
261 | + } catch (\Exception $ex) { |
|
262 | 262 | $this->logger->logException($ex, ['app' => 'dav']); |
263 | 263 | $iTipMessage->scheduleStatus = '5.0; EMail delivery failed'; |
264 | 264 | } |
@@ -294,13 +294,13 @@ discard block |
||
294 | 294 | $lastOccurrence = $firstOccurrence; |
295 | 295 | } |
296 | 296 | } else { |
297 | - $it = new EventIterator($vObject, (string)$component->UID); |
|
297 | + $it = new EventIterator($vObject, (string) $component->UID); |
|
298 | 298 | $maxDate = new \DateTime(self::MAX_DATE); |
299 | 299 | if ($it->isInfinite()) { |
300 | 300 | $lastOccurrence = $maxDate->getTimestamp(); |
301 | 301 | } else { |
302 | 302 | $end = $it->getDtEnd(); |
303 | - while($it->valid() && $end < $maxDate) { |
|
303 | + while ($it->valid() && $end < $maxDate) { |
|
304 | 304 | $end = $it->getDtEnd(); |
305 | 305 | $it->next(); |
306 | 306 | |
@@ -375,7 +375,7 @@ discard block |
||
375 | 375 | $localeStart = $l10n->l('date', $dtstartDt, ['width' => 'medium']); |
376 | 376 | $localeEnd = $l10n->l('date', $dtendDt, ['width' => 'medium']); |
377 | 377 | |
378 | - return $localeStart . ' - ' . $localeEnd; |
|
378 | + return $localeStart.' - '.$localeEnd; |
|
379 | 379 | } |
380 | 380 | |
381 | 381 | /** @var Property\ICalendar\DateTime $dtstart */ |
@@ -394,26 +394,26 @@ discard block |
||
394 | 394 | } |
395 | 395 | } |
396 | 396 | |
397 | - $localeStart = $l10n->l('weekdayName', $dtstartDt, ['width' => 'abbreviated']) . ', ' . |
|
397 | + $localeStart = $l10n->l('weekdayName', $dtstartDt, ['width' => 'abbreviated']).', '. |
|
398 | 398 | $l10n->l('datetime', $dtstartDt, ['width' => 'medium|short']); |
399 | 399 | |
400 | 400 | // always show full date with timezone if timezones are different |
401 | 401 | if ($startTimezone !== $endTimezone) { |
402 | 402 | $localeEnd = $l10n->l('datetime', $dtendDt, ['width' => 'medium|short']); |
403 | 403 | |
404 | - return $localeStart . ' (' . $startTimezone . ') - ' . |
|
405 | - $localeEnd . ' (' . $endTimezone . ')'; |
|
404 | + return $localeStart.' ('.$startTimezone.') - '. |
|
405 | + $localeEnd.' ('.$endTimezone.')'; |
|
406 | 406 | } |
407 | 407 | |
408 | 408 | // show only end time if date is the same |
409 | 409 | if ($this->isDayEqual($dtstartDt, $dtendDt)) { |
410 | 410 | $localeEnd = $l10n->l('time', $dtendDt, ['width' => 'short']); |
411 | 411 | } else { |
412 | - $localeEnd = $l10n->l('weekdayName', $dtendDt, ['width' => 'abbreviated']) . ', ' . |
|
412 | + $localeEnd = $l10n->l('weekdayName', $dtendDt, ['width' => 'abbreviated']).', '. |
|
413 | 413 | $l10n->l('datetime', $dtendDt, ['width' => 'medium|short']); |
414 | 414 | } |
415 | 415 | |
416 | - return $localeStart . ' - ' . $localeEnd . ' (' . $startTimezone . ')'; |
|
416 | + return $localeStart.' - '.$localeEnd.' ('.$startTimezone.')'; |
|
417 | 417 | } |
418 | 418 | |
419 | 419 | /** |
@@ -436,15 +436,15 @@ discard block |
||
436 | 436 | private function addSubjectAndHeading(IEMailTemplate $template, IL10N $l10n, |
437 | 437 | $method, $summary, $attendeeName, $inviteeName) { |
438 | 438 | if ($method === self::METHOD_CANCEL) { |
439 | - $template->setSubject('Cancelled: ' . $summary); |
|
439 | + $template->setSubject('Cancelled: '.$summary); |
|
440 | 440 | $template->addHeading($l10n->t('Invitation canceled'), $l10n->t('Hello %s,', [$attendeeName])); |
441 | 441 | $template->addBodyText($l10n->t('The meeting »%1$s« with %2$s was canceled.', [$summary, $inviteeName])); |
442 | 442 | } else if ($method === self::METHOD_REPLY) { |
443 | - $template->setSubject('Re: ' . $summary); |
|
443 | + $template->setSubject('Re: '.$summary); |
|
444 | 444 | $template->addHeading($l10n->t('Invitation updated'), $l10n->t('Hello %s,', [$attendeeName])); |
445 | 445 | $template->addBodyText($l10n->t('The meeting »%1$s« with %2$s was updated.', [$summary, $inviteeName])); |
446 | 446 | } else { |
447 | - $template->setSubject('Invitation: ' . $summary); |
|
447 | + $template->setSubject('Invitation: '.$summary); |
|
448 | 448 | $template->addHeading($l10n->t('%1$s invited you to »%2$s«', [$inviteeName, $summary]), $l10n->t('Hello %s,', [$attendeeName])); |
449 | 449 | } |
450 | 450 | |
@@ -467,11 +467,11 @@ discard block |
||
467 | 467 | $this->getAbsoluteImagePath('filetypes/location.svg')); |
468 | 468 | } |
469 | 469 | if ($description) { |
470 | - $template->addBodyListItem((string)$description, $l10n->t('Description:'), |
|
470 | + $template->addBodyListItem((string) $description, $l10n->t('Description:'), |
|
471 | 471 | $this->getAbsoluteImagePath('filetypes/text.svg')); |
472 | 472 | } |
473 | 473 | if ($url) { |
474 | - $template->addBodyListItem((string)$url, $l10n->t('Link:'), |
|
474 | + $template->addBodyListItem((string) $url, $l10n->t('Link:'), |
|
475 | 475 | $this->getAbsoluteImagePath('filetypes/link.svg')); |
476 | 476 | } |
477 | 477 | } |
@@ -524,7 +524,7 @@ discard block |
||
524 | 524 | * @return string |
525 | 525 | */ |
526 | 526 | private function createInvitationToken(Message $iTipMessage, $lastOccurrence):string { |
527 | - $token = $this->random->generate(60, ISecureRandom::CHAR_UPPER . ISecureRandom::CHAR_LOWER . ISecureRandom::CHAR_DIGITS); |
|
527 | + $token = $this->random->generate(60, ISecureRandom::CHAR_UPPER.ISecureRandom::CHAR_LOWER.ISecureRandom::CHAR_DIGITS); |
|
528 | 528 | |
529 | 529 | /** @var VEvent $vevent */ |
530 | 530 | $vevent = $iTipMessage->message->VEVENT; |
@@ -26,34 +26,34 @@ |
||
26 | 26 | |
27 | 27 | class AppManagement extends Action { |
28 | 28 | |
29 | - /** |
|
30 | - * @param string $appName |
|
31 | - */ |
|
32 | - public function enableApp(string $appName) { |
|
33 | - $this->log('App "%s" enabled', |
|
34 | - ['app' => $appName], |
|
35 | - ['app'] |
|
36 | - ); |
|
37 | - } |
|
29 | + /** |
|
30 | + * @param string $appName |
|
31 | + */ |
|
32 | + public function enableApp(string $appName) { |
|
33 | + $this->log('App "%s" enabled', |
|
34 | + ['app' => $appName], |
|
35 | + ['app'] |
|
36 | + ); |
|
37 | + } |
|
38 | 38 | |
39 | - /** |
|
40 | - * @param string $appName |
|
41 | - * @param string[] $groups |
|
42 | - */ |
|
43 | - public function enableAppForGroups(string $appName, array $groups) { |
|
44 | - $this->log('App "%1$s" enabled for groups: %2$s', |
|
45 | - ['app' => $appName, 'groups' => implode(', ', $groups)], |
|
46 | - ['app', 'groups'] |
|
47 | - ); |
|
48 | - } |
|
39 | + /** |
|
40 | + * @param string $appName |
|
41 | + * @param string[] $groups |
|
42 | + */ |
|
43 | + public function enableAppForGroups(string $appName, array $groups) { |
|
44 | + $this->log('App "%1$s" enabled for groups: %2$s', |
|
45 | + ['app' => $appName, 'groups' => implode(', ', $groups)], |
|
46 | + ['app', 'groups'] |
|
47 | + ); |
|
48 | + } |
|
49 | 49 | |
50 | - /** |
|
51 | - * @param string $appName |
|
52 | - */ |
|
53 | - public function disableApp(string $appName) { |
|
54 | - $this->log('App "%s" disabled', |
|
55 | - ['app' => $appName], |
|
56 | - ['app'] |
|
57 | - ); |
|
58 | - } |
|
50 | + /** |
|
51 | + * @param string $appName |
|
52 | + */ |
|
53 | + public function disableApp(string $appName) { |
|
54 | + $this->log('App "%s" disabled', |
|
55 | + ['app' => $appName], |
|
56 | + ['app'] |
|
57 | + ); |
|
58 | + } |
|
59 | 59 | } |
@@ -3,24 +3,24 @@ discard block |
||
3 | 3 | |
4 | 4 | <?php |
5 | 5 | |
6 | - $pinned = 0; |
|
7 | - foreach ($_['navigationItems'] as $item) { |
|
8 | - $pinned = NavigationListElements($item, $l, $pinned); |
|
9 | - } |
|
10 | - ?> |
|
6 | + $pinned = 0; |
|
7 | + foreach ($_['navigationItems'] as $item) { |
|
8 | + $pinned = NavigationListElements($item, $l, $pinned); |
|
9 | + } |
|
10 | + ?> |
|
11 | 11 | |
12 | 12 | <li id="quota" |
13 | 13 | class="pinned <?php p($pinned === 0 ? 'first-pinned ' : '') ?><?php |
14 | - if ($_['quota'] !== \OCP\Files\FileInfo::SPACE_UNLIMITED) { |
|
15 | - ?>has-tooltip" title="<?php p($_['usage_relative'] . '%'); |
|
16 | - } ?>"> |
|
14 | + if ($_['quota'] !== \OCP\Files\FileInfo::SPACE_UNLIMITED) { |
|
15 | + ?>has-tooltip" title="<?php p($_['usage_relative'] . '%'); |
|
16 | + } ?>"> |
|
17 | 17 | <a href="#" class="icon-quota svg"> |
18 | 18 | <p id="quotatext"><?php |
19 | - if ($_['quota'] !== \OCP\Files\FileInfo::SPACE_UNLIMITED) { |
|
20 | - p($l->t('%1$s of %2$s used', [$_['usage'], $_['total_space']])); |
|
21 | - } else { |
|
22 | - p($l->t('%s used', [$_['usage']])); |
|
23 | - } ?></p> |
|
19 | + if ($_['quota'] !== \OCP\Files\FileInfo::SPACE_UNLIMITED) { |
|
20 | + p($l->t('%1$s of %2$s used', [$_['usage'], $_['total_space']])); |
|
21 | + } else { |
|
22 | + p($l->t('%s used', [$_['usage']])); |
|
23 | + } ?></p> |
|
24 | 24 | <div class="quota-container"> |
25 | 25 | <progress value="<?php p($_['usage_relative']); ?>" |
26 | 26 | max="100" |
@@ -64,8 +64,8 @@ discard block |
||
64 | 64 | * @return int Returns the pinned value |
65 | 65 | */ |
66 | 66 | function NavigationListElements($item, $l, $pinned) { |
67 | - strpos($item['classes'] ?? '', 'pinned') !== false ? $pinned++ : ''; |
|
68 | - ?> |
|
67 | + strpos($item['classes'] ?? '', 'pinned') !== false ? $pinned++ : ''; |
|
68 | + ?> |
|
69 | 69 | <li |
70 | 70 | data-id="<?php p($item['id']) ?>" |
71 | 71 | <?php if (isset($item['dir'])) { ?> data-dir="<?php p($item['dir']); ?>" <?php } ?> |
@@ -82,23 +82,23 @@ discard block |
||
82 | 82 | |
83 | 83 | |
84 | 84 | <?php |
85 | - NavigationElementMenu($item); |
|
86 | - if (isset($item['sublist'])) { |
|
87 | - ?> |
|
85 | + NavigationElementMenu($item); |
|
86 | + if (isset($item['sublist'])) { |
|
87 | + ?> |
|
88 | 88 | <button class="collapse app-navigation-noclose" <?php if (sizeof($item['sublist']) == 0) { ?> style="display: none" <?php } ?>></button> |
89 | 89 | <ul id="sublist-<?php p($item['id']); ?>"> |
90 | 90 | <?php |
91 | - foreach ($item['sublist'] as $item) { |
|
92 | - $pinned = NavigationListElements($item, $l, $pinned); |
|
93 | - } |
|
94 | - ?> |
|
91 | + foreach ($item['sublist'] as $item) { |
|
92 | + $pinned = NavigationListElements($item, $l, $pinned); |
|
93 | + } |
|
94 | + ?> |
|
95 | 95 | </ul> |
96 | 96 | <?php } ?> |
97 | 97 | </li> |
98 | 98 | |
99 | 99 | |
100 | 100 | <?php |
101 | - return $pinned; |
|
101 | + return $pinned; |
|
102 | 102 | } |
103 | 103 | |
104 | 104 | /** |
@@ -109,8 +109,8 @@ discard block |
||
109 | 109 | * @return void |
110 | 110 | */ |
111 | 111 | function NavigationElementMenu($item) { |
112 | - if (isset($item['menubuttons']) && $item['menubuttons'] === 'true') { |
|
113 | - ?> |
|
112 | + if (isset($item['menubuttons']) && $item['menubuttons'] === 'true') { |
|
113 | + ?> |
|
114 | 114 | <div id="dotmenu-<?php p($item['id']); ?>" |
115 | 115 | class="app-navigation-entry-utils" <?php if (isset($item['enableMenuButton']) && $item['enableMenuButton'] === 0) { ?> style="display: none"<?php } ?>> |
116 | 116 | <ul> |
@@ -55,1044 +55,1044 @@ |
||
55 | 55 | */ |
56 | 56 | class FederatedShareProvider implements IShareProvider { |
57 | 57 | |
58 | - const SHARE_TYPE_REMOTE = 6; |
|
59 | - |
|
60 | - /** @var IDBConnection */ |
|
61 | - private $dbConnection; |
|
62 | - |
|
63 | - /** @var AddressHandler */ |
|
64 | - private $addressHandler; |
|
65 | - |
|
66 | - /** @var Notifications */ |
|
67 | - private $notifications; |
|
68 | - |
|
69 | - /** @var TokenHandler */ |
|
70 | - private $tokenHandler; |
|
71 | - |
|
72 | - /** @var IL10N */ |
|
73 | - private $l; |
|
74 | - |
|
75 | - /** @var ILogger */ |
|
76 | - private $logger; |
|
77 | - |
|
78 | - /** @var IRootFolder */ |
|
79 | - private $rootFolder; |
|
80 | - |
|
81 | - /** @var IConfig */ |
|
82 | - private $config; |
|
83 | - |
|
84 | - /** @var string */ |
|
85 | - private $externalShareTable = 'share_external'; |
|
86 | - |
|
87 | - /** @var IUserManager */ |
|
88 | - private $userManager; |
|
89 | - |
|
90 | - /** @var ICloudIdManager */ |
|
91 | - private $cloudIdManager; |
|
92 | - |
|
93 | - /** @var \OCP\GlobalScale\IConfig */ |
|
94 | - private $gsConfig; |
|
95 | - |
|
96 | - /** @var ICloudFederationProviderManager */ |
|
97 | - private $cloudFederationProviderManager; |
|
98 | - |
|
99 | - /** @var array list of supported share types */ |
|
100 | - private $supportedShareType = [\OCP\Share::SHARE_TYPE_REMOTE_GROUP, \OCP\Share::SHARE_TYPE_REMOTE]; |
|
101 | - |
|
102 | - /** |
|
103 | - * DefaultShareProvider constructor. |
|
104 | - * |
|
105 | - * @param IDBConnection $connection |
|
106 | - * @param AddressHandler $addressHandler |
|
107 | - * @param Notifications $notifications |
|
108 | - * @param TokenHandler $tokenHandler |
|
109 | - * @param IL10N $l10n |
|
110 | - * @param ILogger $logger |
|
111 | - * @param IRootFolder $rootFolder |
|
112 | - * @param IConfig $config |
|
113 | - * @param IUserManager $userManager |
|
114 | - * @param ICloudIdManager $cloudIdManager |
|
115 | - * @param \OCP\GlobalScale\IConfig $globalScaleConfig |
|
116 | - * @param ICloudFederationProviderManager $cloudFederationProviderManager |
|
117 | - */ |
|
118 | - public function __construct( |
|
119 | - IDBConnection $connection, |
|
120 | - AddressHandler $addressHandler, |
|
121 | - Notifications $notifications, |
|
122 | - TokenHandler $tokenHandler, |
|
123 | - IL10N $l10n, |
|
124 | - ILogger $logger, |
|
125 | - IRootFolder $rootFolder, |
|
126 | - IConfig $config, |
|
127 | - IUserManager $userManager, |
|
128 | - ICloudIdManager $cloudIdManager, |
|
129 | - \OCP\GlobalScale\IConfig $globalScaleConfig, |
|
130 | - ICloudFederationProviderManager $cloudFederationProviderManager |
|
131 | - ) { |
|
132 | - $this->dbConnection = $connection; |
|
133 | - $this->addressHandler = $addressHandler; |
|
134 | - $this->notifications = $notifications; |
|
135 | - $this->tokenHandler = $tokenHandler; |
|
136 | - $this->l = $l10n; |
|
137 | - $this->logger = $logger; |
|
138 | - $this->rootFolder = $rootFolder; |
|
139 | - $this->config = $config; |
|
140 | - $this->userManager = $userManager; |
|
141 | - $this->cloudIdManager = $cloudIdManager; |
|
142 | - $this->gsConfig = $globalScaleConfig; |
|
143 | - $this->cloudFederationProviderManager = $cloudFederationProviderManager; |
|
144 | - } |
|
145 | - |
|
146 | - /** |
|
147 | - * Return the identifier of this provider. |
|
148 | - * |
|
149 | - * @return string Containing only [a-zA-Z0-9] |
|
150 | - */ |
|
151 | - public function identifier() { |
|
152 | - return 'ocFederatedSharing'; |
|
153 | - } |
|
154 | - |
|
155 | - /** |
|
156 | - * Share a path |
|
157 | - * |
|
158 | - * @param IShare $share |
|
159 | - * @return IShare The share object |
|
160 | - * @throws ShareNotFound |
|
161 | - * @throws \Exception |
|
162 | - */ |
|
163 | - public function create(IShare $share) { |
|
164 | - |
|
165 | - $shareWith = $share->getSharedWith(); |
|
166 | - $itemSource = $share->getNodeId(); |
|
167 | - $itemType = $share->getNodeType(); |
|
168 | - $permissions = $share->getPermissions(); |
|
169 | - $sharedBy = $share->getSharedBy(); |
|
170 | - $shareType = $share->getShareType(); |
|
171 | - |
|
172 | - if ($shareType === \OCP\Share::SHARE_TYPE_REMOTE_GROUP && |
|
173 | - !$this->isOutgoingServer2serverGroupShareEnabled() |
|
174 | - ) { |
|
175 | - $message = 'It is not allowed to send federated group shares from this server.'; |
|
176 | - $message_t = $this->l->t('It is not allowed to send federated group shares from this server.'); |
|
177 | - $this->logger->debug($message, ['app' => 'Federated File Sharing']); |
|
178 | - throw new \Exception($message_t); |
|
179 | - } |
|
180 | - |
|
181 | - /* |
|
58 | + const SHARE_TYPE_REMOTE = 6; |
|
59 | + |
|
60 | + /** @var IDBConnection */ |
|
61 | + private $dbConnection; |
|
62 | + |
|
63 | + /** @var AddressHandler */ |
|
64 | + private $addressHandler; |
|
65 | + |
|
66 | + /** @var Notifications */ |
|
67 | + private $notifications; |
|
68 | + |
|
69 | + /** @var TokenHandler */ |
|
70 | + private $tokenHandler; |
|
71 | + |
|
72 | + /** @var IL10N */ |
|
73 | + private $l; |
|
74 | + |
|
75 | + /** @var ILogger */ |
|
76 | + private $logger; |
|
77 | + |
|
78 | + /** @var IRootFolder */ |
|
79 | + private $rootFolder; |
|
80 | + |
|
81 | + /** @var IConfig */ |
|
82 | + private $config; |
|
83 | + |
|
84 | + /** @var string */ |
|
85 | + private $externalShareTable = 'share_external'; |
|
86 | + |
|
87 | + /** @var IUserManager */ |
|
88 | + private $userManager; |
|
89 | + |
|
90 | + /** @var ICloudIdManager */ |
|
91 | + private $cloudIdManager; |
|
92 | + |
|
93 | + /** @var \OCP\GlobalScale\IConfig */ |
|
94 | + private $gsConfig; |
|
95 | + |
|
96 | + /** @var ICloudFederationProviderManager */ |
|
97 | + private $cloudFederationProviderManager; |
|
98 | + |
|
99 | + /** @var array list of supported share types */ |
|
100 | + private $supportedShareType = [\OCP\Share::SHARE_TYPE_REMOTE_GROUP, \OCP\Share::SHARE_TYPE_REMOTE]; |
|
101 | + |
|
102 | + /** |
|
103 | + * DefaultShareProvider constructor. |
|
104 | + * |
|
105 | + * @param IDBConnection $connection |
|
106 | + * @param AddressHandler $addressHandler |
|
107 | + * @param Notifications $notifications |
|
108 | + * @param TokenHandler $tokenHandler |
|
109 | + * @param IL10N $l10n |
|
110 | + * @param ILogger $logger |
|
111 | + * @param IRootFolder $rootFolder |
|
112 | + * @param IConfig $config |
|
113 | + * @param IUserManager $userManager |
|
114 | + * @param ICloudIdManager $cloudIdManager |
|
115 | + * @param \OCP\GlobalScale\IConfig $globalScaleConfig |
|
116 | + * @param ICloudFederationProviderManager $cloudFederationProviderManager |
|
117 | + */ |
|
118 | + public function __construct( |
|
119 | + IDBConnection $connection, |
|
120 | + AddressHandler $addressHandler, |
|
121 | + Notifications $notifications, |
|
122 | + TokenHandler $tokenHandler, |
|
123 | + IL10N $l10n, |
|
124 | + ILogger $logger, |
|
125 | + IRootFolder $rootFolder, |
|
126 | + IConfig $config, |
|
127 | + IUserManager $userManager, |
|
128 | + ICloudIdManager $cloudIdManager, |
|
129 | + \OCP\GlobalScale\IConfig $globalScaleConfig, |
|
130 | + ICloudFederationProviderManager $cloudFederationProviderManager |
|
131 | + ) { |
|
132 | + $this->dbConnection = $connection; |
|
133 | + $this->addressHandler = $addressHandler; |
|
134 | + $this->notifications = $notifications; |
|
135 | + $this->tokenHandler = $tokenHandler; |
|
136 | + $this->l = $l10n; |
|
137 | + $this->logger = $logger; |
|
138 | + $this->rootFolder = $rootFolder; |
|
139 | + $this->config = $config; |
|
140 | + $this->userManager = $userManager; |
|
141 | + $this->cloudIdManager = $cloudIdManager; |
|
142 | + $this->gsConfig = $globalScaleConfig; |
|
143 | + $this->cloudFederationProviderManager = $cloudFederationProviderManager; |
|
144 | + } |
|
145 | + |
|
146 | + /** |
|
147 | + * Return the identifier of this provider. |
|
148 | + * |
|
149 | + * @return string Containing only [a-zA-Z0-9] |
|
150 | + */ |
|
151 | + public function identifier() { |
|
152 | + return 'ocFederatedSharing'; |
|
153 | + } |
|
154 | + |
|
155 | + /** |
|
156 | + * Share a path |
|
157 | + * |
|
158 | + * @param IShare $share |
|
159 | + * @return IShare The share object |
|
160 | + * @throws ShareNotFound |
|
161 | + * @throws \Exception |
|
162 | + */ |
|
163 | + public function create(IShare $share) { |
|
164 | + |
|
165 | + $shareWith = $share->getSharedWith(); |
|
166 | + $itemSource = $share->getNodeId(); |
|
167 | + $itemType = $share->getNodeType(); |
|
168 | + $permissions = $share->getPermissions(); |
|
169 | + $sharedBy = $share->getSharedBy(); |
|
170 | + $shareType = $share->getShareType(); |
|
171 | + |
|
172 | + if ($shareType === \OCP\Share::SHARE_TYPE_REMOTE_GROUP && |
|
173 | + !$this->isOutgoingServer2serverGroupShareEnabled() |
|
174 | + ) { |
|
175 | + $message = 'It is not allowed to send federated group shares from this server.'; |
|
176 | + $message_t = $this->l->t('It is not allowed to send federated group shares from this server.'); |
|
177 | + $this->logger->debug($message, ['app' => 'Federated File Sharing']); |
|
178 | + throw new \Exception($message_t); |
|
179 | + } |
|
180 | + |
|
181 | + /* |
|
182 | 182 | * Check if file is not already shared with the remote user |
183 | 183 | */ |
184 | - $alreadyShared = $this->getSharedWith($shareWith, \OCP\Share::SHARE_TYPE_REMOTE, $share->getNode(), 1, 0); |
|
185 | - $alreadySharedGroup = $this->getSharedWith($shareWith, \OCP\Share::SHARE_TYPE_REMOTE_GROUP, $share->getNode(), 1, 0); |
|
186 | - if (!empty($alreadyShared) || !empty($alreadySharedGroup)) { |
|
187 | - $message = 'Sharing %1$s failed, because this item is already shared with %2$s'; |
|
188 | - $message_t = $this->l->t('Sharing %1$s failed, because this item is already shared with %2$s', array($share->getNode()->getName(), $shareWith)); |
|
189 | - $this->logger->debug(sprintf($message, $share->getNode()->getName(), $shareWith), ['app' => 'Federated File Sharing']); |
|
190 | - throw new \Exception($message_t); |
|
191 | - } |
|
192 | - |
|
193 | - |
|
194 | - // don't allow federated shares if source and target server are the same |
|
195 | - $cloudId = $this->cloudIdManager->resolveCloudId($shareWith); |
|
196 | - $currentServer = $this->addressHandler->generateRemoteURL(); |
|
197 | - $currentUser = $sharedBy; |
|
198 | - if ($this->addressHandler->compareAddresses($cloudId->getUser(), $cloudId->getRemote(), $currentUser, $currentServer)) { |
|
199 | - $message = 'Not allowed to create a federated share with the same user.'; |
|
200 | - $message_t = $this->l->t('Not allowed to create a federated share with the same user'); |
|
201 | - $this->logger->debug($message, ['app' => 'Federated File Sharing']); |
|
202 | - throw new \Exception($message_t); |
|
203 | - } |
|
204 | - |
|
205 | - |
|
206 | - $share->setSharedWith($cloudId->getId()); |
|
207 | - |
|
208 | - try { |
|
209 | - $remoteShare = $this->getShareFromExternalShareTable($share); |
|
210 | - } catch (ShareNotFound $e) { |
|
211 | - $remoteShare = null; |
|
212 | - } |
|
213 | - |
|
214 | - if ($remoteShare) { |
|
215 | - try { |
|
216 | - $ownerCloudId = $this->cloudIdManager->getCloudId($remoteShare['owner'], $remoteShare['remote']); |
|
217 | - $shareId = $this->addShareToDB($itemSource, $itemType, $shareWith, $sharedBy, $ownerCloudId->getId(), $permissions, 'tmp_token_' . time(), $shareType); |
|
218 | - $share->setId($shareId); |
|
219 | - list($token, $remoteId) = $this->askOwnerToReShare($shareWith, $share, $shareId); |
|
220 | - // remote share was create successfully if we get a valid token as return |
|
221 | - $send = is_string($token) && $token !== ''; |
|
222 | - } catch (\Exception $e) { |
|
223 | - // fall back to old re-share behavior if the remote server |
|
224 | - // doesn't support flat re-shares (was introduced with Nextcloud 9.1) |
|
225 | - $this->removeShareFromTable($share); |
|
226 | - $shareId = $this->createFederatedShare($share); |
|
227 | - } |
|
228 | - if ($send) { |
|
229 | - $this->updateSuccessfulReshare($shareId, $token); |
|
230 | - $this->storeRemoteId($shareId, $remoteId); |
|
231 | - } else { |
|
232 | - $this->removeShareFromTable($share); |
|
233 | - $message_t = $this->l->t('File is already shared with %s', [$shareWith]); |
|
234 | - throw new \Exception($message_t); |
|
235 | - } |
|
236 | - |
|
237 | - } else { |
|
238 | - $shareId = $this->createFederatedShare($share); |
|
239 | - } |
|
240 | - |
|
241 | - $data = $this->getRawShare($shareId); |
|
242 | - return $this->createShareObject($data); |
|
243 | - } |
|
244 | - |
|
245 | - /** |
|
246 | - * create federated share and inform the recipient |
|
247 | - * |
|
248 | - * @param IShare $share |
|
249 | - * @return int |
|
250 | - * @throws ShareNotFound |
|
251 | - * @throws \Exception |
|
252 | - */ |
|
253 | - protected function createFederatedShare(IShare $share) { |
|
254 | - $token = $this->tokenHandler->generateToken(); |
|
255 | - $shareId = $this->addShareToDB( |
|
256 | - $share->getNodeId(), |
|
257 | - $share->getNodeType(), |
|
258 | - $share->getSharedWith(), |
|
259 | - $share->getSharedBy(), |
|
260 | - $share->getShareOwner(), |
|
261 | - $share->getPermissions(), |
|
262 | - $token, |
|
263 | - $share->getShareType() |
|
264 | - ); |
|
265 | - |
|
266 | - $failure = false; |
|
267 | - |
|
268 | - try { |
|
269 | - $sharedByFederatedId = $share->getSharedBy(); |
|
270 | - if ($this->userManager->userExists($sharedByFederatedId)) { |
|
271 | - $cloudId = $this->cloudIdManager->getCloudId($sharedByFederatedId, $this->addressHandler->generateRemoteURL()); |
|
272 | - $sharedByFederatedId = $cloudId->getId(); |
|
273 | - } |
|
274 | - $ownerCloudId = $this->cloudIdManager->getCloudId($share->getShareOwner(), $this->addressHandler->generateRemoteURL()); |
|
275 | - $send = $this->notifications->sendRemoteShare( |
|
276 | - $token, |
|
277 | - $share->getSharedWith(), |
|
278 | - $share->getNode()->getName(), |
|
279 | - $shareId, |
|
280 | - $share->getShareOwner(), |
|
281 | - $ownerCloudId->getId(), |
|
282 | - $share->getSharedBy(), |
|
283 | - $sharedByFederatedId, |
|
284 | - $share->getShareType() |
|
285 | - ); |
|
286 | - |
|
287 | - if ($send === false) { |
|
288 | - $failure = true; |
|
289 | - } |
|
290 | - } catch (\Exception $e) { |
|
291 | - $this->logger->logException($e, [ |
|
292 | - 'message' => 'Failed to notify remote server of federated share, removing share.', |
|
293 | - 'level' => ILogger::ERROR, |
|
294 | - 'app' => 'federatedfilesharing', |
|
295 | - ]); |
|
296 | - $failure = true; |
|
297 | - } |
|
298 | - |
|
299 | - if($failure) { |
|
300 | - $this->removeShareFromTableById($shareId); |
|
301 | - $message_t = $this->l->t('Sharing %1$s failed, could not find %2$s, maybe the server is currently unreachable or uses a self-signed certificate.', |
|
302 | - [$share->getNode()->getName(), $share->getSharedWith()]); |
|
303 | - throw new \Exception($message_t); |
|
304 | - } |
|
305 | - |
|
306 | - return $shareId; |
|
307 | - |
|
308 | - } |
|
309 | - |
|
310 | - /** |
|
311 | - * @param string $shareWith |
|
312 | - * @param IShare $share |
|
313 | - * @param string $shareId internal share Id |
|
314 | - * @return array |
|
315 | - * @throws \Exception |
|
316 | - */ |
|
317 | - protected function askOwnerToReShare($shareWith, IShare $share, $shareId) { |
|
318 | - |
|
319 | - $remoteShare = $this->getShareFromExternalShareTable($share); |
|
320 | - $token = $remoteShare['share_token']; |
|
321 | - $remoteId = $remoteShare['remote_id']; |
|
322 | - $remote = $remoteShare['remote']; |
|
323 | - |
|
324 | - list($token, $remoteId) = $this->notifications->requestReShare( |
|
325 | - $token, |
|
326 | - $remoteId, |
|
327 | - $shareId, |
|
328 | - $remote, |
|
329 | - $shareWith, |
|
330 | - $share->getPermissions(), |
|
331 | - $share->getNode()->getName() |
|
332 | - ); |
|
333 | - |
|
334 | - return [$token, $remoteId]; |
|
335 | - } |
|
336 | - |
|
337 | - /** |
|
338 | - * get federated share from the share_external table but exclude mounted link shares |
|
339 | - * |
|
340 | - * @param IShare $share |
|
341 | - * @return array |
|
342 | - * @throws ShareNotFound |
|
343 | - */ |
|
344 | - protected function getShareFromExternalShareTable(IShare $share) { |
|
345 | - $query = $this->dbConnection->getQueryBuilder(); |
|
346 | - $query->select('*')->from($this->externalShareTable) |
|
347 | - ->where($query->expr()->eq('user', $query->createNamedParameter($share->getShareOwner()))) |
|
348 | - ->andWhere($query->expr()->eq('mountpoint', $query->createNamedParameter($share->getTarget()))); |
|
349 | - $result = $query->execute()->fetchAll(); |
|
350 | - |
|
351 | - if (isset($result[0]) && (int)$result[0]['remote_id'] > 0) { |
|
352 | - return $result[0]; |
|
353 | - } |
|
354 | - |
|
355 | - throw new ShareNotFound('share not found in share_external table'); |
|
356 | - } |
|
357 | - |
|
358 | - /** |
|
359 | - * add share to the database and return the ID |
|
360 | - * |
|
361 | - * @param int $itemSource |
|
362 | - * @param string $itemType |
|
363 | - * @param string $shareWith |
|
364 | - * @param string $sharedBy |
|
365 | - * @param string $uidOwner |
|
366 | - * @param int $permissions |
|
367 | - * @param string $token |
|
368 | - * @param int $shareType |
|
369 | - * @return int |
|
370 | - */ |
|
371 | - private function addShareToDB($itemSource, $itemType, $shareWith, $sharedBy, $uidOwner, $permissions, $token, $shareType) { |
|
372 | - $qb = $this->dbConnection->getQueryBuilder(); |
|
373 | - $qb->insert('share') |
|
374 | - ->setValue('share_type', $qb->createNamedParameter($shareType)) |
|
375 | - ->setValue('item_type', $qb->createNamedParameter($itemType)) |
|
376 | - ->setValue('item_source', $qb->createNamedParameter($itemSource)) |
|
377 | - ->setValue('file_source', $qb->createNamedParameter($itemSource)) |
|
378 | - ->setValue('share_with', $qb->createNamedParameter($shareWith)) |
|
379 | - ->setValue('uid_owner', $qb->createNamedParameter($uidOwner)) |
|
380 | - ->setValue('uid_initiator', $qb->createNamedParameter($sharedBy)) |
|
381 | - ->setValue('permissions', $qb->createNamedParameter($permissions)) |
|
382 | - ->setValue('token', $qb->createNamedParameter($token)) |
|
383 | - ->setValue('stime', $qb->createNamedParameter(time())); |
|
384 | - |
|
385 | - /* |
|
184 | + $alreadyShared = $this->getSharedWith($shareWith, \OCP\Share::SHARE_TYPE_REMOTE, $share->getNode(), 1, 0); |
|
185 | + $alreadySharedGroup = $this->getSharedWith($shareWith, \OCP\Share::SHARE_TYPE_REMOTE_GROUP, $share->getNode(), 1, 0); |
|
186 | + if (!empty($alreadyShared) || !empty($alreadySharedGroup)) { |
|
187 | + $message = 'Sharing %1$s failed, because this item is already shared with %2$s'; |
|
188 | + $message_t = $this->l->t('Sharing %1$s failed, because this item is already shared with %2$s', array($share->getNode()->getName(), $shareWith)); |
|
189 | + $this->logger->debug(sprintf($message, $share->getNode()->getName(), $shareWith), ['app' => 'Federated File Sharing']); |
|
190 | + throw new \Exception($message_t); |
|
191 | + } |
|
192 | + |
|
193 | + |
|
194 | + // don't allow federated shares if source and target server are the same |
|
195 | + $cloudId = $this->cloudIdManager->resolveCloudId($shareWith); |
|
196 | + $currentServer = $this->addressHandler->generateRemoteURL(); |
|
197 | + $currentUser = $sharedBy; |
|
198 | + if ($this->addressHandler->compareAddresses($cloudId->getUser(), $cloudId->getRemote(), $currentUser, $currentServer)) { |
|
199 | + $message = 'Not allowed to create a federated share with the same user.'; |
|
200 | + $message_t = $this->l->t('Not allowed to create a federated share with the same user'); |
|
201 | + $this->logger->debug($message, ['app' => 'Federated File Sharing']); |
|
202 | + throw new \Exception($message_t); |
|
203 | + } |
|
204 | + |
|
205 | + |
|
206 | + $share->setSharedWith($cloudId->getId()); |
|
207 | + |
|
208 | + try { |
|
209 | + $remoteShare = $this->getShareFromExternalShareTable($share); |
|
210 | + } catch (ShareNotFound $e) { |
|
211 | + $remoteShare = null; |
|
212 | + } |
|
213 | + |
|
214 | + if ($remoteShare) { |
|
215 | + try { |
|
216 | + $ownerCloudId = $this->cloudIdManager->getCloudId($remoteShare['owner'], $remoteShare['remote']); |
|
217 | + $shareId = $this->addShareToDB($itemSource, $itemType, $shareWith, $sharedBy, $ownerCloudId->getId(), $permissions, 'tmp_token_' . time(), $shareType); |
|
218 | + $share->setId($shareId); |
|
219 | + list($token, $remoteId) = $this->askOwnerToReShare($shareWith, $share, $shareId); |
|
220 | + // remote share was create successfully if we get a valid token as return |
|
221 | + $send = is_string($token) && $token !== ''; |
|
222 | + } catch (\Exception $e) { |
|
223 | + // fall back to old re-share behavior if the remote server |
|
224 | + // doesn't support flat re-shares (was introduced with Nextcloud 9.1) |
|
225 | + $this->removeShareFromTable($share); |
|
226 | + $shareId = $this->createFederatedShare($share); |
|
227 | + } |
|
228 | + if ($send) { |
|
229 | + $this->updateSuccessfulReshare($shareId, $token); |
|
230 | + $this->storeRemoteId($shareId, $remoteId); |
|
231 | + } else { |
|
232 | + $this->removeShareFromTable($share); |
|
233 | + $message_t = $this->l->t('File is already shared with %s', [$shareWith]); |
|
234 | + throw new \Exception($message_t); |
|
235 | + } |
|
236 | + |
|
237 | + } else { |
|
238 | + $shareId = $this->createFederatedShare($share); |
|
239 | + } |
|
240 | + |
|
241 | + $data = $this->getRawShare($shareId); |
|
242 | + return $this->createShareObject($data); |
|
243 | + } |
|
244 | + |
|
245 | + /** |
|
246 | + * create federated share and inform the recipient |
|
247 | + * |
|
248 | + * @param IShare $share |
|
249 | + * @return int |
|
250 | + * @throws ShareNotFound |
|
251 | + * @throws \Exception |
|
252 | + */ |
|
253 | + protected function createFederatedShare(IShare $share) { |
|
254 | + $token = $this->tokenHandler->generateToken(); |
|
255 | + $shareId = $this->addShareToDB( |
|
256 | + $share->getNodeId(), |
|
257 | + $share->getNodeType(), |
|
258 | + $share->getSharedWith(), |
|
259 | + $share->getSharedBy(), |
|
260 | + $share->getShareOwner(), |
|
261 | + $share->getPermissions(), |
|
262 | + $token, |
|
263 | + $share->getShareType() |
|
264 | + ); |
|
265 | + |
|
266 | + $failure = false; |
|
267 | + |
|
268 | + try { |
|
269 | + $sharedByFederatedId = $share->getSharedBy(); |
|
270 | + if ($this->userManager->userExists($sharedByFederatedId)) { |
|
271 | + $cloudId = $this->cloudIdManager->getCloudId($sharedByFederatedId, $this->addressHandler->generateRemoteURL()); |
|
272 | + $sharedByFederatedId = $cloudId->getId(); |
|
273 | + } |
|
274 | + $ownerCloudId = $this->cloudIdManager->getCloudId($share->getShareOwner(), $this->addressHandler->generateRemoteURL()); |
|
275 | + $send = $this->notifications->sendRemoteShare( |
|
276 | + $token, |
|
277 | + $share->getSharedWith(), |
|
278 | + $share->getNode()->getName(), |
|
279 | + $shareId, |
|
280 | + $share->getShareOwner(), |
|
281 | + $ownerCloudId->getId(), |
|
282 | + $share->getSharedBy(), |
|
283 | + $sharedByFederatedId, |
|
284 | + $share->getShareType() |
|
285 | + ); |
|
286 | + |
|
287 | + if ($send === false) { |
|
288 | + $failure = true; |
|
289 | + } |
|
290 | + } catch (\Exception $e) { |
|
291 | + $this->logger->logException($e, [ |
|
292 | + 'message' => 'Failed to notify remote server of federated share, removing share.', |
|
293 | + 'level' => ILogger::ERROR, |
|
294 | + 'app' => 'federatedfilesharing', |
|
295 | + ]); |
|
296 | + $failure = true; |
|
297 | + } |
|
298 | + |
|
299 | + if($failure) { |
|
300 | + $this->removeShareFromTableById($shareId); |
|
301 | + $message_t = $this->l->t('Sharing %1$s failed, could not find %2$s, maybe the server is currently unreachable or uses a self-signed certificate.', |
|
302 | + [$share->getNode()->getName(), $share->getSharedWith()]); |
|
303 | + throw new \Exception($message_t); |
|
304 | + } |
|
305 | + |
|
306 | + return $shareId; |
|
307 | + |
|
308 | + } |
|
309 | + |
|
310 | + /** |
|
311 | + * @param string $shareWith |
|
312 | + * @param IShare $share |
|
313 | + * @param string $shareId internal share Id |
|
314 | + * @return array |
|
315 | + * @throws \Exception |
|
316 | + */ |
|
317 | + protected function askOwnerToReShare($shareWith, IShare $share, $shareId) { |
|
318 | + |
|
319 | + $remoteShare = $this->getShareFromExternalShareTable($share); |
|
320 | + $token = $remoteShare['share_token']; |
|
321 | + $remoteId = $remoteShare['remote_id']; |
|
322 | + $remote = $remoteShare['remote']; |
|
323 | + |
|
324 | + list($token, $remoteId) = $this->notifications->requestReShare( |
|
325 | + $token, |
|
326 | + $remoteId, |
|
327 | + $shareId, |
|
328 | + $remote, |
|
329 | + $shareWith, |
|
330 | + $share->getPermissions(), |
|
331 | + $share->getNode()->getName() |
|
332 | + ); |
|
333 | + |
|
334 | + return [$token, $remoteId]; |
|
335 | + } |
|
336 | + |
|
337 | + /** |
|
338 | + * get federated share from the share_external table but exclude mounted link shares |
|
339 | + * |
|
340 | + * @param IShare $share |
|
341 | + * @return array |
|
342 | + * @throws ShareNotFound |
|
343 | + */ |
|
344 | + protected function getShareFromExternalShareTable(IShare $share) { |
|
345 | + $query = $this->dbConnection->getQueryBuilder(); |
|
346 | + $query->select('*')->from($this->externalShareTable) |
|
347 | + ->where($query->expr()->eq('user', $query->createNamedParameter($share->getShareOwner()))) |
|
348 | + ->andWhere($query->expr()->eq('mountpoint', $query->createNamedParameter($share->getTarget()))); |
|
349 | + $result = $query->execute()->fetchAll(); |
|
350 | + |
|
351 | + if (isset($result[0]) && (int)$result[0]['remote_id'] > 0) { |
|
352 | + return $result[0]; |
|
353 | + } |
|
354 | + |
|
355 | + throw new ShareNotFound('share not found in share_external table'); |
|
356 | + } |
|
357 | + |
|
358 | + /** |
|
359 | + * add share to the database and return the ID |
|
360 | + * |
|
361 | + * @param int $itemSource |
|
362 | + * @param string $itemType |
|
363 | + * @param string $shareWith |
|
364 | + * @param string $sharedBy |
|
365 | + * @param string $uidOwner |
|
366 | + * @param int $permissions |
|
367 | + * @param string $token |
|
368 | + * @param int $shareType |
|
369 | + * @return int |
|
370 | + */ |
|
371 | + private function addShareToDB($itemSource, $itemType, $shareWith, $sharedBy, $uidOwner, $permissions, $token, $shareType) { |
|
372 | + $qb = $this->dbConnection->getQueryBuilder(); |
|
373 | + $qb->insert('share') |
|
374 | + ->setValue('share_type', $qb->createNamedParameter($shareType)) |
|
375 | + ->setValue('item_type', $qb->createNamedParameter($itemType)) |
|
376 | + ->setValue('item_source', $qb->createNamedParameter($itemSource)) |
|
377 | + ->setValue('file_source', $qb->createNamedParameter($itemSource)) |
|
378 | + ->setValue('share_with', $qb->createNamedParameter($shareWith)) |
|
379 | + ->setValue('uid_owner', $qb->createNamedParameter($uidOwner)) |
|
380 | + ->setValue('uid_initiator', $qb->createNamedParameter($sharedBy)) |
|
381 | + ->setValue('permissions', $qb->createNamedParameter($permissions)) |
|
382 | + ->setValue('token', $qb->createNamedParameter($token)) |
|
383 | + ->setValue('stime', $qb->createNamedParameter(time())); |
|
384 | + |
|
385 | + /* |
|
386 | 386 | * Added to fix https://github.com/owncloud/core/issues/22215 |
387 | 387 | * Can be removed once we get rid of ajax/share.php |
388 | 388 | */ |
389 | - $qb->setValue('file_target', $qb->createNamedParameter('')); |
|
390 | - |
|
391 | - $qb->execute(); |
|
392 | - $id = $qb->getLastInsertId(); |
|
393 | - |
|
394 | - return (int)$id; |
|
395 | - } |
|
396 | - |
|
397 | - /** |
|
398 | - * Update a share |
|
399 | - * |
|
400 | - * @param IShare $share |
|
401 | - * @return IShare The share object |
|
402 | - */ |
|
403 | - public function update(IShare $share) { |
|
404 | - /* |
|
389 | + $qb->setValue('file_target', $qb->createNamedParameter('')); |
|
390 | + |
|
391 | + $qb->execute(); |
|
392 | + $id = $qb->getLastInsertId(); |
|
393 | + |
|
394 | + return (int)$id; |
|
395 | + } |
|
396 | + |
|
397 | + /** |
|
398 | + * Update a share |
|
399 | + * |
|
400 | + * @param IShare $share |
|
401 | + * @return IShare The share object |
|
402 | + */ |
|
403 | + public function update(IShare $share) { |
|
404 | + /* |
|
405 | 405 | * We allow updating the permissions of federated shares |
406 | 406 | */ |
407 | - $qb = $this->dbConnection->getQueryBuilder(); |
|
408 | - $qb->update('share') |
|
409 | - ->where($qb->expr()->eq('id', $qb->createNamedParameter($share->getId()))) |
|
410 | - ->set('permissions', $qb->createNamedParameter($share->getPermissions())) |
|
411 | - ->set('uid_owner', $qb->createNamedParameter($share->getShareOwner())) |
|
412 | - ->set('uid_initiator', $qb->createNamedParameter($share->getSharedBy())) |
|
413 | - ->execute(); |
|
414 | - |
|
415 | - // send the updated permission to the owner/initiator, if they are not the same |
|
416 | - if ($share->getShareOwner() !== $share->getSharedBy()) { |
|
417 | - $this->sendPermissionUpdate($share); |
|
418 | - } |
|
419 | - |
|
420 | - return $share; |
|
421 | - } |
|
422 | - |
|
423 | - /** |
|
424 | - * send the updated permission to the owner/initiator, if they are not the same |
|
425 | - * |
|
426 | - * @param IShare $share |
|
427 | - * @throws ShareNotFound |
|
428 | - * @throws \OC\HintException |
|
429 | - */ |
|
430 | - protected function sendPermissionUpdate(IShare $share) { |
|
431 | - $remoteId = $this->getRemoteId($share); |
|
432 | - // if the local user is the owner we send the permission change to the initiator |
|
433 | - if ($this->userManager->userExists($share->getShareOwner())) { |
|
434 | - list(, $remote) = $this->addressHandler->splitUserRemote($share->getSharedBy()); |
|
435 | - } else { // ... if not we send the permission change to the owner |
|
436 | - list(, $remote) = $this->addressHandler->splitUserRemote($share->getShareOwner()); |
|
437 | - } |
|
438 | - $this->notifications->sendPermissionChange($remote, $remoteId, $share->getToken(), $share->getPermissions()); |
|
439 | - } |
|
440 | - |
|
441 | - |
|
442 | - /** |
|
443 | - * update successful reShare with the correct token |
|
444 | - * |
|
445 | - * @param int $shareId |
|
446 | - * @param string $token |
|
447 | - */ |
|
448 | - protected function updateSuccessfulReShare($shareId, $token) { |
|
449 | - $query = $this->dbConnection->getQueryBuilder(); |
|
450 | - $query->update('share') |
|
451 | - ->where($query->expr()->eq('id', $query->createNamedParameter($shareId))) |
|
452 | - ->set('token', $query->createNamedParameter($token)) |
|
453 | - ->execute(); |
|
454 | - } |
|
455 | - |
|
456 | - /** |
|
457 | - * store remote ID in federated reShare table |
|
458 | - * |
|
459 | - * @param $shareId |
|
460 | - * @param $remoteId |
|
461 | - */ |
|
462 | - public function storeRemoteId($shareId, $remoteId) { |
|
463 | - $query = $this->dbConnection->getQueryBuilder(); |
|
464 | - $query->insert('federated_reshares') |
|
465 | - ->values( |
|
466 | - [ |
|
467 | - 'share_id' => $query->createNamedParameter($shareId), |
|
468 | - 'remote_id' => $query->createNamedParameter($remoteId), |
|
469 | - ] |
|
470 | - ); |
|
471 | - $query->execute(); |
|
472 | - } |
|
473 | - |
|
474 | - /** |
|
475 | - * get share ID on remote server for federated re-shares |
|
476 | - * |
|
477 | - * @param IShare $share |
|
478 | - * @return int |
|
479 | - * @throws ShareNotFound |
|
480 | - */ |
|
481 | - public function getRemoteId(IShare $share) { |
|
482 | - $query = $this->dbConnection->getQueryBuilder(); |
|
483 | - $query->select('remote_id')->from('federated_reshares') |
|
484 | - ->where($query->expr()->eq('share_id', $query->createNamedParameter((int)$share->getId()))); |
|
485 | - $data = $query->execute()->fetch(); |
|
486 | - |
|
487 | - if (!is_array($data) || !isset($data['remote_id'])) { |
|
488 | - throw new ShareNotFound(); |
|
489 | - } |
|
490 | - |
|
491 | - return (int)$data['remote_id']; |
|
492 | - } |
|
493 | - |
|
494 | - /** |
|
495 | - * @inheritdoc |
|
496 | - */ |
|
497 | - public function move(IShare $share, $recipient) { |
|
498 | - /* |
|
407 | + $qb = $this->dbConnection->getQueryBuilder(); |
|
408 | + $qb->update('share') |
|
409 | + ->where($qb->expr()->eq('id', $qb->createNamedParameter($share->getId()))) |
|
410 | + ->set('permissions', $qb->createNamedParameter($share->getPermissions())) |
|
411 | + ->set('uid_owner', $qb->createNamedParameter($share->getShareOwner())) |
|
412 | + ->set('uid_initiator', $qb->createNamedParameter($share->getSharedBy())) |
|
413 | + ->execute(); |
|
414 | + |
|
415 | + // send the updated permission to the owner/initiator, if they are not the same |
|
416 | + if ($share->getShareOwner() !== $share->getSharedBy()) { |
|
417 | + $this->sendPermissionUpdate($share); |
|
418 | + } |
|
419 | + |
|
420 | + return $share; |
|
421 | + } |
|
422 | + |
|
423 | + /** |
|
424 | + * send the updated permission to the owner/initiator, if they are not the same |
|
425 | + * |
|
426 | + * @param IShare $share |
|
427 | + * @throws ShareNotFound |
|
428 | + * @throws \OC\HintException |
|
429 | + */ |
|
430 | + protected function sendPermissionUpdate(IShare $share) { |
|
431 | + $remoteId = $this->getRemoteId($share); |
|
432 | + // if the local user is the owner we send the permission change to the initiator |
|
433 | + if ($this->userManager->userExists($share->getShareOwner())) { |
|
434 | + list(, $remote) = $this->addressHandler->splitUserRemote($share->getSharedBy()); |
|
435 | + } else { // ... if not we send the permission change to the owner |
|
436 | + list(, $remote) = $this->addressHandler->splitUserRemote($share->getShareOwner()); |
|
437 | + } |
|
438 | + $this->notifications->sendPermissionChange($remote, $remoteId, $share->getToken(), $share->getPermissions()); |
|
439 | + } |
|
440 | + |
|
441 | + |
|
442 | + /** |
|
443 | + * update successful reShare with the correct token |
|
444 | + * |
|
445 | + * @param int $shareId |
|
446 | + * @param string $token |
|
447 | + */ |
|
448 | + protected function updateSuccessfulReShare($shareId, $token) { |
|
449 | + $query = $this->dbConnection->getQueryBuilder(); |
|
450 | + $query->update('share') |
|
451 | + ->where($query->expr()->eq('id', $query->createNamedParameter($shareId))) |
|
452 | + ->set('token', $query->createNamedParameter($token)) |
|
453 | + ->execute(); |
|
454 | + } |
|
455 | + |
|
456 | + /** |
|
457 | + * store remote ID in federated reShare table |
|
458 | + * |
|
459 | + * @param $shareId |
|
460 | + * @param $remoteId |
|
461 | + */ |
|
462 | + public function storeRemoteId($shareId, $remoteId) { |
|
463 | + $query = $this->dbConnection->getQueryBuilder(); |
|
464 | + $query->insert('federated_reshares') |
|
465 | + ->values( |
|
466 | + [ |
|
467 | + 'share_id' => $query->createNamedParameter($shareId), |
|
468 | + 'remote_id' => $query->createNamedParameter($remoteId), |
|
469 | + ] |
|
470 | + ); |
|
471 | + $query->execute(); |
|
472 | + } |
|
473 | + |
|
474 | + /** |
|
475 | + * get share ID on remote server for federated re-shares |
|
476 | + * |
|
477 | + * @param IShare $share |
|
478 | + * @return int |
|
479 | + * @throws ShareNotFound |
|
480 | + */ |
|
481 | + public function getRemoteId(IShare $share) { |
|
482 | + $query = $this->dbConnection->getQueryBuilder(); |
|
483 | + $query->select('remote_id')->from('federated_reshares') |
|
484 | + ->where($query->expr()->eq('share_id', $query->createNamedParameter((int)$share->getId()))); |
|
485 | + $data = $query->execute()->fetch(); |
|
486 | + |
|
487 | + if (!is_array($data) || !isset($data['remote_id'])) { |
|
488 | + throw new ShareNotFound(); |
|
489 | + } |
|
490 | + |
|
491 | + return (int)$data['remote_id']; |
|
492 | + } |
|
493 | + |
|
494 | + /** |
|
495 | + * @inheritdoc |
|
496 | + */ |
|
497 | + public function move(IShare $share, $recipient) { |
|
498 | + /* |
|
499 | 499 | * This function does nothing yet as it is just for outgoing |
500 | 500 | * federated shares. |
501 | 501 | */ |
502 | - return $share; |
|
503 | - } |
|
504 | - |
|
505 | - /** |
|
506 | - * Get all children of this share |
|
507 | - * |
|
508 | - * @param IShare $parent |
|
509 | - * @return IShare[] |
|
510 | - */ |
|
511 | - public function getChildren(IShare $parent) { |
|
512 | - $children = []; |
|
513 | - |
|
514 | - $qb = $this->dbConnection->getQueryBuilder(); |
|
515 | - $qb->select('*') |
|
516 | - ->from('share') |
|
517 | - ->where($qb->expr()->eq('parent', $qb->createNamedParameter($parent->getId()))) |
|
518 | - ->andWhere($qb->expr()->in('share_type', $qb->createNamedParameter($this->supportedShareType, IQueryBuilder::PARAM_INT_ARRAY))) |
|
519 | - ->orderBy('id'); |
|
520 | - |
|
521 | - $cursor = $qb->execute(); |
|
522 | - while($data = $cursor->fetch()) { |
|
523 | - $children[] = $this->createShareObject($data); |
|
524 | - } |
|
525 | - $cursor->closeCursor(); |
|
526 | - |
|
527 | - return $children; |
|
528 | - } |
|
529 | - |
|
530 | - /** |
|
531 | - * Delete a share (owner unShares the file) |
|
532 | - * |
|
533 | - * @param IShare $share |
|
534 | - * @throws ShareNotFound |
|
535 | - * @throws \OC\HintException |
|
536 | - */ |
|
537 | - public function delete(IShare $share) { |
|
538 | - |
|
539 | - list(, $remote) = $this->addressHandler->splitUserRemote($share->getSharedWith()); |
|
540 | - |
|
541 | - // if the local user is the owner we can send the unShare request directly... |
|
542 | - if ($this->userManager->userExists($share->getShareOwner())) { |
|
543 | - $this->notifications->sendRemoteUnShare($remote, $share->getId(), $share->getToken()); |
|
544 | - $this->revokeShare($share, true); |
|
545 | - } else { // ... if not we need to correct ID for the unShare request |
|
546 | - $remoteId = $this->getRemoteId($share); |
|
547 | - $this->notifications->sendRemoteUnShare($remote, $remoteId, $share->getToken()); |
|
548 | - $this->revokeShare($share, false); |
|
549 | - } |
|
550 | - |
|
551 | - // only remove the share when all messages are send to not lose information |
|
552 | - // about the share to early |
|
553 | - $this->removeShareFromTable($share); |
|
554 | - } |
|
555 | - |
|
556 | - /** |
|
557 | - * in case of a re-share we need to send the other use (initiator or owner) |
|
558 | - * a message that the file was unshared |
|
559 | - * |
|
560 | - * @param IShare $share |
|
561 | - * @param bool $isOwner the user can either be the owner or the user who re-sahred it |
|
562 | - * @throws ShareNotFound |
|
563 | - * @throws \OC\HintException |
|
564 | - */ |
|
565 | - protected function revokeShare($share, $isOwner) { |
|
566 | - // also send a unShare request to the initiator, if this is a different user than the owner |
|
567 | - if ($share->getShareOwner() !== $share->getSharedBy()) { |
|
568 | - if ($isOwner) { |
|
569 | - list(, $remote) = $this->addressHandler->splitUserRemote($share->getSharedBy()); |
|
570 | - } else { |
|
571 | - list(, $remote) = $this->addressHandler->splitUserRemote($share->getShareOwner()); |
|
572 | - } |
|
573 | - $remoteId = $this->getRemoteId($share); |
|
574 | - $this->notifications->sendRevokeShare($remote, $remoteId, $share->getToken()); |
|
575 | - } |
|
576 | - } |
|
577 | - |
|
578 | - /** |
|
579 | - * remove share from table |
|
580 | - * |
|
581 | - * @param IShare $share |
|
582 | - */ |
|
583 | - public function removeShareFromTable(IShare $share) { |
|
584 | - $this->removeShareFromTableById($share->getId()); |
|
585 | - } |
|
586 | - |
|
587 | - /** |
|
588 | - * remove share from table |
|
589 | - * |
|
590 | - * @param string $shareId |
|
591 | - */ |
|
592 | - private function removeShareFromTableById($shareId) { |
|
593 | - $qb = $this->dbConnection->getQueryBuilder(); |
|
594 | - $qb->delete('share') |
|
595 | - ->where($qb->expr()->eq('id', $qb->createNamedParameter($shareId))); |
|
596 | - $qb->execute(); |
|
597 | - |
|
598 | - $qb->delete('federated_reshares') |
|
599 | - ->where($qb->expr()->eq('share_id', $qb->createNamedParameter($shareId))); |
|
600 | - $qb->execute(); |
|
601 | - } |
|
602 | - |
|
603 | - /** |
|
604 | - * @inheritdoc |
|
605 | - */ |
|
606 | - public function deleteFromSelf(IShare $share, $recipient) { |
|
607 | - // nothing to do here. Technically deleteFromSelf in the context of federated |
|
608 | - // shares is a umount of a external storage. This is handled here |
|
609 | - // apps/files_sharing/lib/external/manager.php |
|
610 | - // TODO move this code over to this app |
|
611 | - } |
|
612 | - |
|
613 | - public function restore(IShare $share, string $recipient): IShare { |
|
614 | - throw new GenericShareException('not implemented'); |
|
615 | - } |
|
616 | - |
|
617 | - |
|
618 | - public function getSharesInFolder($userId, Folder $node, $reshares) { |
|
619 | - $qb = $this->dbConnection->getQueryBuilder(); |
|
620 | - $qb->select('*') |
|
621 | - ->from('share', 's') |
|
622 | - ->andWhere($qb->expr()->orX( |
|
623 | - $qb->expr()->eq('item_type', $qb->createNamedParameter('file')), |
|
624 | - $qb->expr()->eq('item_type', $qb->createNamedParameter('folder')) |
|
625 | - )) |
|
626 | - ->andWhere( |
|
627 | - $qb->expr()->eq('share_type', $qb->createNamedParameter(\OCP\Share::SHARE_TYPE_REMOTE)) |
|
628 | - ); |
|
629 | - |
|
630 | - /** |
|
631 | - * Reshares for this user are shares where they are the owner. |
|
632 | - */ |
|
633 | - if ($reshares === false) { |
|
634 | - $qb->andWhere($qb->expr()->eq('uid_initiator', $qb->createNamedParameter($userId))); |
|
635 | - } else { |
|
636 | - $qb->andWhere( |
|
637 | - $qb->expr()->orX( |
|
638 | - $qb->expr()->eq('uid_owner', $qb->createNamedParameter($userId)), |
|
639 | - $qb->expr()->eq('uid_initiator', $qb->createNamedParameter($userId)) |
|
640 | - ) |
|
641 | - ); |
|
642 | - } |
|
643 | - |
|
644 | - $qb->innerJoin('s', 'filecache' ,'f', $qb->expr()->eq('s.file_source', 'f.fileid')); |
|
645 | - $qb->andWhere($qb->expr()->eq('f.parent', $qb->createNamedParameter($node->getId()))); |
|
646 | - |
|
647 | - $qb->orderBy('id'); |
|
648 | - |
|
649 | - $cursor = $qb->execute(); |
|
650 | - $shares = []; |
|
651 | - while ($data = $cursor->fetch()) { |
|
652 | - $shares[$data['fileid']][] = $this->createShareObject($data); |
|
653 | - } |
|
654 | - $cursor->closeCursor(); |
|
655 | - |
|
656 | - return $shares; |
|
657 | - } |
|
658 | - |
|
659 | - /** |
|
660 | - * @inheritdoc |
|
661 | - */ |
|
662 | - public function getSharesBy($userId, $shareType, $node, $reshares, $limit, $offset) { |
|
663 | - $qb = $this->dbConnection->getQueryBuilder(); |
|
664 | - $qb->select('*') |
|
665 | - ->from('share'); |
|
666 | - |
|
667 | - $qb->andWhere($qb->expr()->eq('share_type', $qb->createNamedParameter($shareType))); |
|
668 | - |
|
669 | - /** |
|
670 | - * Reshares for this user are shares where they are the owner. |
|
671 | - */ |
|
672 | - if ($reshares === false) { |
|
673 | - //Special case for old shares created via the web UI |
|
674 | - $or1 = $qb->expr()->andX( |
|
675 | - $qb->expr()->eq('uid_owner', $qb->createNamedParameter($userId)), |
|
676 | - $qb->expr()->isNull('uid_initiator') |
|
677 | - ); |
|
678 | - |
|
679 | - $qb->andWhere( |
|
680 | - $qb->expr()->orX( |
|
681 | - $qb->expr()->eq('uid_initiator', $qb->createNamedParameter($userId)), |
|
682 | - $or1 |
|
683 | - ) |
|
684 | - ); |
|
685 | - } else { |
|
686 | - $qb->andWhere( |
|
687 | - $qb->expr()->orX( |
|
688 | - $qb->expr()->eq('uid_owner', $qb->createNamedParameter($userId)), |
|
689 | - $qb->expr()->eq('uid_initiator', $qb->createNamedParameter($userId)) |
|
690 | - ) |
|
691 | - ); |
|
692 | - } |
|
693 | - |
|
694 | - if ($node !== null) { |
|
695 | - $qb->andWhere($qb->expr()->eq('file_source', $qb->createNamedParameter($node->getId()))); |
|
696 | - } |
|
697 | - |
|
698 | - if ($limit !== -1) { |
|
699 | - $qb->setMaxResults($limit); |
|
700 | - } |
|
701 | - |
|
702 | - $qb->setFirstResult($offset); |
|
703 | - $qb->orderBy('id'); |
|
704 | - |
|
705 | - $cursor = $qb->execute(); |
|
706 | - $shares = []; |
|
707 | - while($data = $cursor->fetch()) { |
|
708 | - $shares[] = $this->createShareObject($data); |
|
709 | - } |
|
710 | - $cursor->closeCursor(); |
|
711 | - |
|
712 | - return $shares; |
|
713 | - } |
|
714 | - |
|
715 | - /** |
|
716 | - * @inheritdoc |
|
717 | - */ |
|
718 | - public function getShareById($id, $recipientId = null) { |
|
719 | - $qb = $this->dbConnection->getQueryBuilder(); |
|
720 | - |
|
721 | - $qb->select('*') |
|
722 | - ->from('share') |
|
723 | - ->where($qb->expr()->eq('id', $qb->createNamedParameter($id))) |
|
724 | - ->andWhere($qb->expr()->in('share_type', $qb->createNamedParameter($this->supportedShareType, IQueryBuilder::PARAM_INT_ARRAY))); |
|
725 | - |
|
726 | - $cursor = $qb->execute(); |
|
727 | - $data = $cursor->fetch(); |
|
728 | - $cursor->closeCursor(); |
|
729 | - |
|
730 | - if ($data === false) { |
|
731 | - throw new ShareNotFound('Can not find share with ID: ' . $id); |
|
732 | - } |
|
733 | - |
|
734 | - try { |
|
735 | - $share = $this->createShareObject($data); |
|
736 | - } catch (InvalidShare $e) { |
|
737 | - throw new ShareNotFound(); |
|
738 | - } |
|
739 | - |
|
740 | - return $share; |
|
741 | - } |
|
742 | - |
|
743 | - /** |
|
744 | - * Get shares for a given path |
|
745 | - * |
|
746 | - * @param \OCP\Files\Node $path |
|
747 | - * @return IShare[] |
|
748 | - */ |
|
749 | - public function getSharesByPath(Node $path) { |
|
750 | - $qb = $this->dbConnection->getQueryBuilder(); |
|
751 | - |
|
752 | - // get federated user shares |
|
753 | - $cursor = $qb->select('*') |
|
754 | - ->from('share') |
|
755 | - ->andWhere($qb->expr()->eq('file_source', $qb->createNamedParameter($path->getId()))) |
|
756 | - ->andWhere($qb->expr()->in('share_type', $qb->createNamedParameter($this->supportedShareType, IQueryBuilder::PARAM_INT_ARRAY))) |
|
757 | - ->execute(); |
|
758 | - |
|
759 | - $shares = []; |
|
760 | - while($data = $cursor->fetch()) { |
|
761 | - $shares[] = $this->createShareObject($data); |
|
762 | - } |
|
763 | - $cursor->closeCursor(); |
|
764 | - |
|
765 | - return $shares; |
|
766 | - } |
|
767 | - |
|
768 | - /** |
|
769 | - * @inheritdoc |
|
770 | - */ |
|
771 | - public function getSharedWith($userId, $shareType, $node, $limit, $offset) { |
|
772 | - /** @var IShare[] $shares */ |
|
773 | - $shares = []; |
|
774 | - |
|
775 | - //Get shares directly with this user |
|
776 | - $qb = $this->dbConnection->getQueryBuilder(); |
|
777 | - $qb->select('*') |
|
778 | - ->from('share'); |
|
779 | - |
|
780 | - // Order by id |
|
781 | - $qb->orderBy('id'); |
|
782 | - |
|
783 | - // Set limit and offset |
|
784 | - if ($limit !== -1) { |
|
785 | - $qb->setMaxResults($limit); |
|
786 | - } |
|
787 | - $qb->setFirstResult($offset); |
|
788 | - |
|
789 | - $qb->where($qb->expr()->in('share_type', $qb->createNamedParameter($this->supportedShareType, IQueryBuilder::PARAM_INT_ARRAY))); |
|
790 | - $qb->andWhere($qb->expr()->eq('share_with', $qb->createNamedParameter($userId))); |
|
791 | - |
|
792 | - // Filter by node if provided |
|
793 | - if ($node !== null) { |
|
794 | - $qb->andWhere($qb->expr()->eq('file_source', $qb->createNamedParameter($node->getId()))); |
|
795 | - } |
|
796 | - |
|
797 | - $cursor = $qb->execute(); |
|
798 | - |
|
799 | - while($data = $cursor->fetch()) { |
|
800 | - $shares[] = $this->createShareObject($data); |
|
801 | - } |
|
802 | - $cursor->closeCursor(); |
|
803 | - |
|
804 | - |
|
805 | - return $shares; |
|
806 | - } |
|
807 | - |
|
808 | - /** |
|
809 | - * Get a share by token |
|
810 | - * |
|
811 | - * @param string $token |
|
812 | - * @return IShare |
|
813 | - * @throws ShareNotFound |
|
814 | - */ |
|
815 | - public function getShareByToken($token) { |
|
816 | - $qb = $this->dbConnection->getQueryBuilder(); |
|
817 | - |
|
818 | - $cursor = $qb->select('*') |
|
819 | - ->from('share') |
|
820 | - ->where($qb->expr()->in('share_type', $qb->createNamedParameter($this->supportedShareType, IQueryBuilder::PARAM_INT_ARRAY))) |
|
821 | - ->andWhere($qb->expr()->eq('token', $qb->createNamedParameter($token))) |
|
822 | - ->execute(); |
|
823 | - |
|
824 | - $data = $cursor->fetch(); |
|
825 | - |
|
826 | - if ($data === false) { |
|
827 | - throw new ShareNotFound('Share not found', $this->l->t('Could not find share')); |
|
828 | - } |
|
829 | - |
|
830 | - try { |
|
831 | - $share = $this->createShareObject($data); |
|
832 | - } catch (InvalidShare $e) { |
|
833 | - throw new ShareNotFound('Share not found', $this->l->t('Could not find share')); |
|
834 | - } |
|
835 | - |
|
836 | - return $share; |
|
837 | - } |
|
838 | - |
|
839 | - /** |
|
840 | - * get database row of a give share |
|
841 | - * |
|
842 | - * @param $id |
|
843 | - * @return array |
|
844 | - * @throws ShareNotFound |
|
845 | - */ |
|
846 | - private function getRawShare($id) { |
|
847 | - |
|
848 | - // Now fetch the inserted share and create a complete share object |
|
849 | - $qb = $this->dbConnection->getQueryBuilder(); |
|
850 | - $qb->select('*') |
|
851 | - ->from('share') |
|
852 | - ->where($qb->expr()->eq('id', $qb->createNamedParameter($id))); |
|
853 | - |
|
854 | - $cursor = $qb->execute(); |
|
855 | - $data = $cursor->fetch(); |
|
856 | - $cursor->closeCursor(); |
|
857 | - |
|
858 | - if ($data === false) { |
|
859 | - throw new ShareNotFound; |
|
860 | - } |
|
861 | - |
|
862 | - return $data; |
|
863 | - } |
|
864 | - |
|
865 | - /** |
|
866 | - * Create a share object from an database row |
|
867 | - * |
|
868 | - * @param array $data |
|
869 | - * @return IShare |
|
870 | - * @throws InvalidShare |
|
871 | - * @throws ShareNotFound |
|
872 | - */ |
|
873 | - private function createShareObject($data) { |
|
874 | - |
|
875 | - $share = new Share($this->rootFolder, $this->userManager); |
|
876 | - $share->setId((int)$data['id']) |
|
877 | - ->setShareType((int)$data['share_type']) |
|
878 | - ->setPermissions((int)$data['permissions']) |
|
879 | - ->setTarget($data['file_target']) |
|
880 | - ->setMailSend((bool)$data['mail_send']) |
|
881 | - ->setToken($data['token']); |
|
882 | - |
|
883 | - $shareTime = new \DateTime(); |
|
884 | - $shareTime->setTimestamp((int)$data['stime']); |
|
885 | - $share->setShareTime($shareTime); |
|
886 | - $share->setSharedWith($data['share_with']); |
|
887 | - |
|
888 | - if ($data['uid_initiator'] !== null) { |
|
889 | - $share->setShareOwner($data['uid_owner']); |
|
890 | - $share->setSharedBy($data['uid_initiator']); |
|
891 | - } else { |
|
892 | - //OLD SHARE |
|
893 | - $share->setSharedBy($data['uid_owner']); |
|
894 | - $path = $this->getNode($share->getSharedBy(), (int)$data['file_source']); |
|
895 | - |
|
896 | - $owner = $path->getOwner(); |
|
897 | - $share->setShareOwner($owner->getUID()); |
|
898 | - } |
|
899 | - |
|
900 | - $share->setNodeId((int)$data['file_source']); |
|
901 | - $share->setNodeType($data['item_type']); |
|
902 | - |
|
903 | - $share->setProviderId($this->identifier()); |
|
904 | - |
|
905 | - return $share; |
|
906 | - } |
|
907 | - |
|
908 | - /** |
|
909 | - * Get the node with file $id for $user |
|
910 | - * |
|
911 | - * @param string $userId |
|
912 | - * @param int $id |
|
913 | - * @return \OCP\Files\File|\OCP\Files\Folder |
|
914 | - * @throws InvalidShare |
|
915 | - */ |
|
916 | - private function getNode($userId, $id) { |
|
917 | - try { |
|
918 | - $userFolder = $this->rootFolder->getUserFolder($userId); |
|
919 | - } catch (NotFoundException $e) { |
|
920 | - throw new InvalidShare(); |
|
921 | - } |
|
922 | - |
|
923 | - $nodes = $userFolder->getById($id); |
|
924 | - |
|
925 | - if (empty($nodes)) { |
|
926 | - throw new InvalidShare(); |
|
927 | - } |
|
928 | - |
|
929 | - return $nodes[0]; |
|
930 | - } |
|
931 | - |
|
932 | - /** |
|
933 | - * A user is deleted from the system |
|
934 | - * So clean up the relevant shares. |
|
935 | - * |
|
936 | - * @param string $uid |
|
937 | - * @param int $shareType |
|
938 | - */ |
|
939 | - public function userDeleted($uid, $shareType) { |
|
940 | - //TODO: probabaly a good idea to send unshare info to remote servers |
|
941 | - |
|
942 | - $qb = $this->dbConnection->getQueryBuilder(); |
|
943 | - |
|
944 | - $qb->delete('share') |
|
945 | - ->where($qb->expr()->eq('share_type', $qb->createNamedParameter(\OCP\Share::SHARE_TYPE_REMOTE))) |
|
946 | - ->andWhere($qb->expr()->eq('uid_owner', $qb->createNamedParameter($uid))) |
|
947 | - ->execute(); |
|
948 | - } |
|
949 | - |
|
950 | - /** |
|
951 | - * This provider does not handle groups |
|
952 | - * |
|
953 | - * @param string $gid |
|
954 | - */ |
|
955 | - public function groupDeleted($gid) { |
|
956 | - // We don't handle groups here |
|
957 | - } |
|
958 | - |
|
959 | - /** |
|
960 | - * This provider does not handle groups |
|
961 | - * |
|
962 | - * @param string $uid |
|
963 | - * @param string $gid |
|
964 | - */ |
|
965 | - public function userDeletedFromGroup($uid, $gid) { |
|
966 | - // We don't handle groups here |
|
967 | - } |
|
968 | - |
|
969 | - /** |
|
970 | - * check if users from other Nextcloud instances are allowed to mount public links share by this instance |
|
971 | - * |
|
972 | - * @return bool |
|
973 | - */ |
|
974 | - public function isOutgoingServer2serverShareEnabled() { |
|
975 | - if ($this->gsConfig->onlyInternalFederation()) { |
|
976 | - return false; |
|
977 | - } |
|
978 | - $result = $this->config->getAppValue('files_sharing', 'outgoing_server2server_share_enabled', 'yes'); |
|
979 | - return ($result === 'yes'); |
|
980 | - } |
|
981 | - |
|
982 | - /** |
|
983 | - * check if users are allowed to mount public links from other Nextclouds |
|
984 | - * |
|
985 | - * @return bool |
|
986 | - */ |
|
987 | - public function isIncomingServer2serverShareEnabled() { |
|
988 | - if ($this->gsConfig->onlyInternalFederation()) { |
|
989 | - return false; |
|
990 | - } |
|
991 | - $result = $this->config->getAppValue('files_sharing', 'incoming_server2server_share_enabled', 'yes'); |
|
992 | - return ($result === 'yes'); |
|
993 | - } |
|
994 | - |
|
995 | - |
|
996 | - /** |
|
997 | - * check if users from other Nextcloud instances are allowed to send federated group shares |
|
998 | - * |
|
999 | - * @return bool |
|
1000 | - */ |
|
1001 | - public function isOutgoingServer2serverGroupShareEnabled() { |
|
1002 | - if ($this->gsConfig->onlyInternalFederation()) { |
|
1003 | - return false; |
|
1004 | - } |
|
1005 | - $result = $this->config->getAppValue('files_sharing', 'outgoing_server2server_group_share_enabled', 'no'); |
|
1006 | - return ($result === 'yes'); |
|
1007 | - } |
|
1008 | - |
|
1009 | - /** |
|
1010 | - * check if users are allowed to receive federated group shares |
|
1011 | - * |
|
1012 | - * @return bool |
|
1013 | - */ |
|
1014 | - public function isIncomingServer2serverGroupShareEnabled() { |
|
1015 | - if ($this->gsConfig->onlyInternalFederation()) { |
|
1016 | - return false; |
|
1017 | - } |
|
1018 | - $result = $this->config->getAppValue('files_sharing', 'incoming_server2server_group_share_enabled', 'no'); |
|
1019 | - return ($result === 'yes'); |
|
1020 | - } |
|
1021 | - |
|
1022 | - /** |
|
1023 | - * check if federated group sharing is supported, therefore the OCM API need to be enabled |
|
1024 | - * |
|
1025 | - * @return bool |
|
1026 | - */ |
|
1027 | - public function isFederatedGroupSharingSupported() { |
|
1028 | - return $this->cloudFederationProviderManager->isReady(); |
|
1029 | - } |
|
1030 | - |
|
1031 | - /** |
|
1032 | - * Check if querying sharees on the lookup server is enabled |
|
1033 | - * |
|
1034 | - * @return bool |
|
1035 | - */ |
|
1036 | - public function isLookupServerQueriesEnabled() { |
|
1037 | - // in a global scale setup we should always query the lookup server |
|
1038 | - if ($this->gsConfig->isGlobalScaleEnabled()) { |
|
1039 | - return true; |
|
1040 | - } |
|
1041 | - $result = $this->config->getAppValue('files_sharing', 'lookupServerEnabled', 'no'); |
|
1042 | - return ($result === 'yes'); |
|
1043 | - } |
|
1044 | - |
|
1045 | - |
|
1046 | - /** |
|
1047 | - * Check if it is allowed to publish user specific data to the lookup server |
|
1048 | - * |
|
1049 | - * @return bool |
|
1050 | - */ |
|
1051 | - public function isLookupServerUploadEnabled() { |
|
1052 | - // in a global scale setup the admin is responsible to keep the lookup server up-to-date |
|
1053 | - if ($this->gsConfig->isGlobalScaleEnabled()) { |
|
1054 | - return false; |
|
1055 | - } |
|
1056 | - $result = $this->config->getAppValue('files_sharing', 'lookupServerUploadEnabled', 'yes'); |
|
1057 | - return ($result === 'yes'); |
|
1058 | - } |
|
1059 | - |
|
1060 | - /** |
|
1061 | - * @inheritdoc |
|
1062 | - */ |
|
1063 | - public function getAccessList($nodes, $currentAccess) { |
|
1064 | - $ids = []; |
|
1065 | - foreach ($nodes as $node) { |
|
1066 | - $ids[] = $node->getId(); |
|
1067 | - } |
|
1068 | - |
|
1069 | - $qb = $this->dbConnection->getQueryBuilder(); |
|
1070 | - $qb->select('share_with', 'token', 'file_source') |
|
1071 | - ->from('share') |
|
1072 | - ->where($qb->expr()->eq('share_type', $qb->createNamedParameter(\OCP\Share::SHARE_TYPE_REMOTE))) |
|
1073 | - ->andWhere($qb->expr()->in('file_source', $qb->createNamedParameter($ids, IQueryBuilder::PARAM_INT_ARRAY))) |
|
1074 | - ->andWhere($qb->expr()->orX( |
|
1075 | - $qb->expr()->eq('item_type', $qb->createNamedParameter('file')), |
|
1076 | - $qb->expr()->eq('item_type', $qb->createNamedParameter('folder')) |
|
1077 | - )); |
|
1078 | - $cursor = $qb->execute(); |
|
1079 | - |
|
1080 | - if ($currentAccess === false) { |
|
1081 | - $remote = $cursor->fetch() !== false; |
|
1082 | - $cursor->closeCursor(); |
|
1083 | - |
|
1084 | - return ['remote' => $remote]; |
|
1085 | - } |
|
1086 | - |
|
1087 | - $remote = []; |
|
1088 | - while ($row = $cursor->fetch()) { |
|
1089 | - $remote[$row['share_with']] = [ |
|
1090 | - 'node_id' => $row['file_source'], |
|
1091 | - 'token' => $row['token'], |
|
1092 | - ]; |
|
1093 | - } |
|
1094 | - $cursor->closeCursor(); |
|
1095 | - |
|
1096 | - return ['remote' => $remote]; |
|
1097 | - } |
|
502 | + return $share; |
|
503 | + } |
|
504 | + |
|
505 | + /** |
|
506 | + * Get all children of this share |
|
507 | + * |
|
508 | + * @param IShare $parent |
|
509 | + * @return IShare[] |
|
510 | + */ |
|
511 | + public function getChildren(IShare $parent) { |
|
512 | + $children = []; |
|
513 | + |
|
514 | + $qb = $this->dbConnection->getQueryBuilder(); |
|
515 | + $qb->select('*') |
|
516 | + ->from('share') |
|
517 | + ->where($qb->expr()->eq('parent', $qb->createNamedParameter($parent->getId()))) |
|
518 | + ->andWhere($qb->expr()->in('share_type', $qb->createNamedParameter($this->supportedShareType, IQueryBuilder::PARAM_INT_ARRAY))) |
|
519 | + ->orderBy('id'); |
|
520 | + |
|
521 | + $cursor = $qb->execute(); |
|
522 | + while($data = $cursor->fetch()) { |
|
523 | + $children[] = $this->createShareObject($data); |
|
524 | + } |
|
525 | + $cursor->closeCursor(); |
|
526 | + |
|
527 | + return $children; |
|
528 | + } |
|
529 | + |
|
530 | + /** |
|
531 | + * Delete a share (owner unShares the file) |
|
532 | + * |
|
533 | + * @param IShare $share |
|
534 | + * @throws ShareNotFound |
|
535 | + * @throws \OC\HintException |
|
536 | + */ |
|
537 | + public function delete(IShare $share) { |
|
538 | + |
|
539 | + list(, $remote) = $this->addressHandler->splitUserRemote($share->getSharedWith()); |
|
540 | + |
|
541 | + // if the local user is the owner we can send the unShare request directly... |
|
542 | + if ($this->userManager->userExists($share->getShareOwner())) { |
|
543 | + $this->notifications->sendRemoteUnShare($remote, $share->getId(), $share->getToken()); |
|
544 | + $this->revokeShare($share, true); |
|
545 | + } else { // ... if not we need to correct ID for the unShare request |
|
546 | + $remoteId = $this->getRemoteId($share); |
|
547 | + $this->notifications->sendRemoteUnShare($remote, $remoteId, $share->getToken()); |
|
548 | + $this->revokeShare($share, false); |
|
549 | + } |
|
550 | + |
|
551 | + // only remove the share when all messages are send to not lose information |
|
552 | + // about the share to early |
|
553 | + $this->removeShareFromTable($share); |
|
554 | + } |
|
555 | + |
|
556 | + /** |
|
557 | + * in case of a re-share we need to send the other use (initiator or owner) |
|
558 | + * a message that the file was unshared |
|
559 | + * |
|
560 | + * @param IShare $share |
|
561 | + * @param bool $isOwner the user can either be the owner or the user who re-sahred it |
|
562 | + * @throws ShareNotFound |
|
563 | + * @throws \OC\HintException |
|
564 | + */ |
|
565 | + protected function revokeShare($share, $isOwner) { |
|
566 | + // also send a unShare request to the initiator, if this is a different user than the owner |
|
567 | + if ($share->getShareOwner() !== $share->getSharedBy()) { |
|
568 | + if ($isOwner) { |
|
569 | + list(, $remote) = $this->addressHandler->splitUserRemote($share->getSharedBy()); |
|
570 | + } else { |
|
571 | + list(, $remote) = $this->addressHandler->splitUserRemote($share->getShareOwner()); |
|
572 | + } |
|
573 | + $remoteId = $this->getRemoteId($share); |
|
574 | + $this->notifications->sendRevokeShare($remote, $remoteId, $share->getToken()); |
|
575 | + } |
|
576 | + } |
|
577 | + |
|
578 | + /** |
|
579 | + * remove share from table |
|
580 | + * |
|
581 | + * @param IShare $share |
|
582 | + */ |
|
583 | + public function removeShareFromTable(IShare $share) { |
|
584 | + $this->removeShareFromTableById($share->getId()); |
|
585 | + } |
|
586 | + |
|
587 | + /** |
|
588 | + * remove share from table |
|
589 | + * |
|
590 | + * @param string $shareId |
|
591 | + */ |
|
592 | + private function removeShareFromTableById($shareId) { |
|
593 | + $qb = $this->dbConnection->getQueryBuilder(); |
|
594 | + $qb->delete('share') |
|
595 | + ->where($qb->expr()->eq('id', $qb->createNamedParameter($shareId))); |
|
596 | + $qb->execute(); |
|
597 | + |
|
598 | + $qb->delete('federated_reshares') |
|
599 | + ->where($qb->expr()->eq('share_id', $qb->createNamedParameter($shareId))); |
|
600 | + $qb->execute(); |
|
601 | + } |
|
602 | + |
|
603 | + /** |
|
604 | + * @inheritdoc |
|
605 | + */ |
|
606 | + public function deleteFromSelf(IShare $share, $recipient) { |
|
607 | + // nothing to do here. Technically deleteFromSelf in the context of federated |
|
608 | + // shares is a umount of a external storage. This is handled here |
|
609 | + // apps/files_sharing/lib/external/manager.php |
|
610 | + // TODO move this code over to this app |
|
611 | + } |
|
612 | + |
|
613 | + public function restore(IShare $share, string $recipient): IShare { |
|
614 | + throw new GenericShareException('not implemented'); |
|
615 | + } |
|
616 | + |
|
617 | + |
|
618 | + public function getSharesInFolder($userId, Folder $node, $reshares) { |
|
619 | + $qb = $this->dbConnection->getQueryBuilder(); |
|
620 | + $qb->select('*') |
|
621 | + ->from('share', 's') |
|
622 | + ->andWhere($qb->expr()->orX( |
|
623 | + $qb->expr()->eq('item_type', $qb->createNamedParameter('file')), |
|
624 | + $qb->expr()->eq('item_type', $qb->createNamedParameter('folder')) |
|
625 | + )) |
|
626 | + ->andWhere( |
|
627 | + $qb->expr()->eq('share_type', $qb->createNamedParameter(\OCP\Share::SHARE_TYPE_REMOTE)) |
|
628 | + ); |
|
629 | + |
|
630 | + /** |
|
631 | + * Reshares for this user are shares where they are the owner. |
|
632 | + */ |
|
633 | + if ($reshares === false) { |
|
634 | + $qb->andWhere($qb->expr()->eq('uid_initiator', $qb->createNamedParameter($userId))); |
|
635 | + } else { |
|
636 | + $qb->andWhere( |
|
637 | + $qb->expr()->orX( |
|
638 | + $qb->expr()->eq('uid_owner', $qb->createNamedParameter($userId)), |
|
639 | + $qb->expr()->eq('uid_initiator', $qb->createNamedParameter($userId)) |
|
640 | + ) |
|
641 | + ); |
|
642 | + } |
|
643 | + |
|
644 | + $qb->innerJoin('s', 'filecache' ,'f', $qb->expr()->eq('s.file_source', 'f.fileid')); |
|
645 | + $qb->andWhere($qb->expr()->eq('f.parent', $qb->createNamedParameter($node->getId()))); |
|
646 | + |
|
647 | + $qb->orderBy('id'); |
|
648 | + |
|
649 | + $cursor = $qb->execute(); |
|
650 | + $shares = []; |
|
651 | + while ($data = $cursor->fetch()) { |
|
652 | + $shares[$data['fileid']][] = $this->createShareObject($data); |
|
653 | + } |
|
654 | + $cursor->closeCursor(); |
|
655 | + |
|
656 | + return $shares; |
|
657 | + } |
|
658 | + |
|
659 | + /** |
|
660 | + * @inheritdoc |
|
661 | + */ |
|
662 | + public function getSharesBy($userId, $shareType, $node, $reshares, $limit, $offset) { |
|
663 | + $qb = $this->dbConnection->getQueryBuilder(); |
|
664 | + $qb->select('*') |
|
665 | + ->from('share'); |
|
666 | + |
|
667 | + $qb->andWhere($qb->expr()->eq('share_type', $qb->createNamedParameter($shareType))); |
|
668 | + |
|
669 | + /** |
|
670 | + * Reshares for this user are shares where they are the owner. |
|
671 | + */ |
|
672 | + if ($reshares === false) { |
|
673 | + //Special case for old shares created via the web UI |
|
674 | + $or1 = $qb->expr()->andX( |
|
675 | + $qb->expr()->eq('uid_owner', $qb->createNamedParameter($userId)), |
|
676 | + $qb->expr()->isNull('uid_initiator') |
|
677 | + ); |
|
678 | + |
|
679 | + $qb->andWhere( |
|
680 | + $qb->expr()->orX( |
|
681 | + $qb->expr()->eq('uid_initiator', $qb->createNamedParameter($userId)), |
|
682 | + $or1 |
|
683 | + ) |
|
684 | + ); |
|
685 | + } else { |
|
686 | + $qb->andWhere( |
|
687 | + $qb->expr()->orX( |
|
688 | + $qb->expr()->eq('uid_owner', $qb->createNamedParameter($userId)), |
|
689 | + $qb->expr()->eq('uid_initiator', $qb->createNamedParameter($userId)) |
|
690 | + ) |
|
691 | + ); |
|
692 | + } |
|
693 | + |
|
694 | + if ($node !== null) { |
|
695 | + $qb->andWhere($qb->expr()->eq('file_source', $qb->createNamedParameter($node->getId()))); |
|
696 | + } |
|
697 | + |
|
698 | + if ($limit !== -1) { |
|
699 | + $qb->setMaxResults($limit); |
|
700 | + } |
|
701 | + |
|
702 | + $qb->setFirstResult($offset); |
|
703 | + $qb->orderBy('id'); |
|
704 | + |
|
705 | + $cursor = $qb->execute(); |
|
706 | + $shares = []; |
|
707 | + while($data = $cursor->fetch()) { |
|
708 | + $shares[] = $this->createShareObject($data); |
|
709 | + } |
|
710 | + $cursor->closeCursor(); |
|
711 | + |
|
712 | + return $shares; |
|
713 | + } |
|
714 | + |
|
715 | + /** |
|
716 | + * @inheritdoc |
|
717 | + */ |
|
718 | + public function getShareById($id, $recipientId = null) { |
|
719 | + $qb = $this->dbConnection->getQueryBuilder(); |
|
720 | + |
|
721 | + $qb->select('*') |
|
722 | + ->from('share') |
|
723 | + ->where($qb->expr()->eq('id', $qb->createNamedParameter($id))) |
|
724 | + ->andWhere($qb->expr()->in('share_type', $qb->createNamedParameter($this->supportedShareType, IQueryBuilder::PARAM_INT_ARRAY))); |
|
725 | + |
|
726 | + $cursor = $qb->execute(); |
|
727 | + $data = $cursor->fetch(); |
|
728 | + $cursor->closeCursor(); |
|
729 | + |
|
730 | + if ($data === false) { |
|
731 | + throw new ShareNotFound('Can not find share with ID: ' . $id); |
|
732 | + } |
|
733 | + |
|
734 | + try { |
|
735 | + $share = $this->createShareObject($data); |
|
736 | + } catch (InvalidShare $e) { |
|
737 | + throw new ShareNotFound(); |
|
738 | + } |
|
739 | + |
|
740 | + return $share; |
|
741 | + } |
|
742 | + |
|
743 | + /** |
|
744 | + * Get shares for a given path |
|
745 | + * |
|
746 | + * @param \OCP\Files\Node $path |
|
747 | + * @return IShare[] |
|
748 | + */ |
|
749 | + public function getSharesByPath(Node $path) { |
|
750 | + $qb = $this->dbConnection->getQueryBuilder(); |
|
751 | + |
|
752 | + // get federated user shares |
|
753 | + $cursor = $qb->select('*') |
|
754 | + ->from('share') |
|
755 | + ->andWhere($qb->expr()->eq('file_source', $qb->createNamedParameter($path->getId()))) |
|
756 | + ->andWhere($qb->expr()->in('share_type', $qb->createNamedParameter($this->supportedShareType, IQueryBuilder::PARAM_INT_ARRAY))) |
|
757 | + ->execute(); |
|
758 | + |
|
759 | + $shares = []; |
|
760 | + while($data = $cursor->fetch()) { |
|
761 | + $shares[] = $this->createShareObject($data); |
|
762 | + } |
|
763 | + $cursor->closeCursor(); |
|
764 | + |
|
765 | + return $shares; |
|
766 | + } |
|
767 | + |
|
768 | + /** |
|
769 | + * @inheritdoc |
|
770 | + */ |
|
771 | + public function getSharedWith($userId, $shareType, $node, $limit, $offset) { |
|
772 | + /** @var IShare[] $shares */ |
|
773 | + $shares = []; |
|
774 | + |
|
775 | + //Get shares directly with this user |
|
776 | + $qb = $this->dbConnection->getQueryBuilder(); |
|
777 | + $qb->select('*') |
|
778 | + ->from('share'); |
|
779 | + |
|
780 | + // Order by id |
|
781 | + $qb->orderBy('id'); |
|
782 | + |
|
783 | + // Set limit and offset |
|
784 | + if ($limit !== -1) { |
|
785 | + $qb->setMaxResults($limit); |
|
786 | + } |
|
787 | + $qb->setFirstResult($offset); |
|
788 | + |
|
789 | + $qb->where($qb->expr()->in('share_type', $qb->createNamedParameter($this->supportedShareType, IQueryBuilder::PARAM_INT_ARRAY))); |
|
790 | + $qb->andWhere($qb->expr()->eq('share_with', $qb->createNamedParameter($userId))); |
|
791 | + |
|
792 | + // Filter by node if provided |
|
793 | + if ($node !== null) { |
|
794 | + $qb->andWhere($qb->expr()->eq('file_source', $qb->createNamedParameter($node->getId()))); |
|
795 | + } |
|
796 | + |
|
797 | + $cursor = $qb->execute(); |
|
798 | + |
|
799 | + while($data = $cursor->fetch()) { |
|
800 | + $shares[] = $this->createShareObject($data); |
|
801 | + } |
|
802 | + $cursor->closeCursor(); |
|
803 | + |
|
804 | + |
|
805 | + return $shares; |
|
806 | + } |
|
807 | + |
|
808 | + /** |
|
809 | + * Get a share by token |
|
810 | + * |
|
811 | + * @param string $token |
|
812 | + * @return IShare |
|
813 | + * @throws ShareNotFound |
|
814 | + */ |
|
815 | + public function getShareByToken($token) { |
|
816 | + $qb = $this->dbConnection->getQueryBuilder(); |
|
817 | + |
|
818 | + $cursor = $qb->select('*') |
|
819 | + ->from('share') |
|
820 | + ->where($qb->expr()->in('share_type', $qb->createNamedParameter($this->supportedShareType, IQueryBuilder::PARAM_INT_ARRAY))) |
|
821 | + ->andWhere($qb->expr()->eq('token', $qb->createNamedParameter($token))) |
|
822 | + ->execute(); |
|
823 | + |
|
824 | + $data = $cursor->fetch(); |
|
825 | + |
|
826 | + if ($data === false) { |
|
827 | + throw new ShareNotFound('Share not found', $this->l->t('Could not find share')); |
|
828 | + } |
|
829 | + |
|
830 | + try { |
|
831 | + $share = $this->createShareObject($data); |
|
832 | + } catch (InvalidShare $e) { |
|
833 | + throw new ShareNotFound('Share not found', $this->l->t('Could not find share')); |
|
834 | + } |
|
835 | + |
|
836 | + return $share; |
|
837 | + } |
|
838 | + |
|
839 | + /** |
|
840 | + * get database row of a give share |
|
841 | + * |
|
842 | + * @param $id |
|
843 | + * @return array |
|
844 | + * @throws ShareNotFound |
|
845 | + */ |
|
846 | + private function getRawShare($id) { |
|
847 | + |
|
848 | + // Now fetch the inserted share and create a complete share object |
|
849 | + $qb = $this->dbConnection->getQueryBuilder(); |
|
850 | + $qb->select('*') |
|
851 | + ->from('share') |
|
852 | + ->where($qb->expr()->eq('id', $qb->createNamedParameter($id))); |
|
853 | + |
|
854 | + $cursor = $qb->execute(); |
|
855 | + $data = $cursor->fetch(); |
|
856 | + $cursor->closeCursor(); |
|
857 | + |
|
858 | + if ($data === false) { |
|
859 | + throw new ShareNotFound; |
|
860 | + } |
|
861 | + |
|
862 | + return $data; |
|
863 | + } |
|
864 | + |
|
865 | + /** |
|
866 | + * Create a share object from an database row |
|
867 | + * |
|
868 | + * @param array $data |
|
869 | + * @return IShare |
|
870 | + * @throws InvalidShare |
|
871 | + * @throws ShareNotFound |
|
872 | + */ |
|
873 | + private function createShareObject($data) { |
|
874 | + |
|
875 | + $share = new Share($this->rootFolder, $this->userManager); |
|
876 | + $share->setId((int)$data['id']) |
|
877 | + ->setShareType((int)$data['share_type']) |
|
878 | + ->setPermissions((int)$data['permissions']) |
|
879 | + ->setTarget($data['file_target']) |
|
880 | + ->setMailSend((bool)$data['mail_send']) |
|
881 | + ->setToken($data['token']); |
|
882 | + |
|
883 | + $shareTime = new \DateTime(); |
|
884 | + $shareTime->setTimestamp((int)$data['stime']); |
|
885 | + $share->setShareTime($shareTime); |
|
886 | + $share->setSharedWith($data['share_with']); |
|
887 | + |
|
888 | + if ($data['uid_initiator'] !== null) { |
|
889 | + $share->setShareOwner($data['uid_owner']); |
|
890 | + $share->setSharedBy($data['uid_initiator']); |
|
891 | + } else { |
|
892 | + //OLD SHARE |
|
893 | + $share->setSharedBy($data['uid_owner']); |
|
894 | + $path = $this->getNode($share->getSharedBy(), (int)$data['file_source']); |
|
895 | + |
|
896 | + $owner = $path->getOwner(); |
|
897 | + $share->setShareOwner($owner->getUID()); |
|
898 | + } |
|
899 | + |
|
900 | + $share->setNodeId((int)$data['file_source']); |
|
901 | + $share->setNodeType($data['item_type']); |
|
902 | + |
|
903 | + $share->setProviderId($this->identifier()); |
|
904 | + |
|
905 | + return $share; |
|
906 | + } |
|
907 | + |
|
908 | + /** |
|
909 | + * Get the node with file $id for $user |
|
910 | + * |
|
911 | + * @param string $userId |
|
912 | + * @param int $id |
|
913 | + * @return \OCP\Files\File|\OCP\Files\Folder |
|
914 | + * @throws InvalidShare |
|
915 | + */ |
|
916 | + private function getNode($userId, $id) { |
|
917 | + try { |
|
918 | + $userFolder = $this->rootFolder->getUserFolder($userId); |
|
919 | + } catch (NotFoundException $e) { |
|
920 | + throw new InvalidShare(); |
|
921 | + } |
|
922 | + |
|
923 | + $nodes = $userFolder->getById($id); |
|
924 | + |
|
925 | + if (empty($nodes)) { |
|
926 | + throw new InvalidShare(); |
|
927 | + } |
|
928 | + |
|
929 | + return $nodes[0]; |
|
930 | + } |
|
931 | + |
|
932 | + /** |
|
933 | + * A user is deleted from the system |
|
934 | + * So clean up the relevant shares. |
|
935 | + * |
|
936 | + * @param string $uid |
|
937 | + * @param int $shareType |
|
938 | + */ |
|
939 | + public function userDeleted($uid, $shareType) { |
|
940 | + //TODO: probabaly a good idea to send unshare info to remote servers |
|
941 | + |
|
942 | + $qb = $this->dbConnection->getQueryBuilder(); |
|
943 | + |
|
944 | + $qb->delete('share') |
|
945 | + ->where($qb->expr()->eq('share_type', $qb->createNamedParameter(\OCP\Share::SHARE_TYPE_REMOTE))) |
|
946 | + ->andWhere($qb->expr()->eq('uid_owner', $qb->createNamedParameter($uid))) |
|
947 | + ->execute(); |
|
948 | + } |
|
949 | + |
|
950 | + /** |
|
951 | + * This provider does not handle groups |
|
952 | + * |
|
953 | + * @param string $gid |
|
954 | + */ |
|
955 | + public function groupDeleted($gid) { |
|
956 | + // We don't handle groups here |
|
957 | + } |
|
958 | + |
|
959 | + /** |
|
960 | + * This provider does not handle groups |
|
961 | + * |
|
962 | + * @param string $uid |
|
963 | + * @param string $gid |
|
964 | + */ |
|
965 | + public function userDeletedFromGroup($uid, $gid) { |
|
966 | + // We don't handle groups here |
|
967 | + } |
|
968 | + |
|
969 | + /** |
|
970 | + * check if users from other Nextcloud instances are allowed to mount public links share by this instance |
|
971 | + * |
|
972 | + * @return bool |
|
973 | + */ |
|
974 | + public function isOutgoingServer2serverShareEnabled() { |
|
975 | + if ($this->gsConfig->onlyInternalFederation()) { |
|
976 | + return false; |
|
977 | + } |
|
978 | + $result = $this->config->getAppValue('files_sharing', 'outgoing_server2server_share_enabled', 'yes'); |
|
979 | + return ($result === 'yes'); |
|
980 | + } |
|
981 | + |
|
982 | + /** |
|
983 | + * check if users are allowed to mount public links from other Nextclouds |
|
984 | + * |
|
985 | + * @return bool |
|
986 | + */ |
|
987 | + public function isIncomingServer2serverShareEnabled() { |
|
988 | + if ($this->gsConfig->onlyInternalFederation()) { |
|
989 | + return false; |
|
990 | + } |
|
991 | + $result = $this->config->getAppValue('files_sharing', 'incoming_server2server_share_enabled', 'yes'); |
|
992 | + return ($result === 'yes'); |
|
993 | + } |
|
994 | + |
|
995 | + |
|
996 | + /** |
|
997 | + * check if users from other Nextcloud instances are allowed to send federated group shares |
|
998 | + * |
|
999 | + * @return bool |
|
1000 | + */ |
|
1001 | + public function isOutgoingServer2serverGroupShareEnabled() { |
|
1002 | + if ($this->gsConfig->onlyInternalFederation()) { |
|
1003 | + return false; |
|
1004 | + } |
|
1005 | + $result = $this->config->getAppValue('files_sharing', 'outgoing_server2server_group_share_enabled', 'no'); |
|
1006 | + return ($result === 'yes'); |
|
1007 | + } |
|
1008 | + |
|
1009 | + /** |
|
1010 | + * check if users are allowed to receive federated group shares |
|
1011 | + * |
|
1012 | + * @return bool |
|
1013 | + */ |
|
1014 | + public function isIncomingServer2serverGroupShareEnabled() { |
|
1015 | + if ($this->gsConfig->onlyInternalFederation()) { |
|
1016 | + return false; |
|
1017 | + } |
|
1018 | + $result = $this->config->getAppValue('files_sharing', 'incoming_server2server_group_share_enabled', 'no'); |
|
1019 | + return ($result === 'yes'); |
|
1020 | + } |
|
1021 | + |
|
1022 | + /** |
|
1023 | + * check if federated group sharing is supported, therefore the OCM API need to be enabled |
|
1024 | + * |
|
1025 | + * @return bool |
|
1026 | + */ |
|
1027 | + public function isFederatedGroupSharingSupported() { |
|
1028 | + return $this->cloudFederationProviderManager->isReady(); |
|
1029 | + } |
|
1030 | + |
|
1031 | + /** |
|
1032 | + * Check if querying sharees on the lookup server is enabled |
|
1033 | + * |
|
1034 | + * @return bool |
|
1035 | + */ |
|
1036 | + public function isLookupServerQueriesEnabled() { |
|
1037 | + // in a global scale setup we should always query the lookup server |
|
1038 | + if ($this->gsConfig->isGlobalScaleEnabled()) { |
|
1039 | + return true; |
|
1040 | + } |
|
1041 | + $result = $this->config->getAppValue('files_sharing', 'lookupServerEnabled', 'no'); |
|
1042 | + return ($result === 'yes'); |
|
1043 | + } |
|
1044 | + |
|
1045 | + |
|
1046 | + /** |
|
1047 | + * Check if it is allowed to publish user specific data to the lookup server |
|
1048 | + * |
|
1049 | + * @return bool |
|
1050 | + */ |
|
1051 | + public function isLookupServerUploadEnabled() { |
|
1052 | + // in a global scale setup the admin is responsible to keep the lookup server up-to-date |
|
1053 | + if ($this->gsConfig->isGlobalScaleEnabled()) { |
|
1054 | + return false; |
|
1055 | + } |
|
1056 | + $result = $this->config->getAppValue('files_sharing', 'lookupServerUploadEnabled', 'yes'); |
|
1057 | + return ($result === 'yes'); |
|
1058 | + } |
|
1059 | + |
|
1060 | + /** |
|
1061 | + * @inheritdoc |
|
1062 | + */ |
|
1063 | + public function getAccessList($nodes, $currentAccess) { |
|
1064 | + $ids = []; |
|
1065 | + foreach ($nodes as $node) { |
|
1066 | + $ids[] = $node->getId(); |
|
1067 | + } |
|
1068 | + |
|
1069 | + $qb = $this->dbConnection->getQueryBuilder(); |
|
1070 | + $qb->select('share_with', 'token', 'file_source') |
|
1071 | + ->from('share') |
|
1072 | + ->where($qb->expr()->eq('share_type', $qb->createNamedParameter(\OCP\Share::SHARE_TYPE_REMOTE))) |
|
1073 | + ->andWhere($qb->expr()->in('file_source', $qb->createNamedParameter($ids, IQueryBuilder::PARAM_INT_ARRAY))) |
|
1074 | + ->andWhere($qb->expr()->orX( |
|
1075 | + $qb->expr()->eq('item_type', $qb->createNamedParameter('file')), |
|
1076 | + $qb->expr()->eq('item_type', $qb->createNamedParameter('folder')) |
|
1077 | + )); |
|
1078 | + $cursor = $qb->execute(); |
|
1079 | + |
|
1080 | + if ($currentAccess === false) { |
|
1081 | + $remote = $cursor->fetch() !== false; |
|
1082 | + $cursor->closeCursor(); |
|
1083 | + |
|
1084 | + return ['remote' => $remote]; |
|
1085 | + } |
|
1086 | + |
|
1087 | + $remote = []; |
|
1088 | + while ($row = $cursor->fetch()) { |
|
1089 | + $remote[$row['share_with']] = [ |
|
1090 | + 'node_id' => $row['file_source'], |
|
1091 | + 'token' => $row['token'], |
|
1092 | + ]; |
|
1093 | + } |
|
1094 | + $cursor->closeCursor(); |
|
1095 | + |
|
1096 | + return ['remote' => $remote]; |
|
1097 | + } |
|
1098 | 1098 | } |
@@ -214,7 +214,7 @@ discard block |
||
214 | 214 | if ($remoteShare) { |
215 | 215 | try { |
216 | 216 | $ownerCloudId = $this->cloudIdManager->getCloudId($remoteShare['owner'], $remoteShare['remote']); |
217 | - $shareId = $this->addShareToDB($itemSource, $itemType, $shareWith, $sharedBy, $ownerCloudId->getId(), $permissions, 'tmp_token_' . time(), $shareType); |
|
217 | + $shareId = $this->addShareToDB($itemSource, $itemType, $shareWith, $sharedBy, $ownerCloudId->getId(), $permissions, 'tmp_token_'.time(), $shareType); |
|
218 | 218 | $share->setId($shareId); |
219 | 219 | list($token, $remoteId) = $this->askOwnerToReShare($shareWith, $share, $shareId); |
220 | 220 | // remote share was create successfully if we get a valid token as return |
@@ -296,7 +296,7 @@ discard block |
||
296 | 296 | $failure = true; |
297 | 297 | } |
298 | 298 | |
299 | - if($failure) { |
|
299 | + if ($failure) { |
|
300 | 300 | $this->removeShareFromTableById($shareId); |
301 | 301 | $message_t = $this->l->t('Sharing %1$s failed, could not find %2$s, maybe the server is currently unreachable or uses a self-signed certificate.', |
302 | 302 | [$share->getNode()->getName(), $share->getSharedWith()]); |
@@ -348,7 +348,7 @@ discard block |
||
348 | 348 | ->andWhere($query->expr()->eq('mountpoint', $query->createNamedParameter($share->getTarget()))); |
349 | 349 | $result = $query->execute()->fetchAll(); |
350 | 350 | |
351 | - if (isset($result[0]) && (int)$result[0]['remote_id'] > 0) { |
|
351 | + if (isset($result[0]) && (int) $result[0]['remote_id'] > 0) { |
|
352 | 352 | return $result[0]; |
353 | 353 | } |
354 | 354 | |
@@ -391,7 +391,7 @@ discard block |
||
391 | 391 | $qb->execute(); |
392 | 392 | $id = $qb->getLastInsertId(); |
393 | 393 | |
394 | - return (int)$id; |
|
394 | + return (int) $id; |
|
395 | 395 | } |
396 | 396 | |
397 | 397 | /** |
@@ -481,14 +481,14 @@ discard block |
||
481 | 481 | public function getRemoteId(IShare $share) { |
482 | 482 | $query = $this->dbConnection->getQueryBuilder(); |
483 | 483 | $query->select('remote_id')->from('federated_reshares') |
484 | - ->where($query->expr()->eq('share_id', $query->createNamedParameter((int)$share->getId()))); |
|
484 | + ->where($query->expr()->eq('share_id', $query->createNamedParameter((int) $share->getId()))); |
|
485 | 485 | $data = $query->execute()->fetch(); |
486 | 486 | |
487 | 487 | if (!is_array($data) || !isset($data['remote_id'])) { |
488 | 488 | throw new ShareNotFound(); |
489 | 489 | } |
490 | 490 | |
491 | - return (int)$data['remote_id']; |
|
491 | + return (int) $data['remote_id']; |
|
492 | 492 | } |
493 | 493 | |
494 | 494 | /** |
@@ -519,7 +519,7 @@ discard block |
||
519 | 519 | ->orderBy('id'); |
520 | 520 | |
521 | 521 | $cursor = $qb->execute(); |
522 | - while($data = $cursor->fetch()) { |
|
522 | + while ($data = $cursor->fetch()) { |
|
523 | 523 | $children[] = $this->createShareObject($data); |
524 | 524 | } |
525 | 525 | $cursor->closeCursor(); |
@@ -641,7 +641,7 @@ discard block |
||
641 | 641 | ); |
642 | 642 | } |
643 | 643 | |
644 | - $qb->innerJoin('s', 'filecache' ,'f', $qb->expr()->eq('s.file_source', 'f.fileid')); |
|
644 | + $qb->innerJoin('s', 'filecache', 'f', $qb->expr()->eq('s.file_source', 'f.fileid')); |
|
645 | 645 | $qb->andWhere($qb->expr()->eq('f.parent', $qb->createNamedParameter($node->getId()))); |
646 | 646 | |
647 | 647 | $qb->orderBy('id'); |
@@ -704,7 +704,7 @@ discard block |
||
704 | 704 | |
705 | 705 | $cursor = $qb->execute(); |
706 | 706 | $shares = []; |
707 | - while($data = $cursor->fetch()) { |
|
707 | + while ($data = $cursor->fetch()) { |
|
708 | 708 | $shares[] = $this->createShareObject($data); |
709 | 709 | } |
710 | 710 | $cursor->closeCursor(); |
@@ -728,7 +728,7 @@ discard block |
||
728 | 728 | $cursor->closeCursor(); |
729 | 729 | |
730 | 730 | if ($data === false) { |
731 | - throw new ShareNotFound('Can not find share with ID: ' . $id); |
|
731 | + throw new ShareNotFound('Can not find share with ID: '.$id); |
|
732 | 732 | } |
733 | 733 | |
734 | 734 | try { |
@@ -757,7 +757,7 @@ discard block |
||
757 | 757 | ->execute(); |
758 | 758 | |
759 | 759 | $shares = []; |
760 | - while($data = $cursor->fetch()) { |
|
760 | + while ($data = $cursor->fetch()) { |
|
761 | 761 | $shares[] = $this->createShareObject($data); |
762 | 762 | } |
763 | 763 | $cursor->closeCursor(); |
@@ -796,7 +796,7 @@ discard block |
||
796 | 796 | |
797 | 797 | $cursor = $qb->execute(); |
798 | 798 | |
799 | - while($data = $cursor->fetch()) { |
|
799 | + while ($data = $cursor->fetch()) { |
|
800 | 800 | $shares[] = $this->createShareObject($data); |
801 | 801 | } |
802 | 802 | $cursor->closeCursor(); |
@@ -873,15 +873,15 @@ discard block |
||
873 | 873 | private function createShareObject($data) { |
874 | 874 | |
875 | 875 | $share = new Share($this->rootFolder, $this->userManager); |
876 | - $share->setId((int)$data['id']) |
|
877 | - ->setShareType((int)$data['share_type']) |
|
878 | - ->setPermissions((int)$data['permissions']) |
|
876 | + $share->setId((int) $data['id']) |
|
877 | + ->setShareType((int) $data['share_type']) |
|
878 | + ->setPermissions((int) $data['permissions']) |
|
879 | 879 | ->setTarget($data['file_target']) |
880 | - ->setMailSend((bool)$data['mail_send']) |
|
880 | + ->setMailSend((bool) $data['mail_send']) |
|
881 | 881 | ->setToken($data['token']); |
882 | 882 | |
883 | 883 | $shareTime = new \DateTime(); |
884 | - $shareTime->setTimestamp((int)$data['stime']); |
|
884 | + $shareTime->setTimestamp((int) $data['stime']); |
|
885 | 885 | $share->setShareTime($shareTime); |
886 | 886 | $share->setSharedWith($data['share_with']); |
887 | 887 | |
@@ -891,13 +891,13 @@ discard block |
||
891 | 891 | } else { |
892 | 892 | //OLD SHARE |
893 | 893 | $share->setSharedBy($data['uid_owner']); |
894 | - $path = $this->getNode($share->getSharedBy(), (int)$data['file_source']); |
|
894 | + $path = $this->getNode($share->getSharedBy(), (int) $data['file_source']); |
|
895 | 895 | |
896 | 896 | $owner = $path->getOwner(); |
897 | 897 | $share->setShareOwner($owner->getUID()); |
898 | 898 | } |
899 | 899 | |
900 | - $share->setNodeId((int)$data['file_source']); |
|
900 | + $share->setNodeId((int) $data['file_source']); |
|
901 | 901 | $share->setNodeType($data['item_type']); |
902 | 902 | |
903 | 903 | $share->setProviderId($this->identifier()); |
@@ -52,371 +52,371 @@ |
||
52 | 52 | * Class to configure mount.json globally and for users |
53 | 53 | */ |
54 | 54 | class OC_Mount_Config { |
55 | - // TODO: make this class non-static and give it a proper namespace |
|
56 | - |
|
57 | - const MOUNT_TYPE_GLOBAL = 'global'; |
|
58 | - const MOUNT_TYPE_GROUP = 'group'; |
|
59 | - const MOUNT_TYPE_USER = 'user'; |
|
60 | - const MOUNT_TYPE_PERSONAL = 'personal'; |
|
61 | - |
|
62 | - // whether to skip backend test (for unit tests, as this static class is not mockable) |
|
63 | - public static $skipTest = false; |
|
64 | - |
|
65 | - /** @var Application */ |
|
66 | - public static $app; |
|
67 | - |
|
68 | - /** |
|
69 | - * @param string $class |
|
70 | - * @param array $definition |
|
71 | - * @return bool |
|
72 | - * @deprecated 8.2.0 use \OCA\Files_External\Service\BackendService::registerBackend() |
|
73 | - */ |
|
74 | - public static function registerBackend($class, $definition) { |
|
75 | - $backendService = self::$app->getContainer()->query(BackendService::class); |
|
76 | - $auth = self::$app->getContainer()->query(Builtin::class); |
|
77 | - |
|
78 | - $backendService->registerBackend(new LegacyBackend($class, $definition, $auth)); |
|
79 | - |
|
80 | - return true; |
|
81 | - } |
|
82 | - |
|
83 | - /** |
|
84 | - * Returns the mount points for the given user. |
|
85 | - * The mount point is relative to the data directory. |
|
86 | - * |
|
87 | - * @param string $uid user |
|
88 | - * @return array of mount point string as key, mountpoint config as value |
|
89 | - * |
|
90 | - * @deprecated 8.2.0 use UserGlobalStoragesService::getStorages() and UserStoragesService::getStorages() |
|
91 | - */ |
|
92 | - public static function getAbsoluteMountPoints($uid) { |
|
93 | - $mountPoints = array(); |
|
94 | - |
|
95 | - $userGlobalStoragesService = self::$app->getContainer()->query(UserGlobalStoragesService::class); |
|
96 | - $userStoragesService = self::$app->getContainer()->query(UserStoragesService::class); |
|
97 | - $user = self::$app->getContainer()->query(IUserManager::class)->get($uid); |
|
98 | - |
|
99 | - $userGlobalStoragesService->setUser($user); |
|
100 | - $userStoragesService->setUser($user); |
|
101 | - |
|
102 | - foreach ($userGlobalStoragesService->getStorages() as $storage) { |
|
103 | - /** @var \OCA\Files_External\Lib\StorageConfig $storage */ |
|
104 | - $mountPoint = '/'.$uid.'/files'.$storage->getMountPoint(); |
|
105 | - $mountEntry = self::prepareMountPointEntry($storage, false); |
|
106 | - foreach ($mountEntry['options'] as &$option) { |
|
107 | - $option = self::setUserVars($uid, $option); |
|
108 | - } |
|
109 | - $mountPoints[$mountPoint] = $mountEntry; |
|
110 | - } |
|
111 | - |
|
112 | - foreach ($userStoragesService->getStorages() as $storage) { |
|
113 | - $mountPoint = '/'.$uid.'/files'.$storage->getMountPoint(); |
|
114 | - $mountEntry = self::prepareMountPointEntry($storage, true); |
|
115 | - foreach ($mountEntry['options'] as &$option) { |
|
116 | - $option = self::setUserVars($uid, $option); |
|
117 | - } |
|
118 | - $mountPoints[$mountPoint] = $mountEntry; |
|
119 | - } |
|
120 | - |
|
121 | - $userGlobalStoragesService->resetUser(); |
|
122 | - $userStoragesService->resetUser(); |
|
123 | - |
|
124 | - return $mountPoints; |
|
125 | - } |
|
126 | - |
|
127 | - /** |
|
128 | - * Get the system mount points |
|
129 | - * |
|
130 | - * @return array |
|
131 | - * |
|
132 | - * @deprecated 8.2.0 use GlobalStoragesService::getStorages() |
|
133 | - */ |
|
134 | - public static function getSystemMountPoints() { |
|
135 | - $mountPoints = []; |
|
136 | - $service = self::$app->getContainer()->query(GlobalStoragesService::class); |
|
137 | - |
|
138 | - foreach ($service->getStorages() as $storage) { |
|
139 | - $mountPoints[] = self::prepareMountPointEntry($storage, false); |
|
140 | - } |
|
141 | - |
|
142 | - return $mountPoints; |
|
143 | - } |
|
144 | - |
|
145 | - /** |
|
146 | - * Get the personal mount points of the current user |
|
147 | - * |
|
148 | - * @return array |
|
149 | - * |
|
150 | - * @deprecated 8.2.0 use UserStoragesService::getStorages() |
|
151 | - */ |
|
152 | - public static function getPersonalMountPoints() { |
|
153 | - $mountPoints = []; |
|
154 | - $service = self::$app->getContainer()->query(UserStoragesService::class); |
|
155 | - |
|
156 | - foreach ($service->getStorages() as $storage) { |
|
157 | - $mountPoints[] = self::prepareMountPointEntry($storage, true); |
|
158 | - } |
|
159 | - |
|
160 | - return $mountPoints; |
|
161 | - } |
|
162 | - |
|
163 | - /** |
|
164 | - * Convert a StorageConfig to the legacy mountPoints array format |
|
165 | - * There's a lot of extra information in here, to satisfy all of the legacy functions |
|
166 | - * |
|
167 | - * @param StorageConfig $storage |
|
168 | - * @param bool $isPersonal |
|
169 | - * @return array |
|
170 | - */ |
|
171 | - private static function prepareMountPointEntry(StorageConfig $storage, $isPersonal) { |
|
172 | - $mountEntry = []; |
|
173 | - |
|
174 | - $mountEntry['mountpoint'] = substr($storage->getMountPoint(), 1); // remove leading slash |
|
175 | - $mountEntry['class'] = $storage->getBackend()->getIdentifier(); |
|
176 | - $mountEntry['backend'] = $storage->getBackend()->getText(); |
|
177 | - $mountEntry['authMechanism'] = $storage->getAuthMechanism()->getIdentifier(); |
|
178 | - $mountEntry['personal'] = $isPersonal; |
|
179 | - $mountEntry['options'] = self::decryptPasswords($storage->getBackendOptions()); |
|
180 | - $mountEntry['mountOptions'] = $storage->getMountOptions(); |
|
181 | - $mountEntry['priority'] = $storage->getPriority(); |
|
182 | - $mountEntry['applicable'] = [ |
|
183 | - 'groups' => $storage->getApplicableGroups(), |
|
184 | - 'users' => $storage->getApplicableUsers(), |
|
185 | - ]; |
|
186 | - // if mountpoint is applicable to all users the old API expects ['all'] |
|
187 | - if (empty($mountEntry['applicable']['groups']) && empty($mountEntry['applicable']['users'])) { |
|
188 | - $mountEntry['applicable']['users'] = ['all']; |
|
189 | - } |
|
190 | - |
|
191 | - $mountEntry['id'] = $storage->getId(); |
|
192 | - |
|
193 | - return $mountEntry; |
|
194 | - } |
|
195 | - |
|
196 | - /** |
|
197 | - * fill in the correct values for $user |
|
198 | - * |
|
199 | - * @param string $user user value |
|
200 | - * @param string|array $input |
|
201 | - * @return string |
|
202 | - */ |
|
203 | - public static function setUserVars($user, $input) { |
|
204 | - if (is_array($input)) { |
|
205 | - foreach ($input as &$value) { |
|
206 | - if (is_string($value)) { |
|
207 | - $value = str_replace('$user', $user, $value); |
|
208 | - } |
|
209 | - } |
|
210 | - } else { |
|
211 | - if (is_string($input)) { |
|
212 | - $input = str_replace('$user', $user, $input); |
|
213 | - } |
|
214 | - } |
|
215 | - return $input; |
|
216 | - } |
|
217 | - |
|
218 | - /** |
|
219 | - * Test connecting using the given backend configuration |
|
220 | - * |
|
221 | - * @param string $class backend class name |
|
222 | - * @param array $options backend configuration options |
|
223 | - * @param boolean $isPersonal |
|
224 | - * @return int see self::STATUS_* |
|
225 | - * @throws Exception |
|
226 | - */ |
|
227 | - public static function getBackendStatus($class, $options, $isPersonal, $testOnly = true) { |
|
228 | - if (self::$skipTest) { |
|
229 | - return StorageNotAvailableException::STATUS_SUCCESS; |
|
230 | - } |
|
231 | - foreach ($options as &$option) { |
|
232 | - $option = self::setUserVars(OCP\User::getUser(), $option); |
|
233 | - } |
|
234 | - if (class_exists($class)) { |
|
235 | - try { |
|
236 | - /** @var \OC\Files\Storage\Common $storage */ |
|
237 | - $storage = new $class($options); |
|
238 | - |
|
239 | - try { |
|
240 | - $result = $storage->test($isPersonal, $testOnly); |
|
241 | - $storage->setAvailability($result); |
|
242 | - if ($result) { |
|
243 | - return StorageNotAvailableException::STATUS_SUCCESS; |
|
244 | - } |
|
245 | - } catch (\Exception $e) { |
|
246 | - $storage->setAvailability(false); |
|
247 | - throw $e; |
|
248 | - } |
|
249 | - } catch (Exception $exception) { |
|
250 | - \OC::$server->getLogger()->logException($exception, ['app' => 'files_external']); |
|
251 | - throw $exception; |
|
252 | - } |
|
253 | - } |
|
254 | - return StorageNotAvailableException::STATUS_ERROR; |
|
255 | - } |
|
256 | - |
|
257 | - /** |
|
258 | - * Read the mount points in the config file into an array |
|
259 | - * |
|
260 | - * @param string|null $user If not null, personal for $user, otherwise system |
|
261 | - * @return array |
|
262 | - */ |
|
263 | - public static function readData($user = null) { |
|
264 | - if (isset($user)) { |
|
265 | - $jsonFile = \OC::$server->getUserManager()->get($user)->getHome() . '/mount.json'; |
|
266 | - } else { |
|
267 | - $config = \OC::$server->getConfig(); |
|
268 | - $datadir = $config->getSystemValue('datadirectory', \OC::$SERVERROOT . '/data/'); |
|
269 | - $jsonFile = $config->getSystemValue('mount_file', $datadir . '/mount.json'); |
|
270 | - } |
|
271 | - if (is_file($jsonFile)) { |
|
272 | - $mountPoints = json_decode(file_get_contents($jsonFile), true); |
|
273 | - if (is_array($mountPoints)) { |
|
274 | - return $mountPoints; |
|
275 | - } |
|
276 | - } |
|
277 | - return array(); |
|
278 | - } |
|
279 | - |
|
280 | - /** |
|
281 | - * Get backend dependency message |
|
282 | - * TODO: move into AppFramework along with templates |
|
283 | - * |
|
284 | - * @param Backend[] $backends |
|
285 | - * @return string |
|
286 | - */ |
|
287 | - public static function dependencyMessage($backends) { |
|
288 | - $l = \OC::$server->getL10N('files_external'); |
|
289 | - $message = ''; |
|
290 | - $dependencyGroups = []; |
|
291 | - |
|
292 | - foreach ($backends as $backend) { |
|
293 | - foreach ($backend->checkDependencies() as $dependency) { |
|
294 | - if ($message = $dependency->getMessage()) { |
|
295 | - $message .= '<p>' . $message . '</p>'; |
|
296 | - } else { |
|
297 | - $dependencyGroups[$dependency->getDependency()][] = $backend; |
|
298 | - } |
|
299 | - } |
|
300 | - } |
|
301 | - |
|
302 | - foreach ($dependencyGroups as $module => $dependants) { |
|
303 | - $backends = implode(', ', array_map(function($backend) { |
|
304 | - return '"' . $backend->getText() . '"'; |
|
305 | - }, $dependants)); |
|
306 | - $message .= '<p>' . OC_Mount_Config::getSingleDependencyMessage($l, $module, $backends) . '</p>'; |
|
307 | - } |
|
308 | - |
|
309 | - return $message; |
|
310 | - } |
|
311 | - |
|
312 | - /** |
|
313 | - * Returns a dependency missing message |
|
314 | - * |
|
315 | - * @param \OCP\IL10N $l |
|
316 | - * @param string $module |
|
317 | - * @param string $backend |
|
318 | - * @return string |
|
319 | - */ |
|
320 | - private static function getSingleDependencyMessage(\OCP\IL10N $l, $module, $backend) { |
|
321 | - switch (strtolower($module)) { |
|
322 | - case 'curl': |
|
323 | - return (string)$l->t('The cURL support in PHP is not enabled or installed. Mounting of %s is not possible. Please ask your system administrator to install it.', [$backend]); |
|
324 | - case 'ftp': |
|
325 | - return (string)$l->t('The FTP support in PHP is not enabled or installed. Mounting of %s is not possible. Please ask your system administrator to install it.', [$backend]); |
|
326 | - default: |
|
327 | - return (string)$l->t('"%1$s" is not installed. Mounting of %2$s is not possible. Please ask your system administrator to install it.', [$module, $backend]); |
|
328 | - } |
|
329 | - } |
|
330 | - |
|
331 | - /** |
|
332 | - * Encrypt passwords in the given config options |
|
333 | - * |
|
334 | - * @param array $options mount options |
|
335 | - * @return array updated options |
|
336 | - */ |
|
337 | - public static function encryptPasswords($options) { |
|
338 | - if (isset($options['password'])) { |
|
339 | - $options['password_encrypted'] = self::encryptPassword($options['password']); |
|
340 | - // do not unset the password, we want to keep the keys order |
|
341 | - // on load... because that's how the UI currently works |
|
342 | - $options['password'] = ''; |
|
343 | - } |
|
344 | - return $options; |
|
345 | - } |
|
346 | - |
|
347 | - /** |
|
348 | - * Decrypt passwords in the given config options |
|
349 | - * |
|
350 | - * @param array $options mount options |
|
351 | - * @return array updated options |
|
352 | - */ |
|
353 | - public static function decryptPasswords($options) { |
|
354 | - // note: legacy options might still have the unencrypted password in the "password" field |
|
355 | - if (isset($options['password_encrypted'])) { |
|
356 | - $options['password'] = self::decryptPassword($options['password_encrypted']); |
|
357 | - unset($options['password_encrypted']); |
|
358 | - } |
|
359 | - return $options; |
|
360 | - } |
|
361 | - |
|
362 | - /** |
|
363 | - * Encrypt a single password |
|
364 | - * |
|
365 | - * @param string $password plain text password |
|
366 | - * @return string encrypted password |
|
367 | - */ |
|
368 | - private static function encryptPassword($password) { |
|
369 | - $cipher = self::getCipher(); |
|
370 | - $iv = \OC::$server->getSecureRandom()->generate(16); |
|
371 | - $cipher->setIV($iv); |
|
372 | - return base64_encode($iv . $cipher->encrypt($password)); |
|
373 | - } |
|
374 | - |
|
375 | - /** |
|
376 | - * Decrypts a single password |
|
377 | - * |
|
378 | - * @param string $encryptedPassword encrypted password |
|
379 | - * @return string plain text password |
|
380 | - */ |
|
381 | - private static function decryptPassword($encryptedPassword) { |
|
382 | - $cipher = self::getCipher(); |
|
383 | - $binaryPassword = base64_decode($encryptedPassword); |
|
384 | - $iv = substr($binaryPassword, 0, 16); |
|
385 | - $cipher->setIV($iv); |
|
386 | - $binaryPassword = substr($binaryPassword, 16); |
|
387 | - return $cipher->decrypt($binaryPassword); |
|
388 | - } |
|
389 | - |
|
390 | - /** |
|
391 | - * Returns the encryption cipher |
|
392 | - * |
|
393 | - * @return AES |
|
394 | - */ |
|
395 | - private static function getCipher() { |
|
396 | - $cipher = new AES(AES::MODE_CBC); |
|
397 | - $cipher->setKey(\OC::$server->getConfig()->getSystemValue('passwordsalt', null)); |
|
398 | - return $cipher; |
|
399 | - } |
|
400 | - |
|
401 | - /** |
|
402 | - * Computes a hash based on the given configuration. |
|
403 | - * This is mostly used to find out whether configurations |
|
404 | - * are the same. |
|
405 | - * |
|
406 | - * @param array $config |
|
407 | - * @return string |
|
408 | - */ |
|
409 | - public static function makeConfigHash($config) { |
|
410 | - $data = json_encode( |
|
411 | - array( |
|
412 | - 'c' => $config['backend'], |
|
413 | - 'a' => $config['authMechanism'], |
|
414 | - 'm' => $config['mountpoint'], |
|
415 | - 'o' => $config['options'], |
|
416 | - 'p' => isset($config['priority']) ? $config['priority'] : -1, |
|
417 | - 'mo' => isset($config['mountOptions']) ? $config['mountOptions'] : [], |
|
418 | - ) |
|
419 | - ); |
|
420 | - return hash('md5', $data); |
|
421 | - } |
|
55 | + // TODO: make this class non-static and give it a proper namespace |
|
56 | + |
|
57 | + const MOUNT_TYPE_GLOBAL = 'global'; |
|
58 | + const MOUNT_TYPE_GROUP = 'group'; |
|
59 | + const MOUNT_TYPE_USER = 'user'; |
|
60 | + const MOUNT_TYPE_PERSONAL = 'personal'; |
|
61 | + |
|
62 | + // whether to skip backend test (for unit tests, as this static class is not mockable) |
|
63 | + public static $skipTest = false; |
|
64 | + |
|
65 | + /** @var Application */ |
|
66 | + public static $app; |
|
67 | + |
|
68 | + /** |
|
69 | + * @param string $class |
|
70 | + * @param array $definition |
|
71 | + * @return bool |
|
72 | + * @deprecated 8.2.0 use \OCA\Files_External\Service\BackendService::registerBackend() |
|
73 | + */ |
|
74 | + public static function registerBackend($class, $definition) { |
|
75 | + $backendService = self::$app->getContainer()->query(BackendService::class); |
|
76 | + $auth = self::$app->getContainer()->query(Builtin::class); |
|
77 | + |
|
78 | + $backendService->registerBackend(new LegacyBackend($class, $definition, $auth)); |
|
79 | + |
|
80 | + return true; |
|
81 | + } |
|
82 | + |
|
83 | + /** |
|
84 | + * Returns the mount points for the given user. |
|
85 | + * The mount point is relative to the data directory. |
|
86 | + * |
|
87 | + * @param string $uid user |
|
88 | + * @return array of mount point string as key, mountpoint config as value |
|
89 | + * |
|
90 | + * @deprecated 8.2.0 use UserGlobalStoragesService::getStorages() and UserStoragesService::getStorages() |
|
91 | + */ |
|
92 | + public static function getAbsoluteMountPoints($uid) { |
|
93 | + $mountPoints = array(); |
|
94 | + |
|
95 | + $userGlobalStoragesService = self::$app->getContainer()->query(UserGlobalStoragesService::class); |
|
96 | + $userStoragesService = self::$app->getContainer()->query(UserStoragesService::class); |
|
97 | + $user = self::$app->getContainer()->query(IUserManager::class)->get($uid); |
|
98 | + |
|
99 | + $userGlobalStoragesService->setUser($user); |
|
100 | + $userStoragesService->setUser($user); |
|
101 | + |
|
102 | + foreach ($userGlobalStoragesService->getStorages() as $storage) { |
|
103 | + /** @var \OCA\Files_External\Lib\StorageConfig $storage */ |
|
104 | + $mountPoint = '/'.$uid.'/files'.$storage->getMountPoint(); |
|
105 | + $mountEntry = self::prepareMountPointEntry($storage, false); |
|
106 | + foreach ($mountEntry['options'] as &$option) { |
|
107 | + $option = self::setUserVars($uid, $option); |
|
108 | + } |
|
109 | + $mountPoints[$mountPoint] = $mountEntry; |
|
110 | + } |
|
111 | + |
|
112 | + foreach ($userStoragesService->getStorages() as $storage) { |
|
113 | + $mountPoint = '/'.$uid.'/files'.$storage->getMountPoint(); |
|
114 | + $mountEntry = self::prepareMountPointEntry($storage, true); |
|
115 | + foreach ($mountEntry['options'] as &$option) { |
|
116 | + $option = self::setUserVars($uid, $option); |
|
117 | + } |
|
118 | + $mountPoints[$mountPoint] = $mountEntry; |
|
119 | + } |
|
120 | + |
|
121 | + $userGlobalStoragesService->resetUser(); |
|
122 | + $userStoragesService->resetUser(); |
|
123 | + |
|
124 | + return $mountPoints; |
|
125 | + } |
|
126 | + |
|
127 | + /** |
|
128 | + * Get the system mount points |
|
129 | + * |
|
130 | + * @return array |
|
131 | + * |
|
132 | + * @deprecated 8.2.0 use GlobalStoragesService::getStorages() |
|
133 | + */ |
|
134 | + public static function getSystemMountPoints() { |
|
135 | + $mountPoints = []; |
|
136 | + $service = self::$app->getContainer()->query(GlobalStoragesService::class); |
|
137 | + |
|
138 | + foreach ($service->getStorages() as $storage) { |
|
139 | + $mountPoints[] = self::prepareMountPointEntry($storage, false); |
|
140 | + } |
|
141 | + |
|
142 | + return $mountPoints; |
|
143 | + } |
|
144 | + |
|
145 | + /** |
|
146 | + * Get the personal mount points of the current user |
|
147 | + * |
|
148 | + * @return array |
|
149 | + * |
|
150 | + * @deprecated 8.2.0 use UserStoragesService::getStorages() |
|
151 | + */ |
|
152 | + public static function getPersonalMountPoints() { |
|
153 | + $mountPoints = []; |
|
154 | + $service = self::$app->getContainer()->query(UserStoragesService::class); |
|
155 | + |
|
156 | + foreach ($service->getStorages() as $storage) { |
|
157 | + $mountPoints[] = self::prepareMountPointEntry($storage, true); |
|
158 | + } |
|
159 | + |
|
160 | + return $mountPoints; |
|
161 | + } |
|
162 | + |
|
163 | + /** |
|
164 | + * Convert a StorageConfig to the legacy mountPoints array format |
|
165 | + * There's a lot of extra information in here, to satisfy all of the legacy functions |
|
166 | + * |
|
167 | + * @param StorageConfig $storage |
|
168 | + * @param bool $isPersonal |
|
169 | + * @return array |
|
170 | + */ |
|
171 | + private static function prepareMountPointEntry(StorageConfig $storage, $isPersonal) { |
|
172 | + $mountEntry = []; |
|
173 | + |
|
174 | + $mountEntry['mountpoint'] = substr($storage->getMountPoint(), 1); // remove leading slash |
|
175 | + $mountEntry['class'] = $storage->getBackend()->getIdentifier(); |
|
176 | + $mountEntry['backend'] = $storage->getBackend()->getText(); |
|
177 | + $mountEntry['authMechanism'] = $storage->getAuthMechanism()->getIdentifier(); |
|
178 | + $mountEntry['personal'] = $isPersonal; |
|
179 | + $mountEntry['options'] = self::decryptPasswords($storage->getBackendOptions()); |
|
180 | + $mountEntry['mountOptions'] = $storage->getMountOptions(); |
|
181 | + $mountEntry['priority'] = $storage->getPriority(); |
|
182 | + $mountEntry['applicable'] = [ |
|
183 | + 'groups' => $storage->getApplicableGroups(), |
|
184 | + 'users' => $storage->getApplicableUsers(), |
|
185 | + ]; |
|
186 | + // if mountpoint is applicable to all users the old API expects ['all'] |
|
187 | + if (empty($mountEntry['applicable']['groups']) && empty($mountEntry['applicable']['users'])) { |
|
188 | + $mountEntry['applicable']['users'] = ['all']; |
|
189 | + } |
|
190 | + |
|
191 | + $mountEntry['id'] = $storage->getId(); |
|
192 | + |
|
193 | + return $mountEntry; |
|
194 | + } |
|
195 | + |
|
196 | + /** |
|
197 | + * fill in the correct values for $user |
|
198 | + * |
|
199 | + * @param string $user user value |
|
200 | + * @param string|array $input |
|
201 | + * @return string |
|
202 | + */ |
|
203 | + public static function setUserVars($user, $input) { |
|
204 | + if (is_array($input)) { |
|
205 | + foreach ($input as &$value) { |
|
206 | + if (is_string($value)) { |
|
207 | + $value = str_replace('$user', $user, $value); |
|
208 | + } |
|
209 | + } |
|
210 | + } else { |
|
211 | + if (is_string($input)) { |
|
212 | + $input = str_replace('$user', $user, $input); |
|
213 | + } |
|
214 | + } |
|
215 | + return $input; |
|
216 | + } |
|
217 | + |
|
218 | + /** |
|
219 | + * Test connecting using the given backend configuration |
|
220 | + * |
|
221 | + * @param string $class backend class name |
|
222 | + * @param array $options backend configuration options |
|
223 | + * @param boolean $isPersonal |
|
224 | + * @return int see self::STATUS_* |
|
225 | + * @throws Exception |
|
226 | + */ |
|
227 | + public static function getBackendStatus($class, $options, $isPersonal, $testOnly = true) { |
|
228 | + if (self::$skipTest) { |
|
229 | + return StorageNotAvailableException::STATUS_SUCCESS; |
|
230 | + } |
|
231 | + foreach ($options as &$option) { |
|
232 | + $option = self::setUserVars(OCP\User::getUser(), $option); |
|
233 | + } |
|
234 | + if (class_exists($class)) { |
|
235 | + try { |
|
236 | + /** @var \OC\Files\Storage\Common $storage */ |
|
237 | + $storage = new $class($options); |
|
238 | + |
|
239 | + try { |
|
240 | + $result = $storage->test($isPersonal, $testOnly); |
|
241 | + $storage->setAvailability($result); |
|
242 | + if ($result) { |
|
243 | + return StorageNotAvailableException::STATUS_SUCCESS; |
|
244 | + } |
|
245 | + } catch (\Exception $e) { |
|
246 | + $storage->setAvailability(false); |
|
247 | + throw $e; |
|
248 | + } |
|
249 | + } catch (Exception $exception) { |
|
250 | + \OC::$server->getLogger()->logException($exception, ['app' => 'files_external']); |
|
251 | + throw $exception; |
|
252 | + } |
|
253 | + } |
|
254 | + return StorageNotAvailableException::STATUS_ERROR; |
|
255 | + } |
|
256 | + |
|
257 | + /** |
|
258 | + * Read the mount points in the config file into an array |
|
259 | + * |
|
260 | + * @param string|null $user If not null, personal for $user, otherwise system |
|
261 | + * @return array |
|
262 | + */ |
|
263 | + public static function readData($user = null) { |
|
264 | + if (isset($user)) { |
|
265 | + $jsonFile = \OC::$server->getUserManager()->get($user)->getHome() . '/mount.json'; |
|
266 | + } else { |
|
267 | + $config = \OC::$server->getConfig(); |
|
268 | + $datadir = $config->getSystemValue('datadirectory', \OC::$SERVERROOT . '/data/'); |
|
269 | + $jsonFile = $config->getSystemValue('mount_file', $datadir . '/mount.json'); |
|
270 | + } |
|
271 | + if (is_file($jsonFile)) { |
|
272 | + $mountPoints = json_decode(file_get_contents($jsonFile), true); |
|
273 | + if (is_array($mountPoints)) { |
|
274 | + return $mountPoints; |
|
275 | + } |
|
276 | + } |
|
277 | + return array(); |
|
278 | + } |
|
279 | + |
|
280 | + /** |
|
281 | + * Get backend dependency message |
|
282 | + * TODO: move into AppFramework along with templates |
|
283 | + * |
|
284 | + * @param Backend[] $backends |
|
285 | + * @return string |
|
286 | + */ |
|
287 | + public static function dependencyMessage($backends) { |
|
288 | + $l = \OC::$server->getL10N('files_external'); |
|
289 | + $message = ''; |
|
290 | + $dependencyGroups = []; |
|
291 | + |
|
292 | + foreach ($backends as $backend) { |
|
293 | + foreach ($backend->checkDependencies() as $dependency) { |
|
294 | + if ($message = $dependency->getMessage()) { |
|
295 | + $message .= '<p>' . $message . '</p>'; |
|
296 | + } else { |
|
297 | + $dependencyGroups[$dependency->getDependency()][] = $backend; |
|
298 | + } |
|
299 | + } |
|
300 | + } |
|
301 | + |
|
302 | + foreach ($dependencyGroups as $module => $dependants) { |
|
303 | + $backends = implode(', ', array_map(function($backend) { |
|
304 | + return '"' . $backend->getText() . '"'; |
|
305 | + }, $dependants)); |
|
306 | + $message .= '<p>' . OC_Mount_Config::getSingleDependencyMessage($l, $module, $backends) . '</p>'; |
|
307 | + } |
|
308 | + |
|
309 | + return $message; |
|
310 | + } |
|
311 | + |
|
312 | + /** |
|
313 | + * Returns a dependency missing message |
|
314 | + * |
|
315 | + * @param \OCP\IL10N $l |
|
316 | + * @param string $module |
|
317 | + * @param string $backend |
|
318 | + * @return string |
|
319 | + */ |
|
320 | + private static function getSingleDependencyMessage(\OCP\IL10N $l, $module, $backend) { |
|
321 | + switch (strtolower($module)) { |
|
322 | + case 'curl': |
|
323 | + return (string)$l->t('The cURL support in PHP is not enabled or installed. Mounting of %s is not possible. Please ask your system administrator to install it.', [$backend]); |
|
324 | + case 'ftp': |
|
325 | + return (string)$l->t('The FTP support in PHP is not enabled or installed. Mounting of %s is not possible. Please ask your system administrator to install it.', [$backend]); |
|
326 | + default: |
|
327 | + return (string)$l->t('"%1$s" is not installed. Mounting of %2$s is not possible. Please ask your system administrator to install it.', [$module, $backend]); |
|
328 | + } |
|
329 | + } |
|
330 | + |
|
331 | + /** |
|
332 | + * Encrypt passwords in the given config options |
|
333 | + * |
|
334 | + * @param array $options mount options |
|
335 | + * @return array updated options |
|
336 | + */ |
|
337 | + public static function encryptPasswords($options) { |
|
338 | + if (isset($options['password'])) { |
|
339 | + $options['password_encrypted'] = self::encryptPassword($options['password']); |
|
340 | + // do not unset the password, we want to keep the keys order |
|
341 | + // on load... because that's how the UI currently works |
|
342 | + $options['password'] = ''; |
|
343 | + } |
|
344 | + return $options; |
|
345 | + } |
|
346 | + |
|
347 | + /** |
|
348 | + * Decrypt passwords in the given config options |
|
349 | + * |
|
350 | + * @param array $options mount options |
|
351 | + * @return array updated options |
|
352 | + */ |
|
353 | + public static function decryptPasswords($options) { |
|
354 | + // note: legacy options might still have the unencrypted password in the "password" field |
|
355 | + if (isset($options['password_encrypted'])) { |
|
356 | + $options['password'] = self::decryptPassword($options['password_encrypted']); |
|
357 | + unset($options['password_encrypted']); |
|
358 | + } |
|
359 | + return $options; |
|
360 | + } |
|
361 | + |
|
362 | + /** |
|
363 | + * Encrypt a single password |
|
364 | + * |
|
365 | + * @param string $password plain text password |
|
366 | + * @return string encrypted password |
|
367 | + */ |
|
368 | + private static function encryptPassword($password) { |
|
369 | + $cipher = self::getCipher(); |
|
370 | + $iv = \OC::$server->getSecureRandom()->generate(16); |
|
371 | + $cipher->setIV($iv); |
|
372 | + return base64_encode($iv . $cipher->encrypt($password)); |
|
373 | + } |
|
374 | + |
|
375 | + /** |
|
376 | + * Decrypts a single password |
|
377 | + * |
|
378 | + * @param string $encryptedPassword encrypted password |
|
379 | + * @return string plain text password |
|
380 | + */ |
|
381 | + private static function decryptPassword($encryptedPassword) { |
|
382 | + $cipher = self::getCipher(); |
|
383 | + $binaryPassword = base64_decode($encryptedPassword); |
|
384 | + $iv = substr($binaryPassword, 0, 16); |
|
385 | + $cipher->setIV($iv); |
|
386 | + $binaryPassword = substr($binaryPassword, 16); |
|
387 | + return $cipher->decrypt($binaryPassword); |
|
388 | + } |
|
389 | + |
|
390 | + /** |
|
391 | + * Returns the encryption cipher |
|
392 | + * |
|
393 | + * @return AES |
|
394 | + */ |
|
395 | + private static function getCipher() { |
|
396 | + $cipher = new AES(AES::MODE_CBC); |
|
397 | + $cipher->setKey(\OC::$server->getConfig()->getSystemValue('passwordsalt', null)); |
|
398 | + return $cipher; |
|
399 | + } |
|
400 | + |
|
401 | + /** |
|
402 | + * Computes a hash based on the given configuration. |
|
403 | + * This is mostly used to find out whether configurations |
|
404 | + * are the same. |
|
405 | + * |
|
406 | + * @param array $config |
|
407 | + * @return string |
|
408 | + */ |
|
409 | + public static function makeConfigHash($config) { |
|
410 | + $data = json_encode( |
|
411 | + array( |
|
412 | + 'c' => $config['backend'], |
|
413 | + 'a' => $config['authMechanism'], |
|
414 | + 'm' => $config['mountpoint'], |
|
415 | + 'o' => $config['options'], |
|
416 | + 'p' => isset($config['priority']) ? $config['priority'] : -1, |
|
417 | + 'mo' => isset($config['mountOptions']) ? $config['mountOptions'] : [], |
|
418 | + ) |
|
419 | + ); |
|
420 | + return hash('md5', $data); |
|
421 | + } |
|
422 | 422 | } |
@@ -262,11 +262,11 @@ discard block |
||
262 | 262 | */ |
263 | 263 | public static function readData($user = null) { |
264 | 264 | if (isset($user)) { |
265 | - $jsonFile = \OC::$server->getUserManager()->get($user)->getHome() . '/mount.json'; |
|
265 | + $jsonFile = \OC::$server->getUserManager()->get($user)->getHome().'/mount.json'; |
|
266 | 266 | } else { |
267 | 267 | $config = \OC::$server->getConfig(); |
268 | - $datadir = $config->getSystemValue('datadirectory', \OC::$SERVERROOT . '/data/'); |
|
269 | - $jsonFile = $config->getSystemValue('mount_file', $datadir . '/mount.json'); |
|
268 | + $datadir = $config->getSystemValue('datadirectory', \OC::$SERVERROOT.'/data/'); |
|
269 | + $jsonFile = $config->getSystemValue('mount_file', $datadir.'/mount.json'); |
|
270 | 270 | } |
271 | 271 | if (is_file($jsonFile)) { |
272 | 272 | $mountPoints = json_decode(file_get_contents($jsonFile), true); |
@@ -292,7 +292,7 @@ discard block |
||
292 | 292 | foreach ($backends as $backend) { |
293 | 293 | foreach ($backend->checkDependencies() as $dependency) { |
294 | 294 | if ($message = $dependency->getMessage()) { |
295 | - $message .= '<p>' . $message . '</p>'; |
|
295 | + $message .= '<p>'.$message.'</p>'; |
|
296 | 296 | } else { |
297 | 297 | $dependencyGroups[$dependency->getDependency()][] = $backend; |
298 | 298 | } |
@@ -301,9 +301,9 @@ discard block |
||
301 | 301 | |
302 | 302 | foreach ($dependencyGroups as $module => $dependants) { |
303 | 303 | $backends = implode(', ', array_map(function($backend) { |
304 | - return '"' . $backend->getText() . '"'; |
|
304 | + return '"'.$backend->getText().'"'; |
|
305 | 305 | }, $dependants)); |
306 | - $message .= '<p>' . OC_Mount_Config::getSingleDependencyMessage($l, $module, $backends) . '</p>'; |
|
306 | + $message .= '<p>'.OC_Mount_Config::getSingleDependencyMessage($l, $module, $backends).'</p>'; |
|
307 | 307 | } |
308 | 308 | |
309 | 309 | return $message; |
@@ -320,11 +320,11 @@ discard block |
||
320 | 320 | private static function getSingleDependencyMessage(\OCP\IL10N $l, $module, $backend) { |
321 | 321 | switch (strtolower($module)) { |
322 | 322 | case 'curl': |
323 | - return (string)$l->t('The cURL support in PHP is not enabled or installed. Mounting of %s is not possible. Please ask your system administrator to install it.', [$backend]); |
|
323 | + return (string) $l->t('The cURL support in PHP is not enabled or installed. Mounting of %s is not possible. Please ask your system administrator to install it.', [$backend]); |
|
324 | 324 | case 'ftp': |
325 | - return (string)$l->t('The FTP support in PHP is not enabled or installed. Mounting of %s is not possible. Please ask your system administrator to install it.', [$backend]); |
|
325 | + return (string) $l->t('The FTP support in PHP is not enabled or installed. Mounting of %s is not possible. Please ask your system administrator to install it.', [$backend]); |
|
326 | 326 | default: |
327 | - return (string)$l->t('"%1$s" is not installed. Mounting of %2$s is not possible. Please ask your system administrator to install it.', [$module, $backend]); |
|
327 | + return (string) $l->t('"%1$s" is not installed. Mounting of %2$s is not possible. Please ask your system administrator to install it.', [$module, $backend]); |
|
328 | 328 | } |
329 | 329 | } |
330 | 330 | |
@@ -369,7 +369,7 @@ discard block |
||
369 | 369 | $cipher = self::getCipher(); |
370 | 370 | $iv = \OC::$server->getSecureRandom()->generate(16); |
371 | 371 | $cipher->setIV($iv); |
372 | - return base64_encode($iv . $cipher->encrypt($password)); |
|
372 | + return base64_encode($iv.$cipher->encrypt($password)); |
|
373 | 373 | } |
374 | 374 | |
375 | 375 | /** |
@@ -54,1110 +54,1110 @@ |
||
54 | 54 | */ |
55 | 55 | class ShareByMailProvider implements IShareProvider { |
56 | 56 | |
57 | - /** @var IDBConnection */ |
|
58 | - private $dbConnection; |
|
59 | - |
|
60 | - /** @var ILogger */ |
|
61 | - private $logger; |
|
62 | - |
|
63 | - /** @var ISecureRandom */ |
|
64 | - private $secureRandom; |
|
65 | - |
|
66 | - /** @var IUserManager */ |
|
67 | - private $userManager; |
|
68 | - |
|
69 | - /** @var IRootFolder */ |
|
70 | - private $rootFolder; |
|
71 | - |
|
72 | - /** @var IL10N */ |
|
73 | - private $l; |
|
74 | - |
|
75 | - /** @var IMailer */ |
|
76 | - private $mailer; |
|
77 | - |
|
78 | - /** @var IURLGenerator */ |
|
79 | - private $urlGenerator; |
|
80 | - |
|
81 | - /** @var IManager */ |
|
82 | - private $activityManager; |
|
83 | - |
|
84 | - /** @var SettingsManager */ |
|
85 | - private $settingsManager; |
|
86 | - |
|
87 | - /** @var Defaults */ |
|
88 | - private $defaults; |
|
89 | - |
|
90 | - /** @var IHasher */ |
|
91 | - private $hasher; |
|
92 | - |
|
93 | - /** @var CapabilitiesManager */ |
|
94 | - private $capabilitiesManager; |
|
95 | - |
|
96 | - /** |
|
97 | - * Return the identifier of this provider. |
|
98 | - * |
|
99 | - * @return string Containing only [a-zA-Z0-9] |
|
100 | - */ |
|
101 | - public function identifier() { |
|
102 | - return 'ocMailShare'; |
|
103 | - } |
|
104 | - |
|
105 | - /** |
|
106 | - * DefaultShareProvider constructor. |
|
107 | - * |
|
108 | - * @param IDBConnection $connection |
|
109 | - * @param ISecureRandom $secureRandom |
|
110 | - * @param IUserManager $userManager |
|
111 | - * @param IRootFolder $rootFolder |
|
112 | - * @param IL10N $l |
|
113 | - * @param ILogger $logger |
|
114 | - * @param IMailer $mailer |
|
115 | - * @param IURLGenerator $urlGenerator |
|
116 | - * @param IManager $activityManager |
|
117 | - * @param SettingsManager $settingsManager |
|
118 | - * @param Defaults $defaults |
|
119 | - * @param IHasher $hasher |
|
120 | - * @param CapabilitiesManager $capabilitiesManager |
|
121 | - */ |
|
122 | - public function __construct( |
|
123 | - IDBConnection $connection, |
|
124 | - ISecureRandom $secureRandom, |
|
125 | - IUserManager $userManager, |
|
126 | - IRootFolder $rootFolder, |
|
127 | - IL10N $l, |
|
128 | - ILogger $logger, |
|
129 | - IMailer $mailer, |
|
130 | - IURLGenerator $urlGenerator, |
|
131 | - IManager $activityManager, |
|
132 | - SettingsManager $settingsManager, |
|
133 | - Defaults $defaults, |
|
134 | - IHasher $hasher, |
|
135 | - CapabilitiesManager $capabilitiesManager |
|
136 | - ) { |
|
137 | - $this->dbConnection = $connection; |
|
138 | - $this->secureRandom = $secureRandom; |
|
139 | - $this->userManager = $userManager; |
|
140 | - $this->rootFolder = $rootFolder; |
|
141 | - $this->l = $l; |
|
142 | - $this->logger = $logger; |
|
143 | - $this->mailer = $mailer; |
|
144 | - $this->urlGenerator = $urlGenerator; |
|
145 | - $this->activityManager = $activityManager; |
|
146 | - $this->settingsManager = $settingsManager; |
|
147 | - $this->defaults = $defaults; |
|
148 | - $this->hasher = $hasher; |
|
149 | - $this->capabilitiesManager = $capabilitiesManager; |
|
150 | - } |
|
151 | - |
|
152 | - /** |
|
153 | - * Share a path |
|
154 | - * |
|
155 | - * @param IShare $share |
|
156 | - * @return IShare The share object |
|
157 | - * @throws ShareNotFound |
|
158 | - * @throws \Exception |
|
159 | - */ |
|
160 | - public function create(IShare $share) { |
|
161 | - |
|
162 | - $shareWith = $share->getSharedWith(); |
|
163 | - /* |
|
57 | + /** @var IDBConnection */ |
|
58 | + private $dbConnection; |
|
59 | + |
|
60 | + /** @var ILogger */ |
|
61 | + private $logger; |
|
62 | + |
|
63 | + /** @var ISecureRandom */ |
|
64 | + private $secureRandom; |
|
65 | + |
|
66 | + /** @var IUserManager */ |
|
67 | + private $userManager; |
|
68 | + |
|
69 | + /** @var IRootFolder */ |
|
70 | + private $rootFolder; |
|
71 | + |
|
72 | + /** @var IL10N */ |
|
73 | + private $l; |
|
74 | + |
|
75 | + /** @var IMailer */ |
|
76 | + private $mailer; |
|
77 | + |
|
78 | + /** @var IURLGenerator */ |
|
79 | + private $urlGenerator; |
|
80 | + |
|
81 | + /** @var IManager */ |
|
82 | + private $activityManager; |
|
83 | + |
|
84 | + /** @var SettingsManager */ |
|
85 | + private $settingsManager; |
|
86 | + |
|
87 | + /** @var Defaults */ |
|
88 | + private $defaults; |
|
89 | + |
|
90 | + /** @var IHasher */ |
|
91 | + private $hasher; |
|
92 | + |
|
93 | + /** @var CapabilitiesManager */ |
|
94 | + private $capabilitiesManager; |
|
95 | + |
|
96 | + /** |
|
97 | + * Return the identifier of this provider. |
|
98 | + * |
|
99 | + * @return string Containing only [a-zA-Z0-9] |
|
100 | + */ |
|
101 | + public function identifier() { |
|
102 | + return 'ocMailShare'; |
|
103 | + } |
|
104 | + |
|
105 | + /** |
|
106 | + * DefaultShareProvider constructor. |
|
107 | + * |
|
108 | + * @param IDBConnection $connection |
|
109 | + * @param ISecureRandom $secureRandom |
|
110 | + * @param IUserManager $userManager |
|
111 | + * @param IRootFolder $rootFolder |
|
112 | + * @param IL10N $l |
|
113 | + * @param ILogger $logger |
|
114 | + * @param IMailer $mailer |
|
115 | + * @param IURLGenerator $urlGenerator |
|
116 | + * @param IManager $activityManager |
|
117 | + * @param SettingsManager $settingsManager |
|
118 | + * @param Defaults $defaults |
|
119 | + * @param IHasher $hasher |
|
120 | + * @param CapabilitiesManager $capabilitiesManager |
|
121 | + */ |
|
122 | + public function __construct( |
|
123 | + IDBConnection $connection, |
|
124 | + ISecureRandom $secureRandom, |
|
125 | + IUserManager $userManager, |
|
126 | + IRootFolder $rootFolder, |
|
127 | + IL10N $l, |
|
128 | + ILogger $logger, |
|
129 | + IMailer $mailer, |
|
130 | + IURLGenerator $urlGenerator, |
|
131 | + IManager $activityManager, |
|
132 | + SettingsManager $settingsManager, |
|
133 | + Defaults $defaults, |
|
134 | + IHasher $hasher, |
|
135 | + CapabilitiesManager $capabilitiesManager |
|
136 | + ) { |
|
137 | + $this->dbConnection = $connection; |
|
138 | + $this->secureRandom = $secureRandom; |
|
139 | + $this->userManager = $userManager; |
|
140 | + $this->rootFolder = $rootFolder; |
|
141 | + $this->l = $l; |
|
142 | + $this->logger = $logger; |
|
143 | + $this->mailer = $mailer; |
|
144 | + $this->urlGenerator = $urlGenerator; |
|
145 | + $this->activityManager = $activityManager; |
|
146 | + $this->settingsManager = $settingsManager; |
|
147 | + $this->defaults = $defaults; |
|
148 | + $this->hasher = $hasher; |
|
149 | + $this->capabilitiesManager = $capabilitiesManager; |
|
150 | + } |
|
151 | + |
|
152 | + /** |
|
153 | + * Share a path |
|
154 | + * |
|
155 | + * @param IShare $share |
|
156 | + * @return IShare The share object |
|
157 | + * @throws ShareNotFound |
|
158 | + * @throws \Exception |
|
159 | + */ |
|
160 | + public function create(IShare $share) { |
|
161 | + |
|
162 | + $shareWith = $share->getSharedWith(); |
|
163 | + /* |
|
164 | 164 | * Check if file is not already shared with the remote user |
165 | 165 | */ |
166 | - $alreadyShared = $this->getSharedWith($shareWith, \OCP\Share::SHARE_TYPE_EMAIL, $share->getNode(), 1, 0); |
|
167 | - if (!empty($alreadyShared)) { |
|
168 | - $message = 'Sharing %1$s failed, this item is already shared with %2$s'; |
|
169 | - $message_t = $this->l->t('Sharing %1$s failed, this item is already shared with %2$s', array($share->getNode()->getName(), $shareWith)); |
|
170 | - $this->logger->debug(sprintf($message, $share->getNode()->getName(), $shareWith), ['app' => 'Federated File Sharing']); |
|
171 | - throw new \Exception($message_t); |
|
172 | - } |
|
173 | - |
|
174 | - // if the admin enforces a password for all mail shares we create a |
|
175 | - // random password and send it to the recipient |
|
176 | - $password = ''; |
|
177 | - $passwordEnforced = $this->settingsManager->enforcePasswordProtection(); |
|
178 | - if ($passwordEnforced) { |
|
179 | - $password = $this->autoGeneratePassword($share); |
|
180 | - } |
|
181 | - |
|
182 | - $shareId = $this->createMailShare($share); |
|
183 | - $send = $this->sendPassword($share, $password); |
|
184 | - if ($passwordEnforced && $send === false) { |
|
185 | - $this->sendPasswordToOwner($share, $password); |
|
186 | - } |
|
187 | - |
|
188 | - $this->createShareActivity($share); |
|
189 | - $data = $this->getRawShare($shareId); |
|
190 | - |
|
191 | - return $this->createShareObject($data); |
|
192 | - |
|
193 | - } |
|
194 | - |
|
195 | - /** |
|
196 | - * auto generate password in case of password enforcement on mail shares |
|
197 | - * |
|
198 | - * @param IShare $share |
|
199 | - * @return string |
|
200 | - * @throws \Exception |
|
201 | - */ |
|
202 | - protected function autoGeneratePassword($share) { |
|
203 | - $initiatorUser = $this->userManager->get($share->getSharedBy()); |
|
204 | - $initiatorEMailAddress = ($initiatorUser instanceof IUser) ? $initiatorUser->getEMailAddress() : null; |
|
205 | - $allowPasswordByMail = $this->settingsManager->sendPasswordByMail(); |
|
206 | - |
|
207 | - if ($initiatorEMailAddress === null && !$allowPasswordByMail) { |
|
208 | - throw new \Exception( |
|
209 | - $this->l->t("We can't send you the auto-generated password. Please set a valid email address in your personal settings and try again.") |
|
210 | - ); |
|
211 | - } |
|
212 | - |
|
213 | - $passwordPolicy = $this->getPasswordPolicy(); |
|
214 | - $passwordCharset = ISecureRandom::CHAR_LOWER . ISecureRandom::CHAR_UPPER . ISecureRandom::CHAR_DIGITS; |
|
215 | - $passwordLength = 8; |
|
216 | - if (!empty($passwordPolicy)) { |
|
217 | - $passwordLength = (int)$passwordPolicy['minLength'] > 0 ? (int)$passwordPolicy['minLength'] : $passwordLength; |
|
218 | - $passwordCharset .= $passwordPolicy['enforceSpecialCharacters'] ? ISecureRandom::CHAR_SYMBOLS : ''; |
|
219 | - } |
|
220 | - |
|
221 | - $password = $this->secureRandom->generate($passwordLength, $passwordCharset); |
|
222 | - |
|
223 | - $share->setPassword($this->hasher->hash($password)); |
|
224 | - |
|
225 | - return $password; |
|
226 | - } |
|
227 | - |
|
228 | - /** |
|
229 | - * get password policy |
|
230 | - * |
|
231 | - * @return array |
|
232 | - */ |
|
233 | - protected function getPasswordPolicy() { |
|
234 | - $capabilities = $this->capabilitiesManager->getCapabilities(); |
|
235 | - if (isset($capabilities['password_policy'])) { |
|
236 | - return $capabilities['password_policy']; |
|
237 | - } |
|
238 | - |
|
239 | - return []; |
|
240 | - } |
|
241 | - |
|
242 | - /** |
|
243 | - * create activity if a file/folder was shared by mail |
|
244 | - * |
|
245 | - * @param IShare $share |
|
246 | - */ |
|
247 | - protected function createShareActivity(IShare $share) { |
|
248 | - |
|
249 | - $userFolder = $this->rootFolder->getUserFolder($share->getSharedBy()); |
|
250 | - |
|
251 | - $this->publishActivity( |
|
252 | - Activity::SUBJECT_SHARED_EMAIL_SELF, |
|
253 | - [$userFolder->getRelativePath($share->getNode()->getPath()), $share->getSharedWith()], |
|
254 | - $share->getSharedBy(), |
|
255 | - $share->getNode()->getId(), |
|
256 | - $userFolder->getRelativePath($share->getNode()->getPath()) |
|
257 | - ); |
|
258 | - |
|
259 | - if ($share->getShareOwner() !== $share->getSharedBy()) { |
|
260 | - $ownerFolder = $this->rootFolder->getUserFolder($share->getShareOwner()); |
|
261 | - $fileId = $share->getNode()->getId(); |
|
262 | - $nodes = $ownerFolder->getById($fileId); |
|
263 | - $ownerPath = $nodes[0]->getPath(); |
|
264 | - $this->publishActivity( |
|
265 | - Activity::SUBJECT_SHARED_EMAIL_BY, |
|
266 | - [$ownerFolder->getRelativePath($ownerPath), $share->getSharedWith(), $share->getSharedBy()], |
|
267 | - $share->getShareOwner(), |
|
268 | - $fileId, |
|
269 | - $ownerFolder->getRelativePath($ownerPath) |
|
270 | - ); |
|
271 | - } |
|
272 | - |
|
273 | - } |
|
274 | - |
|
275 | - /** |
|
276 | - * create activity if a file/folder was shared by mail |
|
277 | - * |
|
278 | - * @param IShare $share |
|
279 | - * @param string $sharedWith |
|
280 | - * @param bool $sendToSelf |
|
281 | - */ |
|
282 | - protected function createPasswordSendActivity(IShare $share, $sharedWith, $sendToSelf) { |
|
283 | - |
|
284 | - $userFolder = $this->rootFolder->getUserFolder($share->getSharedBy()); |
|
285 | - |
|
286 | - if ($sendToSelf) { |
|
287 | - $this->publishActivity( |
|
288 | - Activity::SUBJECT_SHARED_EMAIL_PASSWORD_SEND_SELF, |
|
289 | - [$userFolder->getRelativePath($share->getNode()->getPath())], |
|
290 | - $share->getSharedBy(), |
|
291 | - $share->getNode()->getId(), |
|
292 | - $userFolder->getRelativePath($share->getNode()->getPath()) |
|
293 | - ); |
|
294 | - } else { |
|
295 | - $this->publishActivity( |
|
296 | - Activity::SUBJECT_SHARED_EMAIL_PASSWORD_SEND, |
|
297 | - [$userFolder->getRelativePath($share->getNode()->getPath()), $sharedWith], |
|
298 | - $share->getSharedBy(), |
|
299 | - $share->getNode()->getId(), |
|
300 | - $userFolder->getRelativePath($share->getNode()->getPath()) |
|
301 | - ); |
|
302 | - } |
|
303 | - } |
|
304 | - |
|
305 | - |
|
306 | - /** |
|
307 | - * publish activity if a file/folder was shared by mail |
|
308 | - * |
|
309 | - * @param $subject |
|
310 | - * @param $parameters |
|
311 | - * @param $affectedUser |
|
312 | - * @param $fileId |
|
313 | - * @param $filePath |
|
314 | - */ |
|
315 | - protected function publishActivity($subject, $parameters, $affectedUser, $fileId, $filePath) { |
|
316 | - $event = $this->activityManager->generateEvent(); |
|
317 | - $event->setApp('sharebymail') |
|
318 | - ->setType('shared') |
|
319 | - ->setSubject($subject, $parameters) |
|
320 | - ->setAffectedUser($affectedUser) |
|
321 | - ->setObject('files', $fileId, $filePath); |
|
322 | - $this->activityManager->publish($event); |
|
323 | - |
|
324 | - } |
|
325 | - |
|
326 | - /** |
|
327 | - * @param IShare $share |
|
328 | - * @return int |
|
329 | - * @throws \Exception |
|
330 | - */ |
|
331 | - protected function createMailShare(IShare $share) { |
|
332 | - $share->setToken($this->generateToken()); |
|
333 | - $shareId = $this->addShareToDB( |
|
334 | - $share->getNodeId(), |
|
335 | - $share->getNodeType(), |
|
336 | - $share->getSharedWith(), |
|
337 | - $share->getSharedBy(), |
|
338 | - $share->getShareOwner(), |
|
339 | - $share->getPermissions(), |
|
340 | - $share->getToken(), |
|
341 | - $share->getPassword(), |
|
342 | - $share->getSendPasswordByTalk() |
|
343 | - ); |
|
344 | - |
|
345 | - try { |
|
346 | - $link = $this->urlGenerator->linkToRouteAbsolute('files_sharing.sharecontroller.showShare', |
|
347 | - ['token' => $share->getToken()]); |
|
348 | - $this->sendMailNotification( |
|
349 | - $share->getNode()->getName(), |
|
350 | - $link, |
|
351 | - $share->getSharedBy(), |
|
352 | - $share->getSharedWith(), |
|
353 | - $share->getExpirationDate() |
|
354 | - ); |
|
355 | - } catch (HintException $hintException) { |
|
356 | - $this->logger->logException($hintException, [ |
|
357 | - 'message' => 'Failed to send share by mail.', |
|
358 | - 'level' => ILogger::ERROR, |
|
359 | - 'app' => 'sharebymail', |
|
360 | - ]); |
|
361 | - $this->removeShareFromTable($shareId); |
|
362 | - throw $hintException; |
|
363 | - } catch (\Exception $e) { |
|
364 | - $this->logger->logException($e, [ |
|
365 | - 'message' => 'Failed to send share by mail.', |
|
366 | - 'level' => ILogger::ERROR, |
|
367 | - 'app' => 'sharebymail', |
|
368 | - ]); |
|
369 | - $this->removeShareFromTable($shareId); |
|
370 | - throw new HintException('Failed to send share by mail', |
|
371 | - $this->l->t('Failed to send share by email')); |
|
372 | - } |
|
373 | - |
|
374 | - return $shareId; |
|
375 | - |
|
376 | - } |
|
377 | - |
|
378 | - /** |
|
379 | - * @param string $filename |
|
380 | - * @param string $link |
|
381 | - * @param string $initiator |
|
382 | - * @param string $shareWith |
|
383 | - * @param \DateTime|null $expiration |
|
384 | - * @throws \Exception If mail couldn't be sent |
|
385 | - */ |
|
386 | - protected function sendMailNotification($filename, |
|
387 | - $link, |
|
388 | - $initiator, |
|
389 | - $shareWith, |
|
390 | - \DateTime $expiration = null) { |
|
391 | - $initiatorUser = $this->userManager->get($initiator); |
|
392 | - $initiatorDisplayName = ($initiatorUser instanceof IUser) ? $initiatorUser->getDisplayName() : $initiator; |
|
393 | - $message = $this->mailer->createMessage(); |
|
394 | - |
|
395 | - $emailTemplate = $this->mailer->createEMailTemplate('sharebymail.RecipientNotification', [ |
|
396 | - 'filename' => $filename, |
|
397 | - 'link' => $link, |
|
398 | - 'initiator' => $initiatorDisplayName, |
|
399 | - 'expiration' => $expiration, |
|
400 | - 'shareWith' => $shareWith, |
|
401 | - ]); |
|
402 | - |
|
403 | - $emailTemplate->setSubject($this->l->t('%1$s shared »%2$s« with you', array($initiatorDisplayName, $filename))); |
|
404 | - $emailTemplate->addHeader(); |
|
405 | - $emailTemplate->addHeading($this->l->t('%1$s shared »%2$s« with you', [$initiatorDisplayName, $filename]), false); |
|
406 | - $text = $this->l->t('%1$s shared »%2$s« with you.', [$initiatorDisplayName, $filename]); |
|
407 | - |
|
408 | - $emailTemplate->addBodyText( |
|
409 | - htmlspecialchars($text . ' ' . $this->l->t('Click the button below to open it.')), |
|
410 | - $text |
|
411 | - ); |
|
412 | - $emailTemplate->addBodyButton( |
|
413 | - $this->l->t('Open »%s«', [$filename]), |
|
414 | - $link |
|
415 | - ); |
|
416 | - |
|
417 | - $message->setTo([$shareWith]); |
|
418 | - |
|
419 | - // The "From" contains the sharers name |
|
420 | - $instanceName = $this->defaults->getName(); |
|
421 | - $senderName = $this->l->t( |
|
422 | - '%1$s via %2$s', |
|
423 | - [ |
|
424 | - $initiatorDisplayName, |
|
425 | - $instanceName |
|
426 | - ] |
|
427 | - ); |
|
428 | - $message->setFrom([\OCP\Util::getDefaultEmailAddress($instanceName) => $senderName]); |
|
429 | - |
|
430 | - // The "Reply-To" is set to the sharer if an mail address is configured |
|
431 | - // also the default footer contains a "Do not reply" which needs to be adjusted. |
|
432 | - $initiatorEmail = $initiatorUser->getEMailAddress(); |
|
433 | - if($initiatorEmail !== null) { |
|
434 | - $message->setReplyTo([$initiatorEmail => $initiatorDisplayName]); |
|
435 | - $emailTemplate->addFooter($instanceName . ($this->defaults->getSlogan() !== '' ? ' - ' . $this->defaults->getSlogan() : '')); |
|
436 | - } else { |
|
437 | - $emailTemplate->addFooter(); |
|
438 | - } |
|
439 | - |
|
440 | - $message->useTemplate($emailTemplate); |
|
441 | - $this->mailer->send($message); |
|
442 | - } |
|
443 | - |
|
444 | - /** |
|
445 | - * send password to recipient of a mail share |
|
446 | - * |
|
447 | - * @param IShare $share |
|
448 | - * @param string $password |
|
449 | - * @return bool |
|
450 | - */ |
|
451 | - protected function sendPassword(IShare $share, $password) { |
|
452 | - |
|
453 | - $filename = $share->getNode()->getName(); |
|
454 | - $initiator = $share->getSharedBy(); |
|
455 | - $shareWith = $share->getSharedWith(); |
|
456 | - |
|
457 | - if ($password === '' || $this->settingsManager->sendPasswordByMail() === false || $share->getSendPasswordByTalk()) { |
|
458 | - return false; |
|
459 | - } |
|
460 | - |
|
461 | - $initiatorUser = $this->userManager->get($initiator); |
|
462 | - $initiatorDisplayName = ($initiatorUser instanceof IUser) ? $initiatorUser->getDisplayName() : $initiator; |
|
463 | - $initiatorEmailAddress = ($initiatorUser instanceof IUser) ? $initiatorUser->getEMailAddress() : null; |
|
464 | - |
|
465 | - $plainBodyPart = $this->l->t("%1\$s shared »%2\$s« with you.\nYou should have already received a separate mail with a link to access it.\n", [$initiatorDisplayName, $filename]); |
|
466 | - $htmlBodyPart = $this->l->t('%1$s shared »%2$s« with you. You should have already received a separate mail with a link to access it.', [$initiatorDisplayName, $filename]); |
|
467 | - |
|
468 | - $message = $this->mailer->createMessage(); |
|
469 | - |
|
470 | - $emailTemplate = $this->mailer->createEMailTemplate('sharebymail.RecipientPasswordNotification', [ |
|
471 | - 'filename' => $filename, |
|
472 | - 'password' => $password, |
|
473 | - 'initiator' => $initiatorDisplayName, |
|
474 | - 'initiatorEmail' => $initiatorEmailAddress, |
|
475 | - 'shareWith' => $shareWith, |
|
476 | - ]); |
|
477 | - |
|
478 | - $emailTemplate->setSubject($this->l->t('Password to access »%1$s« shared to you by %2$s', [$filename, $initiatorDisplayName])); |
|
479 | - $emailTemplate->addHeader(); |
|
480 | - $emailTemplate->addHeading($this->l->t('Password to access »%s«', [$filename]), false); |
|
481 | - $emailTemplate->addBodyText(htmlspecialchars($htmlBodyPart), $plainBodyPart); |
|
482 | - $emailTemplate->addBodyText($this->l->t('It is protected with the following password:')); |
|
483 | - $emailTemplate->addBodyText($password); |
|
484 | - |
|
485 | - // The "From" contains the sharers name |
|
486 | - $instanceName = $this->defaults->getName(); |
|
487 | - $senderName = $this->l->t( |
|
488 | - '%1$s via %2$s', |
|
489 | - [ |
|
490 | - $initiatorDisplayName, |
|
491 | - $instanceName |
|
492 | - ] |
|
493 | - ); |
|
494 | - $message->setFrom([\OCP\Util::getDefaultEmailAddress($instanceName) => $senderName]); |
|
495 | - if ($initiatorEmailAddress !== null) { |
|
496 | - $message->setReplyTo([$initiatorEmailAddress => $initiatorDisplayName]); |
|
497 | - $emailTemplate->addFooter($instanceName . ' - ' . $this->defaults->getSlogan()); |
|
498 | - } else { |
|
499 | - $emailTemplate->addFooter(); |
|
500 | - } |
|
501 | - |
|
502 | - $message->setTo([$shareWith]); |
|
503 | - $message->useTemplate($emailTemplate); |
|
504 | - $this->mailer->send($message); |
|
505 | - |
|
506 | - $this->createPasswordSendActivity($share, $shareWith, false); |
|
507 | - |
|
508 | - return true; |
|
509 | - } |
|
510 | - |
|
511 | - protected function sendNote(IShare $share) { |
|
512 | - |
|
513 | - $recipient = $share->getSharedWith(); |
|
514 | - |
|
515 | - |
|
516 | - $filename = $share->getNode()->getName(); |
|
517 | - $initiator = $share->getSharedBy(); |
|
518 | - $note = $share->getNote(); |
|
519 | - |
|
520 | - $initiatorUser = $this->userManager->get($initiator); |
|
521 | - $initiatorDisplayName = ($initiatorUser instanceof IUser) ? $initiatorUser->getDisplayName() : $initiator; |
|
522 | - $initiatorEmailAddress = ($initiatorUser instanceof IUser) ? $initiatorUser->getEMailAddress() : null; |
|
523 | - |
|
524 | - $plainHeading = $this->l->t('%1$s shared »%2$s« with you and wants to add:', [$initiatorDisplayName, $filename]); |
|
525 | - $htmlHeading = $this->l->t('%1$s shared »%2$s« with you and wants to add', [$initiatorDisplayName, $filename]); |
|
526 | - |
|
527 | - $message = $this->mailer->createMessage(); |
|
528 | - |
|
529 | - $emailTemplate = $this->mailer->createEMailTemplate('shareByMail.sendNote'); |
|
530 | - |
|
531 | - $emailTemplate->setSubject($this->l->t('»%s« added a note to a file shared with you', [$initiatorDisplayName])); |
|
532 | - $emailTemplate->addHeader(); |
|
533 | - $emailTemplate->addHeading(htmlspecialchars($htmlHeading), $plainHeading); |
|
534 | - $emailTemplate->addBodyText(htmlspecialchars($note), $note); |
|
535 | - |
|
536 | - $link = $this->urlGenerator->linkToRouteAbsolute('files_sharing.sharecontroller.showShare', |
|
537 | - ['token' => $share->getToken()]); |
|
538 | - $emailTemplate->addBodyButton( |
|
539 | - $this->l->t('Open »%s«', [$filename]), |
|
540 | - $link |
|
541 | - ); |
|
542 | - |
|
543 | - // The "From" contains the sharers name |
|
544 | - $instanceName = $this->defaults->getName(); |
|
545 | - $senderName = $this->l->t( |
|
546 | - '%1$s via %2$s', |
|
547 | - [ |
|
548 | - $initiatorDisplayName, |
|
549 | - $instanceName |
|
550 | - ] |
|
551 | - ); |
|
552 | - $message->setFrom([\OCP\Util::getDefaultEmailAddress($instanceName) => $senderName]); |
|
553 | - if ($initiatorEmailAddress !== null) { |
|
554 | - $message->setReplyTo([$initiatorEmailAddress => $initiatorDisplayName]); |
|
555 | - $emailTemplate->addFooter($instanceName . ' - ' . $this->defaults->getSlogan()); |
|
556 | - } else { |
|
557 | - $emailTemplate->addFooter(); |
|
558 | - } |
|
559 | - |
|
560 | - $message->setTo([$recipient]); |
|
561 | - $message->useTemplate($emailTemplate); |
|
562 | - $this->mailer->send($message); |
|
563 | - |
|
564 | - } |
|
565 | - |
|
566 | - /** |
|
567 | - * send auto generated password to the owner. This happens if the admin enforces |
|
568 | - * a password for mail shares and forbid to send the password by mail to the recipient |
|
569 | - * |
|
570 | - * @param IShare $share |
|
571 | - * @param string $password |
|
572 | - * @return bool |
|
573 | - * @throws \Exception |
|
574 | - */ |
|
575 | - protected function sendPasswordToOwner(IShare $share, $password) { |
|
576 | - |
|
577 | - $filename = $share->getNode()->getName(); |
|
578 | - $initiator = $this->userManager->get($share->getSharedBy()); |
|
579 | - $initiatorEMailAddress = ($initiator instanceof IUser) ? $initiator->getEMailAddress() : null; |
|
580 | - $initiatorDisplayName = ($initiator instanceof IUser) ? $initiator->getDisplayName() : $share->getSharedBy(); |
|
581 | - $shareWith = $share->getSharedWith(); |
|
582 | - |
|
583 | - if ($initiatorEMailAddress === null) { |
|
584 | - throw new \Exception( |
|
585 | - $this->l->t("We can't send you the auto-generated password. Please set a valid email address in your personal settings and try again.") |
|
586 | - ); |
|
587 | - } |
|
588 | - |
|
589 | - $bodyPart = $this->l->t('You just shared »%1$s« with %2$s. The share was already send to the recipient. Due to the security policies defined by the administrator of %3$s each share needs to be protected by password and it is not allowed to send the password directly to the recipient. Therefore you need to forward the password manually to the recipient.', [$filename, $shareWith, $this->defaults->getName()]); |
|
590 | - |
|
591 | - $message = $this->mailer->createMessage(); |
|
592 | - $emailTemplate = $this->mailer->createEMailTemplate('sharebymail.OwnerPasswordNotification', [ |
|
593 | - 'filename' => $filename, |
|
594 | - 'password' => $password, |
|
595 | - 'initiator' => $initiatorDisplayName, |
|
596 | - 'initiatorEmail' => $initiatorEMailAddress, |
|
597 | - 'shareWith' => $shareWith, |
|
598 | - ]); |
|
599 | - |
|
600 | - $emailTemplate->setSubject($this->l->t('Password to access »%1$s« shared with %2$s', [$filename, $shareWith])); |
|
601 | - $emailTemplate->addHeader(); |
|
602 | - $emailTemplate->addHeading($this->l->t('Password to access »%s«', [$filename]), false); |
|
603 | - $emailTemplate->addBodyText($bodyPart); |
|
604 | - $emailTemplate->addBodyText($this->l->t('This is the password:')); |
|
605 | - $emailTemplate->addBodyText($password); |
|
606 | - $emailTemplate->addBodyText($this->l->t('You can choose a different password at any time in the share dialog.')); |
|
607 | - $emailTemplate->addFooter(); |
|
608 | - |
|
609 | - if ($initiatorEMailAddress) { |
|
610 | - $message->setFrom([$initiatorEMailAddress => $initiatorDisplayName]); |
|
611 | - } |
|
612 | - $message->setTo([$initiatorEMailAddress => $initiatorDisplayName]); |
|
613 | - $message->useTemplate($emailTemplate); |
|
614 | - $this->mailer->send($message); |
|
615 | - |
|
616 | - $this->createPasswordSendActivity($share, $shareWith, true); |
|
617 | - |
|
618 | - return true; |
|
619 | - } |
|
620 | - |
|
621 | - /** |
|
622 | - * generate share token |
|
623 | - * |
|
624 | - * @return string |
|
625 | - */ |
|
626 | - protected function generateToken($size = 15) { |
|
627 | - $token = $this->secureRandom->generate($size, ISecureRandom::CHAR_HUMAN_READABLE); |
|
628 | - return $token; |
|
629 | - } |
|
630 | - |
|
631 | - /** |
|
632 | - * Get all children of this share |
|
633 | - * |
|
634 | - * @param IShare $parent |
|
635 | - * @return IShare[] |
|
636 | - */ |
|
637 | - public function getChildren(IShare $parent) { |
|
638 | - $children = []; |
|
639 | - |
|
640 | - $qb = $this->dbConnection->getQueryBuilder(); |
|
641 | - $qb->select('*') |
|
642 | - ->from('share') |
|
643 | - ->where($qb->expr()->eq('parent', $qb->createNamedParameter($parent->getId()))) |
|
644 | - ->andWhere($qb->expr()->eq('share_type', $qb->createNamedParameter(\OCP\Share::SHARE_TYPE_EMAIL))) |
|
645 | - ->orderBy('id'); |
|
646 | - |
|
647 | - $cursor = $qb->execute(); |
|
648 | - while($data = $cursor->fetch()) { |
|
649 | - $children[] = $this->createShareObject($data); |
|
650 | - } |
|
651 | - $cursor->closeCursor(); |
|
652 | - |
|
653 | - return $children; |
|
654 | - } |
|
655 | - |
|
656 | - /** |
|
657 | - * add share to the database and return the ID |
|
658 | - * |
|
659 | - * @param int $itemSource |
|
660 | - * @param string $itemType |
|
661 | - * @param string $shareWith |
|
662 | - * @param string $sharedBy |
|
663 | - * @param string $uidOwner |
|
664 | - * @param int $permissions |
|
665 | - * @param string $token |
|
666 | - * @param string $password |
|
667 | - * @param bool $sendPasswordByTalk |
|
668 | - * @return int |
|
669 | - */ |
|
670 | - protected function addShareToDB($itemSource, $itemType, $shareWith, $sharedBy, $uidOwner, $permissions, $token, $password, $sendPasswordByTalk) { |
|
671 | - $qb = $this->dbConnection->getQueryBuilder(); |
|
672 | - $qb->insert('share') |
|
673 | - ->setValue('share_type', $qb->createNamedParameter(\OCP\Share::SHARE_TYPE_EMAIL)) |
|
674 | - ->setValue('item_type', $qb->createNamedParameter($itemType)) |
|
675 | - ->setValue('item_source', $qb->createNamedParameter($itemSource)) |
|
676 | - ->setValue('file_source', $qb->createNamedParameter($itemSource)) |
|
677 | - ->setValue('share_with', $qb->createNamedParameter($shareWith)) |
|
678 | - ->setValue('uid_owner', $qb->createNamedParameter($uidOwner)) |
|
679 | - ->setValue('uid_initiator', $qb->createNamedParameter($sharedBy)) |
|
680 | - ->setValue('permissions', $qb->createNamedParameter($permissions)) |
|
681 | - ->setValue('token', $qb->createNamedParameter($token)) |
|
682 | - ->setValue('password', $qb->createNamedParameter($password)) |
|
683 | - ->setValue('password_by_talk', $qb->createNamedParameter($sendPasswordByTalk, IQueryBuilder::PARAM_BOOL)) |
|
684 | - ->setValue('stime', $qb->createNamedParameter(time())); |
|
685 | - |
|
686 | - /* |
|
166 | + $alreadyShared = $this->getSharedWith($shareWith, \OCP\Share::SHARE_TYPE_EMAIL, $share->getNode(), 1, 0); |
|
167 | + if (!empty($alreadyShared)) { |
|
168 | + $message = 'Sharing %1$s failed, this item is already shared with %2$s'; |
|
169 | + $message_t = $this->l->t('Sharing %1$s failed, this item is already shared with %2$s', array($share->getNode()->getName(), $shareWith)); |
|
170 | + $this->logger->debug(sprintf($message, $share->getNode()->getName(), $shareWith), ['app' => 'Federated File Sharing']); |
|
171 | + throw new \Exception($message_t); |
|
172 | + } |
|
173 | + |
|
174 | + // if the admin enforces a password for all mail shares we create a |
|
175 | + // random password and send it to the recipient |
|
176 | + $password = ''; |
|
177 | + $passwordEnforced = $this->settingsManager->enforcePasswordProtection(); |
|
178 | + if ($passwordEnforced) { |
|
179 | + $password = $this->autoGeneratePassword($share); |
|
180 | + } |
|
181 | + |
|
182 | + $shareId = $this->createMailShare($share); |
|
183 | + $send = $this->sendPassword($share, $password); |
|
184 | + if ($passwordEnforced && $send === false) { |
|
185 | + $this->sendPasswordToOwner($share, $password); |
|
186 | + } |
|
187 | + |
|
188 | + $this->createShareActivity($share); |
|
189 | + $data = $this->getRawShare($shareId); |
|
190 | + |
|
191 | + return $this->createShareObject($data); |
|
192 | + |
|
193 | + } |
|
194 | + |
|
195 | + /** |
|
196 | + * auto generate password in case of password enforcement on mail shares |
|
197 | + * |
|
198 | + * @param IShare $share |
|
199 | + * @return string |
|
200 | + * @throws \Exception |
|
201 | + */ |
|
202 | + protected function autoGeneratePassword($share) { |
|
203 | + $initiatorUser = $this->userManager->get($share->getSharedBy()); |
|
204 | + $initiatorEMailAddress = ($initiatorUser instanceof IUser) ? $initiatorUser->getEMailAddress() : null; |
|
205 | + $allowPasswordByMail = $this->settingsManager->sendPasswordByMail(); |
|
206 | + |
|
207 | + if ($initiatorEMailAddress === null && !$allowPasswordByMail) { |
|
208 | + throw new \Exception( |
|
209 | + $this->l->t("We can't send you the auto-generated password. Please set a valid email address in your personal settings and try again.") |
|
210 | + ); |
|
211 | + } |
|
212 | + |
|
213 | + $passwordPolicy = $this->getPasswordPolicy(); |
|
214 | + $passwordCharset = ISecureRandom::CHAR_LOWER . ISecureRandom::CHAR_UPPER . ISecureRandom::CHAR_DIGITS; |
|
215 | + $passwordLength = 8; |
|
216 | + if (!empty($passwordPolicy)) { |
|
217 | + $passwordLength = (int)$passwordPolicy['minLength'] > 0 ? (int)$passwordPolicy['minLength'] : $passwordLength; |
|
218 | + $passwordCharset .= $passwordPolicy['enforceSpecialCharacters'] ? ISecureRandom::CHAR_SYMBOLS : ''; |
|
219 | + } |
|
220 | + |
|
221 | + $password = $this->secureRandom->generate($passwordLength, $passwordCharset); |
|
222 | + |
|
223 | + $share->setPassword($this->hasher->hash($password)); |
|
224 | + |
|
225 | + return $password; |
|
226 | + } |
|
227 | + |
|
228 | + /** |
|
229 | + * get password policy |
|
230 | + * |
|
231 | + * @return array |
|
232 | + */ |
|
233 | + protected function getPasswordPolicy() { |
|
234 | + $capabilities = $this->capabilitiesManager->getCapabilities(); |
|
235 | + if (isset($capabilities['password_policy'])) { |
|
236 | + return $capabilities['password_policy']; |
|
237 | + } |
|
238 | + |
|
239 | + return []; |
|
240 | + } |
|
241 | + |
|
242 | + /** |
|
243 | + * create activity if a file/folder was shared by mail |
|
244 | + * |
|
245 | + * @param IShare $share |
|
246 | + */ |
|
247 | + protected function createShareActivity(IShare $share) { |
|
248 | + |
|
249 | + $userFolder = $this->rootFolder->getUserFolder($share->getSharedBy()); |
|
250 | + |
|
251 | + $this->publishActivity( |
|
252 | + Activity::SUBJECT_SHARED_EMAIL_SELF, |
|
253 | + [$userFolder->getRelativePath($share->getNode()->getPath()), $share->getSharedWith()], |
|
254 | + $share->getSharedBy(), |
|
255 | + $share->getNode()->getId(), |
|
256 | + $userFolder->getRelativePath($share->getNode()->getPath()) |
|
257 | + ); |
|
258 | + |
|
259 | + if ($share->getShareOwner() !== $share->getSharedBy()) { |
|
260 | + $ownerFolder = $this->rootFolder->getUserFolder($share->getShareOwner()); |
|
261 | + $fileId = $share->getNode()->getId(); |
|
262 | + $nodes = $ownerFolder->getById($fileId); |
|
263 | + $ownerPath = $nodes[0]->getPath(); |
|
264 | + $this->publishActivity( |
|
265 | + Activity::SUBJECT_SHARED_EMAIL_BY, |
|
266 | + [$ownerFolder->getRelativePath($ownerPath), $share->getSharedWith(), $share->getSharedBy()], |
|
267 | + $share->getShareOwner(), |
|
268 | + $fileId, |
|
269 | + $ownerFolder->getRelativePath($ownerPath) |
|
270 | + ); |
|
271 | + } |
|
272 | + |
|
273 | + } |
|
274 | + |
|
275 | + /** |
|
276 | + * create activity if a file/folder was shared by mail |
|
277 | + * |
|
278 | + * @param IShare $share |
|
279 | + * @param string $sharedWith |
|
280 | + * @param bool $sendToSelf |
|
281 | + */ |
|
282 | + protected function createPasswordSendActivity(IShare $share, $sharedWith, $sendToSelf) { |
|
283 | + |
|
284 | + $userFolder = $this->rootFolder->getUserFolder($share->getSharedBy()); |
|
285 | + |
|
286 | + if ($sendToSelf) { |
|
287 | + $this->publishActivity( |
|
288 | + Activity::SUBJECT_SHARED_EMAIL_PASSWORD_SEND_SELF, |
|
289 | + [$userFolder->getRelativePath($share->getNode()->getPath())], |
|
290 | + $share->getSharedBy(), |
|
291 | + $share->getNode()->getId(), |
|
292 | + $userFolder->getRelativePath($share->getNode()->getPath()) |
|
293 | + ); |
|
294 | + } else { |
|
295 | + $this->publishActivity( |
|
296 | + Activity::SUBJECT_SHARED_EMAIL_PASSWORD_SEND, |
|
297 | + [$userFolder->getRelativePath($share->getNode()->getPath()), $sharedWith], |
|
298 | + $share->getSharedBy(), |
|
299 | + $share->getNode()->getId(), |
|
300 | + $userFolder->getRelativePath($share->getNode()->getPath()) |
|
301 | + ); |
|
302 | + } |
|
303 | + } |
|
304 | + |
|
305 | + |
|
306 | + /** |
|
307 | + * publish activity if a file/folder was shared by mail |
|
308 | + * |
|
309 | + * @param $subject |
|
310 | + * @param $parameters |
|
311 | + * @param $affectedUser |
|
312 | + * @param $fileId |
|
313 | + * @param $filePath |
|
314 | + */ |
|
315 | + protected function publishActivity($subject, $parameters, $affectedUser, $fileId, $filePath) { |
|
316 | + $event = $this->activityManager->generateEvent(); |
|
317 | + $event->setApp('sharebymail') |
|
318 | + ->setType('shared') |
|
319 | + ->setSubject($subject, $parameters) |
|
320 | + ->setAffectedUser($affectedUser) |
|
321 | + ->setObject('files', $fileId, $filePath); |
|
322 | + $this->activityManager->publish($event); |
|
323 | + |
|
324 | + } |
|
325 | + |
|
326 | + /** |
|
327 | + * @param IShare $share |
|
328 | + * @return int |
|
329 | + * @throws \Exception |
|
330 | + */ |
|
331 | + protected function createMailShare(IShare $share) { |
|
332 | + $share->setToken($this->generateToken()); |
|
333 | + $shareId = $this->addShareToDB( |
|
334 | + $share->getNodeId(), |
|
335 | + $share->getNodeType(), |
|
336 | + $share->getSharedWith(), |
|
337 | + $share->getSharedBy(), |
|
338 | + $share->getShareOwner(), |
|
339 | + $share->getPermissions(), |
|
340 | + $share->getToken(), |
|
341 | + $share->getPassword(), |
|
342 | + $share->getSendPasswordByTalk() |
|
343 | + ); |
|
344 | + |
|
345 | + try { |
|
346 | + $link = $this->urlGenerator->linkToRouteAbsolute('files_sharing.sharecontroller.showShare', |
|
347 | + ['token' => $share->getToken()]); |
|
348 | + $this->sendMailNotification( |
|
349 | + $share->getNode()->getName(), |
|
350 | + $link, |
|
351 | + $share->getSharedBy(), |
|
352 | + $share->getSharedWith(), |
|
353 | + $share->getExpirationDate() |
|
354 | + ); |
|
355 | + } catch (HintException $hintException) { |
|
356 | + $this->logger->logException($hintException, [ |
|
357 | + 'message' => 'Failed to send share by mail.', |
|
358 | + 'level' => ILogger::ERROR, |
|
359 | + 'app' => 'sharebymail', |
|
360 | + ]); |
|
361 | + $this->removeShareFromTable($shareId); |
|
362 | + throw $hintException; |
|
363 | + } catch (\Exception $e) { |
|
364 | + $this->logger->logException($e, [ |
|
365 | + 'message' => 'Failed to send share by mail.', |
|
366 | + 'level' => ILogger::ERROR, |
|
367 | + 'app' => 'sharebymail', |
|
368 | + ]); |
|
369 | + $this->removeShareFromTable($shareId); |
|
370 | + throw new HintException('Failed to send share by mail', |
|
371 | + $this->l->t('Failed to send share by email')); |
|
372 | + } |
|
373 | + |
|
374 | + return $shareId; |
|
375 | + |
|
376 | + } |
|
377 | + |
|
378 | + /** |
|
379 | + * @param string $filename |
|
380 | + * @param string $link |
|
381 | + * @param string $initiator |
|
382 | + * @param string $shareWith |
|
383 | + * @param \DateTime|null $expiration |
|
384 | + * @throws \Exception If mail couldn't be sent |
|
385 | + */ |
|
386 | + protected function sendMailNotification($filename, |
|
387 | + $link, |
|
388 | + $initiator, |
|
389 | + $shareWith, |
|
390 | + \DateTime $expiration = null) { |
|
391 | + $initiatorUser = $this->userManager->get($initiator); |
|
392 | + $initiatorDisplayName = ($initiatorUser instanceof IUser) ? $initiatorUser->getDisplayName() : $initiator; |
|
393 | + $message = $this->mailer->createMessage(); |
|
394 | + |
|
395 | + $emailTemplate = $this->mailer->createEMailTemplate('sharebymail.RecipientNotification', [ |
|
396 | + 'filename' => $filename, |
|
397 | + 'link' => $link, |
|
398 | + 'initiator' => $initiatorDisplayName, |
|
399 | + 'expiration' => $expiration, |
|
400 | + 'shareWith' => $shareWith, |
|
401 | + ]); |
|
402 | + |
|
403 | + $emailTemplate->setSubject($this->l->t('%1$s shared »%2$s« with you', array($initiatorDisplayName, $filename))); |
|
404 | + $emailTemplate->addHeader(); |
|
405 | + $emailTemplate->addHeading($this->l->t('%1$s shared »%2$s« with you', [$initiatorDisplayName, $filename]), false); |
|
406 | + $text = $this->l->t('%1$s shared »%2$s« with you.', [$initiatorDisplayName, $filename]); |
|
407 | + |
|
408 | + $emailTemplate->addBodyText( |
|
409 | + htmlspecialchars($text . ' ' . $this->l->t('Click the button below to open it.')), |
|
410 | + $text |
|
411 | + ); |
|
412 | + $emailTemplate->addBodyButton( |
|
413 | + $this->l->t('Open »%s«', [$filename]), |
|
414 | + $link |
|
415 | + ); |
|
416 | + |
|
417 | + $message->setTo([$shareWith]); |
|
418 | + |
|
419 | + // The "From" contains the sharers name |
|
420 | + $instanceName = $this->defaults->getName(); |
|
421 | + $senderName = $this->l->t( |
|
422 | + '%1$s via %2$s', |
|
423 | + [ |
|
424 | + $initiatorDisplayName, |
|
425 | + $instanceName |
|
426 | + ] |
|
427 | + ); |
|
428 | + $message->setFrom([\OCP\Util::getDefaultEmailAddress($instanceName) => $senderName]); |
|
429 | + |
|
430 | + // The "Reply-To" is set to the sharer if an mail address is configured |
|
431 | + // also the default footer contains a "Do not reply" which needs to be adjusted. |
|
432 | + $initiatorEmail = $initiatorUser->getEMailAddress(); |
|
433 | + if($initiatorEmail !== null) { |
|
434 | + $message->setReplyTo([$initiatorEmail => $initiatorDisplayName]); |
|
435 | + $emailTemplate->addFooter($instanceName . ($this->defaults->getSlogan() !== '' ? ' - ' . $this->defaults->getSlogan() : '')); |
|
436 | + } else { |
|
437 | + $emailTemplate->addFooter(); |
|
438 | + } |
|
439 | + |
|
440 | + $message->useTemplate($emailTemplate); |
|
441 | + $this->mailer->send($message); |
|
442 | + } |
|
443 | + |
|
444 | + /** |
|
445 | + * send password to recipient of a mail share |
|
446 | + * |
|
447 | + * @param IShare $share |
|
448 | + * @param string $password |
|
449 | + * @return bool |
|
450 | + */ |
|
451 | + protected function sendPassword(IShare $share, $password) { |
|
452 | + |
|
453 | + $filename = $share->getNode()->getName(); |
|
454 | + $initiator = $share->getSharedBy(); |
|
455 | + $shareWith = $share->getSharedWith(); |
|
456 | + |
|
457 | + if ($password === '' || $this->settingsManager->sendPasswordByMail() === false || $share->getSendPasswordByTalk()) { |
|
458 | + return false; |
|
459 | + } |
|
460 | + |
|
461 | + $initiatorUser = $this->userManager->get($initiator); |
|
462 | + $initiatorDisplayName = ($initiatorUser instanceof IUser) ? $initiatorUser->getDisplayName() : $initiator; |
|
463 | + $initiatorEmailAddress = ($initiatorUser instanceof IUser) ? $initiatorUser->getEMailAddress() : null; |
|
464 | + |
|
465 | + $plainBodyPart = $this->l->t("%1\$s shared »%2\$s« with you.\nYou should have already received a separate mail with a link to access it.\n", [$initiatorDisplayName, $filename]); |
|
466 | + $htmlBodyPart = $this->l->t('%1$s shared »%2$s« with you. You should have already received a separate mail with a link to access it.', [$initiatorDisplayName, $filename]); |
|
467 | + |
|
468 | + $message = $this->mailer->createMessage(); |
|
469 | + |
|
470 | + $emailTemplate = $this->mailer->createEMailTemplate('sharebymail.RecipientPasswordNotification', [ |
|
471 | + 'filename' => $filename, |
|
472 | + 'password' => $password, |
|
473 | + 'initiator' => $initiatorDisplayName, |
|
474 | + 'initiatorEmail' => $initiatorEmailAddress, |
|
475 | + 'shareWith' => $shareWith, |
|
476 | + ]); |
|
477 | + |
|
478 | + $emailTemplate->setSubject($this->l->t('Password to access »%1$s« shared to you by %2$s', [$filename, $initiatorDisplayName])); |
|
479 | + $emailTemplate->addHeader(); |
|
480 | + $emailTemplate->addHeading($this->l->t('Password to access »%s«', [$filename]), false); |
|
481 | + $emailTemplate->addBodyText(htmlspecialchars($htmlBodyPart), $plainBodyPart); |
|
482 | + $emailTemplate->addBodyText($this->l->t('It is protected with the following password:')); |
|
483 | + $emailTemplate->addBodyText($password); |
|
484 | + |
|
485 | + // The "From" contains the sharers name |
|
486 | + $instanceName = $this->defaults->getName(); |
|
487 | + $senderName = $this->l->t( |
|
488 | + '%1$s via %2$s', |
|
489 | + [ |
|
490 | + $initiatorDisplayName, |
|
491 | + $instanceName |
|
492 | + ] |
|
493 | + ); |
|
494 | + $message->setFrom([\OCP\Util::getDefaultEmailAddress($instanceName) => $senderName]); |
|
495 | + if ($initiatorEmailAddress !== null) { |
|
496 | + $message->setReplyTo([$initiatorEmailAddress => $initiatorDisplayName]); |
|
497 | + $emailTemplate->addFooter($instanceName . ' - ' . $this->defaults->getSlogan()); |
|
498 | + } else { |
|
499 | + $emailTemplate->addFooter(); |
|
500 | + } |
|
501 | + |
|
502 | + $message->setTo([$shareWith]); |
|
503 | + $message->useTemplate($emailTemplate); |
|
504 | + $this->mailer->send($message); |
|
505 | + |
|
506 | + $this->createPasswordSendActivity($share, $shareWith, false); |
|
507 | + |
|
508 | + return true; |
|
509 | + } |
|
510 | + |
|
511 | + protected function sendNote(IShare $share) { |
|
512 | + |
|
513 | + $recipient = $share->getSharedWith(); |
|
514 | + |
|
515 | + |
|
516 | + $filename = $share->getNode()->getName(); |
|
517 | + $initiator = $share->getSharedBy(); |
|
518 | + $note = $share->getNote(); |
|
519 | + |
|
520 | + $initiatorUser = $this->userManager->get($initiator); |
|
521 | + $initiatorDisplayName = ($initiatorUser instanceof IUser) ? $initiatorUser->getDisplayName() : $initiator; |
|
522 | + $initiatorEmailAddress = ($initiatorUser instanceof IUser) ? $initiatorUser->getEMailAddress() : null; |
|
523 | + |
|
524 | + $plainHeading = $this->l->t('%1$s shared »%2$s« with you and wants to add:', [$initiatorDisplayName, $filename]); |
|
525 | + $htmlHeading = $this->l->t('%1$s shared »%2$s« with you and wants to add', [$initiatorDisplayName, $filename]); |
|
526 | + |
|
527 | + $message = $this->mailer->createMessage(); |
|
528 | + |
|
529 | + $emailTemplate = $this->mailer->createEMailTemplate('shareByMail.sendNote'); |
|
530 | + |
|
531 | + $emailTemplate->setSubject($this->l->t('»%s« added a note to a file shared with you', [$initiatorDisplayName])); |
|
532 | + $emailTemplate->addHeader(); |
|
533 | + $emailTemplate->addHeading(htmlspecialchars($htmlHeading), $plainHeading); |
|
534 | + $emailTemplate->addBodyText(htmlspecialchars($note), $note); |
|
535 | + |
|
536 | + $link = $this->urlGenerator->linkToRouteAbsolute('files_sharing.sharecontroller.showShare', |
|
537 | + ['token' => $share->getToken()]); |
|
538 | + $emailTemplate->addBodyButton( |
|
539 | + $this->l->t('Open »%s«', [$filename]), |
|
540 | + $link |
|
541 | + ); |
|
542 | + |
|
543 | + // The "From" contains the sharers name |
|
544 | + $instanceName = $this->defaults->getName(); |
|
545 | + $senderName = $this->l->t( |
|
546 | + '%1$s via %2$s', |
|
547 | + [ |
|
548 | + $initiatorDisplayName, |
|
549 | + $instanceName |
|
550 | + ] |
|
551 | + ); |
|
552 | + $message->setFrom([\OCP\Util::getDefaultEmailAddress($instanceName) => $senderName]); |
|
553 | + if ($initiatorEmailAddress !== null) { |
|
554 | + $message->setReplyTo([$initiatorEmailAddress => $initiatorDisplayName]); |
|
555 | + $emailTemplate->addFooter($instanceName . ' - ' . $this->defaults->getSlogan()); |
|
556 | + } else { |
|
557 | + $emailTemplate->addFooter(); |
|
558 | + } |
|
559 | + |
|
560 | + $message->setTo([$recipient]); |
|
561 | + $message->useTemplate($emailTemplate); |
|
562 | + $this->mailer->send($message); |
|
563 | + |
|
564 | + } |
|
565 | + |
|
566 | + /** |
|
567 | + * send auto generated password to the owner. This happens if the admin enforces |
|
568 | + * a password for mail shares and forbid to send the password by mail to the recipient |
|
569 | + * |
|
570 | + * @param IShare $share |
|
571 | + * @param string $password |
|
572 | + * @return bool |
|
573 | + * @throws \Exception |
|
574 | + */ |
|
575 | + protected function sendPasswordToOwner(IShare $share, $password) { |
|
576 | + |
|
577 | + $filename = $share->getNode()->getName(); |
|
578 | + $initiator = $this->userManager->get($share->getSharedBy()); |
|
579 | + $initiatorEMailAddress = ($initiator instanceof IUser) ? $initiator->getEMailAddress() : null; |
|
580 | + $initiatorDisplayName = ($initiator instanceof IUser) ? $initiator->getDisplayName() : $share->getSharedBy(); |
|
581 | + $shareWith = $share->getSharedWith(); |
|
582 | + |
|
583 | + if ($initiatorEMailAddress === null) { |
|
584 | + throw new \Exception( |
|
585 | + $this->l->t("We can't send you the auto-generated password. Please set a valid email address in your personal settings and try again.") |
|
586 | + ); |
|
587 | + } |
|
588 | + |
|
589 | + $bodyPart = $this->l->t('You just shared »%1$s« with %2$s. The share was already send to the recipient. Due to the security policies defined by the administrator of %3$s each share needs to be protected by password and it is not allowed to send the password directly to the recipient. Therefore you need to forward the password manually to the recipient.', [$filename, $shareWith, $this->defaults->getName()]); |
|
590 | + |
|
591 | + $message = $this->mailer->createMessage(); |
|
592 | + $emailTemplate = $this->mailer->createEMailTemplate('sharebymail.OwnerPasswordNotification', [ |
|
593 | + 'filename' => $filename, |
|
594 | + 'password' => $password, |
|
595 | + 'initiator' => $initiatorDisplayName, |
|
596 | + 'initiatorEmail' => $initiatorEMailAddress, |
|
597 | + 'shareWith' => $shareWith, |
|
598 | + ]); |
|
599 | + |
|
600 | + $emailTemplate->setSubject($this->l->t('Password to access »%1$s« shared with %2$s', [$filename, $shareWith])); |
|
601 | + $emailTemplate->addHeader(); |
|
602 | + $emailTemplate->addHeading($this->l->t('Password to access »%s«', [$filename]), false); |
|
603 | + $emailTemplate->addBodyText($bodyPart); |
|
604 | + $emailTemplate->addBodyText($this->l->t('This is the password:')); |
|
605 | + $emailTemplate->addBodyText($password); |
|
606 | + $emailTemplate->addBodyText($this->l->t('You can choose a different password at any time in the share dialog.')); |
|
607 | + $emailTemplate->addFooter(); |
|
608 | + |
|
609 | + if ($initiatorEMailAddress) { |
|
610 | + $message->setFrom([$initiatorEMailAddress => $initiatorDisplayName]); |
|
611 | + } |
|
612 | + $message->setTo([$initiatorEMailAddress => $initiatorDisplayName]); |
|
613 | + $message->useTemplate($emailTemplate); |
|
614 | + $this->mailer->send($message); |
|
615 | + |
|
616 | + $this->createPasswordSendActivity($share, $shareWith, true); |
|
617 | + |
|
618 | + return true; |
|
619 | + } |
|
620 | + |
|
621 | + /** |
|
622 | + * generate share token |
|
623 | + * |
|
624 | + * @return string |
|
625 | + */ |
|
626 | + protected function generateToken($size = 15) { |
|
627 | + $token = $this->secureRandom->generate($size, ISecureRandom::CHAR_HUMAN_READABLE); |
|
628 | + return $token; |
|
629 | + } |
|
630 | + |
|
631 | + /** |
|
632 | + * Get all children of this share |
|
633 | + * |
|
634 | + * @param IShare $parent |
|
635 | + * @return IShare[] |
|
636 | + */ |
|
637 | + public function getChildren(IShare $parent) { |
|
638 | + $children = []; |
|
639 | + |
|
640 | + $qb = $this->dbConnection->getQueryBuilder(); |
|
641 | + $qb->select('*') |
|
642 | + ->from('share') |
|
643 | + ->where($qb->expr()->eq('parent', $qb->createNamedParameter($parent->getId()))) |
|
644 | + ->andWhere($qb->expr()->eq('share_type', $qb->createNamedParameter(\OCP\Share::SHARE_TYPE_EMAIL))) |
|
645 | + ->orderBy('id'); |
|
646 | + |
|
647 | + $cursor = $qb->execute(); |
|
648 | + while($data = $cursor->fetch()) { |
|
649 | + $children[] = $this->createShareObject($data); |
|
650 | + } |
|
651 | + $cursor->closeCursor(); |
|
652 | + |
|
653 | + return $children; |
|
654 | + } |
|
655 | + |
|
656 | + /** |
|
657 | + * add share to the database and return the ID |
|
658 | + * |
|
659 | + * @param int $itemSource |
|
660 | + * @param string $itemType |
|
661 | + * @param string $shareWith |
|
662 | + * @param string $sharedBy |
|
663 | + * @param string $uidOwner |
|
664 | + * @param int $permissions |
|
665 | + * @param string $token |
|
666 | + * @param string $password |
|
667 | + * @param bool $sendPasswordByTalk |
|
668 | + * @return int |
|
669 | + */ |
|
670 | + protected function addShareToDB($itemSource, $itemType, $shareWith, $sharedBy, $uidOwner, $permissions, $token, $password, $sendPasswordByTalk) { |
|
671 | + $qb = $this->dbConnection->getQueryBuilder(); |
|
672 | + $qb->insert('share') |
|
673 | + ->setValue('share_type', $qb->createNamedParameter(\OCP\Share::SHARE_TYPE_EMAIL)) |
|
674 | + ->setValue('item_type', $qb->createNamedParameter($itemType)) |
|
675 | + ->setValue('item_source', $qb->createNamedParameter($itemSource)) |
|
676 | + ->setValue('file_source', $qb->createNamedParameter($itemSource)) |
|
677 | + ->setValue('share_with', $qb->createNamedParameter($shareWith)) |
|
678 | + ->setValue('uid_owner', $qb->createNamedParameter($uidOwner)) |
|
679 | + ->setValue('uid_initiator', $qb->createNamedParameter($sharedBy)) |
|
680 | + ->setValue('permissions', $qb->createNamedParameter($permissions)) |
|
681 | + ->setValue('token', $qb->createNamedParameter($token)) |
|
682 | + ->setValue('password', $qb->createNamedParameter($password)) |
|
683 | + ->setValue('password_by_talk', $qb->createNamedParameter($sendPasswordByTalk, IQueryBuilder::PARAM_BOOL)) |
|
684 | + ->setValue('stime', $qb->createNamedParameter(time())); |
|
685 | + |
|
686 | + /* |
|
687 | 687 | * Added to fix https://github.com/owncloud/core/issues/22215 |
688 | 688 | * Can be removed once we get rid of ajax/share.php |
689 | 689 | */ |
690 | - $qb->setValue('file_target', $qb->createNamedParameter('')); |
|
690 | + $qb->setValue('file_target', $qb->createNamedParameter('')); |
|
691 | 691 | |
692 | - $qb->execute(); |
|
693 | - $id = $qb->getLastInsertId(); |
|
692 | + $qb->execute(); |
|
693 | + $id = $qb->getLastInsertId(); |
|
694 | 694 | |
695 | - return (int)$id; |
|
696 | - } |
|
695 | + return (int)$id; |
|
696 | + } |
|
697 | 697 | |
698 | - /** |
|
699 | - * Update a share |
|
700 | - * |
|
701 | - * @param IShare $share |
|
702 | - * @param string|null $plainTextPassword |
|
703 | - * @return IShare The share object |
|
704 | - */ |
|
705 | - public function update(IShare $share, $plainTextPassword = null) { |
|
698 | + /** |
|
699 | + * Update a share |
|
700 | + * |
|
701 | + * @param IShare $share |
|
702 | + * @param string|null $plainTextPassword |
|
703 | + * @return IShare The share object |
|
704 | + */ |
|
705 | + public function update(IShare $share, $plainTextPassword = null) { |
|
706 | 706 | |
707 | - $originalShare = $this->getShareById($share->getId()); |
|
707 | + $originalShare = $this->getShareById($share->getId()); |
|
708 | 708 | |
709 | - // a real password was given |
|
710 | - $validPassword = $plainTextPassword !== null && $plainTextPassword !== ''; |
|
709 | + // a real password was given |
|
710 | + $validPassword = $plainTextPassword !== null && $plainTextPassword !== ''; |
|
711 | 711 | |
712 | - if($validPassword && ($originalShare->getPassword() !== $share->getPassword() || |
|
713 | - ($originalShare->getSendPasswordByTalk() && !$share->getSendPasswordByTalk()))) { |
|
714 | - $this->sendPassword($share, $plainTextPassword); |
|
715 | - } |
|
716 | - /* |
|
712 | + if($validPassword && ($originalShare->getPassword() !== $share->getPassword() || |
|
713 | + ($originalShare->getSendPasswordByTalk() && !$share->getSendPasswordByTalk()))) { |
|
714 | + $this->sendPassword($share, $plainTextPassword); |
|
715 | + } |
|
716 | + /* |
|
717 | 717 | * We allow updating the permissions and password of mail shares |
718 | 718 | */ |
719 | - $qb = $this->dbConnection->getQueryBuilder(); |
|
720 | - $qb->update('share') |
|
721 | - ->where($qb->expr()->eq('id', $qb->createNamedParameter($share->getId()))) |
|
722 | - ->set('permissions', $qb->createNamedParameter($share->getPermissions())) |
|
723 | - ->set('uid_owner', $qb->createNamedParameter($share->getShareOwner())) |
|
724 | - ->set('uid_initiator', $qb->createNamedParameter($share->getSharedBy())) |
|
725 | - ->set('password', $qb->createNamedParameter($share->getPassword())) |
|
726 | - ->set('password_by_talk', $qb->createNamedParameter($share->getSendPasswordByTalk(), IQueryBuilder::PARAM_BOOL)) |
|
727 | - ->set('expiration', $qb->createNamedParameter($share->getExpirationDate(), IQueryBuilder::PARAM_DATE)) |
|
728 | - ->set('note', $qb->createNamedParameter($share->getNote())) |
|
729 | - ->execute(); |
|
730 | - |
|
731 | - if ($originalShare->getNote() !== $share->getNote() && $share->getNote() !== '') { |
|
732 | - $this->sendNote($share); |
|
733 | - } |
|
734 | - |
|
735 | - return $share; |
|
736 | - } |
|
737 | - |
|
738 | - /** |
|
739 | - * @inheritdoc |
|
740 | - */ |
|
741 | - public function move(IShare $share, $recipient) { |
|
742 | - /** |
|
743 | - * nothing to do here, mail shares are only outgoing shares |
|
744 | - */ |
|
745 | - return $share; |
|
746 | - } |
|
747 | - |
|
748 | - /** |
|
749 | - * Delete a share (owner unShares the file) |
|
750 | - * |
|
751 | - * @param IShare $share |
|
752 | - */ |
|
753 | - public function delete(IShare $share) { |
|
754 | - $this->removeShareFromTable($share->getId()); |
|
755 | - } |
|
756 | - |
|
757 | - /** |
|
758 | - * @inheritdoc |
|
759 | - */ |
|
760 | - public function deleteFromSelf(IShare $share, $recipient) { |
|
761 | - // nothing to do here, mail shares are only outgoing shares |
|
762 | - } |
|
763 | - |
|
764 | - public function restore(IShare $share, string $recipient): IShare { |
|
765 | - throw new GenericShareException('not implemented'); |
|
766 | - } |
|
767 | - |
|
768 | - /** |
|
769 | - * @inheritdoc |
|
770 | - */ |
|
771 | - public function getSharesBy($userId, $shareType, $node, $reshares, $limit, $offset) { |
|
772 | - $qb = $this->dbConnection->getQueryBuilder(); |
|
773 | - $qb->select('*') |
|
774 | - ->from('share'); |
|
775 | - |
|
776 | - $qb->andWhere($qb->expr()->eq('share_type', $qb->createNamedParameter(\OCP\Share::SHARE_TYPE_EMAIL))); |
|
777 | - |
|
778 | - /** |
|
779 | - * Reshares for this user are shares where they are the owner. |
|
780 | - */ |
|
781 | - if ($reshares === false) { |
|
782 | - //Special case for old shares created via the web UI |
|
783 | - $or1 = $qb->expr()->andX( |
|
784 | - $qb->expr()->eq('uid_owner', $qb->createNamedParameter($userId)), |
|
785 | - $qb->expr()->isNull('uid_initiator') |
|
786 | - ); |
|
787 | - |
|
788 | - $qb->andWhere( |
|
789 | - $qb->expr()->orX( |
|
790 | - $qb->expr()->eq('uid_initiator', $qb->createNamedParameter($userId)), |
|
791 | - $or1 |
|
792 | - ) |
|
793 | - ); |
|
794 | - } else { |
|
795 | - $qb->andWhere( |
|
796 | - $qb->expr()->orX( |
|
797 | - $qb->expr()->eq('uid_owner', $qb->createNamedParameter($userId)), |
|
798 | - $qb->expr()->eq('uid_initiator', $qb->createNamedParameter($userId)) |
|
799 | - ) |
|
800 | - ); |
|
801 | - } |
|
802 | - |
|
803 | - if ($node !== null) { |
|
804 | - $qb->andWhere($qb->expr()->eq('file_source', $qb->createNamedParameter($node->getId()))); |
|
805 | - } |
|
806 | - |
|
807 | - if ($limit !== -1) { |
|
808 | - $qb->setMaxResults($limit); |
|
809 | - } |
|
810 | - |
|
811 | - $qb->setFirstResult($offset); |
|
812 | - $qb->orderBy('id'); |
|
813 | - |
|
814 | - $cursor = $qb->execute(); |
|
815 | - $shares = []; |
|
816 | - while($data = $cursor->fetch()) { |
|
817 | - $shares[] = $this->createShareObject($data); |
|
818 | - } |
|
819 | - $cursor->closeCursor(); |
|
820 | - |
|
821 | - return $shares; |
|
822 | - } |
|
823 | - |
|
824 | - /** |
|
825 | - * @inheritdoc |
|
826 | - */ |
|
827 | - public function getShareById($id, $recipientId = null) { |
|
828 | - $qb = $this->dbConnection->getQueryBuilder(); |
|
829 | - |
|
830 | - $qb->select('*') |
|
831 | - ->from('share') |
|
832 | - ->where($qb->expr()->eq('id', $qb->createNamedParameter($id))) |
|
833 | - ->andWhere($qb->expr()->eq('share_type', $qb->createNamedParameter(\OCP\Share::SHARE_TYPE_EMAIL))); |
|
834 | - |
|
835 | - $cursor = $qb->execute(); |
|
836 | - $data = $cursor->fetch(); |
|
837 | - $cursor->closeCursor(); |
|
838 | - |
|
839 | - if ($data === false) { |
|
840 | - throw new ShareNotFound(); |
|
841 | - } |
|
842 | - |
|
843 | - try { |
|
844 | - $share = $this->createShareObject($data); |
|
845 | - } catch (InvalidShare $e) { |
|
846 | - throw new ShareNotFound(); |
|
847 | - } |
|
848 | - |
|
849 | - return $share; |
|
850 | - } |
|
851 | - |
|
852 | - /** |
|
853 | - * Get shares for a given path |
|
854 | - * |
|
855 | - * @param \OCP\Files\Node $path |
|
856 | - * @return IShare[] |
|
857 | - */ |
|
858 | - public function getSharesByPath(Node $path) { |
|
859 | - $qb = $this->dbConnection->getQueryBuilder(); |
|
860 | - |
|
861 | - $cursor = $qb->select('*') |
|
862 | - ->from('share') |
|
863 | - ->andWhere($qb->expr()->eq('file_source', $qb->createNamedParameter($path->getId()))) |
|
864 | - ->andWhere($qb->expr()->eq('share_type', $qb->createNamedParameter(\OCP\Share::SHARE_TYPE_EMAIL))) |
|
865 | - ->execute(); |
|
866 | - |
|
867 | - $shares = []; |
|
868 | - while($data = $cursor->fetch()) { |
|
869 | - $shares[] = $this->createShareObject($data); |
|
870 | - } |
|
871 | - $cursor->closeCursor(); |
|
872 | - |
|
873 | - return $shares; |
|
874 | - } |
|
875 | - |
|
876 | - /** |
|
877 | - * @inheritdoc |
|
878 | - */ |
|
879 | - public function getSharedWith($userId, $shareType, $node, $limit, $offset) { |
|
880 | - /** @var IShare[] $shares */ |
|
881 | - $shares = []; |
|
882 | - |
|
883 | - //Get shares directly with this user |
|
884 | - $qb = $this->dbConnection->getQueryBuilder(); |
|
885 | - $qb->select('*') |
|
886 | - ->from('share'); |
|
887 | - |
|
888 | - // Order by id |
|
889 | - $qb->orderBy('id'); |
|
890 | - |
|
891 | - // Set limit and offset |
|
892 | - if ($limit !== -1) { |
|
893 | - $qb->setMaxResults($limit); |
|
894 | - } |
|
895 | - $qb->setFirstResult($offset); |
|
896 | - |
|
897 | - $qb->where($qb->expr()->eq('share_type', $qb->createNamedParameter(\OCP\Share::SHARE_TYPE_EMAIL))); |
|
898 | - $qb->andWhere($qb->expr()->eq('share_with', $qb->createNamedParameter($userId))); |
|
899 | - |
|
900 | - // Filter by node if provided |
|
901 | - if ($node !== null) { |
|
902 | - $qb->andWhere($qb->expr()->eq('file_source', $qb->createNamedParameter($node->getId()))); |
|
903 | - } |
|
904 | - |
|
905 | - $cursor = $qb->execute(); |
|
906 | - |
|
907 | - while($data = $cursor->fetch()) { |
|
908 | - $shares[] = $this->createShareObject($data); |
|
909 | - } |
|
910 | - $cursor->closeCursor(); |
|
911 | - |
|
912 | - |
|
913 | - return $shares; |
|
914 | - } |
|
915 | - |
|
916 | - /** |
|
917 | - * Get a share by token |
|
918 | - * |
|
919 | - * @param string $token |
|
920 | - * @return IShare |
|
921 | - * @throws ShareNotFound |
|
922 | - */ |
|
923 | - public function getShareByToken($token) { |
|
924 | - $qb = $this->dbConnection->getQueryBuilder(); |
|
925 | - |
|
926 | - $cursor = $qb->select('*') |
|
927 | - ->from('share') |
|
928 | - ->where($qb->expr()->eq('share_type', $qb->createNamedParameter(\OCP\Share::SHARE_TYPE_EMAIL))) |
|
929 | - ->andWhere($qb->expr()->eq('token', $qb->createNamedParameter($token))) |
|
930 | - ->execute(); |
|
931 | - |
|
932 | - $data = $cursor->fetch(); |
|
933 | - |
|
934 | - if ($data === false) { |
|
935 | - throw new ShareNotFound('Share not found', $this->l->t('Could not find share')); |
|
936 | - } |
|
937 | - |
|
938 | - try { |
|
939 | - $share = $this->createShareObject($data); |
|
940 | - } catch (InvalidShare $e) { |
|
941 | - throw new ShareNotFound('Share not found', $this->l->t('Could not find share')); |
|
942 | - } |
|
943 | - |
|
944 | - return $share; |
|
945 | - } |
|
946 | - |
|
947 | - /** |
|
948 | - * remove share from table |
|
949 | - * |
|
950 | - * @param string $shareId |
|
951 | - */ |
|
952 | - protected function removeShareFromTable($shareId) { |
|
953 | - $qb = $this->dbConnection->getQueryBuilder(); |
|
954 | - $qb->delete('share') |
|
955 | - ->where($qb->expr()->eq('id', $qb->createNamedParameter($shareId))); |
|
956 | - $qb->execute(); |
|
957 | - } |
|
958 | - |
|
959 | - /** |
|
960 | - * Create a share object from an database row |
|
961 | - * |
|
962 | - * @param array $data |
|
963 | - * @return IShare |
|
964 | - * @throws InvalidShare |
|
965 | - * @throws ShareNotFound |
|
966 | - */ |
|
967 | - protected function createShareObject($data) { |
|
968 | - |
|
969 | - $share = new Share($this->rootFolder, $this->userManager); |
|
970 | - $share->setId((int)$data['id']) |
|
971 | - ->setShareType((int)$data['share_type']) |
|
972 | - ->setPermissions((int)$data['permissions']) |
|
973 | - ->setTarget($data['file_target']) |
|
974 | - ->setMailSend((bool)$data['mail_send']) |
|
975 | - ->setNote($data['note']) |
|
976 | - ->setToken($data['token']); |
|
977 | - |
|
978 | - $shareTime = new \DateTime(); |
|
979 | - $shareTime->setTimestamp((int)$data['stime']); |
|
980 | - $share->setShareTime($shareTime); |
|
981 | - $share->setSharedWith($data['share_with']); |
|
982 | - $share->setPassword($data['password']); |
|
983 | - $share->setSendPasswordByTalk($data['password_by_talk']); |
|
984 | - |
|
985 | - if ($data['uid_initiator'] !== null) { |
|
986 | - $share->setShareOwner($data['uid_owner']); |
|
987 | - $share->setSharedBy($data['uid_initiator']); |
|
988 | - } else { |
|
989 | - //OLD SHARE |
|
990 | - $share->setSharedBy($data['uid_owner']); |
|
991 | - $path = $this->getNode($share->getSharedBy(), (int)$data['file_source']); |
|
992 | - |
|
993 | - $owner = $path->getOwner(); |
|
994 | - $share->setShareOwner($owner->getUID()); |
|
995 | - } |
|
996 | - |
|
997 | - if ($data['expiration'] !== null) { |
|
998 | - $expiration = \DateTime::createFromFormat('Y-m-d H:i:s', $data['expiration']); |
|
999 | - if ($expiration !== false) { |
|
1000 | - $share->setExpirationDate($expiration); |
|
1001 | - } |
|
1002 | - } |
|
1003 | - |
|
1004 | - $share->setNodeId((int)$data['file_source']); |
|
1005 | - $share->setNodeType($data['item_type']); |
|
1006 | - |
|
1007 | - $share->setProviderId($this->identifier()); |
|
1008 | - |
|
1009 | - return $share; |
|
1010 | - } |
|
1011 | - |
|
1012 | - /** |
|
1013 | - * Get the node with file $id for $user |
|
1014 | - * |
|
1015 | - * @param string $userId |
|
1016 | - * @param int $id |
|
1017 | - * @return \OCP\Files\File|\OCP\Files\Folder |
|
1018 | - * @throws InvalidShare |
|
1019 | - */ |
|
1020 | - private function getNode($userId, $id) { |
|
1021 | - try { |
|
1022 | - $userFolder = $this->rootFolder->getUserFolder($userId); |
|
1023 | - } catch (NoUserException $e) { |
|
1024 | - throw new InvalidShare(); |
|
1025 | - } |
|
1026 | - |
|
1027 | - $nodes = $userFolder->getById($id); |
|
1028 | - |
|
1029 | - if (empty($nodes)) { |
|
1030 | - throw new InvalidShare(); |
|
1031 | - } |
|
1032 | - |
|
1033 | - return $nodes[0]; |
|
1034 | - } |
|
1035 | - |
|
1036 | - /** |
|
1037 | - * A user is deleted from the system |
|
1038 | - * So clean up the relevant shares. |
|
1039 | - * |
|
1040 | - * @param string $uid |
|
1041 | - * @param int $shareType |
|
1042 | - */ |
|
1043 | - public function userDeleted($uid, $shareType) { |
|
1044 | - $qb = $this->dbConnection->getQueryBuilder(); |
|
1045 | - |
|
1046 | - $qb->delete('share') |
|
1047 | - ->where($qb->expr()->eq('share_type', $qb->createNamedParameter(\OCP\Share::SHARE_TYPE_EMAIL))) |
|
1048 | - ->andWhere($qb->expr()->eq('uid_owner', $qb->createNamedParameter($uid))) |
|
1049 | - ->execute(); |
|
1050 | - } |
|
1051 | - |
|
1052 | - /** |
|
1053 | - * This provider does not support group shares |
|
1054 | - * |
|
1055 | - * @param string $gid |
|
1056 | - */ |
|
1057 | - public function groupDeleted($gid) { |
|
1058 | - } |
|
1059 | - |
|
1060 | - /** |
|
1061 | - * This provider does not support group shares |
|
1062 | - * |
|
1063 | - * @param string $uid |
|
1064 | - * @param string $gid |
|
1065 | - */ |
|
1066 | - public function userDeletedFromGroup($uid, $gid) { |
|
1067 | - } |
|
1068 | - |
|
1069 | - /** |
|
1070 | - * get database row of a give share |
|
1071 | - * |
|
1072 | - * @param $id |
|
1073 | - * @return array |
|
1074 | - * @throws ShareNotFound |
|
1075 | - */ |
|
1076 | - protected function getRawShare($id) { |
|
1077 | - |
|
1078 | - // Now fetch the inserted share and create a complete share object |
|
1079 | - $qb = $this->dbConnection->getQueryBuilder(); |
|
1080 | - $qb->select('*') |
|
1081 | - ->from('share') |
|
1082 | - ->where($qb->expr()->eq('id', $qb->createNamedParameter($id))); |
|
1083 | - |
|
1084 | - $cursor = $qb->execute(); |
|
1085 | - $data = $cursor->fetch(); |
|
1086 | - $cursor->closeCursor(); |
|
1087 | - |
|
1088 | - if ($data === false) { |
|
1089 | - throw new ShareNotFound; |
|
1090 | - } |
|
1091 | - |
|
1092 | - return $data; |
|
1093 | - } |
|
1094 | - |
|
1095 | - public function getSharesInFolder($userId, Folder $node, $reshares) { |
|
1096 | - $qb = $this->dbConnection->getQueryBuilder(); |
|
1097 | - $qb->select('*') |
|
1098 | - ->from('share', 's') |
|
1099 | - ->andWhere($qb->expr()->orX( |
|
1100 | - $qb->expr()->eq('item_type', $qb->createNamedParameter('file')), |
|
1101 | - $qb->expr()->eq('item_type', $qb->createNamedParameter('folder')) |
|
1102 | - )) |
|
1103 | - ->andWhere( |
|
1104 | - $qb->expr()->eq('share_type', $qb->createNamedParameter(\OCP\Share::SHARE_TYPE_EMAIL)) |
|
1105 | - ); |
|
1106 | - |
|
1107 | - /** |
|
1108 | - * Reshares for this user are shares where they are the owner. |
|
1109 | - */ |
|
1110 | - if ($reshares === false) { |
|
1111 | - $qb->andWhere($qb->expr()->eq('uid_initiator', $qb->createNamedParameter($userId))); |
|
1112 | - } else { |
|
1113 | - $qb->andWhere( |
|
1114 | - $qb->expr()->orX( |
|
1115 | - $qb->expr()->eq('uid_owner', $qb->createNamedParameter($userId)), |
|
1116 | - $qb->expr()->eq('uid_initiator', $qb->createNamedParameter($userId)) |
|
1117 | - ) |
|
1118 | - ); |
|
1119 | - } |
|
1120 | - |
|
1121 | - $qb->innerJoin('s', 'filecache' ,'f', $qb->expr()->eq('s.file_source', 'f.fileid')); |
|
1122 | - $qb->andWhere($qb->expr()->eq('f.parent', $qb->createNamedParameter($node->getId()))); |
|
1123 | - |
|
1124 | - $qb->orderBy('id'); |
|
1125 | - |
|
1126 | - $cursor = $qb->execute(); |
|
1127 | - $shares = []; |
|
1128 | - while ($data = $cursor->fetch()) { |
|
1129 | - $shares[$data['fileid']][] = $this->createShareObject($data); |
|
1130 | - } |
|
1131 | - $cursor->closeCursor(); |
|
1132 | - |
|
1133 | - return $shares; |
|
1134 | - } |
|
1135 | - |
|
1136 | - /** |
|
1137 | - * @inheritdoc |
|
1138 | - */ |
|
1139 | - public function getAccessList($nodes, $currentAccess) { |
|
1140 | - $ids = []; |
|
1141 | - foreach ($nodes as $node) { |
|
1142 | - $ids[] = $node->getId(); |
|
1143 | - } |
|
1144 | - |
|
1145 | - $qb = $this->dbConnection->getQueryBuilder(); |
|
1146 | - $qb->select('share_with') |
|
1147 | - ->from('share') |
|
1148 | - ->where($qb->expr()->eq('share_type', $qb->createNamedParameter(\OCP\Share::SHARE_TYPE_EMAIL))) |
|
1149 | - ->andWhere($qb->expr()->in('file_source', $qb->createNamedParameter($ids, IQueryBuilder::PARAM_INT_ARRAY))) |
|
1150 | - ->andWhere($qb->expr()->orX( |
|
1151 | - $qb->expr()->eq('item_type', $qb->createNamedParameter('file')), |
|
1152 | - $qb->expr()->eq('item_type', $qb->createNamedParameter('folder')) |
|
1153 | - )) |
|
1154 | - ->setMaxResults(1); |
|
1155 | - $cursor = $qb->execute(); |
|
1156 | - |
|
1157 | - $mail = $cursor->fetch() !== false; |
|
1158 | - $cursor->closeCursor(); |
|
1159 | - |
|
1160 | - return ['public' => $mail]; |
|
1161 | - } |
|
719 | + $qb = $this->dbConnection->getQueryBuilder(); |
|
720 | + $qb->update('share') |
|
721 | + ->where($qb->expr()->eq('id', $qb->createNamedParameter($share->getId()))) |
|
722 | + ->set('permissions', $qb->createNamedParameter($share->getPermissions())) |
|
723 | + ->set('uid_owner', $qb->createNamedParameter($share->getShareOwner())) |
|
724 | + ->set('uid_initiator', $qb->createNamedParameter($share->getSharedBy())) |
|
725 | + ->set('password', $qb->createNamedParameter($share->getPassword())) |
|
726 | + ->set('password_by_talk', $qb->createNamedParameter($share->getSendPasswordByTalk(), IQueryBuilder::PARAM_BOOL)) |
|
727 | + ->set('expiration', $qb->createNamedParameter($share->getExpirationDate(), IQueryBuilder::PARAM_DATE)) |
|
728 | + ->set('note', $qb->createNamedParameter($share->getNote())) |
|
729 | + ->execute(); |
|
730 | + |
|
731 | + if ($originalShare->getNote() !== $share->getNote() && $share->getNote() !== '') { |
|
732 | + $this->sendNote($share); |
|
733 | + } |
|
734 | + |
|
735 | + return $share; |
|
736 | + } |
|
737 | + |
|
738 | + /** |
|
739 | + * @inheritdoc |
|
740 | + */ |
|
741 | + public function move(IShare $share, $recipient) { |
|
742 | + /** |
|
743 | + * nothing to do here, mail shares are only outgoing shares |
|
744 | + */ |
|
745 | + return $share; |
|
746 | + } |
|
747 | + |
|
748 | + /** |
|
749 | + * Delete a share (owner unShares the file) |
|
750 | + * |
|
751 | + * @param IShare $share |
|
752 | + */ |
|
753 | + public function delete(IShare $share) { |
|
754 | + $this->removeShareFromTable($share->getId()); |
|
755 | + } |
|
756 | + |
|
757 | + /** |
|
758 | + * @inheritdoc |
|
759 | + */ |
|
760 | + public function deleteFromSelf(IShare $share, $recipient) { |
|
761 | + // nothing to do here, mail shares are only outgoing shares |
|
762 | + } |
|
763 | + |
|
764 | + public function restore(IShare $share, string $recipient): IShare { |
|
765 | + throw new GenericShareException('not implemented'); |
|
766 | + } |
|
767 | + |
|
768 | + /** |
|
769 | + * @inheritdoc |
|
770 | + */ |
|
771 | + public function getSharesBy($userId, $shareType, $node, $reshares, $limit, $offset) { |
|
772 | + $qb = $this->dbConnection->getQueryBuilder(); |
|
773 | + $qb->select('*') |
|
774 | + ->from('share'); |
|
775 | + |
|
776 | + $qb->andWhere($qb->expr()->eq('share_type', $qb->createNamedParameter(\OCP\Share::SHARE_TYPE_EMAIL))); |
|
777 | + |
|
778 | + /** |
|
779 | + * Reshares for this user are shares where they are the owner. |
|
780 | + */ |
|
781 | + if ($reshares === false) { |
|
782 | + //Special case for old shares created via the web UI |
|
783 | + $or1 = $qb->expr()->andX( |
|
784 | + $qb->expr()->eq('uid_owner', $qb->createNamedParameter($userId)), |
|
785 | + $qb->expr()->isNull('uid_initiator') |
|
786 | + ); |
|
787 | + |
|
788 | + $qb->andWhere( |
|
789 | + $qb->expr()->orX( |
|
790 | + $qb->expr()->eq('uid_initiator', $qb->createNamedParameter($userId)), |
|
791 | + $or1 |
|
792 | + ) |
|
793 | + ); |
|
794 | + } else { |
|
795 | + $qb->andWhere( |
|
796 | + $qb->expr()->orX( |
|
797 | + $qb->expr()->eq('uid_owner', $qb->createNamedParameter($userId)), |
|
798 | + $qb->expr()->eq('uid_initiator', $qb->createNamedParameter($userId)) |
|
799 | + ) |
|
800 | + ); |
|
801 | + } |
|
802 | + |
|
803 | + if ($node !== null) { |
|
804 | + $qb->andWhere($qb->expr()->eq('file_source', $qb->createNamedParameter($node->getId()))); |
|
805 | + } |
|
806 | + |
|
807 | + if ($limit !== -1) { |
|
808 | + $qb->setMaxResults($limit); |
|
809 | + } |
|
810 | + |
|
811 | + $qb->setFirstResult($offset); |
|
812 | + $qb->orderBy('id'); |
|
813 | + |
|
814 | + $cursor = $qb->execute(); |
|
815 | + $shares = []; |
|
816 | + while($data = $cursor->fetch()) { |
|
817 | + $shares[] = $this->createShareObject($data); |
|
818 | + } |
|
819 | + $cursor->closeCursor(); |
|
820 | + |
|
821 | + return $shares; |
|
822 | + } |
|
823 | + |
|
824 | + /** |
|
825 | + * @inheritdoc |
|
826 | + */ |
|
827 | + public function getShareById($id, $recipientId = null) { |
|
828 | + $qb = $this->dbConnection->getQueryBuilder(); |
|
829 | + |
|
830 | + $qb->select('*') |
|
831 | + ->from('share') |
|
832 | + ->where($qb->expr()->eq('id', $qb->createNamedParameter($id))) |
|
833 | + ->andWhere($qb->expr()->eq('share_type', $qb->createNamedParameter(\OCP\Share::SHARE_TYPE_EMAIL))); |
|
834 | + |
|
835 | + $cursor = $qb->execute(); |
|
836 | + $data = $cursor->fetch(); |
|
837 | + $cursor->closeCursor(); |
|
838 | + |
|
839 | + if ($data === false) { |
|
840 | + throw new ShareNotFound(); |
|
841 | + } |
|
842 | + |
|
843 | + try { |
|
844 | + $share = $this->createShareObject($data); |
|
845 | + } catch (InvalidShare $e) { |
|
846 | + throw new ShareNotFound(); |
|
847 | + } |
|
848 | + |
|
849 | + return $share; |
|
850 | + } |
|
851 | + |
|
852 | + /** |
|
853 | + * Get shares for a given path |
|
854 | + * |
|
855 | + * @param \OCP\Files\Node $path |
|
856 | + * @return IShare[] |
|
857 | + */ |
|
858 | + public function getSharesByPath(Node $path) { |
|
859 | + $qb = $this->dbConnection->getQueryBuilder(); |
|
860 | + |
|
861 | + $cursor = $qb->select('*') |
|
862 | + ->from('share') |
|
863 | + ->andWhere($qb->expr()->eq('file_source', $qb->createNamedParameter($path->getId()))) |
|
864 | + ->andWhere($qb->expr()->eq('share_type', $qb->createNamedParameter(\OCP\Share::SHARE_TYPE_EMAIL))) |
|
865 | + ->execute(); |
|
866 | + |
|
867 | + $shares = []; |
|
868 | + while($data = $cursor->fetch()) { |
|
869 | + $shares[] = $this->createShareObject($data); |
|
870 | + } |
|
871 | + $cursor->closeCursor(); |
|
872 | + |
|
873 | + return $shares; |
|
874 | + } |
|
875 | + |
|
876 | + /** |
|
877 | + * @inheritdoc |
|
878 | + */ |
|
879 | + public function getSharedWith($userId, $shareType, $node, $limit, $offset) { |
|
880 | + /** @var IShare[] $shares */ |
|
881 | + $shares = []; |
|
882 | + |
|
883 | + //Get shares directly with this user |
|
884 | + $qb = $this->dbConnection->getQueryBuilder(); |
|
885 | + $qb->select('*') |
|
886 | + ->from('share'); |
|
887 | + |
|
888 | + // Order by id |
|
889 | + $qb->orderBy('id'); |
|
890 | + |
|
891 | + // Set limit and offset |
|
892 | + if ($limit !== -1) { |
|
893 | + $qb->setMaxResults($limit); |
|
894 | + } |
|
895 | + $qb->setFirstResult($offset); |
|
896 | + |
|
897 | + $qb->where($qb->expr()->eq('share_type', $qb->createNamedParameter(\OCP\Share::SHARE_TYPE_EMAIL))); |
|
898 | + $qb->andWhere($qb->expr()->eq('share_with', $qb->createNamedParameter($userId))); |
|
899 | + |
|
900 | + // Filter by node if provided |
|
901 | + if ($node !== null) { |
|
902 | + $qb->andWhere($qb->expr()->eq('file_source', $qb->createNamedParameter($node->getId()))); |
|
903 | + } |
|
904 | + |
|
905 | + $cursor = $qb->execute(); |
|
906 | + |
|
907 | + while($data = $cursor->fetch()) { |
|
908 | + $shares[] = $this->createShareObject($data); |
|
909 | + } |
|
910 | + $cursor->closeCursor(); |
|
911 | + |
|
912 | + |
|
913 | + return $shares; |
|
914 | + } |
|
915 | + |
|
916 | + /** |
|
917 | + * Get a share by token |
|
918 | + * |
|
919 | + * @param string $token |
|
920 | + * @return IShare |
|
921 | + * @throws ShareNotFound |
|
922 | + */ |
|
923 | + public function getShareByToken($token) { |
|
924 | + $qb = $this->dbConnection->getQueryBuilder(); |
|
925 | + |
|
926 | + $cursor = $qb->select('*') |
|
927 | + ->from('share') |
|
928 | + ->where($qb->expr()->eq('share_type', $qb->createNamedParameter(\OCP\Share::SHARE_TYPE_EMAIL))) |
|
929 | + ->andWhere($qb->expr()->eq('token', $qb->createNamedParameter($token))) |
|
930 | + ->execute(); |
|
931 | + |
|
932 | + $data = $cursor->fetch(); |
|
933 | + |
|
934 | + if ($data === false) { |
|
935 | + throw new ShareNotFound('Share not found', $this->l->t('Could not find share')); |
|
936 | + } |
|
937 | + |
|
938 | + try { |
|
939 | + $share = $this->createShareObject($data); |
|
940 | + } catch (InvalidShare $e) { |
|
941 | + throw new ShareNotFound('Share not found', $this->l->t('Could not find share')); |
|
942 | + } |
|
943 | + |
|
944 | + return $share; |
|
945 | + } |
|
946 | + |
|
947 | + /** |
|
948 | + * remove share from table |
|
949 | + * |
|
950 | + * @param string $shareId |
|
951 | + */ |
|
952 | + protected function removeShareFromTable($shareId) { |
|
953 | + $qb = $this->dbConnection->getQueryBuilder(); |
|
954 | + $qb->delete('share') |
|
955 | + ->where($qb->expr()->eq('id', $qb->createNamedParameter($shareId))); |
|
956 | + $qb->execute(); |
|
957 | + } |
|
958 | + |
|
959 | + /** |
|
960 | + * Create a share object from an database row |
|
961 | + * |
|
962 | + * @param array $data |
|
963 | + * @return IShare |
|
964 | + * @throws InvalidShare |
|
965 | + * @throws ShareNotFound |
|
966 | + */ |
|
967 | + protected function createShareObject($data) { |
|
968 | + |
|
969 | + $share = new Share($this->rootFolder, $this->userManager); |
|
970 | + $share->setId((int)$data['id']) |
|
971 | + ->setShareType((int)$data['share_type']) |
|
972 | + ->setPermissions((int)$data['permissions']) |
|
973 | + ->setTarget($data['file_target']) |
|
974 | + ->setMailSend((bool)$data['mail_send']) |
|
975 | + ->setNote($data['note']) |
|
976 | + ->setToken($data['token']); |
|
977 | + |
|
978 | + $shareTime = new \DateTime(); |
|
979 | + $shareTime->setTimestamp((int)$data['stime']); |
|
980 | + $share->setShareTime($shareTime); |
|
981 | + $share->setSharedWith($data['share_with']); |
|
982 | + $share->setPassword($data['password']); |
|
983 | + $share->setSendPasswordByTalk($data['password_by_talk']); |
|
984 | + |
|
985 | + if ($data['uid_initiator'] !== null) { |
|
986 | + $share->setShareOwner($data['uid_owner']); |
|
987 | + $share->setSharedBy($data['uid_initiator']); |
|
988 | + } else { |
|
989 | + //OLD SHARE |
|
990 | + $share->setSharedBy($data['uid_owner']); |
|
991 | + $path = $this->getNode($share->getSharedBy(), (int)$data['file_source']); |
|
992 | + |
|
993 | + $owner = $path->getOwner(); |
|
994 | + $share->setShareOwner($owner->getUID()); |
|
995 | + } |
|
996 | + |
|
997 | + if ($data['expiration'] !== null) { |
|
998 | + $expiration = \DateTime::createFromFormat('Y-m-d H:i:s', $data['expiration']); |
|
999 | + if ($expiration !== false) { |
|
1000 | + $share->setExpirationDate($expiration); |
|
1001 | + } |
|
1002 | + } |
|
1003 | + |
|
1004 | + $share->setNodeId((int)$data['file_source']); |
|
1005 | + $share->setNodeType($data['item_type']); |
|
1006 | + |
|
1007 | + $share->setProviderId($this->identifier()); |
|
1008 | + |
|
1009 | + return $share; |
|
1010 | + } |
|
1011 | + |
|
1012 | + /** |
|
1013 | + * Get the node with file $id for $user |
|
1014 | + * |
|
1015 | + * @param string $userId |
|
1016 | + * @param int $id |
|
1017 | + * @return \OCP\Files\File|\OCP\Files\Folder |
|
1018 | + * @throws InvalidShare |
|
1019 | + */ |
|
1020 | + private function getNode($userId, $id) { |
|
1021 | + try { |
|
1022 | + $userFolder = $this->rootFolder->getUserFolder($userId); |
|
1023 | + } catch (NoUserException $e) { |
|
1024 | + throw new InvalidShare(); |
|
1025 | + } |
|
1026 | + |
|
1027 | + $nodes = $userFolder->getById($id); |
|
1028 | + |
|
1029 | + if (empty($nodes)) { |
|
1030 | + throw new InvalidShare(); |
|
1031 | + } |
|
1032 | + |
|
1033 | + return $nodes[0]; |
|
1034 | + } |
|
1035 | + |
|
1036 | + /** |
|
1037 | + * A user is deleted from the system |
|
1038 | + * So clean up the relevant shares. |
|
1039 | + * |
|
1040 | + * @param string $uid |
|
1041 | + * @param int $shareType |
|
1042 | + */ |
|
1043 | + public function userDeleted($uid, $shareType) { |
|
1044 | + $qb = $this->dbConnection->getQueryBuilder(); |
|
1045 | + |
|
1046 | + $qb->delete('share') |
|
1047 | + ->where($qb->expr()->eq('share_type', $qb->createNamedParameter(\OCP\Share::SHARE_TYPE_EMAIL))) |
|
1048 | + ->andWhere($qb->expr()->eq('uid_owner', $qb->createNamedParameter($uid))) |
|
1049 | + ->execute(); |
|
1050 | + } |
|
1051 | + |
|
1052 | + /** |
|
1053 | + * This provider does not support group shares |
|
1054 | + * |
|
1055 | + * @param string $gid |
|
1056 | + */ |
|
1057 | + public function groupDeleted($gid) { |
|
1058 | + } |
|
1059 | + |
|
1060 | + /** |
|
1061 | + * This provider does not support group shares |
|
1062 | + * |
|
1063 | + * @param string $uid |
|
1064 | + * @param string $gid |
|
1065 | + */ |
|
1066 | + public function userDeletedFromGroup($uid, $gid) { |
|
1067 | + } |
|
1068 | + |
|
1069 | + /** |
|
1070 | + * get database row of a give share |
|
1071 | + * |
|
1072 | + * @param $id |
|
1073 | + * @return array |
|
1074 | + * @throws ShareNotFound |
|
1075 | + */ |
|
1076 | + protected function getRawShare($id) { |
|
1077 | + |
|
1078 | + // Now fetch the inserted share and create a complete share object |
|
1079 | + $qb = $this->dbConnection->getQueryBuilder(); |
|
1080 | + $qb->select('*') |
|
1081 | + ->from('share') |
|
1082 | + ->where($qb->expr()->eq('id', $qb->createNamedParameter($id))); |
|
1083 | + |
|
1084 | + $cursor = $qb->execute(); |
|
1085 | + $data = $cursor->fetch(); |
|
1086 | + $cursor->closeCursor(); |
|
1087 | + |
|
1088 | + if ($data === false) { |
|
1089 | + throw new ShareNotFound; |
|
1090 | + } |
|
1091 | + |
|
1092 | + return $data; |
|
1093 | + } |
|
1094 | + |
|
1095 | + public function getSharesInFolder($userId, Folder $node, $reshares) { |
|
1096 | + $qb = $this->dbConnection->getQueryBuilder(); |
|
1097 | + $qb->select('*') |
|
1098 | + ->from('share', 's') |
|
1099 | + ->andWhere($qb->expr()->orX( |
|
1100 | + $qb->expr()->eq('item_type', $qb->createNamedParameter('file')), |
|
1101 | + $qb->expr()->eq('item_type', $qb->createNamedParameter('folder')) |
|
1102 | + )) |
|
1103 | + ->andWhere( |
|
1104 | + $qb->expr()->eq('share_type', $qb->createNamedParameter(\OCP\Share::SHARE_TYPE_EMAIL)) |
|
1105 | + ); |
|
1106 | + |
|
1107 | + /** |
|
1108 | + * Reshares for this user are shares where they are the owner. |
|
1109 | + */ |
|
1110 | + if ($reshares === false) { |
|
1111 | + $qb->andWhere($qb->expr()->eq('uid_initiator', $qb->createNamedParameter($userId))); |
|
1112 | + } else { |
|
1113 | + $qb->andWhere( |
|
1114 | + $qb->expr()->orX( |
|
1115 | + $qb->expr()->eq('uid_owner', $qb->createNamedParameter($userId)), |
|
1116 | + $qb->expr()->eq('uid_initiator', $qb->createNamedParameter($userId)) |
|
1117 | + ) |
|
1118 | + ); |
|
1119 | + } |
|
1120 | + |
|
1121 | + $qb->innerJoin('s', 'filecache' ,'f', $qb->expr()->eq('s.file_source', 'f.fileid')); |
|
1122 | + $qb->andWhere($qb->expr()->eq('f.parent', $qb->createNamedParameter($node->getId()))); |
|
1123 | + |
|
1124 | + $qb->orderBy('id'); |
|
1125 | + |
|
1126 | + $cursor = $qb->execute(); |
|
1127 | + $shares = []; |
|
1128 | + while ($data = $cursor->fetch()) { |
|
1129 | + $shares[$data['fileid']][] = $this->createShareObject($data); |
|
1130 | + } |
|
1131 | + $cursor->closeCursor(); |
|
1132 | + |
|
1133 | + return $shares; |
|
1134 | + } |
|
1135 | + |
|
1136 | + /** |
|
1137 | + * @inheritdoc |
|
1138 | + */ |
|
1139 | + public function getAccessList($nodes, $currentAccess) { |
|
1140 | + $ids = []; |
|
1141 | + foreach ($nodes as $node) { |
|
1142 | + $ids[] = $node->getId(); |
|
1143 | + } |
|
1144 | + |
|
1145 | + $qb = $this->dbConnection->getQueryBuilder(); |
|
1146 | + $qb->select('share_with') |
|
1147 | + ->from('share') |
|
1148 | + ->where($qb->expr()->eq('share_type', $qb->createNamedParameter(\OCP\Share::SHARE_TYPE_EMAIL))) |
|
1149 | + ->andWhere($qb->expr()->in('file_source', $qb->createNamedParameter($ids, IQueryBuilder::PARAM_INT_ARRAY))) |
|
1150 | + ->andWhere($qb->expr()->orX( |
|
1151 | + $qb->expr()->eq('item_type', $qb->createNamedParameter('file')), |
|
1152 | + $qb->expr()->eq('item_type', $qb->createNamedParameter('folder')) |
|
1153 | + )) |
|
1154 | + ->setMaxResults(1); |
|
1155 | + $cursor = $qb->execute(); |
|
1156 | + |
|
1157 | + $mail = $cursor->fetch() !== false; |
|
1158 | + $cursor->closeCursor(); |
|
1159 | + |
|
1160 | + return ['public' => $mail]; |
|
1161 | + } |
|
1162 | 1162 | |
1163 | 1163 | } |
@@ -211,10 +211,10 @@ discard block |
||
211 | 211 | } |
212 | 212 | |
213 | 213 | $passwordPolicy = $this->getPasswordPolicy(); |
214 | - $passwordCharset = ISecureRandom::CHAR_LOWER . ISecureRandom::CHAR_UPPER . ISecureRandom::CHAR_DIGITS; |
|
214 | + $passwordCharset = ISecureRandom::CHAR_LOWER.ISecureRandom::CHAR_UPPER.ISecureRandom::CHAR_DIGITS; |
|
215 | 215 | $passwordLength = 8; |
216 | 216 | if (!empty($passwordPolicy)) { |
217 | - $passwordLength = (int)$passwordPolicy['minLength'] > 0 ? (int)$passwordPolicy['minLength'] : $passwordLength; |
|
217 | + $passwordLength = (int) $passwordPolicy['minLength'] > 0 ? (int) $passwordPolicy['minLength'] : $passwordLength; |
|
218 | 218 | $passwordCharset .= $passwordPolicy['enforceSpecialCharacters'] ? ISecureRandom::CHAR_SYMBOLS : ''; |
219 | 219 | } |
220 | 220 | |
@@ -406,7 +406,7 @@ discard block |
||
406 | 406 | $text = $this->l->t('%1$s shared »%2$s« with you.', [$initiatorDisplayName, $filename]); |
407 | 407 | |
408 | 408 | $emailTemplate->addBodyText( |
409 | - htmlspecialchars($text . ' ' . $this->l->t('Click the button below to open it.')), |
|
409 | + htmlspecialchars($text.' '.$this->l->t('Click the button below to open it.')), |
|
410 | 410 | $text |
411 | 411 | ); |
412 | 412 | $emailTemplate->addBodyButton( |
@@ -430,9 +430,9 @@ discard block |
||
430 | 430 | // The "Reply-To" is set to the sharer if an mail address is configured |
431 | 431 | // also the default footer contains a "Do not reply" which needs to be adjusted. |
432 | 432 | $initiatorEmail = $initiatorUser->getEMailAddress(); |
433 | - if($initiatorEmail !== null) { |
|
433 | + if ($initiatorEmail !== null) { |
|
434 | 434 | $message->setReplyTo([$initiatorEmail => $initiatorDisplayName]); |
435 | - $emailTemplate->addFooter($instanceName . ($this->defaults->getSlogan() !== '' ? ' - ' . $this->defaults->getSlogan() : '')); |
|
435 | + $emailTemplate->addFooter($instanceName.($this->defaults->getSlogan() !== '' ? ' - '.$this->defaults->getSlogan() : '')); |
|
436 | 436 | } else { |
437 | 437 | $emailTemplate->addFooter(); |
438 | 438 | } |
@@ -494,7 +494,7 @@ discard block |
||
494 | 494 | $message->setFrom([\OCP\Util::getDefaultEmailAddress($instanceName) => $senderName]); |
495 | 495 | if ($initiatorEmailAddress !== null) { |
496 | 496 | $message->setReplyTo([$initiatorEmailAddress => $initiatorDisplayName]); |
497 | - $emailTemplate->addFooter($instanceName . ' - ' . $this->defaults->getSlogan()); |
|
497 | + $emailTemplate->addFooter($instanceName.' - '.$this->defaults->getSlogan()); |
|
498 | 498 | } else { |
499 | 499 | $emailTemplate->addFooter(); |
500 | 500 | } |
@@ -552,7 +552,7 @@ discard block |
||
552 | 552 | $message->setFrom([\OCP\Util::getDefaultEmailAddress($instanceName) => $senderName]); |
553 | 553 | if ($initiatorEmailAddress !== null) { |
554 | 554 | $message->setReplyTo([$initiatorEmailAddress => $initiatorDisplayName]); |
555 | - $emailTemplate->addFooter($instanceName . ' - ' . $this->defaults->getSlogan()); |
|
555 | + $emailTemplate->addFooter($instanceName.' - '.$this->defaults->getSlogan()); |
|
556 | 556 | } else { |
557 | 557 | $emailTemplate->addFooter(); |
558 | 558 | } |
@@ -645,7 +645,7 @@ discard block |
||
645 | 645 | ->orderBy('id'); |
646 | 646 | |
647 | 647 | $cursor = $qb->execute(); |
648 | - while($data = $cursor->fetch()) { |
|
648 | + while ($data = $cursor->fetch()) { |
|
649 | 649 | $children[] = $this->createShareObject($data); |
650 | 650 | } |
651 | 651 | $cursor->closeCursor(); |
@@ -692,7 +692,7 @@ discard block |
||
692 | 692 | $qb->execute(); |
693 | 693 | $id = $qb->getLastInsertId(); |
694 | 694 | |
695 | - return (int)$id; |
|
695 | + return (int) $id; |
|
696 | 696 | } |
697 | 697 | |
698 | 698 | /** |
@@ -709,7 +709,7 @@ discard block |
||
709 | 709 | // a real password was given |
710 | 710 | $validPassword = $plainTextPassword !== null && $plainTextPassword !== ''; |
711 | 711 | |
712 | - if($validPassword && ($originalShare->getPassword() !== $share->getPassword() || |
|
712 | + if ($validPassword && ($originalShare->getPassword() !== $share->getPassword() || |
|
713 | 713 | ($originalShare->getSendPasswordByTalk() && !$share->getSendPasswordByTalk()))) { |
714 | 714 | $this->sendPassword($share, $plainTextPassword); |
715 | 715 | } |
@@ -813,7 +813,7 @@ discard block |
||
813 | 813 | |
814 | 814 | $cursor = $qb->execute(); |
815 | 815 | $shares = []; |
816 | - while($data = $cursor->fetch()) { |
|
816 | + while ($data = $cursor->fetch()) { |
|
817 | 817 | $shares[] = $this->createShareObject($data); |
818 | 818 | } |
819 | 819 | $cursor->closeCursor(); |
@@ -865,7 +865,7 @@ discard block |
||
865 | 865 | ->execute(); |
866 | 866 | |
867 | 867 | $shares = []; |
868 | - while($data = $cursor->fetch()) { |
|
868 | + while ($data = $cursor->fetch()) { |
|
869 | 869 | $shares[] = $this->createShareObject($data); |
870 | 870 | } |
871 | 871 | $cursor->closeCursor(); |
@@ -904,7 +904,7 @@ discard block |
||
904 | 904 | |
905 | 905 | $cursor = $qb->execute(); |
906 | 906 | |
907 | - while($data = $cursor->fetch()) { |
|
907 | + while ($data = $cursor->fetch()) { |
|
908 | 908 | $shares[] = $this->createShareObject($data); |
909 | 909 | } |
910 | 910 | $cursor->closeCursor(); |
@@ -967,16 +967,16 @@ discard block |
||
967 | 967 | protected function createShareObject($data) { |
968 | 968 | |
969 | 969 | $share = new Share($this->rootFolder, $this->userManager); |
970 | - $share->setId((int)$data['id']) |
|
971 | - ->setShareType((int)$data['share_type']) |
|
972 | - ->setPermissions((int)$data['permissions']) |
|
970 | + $share->setId((int) $data['id']) |
|
971 | + ->setShareType((int) $data['share_type']) |
|
972 | + ->setPermissions((int) $data['permissions']) |
|
973 | 973 | ->setTarget($data['file_target']) |
974 | - ->setMailSend((bool)$data['mail_send']) |
|
974 | + ->setMailSend((bool) $data['mail_send']) |
|
975 | 975 | ->setNote($data['note']) |
976 | 976 | ->setToken($data['token']); |
977 | 977 | |
978 | 978 | $shareTime = new \DateTime(); |
979 | - $shareTime->setTimestamp((int)$data['stime']); |
|
979 | + $shareTime->setTimestamp((int) $data['stime']); |
|
980 | 980 | $share->setShareTime($shareTime); |
981 | 981 | $share->setSharedWith($data['share_with']); |
982 | 982 | $share->setPassword($data['password']); |
@@ -988,7 +988,7 @@ discard block |
||
988 | 988 | } else { |
989 | 989 | //OLD SHARE |
990 | 990 | $share->setSharedBy($data['uid_owner']); |
991 | - $path = $this->getNode($share->getSharedBy(), (int)$data['file_source']); |
|
991 | + $path = $this->getNode($share->getSharedBy(), (int) $data['file_source']); |
|
992 | 992 | |
993 | 993 | $owner = $path->getOwner(); |
994 | 994 | $share->setShareOwner($owner->getUID()); |
@@ -1001,7 +1001,7 @@ discard block |
||
1001 | 1001 | } |
1002 | 1002 | } |
1003 | 1003 | |
1004 | - $share->setNodeId((int)$data['file_source']); |
|
1004 | + $share->setNodeId((int) $data['file_source']); |
|
1005 | 1005 | $share->setNodeType($data['item_type']); |
1006 | 1006 | |
1007 | 1007 | $share->setProviderId($this->identifier()); |
@@ -1118,7 +1118,7 @@ discard block |
||
1118 | 1118 | ); |
1119 | 1119 | } |
1120 | 1120 | |
1121 | - $qb->innerJoin('s', 'filecache' ,'f', $qb->expr()->eq('s.file_source', 'f.fileid')); |
|
1121 | + $qb->innerJoin('s', 'filecache', 'f', $qb->expr()->eq('s.file_source', 'f.fileid')); |
|
1122 | 1122 | $qb->andWhere($qb->expr()->eq('f.parent', $qb->createNamedParameter($node->getId()))); |
1123 | 1123 | |
1124 | 1124 | $qb->orderBy('id'); |
@@ -66,1017 +66,1017 @@ |
||
66 | 66 | */ |
67 | 67 | class ShareAPIController extends OCSController { |
68 | 68 | |
69 | - /** @var IManager */ |
|
70 | - private $shareManager; |
|
71 | - /** @var IGroupManager */ |
|
72 | - private $groupManager; |
|
73 | - /** @var IUserManager */ |
|
74 | - private $userManager; |
|
75 | - /** @var IRootFolder */ |
|
76 | - private $rootFolder; |
|
77 | - /** @var IURLGenerator */ |
|
78 | - private $urlGenerator; |
|
79 | - /** @var string */ |
|
80 | - private $currentUser; |
|
81 | - /** @var IL10N */ |
|
82 | - private $l; |
|
83 | - /** @var \OCP\Files\Node */ |
|
84 | - private $lockedNode; |
|
85 | - /** @var IConfig */ |
|
86 | - private $config; |
|
87 | - /** @var IAppManager */ |
|
88 | - private $appManager; |
|
89 | - /** @var IServerContainer */ |
|
90 | - private $serverContainer; |
|
91 | - |
|
92 | - /** |
|
93 | - * Share20OCS constructor. |
|
94 | - * |
|
95 | - * @param string $appName |
|
96 | - * @param IRequest $request |
|
97 | - * @param IManager $shareManager |
|
98 | - * @param IGroupManager $groupManager |
|
99 | - * @param IUserManager $userManager |
|
100 | - * @param IRootFolder $rootFolder |
|
101 | - * @param IURLGenerator $urlGenerator |
|
102 | - * @param string $userId |
|
103 | - * @param IL10N $l10n |
|
104 | - * @param IConfig $config |
|
105 | - * @param IAppManager $appManager |
|
106 | - * @param IServerContainer $serverContainer |
|
107 | - */ |
|
108 | - public function __construct( |
|
109 | - string $appName, |
|
110 | - IRequest $request, |
|
111 | - IManager $shareManager, |
|
112 | - IGroupManager $groupManager, |
|
113 | - IUserManager $userManager, |
|
114 | - IRootFolder $rootFolder, |
|
115 | - IURLGenerator $urlGenerator, |
|
116 | - string $userId = null, |
|
117 | - IL10N $l10n, |
|
118 | - IConfig $config, |
|
119 | - IAppManager $appManager, |
|
120 | - IServerContainer $serverContainer |
|
121 | - ) { |
|
122 | - parent::__construct($appName, $request); |
|
123 | - |
|
124 | - $this->shareManager = $shareManager; |
|
125 | - $this->userManager = $userManager; |
|
126 | - $this->groupManager = $groupManager; |
|
127 | - $this->request = $request; |
|
128 | - $this->rootFolder = $rootFolder; |
|
129 | - $this->urlGenerator = $urlGenerator; |
|
130 | - $this->currentUser = $userId; |
|
131 | - $this->l = $l10n; |
|
132 | - $this->config = $config; |
|
133 | - $this->appManager = $appManager; |
|
134 | - $this->serverContainer = $serverContainer; |
|
135 | - } |
|
136 | - |
|
137 | - /** |
|
138 | - * Convert an IShare to an array for OCS output |
|
139 | - * |
|
140 | - * @param \OCP\Share\IShare $share |
|
141 | - * @param Node|null $recipientNode |
|
142 | - * @return array |
|
143 | - * @throws NotFoundException In case the node can't be resolved. |
|
144 | - * |
|
145 | - * @suppress PhanUndeclaredClassMethod |
|
146 | - */ |
|
147 | - protected function formatShare(\OCP\Share\IShare $share, Node $recipientNode = null): array { |
|
148 | - $sharedBy = $this->userManager->get($share->getSharedBy()); |
|
149 | - $shareOwner = $this->userManager->get($share->getShareOwner()); |
|
150 | - |
|
151 | - $result = [ |
|
152 | - 'id' => $share->getId(), |
|
153 | - 'share_type' => $share->getShareType(), |
|
154 | - 'uid_owner' => $share->getSharedBy(), |
|
155 | - 'displayname_owner' => $sharedBy !== null ? $sharedBy->getDisplayName() : $share->getSharedBy(), |
|
156 | - 'permissions' => $share->getPermissions(), |
|
157 | - 'stime' => $share->getShareTime()->getTimestamp(), |
|
158 | - 'parent' => null, |
|
159 | - 'expiration' => null, |
|
160 | - 'token' => null, |
|
161 | - 'uid_file_owner' => $share->getShareOwner(), |
|
162 | - 'note' => $share->getNote(), |
|
163 | - 'displayname_file_owner' => $shareOwner !== null ? $shareOwner->getDisplayName() : $share->getShareOwner(), |
|
164 | - ]; |
|
165 | - |
|
166 | - $userFolder = $this->rootFolder->getUserFolder($this->currentUser); |
|
167 | - if ($recipientNode) { |
|
168 | - $node = $recipientNode; |
|
169 | - } else { |
|
170 | - $nodes = $userFolder->getById($share->getNodeId()); |
|
171 | - if (empty($nodes)) { |
|
172 | - // fallback to guessing the path |
|
173 | - $node = $userFolder->get($share->getTarget()); |
|
174 | - if ($node === null || $share->getTarget() === '') { |
|
175 | - throw new NotFoundException(); |
|
176 | - } |
|
177 | - } else { |
|
178 | - $node = $nodes[0]; |
|
179 | - } |
|
180 | - } |
|
181 | - |
|
182 | - $result['path'] = $userFolder->getRelativePath($node->getPath()); |
|
183 | - if ($node instanceOf \OCP\Files\Folder) { |
|
184 | - $result['item_type'] = 'folder'; |
|
185 | - } else { |
|
186 | - $result['item_type'] = 'file'; |
|
187 | - } |
|
188 | - $result['mimetype'] = $node->getMimetype(); |
|
189 | - $result['storage_id'] = $node->getStorage()->getId(); |
|
190 | - $result['storage'] = $node->getStorage()->getCache()->getNumericStorageId(); |
|
191 | - $result['item_source'] = $node->getId(); |
|
192 | - $result['file_source'] = $node->getId(); |
|
193 | - $result['file_parent'] = $node->getParent()->getId(); |
|
194 | - $result['file_target'] = $share->getTarget(); |
|
195 | - |
|
196 | - $expiration = $share->getExpirationDate(); |
|
197 | - if ($expiration !== null) { |
|
198 | - $result['expiration'] = $expiration->format('Y-m-d 00:00:00'); |
|
199 | - } |
|
200 | - |
|
201 | - if ($share->getShareType() === Share::SHARE_TYPE_USER) { |
|
202 | - $sharedWith = $this->userManager->get($share->getSharedWith()); |
|
203 | - $result['share_with'] = $share->getSharedWith(); |
|
204 | - $result['share_with_displayname'] = $sharedWith !== null ? $sharedWith->getDisplayName() : $share->getSharedWith(); |
|
205 | - } else if ($share->getShareType() === Share::SHARE_TYPE_GROUP) { |
|
206 | - $group = $this->groupManager->get($share->getSharedWith()); |
|
207 | - $result['share_with'] = $share->getSharedWith(); |
|
208 | - $result['share_with_displayname'] = $group !== null ? $group->getDisplayName() : $share->getSharedWith(); |
|
209 | - } else if ($share->getShareType() === Share::SHARE_TYPE_LINK) { |
|
210 | - |
|
211 | - $result['share_with'] = $share->getPassword(); |
|
212 | - $result['share_with_displayname'] = $share->getPassword(); |
|
213 | - |
|
214 | - $result['token'] = $share->getToken(); |
|
215 | - $result['url'] = $this->urlGenerator->linkToRouteAbsolute('files_sharing.sharecontroller.showShare', ['token' => $share->getToken()]); |
|
216 | - |
|
217 | - } else if ($share->getShareType() === Share::SHARE_TYPE_REMOTE || $share->getShareType() === Share::SHARE_TYPE_REMOTE_GROUP) { |
|
218 | - $result['share_with'] = $share->getSharedWith(); |
|
219 | - $result['share_with_displayname'] = $this->getDisplayNameFromAddressBook($share->getSharedWith(), 'CLOUD'); |
|
220 | - $result['token'] = $share->getToken(); |
|
221 | - } else if ($share->getShareType() === Share::SHARE_TYPE_EMAIL) { |
|
222 | - $result['share_with'] = $share->getSharedWith(); |
|
223 | - $result['password'] = $share->getPassword(); |
|
224 | - $result['send_password_by_talk'] = $share->getSendPasswordByTalk(); |
|
225 | - $result['share_with_displayname'] = $this->getDisplayNameFromAddressBook($share->getSharedWith(), 'EMAIL'); |
|
226 | - $result['token'] = $share->getToken(); |
|
227 | - } else if ($share->getShareType() === Share::SHARE_TYPE_CIRCLE) { |
|
228 | - // getSharedWith() returns either "name (type, owner)" or |
|
229 | - // "name (type, owner) [id]", depending on the Circles app version. |
|
230 | - $hasCircleId = (substr($share->getSharedWith(), -1) === ']'); |
|
231 | - |
|
232 | - $result['share_with_displayname'] = $share->getSharedWithDisplayName(); |
|
233 | - if (empty($result['share_with_displayname'])) { |
|
234 | - $displayNameLength = ($hasCircleId? strrpos($share->getSharedWith(), ' '): strlen($share->getSharedWith())); |
|
235 | - $result['share_with_displayname'] = substr($share->getSharedWith(), 0, $displayNameLength); |
|
236 | - } |
|
237 | - |
|
238 | - $result['share_with_avatar'] = $share->getSharedWithAvatar(); |
|
239 | - |
|
240 | - $shareWithStart = ($hasCircleId? strrpos($share->getSharedWith(), '[') + 1: 0); |
|
241 | - $shareWithLength = ($hasCircleId? -1: strpos($share->getSharedWith(), ' ')); |
|
242 | - $result['share_with'] = substr($share->getSharedWith(), $shareWithStart, $shareWithLength); |
|
243 | - } else if ($share->getShareType() === Share::SHARE_TYPE_ROOM) { |
|
244 | - $result['share_with'] = $share->getSharedWith(); |
|
245 | - $result['share_with_displayname'] = ''; |
|
246 | - |
|
247 | - try { |
|
248 | - $result = array_merge($result, $this->getRoomShareHelper()->formatShare($share)); |
|
249 | - } catch (QueryException $e) { |
|
250 | - } |
|
251 | - } |
|
252 | - |
|
253 | - |
|
254 | - $result['mail_send'] = $share->getMailSend() ? 1 : 0; |
|
255 | - |
|
256 | - return $result; |
|
257 | - } |
|
258 | - |
|
259 | - /** |
|
260 | - * Check if one of the users address books knows the exact property, if |
|
261 | - * yes we return the full name. |
|
262 | - * |
|
263 | - * @param string $query |
|
264 | - * @param string $property |
|
265 | - * @return string |
|
266 | - */ |
|
267 | - private function getDisplayNameFromAddressBook(string $query, string $property): string { |
|
268 | - // FIXME: If we inject the contacts manager it gets initialized bofore any address books are registered |
|
269 | - $result = \OC::$server->getContactsManager()->search($query, [$property]); |
|
270 | - foreach ($result as $r) { |
|
271 | - foreach($r[$property] as $value) { |
|
272 | - if ($value === $query) { |
|
273 | - return $r['FN']; |
|
274 | - } |
|
275 | - } |
|
276 | - } |
|
277 | - |
|
278 | - return $query; |
|
279 | - } |
|
280 | - |
|
281 | - /** |
|
282 | - * Get a specific share by id |
|
283 | - * |
|
284 | - * @NoAdminRequired |
|
285 | - * |
|
286 | - * @param string $id |
|
287 | - * @return DataResponse |
|
288 | - * @throws OCSNotFoundException |
|
289 | - */ |
|
290 | - public function getShare(string $id): DataResponse { |
|
291 | - try { |
|
292 | - $share = $this->getShareById($id); |
|
293 | - } catch (ShareNotFound $e) { |
|
294 | - throw new OCSNotFoundException($this->l->t('Wrong share ID, share doesn\'t exist')); |
|
295 | - } |
|
296 | - |
|
297 | - if ($this->canAccessShare($share)) { |
|
298 | - try { |
|
299 | - $share = $this->formatShare($share); |
|
300 | - return new DataResponse([$share]); |
|
301 | - } catch (NotFoundException $e) { |
|
302 | - //Fall trough |
|
303 | - } |
|
304 | - } |
|
305 | - |
|
306 | - throw new OCSNotFoundException($this->l->t('Wrong share ID, share doesn\'t exist')); |
|
307 | - } |
|
308 | - |
|
309 | - /** |
|
310 | - * Delete a share |
|
311 | - * |
|
312 | - * @NoAdminRequired |
|
313 | - * |
|
314 | - * @param string $id |
|
315 | - * @return DataResponse |
|
316 | - * @throws OCSNotFoundException |
|
317 | - */ |
|
318 | - public function deleteShare(string $id): DataResponse { |
|
319 | - try { |
|
320 | - $share = $this->getShareById($id); |
|
321 | - } catch (ShareNotFound $e) { |
|
322 | - throw new OCSNotFoundException($this->l->t('Wrong share ID, share doesn\'t exist')); |
|
323 | - } |
|
324 | - |
|
325 | - try { |
|
326 | - $this->lock($share->getNode()); |
|
327 | - } catch (LockedException $e) { |
|
328 | - throw new OCSNotFoundException($this->l->t('could not delete share')); |
|
329 | - } |
|
330 | - |
|
331 | - if (!$this->canAccessShare($share)) { |
|
332 | - throw new OCSNotFoundException($this->l->t('Could not delete share')); |
|
333 | - } |
|
334 | - |
|
335 | - if (($share->getShareType() === Share::SHARE_TYPE_GROUP || |
|
336 | - $share->getShareType() === Share::SHARE_TYPE_ROOM) && |
|
337 | - $share->getShareOwner() !== $this->currentUser && |
|
338 | - $share->getSharedBy() !== $this->currentUser) { |
|
339 | - $this->shareManager->deleteFromSelf($share, $this->currentUser); |
|
340 | - } else { |
|
341 | - $this->shareManager->deleteShare($share); |
|
342 | - } |
|
343 | - |
|
344 | - return new DataResponse(); |
|
345 | - } |
|
346 | - |
|
347 | - /** |
|
348 | - * @NoAdminRequired |
|
349 | - * |
|
350 | - * @param string $path |
|
351 | - * @param int $permissions |
|
352 | - * @param int $shareType |
|
353 | - * @param string $shareWith |
|
354 | - * @param string $publicUpload |
|
355 | - * @param string $password |
|
356 | - * @param bool $sendPasswordByTalk |
|
357 | - * @param string $expireDate |
|
358 | - * |
|
359 | - * @return DataResponse |
|
360 | - * @throws OCSNotFoundException |
|
361 | - * @throws OCSForbiddenException |
|
362 | - * @throws OCSBadRequestException |
|
363 | - * @throws OCSException |
|
364 | - * |
|
365 | - * @suppress PhanUndeclaredClassMethod |
|
366 | - */ |
|
367 | - public function createShare( |
|
368 | - string $path = null, |
|
369 | - int $permissions = null, |
|
370 | - int $shareType = -1, |
|
371 | - string $shareWith = null, |
|
372 | - string $publicUpload = 'false', |
|
373 | - string $password = '', |
|
374 | - string $sendPasswordByTalk = null, |
|
375 | - string $expireDate = '' |
|
376 | - ): DataResponse { |
|
377 | - $share = $this->shareManager->newShare(); |
|
378 | - |
|
379 | - if ($permissions === null) { |
|
380 | - $permissions = $this->config->getAppValue('core', 'shareapi_default_permissions', Constants::PERMISSION_ALL); |
|
381 | - } |
|
382 | - |
|
383 | - // Verify path |
|
384 | - if ($path === null) { |
|
385 | - throw new OCSNotFoundException($this->l->t('Please specify a file or folder path')); |
|
386 | - } |
|
387 | - |
|
388 | - $userFolder = $this->rootFolder->getUserFolder($this->currentUser); |
|
389 | - try { |
|
390 | - $path = $userFolder->get($path); |
|
391 | - } catch (NotFoundException $e) { |
|
392 | - throw new OCSNotFoundException($this->l->t('Wrong path, file/folder doesn\'t exist')); |
|
393 | - } |
|
394 | - |
|
395 | - $share->setNode($path); |
|
396 | - |
|
397 | - try { |
|
398 | - $this->lock($share->getNode()); |
|
399 | - } catch (LockedException $e) { |
|
400 | - throw new OCSNotFoundException($this->l->t('Could not create share')); |
|
401 | - } |
|
402 | - |
|
403 | - if ($permissions < 0 || $permissions > Constants::PERMISSION_ALL) { |
|
404 | - throw new OCSNotFoundException($this->l->t('invalid permissions')); |
|
405 | - } |
|
406 | - |
|
407 | - // Shares always require read permissions |
|
408 | - $permissions |= Constants::PERMISSION_READ; |
|
409 | - |
|
410 | - if ($path instanceof \OCP\Files\File) { |
|
411 | - // Single file shares should never have delete or create permissions |
|
412 | - $permissions &= ~Constants::PERMISSION_DELETE; |
|
413 | - $permissions &= ~Constants::PERMISSION_CREATE; |
|
414 | - } |
|
415 | - |
|
416 | - /* |
|
69 | + /** @var IManager */ |
|
70 | + private $shareManager; |
|
71 | + /** @var IGroupManager */ |
|
72 | + private $groupManager; |
|
73 | + /** @var IUserManager */ |
|
74 | + private $userManager; |
|
75 | + /** @var IRootFolder */ |
|
76 | + private $rootFolder; |
|
77 | + /** @var IURLGenerator */ |
|
78 | + private $urlGenerator; |
|
79 | + /** @var string */ |
|
80 | + private $currentUser; |
|
81 | + /** @var IL10N */ |
|
82 | + private $l; |
|
83 | + /** @var \OCP\Files\Node */ |
|
84 | + private $lockedNode; |
|
85 | + /** @var IConfig */ |
|
86 | + private $config; |
|
87 | + /** @var IAppManager */ |
|
88 | + private $appManager; |
|
89 | + /** @var IServerContainer */ |
|
90 | + private $serverContainer; |
|
91 | + |
|
92 | + /** |
|
93 | + * Share20OCS constructor. |
|
94 | + * |
|
95 | + * @param string $appName |
|
96 | + * @param IRequest $request |
|
97 | + * @param IManager $shareManager |
|
98 | + * @param IGroupManager $groupManager |
|
99 | + * @param IUserManager $userManager |
|
100 | + * @param IRootFolder $rootFolder |
|
101 | + * @param IURLGenerator $urlGenerator |
|
102 | + * @param string $userId |
|
103 | + * @param IL10N $l10n |
|
104 | + * @param IConfig $config |
|
105 | + * @param IAppManager $appManager |
|
106 | + * @param IServerContainer $serverContainer |
|
107 | + */ |
|
108 | + public function __construct( |
|
109 | + string $appName, |
|
110 | + IRequest $request, |
|
111 | + IManager $shareManager, |
|
112 | + IGroupManager $groupManager, |
|
113 | + IUserManager $userManager, |
|
114 | + IRootFolder $rootFolder, |
|
115 | + IURLGenerator $urlGenerator, |
|
116 | + string $userId = null, |
|
117 | + IL10N $l10n, |
|
118 | + IConfig $config, |
|
119 | + IAppManager $appManager, |
|
120 | + IServerContainer $serverContainer |
|
121 | + ) { |
|
122 | + parent::__construct($appName, $request); |
|
123 | + |
|
124 | + $this->shareManager = $shareManager; |
|
125 | + $this->userManager = $userManager; |
|
126 | + $this->groupManager = $groupManager; |
|
127 | + $this->request = $request; |
|
128 | + $this->rootFolder = $rootFolder; |
|
129 | + $this->urlGenerator = $urlGenerator; |
|
130 | + $this->currentUser = $userId; |
|
131 | + $this->l = $l10n; |
|
132 | + $this->config = $config; |
|
133 | + $this->appManager = $appManager; |
|
134 | + $this->serverContainer = $serverContainer; |
|
135 | + } |
|
136 | + |
|
137 | + /** |
|
138 | + * Convert an IShare to an array for OCS output |
|
139 | + * |
|
140 | + * @param \OCP\Share\IShare $share |
|
141 | + * @param Node|null $recipientNode |
|
142 | + * @return array |
|
143 | + * @throws NotFoundException In case the node can't be resolved. |
|
144 | + * |
|
145 | + * @suppress PhanUndeclaredClassMethod |
|
146 | + */ |
|
147 | + protected function formatShare(\OCP\Share\IShare $share, Node $recipientNode = null): array { |
|
148 | + $sharedBy = $this->userManager->get($share->getSharedBy()); |
|
149 | + $shareOwner = $this->userManager->get($share->getShareOwner()); |
|
150 | + |
|
151 | + $result = [ |
|
152 | + 'id' => $share->getId(), |
|
153 | + 'share_type' => $share->getShareType(), |
|
154 | + 'uid_owner' => $share->getSharedBy(), |
|
155 | + 'displayname_owner' => $sharedBy !== null ? $sharedBy->getDisplayName() : $share->getSharedBy(), |
|
156 | + 'permissions' => $share->getPermissions(), |
|
157 | + 'stime' => $share->getShareTime()->getTimestamp(), |
|
158 | + 'parent' => null, |
|
159 | + 'expiration' => null, |
|
160 | + 'token' => null, |
|
161 | + 'uid_file_owner' => $share->getShareOwner(), |
|
162 | + 'note' => $share->getNote(), |
|
163 | + 'displayname_file_owner' => $shareOwner !== null ? $shareOwner->getDisplayName() : $share->getShareOwner(), |
|
164 | + ]; |
|
165 | + |
|
166 | + $userFolder = $this->rootFolder->getUserFolder($this->currentUser); |
|
167 | + if ($recipientNode) { |
|
168 | + $node = $recipientNode; |
|
169 | + } else { |
|
170 | + $nodes = $userFolder->getById($share->getNodeId()); |
|
171 | + if (empty($nodes)) { |
|
172 | + // fallback to guessing the path |
|
173 | + $node = $userFolder->get($share->getTarget()); |
|
174 | + if ($node === null || $share->getTarget() === '') { |
|
175 | + throw new NotFoundException(); |
|
176 | + } |
|
177 | + } else { |
|
178 | + $node = $nodes[0]; |
|
179 | + } |
|
180 | + } |
|
181 | + |
|
182 | + $result['path'] = $userFolder->getRelativePath($node->getPath()); |
|
183 | + if ($node instanceOf \OCP\Files\Folder) { |
|
184 | + $result['item_type'] = 'folder'; |
|
185 | + } else { |
|
186 | + $result['item_type'] = 'file'; |
|
187 | + } |
|
188 | + $result['mimetype'] = $node->getMimetype(); |
|
189 | + $result['storage_id'] = $node->getStorage()->getId(); |
|
190 | + $result['storage'] = $node->getStorage()->getCache()->getNumericStorageId(); |
|
191 | + $result['item_source'] = $node->getId(); |
|
192 | + $result['file_source'] = $node->getId(); |
|
193 | + $result['file_parent'] = $node->getParent()->getId(); |
|
194 | + $result['file_target'] = $share->getTarget(); |
|
195 | + |
|
196 | + $expiration = $share->getExpirationDate(); |
|
197 | + if ($expiration !== null) { |
|
198 | + $result['expiration'] = $expiration->format('Y-m-d 00:00:00'); |
|
199 | + } |
|
200 | + |
|
201 | + if ($share->getShareType() === Share::SHARE_TYPE_USER) { |
|
202 | + $sharedWith = $this->userManager->get($share->getSharedWith()); |
|
203 | + $result['share_with'] = $share->getSharedWith(); |
|
204 | + $result['share_with_displayname'] = $sharedWith !== null ? $sharedWith->getDisplayName() : $share->getSharedWith(); |
|
205 | + } else if ($share->getShareType() === Share::SHARE_TYPE_GROUP) { |
|
206 | + $group = $this->groupManager->get($share->getSharedWith()); |
|
207 | + $result['share_with'] = $share->getSharedWith(); |
|
208 | + $result['share_with_displayname'] = $group !== null ? $group->getDisplayName() : $share->getSharedWith(); |
|
209 | + } else if ($share->getShareType() === Share::SHARE_TYPE_LINK) { |
|
210 | + |
|
211 | + $result['share_with'] = $share->getPassword(); |
|
212 | + $result['share_with_displayname'] = $share->getPassword(); |
|
213 | + |
|
214 | + $result['token'] = $share->getToken(); |
|
215 | + $result['url'] = $this->urlGenerator->linkToRouteAbsolute('files_sharing.sharecontroller.showShare', ['token' => $share->getToken()]); |
|
216 | + |
|
217 | + } else if ($share->getShareType() === Share::SHARE_TYPE_REMOTE || $share->getShareType() === Share::SHARE_TYPE_REMOTE_GROUP) { |
|
218 | + $result['share_with'] = $share->getSharedWith(); |
|
219 | + $result['share_with_displayname'] = $this->getDisplayNameFromAddressBook($share->getSharedWith(), 'CLOUD'); |
|
220 | + $result['token'] = $share->getToken(); |
|
221 | + } else if ($share->getShareType() === Share::SHARE_TYPE_EMAIL) { |
|
222 | + $result['share_with'] = $share->getSharedWith(); |
|
223 | + $result['password'] = $share->getPassword(); |
|
224 | + $result['send_password_by_talk'] = $share->getSendPasswordByTalk(); |
|
225 | + $result['share_with_displayname'] = $this->getDisplayNameFromAddressBook($share->getSharedWith(), 'EMAIL'); |
|
226 | + $result['token'] = $share->getToken(); |
|
227 | + } else if ($share->getShareType() === Share::SHARE_TYPE_CIRCLE) { |
|
228 | + // getSharedWith() returns either "name (type, owner)" or |
|
229 | + // "name (type, owner) [id]", depending on the Circles app version. |
|
230 | + $hasCircleId = (substr($share->getSharedWith(), -1) === ']'); |
|
231 | + |
|
232 | + $result['share_with_displayname'] = $share->getSharedWithDisplayName(); |
|
233 | + if (empty($result['share_with_displayname'])) { |
|
234 | + $displayNameLength = ($hasCircleId? strrpos($share->getSharedWith(), ' '): strlen($share->getSharedWith())); |
|
235 | + $result['share_with_displayname'] = substr($share->getSharedWith(), 0, $displayNameLength); |
|
236 | + } |
|
237 | + |
|
238 | + $result['share_with_avatar'] = $share->getSharedWithAvatar(); |
|
239 | + |
|
240 | + $shareWithStart = ($hasCircleId? strrpos($share->getSharedWith(), '[') + 1: 0); |
|
241 | + $shareWithLength = ($hasCircleId? -1: strpos($share->getSharedWith(), ' ')); |
|
242 | + $result['share_with'] = substr($share->getSharedWith(), $shareWithStart, $shareWithLength); |
|
243 | + } else if ($share->getShareType() === Share::SHARE_TYPE_ROOM) { |
|
244 | + $result['share_with'] = $share->getSharedWith(); |
|
245 | + $result['share_with_displayname'] = ''; |
|
246 | + |
|
247 | + try { |
|
248 | + $result = array_merge($result, $this->getRoomShareHelper()->formatShare($share)); |
|
249 | + } catch (QueryException $e) { |
|
250 | + } |
|
251 | + } |
|
252 | + |
|
253 | + |
|
254 | + $result['mail_send'] = $share->getMailSend() ? 1 : 0; |
|
255 | + |
|
256 | + return $result; |
|
257 | + } |
|
258 | + |
|
259 | + /** |
|
260 | + * Check if one of the users address books knows the exact property, if |
|
261 | + * yes we return the full name. |
|
262 | + * |
|
263 | + * @param string $query |
|
264 | + * @param string $property |
|
265 | + * @return string |
|
266 | + */ |
|
267 | + private function getDisplayNameFromAddressBook(string $query, string $property): string { |
|
268 | + // FIXME: If we inject the contacts manager it gets initialized bofore any address books are registered |
|
269 | + $result = \OC::$server->getContactsManager()->search($query, [$property]); |
|
270 | + foreach ($result as $r) { |
|
271 | + foreach($r[$property] as $value) { |
|
272 | + if ($value === $query) { |
|
273 | + return $r['FN']; |
|
274 | + } |
|
275 | + } |
|
276 | + } |
|
277 | + |
|
278 | + return $query; |
|
279 | + } |
|
280 | + |
|
281 | + /** |
|
282 | + * Get a specific share by id |
|
283 | + * |
|
284 | + * @NoAdminRequired |
|
285 | + * |
|
286 | + * @param string $id |
|
287 | + * @return DataResponse |
|
288 | + * @throws OCSNotFoundException |
|
289 | + */ |
|
290 | + public function getShare(string $id): DataResponse { |
|
291 | + try { |
|
292 | + $share = $this->getShareById($id); |
|
293 | + } catch (ShareNotFound $e) { |
|
294 | + throw new OCSNotFoundException($this->l->t('Wrong share ID, share doesn\'t exist')); |
|
295 | + } |
|
296 | + |
|
297 | + if ($this->canAccessShare($share)) { |
|
298 | + try { |
|
299 | + $share = $this->formatShare($share); |
|
300 | + return new DataResponse([$share]); |
|
301 | + } catch (NotFoundException $e) { |
|
302 | + //Fall trough |
|
303 | + } |
|
304 | + } |
|
305 | + |
|
306 | + throw new OCSNotFoundException($this->l->t('Wrong share ID, share doesn\'t exist')); |
|
307 | + } |
|
308 | + |
|
309 | + /** |
|
310 | + * Delete a share |
|
311 | + * |
|
312 | + * @NoAdminRequired |
|
313 | + * |
|
314 | + * @param string $id |
|
315 | + * @return DataResponse |
|
316 | + * @throws OCSNotFoundException |
|
317 | + */ |
|
318 | + public function deleteShare(string $id): DataResponse { |
|
319 | + try { |
|
320 | + $share = $this->getShareById($id); |
|
321 | + } catch (ShareNotFound $e) { |
|
322 | + throw new OCSNotFoundException($this->l->t('Wrong share ID, share doesn\'t exist')); |
|
323 | + } |
|
324 | + |
|
325 | + try { |
|
326 | + $this->lock($share->getNode()); |
|
327 | + } catch (LockedException $e) { |
|
328 | + throw new OCSNotFoundException($this->l->t('could not delete share')); |
|
329 | + } |
|
330 | + |
|
331 | + if (!$this->canAccessShare($share)) { |
|
332 | + throw new OCSNotFoundException($this->l->t('Could not delete share')); |
|
333 | + } |
|
334 | + |
|
335 | + if (($share->getShareType() === Share::SHARE_TYPE_GROUP || |
|
336 | + $share->getShareType() === Share::SHARE_TYPE_ROOM) && |
|
337 | + $share->getShareOwner() !== $this->currentUser && |
|
338 | + $share->getSharedBy() !== $this->currentUser) { |
|
339 | + $this->shareManager->deleteFromSelf($share, $this->currentUser); |
|
340 | + } else { |
|
341 | + $this->shareManager->deleteShare($share); |
|
342 | + } |
|
343 | + |
|
344 | + return new DataResponse(); |
|
345 | + } |
|
346 | + |
|
347 | + /** |
|
348 | + * @NoAdminRequired |
|
349 | + * |
|
350 | + * @param string $path |
|
351 | + * @param int $permissions |
|
352 | + * @param int $shareType |
|
353 | + * @param string $shareWith |
|
354 | + * @param string $publicUpload |
|
355 | + * @param string $password |
|
356 | + * @param bool $sendPasswordByTalk |
|
357 | + * @param string $expireDate |
|
358 | + * |
|
359 | + * @return DataResponse |
|
360 | + * @throws OCSNotFoundException |
|
361 | + * @throws OCSForbiddenException |
|
362 | + * @throws OCSBadRequestException |
|
363 | + * @throws OCSException |
|
364 | + * |
|
365 | + * @suppress PhanUndeclaredClassMethod |
|
366 | + */ |
|
367 | + public function createShare( |
|
368 | + string $path = null, |
|
369 | + int $permissions = null, |
|
370 | + int $shareType = -1, |
|
371 | + string $shareWith = null, |
|
372 | + string $publicUpload = 'false', |
|
373 | + string $password = '', |
|
374 | + string $sendPasswordByTalk = null, |
|
375 | + string $expireDate = '' |
|
376 | + ): DataResponse { |
|
377 | + $share = $this->shareManager->newShare(); |
|
378 | + |
|
379 | + if ($permissions === null) { |
|
380 | + $permissions = $this->config->getAppValue('core', 'shareapi_default_permissions', Constants::PERMISSION_ALL); |
|
381 | + } |
|
382 | + |
|
383 | + // Verify path |
|
384 | + if ($path === null) { |
|
385 | + throw new OCSNotFoundException($this->l->t('Please specify a file or folder path')); |
|
386 | + } |
|
387 | + |
|
388 | + $userFolder = $this->rootFolder->getUserFolder($this->currentUser); |
|
389 | + try { |
|
390 | + $path = $userFolder->get($path); |
|
391 | + } catch (NotFoundException $e) { |
|
392 | + throw new OCSNotFoundException($this->l->t('Wrong path, file/folder doesn\'t exist')); |
|
393 | + } |
|
394 | + |
|
395 | + $share->setNode($path); |
|
396 | + |
|
397 | + try { |
|
398 | + $this->lock($share->getNode()); |
|
399 | + } catch (LockedException $e) { |
|
400 | + throw new OCSNotFoundException($this->l->t('Could not create share')); |
|
401 | + } |
|
402 | + |
|
403 | + if ($permissions < 0 || $permissions > Constants::PERMISSION_ALL) { |
|
404 | + throw new OCSNotFoundException($this->l->t('invalid permissions')); |
|
405 | + } |
|
406 | + |
|
407 | + // Shares always require read permissions |
|
408 | + $permissions |= Constants::PERMISSION_READ; |
|
409 | + |
|
410 | + if ($path instanceof \OCP\Files\File) { |
|
411 | + // Single file shares should never have delete or create permissions |
|
412 | + $permissions &= ~Constants::PERMISSION_DELETE; |
|
413 | + $permissions &= ~Constants::PERMISSION_CREATE; |
|
414 | + } |
|
415 | + |
|
416 | + /* |
|
417 | 417 | * Hack for https://github.com/owncloud/core/issues/22587 |
418 | 418 | * We check the permissions via webdav. But the permissions of the mount point |
419 | 419 | * do not equal the share permissions. Here we fix that for federated mounts. |
420 | 420 | */ |
421 | - if ($path->getStorage()->instanceOfStorage(Storage::class)) { |
|
422 | - $permissions &= ~($permissions & ~$path->getPermissions()); |
|
423 | - } |
|
424 | - |
|
425 | - if ($shareType === Share::SHARE_TYPE_USER) { |
|
426 | - // Valid user is required to share |
|
427 | - if ($shareWith === null || !$this->userManager->userExists($shareWith)) { |
|
428 | - throw new OCSNotFoundException($this->l->t('Please specify a valid user')); |
|
429 | - } |
|
430 | - $share->setSharedWith($shareWith); |
|
431 | - $share->setPermissions($permissions); |
|
432 | - } else if ($shareType === Share::SHARE_TYPE_GROUP) { |
|
433 | - if (!$this->shareManager->allowGroupSharing()) { |
|
434 | - throw new OCSNotFoundException($this->l->t('Group sharing is disabled by the administrator')); |
|
435 | - } |
|
436 | - |
|
437 | - // Valid group is required to share |
|
438 | - if ($shareWith === null || !$this->groupManager->groupExists($shareWith)) { |
|
439 | - throw new OCSNotFoundException($this->l->t('Please specify a valid group')); |
|
440 | - } |
|
441 | - $share->setSharedWith($shareWith); |
|
442 | - $share->setPermissions($permissions); |
|
443 | - } else if ($shareType === Share::SHARE_TYPE_LINK) { |
|
444 | - //Can we even share links? |
|
445 | - if (!$this->shareManager->shareApiAllowLinks()) { |
|
446 | - throw new OCSNotFoundException($this->l->t('Public link sharing is disabled by the administrator')); |
|
447 | - } |
|
448 | - |
|
449 | - /* |
|
421 | + if ($path->getStorage()->instanceOfStorage(Storage::class)) { |
|
422 | + $permissions &= ~($permissions & ~$path->getPermissions()); |
|
423 | + } |
|
424 | + |
|
425 | + if ($shareType === Share::SHARE_TYPE_USER) { |
|
426 | + // Valid user is required to share |
|
427 | + if ($shareWith === null || !$this->userManager->userExists($shareWith)) { |
|
428 | + throw new OCSNotFoundException($this->l->t('Please specify a valid user')); |
|
429 | + } |
|
430 | + $share->setSharedWith($shareWith); |
|
431 | + $share->setPermissions($permissions); |
|
432 | + } else if ($shareType === Share::SHARE_TYPE_GROUP) { |
|
433 | + if (!$this->shareManager->allowGroupSharing()) { |
|
434 | + throw new OCSNotFoundException($this->l->t('Group sharing is disabled by the administrator')); |
|
435 | + } |
|
436 | + |
|
437 | + // Valid group is required to share |
|
438 | + if ($shareWith === null || !$this->groupManager->groupExists($shareWith)) { |
|
439 | + throw new OCSNotFoundException($this->l->t('Please specify a valid group')); |
|
440 | + } |
|
441 | + $share->setSharedWith($shareWith); |
|
442 | + $share->setPermissions($permissions); |
|
443 | + } else if ($shareType === Share::SHARE_TYPE_LINK) { |
|
444 | + //Can we even share links? |
|
445 | + if (!$this->shareManager->shareApiAllowLinks()) { |
|
446 | + throw new OCSNotFoundException($this->l->t('Public link sharing is disabled by the administrator')); |
|
447 | + } |
|
448 | + |
|
449 | + /* |
|
450 | 450 | * For now we only allow 1 link share. |
451 | 451 | * Return the existing link share if this is a duplicate |
452 | 452 | */ |
453 | - $existingShares = $this->shareManager->getSharesBy($this->currentUser, Share::SHARE_TYPE_LINK, $path, false, 1, 0); |
|
454 | - if (!empty($existingShares)) { |
|
455 | - return new DataResponse($this->formatShare($existingShares[0])); |
|
456 | - } |
|
457 | - |
|
458 | - if ($publicUpload === 'true') { |
|
459 | - // Check if public upload is allowed |
|
460 | - if (!$this->shareManager->shareApiLinkAllowPublicUpload()) { |
|
461 | - throw new OCSForbiddenException($this->l->t('Public upload disabled by the administrator')); |
|
462 | - } |
|
463 | - |
|
464 | - // Public upload can only be set for folders |
|
465 | - if ($path instanceof \OCP\Files\File) { |
|
466 | - throw new OCSNotFoundException($this->l->t('Public upload is only possible for publicly shared folders')); |
|
467 | - } |
|
468 | - |
|
469 | - $share->setPermissions( |
|
470 | - Constants::PERMISSION_READ | |
|
471 | - Constants::PERMISSION_CREATE | |
|
472 | - Constants::PERMISSION_UPDATE | |
|
473 | - Constants::PERMISSION_DELETE |
|
474 | - ); |
|
475 | - } else { |
|
476 | - $share->setPermissions(Constants::PERMISSION_READ); |
|
477 | - } |
|
478 | - |
|
479 | - // Set password |
|
480 | - if ($password !== '') { |
|
481 | - $share->setPassword($password); |
|
482 | - } |
|
483 | - |
|
484 | - //Expire date |
|
485 | - if ($expireDate !== '') { |
|
486 | - try { |
|
487 | - $expireDate = $this->parseDate($expireDate); |
|
488 | - $share->setExpirationDate($expireDate); |
|
489 | - } catch (\Exception $e) { |
|
490 | - throw new OCSNotFoundException($this->l->t('Invalid date, date format must be YYYY-MM-DD')); |
|
491 | - } |
|
492 | - } |
|
493 | - |
|
494 | - } else if ($shareType === Share::SHARE_TYPE_REMOTE) { |
|
495 | - if (!$this->shareManager->outgoingServer2ServerSharesAllowed()) { |
|
496 | - 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])); |
|
497 | - } |
|
498 | - |
|
499 | - $share->setSharedWith($shareWith); |
|
500 | - $share->setPermissions($permissions); |
|
501 | - } else if ($shareType === Share::SHARE_TYPE_REMOTE_GROUP) { |
|
502 | - if (!$this->shareManager->outgoingServer2ServerGroupSharesAllowed()) { |
|
503 | - 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])); |
|
504 | - } |
|
505 | - |
|
506 | - $share->setSharedWith($shareWith); |
|
507 | - $share->setPermissions($permissions); |
|
508 | - } else if ($shareType === Share::SHARE_TYPE_EMAIL) { |
|
509 | - if ($share->getNodeType() === 'file') { |
|
510 | - $share->setPermissions(Constants::PERMISSION_READ); |
|
511 | - } else { |
|
512 | - $share->setPermissions($permissions); |
|
513 | - } |
|
514 | - $share->setSharedWith($shareWith); |
|
515 | - |
|
516 | - if ($sendPasswordByTalk === 'true') { |
|
517 | - if (!$this->appManager->isEnabledForUser('spreed')) { |
|
518 | - throw new OCSForbiddenException($this->l->t('Sharing %s sending the password by Nextcloud Talk failed because Nextcloud Talk is not enabled', [$path->getPath()])); |
|
519 | - } |
|
520 | - |
|
521 | - $share->setSendPasswordByTalk(true); |
|
522 | - } |
|
523 | - } else if ($shareType === Share::SHARE_TYPE_CIRCLE) { |
|
524 | - if (!\OC::$server->getAppManager()->isEnabledForUser('circles') || !class_exists('\OCA\Circles\ShareByCircleProvider')) { |
|
525 | - throw new OCSNotFoundException($this->l->t('You cannot share to a Circle if the app is not enabled')); |
|
526 | - } |
|
527 | - |
|
528 | - $circle = \OCA\Circles\Api\v1\Circles::detailsCircle($shareWith); |
|
529 | - |
|
530 | - // Valid circle is required to share |
|
531 | - if ($circle === null) { |
|
532 | - throw new OCSNotFoundException($this->l->t('Please specify a valid circle')); |
|
533 | - } |
|
534 | - $share->setSharedWith($shareWith); |
|
535 | - $share->setPermissions($permissions); |
|
536 | - } else if ($shareType === Share::SHARE_TYPE_ROOM) { |
|
537 | - try { |
|
538 | - $this->getRoomShareHelper()->createShare($share, $shareWith, $permissions, $expireDate); |
|
539 | - } catch (QueryException $e) { |
|
540 | - throw new OCSForbiddenException($this->l->t('Sharing %s failed because the back end does not support room shares', [$path->getPath()])); |
|
541 | - } |
|
542 | - } else { |
|
543 | - throw new OCSBadRequestException($this->l->t('Unknown share type')); |
|
544 | - } |
|
545 | - |
|
546 | - $share->setShareType($shareType); |
|
547 | - $share->setSharedBy($this->currentUser); |
|
548 | - |
|
549 | - try { |
|
550 | - $share = $this->shareManager->createShare($share); |
|
551 | - } catch (GenericShareException $e) { |
|
552 | - $code = $e->getCode() === 0 ? 403 : $e->getCode(); |
|
553 | - throw new OCSException($e->getHint(), $code); |
|
554 | - } catch (\Exception $e) { |
|
555 | - throw new OCSForbiddenException($e->getMessage(), $e); |
|
556 | - } |
|
557 | - |
|
558 | - $output = $this->formatShare($share); |
|
559 | - |
|
560 | - return new DataResponse($output); |
|
561 | - } |
|
562 | - |
|
563 | - /** |
|
564 | - * @param \OCP\Files\File|\OCP\Files\Folder $node |
|
565 | - * @param boolean $includeTags |
|
566 | - * @return DataResponse |
|
567 | - */ |
|
568 | - private function getSharedWithMe($node = null, bool $includeTags): DataResponse { |
|
569 | - |
|
570 | - $userShares = $this->shareManager->getSharedWith($this->currentUser, Share::SHARE_TYPE_USER, $node, -1, 0); |
|
571 | - $groupShares = $this->shareManager->getSharedWith($this->currentUser, Share::SHARE_TYPE_GROUP, $node, -1, 0); |
|
572 | - $circleShares = $this->shareManager->getSharedWith($this->currentUser, Share::SHARE_TYPE_CIRCLE, $node, -1, 0); |
|
573 | - $roomShares = $this->shareManager->getSharedWith($this->currentUser, Share::SHARE_TYPE_ROOM, $node, -1, 0); |
|
574 | - |
|
575 | - $shares = array_merge($userShares, $groupShares, $circleShares, $roomShares); |
|
576 | - |
|
577 | - $shares = array_filter($shares, function (IShare $share) { |
|
578 | - return $share->getShareOwner() !== $this->currentUser; |
|
579 | - }); |
|
580 | - |
|
581 | - $formatted = []; |
|
582 | - foreach ($shares as $share) { |
|
583 | - if ($this->canAccessShare($share)) { |
|
584 | - try { |
|
585 | - $formatted[] = $this->formatShare($share); |
|
586 | - } catch (NotFoundException $e) { |
|
587 | - // Ignore this share |
|
588 | - } |
|
589 | - } |
|
590 | - } |
|
591 | - |
|
592 | - if ($includeTags) { |
|
593 | - $formatted = Helper::populateTags($formatted, 'file_source', \OC::$server->getTagManager()); |
|
594 | - } |
|
595 | - |
|
596 | - return new DataResponse($formatted); |
|
597 | - } |
|
598 | - |
|
599 | - /** |
|
600 | - * @param \OCP\Files\Folder $folder |
|
601 | - * @return DataResponse |
|
602 | - * @throws OCSBadRequestException |
|
603 | - */ |
|
604 | - private function getSharesInDir(Node $folder): DataResponse { |
|
605 | - if (!($folder instanceof \OCP\Files\Folder)) { |
|
606 | - throw new OCSBadRequestException($this->l->t('Not a directory')); |
|
607 | - } |
|
608 | - |
|
609 | - $nodes = $folder->getDirectoryListing(); |
|
610 | - /** @var \OCP\Share\IShare[] $shares */ |
|
611 | - $shares = []; |
|
612 | - foreach ($nodes as $node) { |
|
613 | - $shares = array_merge($shares, $this->shareManager->getSharesBy($this->currentUser, Share::SHARE_TYPE_USER, $node, false, -1, 0)); |
|
614 | - $shares = array_merge($shares, $this->shareManager->getSharesBy($this->currentUser, Share::SHARE_TYPE_GROUP, $node, false, -1, 0)); |
|
615 | - $shares = array_merge($shares, $this->shareManager->getSharesBy($this->currentUser, Share::SHARE_TYPE_LINK, $node, false, -1, 0)); |
|
616 | - if($this->shareManager->shareProviderExists(Share::SHARE_TYPE_EMAIL)) { |
|
617 | - $shares = array_merge($shares, $this->shareManager->getSharesBy($this->currentUser, Share::SHARE_TYPE_EMAIL, $node, false, -1, 0)); |
|
618 | - } |
|
619 | - if ($this->shareManager->outgoingServer2ServerSharesAllowed()) { |
|
620 | - $shares = array_merge($shares, $this->shareManager->getSharesBy($this->currentUser, Share::SHARE_TYPE_REMOTE, $node, false, -1, 0)); |
|
621 | - } |
|
622 | - $shares = array_merge($shares, $this->shareManager->getSharesBy($this->currentUser, Share::SHARE_TYPE_ROOM, $node, false, -1, 0)); |
|
623 | - } |
|
624 | - |
|
625 | - $formatted = []; |
|
626 | - foreach ($shares as $share) { |
|
627 | - try { |
|
628 | - $formatted[] = $this->formatShare($share); |
|
629 | - } catch (NotFoundException $e) { |
|
630 | - //Ignore this share |
|
631 | - } |
|
632 | - } |
|
633 | - |
|
634 | - return new DataResponse($formatted); |
|
635 | - } |
|
636 | - |
|
637 | - /** |
|
638 | - * The getShares function. |
|
639 | - * |
|
640 | - * @NoAdminRequired |
|
641 | - * |
|
642 | - * @param string $shared_with_me |
|
643 | - * @param string $reshares |
|
644 | - * @param string $subfiles |
|
645 | - * @param string $path |
|
646 | - * |
|
647 | - * - Get shares by the current user |
|
648 | - * - Get shares by the current user and reshares (?reshares=true) |
|
649 | - * - Get shares with the current user (?shared_with_me=true) |
|
650 | - * - Get shares for a specific path (?path=...) |
|
651 | - * - Get all shares in a folder (?subfiles=true&path=..) |
|
652 | - * |
|
653 | - * @return DataResponse |
|
654 | - * @throws OCSNotFoundException |
|
655 | - */ |
|
656 | - public function getShares( |
|
657 | - string $shared_with_me = 'false', |
|
658 | - string $reshares = 'false', |
|
659 | - string $subfiles = 'false', |
|
660 | - string $path = null, |
|
661 | - string $include_tags = 'false' |
|
662 | - ): DataResponse { |
|
663 | - |
|
664 | - if ($path !== null) { |
|
665 | - $userFolder = $this->rootFolder->getUserFolder($this->currentUser); |
|
666 | - try { |
|
667 | - $path = $userFolder->get($path); |
|
668 | - $this->lock($path); |
|
669 | - } catch (\OCP\Files\NotFoundException $e) { |
|
670 | - throw new OCSNotFoundException($this->l->t('Wrong path, file/folder doesn\'t exist')); |
|
671 | - } catch (LockedException $e) { |
|
672 | - throw new OCSNotFoundException($this->l->t('Could not lock path')); |
|
673 | - } |
|
674 | - } |
|
675 | - |
|
676 | - $include_tags = $include_tags === 'true'; |
|
677 | - |
|
678 | - if ($shared_with_me === 'true') { |
|
679 | - $result = $this->getSharedWithMe($path, $include_tags); |
|
680 | - return $result; |
|
681 | - } |
|
682 | - |
|
683 | - if ($subfiles === 'true') { |
|
684 | - $result = $this->getSharesInDir($path); |
|
685 | - return $result; |
|
686 | - } |
|
687 | - |
|
688 | - if ($reshares === 'true') { |
|
689 | - $reshares = true; |
|
690 | - } else { |
|
691 | - $reshares = false; |
|
692 | - } |
|
693 | - |
|
694 | - // Get all shares |
|
695 | - $userShares = $this->shareManager->getSharesBy($this->currentUser, Share::SHARE_TYPE_USER, $path, $reshares, -1, 0); |
|
696 | - $groupShares = $this->shareManager->getSharesBy($this->currentUser, Share::SHARE_TYPE_GROUP, $path, $reshares, -1, 0); |
|
697 | - $linkShares = $this->shareManager->getSharesBy($this->currentUser, Share::SHARE_TYPE_LINK, $path, $reshares, -1, 0); |
|
698 | - if ($this->shareManager->shareProviderExists(Share::SHARE_TYPE_EMAIL)) { |
|
699 | - $mailShares = $this->shareManager->getSharesBy($this->currentUser, Share::SHARE_TYPE_EMAIL, $path, $reshares, -1, 0); |
|
700 | - } else { |
|
701 | - $mailShares = []; |
|
702 | - } |
|
703 | - if ($this->shareManager->shareProviderExists(Share::SHARE_TYPE_CIRCLE)) { |
|
704 | - $circleShares = $this->shareManager->getSharesBy($this->currentUser, Share::SHARE_TYPE_CIRCLE, $path, $reshares, -1, 0); |
|
705 | - } else { |
|
706 | - $circleShares = []; |
|
707 | - } |
|
708 | - $roomShares = $this->shareManager->getSharesBy($this->currentUser, Share::SHARE_TYPE_ROOM, $path, $reshares, -1, 0); |
|
709 | - |
|
710 | - $shares = array_merge($userShares, $groupShares, $linkShares, $mailShares, $circleShares, $roomShares); |
|
711 | - |
|
712 | - if ($this->shareManager->outgoingServer2ServerSharesAllowed()) { |
|
713 | - $federatedShares = $this->shareManager->getSharesBy($this->currentUser, Share::SHARE_TYPE_REMOTE, $path, $reshares, -1, 0); |
|
714 | - $shares = array_merge($shares, $federatedShares); |
|
715 | - } |
|
716 | - |
|
717 | - if ($this->shareManager->outgoingServer2ServerGroupSharesAllowed()) { |
|
718 | - $federatedShares = $this->shareManager->getSharesBy($this->currentUser, Share::SHARE_TYPE_REMOTE_GROUP, $path, $reshares, -1, 0); |
|
719 | - $shares = array_merge($shares, $federatedShares); |
|
720 | - } |
|
721 | - |
|
722 | - $formatted = []; |
|
723 | - foreach ($shares as $share) { |
|
724 | - try { |
|
725 | - $formatted[] = $this->formatShare($share, $path); |
|
726 | - } catch (NotFoundException $e) { |
|
727 | - //Ignore share |
|
728 | - } |
|
729 | - } |
|
730 | - |
|
731 | - if ($include_tags) { |
|
732 | - $formatted = Helper::populateTags($formatted, 'file_source', \OC::$server->getTagManager()); |
|
733 | - } |
|
734 | - |
|
735 | - return new DataResponse($formatted); |
|
736 | - } |
|
737 | - |
|
738 | - /** |
|
739 | - * @NoAdminRequired |
|
740 | - * |
|
741 | - * @param string $id |
|
742 | - * @param int $permissions |
|
743 | - * @param string $password |
|
744 | - * @param string $sendPasswordByTalk |
|
745 | - * @param string $publicUpload |
|
746 | - * @param string $expireDate |
|
747 | - * @param string $note |
|
748 | - * @return DataResponse |
|
749 | - * @throws LockedException |
|
750 | - * @throws NotFoundException |
|
751 | - * @throws OCSBadRequestException |
|
752 | - * @throws OCSForbiddenException |
|
753 | - * @throws OCSNotFoundException |
|
754 | - */ |
|
755 | - public function updateShare( |
|
756 | - string $id, |
|
757 | - int $permissions = null, |
|
758 | - string $password = null, |
|
759 | - string $sendPasswordByTalk = null, |
|
760 | - string $publicUpload = null, |
|
761 | - string $expireDate = null, |
|
762 | - string $note = null |
|
763 | - ): DataResponse { |
|
764 | - try { |
|
765 | - $share = $this->getShareById($id); |
|
766 | - } catch (ShareNotFound $e) { |
|
767 | - throw new OCSNotFoundException($this->l->t('Wrong share ID, share doesn\'t exist')); |
|
768 | - } |
|
769 | - |
|
770 | - $this->lock($share->getNode()); |
|
771 | - |
|
772 | - if (!$this->canAccessShare($share, false)) { |
|
773 | - throw new OCSNotFoundException($this->l->t('Wrong share ID, share doesn\'t exist')); |
|
774 | - } |
|
775 | - |
|
776 | - if ($permissions === null && $password === null && $sendPasswordByTalk === null && $publicUpload === null && $expireDate === null && $note === null) { |
|
777 | - throw new OCSBadRequestException($this->l->t('Wrong or no update parameter given')); |
|
778 | - } |
|
779 | - |
|
780 | - if($note !== null) { |
|
781 | - $share->setNote($note); |
|
782 | - } |
|
783 | - |
|
784 | - /* |
|
453 | + $existingShares = $this->shareManager->getSharesBy($this->currentUser, Share::SHARE_TYPE_LINK, $path, false, 1, 0); |
|
454 | + if (!empty($existingShares)) { |
|
455 | + return new DataResponse($this->formatShare($existingShares[0])); |
|
456 | + } |
|
457 | + |
|
458 | + if ($publicUpload === 'true') { |
|
459 | + // Check if public upload is allowed |
|
460 | + if (!$this->shareManager->shareApiLinkAllowPublicUpload()) { |
|
461 | + throw new OCSForbiddenException($this->l->t('Public upload disabled by the administrator')); |
|
462 | + } |
|
463 | + |
|
464 | + // Public upload can only be set for folders |
|
465 | + if ($path instanceof \OCP\Files\File) { |
|
466 | + throw new OCSNotFoundException($this->l->t('Public upload is only possible for publicly shared folders')); |
|
467 | + } |
|
468 | + |
|
469 | + $share->setPermissions( |
|
470 | + Constants::PERMISSION_READ | |
|
471 | + Constants::PERMISSION_CREATE | |
|
472 | + Constants::PERMISSION_UPDATE | |
|
473 | + Constants::PERMISSION_DELETE |
|
474 | + ); |
|
475 | + } else { |
|
476 | + $share->setPermissions(Constants::PERMISSION_READ); |
|
477 | + } |
|
478 | + |
|
479 | + // Set password |
|
480 | + if ($password !== '') { |
|
481 | + $share->setPassword($password); |
|
482 | + } |
|
483 | + |
|
484 | + //Expire date |
|
485 | + if ($expireDate !== '') { |
|
486 | + try { |
|
487 | + $expireDate = $this->parseDate($expireDate); |
|
488 | + $share->setExpirationDate($expireDate); |
|
489 | + } catch (\Exception $e) { |
|
490 | + throw new OCSNotFoundException($this->l->t('Invalid date, date format must be YYYY-MM-DD')); |
|
491 | + } |
|
492 | + } |
|
493 | + |
|
494 | + } else if ($shareType === Share::SHARE_TYPE_REMOTE) { |
|
495 | + if (!$this->shareManager->outgoingServer2ServerSharesAllowed()) { |
|
496 | + 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])); |
|
497 | + } |
|
498 | + |
|
499 | + $share->setSharedWith($shareWith); |
|
500 | + $share->setPermissions($permissions); |
|
501 | + } else if ($shareType === Share::SHARE_TYPE_REMOTE_GROUP) { |
|
502 | + if (!$this->shareManager->outgoingServer2ServerGroupSharesAllowed()) { |
|
503 | + 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])); |
|
504 | + } |
|
505 | + |
|
506 | + $share->setSharedWith($shareWith); |
|
507 | + $share->setPermissions($permissions); |
|
508 | + } else if ($shareType === Share::SHARE_TYPE_EMAIL) { |
|
509 | + if ($share->getNodeType() === 'file') { |
|
510 | + $share->setPermissions(Constants::PERMISSION_READ); |
|
511 | + } else { |
|
512 | + $share->setPermissions($permissions); |
|
513 | + } |
|
514 | + $share->setSharedWith($shareWith); |
|
515 | + |
|
516 | + if ($sendPasswordByTalk === 'true') { |
|
517 | + if (!$this->appManager->isEnabledForUser('spreed')) { |
|
518 | + throw new OCSForbiddenException($this->l->t('Sharing %s sending the password by Nextcloud Talk failed because Nextcloud Talk is not enabled', [$path->getPath()])); |
|
519 | + } |
|
520 | + |
|
521 | + $share->setSendPasswordByTalk(true); |
|
522 | + } |
|
523 | + } else if ($shareType === Share::SHARE_TYPE_CIRCLE) { |
|
524 | + if (!\OC::$server->getAppManager()->isEnabledForUser('circles') || !class_exists('\OCA\Circles\ShareByCircleProvider')) { |
|
525 | + throw new OCSNotFoundException($this->l->t('You cannot share to a Circle if the app is not enabled')); |
|
526 | + } |
|
527 | + |
|
528 | + $circle = \OCA\Circles\Api\v1\Circles::detailsCircle($shareWith); |
|
529 | + |
|
530 | + // Valid circle is required to share |
|
531 | + if ($circle === null) { |
|
532 | + throw new OCSNotFoundException($this->l->t('Please specify a valid circle')); |
|
533 | + } |
|
534 | + $share->setSharedWith($shareWith); |
|
535 | + $share->setPermissions($permissions); |
|
536 | + } else if ($shareType === Share::SHARE_TYPE_ROOM) { |
|
537 | + try { |
|
538 | + $this->getRoomShareHelper()->createShare($share, $shareWith, $permissions, $expireDate); |
|
539 | + } catch (QueryException $e) { |
|
540 | + throw new OCSForbiddenException($this->l->t('Sharing %s failed because the back end does not support room shares', [$path->getPath()])); |
|
541 | + } |
|
542 | + } else { |
|
543 | + throw new OCSBadRequestException($this->l->t('Unknown share type')); |
|
544 | + } |
|
545 | + |
|
546 | + $share->setShareType($shareType); |
|
547 | + $share->setSharedBy($this->currentUser); |
|
548 | + |
|
549 | + try { |
|
550 | + $share = $this->shareManager->createShare($share); |
|
551 | + } catch (GenericShareException $e) { |
|
552 | + $code = $e->getCode() === 0 ? 403 : $e->getCode(); |
|
553 | + throw new OCSException($e->getHint(), $code); |
|
554 | + } catch (\Exception $e) { |
|
555 | + throw new OCSForbiddenException($e->getMessage(), $e); |
|
556 | + } |
|
557 | + |
|
558 | + $output = $this->formatShare($share); |
|
559 | + |
|
560 | + return new DataResponse($output); |
|
561 | + } |
|
562 | + |
|
563 | + /** |
|
564 | + * @param \OCP\Files\File|\OCP\Files\Folder $node |
|
565 | + * @param boolean $includeTags |
|
566 | + * @return DataResponse |
|
567 | + */ |
|
568 | + private function getSharedWithMe($node = null, bool $includeTags): DataResponse { |
|
569 | + |
|
570 | + $userShares = $this->shareManager->getSharedWith($this->currentUser, Share::SHARE_TYPE_USER, $node, -1, 0); |
|
571 | + $groupShares = $this->shareManager->getSharedWith($this->currentUser, Share::SHARE_TYPE_GROUP, $node, -1, 0); |
|
572 | + $circleShares = $this->shareManager->getSharedWith($this->currentUser, Share::SHARE_TYPE_CIRCLE, $node, -1, 0); |
|
573 | + $roomShares = $this->shareManager->getSharedWith($this->currentUser, Share::SHARE_TYPE_ROOM, $node, -1, 0); |
|
574 | + |
|
575 | + $shares = array_merge($userShares, $groupShares, $circleShares, $roomShares); |
|
576 | + |
|
577 | + $shares = array_filter($shares, function (IShare $share) { |
|
578 | + return $share->getShareOwner() !== $this->currentUser; |
|
579 | + }); |
|
580 | + |
|
581 | + $formatted = []; |
|
582 | + foreach ($shares as $share) { |
|
583 | + if ($this->canAccessShare($share)) { |
|
584 | + try { |
|
585 | + $formatted[] = $this->formatShare($share); |
|
586 | + } catch (NotFoundException $e) { |
|
587 | + // Ignore this share |
|
588 | + } |
|
589 | + } |
|
590 | + } |
|
591 | + |
|
592 | + if ($includeTags) { |
|
593 | + $formatted = Helper::populateTags($formatted, 'file_source', \OC::$server->getTagManager()); |
|
594 | + } |
|
595 | + |
|
596 | + return new DataResponse($formatted); |
|
597 | + } |
|
598 | + |
|
599 | + /** |
|
600 | + * @param \OCP\Files\Folder $folder |
|
601 | + * @return DataResponse |
|
602 | + * @throws OCSBadRequestException |
|
603 | + */ |
|
604 | + private function getSharesInDir(Node $folder): DataResponse { |
|
605 | + if (!($folder instanceof \OCP\Files\Folder)) { |
|
606 | + throw new OCSBadRequestException($this->l->t('Not a directory')); |
|
607 | + } |
|
608 | + |
|
609 | + $nodes = $folder->getDirectoryListing(); |
|
610 | + /** @var \OCP\Share\IShare[] $shares */ |
|
611 | + $shares = []; |
|
612 | + foreach ($nodes as $node) { |
|
613 | + $shares = array_merge($shares, $this->shareManager->getSharesBy($this->currentUser, Share::SHARE_TYPE_USER, $node, false, -1, 0)); |
|
614 | + $shares = array_merge($shares, $this->shareManager->getSharesBy($this->currentUser, Share::SHARE_TYPE_GROUP, $node, false, -1, 0)); |
|
615 | + $shares = array_merge($shares, $this->shareManager->getSharesBy($this->currentUser, Share::SHARE_TYPE_LINK, $node, false, -1, 0)); |
|
616 | + if($this->shareManager->shareProviderExists(Share::SHARE_TYPE_EMAIL)) { |
|
617 | + $shares = array_merge($shares, $this->shareManager->getSharesBy($this->currentUser, Share::SHARE_TYPE_EMAIL, $node, false, -1, 0)); |
|
618 | + } |
|
619 | + if ($this->shareManager->outgoingServer2ServerSharesAllowed()) { |
|
620 | + $shares = array_merge($shares, $this->shareManager->getSharesBy($this->currentUser, Share::SHARE_TYPE_REMOTE, $node, false, -1, 0)); |
|
621 | + } |
|
622 | + $shares = array_merge($shares, $this->shareManager->getSharesBy($this->currentUser, Share::SHARE_TYPE_ROOM, $node, false, -1, 0)); |
|
623 | + } |
|
624 | + |
|
625 | + $formatted = []; |
|
626 | + foreach ($shares as $share) { |
|
627 | + try { |
|
628 | + $formatted[] = $this->formatShare($share); |
|
629 | + } catch (NotFoundException $e) { |
|
630 | + //Ignore this share |
|
631 | + } |
|
632 | + } |
|
633 | + |
|
634 | + return new DataResponse($formatted); |
|
635 | + } |
|
636 | + |
|
637 | + /** |
|
638 | + * The getShares function. |
|
639 | + * |
|
640 | + * @NoAdminRequired |
|
641 | + * |
|
642 | + * @param string $shared_with_me |
|
643 | + * @param string $reshares |
|
644 | + * @param string $subfiles |
|
645 | + * @param string $path |
|
646 | + * |
|
647 | + * - Get shares by the current user |
|
648 | + * - Get shares by the current user and reshares (?reshares=true) |
|
649 | + * - Get shares with the current user (?shared_with_me=true) |
|
650 | + * - Get shares for a specific path (?path=...) |
|
651 | + * - Get all shares in a folder (?subfiles=true&path=..) |
|
652 | + * |
|
653 | + * @return DataResponse |
|
654 | + * @throws OCSNotFoundException |
|
655 | + */ |
|
656 | + public function getShares( |
|
657 | + string $shared_with_me = 'false', |
|
658 | + string $reshares = 'false', |
|
659 | + string $subfiles = 'false', |
|
660 | + string $path = null, |
|
661 | + string $include_tags = 'false' |
|
662 | + ): DataResponse { |
|
663 | + |
|
664 | + if ($path !== null) { |
|
665 | + $userFolder = $this->rootFolder->getUserFolder($this->currentUser); |
|
666 | + try { |
|
667 | + $path = $userFolder->get($path); |
|
668 | + $this->lock($path); |
|
669 | + } catch (\OCP\Files\NotFoundException $e) { |
|
670 | + throw new OCSNotFoundException($this->l->t('Wrong path, file/folder doesn\'t exist')); |
|
671 | + } catch (LockedException $e) { |
|
672 | + throw new OCSNotFoundException($this->l->t('Could not lock path')); |
|
673 | + } |
|
674 | + } |
|
675 | + |
|
676 | + $include_tags = $include_tags === 'true'; |
|
677 | + |
|
678 | + if ($shared_with_me === 'true') { |
|
679 | + $result = $this->getSharedWithMe($path, $include_tags); |
|
680 | + return $result; |
|
681 | + } |
|
682 | + |
|
683 | + if ($subfiles === 'true') { |
|
684 | + $result = $this->getSharesInDir($path); |
|
685 | + return $result; |
|
686 | + } |
|
687 | + |
|
688 | + if ($reshares === 'true') { |
|
689 | + $reshares = true; |
|
690 | + } else { |
|
691 | + $reshares = false; |
|
692 | + } |
|
693 | + |
|
694 | + // Get all shares |
|
695 | + $userShares = $this->shareManager->getSharesBy($this->currentUser, Share::SHARE_TYPE_USER, $path, $reshares, -1, 0); |
|
696 | + $groupShares = $this->shareManager->getSharesBy($this->currentUser, Share::SHARE_TYPE_GROUP, $path, $reshares, -1, 0); |
|
697 | + $linkShares = $this->shareManager->getSharesBy($this->currentUser, Share::SHARE_TYPE_LINK, $path, $reshares, -1, 0); |
|
698 | + if ($this->shareManager->shareProviderExists(Share::SHARE_TYPE_EMAIL)) { |
|
699 | + $mailShares = $this->shareManager->getSharesBy($this->currentUser, Share::SHARE_TYPE_EMAIL, $path, $reshares, -1, 0); |
|
700 | + } else { |
|
701 | + $mailShares = []; |
|
702 | + } |
|
703 | + if ($this->shareManager->shareProviderExists(Share::SHARE_TYPE_CIRCLE)) { |
|
704 | + $circleShares = $this->shareManager->getSharesBy($this->currentUser, Share::SHARE_TYPE_CIRCLE, $path, $reshares, -1, 0); |
|
705 | + } else { |
|
706 | + $circleShares = []; |
|
707 | + } |
|
708 | + $roomShares = $this->shareManager->getSharesBy($this->currentUser, Share::SHARE_TYPE_ROOM, $path, $reshares, -1, 0); |
|
709 | + |
|
710 | + $shares = array_merge($userShares, $groupShares, $linkShares, $mailShares, $circleShares, $roomShares); |
|
711 | + |
|
712 | + if ($this->shareManager->outgoingServer2ServerSharesAllowed()) { |
|
713 | + $federatedShares = $this->shareManager->getSharesBy($this->currentUser, Share::SHARE_TYPE_REMOTE, $path, $reshares, -1, 0); |
|
714 | + $shares = array_merge($shares, $federatedShares); |
|
715 | + } |
|
716 | + |
|
717 | + if ($this->shareManager->outgoingServer2ServerGroupSharesAllowed()) { |
|
718 | + $federatedShares = $this->shareManager->getSharesBy($this->currentUser, Share::SHARE_TYPE_REMOTE_GROUP, $path, $reshares, -1, 0); |
|
719 | + $shares = array_merge($shares, $federatedShares); |
|
720 | + } |
|
721 | + |
|
722 | + $formatted = []; |
|
723 | + foreach ($shares as $share) { |
|
724 | + try { |
|
725 | + $formatted[] = $this->formatShare($share, $path); |
|
726 | + } catch (NotFoundException $e) { |
|
727 | + //Ignore share |
|
728 | + } |
|
729 | + } |
|
730 | + |
|
731 | + if ($include_tags) { |
|
732 | + $formatted = Helper::populateTags($formatted, 'file_source', \OC::$server->getTagManager()); |
|
733 | + } |
|
734 | + |
|
735 | + return new DataResponse($formatted); |
|
736 | + } |
|
737 | + |
|
738 | + /** |
|
739 | + * @NoAdminRequired |
|
740 | + * |
|
741 | + * @param string $id |
|
742 | + * @param int $permissions |
|
743 | + * @param string $password |
|
744 | + * @param string $sendPasswordByTalk |
|
745 | + * @param string $publicUpload |
|
746 | + * @param string $expireDate |
|
747 | + * @param string $note |
|
748 | + * @return DataResponse |
|
749 | + * @throws LockedException |
|
750 | + * @throws NotFoundException |
|
751 | + * @throws OCSBadRequestException |
|
752 | + * @throws OCSForbiddenException |
|
753 | + * @throws OCSNotFoundException |
|
754 | + */ |
|
755 | + public function updateShare( |
|
756 | + string $id, |
|
757 | + int $permissions = null, |
|
758 | + string $password = null, |
|
759 | + string $sendPasswordByTalk = null, |
|
760 | + string $publicUpload = null, |
|
761 | + string $expireDate = null, |
|
762 | + string $note = null |
|
763 | + ): DataResponse { |
|
764 | + try { |
|
765 | + $share = $this->getShareById($id); |
|
766 | + } catch (ShareNotFound $e) { |
|
767 | + throw new OCSNotFoundException($this->l->t('Wrong share ID, share doesn\'t exist')); |
|
768 | + } |
|
769 | + |
|
770 | + $this->lock($share->getNode()); |
|
771 | + |
|
772 | + if (!$this->canAccessShare($share, false)) { |
|
773 | + throw new OCSNotFoundException($this->l->t('Wrong share ID, share doesn\'t exist')); |
|
774 | + } |
|
775 | + |
|
776 | + if ($permissions === null && $password === null && $sendPasswordByTalk === null && $publicUpload === null && $expireDate === null && $note === null) { |
|
777 | + throw new OCSBadRequestException($this->l->t('Wrong or no update parameter given')); |
|
778 | + } |
|
779 | + |
|
780 | + if($note !== null) { |
|
781 | + $share->setNote($note); |
|
782 | + } |
|
783 | + |
|
784 | + /* |
|
785 | 785 | * expirationdate, password and publicUpload only make sense for link shares |
786 | 786 | */ |
787 | - if ($share->getShareType() === Share::SHARE_TYPE_LINK) { |
|
788 | - |
|
789 | - $newPermissions = null; |
|
790 | - if ($publicUpload === 'true') { |
|
791 | - $newPermissions = Constants::PERMISSION_READ | Constants::PERMISSION_CREATE | Constants::PERMISSION_UPDATE | Constants::PERMISSION_DELETE; |
|
792 | - } else if ($publicUpload === 'false') { |
|
793 | - $newPermissions = Constants::PERMISSION_READ; |
|
794 | - } |
|
795 | - |
|
796 | - if ($permissions !== null) { |
|
797 | - $newPermissions = (int)$permissions; |
|
798 | - $newPermissions = $newPermissions & ~Constants::PERMISSION_SHARE; |
|
799 | - } |
|
800 | - |
|
801 | - if ($newPermissions !== null && |
|
802 | - !in_array($newPermissions, [ |
|
803 | - Constants::PERMISSION_READ, |
|
804 | - Constants::PERMISSION_READ | Constants::PERMISSION_CREATE | Constants::PERMISSION_UPDATE, // legacy |
|
805 | - Constants::PERMISSION_READ | Constants::PERMISSION_CREATE | Constants::PERMISSION_UPDATE | Constants::PERMISSION_DELETE, // correct |
|
806 | - Constants::PERMISSION_CREATE, // hidden file list |
|
807 | - Constants::PERMISSION_READ | Constants::PERMISSION_UPDATE, // allow to edit single files |
|
808 | - ], true) |
|
809 | - ) { |
|
810 | - throw new OCSBadRequestException($this->l->t('Can\'t change permissions for public share links')); |
|
811 | - } |
|
812 | - |
|
813 | - if ( |
|
814 | - // legacy |
|
815 | - $newPermissions === (Constants::PERMISSION_READ | Constants::PERMISSION_CREATE | Constants::PERMISSION_UPDATE) || |
|
816 | - // correct |
|
817 | - $newPermissions === (Constants::PERMISSION_READ | Constants::PERMISSION_CREATE | Constants::PERMISSION_UPDATE | Constants::PERMISSION_DELETE) |
|
818 | - ) { |
|
819 | - if (!$this->shareManager->shareApiLinkAllowPublicUpload()) { |
|
820 | - throw new OCSForbiddenException($this->l->t('Public upload disabled by the administrator')); |
|
821 | - } |
|
822 | - |
|
823 | - if (!($share->getNode() instanceof \OCP\Files\Folder)) { |
|
824 | - throw new OCSBadRequestException($this->l->t('Public upload is only possible for publicly shared folders')); |
|
825 | - } |
|
826 | - |
|
827 | - // normalize to correct public upload permissions |
|
828 | - $newPermissions = Constants::PERMISSION_READ | Constants::PERMISSION_CREATE | Constants::PERMISSION_UPDATE | Constants::PERMISSION_DELETE; |
|
829 | - } |
|
830 | - |
|
831 | - if ($newPermissions !== null) { |
|
832 | - $share->setPermissions($newPermissions); |
|
833 | - $permissions = $newPermissions; |
|
834 | - } |
|
835 | - |
|
836 | - if ($expireDate === '') { |
|
837 | - $share->setExpirationDate(null); |
|
838 | - } else if ($expireDate !== null) { |
|
839 | - try { |
|
840 | - $expireDate = $this->parseDate($expireDate); |
|
841 | - } catch (\Exception $e) { |
|
842 | - throw new OCSBadRequestException($e->getMessage(), $e); |
|
843 | - } |
|
844 | - $share->setExpirationDate($expireDate); |
|
845 | - } |
|
846 | - |
|
847 | - if ($password === '') { |
|
848 | - $share->setPassword(null); |
|
849 | - } else if ($password !== null) { |
|
850 | - $share->setPassword($password); |
|
851 | - } |
|
852 | - |
|
853 | - } else { |
|
854 | - if ($permissions !== null) { |
|
855 | - $permissions = (int)$permissions; |
|
856 | - $share->setPermissions($permissions); |
|
857 | - } |
|
858 | - |
|
859 | - if ($share->getShareType() === Share::SHARE_TYPE_EMAIL) { |
|
860 | - if ($password === '') { |
|
861 | - $share->setPassword(null); |
|
862 | - } else if ($password !== null) { |
|
863 | - $share->setPassword($password); |
|
864 | - } |
|
865 | - |
|
866 | - if ($sendPasswordByTalk === 'true') { |
|
867 | - if (!$this->appManager->isEnabledForUser('spreed')) { |
|
868 | - throw new OCSForbiddenException($this->l->t('Sharing sending the password by Nextcloud Talk failed because Nextcloud Talk is not enabled')); |
|
869 | - } |
|
870 | - |
|
871 | - $share->setSendPasswordByTalk(true); |
|
872 | - } else { |
|
873 | - $share->setSendPasswordByTalk(false); |
|
874 | - } |
|
875 | - } |
|
876 | - |
|
877 | - if ($expireDate === '') { |
|
878 | - $share->setExpirationDate(null); |
|
879 | - } else if ($expireDate !== null) { |
|
880 | - try { |
|
881 | - $expireDate = $this->parseDate($expireDate); |
|
882 | - } catch (\Exception $e) { |
|
883 | - throw new OCSBadRequestException($e->getMessage(), $e); |
|
884 | - } |
|
885 | - $share->setExpirationDate($expireDate); |
|
886 | - } |
|
887 | - |
|
888 | - } |
|
889 | - |
|
890 | - if ($permissions !== null && $share->getShareOwner() !== $this->currentUser) { |
|
891 | - /* Check if this is an incomming share */ |
|
892 | - $incomingShares = $this->shareManager->getSharedWith($this->currentUser, Share::SHARE_TYPE_USER, $share->getNode(), -1, 0); |
|
893 | - $incomingShares = array_merge($incomingShares, $this->shareManager->getSharedWith($this->currentUser, Share::SHARE_TYPE_GROUP, $share->getNode(), -1, 0)); |
|
894 | - $incomingShares = array_merge($incomingShares, $this->shareManager->getSharedWith($this->currentUser, Share::SHARE_TYPE_ROOM, $share->getNode(), -1, 0)); |
|
895 | - |
|
896 | - /** @var \OCP\Share\IShare[] $incomingShares */ |
|
897 | - if (!empty($incomingShares)) { |
|
898 | - $maxPermissions = 0; |
|
899 | - foreach ($incomingShares as $incomingShare) { |
|
900 | - $maxPermissions |= $incomingShare->getPermissions(); |
|
901 | - } |
|
902 | - |
|
903 | - if ($share->getPermissions() & ~$maxPermissions) { |
|
904 | - throw new OCSNotFoundException($this->l->t('Cannot increase permissions')); |
|
905 | - } |
|
906 | - } |
|
907 | - } |
|
908 | - |
|
909 | - |
|
910 | - try { |
|
911 | - $share = $this->shareManager->updateShare($share); |
|
912 | - } catch (\Exception $e) { |
|
913 | - throw new OCSBadRequestException($e->getMessage(), $e); |
|
914 | - } |
|
915 | - |
|
916 | - return new DataResponse($this->formatShare($share)); |
|
917 | - } |
|
918 | - |
|
919 | - /** |
|
920 | - * @suppress PhanUndeclaredClassMethod |
|
921 | - */ |
|
922 | - protected function canAccessShare(\OCP\Share\IShare $share, bool $checkGroups = true): bool { |
|
923 | - // A file with permissions 0 can't be accessed by us. So Don't show it |
|
924 | - if ($share->getPermissions() === 0) { |
|
925 | - return false; |
|
926 | - } |
|
927 | - |
|
928 | - // Owner of the file and the sharer of the file can always get share |
|
929 | - if ($share->getShareOwner() === $this->currentUser || |
|
930 | - $share->getSharedBy() === $this->currentUser |
|
931 | - ) { |
|
932 | - return true; |
|
933 | - } |
|
934 | - |
|
935 | - // If the share is shared with you (or a group you are a member of) |
|
936 | - if ($share->getShareType() === Share::SHARE_TYPE_USER && |
|
937 | - $share->getSharedWith() === $this->currentUser |
|
938 | - ) { |
|
939 | - return true; |
|
940 | - } |
|
941 | - |
|
942 | - if ($checkGroups && $share->getShareType() === Share::SHARE_TYPE_GROUP) { |
|
943 | - $sharedWith = $this->groupManager->get($share->getSharedWith()); |
|
944 | - $user = $this->userManager->get($this->currentUser); |
|
945 | - if ($user !== null && $sharedWith !== null && $sharedWith->inGroup($user)) { |
|
946 | - return true; |
|
947 | - } |
|
948 | - } |
|
949 | - |
|
950 | - if ($share->getShareType() === Share::SHARE_TYPE_CIRCLE) { |
|
951 | - // TODO: have a sanity check like above? |
|
952 | - return true; |
|
953 | - } |
|
954 | - |
|
955 | - if ($share->getShareType() === Share::SHARE_TYPE_ROOM) { |
|
956 | - try { |
|
957 | - return $this->getRoomShareHelper()->canAccessShare($share, $this->currentUser); |
|
958 | - } catch (QueryException $e) { |
|
959 | - return false; |
|
960 | - } |
|
961 | - } |
|
962 | - |
|
963 | - return false; |
|
964 | - } |
|
965 | - |
|
966 | - /** |
|
967 | - * Make sure that the passed date is valid ISO 8601 |
|
968 | - * So YYYY-MM-DD |
|
969 | - * If not throw an exception |
|
970 | - * |
|
971 | - * @param string $expireDate |
|
972 | - * |
|
973 | - * @throws \Exception |
|
974 | - * @return \DateTime |
|
975 | - */ |
|
976 | - private function parseDate(string $expireDate): \DateTime { |
|
977 | - try { |
|
978 | - $date = new \DateTime($expireDate); |
|
979 | - } catch (\Exception $e) { |
|
980 | - throw new \Exception('Invalid date. Format must be YYYY-MM-DD'); |
|
981 | - } |
|
982 | - |
|
983 | - if ($date === false) { |
|
984 | - throw new \Exception('Invalid date. Format must be YYYY-MM-DD'); |
|
985 | - } |
|
986 | - |
|
987 | - $date->setTime(0, 0, 0); |
|
988 | - |
|
989 | - return $date; |
|
990 | - } |
|
991 | - |
|
992 | - /** |
|
993 | - * Since we have multiple providers but the OCS Share API v1 does |
|
994 | - * not support this we need to check all backends. |
|
995 | - * |
|
996 | - * @param string $id |
|
997 | - * @return \OCP\Share\IShare |
|
998 | - * @throws ShareNotFound |
|
999 | - */ |
|
1000 | - private function getShareById(string $id): IShare { |
|
1001 | - $share = null; |
|
1002 | - |
|
1003 | - // First check if it is an internal share. |
|
1004 | - try { |
|
1005 | - $share = $this->shareManager->getShareById('ocinternal:' . $id, $this->currentUser); |
|
1006 | - return $share; |
|
1007 | - } catch (ShareNotFound $e) { |
|
1008 | - // Do nothing, just try the other share type |
|
1009 | - } |
|
1010 | - |
|
1011 | - |
|
1012 | - try { |
|
1013 | - if ($this->shareManager->shareProviderExists(Share::SHARE_TYPE_CIRCLE)) { |
|
1014 | - $share = $this->shareManager->getShareById('ocCircleShare:' . $id, $this->currentUser); |
|
1015 | - return $share; |
|
1016 | - } |
|
1017 | - } catch (ShareNotFound $e) { |
|
1018 | - // Do nothing, just try the other share type |
|
1019 | - } |
|
1020 | - |
|
1021 | - try { |
|
1022 | - if ($this->shareManager->shareProviderExists(Share::SHARE_TYPE_EMAIL)) { |
|
1023 | - $share = $this->shareManager->getShareById('ocMailShare:' . $id, $this->currentUser); |
|
1024 | - return $share; |
|
1025 | - } |
|
1026 | - } catch (ShareNotFound $e) { |
|
1027 | - // Do nothing, just try the other share type |
|
1028 | - } |
|
1029 | - |
|
1030 | - try { |
|
1031 | - $share = $this->shareManager->getShareById('ocRoomShare:' . $id, $this->currentUser); |
|
1032 | - return $share; |
|
1033 | - } catch (ShareNotFound $e) { |
|
1034 | - // Do nothing, just try the other share type |
|
1035 | - } |
|
1036 | - |
|
1037 | - if (!$this->shareManager->outgoingServer2ServerSharesAllowed()) { |
|
1038 | - throw new ShareNotFound(); |
|
1039 | - } |
|
1040 | - $share = $this->shareManager->getShareById('ocFederatedSharing:' . $id, $this->currentUser); |
|
1041 | - |
|
1042 | - return $share; |
|
1043 | - } |
|
1044 | - |
|
1045 | - /** |
|
1046 | - * Lock a Node |
|
1047 | - * |
|
1048 | - * @param \OCP\Files\Node $node |
|
1049 | - * @throws LockedException |
|
1050 | - */ |
|
1051 | - private function lock(\OCP\Files\Node $node) { |
|
1052 | - $node->lock(ILockingProvider::LOCK_SHARED); |
|
1053 | - $this->lockedNode = $node; |
|
1054 | - } |
|
1055 | - |
|
1056 | - /** |
|
1057 | - * Cleanup the remaining locks |
|
1058 | - * @throws @LockedException |
|
1059 | - */ |
|
1060 | - public function cleanup() { |
|
1061 | - if ($this->lockedNode !== null) { |
|
1062 | - $this->lockedNode->unlock(ILockingProvider::LOCK_SHARED); |
|
1063 | - } |
|
1064 | - } |
|
1065 | - |
|
1066 | - /** |
|
1067 | - * Returns the helper of ShareAPIController for room shares. |
|
1068 | - * |
|
1069 | - * If the Talk application is not enabled or the helper is not available |
|
1070 | - * a QueryException is thrown instead. |
|
1071 | - * |
|
1072 | - * @return \OCA\Spreed\Share\Helper\ShareAPIController |
|
1073 | - * @throws QueryException |
|
1074 | - */ |
|
1075 | - private function getRoomShareHelper() { |
|
1076 | - if (!$this->appManager->isEnabledForUser('spreed')) { |
|
1077 | - throw new QueryException(); |
|
1078 | - } |
|
1079 | - |
|
1080 | - return $this->serverContainer->query('\OCA\Spreed\Share\Helper\ShareAPIController'); |
|
1081 | - } |
|
787 | + if ($share->getShareType() === Share::SHARE_TYPE_LINK) { |
|
788 | + |
|
789 | + $newPermissions = null; |
|
790 | + if ($publicUpload === 'true') { |
|
791 | + $newPermissions = Constants::PERMISSION_READ | Constants::PERMISSION_CREATE | Constants::PERMISSION_UPDATE | Constants::PERMISSION_DELETE; |
|
792 | + } else if ($publicUpload === 'false') { |
|
793 | + $newPermissions = Constants::PERMISSION_READ; |
|
794 | + } |
|
795 | + |
|
796 | + if ($permissions !== null) { |
|
797 | + $newPermissions = (int)$permissions; |
|
798 | + $newPermissions = $newPermissions & ~Constants::PERMISSION_SHARE; |
|
799 | + } |
|
800 | + |
|
801 | + if ($newPermissions !== null && |
|
802 | + !in_array($newPermissions, [ |
|
803 | + Constants::PERMISSION_READ, |
|
804 | + Constants::PERMISSION_READ | Constants::PERMISSION_CREATE | Constants::PERMISSION_UPDATE, // legacy |
|
805 | + Constants::PERMISSION_READ | Constants::PERMISSION_CREATE | Constants::PERMISSION_UPDATE | Constants::PERMISSION_DELETE, // correct |
|
806 | + Constants::PERMISSION_CREATE, // hidden file list |
|
807 | + Constants::PERMISSION_READ | Constants::PERMISSION_UPDATE, // allow to edit single files |
|
808 | + ], true) |
|
809 | + ) { |
|
810 | + throw new OCSBadRequestException($this->l->t('Can\'t change permissions for public share links')); |
|
811 | + } |
|
812 | + |
|
813 | + if ( |
|
814 | + // legacy |
|
815 | + $newPermissions === (Constants::PERMISSION_READ | Constants::PERMISSION_CREATE | Constants::PERMISSION_UPDATE) || |
|
816 | + // correct |
|
817 | + $newPermissions === (Constants::PERMISSION_READ | Constants::PERMISSION_CREATE | Constants::PERMISSION_UPDATE | Constants::PERMISSION_DELETE) |
|
818 | + ) { |
|
819 | + if (!$this->shareManager->shareApiLinkAllowPublicUpload()) { |
|
820 | + throw new OCSForbiddenException($this->l->t('Public upload disabled by the administrator')); |
|
821 | + } |
|
822 | + |
|
823 | + if (!($share->getNode() instanceof \OCP\Files\Folder)) { |
|
824 | + throw new OCSBadRequestException($this->l->t('Public upload is only possible for publicly shared folders')); |
|
825 | + } |
|
826 | + |
|
827 | + // normalize to correct public upload permissions |
|
828 | + $newPermissions = Constants::PERMISSION_READ | Constants::PERMISSION_CREATE | Constants::PERMISSION_UPDATE | Constants::PERMISSION_DELETE; |
|
829 | + } |
|
830 | + |
|
831 | + if ($newPermissions !== null) { |
|
832 | + $share->setPermissions($newPermissions); |
|
833 | + $permissions = $newPermissions; |
|
834 | + } |
|
835 | + |
|
836 | + if ($expireDate === '') { |
|
837 | + $share->setExpirationDate(null); |
|
838 | + } else if ($expireDate !== null) { |
|
839 | + try { |
|
840 | + $expireDate = $this->parseDate($expireDate); |
|
841 | + } catch (\Exception $e) { |
|
842 | + throw new OCSBadRequestException($e->getMessage(), $e); |
|
843 | + } |
|
844 | + $share->setExpirationDate($expireDate); |
|
845 | + } |
|
846 | + |
|
847 | + if ($password === '') { |
|
848 | + $share->setPassword(null); |
|
849 | + } else if ($password !== null) { |
|
850 | + $share->setPassword($password); |
|
851 | + } |
|
852 | + |
|
853 | + } else { |
|
854 | + if ($permissions !== null) { |
|
855 | + $permissions = (int)$permissions; |
|
856 | + $share->setPermissions($permissions); |
|
857 | + } |
|
858 | + |
|
859 | + if ($share->getShareType() === Share::SHARE_TYPE_EMAIL) { |
|
860 | + if ($password === '') { |
|
861 | + $share->setPassword(null); |
|
862 | + } else if ($password !== null) { |
|
863 | + $share->setPassword($password); |
|
864 | + } |
|
865 | + |
|
866 | + if ($sendPasswordByTalk === 'true') { |
|
867 | + if (!$this->appManager->isEnabledForUser('spreed')) { |
|
868 | + throw new OCSForbiddenException($this->l->t('Sharing sending the password by Nextcloud Talk failed because Nextcloud Talk is not enabled')); |
|
869 | + } |
|
870 | + |
|
871 | + $share->setSendPasswordByTalk(true); |
|
872 | + } else { |
|
873 | + $share->setSendPasswordByTalk(false); |
|
874 | + } |
|
875 | + } |
|
876 | + |
|
877 | + if ($expireDate === '') { |
|
878 | + $share->setExpirationDate(null); |
|
879 | + } else if ($expireDate !== null) { |
|
880 | + try { |
|
881 | + $expireDate = $this->parseDate($expireDate); |
|
882 | + } catch (\Exception $e) { |
|
883 | + throw new OCSBadRequestException($e->getMessage(), $e); |
|
884 | + } |
|
885 | + $share->setExpirationDate($expireDate); |
|
886 | + } |
|
887 | + |
|
888 | + } |
|
889 | + |
|
890 | + if ($permissions !== null && $share->getShareOwner() !== $this->currentUser) { |
|
891 | + /* Check if this is an incomming share */ |
|
892 | + $incomingShares = $this->shareManager->getSharedWith($this->currentUser, Share::SHARE_TYPE_USER, $share->getNode(), -1, 0); |
|
893 | + $incomingShares = array_merge($incomingShares, $this->shareManager->getSharedWith($this->currentUser, Share::SHARE_TYPE_GROUP, $share->getNode(), -1, 0)); |
|
894 | + $incomingShares = array_merge($incomingShares, $this->shareManager->getSharedWith($this->currentUser, Share::SHARE_TYPE_ROOM, $share->getNode(), -1, 0)); |
|
895 | + |
|
896 | + /** @var \OCP\Share\IShare[] $incomingShares */ |
|
897 | + if (!empty($incomingShares)) { |
|
898 | + $maxPermissions = 0; |
|
899 | + foreach ($incomingShares as $incomingShare) { |
|
900 | + $maxPermissions |= $incomingShare->getPermissions(); |
|
901 | + } |
|
902 | + |
|
903 | + if ($share->getPermissions() & ~$maxPermissions) { |
|
904 | + throw new OCSNotFoundException($this->l->t('Cannot increase permissions')); |
|
905 | + } |
|
906 | + } |
|
907 | + } |
|
908 | + |
|
909 | + |
|
910 | + try { |
|
911 | + $share = $this->shareManager->updateShare($share); |
|
912 | + } catch (\Exception $e) { |
|
913 | + throw new OCSBadRequestException($e->getMessage(), $e); |
|
914 | + } |
|
915 | + |
|
916 | + return new DataResponse($this->formatShare($share)); |
|
917 | + } |
|
918 | + |
|
919 | + /** |
|
920 | + * @suppress PhanUndeclaredClassMethod |
|
921 | + */ |
|
922 | + protected function canAccessShare(\OCP\Share\IShare $share, bool $checkGroups = true): bool { |
|
923 | + // A file with permissions 0 can't be accessed by us. So Don't show it |
|
924 | + if ($share->getPermissions() === 0) { |
|
925 | + return false; |
|
926 | + } |
|
927 | + |
|
928 | + // Owner of the file and the sharer of the file can always get share |
|
929 | + if ($share->getShareOwner() === $this->currentUser || |
|
930 | + $share->getSharedBy() === $this->currentUser |
|
931 | + ) { |
|
932 | + return true; |
|
933 | + } |
|
934 | + |
|
935 | + // If the share is shared with you (or a group you are a member of) |
|
936 | + if ($share->getShareType() === Share::SHARE_TYPE_USER && |
|
937 | + $share->getSharedWith() === $this->currentUser |
|
938 | + ) { |
|
939 | + return true; |
|
940 | + } |
|
941 | + |
|
942 | + if ($checkGroups && $share->getShareType() === Share::SHARE_TYPE_GROUP) { |
|
943 | + $sharedWith = $this->groupManager->get($share->getSharedWith()); |
|
944 | + $user = $this->userManager->get($this->currentUser); |
|
945 | + if ($user !== null && $sharedWith !== null && $sharedWith->inGroup($user)) { |
|
946 | + return true; |
|
947 | + } |
|
948 | + } |
|
949 | + |
|
950 | + if ($share->getShareType() === Share::SHARE_TYPE_CIRCLE) { |
|
951 | + // TODO: have a sanity check like above? |
|
952 | + return true; |
|
953 | + } |
|
954 | + |
|
955 | + if ($share->getShareType() === Share::SHARE_TYPE_ROOM) { |
|
956 | + try { |
|
957 | + return $this->getRoomShareHelper()->canAccessShare($share, $this->currentUser); |
|
958 | + } catch (QueryException $e) { |
|
959 | + return false; |
|
960 | + } |
|
961 | + } |
|
962 | + |
|
963 | + return false; |
|
964 | + } |
|
965 | + |
|
966 | + /** |
|
967 | + * Make sure that the passed date is valid ISO 8601 |
|
968 | + * So YYYY-MM-DD |
|
969 | + * If not throw an exception |
|
970 | + * |
|
971 | + * @param string $expireDate |
|
972 | + * |
|
973 | + * @throws \Exception |
|
974 | + * @return \DateTime |
|
975 | + */ |
|
976 | + private function parseDate(string $expireDate): \DateTime { |
|
977 | + try { |
|
978 | + $date = new \DateTime($expireDate); |
|
979 | + } catch (\Exception $e) { |
|
980 | + throw new \Exception('Invalid date. Format must be YYYY-MM-DD'); |
|
981 | + } |
|
982 | + |
|
983 | + if ($date === false) { |
|
984 | + throw new \Exception('Invalid date. Format must be YYYY-MM-DD'); |
|
985 | + } |
|
986 | + |
|
987 | + $date->setTime(0, 0, 0); |
|
988 | + |
|
989 | + return $date; |
|
990 | + } |
|
991 | + |
|
992 | + /** |
|
993 | + * Since we have multiple providers but the OCS Share API v1 does |
|
994 | + * not support this we need to check all backends. |
|
995 | + * |
|
996 | + * @param string $id |
|
997 | + * @return \OCP\Share\IShare |
|
998 | + * @throws ShareNotFound |
|
999 | + */ |
|
1000 | + private function getShareById(string $id): IShare { |
|
1001 | + $share = null; |
|
1002 | + |
|
1003 | + // First check if it is an internal share. |
|
1004 | + try { |
|
1005 | + $share = $this->shareManager->getShareById('ocinternal:' . $id, $this->currentUser); |
|
1006 | + return $share; |
|
1007 | + } catch (ShareNotFound $e) { |
|
1008 | + // Do nothing, just try the other share type |
|
1009 | + } |
|
1010 | + |
|
1011 | + |
|
1012 | + try { |
|
1013 | + if ($this->shareManager->shareProviderExists(Share::SHARE_TYPE_CIRCLE)) { |
|
1014 | + $share = $this->shareManager->getShareById('ocCircleShare:' . $id, $this->currentUser); |
|
1015 | + return $share; |
|
1016 | + } |
|
1017 | + } catch (ShareNotFound $e) { |
|
1018 | + // Do nothing, just try the other share type |
|
1019 | + } |
|
1020 | + |
|
1021 | + try { |
|
1022 | + if ($this->shareManager->shareProviderExists(Share::SHARE_TYPE_EMAIL)) { |
|
1023 | + $share = $this->shareManager->getShareById('ocMailShare:' . $id, $this->currentUser); |
|
1024 | + return $share; |
|
1025 | + } |
|
1026 | + } catch (ShareNotFound $e) { |
|
1027 | + // Do nothing, just try the other share type |
|
1028 | + } |
|
1029 | + |
|
1030 | + try { |
|
1031 | + $share = $this->shareManager->getShareById('ocRoomShare:' . $id, $this->currentUser); |
|
1032 | + return $share; |
|
1033 | + } catch (ShareNotFound $e) { |
|
1034 | + // Do nothing, just try the other share type |
|
1035 | + } |
|
1036 | + |
|
1037 | + if (!$this->shareManager->outgoingServer2ServerSharesAllowed()) { |
|
1038 | + throw new ShareNotFound(); |
|
1039 | + } |
|
1040 | + $share = $this->shareManager->getShareById('ocFederatedSharing:' . $id, $this->currentUser); |
|
1041 | + |
|
1042 | + return $share; |
|
1043 | + } |
|
1044 | + |
|
1045 | + /** |
|
1046 | + * Lock a Node |
|
1047 | + * |
|
1048 | + * @param \OCP\Files\Node $node |
|
1049 | + * @throws LockedException |
|
1050 | + */ |
|
1051 | + private function lock(\OCP\Files\Node $node) { |
|
1052 | + $node->lock(ILockingProvider::LOCK_SHARED); |
|
1053 | + $this->lockedNode = $node; |
|
1054 | + } |
|
1055 | + |
|
1056 | + /** |
|
1057 | + * Cleanup the remaining locks |
|
1058 | + * @throws @LockedException |
|
1059 | + */ |
|
1060 | + public function cleanup() { |
|
1061 | + if ($this->lockedNode !== null) { |
|
1062 | + $this->lockedNode->unlock(ILockingProvider::LOCK_SHARED); |
|
1063 | + } |
|
1064 | + } |
|
1065 | + |
|
1066 | + /** |
|
1067 | + * Returns the helper of ShareAPIController for room shares. |
|
1068 | + * |
|
1069 | + * If the Talk application is not enabled or the helper is not available |
|
1070 | + * a QueryException is thrown instead. |
|
1071 | + * |
|
1072 | + * @return \OCA\Spreed\Share\Helper\ShareAPIController |
|
1073 | + * @throws QueryException |
|
1074 | + */ |
|
1075 | + private function getRoomShareHelper() { |
|
1076 | + if (!$this->appManager->isEnabledForUser('spreed')) { |
|
1077 | + throw new QueryException(); |
|
1078 | + } |
|
1079 | + |
|
1080 | + return $this->serverContainer->query('\OCA\Spreed\Share\Helper\ShareAPIController'); |
|
1081 | + } |
|
1082 | 1082 | } |
@@ -231,14 +231,14 @@ discard block |
||
231 | 231 | |
232 | 232 | $result['share_with_displayname'] = $share->getSharedWithDisplayName(); |
233 | 233 | if (empty($result['share_with_displayname'])) { |
234 | - $displayNameLength = ($hasCircleId? strrpos($share->getSharedWith(), ' '): strlen($share->getSharedWith())); |
|
234 | + $displayNameLength = ($hasCircleId ? strrpos($share->getSharedWith(), ' ') : strlen($share->getSharedWith())); |
|
235 | 235 | $result['share_with_displayname'] = substr($share->getSharedWith(), 0, $displayNameLength); |
236 | 236 | } |
237 | 237 | |
238 | 238 | $result['share_with_avatar'] = $share->getSharedWithAvatar(); |
239 | 239 | |
240 | - $shareWithStart = ($hasCircleId? strrpos($share->getSharedWith(), '[') + 1: 0); |
|
241 | - $shareWithLength = ($hasCircleId? -1: strpos($share->getSharedWith(), ' ')); |
|
240 | + $shareWithStart = ($hasCircleId ? strrpos($share->getSharedWith(), '[') + 1 : 0); |
|
241 | + $shareWithLength = ($hasCircleId ? -1 : strpos($share->getSharedWith(), ' ')); |
|
242 | 242 | $result['share_with'] = substr($share->getSharedWith(), $shareWithStart, $shareWithLength); |
243 | 243 | } else if ($share->getShareType() === Share::SHARE_TYPE_ROOM) { |
244 | 244 | $result['share_with'] = $share->getSharedWith(); |
@@ -268,7 +268,7 @@ discard block |
||
268 | 268 | // FIXME: If we inject the contacts manager it gets initialized bofore any address books are registered |
269 | 269 | $result = \OC::$server->getContactsManager()->search($query, [$property]); |
270 | 270 | foreach ($result as $r) { |
271 | - foreach($r[$property] as $value) { |
|
271 | + foreach ($r[$property] as $value) { |
|
272 | 272 | if ($value === $query) { |
273 | 273 | return $r['FN']; |
274 | 274 | } |
@@ -498,7 +498,7 @@ discard block |
||
498 | 498 | |
499 | 499 | $share->setSharedWith($shareWith); |
500 | 500 | $share->setPermissions($permissions); |
501 | - } else if ($shareType === Share::SHARE_TYPE_REMOTE_GROUP) { |
|
501 | + } else if ($shareType === Share::SHARE_TYPE_REMOTE_GROUP) { |
|
502 | 502 | if (!$this->shareManager->outgoingServer2ServerGroupSharesAllowed()) { |
503 | 503 | 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])); |
504 | 504 | } |
@@ -574,7 +574,7 @@ discard block |
||
574 | 574 | |
575 | 575 | $shares = array_merge($userShares, $groupShares, $circleShares, $roomShares); |
576 | 576 | |
577 | - $shares = array_filter($shares, function (IShare $share) { |
|
577 | + $shares = array_filter($shares, function(IShare $share) { |
|
578 | 578 | return $share->getShareOwner() !== $this->currentUser; |
579 | 579 | }); |
580 | 580 | |
@@ -613,7 +613,7 @@ discard block |
||
613 | 613 | $shares = array_merge($shares, $this->shareManager->getSharesBy($this->currentUser, Share::SHARE_TYPE_USER, $node, false, -1, 0)); |
614 | 614 | $shares = array_merge($shares, $this->shareManager->getSharesBy($this->currentUser, Share::SHARE_TYPE_GROUP, $node, false, -1, 0)); |
615 | 615 | $shares = array_merge($shares, $this->shareManager->getSharesBy($this->currentUser, Share::SHARE_TYPE_LINK, $node, false, -1, 0)); |
616 | - if($this->shareManager->shareProviderExists(Share::SHARE_TYPE_EMAIL)) { |
|
616 | + if ($this->shareManager->shareProviderExists(Share::SHARE_TYPE_EMAIL)) { |
|
617 | 617 | $shares = array_merge($shares, $this->shareManager->getSharesBy($this->currentUser, Share::SHARE_TYPE_EMAIL, $node, false, -1, 0)); |
618 | 618 | } |
619 | 619 | if ($this->shareManager->outgoingServer2ServerSharesAllowed()) { |
@@ -777,7 +777,7 @@ discard block |
||
777 | 777 | throw new OCSBadRequestException($this->l->t('Wrong or no update parameter given')); |
778 | 778 | } |
779 | 779 | |
780 | - if($note !== null) { |
|
780 | + if ($note !== null) { |
|
781 | 781 | $share->setNote($note); |
782 | 782 | } |
783 | 783 | |
@@ -794,7 +794,7 @@ discard block |
||
794 | 794 | } |
795 | 795 | |
796 | 796 | if ($permissions !== null) { |
797 | - $newPermissions = (int)$permissions; |
|
797 | + $newPermissions = (int) $permissions; |
|
798 | 798 | $newPermissions = $newPermissions & ~Constants::PERMISSION_SHARE; |
799 | 799 | } |
800 | 800 | |
@@ -852,7 +852,7 @@ discard block |
||
852 | 852 | |
853 | 853 | } else { |
854 | 854 | if ($permissions !== null) { |
855 | - $permissions = (int)$permissions; |
|
855 | + $permissions = (int) $permissions; |
|
856 | 856 | $share->setPermissions($permissions); |
857 | 857 | } |
858 | 858 | |
@@ -1002,7 +1002,7 @@ discard block |
||
1002 | 1002 | |
1003 | 1003 | // First check if it is an internal share. |
1004 | 1004 | try { |
1005 | - $share = $this->shareManager->getShareById('ocinternal:' . $id, $this->currentUser); |
|
1005 | + $share = $this->shareManager->getShareById('ocinternal:'.$id, $this->currentUser); |
|
1006 | 1006 | return $share; |
1007 | 1007 | } catch (ShareNotFound $e) { |
1008 | 1008 | // Do nothing, just try the other share type |
@@ -1011,7 +1011,7 @@ discard block |
||
1011 | 1011 | |
1012 | 1012 | try { |
1013 | 1013 | if ($this->shareManager->shareProviderExists(Share::SHARE_TYPE_CIRCLE)) { |
1014 | - $share = $this->shareManager->getShareById('ocCircleShare:' . $id, $this->currentUser); |
|
1014 | + $share = $this->shareManager->getShareById('ocCircleShare:'.$id, $this->currentUser); |
|
1015 | 1015 | return $share; |
1016 | 1016 | } |
1017 | 1017 | } catch (ShareNotFound $e) { |
@@ -1020,7 +1020,7 @@ discard block |
||
1020 | 1020 | |
1021 | 1021 | try { |
1022 | 1022 | if ($this->shareManager->shareProviderExists(Share::SHARE_TYPE_EMAIL)) { |
1023 | - $share = $this->shareManager->getShareById('ocMailShare:' . $id, $this->currentUser); |
|
1023 | + $share = $this->shareManager->getShareById('ocMailShare:'.$id, $this->currentUser); |
|
1024 | 1024 | return $share; |
1025 | 1025 | } |
1026 | 1026 | } catch (ShareNotFound $e) { |
@@ -1028,7 +1028,7 @@ discard block |
||
1028 | 1028 | } |
1029 | 1029 | |
1030 | 1030 | try { |
1031 | - $share = $this->shareManager->getShareById('ocRoomShare:' . $id, $this->currentUser); |
|
1031 | + $share = $this->shareManager->getShareById('ocRoomShare:'.$id, $this->currentUser); |
|
1032 | 1032 | return $share; |
1033 | 1033 | } catch (ShareNotFound $e) { |
1034 | 1034 | // Do nothing, just try the other share type |
@@ -1037,7 +1037,7 @@ discard block |
||
1037 | 1037 | if (!$this->shareManager->outgoingServer2ServerSharesAllowed()) { |
1038 | 1038 | throw new ShareNotFound(); |
1039 | 1039 | } |
1040 | - $share = $this->shareManager->getShareById('ocFederatedSharing:' . $id, $this->currentUser); |
|
1040 | + $share = $this->shareManager->getShareById('ocFederatedSharing:'.$id, $this->currentUser); |
|
1041 | 1041 | |
1042 | 1042 | return $share; |
1043 | 1043 | } |
@@ -498,7 +498,7 @@ |
||
498 | 498 | |
499 | 499 | $share->setSharedWith($shareWith); |
500 | 500 | $share->setPermissions($permissions); |
501 | - } else if ($shareType === Share::SHARE_TYPE_REMOTE_GROUP) { |
|
501 | + } else if ($shareType === Share::SHARE_TYPE_REMOTE_GROUP) { |
|
502 | 502 | if (!$this->shareManager->outgoingServer2ServerGroupSharesAllowed()) { |
503 | 503 | 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])); |
504 | 504 | } |
@@ -32,19 +32,19 @@ |
||
32 | 32 | */ |
33 | 33 | class ProviderAlreadyExistsException extends HintException { |
34 | 34 | |
35 | - /** |
|
36 | - * ProviderAlreadyExistsException constructor. |
|
37 | - * |
|
38 | - * @since 14.0.0 |
|
39 | - * |
|
40 | - * @param string $newProviderId cloud federation provider ID of the new provider |
|
41 | - * @param string $existingProviderName name of cloud federation provider which already use the same ID |
|
42 | - */ |
|
43 | - public function __construct($newProviderId, $existingProviderName) { |
|
44 | - $l = \OC::$server->getL10N('federation'); |
|
45 | - $message = 'ID "' . $newProviderId . '" already used by cloud federation provider "' . $existingProviderName . '"'; |
|
46 | - $hint = $l->t('ID "%1$s" already used by cloud federation provider "%2$s"', [$newProviderId, $existingProviderName]); |
|
47 | - parent::__construct($message, $hint); |
|
48 | - } |
|
35 | + /** |
|
36 | + * ProviderAlreadyExistsException constructor. |
|
37 | + * |
|
38 | + * @since 14.0.0 |
|
39 | + * |
|
40 | + * @param string $newProviderId cloud federation provider ID of the new provider |
|
41 | + * @param string $existingProviderName name of cloud federation provider which already use the same ID |
|
42 | + */ |
|
43 | + public function __construct($newProviderId, $existingProviderName) { |
|
44 | + $l = \OC::$server->getL10N('federation'); |
|
45 | + $message = 'ID "' . $newProviderId . '" already used by cloud federation provider "' . $existingProviderName . '"'; |
|
46 | + $hint = $l->t('ID "%1$s" already used by cloud federation provider "%2$s"', [$newProviderId, $existingProviderName]); |
|
47 | + parent::__construct($message, $hint); |
|
48 | + } |
|
49 | 49 | |
50 | 50 | } |
@@ -42,7 +42,7 @@ |
||
42 | 42 | */ |
43 | 43 | public function __construct($newProviderId, $existingProviderName) { |
44 | 44 | $l = \OC::$server->getL10N('federation'); |
45 | - $message = 'ID "' . $newProviderId . '" already used by cloud federation provider "' . $existingProviderName . '"'; |
|
45 | + $message = 'ID "'.$newProviderId.'" already used by cloud federation provider "'.$existingProviderName.'"'; |
|
46 | 46 | $hint = $l->t('ID "%1$s" already used by cloud federation provider "%2$s"', [$newProviderId, $existingProviderName]); |
47 | 47 | parent::__construct($message, $hint); |
48 | 48 | } |
@@ -33,326 +33,326 @@ |
||
33 | 33 | |
34 | 34 | class DependencyAnalyzer { |
35 | 35 | |
36 | - /** @var Platform */ |
|
37 | - private $platform; |
|
38 | - /** @var \OCP\IL10N */ |
|
39 | - private $l; |
|
40 | - /** @var array */ |
|
41 | - private $appInfo; |
|
36 | + /** @var Platform */ |
|
37 | + private $platform; |
|
38 | + /** @var \OCP\IL10N */ |
|
39 | + private $l; |
|
40 | + /** @var array */ |
|
41 | + private $appInfo; |
|
42 | 42 | |
43 | - /** |
|
44 | - * @param Platform $platform |
|
45 | - * @param \OCP\IL10N $l |
|
46 | - */ |
|
47 | - public function __construct(Platform $platform, IL10N $l) { |
|
48 | - $this->platform = $platform; |
|
49 | - $this->l = $l; |
|
50 | - } |
|
43 | + /** |
|
44 | + * @param Platform $platform |
|
45 | + * @param \OCP\IL10N $l |
|
46 | + */ |
|
47 | + public function __construct(Platform $platform, IL10N $l) { |
|
48 | + $this->platform = $platform; |
|
49 | + $this->l = $l; |
|
50 | + } |
|
51 | 51 | |
52 | - /** |
|
53 | - * @param array $app |
|
54 | - * @returns array of missing dependencies |
|
55 | - */ |
|
56 | - public function analyze(array $app) { |
|
57 | - $this->appInfo = $app; |
|
58 | - if (isset($app['dependencies'])) { |
|
59 | - $dependencies = $app['dependencies']; |
|
60 | - } else { |
|
61 | - $dependencies = []; |
|
62 | - } |
|
52 | + /** |
|
53 | + * @param array $app |
|
54 | + * @returns array of missing dependencies |
|
55 | + */ |
|
56 | + public function analyze(array $app) { |
|
57 | + $this->appInfo = $app; |
|
58 | + if (isset($app['dependencies'])) { |
|
59 | + $dependencies = $app['dependencies']; |
|
60 | + } else { |
|
61 | + $dependencies = []; |
|
62 | + } |
|
63 | 63 | |
64 | - return array_merge( |
|
65 | - $this->analyzePhpVersion($dependencies), |
|
66 | - $this->analyzeDatabases($dependencies), |
|
67 | - $this->analyzeCommands($dependencies), |
|
68 | - $this->analyzeLibraries($dependencies), |
|
69 | - $this->analyzeOS($dependencies), |
|
70 | - $this->analyzeOC($dependencies, $app) |
|
71 | - ); |
|
72 | - } |
|
64 | + return array_merge( |
|
65 | + $this->analyzePhpVersion($dependencies), |
|
66 | + $this->analyzeDatabases($dependencies), |
|
67 | + $this->analyzeCommands($dependencies), |
|
68 | + $this->analyzeLibraries($dependencies), |
|
69 | + $this->analyzeOS($dependencies), |
|
70 | + $this->analyzeOC($dependencies, $app) |
|
71 | + ); |
|
72 | + } |
|
73 | 73 | |
74 | - /** |
|
75 | - * Truncates both versions to the lowest common version, e.g. |
|
76 | - * 5.1.2.3 and 5.1 will be turned into 5.1 and 5.1, |
|
77 | - * 5.2.6.5 and 5.1 will be turned into 5.2 and 5.1 |
|
78 | - * @param string $first |
|
79 | - * @param string $second |
|
80 | - * @return string[] first element is the first version, second element is the |
|
81 | - * second version |
|
82 | - */ |
|
83 | - private function normalizeVersions($first, $second) { |
|
84 | - $first = explode('.', $first); |
|
85 | - $second = explode('.', $second); |
|
74 | + /** |
|
75 | + * Truncates both versions to the lowest common version, e.g. |
|
76 | + * 5.1.2.3 and 5.1 will be turned into 5.1 and 5.1, |
|
77 | + * 5.2.6.5 and 5.1 will be turned into 5.2 and 5.1 |
|
78 | + * @param string $first |
|
79 | + * @param string $second |
|
80 | + * @return string[] first element is the first version, second element is the |
|
81 | + * second version |
|
82 | + */ |
|
83 | + private function normalizeVersions($first, $second) { |
|
84 | + $first = explode('.', $first); |
|
85 | + $second = explode('.', $second); |
|
86 | 86 | |
87 | - // get both arrays to the same minimum size |
|
88 | - $length = min(count($second), count($first)); |
|
89 | - $first = array_slice($first, 0, $length); |
|
90 | - $second = array_slice($second, 0, $length); |
|
87 | + // get both arrays to the same minimum size |
|
88 | + $length = min(count($second), count($first)); |
|
89 | + $first = array_slice($first, 0, $length); |
|
90 | + $second = array_slice($second, 0, $length); |
|
91 | 91 | |
92 | - return [implode('.', $first), implode('.', $second)]; |
|
93 | - } |
|
92 | + return [implode('.', $first), implode('.', $second)]; |
|
93 | + } |
|
94 | 94 | |
95 | - /** |
|
96 | - * Parameters will be normalized and then passed into version_compare |
|
97 | - * in the same order they are specified in the method header |
|
98 | - * @param string $first |
|
99 | - * @param string $second |
|
100 | - * @param string $operator |
|
101 | - * @return bool result similar to version_compare |
|
102 | - */ |
|
103 | - private function compare($first, $second, $operator) { |
|
104 | - // we can't normalize versions if one of the given parameters is not a |
|
105 | - // version string but null. In case one parameter is null normalization |
|
106 | - // will therefore be skipped |
|
107 | - if ($first !== null && $second !== null) { |
|
108 | - list($first, $second) = $this->normalizeVersions($first, $second); |
|
109 | - } |
|
95 | + /** |
|
96 | + * Parameters will be normalized and then passed into version_compare |
|
97 | + * in the same order they are specified in the method header |
|
98 | + * @param string $first |
|
99 | + * @param string $second |
|
100 | + * @param string $operator |
|
101 | + * @return bool result similar to version_compare |
|
102 | + */ |
|
103 | + private function compare($first, $second, $operator) { |
|
104 | + // we can't normalize versions if one of the given parameters is not a |
|
105 | + // version string but null. In case one parameter is null normalization |
|
106 | + // will therefore be skipped |
|
107 | + if ($first !== null && $second !== null) { |
|
108 | + list($first, $second) = $this->normalizeVersions($first, $second); |
|
109 | + } |
|
110 | 110 | |
111 | - return version_compare($first, $second, $operator); |
|
112 | - } |
|
111 | + return version_compare($first, $second, $operator); |
|
112 | + } |
|
113 | 113 | |
114 | - /** |
|
115 | - * Checks if a version is bigger than another version |
|
116 | - * @param string $first |
|
117 | - * @param string $second |
|
118 | - * @return bool true if the first version is bigger than the second |
|
119 | - */ |
|
120 | - private function compareBigger($first, $second) { |
|
121 | - return $this->compare($first, $second, '>'); |
|
122 | - } |
|
114 | + /** |
|
115 | + * Checks if a version is bigger than another version |
|
116 | + * @param string $first |
|
117 | + * @param string $second |
|
118 | + * @return bool true if the first version is bigger than the second |
|
119 | + */ |
|
120 | + private function compareBigger($first, $second) { |
|
121 | + return $this->compare($first, $second, '>'); |
|
122 | + } |
|
123 | 123 | |
124 | - /** |
|
125 | - * Checks if a version is smaller than another version |
|
126 | - * @param string $first |
|
127 | - * @param string $second |
|
128 | - * @return bool true if the first version is smaller than the second |
|
129 | - */ |
|
130 | - private function compareSmaller($first, $second) { |
|
131 | - return $this->compare($first, $second, '<'); |
|
132 | - } |
|
124 | + /** |
|
125 | + * Checks if a version is smaller than another version |
|
126 | + * @param string $first |
|
127 | + * @param string $second |
|
128 | + * @return bool true if the first version is smaller than the second |
|
129 | + */ |
|
130 | + private function compareSmaller($first, $second) { |
|
131 | + return $this->compare($first, $second, '<'); |
|
132 | + } |
|
133 | 133 | |
134 | - /** |
|
135 | - * @param array $dependencies |
|
136 | - * @return array |
|
137 | - */ |
|
138 | - private function analyzePhpVersion(array $dependencies) { |
|
139 | - $missing = []; |
|
140 | - if (isset($dependencies['php']['@attributes']['min-version'])) { |
|
141 | - $minVersion = $dependencies['php']['@attributes']['min-version']; |
|
142 | - if ($this->compareSmaller($this->platform->getPhpVersion(), $minVersion)) { |
|
143 | - $missing[] = (string)$this->l->t('PHP %s or higher is required.', [$minVersion]); |
|
144 | - } |
|
145 | - } |
|
146 | - if (isset($dependencies['php']['@attributes']['max-version'])) { |
|
147 | - $maxVersion = $dependencies['php']['@attributes']['max-version']; |
|
148 | - if ($this->compareBigger($this->platform->getPhpVersion(), $maxVersion)) { |
|
149 | - $missing[] = (string)$this->l->t('PHP with a version lower than %s is required.', [$maxVersion]); |
|
150 | - } |
|
151 | - } |
|
152 | - if (isset($dependencies['php']['@attributes']['min-int-size'])) { |
|
153 | - $intSize = $dependencies['php']['@attributes']['min-int-size']; |
|
154 | - if ($intSize > $this->platform->getIntSize()*8) { |
|
155 | - $missing[] = (string)$this->l->t('%sbit or higher PHP required.', [$intSize]); |
|
156 | - } |
|
157 | - } |
|
158 | - return $missing; |
|
159 | - } |
|
134 | + /** |
|
135 | + * @param array $dependencies |
|
136 | + * @return array |
|
137 | + */ |
|
138 | + private function analyzePhpVersion(array $dependencies) { |
|
139 | + $missing = []; |
|
140 | + if (isset($dependencies['php']['@attributes']['min-version'])) { |
|
141 | + $minVersion = $dependencies['php']['@attributes']['min-version']; |
|
142 | + if ($this->compareSmaller($this->platform->getPhpVersion(), $minVersion)) { |
|
143 | + $missing[] = (string)$this->l->t('PHP %s or higher is required.', [$minVersion]); |
|
144 | + } |
|
145 | + } |
|
146 | + if (isset($dependencies['php']['@attributes']['max-version'])) { |
|
147 | + $maxVersion = $dependencies['php']['@attributes']['max-version']; |
|
148 | + if ($this->compareBigger($this->platform->getPhpVersion(), $maxVersion)) { |
|
149 | + $missing[] = (string)$this->l->t('PHP with a version lower than %s is required.', [$maxVersion]); |
|
150 | + } |
|
151 | + } |
|
152 | + if (isset($dependencies['php']['@attributes']['min-int-size'])) { |
|
153 | + $intSize = $dependencies['php']['@attributes']['min-int-size']; |
|
154 | + if ($intSize > $this->platform->getIntSize()*8) { |
|
155 | + $missing[] = (string)$this->l->t('%sbit or higher PHP required.', [$intSize]); |
|
156 | + } |
|
157 | + } |
|
158 | + return $missing; |
|
159 | + } |
|
160 | 160 | |
161 | - /** |
|
162 | - * @param array $dependencies |
|
163 | - * @return array |
|
164 | - */ |
|
165 | - private function analyzeDatabases(array $dependencies) { |
|
166 | - $missing = []; |
|
167 | - if (!isset($dependencies['database'])) { |
|
168 | - return $missing; |
|
169 | - } |
|
161 | + /** |
|
162 | + * @param array $dependencies |
|
163 | + * @return array |
|
164 | + */ |
|
165 | + private function analyzeDatabases(array $dependencies) { |
|
166 | + $missing = []; |
|
167 | + if (!isset($dependencies['database'])) { |
|
168 | + return $missing; |
|
169 | + } |
|
170 | 170 | |
171 | - $supportedDatabases = $dependencies['database']; |
|
172 | - if (empty($supportedDatabases)) { |
|
173 | - return $missing; |
|
174 | - } |
|
175 | - if (!is_array($supportedDatabases)) { |
|
176 | - $supportedDatabases = array($supportedDatabases); |
|
177 | - } |
|
178 | - $supportedDatabases = array_map(function ($db) { |
|
179 | - return $this->getValue($db); |
|
180 | - }, $supportedDatabases); |
|
181 | - $currentDatabase = $this->platform->getDatabase(); |
|
182 | - if (!in_array($currentDatabase, $supportedDatabases)) { |
|
183 | - $missing[] = (string)$this->l->t('Following databases are supported: %s', [implode(', ', $supportedDatabases)]); |
|
184 | - } |
|
185 | - return $missing; |
|
186 | - } |
|
171 | + $supportedDatabases = $dependencies['database']; |
|
172 | + if (empty($supportedDatabases)) { |
|
173 | + return $missing; |
|
174 | + } |
|
175 | + if (!is_array($supportedDatabases)) { |
|
176 | + $supportedDatabases = array($supportedDatabases); |
|
177 | + } |
|
178 | + $supportedDatabases = array_map(function ($db) { |
|
179 | + return $this->getValue($db); |
|
180 | + }, $supportedDatabases); |
|
181 | + $currentDatabase = $this->platform->getDatabase(); |
|
182 | + if (!in_array($currentDatabase, $supportedDatabases)) { |
|
183 | + $missing[] = (string)$this->l->t('Following databases are supported: %s', [implode(', ', $supportedDatabases)]); |
|
184 | + } |
|
185 | + return $missing; |
|
186 | + } |
|
187 | 187 | |
188 | - /** |
|
189 | - * @param array $dependencies |
|
190 | - * @return array |
|
191 | - */ |
|
192 | - private function analyzeCommands(array $dependencies) { |
|
193 | - $missing = []; |
|
194 | - if (!isset($dependencies['command'])) { |
|
195 | - return $missing; |
|
196 | - } |
|
188 | + /** |
|
189 | + * @param array $dependencies |
|
190 | + * @return array |
|
191 | + */ |
|
192 | + private function analyzeCommands(array $dependencies) { |
|
193 | + $missing = []; |
|
194 | + if (!isset($dependencies['command'])) { |
|
195 | + return $missing; |
|
196 | + } |
|
197 | 197 | |
198 | - $commands = $dependencies['command']; |
|
199 | - if (!is_array($commands)) { |
|
200 | - $commands = array($commands); |
|
201 | - } |
|
202 | - if (isset($commands['@value'])) { |
|
203 | - $commands = [$commands]; |
|
204 | - } |
|
205 | - $os = $this->platform->getOS(); |
|
206 | - foreach ($commands as $command) { |
|
207 | - if (isset($command['@attributes']['os']) && $command['@attributes']['os'] !== $os) { |
|
208 | - continue; |
|
209 | - } |
|
210 | - $commandName = $this->getValue($command); |
|
211 | - if (!$this->platform->isCommandKnown($commandName)) { |
|
212 | - $missing[] = (string)$this->l->t('The command line tool %s could not be found', [$commandName]); |
|
213 | - } |
|
214 | - } |
|
215 | - return $missing; |
|
216 | - } |
|
198 | + $commands = $dependencies['command']; |
|
199 | + if (!is_array($commands)) { |
|
200 | + $commands = array($commands); |
|
201 | + } |
|
202 | + if (isset($commands['@value'])) { |
|
203 | + $commands = [$commands]; |
|
204 | + } |
|
205 | + $os = $this->platform->getOS(); |
|
206 | + foreach ($commands as $command) { |
|
207 | + if (isset($command['@attributes']['os']) && $command['@attributes']['os'] !== $os) { |
|
208 | + continue; |
|
209 | + } |
|
210 | + $commandName = $this->getValue($command); |
|
211 | + if (!$this->platform->isCommandKnown($commandName)) { |
|
212 | + $missing[] = (string)$this->l->t('The command line tool %s could not be found', [$commandName]); |
|
213 | + } |
|
214 | + } |
|
215 | + return $missing; |
|
216 | + } |
|
217 | 217 | |
218 | - /** |
|
219 | - * @param array $dependencies |
|
220 | - * @return array |
|
221 | - */ |
|
222 | - private function analyzeLibraries(array $dependencies) { |
|
223 | - $missing = []; |
|
224 | - if (!isset($dependencies['lib'])) { |
|
225 | - return $missing; |
|
226 | - } |
|
218 | + /** |
|
219 | + * @param array $dependencies |
|
220 | + * @return array |
|
221 | + */ |
|
222 | + private function analyzeLibraries(array $dependencies) { |
|
223 | + $missing = []; |
|
224 | + if (!isset($dependencies['lib'])) { |
|
225 | + return $missing; |
|
226 | + } |
|
227 | 227 | |
228 | - $libs = $dependencies['lib']; |
|
229 | - if (!is_array($libs)) { |
|
230 | - $libs = array($libs); |
|
231 | - } |
|
232 | - if (isset($libs['@value'])) { |
|
233 | - $libs = [$libs]; |
|
234 | - } |
|
235 | - foreach ($libs as $lib) { |
|
236 | - $libName = $this->getValue($lib); |
|
237 | - $libVersion = $this->platform->getLibraryVersion($libName); |
|
238 | - if (is_null($libVersion)) { |
|
239 | - $missing[] = $this->l->t('The library %s is not available.', [$libName]); |
|
240 | - continue; |
|
241 | - } |
|
228 | + $libs = $dependencies['lib']; |
|
229 | + if (!is_array($libs)) { |
|
230 | + $libs = array($libs); |
|
231 | + } |
|
232 | + if (isset($libs['@value'])) { |
|
233 | + $libs = [$libs]; |
|
234 | + } |
|
235 | + foreach ($libs as $lib) { |
|
236 | + $libName = $this->getValue($lib); |
|
237 | + $libVersion = $this->platform->getLibraryVersion($libName); |
|
238 | + if (is_null($libVersion)) { |
|
239 | + $missing[] = $this->l->t('The library %s is not available.', [$libName]); |
|
240 | + continue; |
|
241 | + } |
|
242 | 242 | |
243 | - if (is_array($lib)) { |
|
244 | - if (isset($lib['@attributes']['min-version'])) { |
|
245 | - $minVersion = $lib['@attributes']['min-version']; |
|
246 | - if ($this->compareSmaller($libVersion, $minVersion)) { |
|
247 | - $missing[] = $this->l->t('Library %1$s with a version higher than %2$s is required - available version %3$s.', |
|
248 | - [$libName, $minVersion, $libVersion]); |
|
249 | - } |
|
250 | - } |
|
251 | - if (isset($lib['@attributes']['max-version'])) { |
|
252 | - $maxVersion = $lib['@attributes']['max-version']; |
|
253 | - if ($this->compareBigger($libVersion, $maxVersion)) { |
|
254 | - $missing[] = $this->l->t('Library %1$s with a version lower than %2$s is required - available version %3$s.', |
|
255 | - [$libName, $maxVersion, $libVersion]); |
|
256 | - } |
|
257 | - } |
|
258 | - } |
|
259 | - } |
|
260 | - return $missing; |
|
261 | - } |
|
243 | + if (is_array($lib)) { |
|
244 | + if (isset($lib['@attributes']['min-version'])) { |
|
245 | + $minVersion = $lib['@attributes']['min-version']; |
|
246 | + if ($this->compareSmaller($libVersion, $minVersion)) { |
|
247 | + $missing[] = $this->l->t('Library %1$s with a version higher than %2$s is required - available version %3$s.', |
|
248 | + [$libName, $minVersion, $libVersion]); |
|
249 | + } |
|
250 | + } |
|
251 | + if (isset($lib['@attributes']['max-version'])) { |
|
252 | + $maxVersion = $lib['@attributes']['max-version']; |
|
253 | + if ($this->compareBigger($libVersion, $maxVersion)) { |
|
254 | + $missing[] = $this->l->t('Library %1$s with a version lower than %2$s is required - available version %3$s.', |
|
255 | + [$libName, $maxVersion, $libVersion]); |
|
256 | + } |
|
257 | + } |
|
258 | + } |
|
259 | + } |
|
260 | + return $missing; |
|
261 | + } |
|
262 | 262 | |
263 | - /** |
|
264 | - * @param array $dependencies |
|
265 | - * @return array |
|
266 | - */ |
|
267 | - private function analyzeOS(array $dependencies) { |
|
268 | - $missing = []; |
|
269 | - if (!isset($dependencies['os'])) { |
|
270 | - return $missing; |
|
271 | - } |
|
263 | + /** |
|
264 | + * @param array $dependencies |
|
265 | + * @return array |
|
266 | + */ |
|
267 | + private function analyzeOS(array $dependencies) { |
|
268 | + $missing = []; |
|
269 | + if (!isset($dependencies['os'])) { |
|
270 | + return $missing; |
|
271 | + } |
|
272 | 272 | |
273 | - $oss = $dependencies['os']; |
|
274 | - if (empty($oss)) { |
|
275 | - return $missing; |
|
276 | - } |
|
277 | - if (is_array($oss)) { |
|
278 | - $oss = array_map(function ($os) { |
|
279 | - return $this->getValue($os); |
|
280 | - }, $oss); |
|
281 | - } else { |
|
282 | - $oss = array($oss); |
|
283 | - } |
|
284 | - $currentOS = $this->platform->getOS(); |
|
285 | - if (!in_array($currentOS, $oss)) { |
|
286 | - $missing[] = (string)$this->l->t('Following platforms are supported: %s', [implode(', ', $oss)]); |
|
287 | - } |
|
288 | - return $missing; |
|
289 | - } |
|
273 | + $oss = $dependencies['os']; |
|
274 | + if (empty($oss)) { |
|
275 | + return $missing; |
|
276 | + } |
|
277 | + if (is_array($oss)) { |
|
278 | + $oss = array_map(function ($os) { |
|
279 | + return $this->getValue($os); |
|
280 | + }, $oss); |
|
281 | + } else { |
|
282 | + $oss = array($oss); |
|
283 | + } |
|
284 | + $currentOS = $this->platform->getOS(); |
|
285 | + if (!in_array($currentOS, $oss)) { |
|
286 | + $missing[] = (string)$this->l->t('Following platforms are supported: %s', [implode(', ', $oss)]); |
|
287 | + } |
|
288 | + return $missing; |
|
289 | + } |
|
290 | 290 | |
291 | - /** |
|
292 | - * @param array $dependencies |
|
293 | - * @param array $appInfo |
|
294 | - * @return array |
|
295 | - */ |
|
296 | - private function analyzeOC(array $dependencies, array $appInfo) { |
|
297 | - $missing = []; |
|
298 | - $minVersion = null; |
|
299 | - if (isset($dependencies['nextcloud']['@attributes']['min-version'])) { |
|
300 | - $minVersion = $dependencies['nextcloud']['@attributes']['min-version']; |
|
301 | - } elseif (isset($dependencies['owncloud']['@attributes']['min-version'])) { |
|
302 | - $minVersion = $dependencies['owncloud']['@attributes']['min-version']; |
|
303 | - } elseif (isset($appInfo['requiremin'])) { |
|
304 | - $minVersion = $appInfo['requiremin']; |
|
305 | - } elseif (isset($appInfo['require'])) { |
|
306 | - $minVersion = $appInfo['require']; |
|
307 | - } |
|
308 | - $maxVersion = null; |
|
309 | - if (isset($dependencies['nextcloud']['@attributes']['max-version'])) { |
|
310 | - $maxVersion = $dependencies['nextcloud']['@attributes']['max-version']; |
|
311 | - } elseif (isset($dependencies['owncloud']['@attributes']['max-version'])) { |
|
312 | - $maxVersion = $dependencies['owncloud']['@attributes']['max-version']; |
|
313 | - } elseif (isset($appInfo['requiremax'])) { |
|
314 | - $maxVersion = $appInfo['requiremax']; |
|
315 | - } |
|
291 | + /** |
|
292 | + * @param array $dependencies |
|
293 | + * @param array $appInfo |
|
294 | + * @return array |
|
295 | + */ |
|
296 | + private function analyzeOC(array $dependencies, array $appInfo) { |
|
297 | + $missing = []; |
|
298 | + $minVersion = null; |
|
299 | + if (isset($dependencies['nextcloud']['@attributes']['min-version'])) { |
|
300 | + $minVersion = $dependencies['nextcloud']['@attributes']['min-version']; |
|
301 | + } elseif (isset($dependencies['owncloud']['@attributes']['min-version'])) { |
|
302 | + $minVersion = $dependencies['owncloud']['@attributes']['min-version']; |
|
303 | + } elseif (isset($appInfo['requiremin'])) { |
|
304 | + $minVersion = $appInfo['requiremin']; |
|
305 | + } elseif (isset($appInfo['require'])) { |
|
306 | + $minVersion = $appInfo['require']; |
|
307 | + } |
|
308 | + $maxVersion = null; |
|
309 | + if (isset($dependencies['nextcloud']['@attributes']['max-version'])) { |
|
310 | + $maxVersion = $dependencies['nextcloud']['@attributes']['max-version']; |
|
311 | + } elseif (isset($dependencies['owncloud']['@attributes']['max-version'])) { |
|
312 | + $maxVersion = $dependencies['owncloud']['@attributes']['max-version']; |
|
313 | + } elseif (isset($appInfo['requiremax'])) { |
|
314 | + $maxVersion = $appInfo['requiremax']; |
|
315 | + } |
|
316 | 316 | |
317 | - if (!is_null($minVersion)) { |
|
318 | - if ($this->compareSmaller($this->platform->getOcVersion(), $minVersion)) { |
|
319 | - $missing[] = (string)$this->l->t('Server version %s or higher is required.', [$this->toVisibleVersion($minVersion)]); |
|
320 | - } |
|
321 | - } |
|
322 | - if (!is_null($maxVersion)) { |
|
323 | - if ($this->compareBigger($this->platform->getOcVersion(), $maxVersion)) { |
|
324 | - $missing[] = (string)$this->l->t('Server version %s or lower is required.', [$this->toVisibleVersion($maxVersion)]); |
|
325 | - } |
|
326 | - } |
|
327 | - return $missing; |
|
328 | - } |
|
317 | + if (!is_null($minVersion)) { |
|
318 | + if ($this->compareSmaller($this->platform->getOcVersion(), $minVersion)) { |
|
319 | + $missing[] = (string)$this->l->t('Server version %s or higher is required.', [$this->toVisibleVersion($minVersion)]); |
|
320 | + } |
|
321 | + } |
|
322 | + if (!is_null($maxVersion)) { |
|
323 | + if ($this->compareBigger($this->platform->getOcVersion(), $maxVersion)) { |
|
324 | + $missing[] = (string)$this->l->t('Server version %s or lower is required.', [$this->toVisibleVersion($maxVersion)]); |
|
325 | + } |
|
326 | + } |
|
327 | + return $missing; |
|
328 | + } |
|
329 | 329 | |
330 | - /** |
|
331 | - * Map the internal version number to the Nextcloud version |
|
332 | - * |
|
333 | - * @param string $version |
|
334 | - * @return string |
|
335 | - */ |
|
336 | - protected function toVisibleVersion($version) { |
|
337 | - switch ($version) { |
|
338 | - case '9.1': |
|
339 | - return '10'; |
|
340 | - default: |
|
341 | - if (strpos($version, '9.1.') === 0) { |
|
342 | - $version = '10.0.' . substr($version, 4); |
|
343 | - } |
|
344 | - return $version; |
|
345 | - } |
|
346 | - } |
|
330 | + /** |
|
331 | + * Map the internal version number to the Nextcloud version |
|
332 | + * |
|
333 | + * @param string $version |
|
334 | + * @return string |
|
335 | + */ |
|
336 | + protected function toVisibleVersion($version) { |
|
337 | + switch ($version) { |
|
338 | + case '9.1': |
|
339 | + return '10'; |
|
340 | + default: |
|
341 | + if (strpos($version, '9.1.') === 0) { |
|
342 | + $version = '10.0.' . substr($version, 4); |
|
343 | + } |
|
344 | + return $version; |
|
345 | + } |
|
346 | + } |
|
347 | 347 | |
348 | - /** |
|
349 | - * @param $element |
|
350 | - * @return mixed |
|
351 | - */ |
|
352 | - private function getValue($element) { |
|
353 | - if (isset($element['@value'])) { |
|
354 | - return $element['@value']; |
|
355 | - } |
|
356 | - return (string)$element; |
|
357 | - } |
|
348 | + /** |
|
349 | + * @param $element |
|
350 | + * @return mixed |
|
351 | + */ |
|
352 | + private function getValue($element) { |
|
353 | + if (isset($element['@value'])) { |
|
354 | + return $element['@value']; |
|
355 | + } |
|
356 | + return (string)$element; |
|
357 | + } |
|
358 | 358 | } |
@@ -140,19 +140,19 @@ discard block |
||
140 | 140 | if (isset($dependencies['php']['@attributes']['min-version'])) { |
141 | 141 | $minVersion = $dependencies['php']['@attributes']['min-version']; |
142 | 142 | if ($this->compareSmaller($this->platform->getPhpVersion(), $minVersion)) { |
143 | - $missing[] = (string)$this->l->t('PHP %s or higher is required.', [$minVersion]); |
|
143 | + $missing[] = (string) $this->l->t('PHP %s or higher is required.', [$minVersion]); |
|
144 | 144 | } |
145 | 145 | } |
146 | 146 | if (isset($dependencies['php']['@attributes']['max-version'])) { |
147 | 147 | $maxVersion = $dependencies['php']['@attributes']['max-version']; |
148 | 148 | if ($this->compareBigger($this->platform->getPhpVersion(), $maxVersion)) { |
149 | - $missing[] = (string)$this->l->t('PHP with a version lower than %s is required.', [$maxVersion]); |
|
149 | + $missing[] = (string) $this->l->t('PHP with a version lower than %s is required.', [$maxVersion]); |
|
150 | 150 | } |
151 | 151 | } |
152 | 152 | if (isset($dependencies['php']['@attributes']['min-int-size'])) { |
153 | 153 | $intSize = $dependencies['php']['@attributes']['min-int-size']; |
154 | - if ($intSize > $this->platform->getIntSize()*8) { |
|
155 | - $missing[] = (string)$this->l->t('%sbit or higher PHP required.', [$intSize]); |
|
154 | + if ($intSize > $this->platform->getIntSize() * 8) { |
|
155 | + $missing[] = (string) $this->l->t('%sbit or higher PHP required.', [$intSize]); |
|
156 | 156 | } |
157 | 157 | } |
158 | 158 | return $missing; |
@@ -175,12 +175,12 @@ discard block |
||
175 | 175 | if (!is_array($supportedDatabases)) { |
176 | 176 | $supportedDatabases = array($supportedDatabases); |
177 | 177 | } |
178 | - $supportedDatabases = array_map(function ($db) { |
|
178 | + $supportedDatabases = array_map(function($db) { |
|
179 | 179 | return $this->getValue($db); |
180 | 180 | }, $supportedDatabases); |
181 | 181 | $currentDatabase = $this->platform->getDatabase(); |
182 | 182 | if (!in_array($currentDatabase, $supportedDatabases)) { |
183 | - $missing[] = (string)$this->l->t('Following databases are supported: %s', [implode(', ', $supportedDatabases)]); |
|
183 | + $missing[] = (string) $this->l->t('Following databases are supported: %s', [implode(', ', $supportedDatabases)]); |
|
184 | 184 | } |
185 | 185 | return $missing; |
186 | 186 | } |
@@ -209,7 +209,7 @@ discard block |
||
209 | 209 | } |
210 | 210 | $commandName = $this->getValue($command); |
211 | 211 | if (!$this->platform->isCommandKnown($commandName)) { |
212 | - $missing[] = (string)$this->l->t('The command line tool %s could not be found', [$commandName]); |
|
212 | + $missing[] = (string) $this->l->t('The command line tool %s could not be found', [$commandName]); |
|
213 | 213 | } |
214 | 214 | } |
215 | 215 | return $missing; |
@@ -275,7 +275,7 @@ discard block |
||
275 | 275 | return $missing; |
276 | 276 | } |
277 | 277 | if (is_array($oss)) { |
278 | - $oss = array_map(function ($os) { |
|
278 | + $oss = array_map(function($os) { |
|
279 | 279 | return $this->getValue($os); |
280 | 280 | }, $oss); |
281 | 281 | } else { |
@@ -283,7 +283,7 @@ discard block |
||
283 | 283 | } |
284 | 284 | $currentOS = $this->platform->getOS(); |
285 | 285 | if (!in_array($currentOS, $oss)) { |
286 | - $missing[] = (string)$this->l->t('Following platforms are supported: %s', [implode(', ', $oss)]); |
|
286 | + $missing[] = (string) $this->l->t('Following platforms are supported: %s', [implode(', ', $oss)]); |
|
287 | 287 | } |
288 | 288 | return $missing; |
289 | 289 | } |
@@ -316,12 +316,12 @@ discard block |
||
316 | 316 | |
317 | 317 | if (!is_null($minVersion)) { |
318 | 318 | if ($this->compareSmaller($this->platform->getOcVersion(), $minVersion)) { |
319 | - $missing[] = (string)$this->l->t('Server version %s or higher is required.', [$this->toVisibleVersion($minVersion)]); |
|
319 | + $missing[] = (string) $this->l->t('Server version %s or higher is required.', [$this->toVisibleVersion($minVersion)]); |
|
320 | 320 | } |
321 | 321 | } |
322 | 322 | if (!is_null($maxVersion)) { |
323 | 323 | if ($this->compareBigger($this->platform->getOcVersion(), $maxVersion)) { |
324 | - $missing[] = (string)$this->l->t('Server version %s or lower is required.', [$this->toVisibleVersion($maxVersion)]); |
|
324 | + $missing[] = (string) $this->l->t('Server version %s or lower is required.', [$this->toVisibleVersion($maxVersion)]); |
|
325 | 325 | } |
326 | 326 | } |
327 | 327 | return $missing; |
@@ -339,7 +339,7 @@ discard block |
||
339 | 339 | return '10'; |
340 | 340 | default: |
341 | 341 | if (strpos($version, '9.1.') === 0) { |
342 | - $version = '10.0.' . substr($version, 4); |
|
342 | + $version = '10.0.'.substr($version, 4); |
|
343 | 343 | } |
344 | 344 | return $version; |
345 | 345 | } |
@@ -353,6 +353,6 @@ discard block |
||
353 | 353 | if (isset($element['@value'])) { |
354 | 354 | return $element['@value']; |
355 | 355 | } |
356 | - return (string)$element; |
|
356 | + return (string) $element; |
|
357 | 357 | } |
358 | 358 | } |