* * @license GNU AGPL version 3 or any later version * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . * */ namespace OCA\Talk; use Doctrine\DBAL\Exception; use OCA\Talk\Events\AddEmailEvent; use OCA\Talk\Events\ModifyParticipantEvent; use OCA\Talk\Model\Attendee; use OCA\Talk\Exceptions\ParticipantNotFoundException; use OCP\DB\QueryBuilder\IQueryBuilder; use OCP\Defaults; use OCP\EventDispatcher\IEventDispatcher; use OCP\IDBConnection; use OCP\IL10N; use OCP\IURLGenerator; use OCP\IUser; use OCP\IUserSession; use OCP\Mail\IMailer; use OCP\Util; class GuestManager { public const EVENT_BEFORE_EMAIL_INVITE = self::class . '::preInviteByEmail'; public const EVENT_AFTER_EMAIL_INVITE = self::class . '::postInviteByEmail'; public const EVENT_AFTER_NAME_UPDATE = self::class . '::updateName'; /** @var IDBConnection */ protected $connection; /** @var Config */ protected $talkConfig; /** @var IMailer */ protected $mailer; /** @var Defaults */ protected $defaults; /** @var IUserSession */ protected $userSession; /** @var IURLGenerator */ protected $url; /** @var IL10N */ protected $l; /** @var IEventDispatcher */ protected $dispatcher; public function __construct(IDBConnection $connection, Config $talkConfig, IMailer $mailer, Defaults $defaults, IUserSession $userSession, IURLGenerator $url, IL10N $l, IEventDispatcher $dispatcher) { $this->connection = $connection; $this->talkConfig = $talkConfig; $this->mailer = $mailer; $this->defaults = $defaults; $this->userSession = $userSession; $this->url = $url; $this->l = $l; $this->dispatcher = $dispatcher; } /** * @param Room $room * @param Participant $participant * @param string $displayName * @throws Exception */ public function updateName(Room $room, Participant $participant, string $displayName): void { $sessionHash = $participant->getAttendee()->getActorId(); $dispatchEvent = true; try { $oldName = $this->getNameBySessionHash($sessionHash, true); if ($oldName !== $displayName) { $query = $this->connection->getQueryBuilder(); $query->update('talk_guestnames') ->set('display_name', $query->createNamedParameter($displayName)) ->where($query->expr()->eq('session_hash', $query->createNamedParameter($sessionHash))); $query->execute(); } else { $dispatchEvent = false; } } catch (ParticipantNotFoundException $e) { $this->connection->insertIfNotExist('*PREFIX*talk_guestnames', [ 'session_hash' => $sessionHash, 'display_name' => $displayName, ], ['session_hash']); } if ($dispatchEvent) { $event = new ModifyParticipantEvent($room, $participant, 'name', $displayName); $this->dispatcher->dispatch(self::EVENT_AFTER_NAME_UPDATE, $event); } } /** * @param string $sessionHash * @param bool $allowEmpty * @return string * @throws ParticipantNotFoundException */ public function getNameBySessionHash(string $sessionHash, bool $allowEmpty = false): string { $query = $this->connection->getQueryBuilder(); $query->select('display_name') ->from('talk_guestnames') ->where($query->expr()->eq('session_hash', $query->createNamedParameter($sessionHash))); $result = $query->execute(); $row = $result->fetch(); $result->closeCursor(); if (isset($row['display_name']) && ($allowEmpty || $row['display_name'] !== '')) { return $row['display_name']; } throw new ParticipantNotFoundException(); } /** * @param string[] $sessionHashes * @return string[] */ public function getNamesBySessionHashes(array $sessionHashes): array { if (empty($sessionHashes)) { return []; } $query = $this->connection->getQueryBuilder(); $query->select('*') ->from('talk_guestnames') ->where($query->expr()->in('session_hash', $query->createNamedParameter($sessionHashes, IQueryBuilder::PARAM_STR_ARRAY))); $result = $query->execute(); $map = []; while ($row = $result->fetch()) { if ($row['display_name'] === '') { continue; } $map[$row['session_hash']] = $row['display_name']; } $result->closeCursor(); return $map; } public function sendEmailInvitation(Room $room, Participant $participant): void { if ($participant->getAttendee()->getActorType() !== Attendee::ACTOR_EMAILS) { throw new \InvalidArgumentException('Cannot send email for non-email participant actor type'); } $email = $participant->getAttendee()->getActorId(); $pin = $participant->getAttendee()->getPin(); $event = new AddEmailEvent($room, $email); $this->dispatcher->dispatch(self::EVENT_BEFORE_EMAIL_INVITE, $event); $link = $this->url->linkToRouteAbsolute('spreed.Page.showCall', ['token' => $room->getToken()]); $message = $this->mailer->createMessage(); $user = $this->userSession->getUser(); $invitee = $user instanceof IUser ? $user->getDisplayName() : ''; $template = $this->mailer->createEMailTemplate('Talk.InviteByEmail', [ 'invitee' => $invitee, 'roomName' => $room->getDisplayName(''), 'roomLink' => $link, 'email' => $email, 'pin' => $pin, ]); if ($user instanceof IUser) { $subject = $this->l->t('%s invited you to a conversation.', $user->getDisplayName()); $message->setFrom([Util::getDefaultEmailAddress('no-reply') => $user->getDisplayName()]); } else { $subject = $this->l->t('You were invited to a conversation.'); $message->setFrom([Util::getDefaultEmailAddress('no-reply') => $this->defaults->getName()]); } $template->setSubject($subject); $template->addHeader(); $template->addHeading($this->l->t('Conversation invitation')); $template->addBodyText( htmlspecialchars($subject . ' ' . $this->l->t('Click the button below to join.')), $subject ); $template->addBodyButton( $this->l->t('Join »%s«', [$room->getDisplayName('')]), $link ); if ($pin) { $template->addBodyText($this->l->t('You can also dial-in via phone with the following details')); $template->addBodyListItem( $this->talkConfig->getDialInInfo(), $this->l->t('Dial-in information'), $this->url->getAbsoluteURL($this->url->imagePath('spreed', 'phone.png')) ); $template->addBodyListItem( $room->getToken(), $this->l->t('Meeting ID'), $this->url->getAbsoluteURL($this->url->imagePath('core', 'places/calendar-dark.png')) ); $template->addBodyListItem( $pin, $this->l->t('Your PIN'), $this->url->getAbsoluteURL($this->url->imagePath('core', 'actions/password.png')) ); } $template->addFooter(); $message->setTo([$email]); $message->useTemplate($template); try { $this->mailer->send($message); $this->dispatcher->dispatch(self::EVENT_AFTER_EMAIL_INVITE, $event); } catch (\Exception $e) { } } }