1<?php 2 3declare(strict_types=1); 4/** 5 * @copyright Copyright (c) 2016 Joas Schilling <coding@schilljs.com> 6 * 7 * @license GNU AGPL version 3 or any later version 8 * 9 * This program is free software: you can redistribute it and/or modify 10 * it under the terms of the GNU Affero General Public License as 11 * published by the Free Software Foundation, either version 3 of the 12 * License, or (at your option) any later version. 13 * 14 * This program is distributed in the hope that it will be useful, 15 * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 * GNU Affero General Public License for more details. 18 * 19 * You should have received a copy of the GNU Affero General Public License 20 * along with this program. If not, see <http://www.gnu.org/licenses/>. 21 * 22 */ 23 24namespace OCA\Talk\Notification; 25 26use OCA\FederatedFileSharing\AddressHandler; 27use OCA\Talk\Chat\CommentsManager; 28use OCA\Talk\Chat\MessageParser; 29use OCA\Talk\Config; 30use OCA\Talk\Exceptions\ParticipantNotFoundException; 31use OCA\Talk\Exceptions\RoomNotFoundException; 32use OCA\Talk\GuestManager; 33use OCA\Talk\Manager; 34use OCA\Talk\Model\Attendee; 35use OCA\Talk\Participant; 36use OCA\Talk\Room; 37use OCA\Talk\Service\ParticipantService; 38use OCP\Comments\ICommentsManager; 39use OCP\Comments\NotFoundException; 40use OCP\HintException; 41use OCP\IL10N; 42use OCP\IURLGenerator; 43use OCP\IUser; 44use OCP\IUserManager; 45use OCP\L10N\IFactory; 46use OCP\Notification\AlreadyProcessedException; 47use OCP\Notification\IAction; 48use OCP\Notification\IManager as INotificationManager; 49use OCP\Notification\INotification; 50use OCP\Notification\INotifier; 51use OCP\RichObjectStrings\Definitions; 52use OCP\Share\Exceptions\ShareNotFound; 53use OCP\Share\IManager as IShareManager; 54use OCP\Share\IShare; 55 56class Notifier implements INotifier { 57 58 /** @var IFactory */ 59 protected $lFactory; 60 /** @var IURLGenerator */ 61 protected $url; 62 /** @var Config */ 63 protected $config; 64 /** @var IUserManager */ 65 protected $userManager; 66 /** @var GuestManager */ 67 protected $guestManager; 68 /** @var IShareManager */ 69 private $shareManager; 70 /** @var Manager */ 71 protected $manager; 72 /** @var ParticipantService */ 73 protected $participantService; 74 /** @var INotificationManager */ 75 protected $notificationManager; 76 /** @var ICommentsManager */ 77 protected $commentManager; 78 /** @var MessageParser */ 79 protected $messageParser; 80 /** @var Definitions */ 81 protected $definitions; 82 /** @var AddressHandler */ 83 protected $addressHandler; 84 85 /** @var Room[] */ 86 protected $rooms = []; 87 /** @var Participant[][] */ 88 protected $participants = []; 89 90 public function __construct(IFactory $lFactory, 91 IURLGenerator $url, 92 Config $config, 93 IUserManager $userManager, 94 GuestManager $guestManager, 95 IShareManager $shareManager, 96 Manager $manager, 97 ParticipantService $participantService, 98 INotificationManager $notificationManager, 99 CommentsManager $commentManager, 100 MessageParser $messageParser, 101 Definitions $definitions, 102 AddressHandler $addressHandler) { 103 $this->lFactory = $lFactory; 104 $this->url = $url; 105 $this->config = $config; 106 $this->userManager = $userManager; 107 $this->guestManager = $guestManager; 108 $this->shareManager = $shareManager; 109 $this->manager = $manager; 110 $this->participantService = $participantService; 111 $this->notificationManager = $notificationManager; 112 $this->commentManager = $commentManager; 113 $this->messageParser = $messageParser; 114 $this->definitions = $definitions; 115 $this->addressHandler = $addressHandler; 116 } 117 118 /** 119 * Identifier of the notifier, only use [a-z0-9_] 120 * 121 * @return string 122 * @since 17.0.0 123 */ 124 public function getID(): string { 125 return 'talk'; 126 } 127 128 /** 129 * Human readable name describing the notifier 130 * 131 * @return string 132 * @since 17.0.0 133 */ 134 public function getName(): string { 135 return $this->lFactory->get('spreed')->t('Talk'); 136 } 137 138 /** 139 * @param string $objectId 140 * @param string $userId 141 * @return Room 142 * @throws RoomNotFoundException 143 */ 144 protected function getRoom(string $objectId, string $userId): Room { 145 if (array_key_exists($objectId, $this->rooms)) { 146 if ($this->rooms[$objectId] === null) { 147 throw new RoomNotFoundException('Room does not exist'); 148 } 149 150 return $this->rooms[$objectId]; 151 } 152 153 try { 154 $room = $this->manager->getRoomByToken($objectId, $userId); 155 $this->rooms[$objectId] = $room; 156 return $room; 157 } catch (RoomNotFoundException $e) { 158 if (!is_numeric($objectId)) { 159 // Room does not exist 160 $this->rooms[$objectId] = null; 161 throw $e; 162 } 163 164 try { 165 // Before 3.2.3 the id was passed in notifications 166 $room = $this->manager->getRoomById((int) $objectId); 167 $this->rooms[$objectId] = $room; 168 return $room; 169 } catch (RoomNotFoundException $e) { 170 // Room does not exist 171 $this->rooms[$objectId] = null; 172 throw $e; 173 } 174 } 175 } 176 177 /** 178 * @param Room $room 179 * @param string $userId 180 * @return Participant 181 * @throws ParticipantNotFoundException 182 */ 183 protected function getParticipant(Room $room, string $userId): Participant { 184 $roomId = $room->getId(); 185 if (array_key_exists($roomId, $this->participants) && array_key_exists($userId, $this->participants[$roomId])) { 186 if ($this->participants[$roomId][$userId] === null) { 187 throw new ParticipantNotFoundException('Participant does not exist'); 188 } 189 190 return $this->participants[$roomId][$userId]; 191 } 192 193 try { 194 $participant = $room->getParticipant($userId, false); 195 $this->participants[$roomId][$userId] = $participant; 196 return $participant; 197 } catch (ParticipantNotFoundException $e) { 198 // Participant does not exist 199 $this->participants[$roomId][$userId] = null; 200 throw $e; 201 } 202 } 203 204 /** 205 * @param INotification $notification 206 * @param string $languageCode The code of the language that should be used to prepare the notification 207 * @return INotification 208 * @throws \InvalidArgumentException When the notification was not prepared by a notifier 209 * @since 9.0.0 210 */ 211 public function prepare(INotification $notification, string $languageCode): INotification { 212 if ($notification->getApp() !== 'spreed') { 213 throw new \InvalidArgumentException('Incorrect app'); 214 } 215 216 $userId = $notification->getUser(); 217 $user = $this->userManager->get($userId); 218 if (!$user instanceof IUser || $this->config->isDisabledForUser($user)) { 219 throw new AlreadyProcessedException(); 220 } 221 222 $l = $this->lFactory->get('spreed', $languageCode); 223 224 if ($notification->getObjectType() === 'hosted-signaling-server') { 225 return $this->parseHostedSignalingServer($notification, $l); 226 } 227 228 try { 229 $room = $this->getRoom($notification->getObjectId(), $userId); 230 } catch (RoomNotFoundException $e) { 231 // Room does not exist 232 throw new AlreadyProcessedException(); 233 } 234 235 if ($this->notificationManager->isPreparingPushNotification() && $notification->getSubject() === 'call') { 236 // Skip the participant check when we generate push notifications 237 // we just looped over the participants to create the notification, 238 // they can not be removed between these 2 steps, but we can save 239 // n queries. 240 } else { 241 try { 242 $participant = $this->getParticipant($room, $userId); 243 } catch (ParticipantNotFoundException $e) { 244 // Room does not exist 245 throw new AlreadyProcessedException(); 246 } 247 } 248 249 $notification 250 ->setIcon($this->url->getAbsoluteURL($this->url->imagePath('spreed', 'app-dark.svg'))) 251 ->setLink($this->url->linkToRouteAbsolute('spreed.Page.showCall', ['token' => $room->getToken()])); 252 253 $subject = $notification->getSubject(); 254 if ($subject === 'invitation') { 255 return $this->parseInvitation($notification, $room, $l); 256 } 257 if ($subject === 'call') { 258 if ($room->getObjectType() === 'share:password') { 259 return $this->parsePasswordRequest($notification, $room, $l); 260 } 261 return $this->parseCall($notification, $room, $l); 262 } 263 if ($subject === 'reply' || $subject === 'mention' || $subject === 'chat') { 264 return $this->parseChatMessage($notification, $room, $participant, $l); 265 } 266 267 if ($subject === 'remote_talk_share') { 268 return $this->parseRemoteInvitationMessage($notification, $l); 269 } 270 271 $this->notificationManager->markProcessed($notification); 272 throw new \InvalidArgumentException('Unknown subject'); 273 } 274 275 protected function shortenJsonEncodedMultibyteSave(string $subject, int $dataLength): string { 276 $temp = mb_substr($subject, 0, $dataLength); 277 while (strlen(json_encode($temp)) > $dataLength) { 278 $temp = mb_substr($temp, 0, -5); 279 } 280 return $temp; 281 } 282 283 /** 284 * @throws HintException 285 */ 286 protected function parseRemoteInvitationMessage(INotification $notification, IL10N $l): INotification { 287 $subjectParameters = $notification->getSubjectParameters(); 288 289 [$sharedById, $sharedByServer] = $this->addressHandler->splitUserRemote($subjectParameters['sharedByFederatedId']); 290 291 $message = $l->t('{user1} shared room {roomName} on {remoteServer} with you'); 292 293 $rosParameters = [ 294 'user1' => [ 295 'type' => 'user', 296 'id' => $sharedById, 297 'name' => $subjectParameters['sharedByDisplayName'], 298 'server' => $sharedByServer, 299 ], 300 'roomName' => [ 301 'type' => 'highlight', 302 'id' => $subjectParameters['serverUrl'] . '::' . $subjectParameters['roomToken'], 303 'name' => $subjectParameters['roomName'], 304 ], 305 'remoteServer' => [ 306 'type' => 'highlight', 307 'id' => $subjectParameters['serverUrl'], 308 'name' => $subjectParameters['serverUrl'], 309 ] 310 ]; 311 312 $placeholders = $replacements = []; 313 foreach ($rosParameters as $placeholder => $parameter) { 314 $placeholders[] = '{' . $placeholder .'}'; 315 $replacements[] = $parameter['name']; 316 } 317 318 $notification->setParsedMessage(str_replace($placeholders, $replacements, $message)); 319 $notification->setRichMessage($message, $rosParameters); 320 321 return $notification; 322 } 323 324 /** 325 * @param INotification $notification 326 * @param Room $room 327 * @param Participant $participant 328 * @param IL10N $l 329 * @return INotification 330 * @throws \InvalidArgumentException 331 */ 332 protected function parseChatMessage(INotification $notification, Room $room, Participant $participant, IL10N $l): INotification { 333 if ($notification->getObjectType() !== 'chat') { 334 throw new \InvalidArgumentException('Unknown object type'); 335 } 336 337 $subjectParameters = $notification->getSubjectParameters(); 338 339 $richSubjectUser = null; 340 $isGuest = false; 341 if ($subjectParameters['userType'] === 'users') { 342 $userId = $subjectParameters['userId']; 343 $user = $this->userManager->get($userId); 344 345 if ($user instanceof IUser) { 346 $richSubjectUser = [ 347 'type' => 'user', 348 'id' => $userId, 349 'name' => $user->getDisplayName(), 350 ]; 351 } 352 } else { 353 $isGuest = true; 354 } 355 356 $richSubjectCall = [ 357 'type' => 'call', 358 'id' => $room->getId(), 359 'name' => $room->getDisplayName($notification->getUser()), 360 'call-type' => $this->getRoomType($room), 361 ]; 362 363 $messageParameters = $notification->getMessageParameters(); 364 if (!isset($messageParameters['commentId'])) { 365 throw new AlreadyProcessedException(); 366 } 367 368 try { 369 $comment = $this->commentManager->get($messageParameters['commentId']); 370 } catch (NotFoundException $e) { 371 throw new AlreadyProcessedException(); 372 } 373 374 $message = $this->messageParser->createMessage($room, $participant, $comment, $l); 375 $this->messageParser->parseMessage($message); 376 377 if (!$message->getVisibility()) { 378 throw new AlreadyProcessedException(); 379 } 380 381 $placeholders = $replacements = []; 382 foreach ($message->getMessageParameters() as $placeholder => $parameter) { 383 $placeholders[] = '{' . $placeholder . '}'; 384 if ($parameter['type'] === 'user' || $parameter['type'] === 'guest') { 385 $replacements[] = '@' . $parameter['name']; 386 } else { 387 $replacements[] = $parameter['name']; 388 } 389 } 390 391 $parsedMessage = str_replace($placeholders, $replacements, $message->getMessage()); 392 if (!$this->notificationManager->isPreparingPushNotification()) { 393 $notification->setParsedMessage($parsedMessage); 394 $notification->setRichMessage($message->getMessage(), $message->getMessageParameters()); 395 } 396 397 $richSubjectParameters = [ 398 'user' => $richSubjectUser, 399 'call' => $richSubjectCall, 400 ]; 401 402 if ($this->notificationManager->isPreparingPushNotification()) { 403 $shortenMessage = $this->shortenJsonEncodedMultibyteSave($parsedMessage, 100); 404 if ($shortenMessage !== $parsedMessage) { 405 $shortenMessage .= '…'; 406 } 407 $richSubjectParameters['message'] = [ 408 'type' => 'highlight', 409 'id' => $message->getComment()->getId(), 410 'name' => $shortenMessage, 411 ]; 412 if ($room->getType() === Room::TYPE_ONE_TO_ONE) { 413 $subject = "{user}\n{message}"; 414 } elseif ($richSubjectUser) { 415 $subject = $l->t('{user} in {call}') . "\n{message}"; 416 } elseif (!$isGuest) { 417 $subject = $l->t('Deleted user in {call}') . "\n{message}"; 418 } else { 419 try { 420 $richSubjectParameters['guest'] = $this->getGuestParameter($room, $comment->getActorId()); 421 $subject = $l->t('{guest} (guest) in {call}') . "\n{message}"; 422 } catch (ParticipantNotFoundException $e) { 423 $subject = $l->t('Guest in {call}') . "\n{message}"; 424 } 425 } 426 } elseif ($notification->getSubject() === 'chat') { 427 if ($room->getType() === Room::TYPE_ONE_TO_ONE) { 428 $subject = $l->t('{user} sent you a private message'); 429 } elseif ($richSubjectUser) { 430 $subject = $l->t('{user} sent a message in conversation {call}'); 431 } elseif (!$isGuest) { 432 $subject = $l->t('A deleted user sent a message in conversation {call}'); 433 } else { 434 try { 435 $richSubjectParameters['guest'] = $this->getGuestParameter($room, $comment->getActorId()); 436 $subject = $l->t('{guest} (guest) sent a message in conversation {call}'); 437 } catch (ParticipantNotFoundException $e) { 438 $subject = $l->t('A guest sent a message in conversation {call}'); 439 } 440 } 441 } elseif ($notification->getSubject() === 'reply') { 442 if ($room->getType() === Room::TYPE_ONE_TO_ONE) { 443 $subject = $l->t('{user} replied to your private message'); 444 } elseif ($richSubjectUser) { 445 $subject = $l->t('{user} replied to your message in conversation {call}'); 446 } elseif (!$isGuest) { 447 $subject = $l->t('A deleted user replied to your message in conversation {call}'); 448 } else { 449 try { 450 $richSubjectParameters['guest'] = $this->getGuestParameter($room, $comment->getActorId()); 451 $subject = $l->t('{guest} (guest) replied to your message in conversation {call}'); 452 } catch (ParticipantNotFoundException $e) { 453 $subject = $l->t('A guest replied to your message in conversation {call}'); 454 } 455 } 456 } elseif ($room->getType() === Room::TYPE_ONE_TO_ONE) { 457 $subject = $l->t('{user} mentioned you in a private conversation'); 458 } elseif ($richSubjectUser) { 459 $subject = $l->t('{user} mentioned you in conversation {call}'); 460 } elseif (!$isGuest) { 461 $subject = $l->t('A deleted user mentioned you in conversation {call}'); 462 } else { 463 try { 464 $richSubjectParameters['guest'] = $this->getGuestParameter($room, $comment->getActorId()); 465 $subject = $l->t('{guest} (guest) mentioned you in conversation {call}'); 466 } catch (ParticipantNotFoundException $e) { 467 $subject = $l->t('A guest mentioned you in conversation {call}'); 468 } 469 } 470 $notification = $this->addActionButton($notification, $l->t('View chat'), false); 471 472 if ($richSubjectParameters['user'] === null) { 473 unset($richSubjectParameters['user']); 474 } 475 476 $placeholders = $replacements = []; 477 foreach ($richSubjectParameters as $placeholder => $parameter) { 478 $placeholders[] = '{' . $placeholder . '}'; 479 $replacements[] = $parameter['name']; 480 } 481 482 $notification->setParsedSubject(str_replace($placeholders, $replacements, $subject)) 483 ->setRichSubject($subject, $richSubjectParameters); 484 485 return $notification; 486 } 487 488 /** 489 * @param Room $room 490 * @param string $actorId 491 * @return array 492 * @throws ParticipantNotFoundException 493 */ 494 protected function getGuestParameter(Room $room, string $actorId): array { 495 $participant = $room->getParticipantByActor(Attendee::ACTOR_GUESTS, $actorId, false); 496 $name = $participant->getAttendee()->getDisplayName(); 497 if (trim($name) === '') { 498 throw new ParticipantNotFoundException('Empty name'); 499 } 500 501 return [ 502 'type' => 'guest', 503 'id' => $actorId, 504 'name' => $name, 505 ]; 506 } 507 508 /** 509 * @param Room $room 510 * @return string 511 * @throws \InvalidArgumentException 512 */ 513 protected function getRoomType(Room $room): string { 514 switch ($room->getType()) { 515 case Room::TYPE_ONE_TO_ONE: 516 return 'one2one'; 517 case Room::TYPE_GROUP: 518 return 'group'; 519 case Room::TYPE_PUBLIC: 520 return 'public'; 521 default: 522 throw new \InvalidArgumentException('Unknown room type'); 523 } 524 } 525 526 /** 527 * @param INotification $notification 528 * @param Room $room 529 * @param IL10N $l 530 * @return INotification 531 * @throws \InvalidArgumentException 532 * @throws AlreadyProcessedException 533 */ 534 protected function parseInvitation(INotification $notification, Room $room, IL10N $l): INotification { 535 if ($notification->getObjectType() !== 'room') { 536 throw new \InvalidArgumentException('Unknown object type'); 537 } 538 539 $parameters = $notification->getSubjectParameters(); 540 $uid = $parameters['actorId'] ?? $parameters[0]; 541 542 $user = $this->userManager->get($uid); 543 if (!$user instanceof IUser) { 544 throw new AlreadyProcessedException(); 545 } 546 547 $roomName = $room->getDisplayName($notification->getUser()); 548 if ($room->getType() === Room::TYPE_ONE_TO_ONE) { 549 $subject = $l->t('{user} invited you to a private conversation'); 550 if ($this->participantService->hasActiveSessionsInCall($room)) { 551 $notification = $this->addActionButton($notification, $l->t('Join call')); 552 } else { 553 $notification = $this->addActionButton($notification, $l->t('View chat'), false); 554 } 555 556 $notification 557 ->setParsedSubject(str_replace('{user}', $user->getDisplayName(), $subject)) 558 ->setRichSubject( 559 $subject, [ 560 'user' => [ 561 'type' => 'user', 562 'id' => $uid, 563 'name' => $user->getDisplayName(), 564 ], 565 'call' => [ 566 'type' => 'call', 567 'id' => $room->getId(), 568 'name' => $roomName, 569 'call-type' => $this->getRoomType($room), 570 ], 571 ] 572 ); 573 } elseif (\in_array($room->getType(), [Room::TYPE_GROUP, Room::TYPE_PUBLIC], true)) { 574 $subject = $l->t('{user} invited you to a group conversation: {call}'); 575 if ($this->participantService->hasActiveSessionsInCall($room)) { 576 $notification = $this->addActionButton($notification, $l->t('Join call')); 577 } else { 578 $notification = $this->addActionButton($notification, $l->t('View chat'), false); 579 } 580 581 $notification 582 ->setParsedSubject(str_replace(['{user}', '{call}'], [$user->getDisplayName(), $roomName], $subject)) 583 ->setRichSubject( 584 $subject, [ 585 'user' => [ 586 'type' => 'user', 587 'id' => $uid, 588 'name' => $user->getDisplayName(), 589 ], 590 'call' => [ 591 'type' => 'call', 592 'id' => $room->getId(), 593 'name' => $roomName, 594 'call-type' => $this->getRoomType($room), 595 ], 596 ] 597 ); 598 } else { 599 throw new AlreadyProcessedException(); 600 } 601 602 return $notification; 603 } 604 605 /** 606 * @param INotification $notification 607 * @param Room $room 608 * @param IL10N $l 609 * @return INotification 610 * @throws \InvalidArgumentException 611 * @throws AlreadyProcessedException 612 */ 613 protected function parseCall(INotification $notification, Room $room, IL10N $l): INotification { 614 if ($notification->getObjectType() !== 'call') { 615 throw new \InvalidArgumentException('Unknown object type'); 616 } 617 618 $roomName = $room->getDisplayName($notification->getUser()); 619 if ($room->getType() === Room::TYPE_ONE_TO_ONE) { 620 $parameters = $notification->getSubjectParameters(); 621 $calleeId = $parameters['callee']; 622 $user = $this->userManager->get($calleeId); 623 if ($user instanceof IUser) { 624 if ($this->notificationManager->isPreparingPushNotification() || $this->participantService->hasActiveSessionsInCall($room)) { 625 $notification = $this->addActionButton($notification, $l->t('Answer call')); 626 $subject = $l->t('{user} would like to talk with you'); 627 } else { 628 $notification = $this->addActionButton($notification, $l->t('Call back')); 629 $subject = $l->t('You missed a call from {user}'); 630 } 631 632 $notification 633 ->setParsedSubject(str_replace('{user}', $user->getDisplayName(), $subject)) 634 ->setRichSubject( 635 $subject, [ 636 'user' => [ 637 'type' => 'user', 638 'id' => $calleeId, 639 'name' => $user->getDisplayName(), 640 ], 641 'call' => [ 642 'type' => 'call', 643 'id' => $room->getId(), 644 'name' => $roomName, 645 'call-type' => $this->getRoomType($room), 646 ], 647 ] 648 ); 649 } else { 650 throw new AlreadyProcessedException(); 651 } 652 } elseif (\in_array($room->getType(), [Room::TYPE_GROUP, Room::TYPE_PUBLIC], true)) { 653 if ($this->notificationManager->isPreparingPushNotification() || $this->participantService->hasActiveSessionsInCall($room)) { 654 $notification = $this->addActionButton($notification, $l->t('Join call')); 655 $subject = $l->t('A group call has started in {call}'); 656 } else { 657 $notification = $this->addActionButton($notification, $l->t('View chat'), false); 658 $subject = $l->t('You missed a group call in {call}'); 659 } 660 661 $notification 662 ->setParsedSubject(str_replace('{call}', $roomName, $subject)) 663 ->setRichSubject( 664 $subject, [ 665 'call' => [ 666 'type' => 'call', 667 'id' => $room->getId(), 668 'name' => $roomName, 669 'call-type' => $this->getRoomType($room), 670 ], 671 ] 672 ); 673 } else { 674 throw new AlreadyProcessedException(); 675 } 676 677 return $notification; 678 } 679 680 /** 681 * @param INotification $notification 682 * @param Room $room 683 * @param IL10N $l 684 * @return INotification 685 * @throws \InvalidArgumentException 686 * @throws AlreadyProcessedException 687 */ 688 protected function parsePasswordRequest(INotification $notification, Room $room, IL10N $l): INotification { 689 if ($notification->getObjectType() !== 'call') { 690 throw new \InvalidArgumentException('Unknown object type'); 691 } 692 693 try { 694 $share = $this->shareManager->getShareByToken($room->getObjectId()); 695 } catch (ShareNotFound $e) { 696 throw new AlreadyProcessedException(); 697 } 698 699 try { 700 $file = [ 701 'type' => 'highlight', 702 'id' => $share->getNodeId(), 703 'name' => $share->getNode()->getName(), 704 ]; 705 } catch (\OCP\Files\NotFoundException $e) { 706 throw new AlreadyProcessedException(); 707 } 708 709 $callIsActive = $this->notificationManager->isPreparingPushNotification() || $this->participantService->hasActiveSessionsInCall($room); 710 if ($callIsActive) { 711 $notification = $this->addActionButton($notification, $l->t('Answer call')); 712 } else { 713 $notification = $this->addActionButton($notification, $l->t('Call back')); 714 } 715 716 if ($share->getShareType() === IShare::TYPE_EMAIL) { 717 $sharedWith = $share->getSharedWith(); 718 if ($callIsActive) { 719 $subject = $l->t('{email} is requesting the password to access {file}'); 720 } else { 721 $subject = $l->t('{email} tried to request the password to access {file}'); 722 } 723 724 $notification 725 ->setParsedSubject(str_replace(['{email}', '{file}'], [$sharedWith, $file['name']], $subject)) 726 ->setRichSubject($subject, [ 727 'email' => [ 728 'type' => 'email', 729 'id' => $sharedWith, 730 'name' => $sharedWith, 731 ], 732 'file' => $file, 733 ] 734 ); 735 } else { 736 if ($callIsActive) { 737 $subject = $l->t('Someone is requesting the password to access {file}'); 738 } else { 739 $subject = $l->t('Someone tried to request the password to access {file}'); 740 } 741 742 $notification 743 ->setParsedSubject(str_replace('{file}', $file['name'], $subject)) 744 ->setRichSubject($subject, ['file' => $file]); 745 } 746 747 return $notification; 748 } 749 750 protected function addActionButton(INotification $notification, string $label, bool $primary = true): INotification { 751 $action = $notification->createAction(); 752 $action->setLabel($label) 753 ->setParsedLabel($label) 754 ->setLink($notification->getLink(), IAction::TYPE_WEB) 755 ->setPrimary($primary); 756 757 $notification->addParsedAction($action); 758 759 return $notification; 760 } 761 762 protected function parseHostedSignalingServer(INotification $notification, IL10N $l): INotification { 763 $action = $notification->createAction(); 764 $action->setLabel('open_settings') 765 ->setParsedLabel($l->t('Open settings')) 766 ->setLink($notification->getLink(), IAction::TYPE_WEB) 767 ->setPrimary(true); 768 769 switch ($notification->getSubject()) { 770 case 'added': 771 $subject = $l->t('The hosted signaling server is now configured and will be used.'); 772 break; 773 case 'removed': 774 $subject = $l->t('The hosted signaling server was removed and will not be used anymore.'); 775 break; 776 case 'changed-status': 777 $subject = $l->t('The hosted signaling server account has changed the status from "{oldstatus}" to "{newstatus}".'); 778 779 $parameters = $notification->getSubjectParameters(); 780 $subject = str_replace( 781 ['{oldstatus}', '{newstatus}'], 782 [$parameters['oldstatus'], $parameters['newstatus']], 783 $subject 784 ); 785 break; 786 default: 787 throw new \InvalidArgumentException('Unknown subject'); 788 } 789 790 return $notification 791 ->setParsedSubject($subject) 792 ->setIcon($notification->getIcon()) 793 ->addParsedAction($action); 794 } 795} 796