diff options
Diffstat (limited to 'lib')
-rw-r--r-- | lib/Chat/Parser/Command.php | 3 | ||||
-rw-r--r-- | lib/Chat/Parser/SystemMessage.php | 26 | ||||
-rw-r--r-- | lib/Chat/Parser/UserMention.php | 2 | ||||
-rw-r--r-- | lib/Controller/ChatController.php | 31 | ||||
-rw-r--r-- | lib/Controller/RoomController.php | 230 | ||||
-rw-r--r-- | lib/Controller/SignalingController.php | 7 | ||||
-rw-r--r-- | lib/Manager.php | 57 | ||||
-rw-r--r-- | lib/Middleware/InjectionMiddleware.php | 4 | ||||
-rw-r--r-- | lib/Migration/Version10000Date20201015134000.php | 13 | ||||
-rw-r--r-- | lib/Model/Attendee.php | 113 | ||||
-rw-r--r-- | lib/Model/AttendeeMapper.php | 72 | ||||
-rw-r--r-- | lib/Model/Session.php | 71 | ||||
-rw-r--r-- | lib/Model/SessionMapper.php | 64 | ||||
-rw-r--r-- | lib/Participant.php | 174 | ||||
-rw-r--r-- | lib/Room.php | 35 | ||||
-rw-r--r-- | lib/Service/SessionService.php | 60 |
16 files changed, 644 insertions, 318 deletions
diff --git a/lib/Chat/Parser/Command.php b/lib/Chat/Parser/Command.php index 4e093c269..1e321d8d8 100644 --- a/lib/Chat/Parser/Command.php +++ b/lib/Chat/Parser/Command.php @@ -44,7 +44,8 @@ class Command { $participant = $message->getParticipant(); if ($data['visibility'] !== \OCA\Talk\Model\Command::RESPONSE_ALL && - $data['user'] !== $participant->getUser()) { + ($participant->getAttendee()->getActorType() !== 'users' + || $data['user'] !== $participant->getAttendee()->getActorId())) { $message->setVisibility(false); return; } diff --git a/lib/Chat/Parser/SystemMessage.php b/lib/Chat/Parser/SystemMessage.php index c69aeaf95..e9509b722 100644 --- a/lib/Chat/Parser/SystemMessage.php +++ b/lib/Chat/Parser/SystemMessage.php @@ -92,11 +92,15 @@ class SystemMessage { $participant = $chatMessage->getParticipant(); if (!$participant->isGuest()) { + $currentActorId = $participant->getAttendee()->getActorId(); $currentUserIsActor = $parsedParameters['actor']['type'] === 'user' && - $participant->getUser() === $parsedParameters['actor']['id']; + $participant->getAttendee()->getActorType() === 'users' && + $currentActorId === $parsedParameters['actor']['id']; } else { $currentUserIsActor = $parsedParameters['actor']['type'] === 'guest' && - sha1($participant->getSessionId()) === $parsedParameters['actor']['id']; + $participant->getAttendee()->getActorType() === 'guest' && + $participant->getAttendee()->getActorId() === $parsedParameters['actor']['id']; + $currentActorId = null; } $cliIsActor = $parsedParameters['actor']['type'] === 'guest' && 'guest/cli' === $parsedParameters['actor']['id']; @@ -197,7 +201,7 @@ class SystemMessage { } } elseif ($currentUserIsActor) { $parsedMessage = $this->l->t('You added {user}'); - } elseif (!$participant->isGuest() && $participant->getUser() === $parsedParameters['user']['id']) { + } elseif (!$participant->isGuest() && $currentActorId === $parsedParameters['user']['id']) { $parsedMessage = $this->l->t('{actor} added you'); if ($cliIsActor) { $parsedMessage = $this->l->t('An administrator added you'); @@ -217,7 +221,7 @@ class SystemMessage { $parsedMessage = $this->l->t('{actor} removed {user}'); if ($currentUserIsActor) { $parsedMessage = $this->l->t('You removed {user}'); - } elseif (!$participant->isGuest() && $participant->getUser() === $parsedParameters['user']['id']) { + } elseif (!$participant->isGuest() && $currentActorId === $parsedParameters['user']['id']) { $parsedMessage = $this->l->t('{actor} removed you'); if ($cliIsActor) { $parsedMessage = $this->l->t('An administrator removed you'); @@ -231,7 +235,7 @@ class SystemMessage { $parsedMessage = $this->l->t('{actor} promoted {user} to moderator'); if ($currentUserIsActor) { $parsedMessage = $this->l->t('You promoted {user} to moderator'); - } elseif (!$participant->isGuest() && $participant->getUser() === $parsedParameters['user']['id']) { + } elseif (!$participant->isGuest() && $currentActorId === $parsedParameters['user']['id']) { $parsedMessage = $this->l->t('{actor} promoted you to moderator'); if ($cliIsActor) { $parsedMessage = $this->l->t('An administrator promoted you to moderator'); @@ -244,7 +248,7 @@ class SystemMessage { $parsedMessage = $this->l->t('{actor} demoted {user} from moderator'); if ($currentUserIsActor) { $parsedMessage = $this->l->t('You demoted {user} from moderator'); - } elseif (!$participant->isGuest() && $participant->getUser() === $parsedParameters['user']['id']) { + } elseif (!$participant->isGuest() && $currentActorId === $parsedParameters['user']['id']) { $parsedMessage = $this->l->t('{actor} demoted you from moderator'); if ($cliIsActor) { $parsedMessage = $this->l->t('An administrator demoted you from moderator'); @@ -257,7 +261,7 @@ class SystemMessage { $parsedMessage = $this->l->t('{actor} promoted {user} to moderator'); if ($currentUserIsActor) { $parsedMessage = $this->l->t('You promoted {user} to moderator'); - } elseif ($participant->isGuest() && $participant->getSessionId() === $parsedParameters['user']['id']) { + } elseif ($participant->isGuest() && $currentActorId === $parsedParameters['user']['id']) { $parsedMessage = $this->l->t('{actor} promoted you to moderator'); if ($cliIsActor) { $parsedMessage = $this->l->t('An administrator promoted you to moderator'); @@ -270,7 +274,7 @@ class SystemMessage { $parsedMessage = $this->l->t('{actor} demoted {user} from moderator'); if ($currentUserIsActor) { $parsedMessage = $this->l->t('You demoted {user} from moderator'); - } elseif ($participant->isGuest() && $participant->getSessionId() === $parsedParameters['user']['id']) { + } elseif ($participant->isGuest() && $currentActorId === $parsedParameters['user']['id']) { $parsedMessage = $this->l->t('{actor} demoted you from moderator'); if ($cliIsActor) { $parsedMessage = $this->l->t('An administrator demoted you from moderator'); @@ -327,8 +331,8 @@ class SystemMessage { $path = $name; if (!$participant->isGuest()) { - if ($share->getShareOwner() !== $participant->getUser()) { - $userFolder = $this->rootFolder->getUserFolder($participant->getUser()); + if ($share->getShareOwner() !== $participant->getAttendee()->getActorId()) { + $userFolder = $this->rootFolder->getUserFolder($participant->getAttendee()->getActorId()); if ($userFolder instanceof Node) { $userNodes = $userFolder->getById($node->getId()); @@ -337,7 +341,7 @@ class SystemMessage { // 1. Only be executed on "Waiting for new messages" // 2. Once per request \OC_Util::tearDownFS(); - \OC_Util::setupFS($participant->getUser()); + \OC_Util::setupFS($participant->ggetAttendee()->getActorId()); $userNodes = $userFolder->getById($node->getId()); } diff --git a/lib/Chat/Parser/UserMention.php b/lib/Chat/Parser/UserMention.php index 9f83f996e..4d5862ef9 100644 --- a/lib/Chat/Parser/UserMention.php +++ b/lib/Chat/Parser/UserMention.php @@ -118,7 +118,7 @@ class UserMention { $messageParameters[$mentionParameterId] = [ 'type' => $mention['type'], 'id' => $chatMessage->getRoom()->getToken(), - 'name' => $chatMessage->getRoom()->getDisplayName($chatMessage->getParticipant()->getUser()), + 'name' => $chatMessage->getRoom()->getDisplayName($chatMessage->getParticipant()->getAttendee()->getActorId()), 'call-type' => $this->getRoomType($chatMessage->getRoom()), ]; } elseif ($mention['type'] === 'guest') { diff --git a/lib/Controller/ChatController.php b/lib/Controller/ChatController.php index 6aaf30d8b..8a5d48066 100644 --- a/lib/Controller/ChatController.php +++ b/lib/Controller/ChatController.php @@ -29,6 +29,7 @@ use OCA\Talk\Chat\AutoComplete\Sorter; use OCA\Talk\Chat\ChatManager; use OCA\Talk\Chat\MessageParser; use OCA\Talk\GuestManager; +use OCA\Talk\Model\AttendeeMapper; use OCA\Talk\Model\Message; use OCA\Talk\Participant; use OCA\Talk\Room; @@ -67,6 +68,9 @@ class ChatController extends AEnvironmentAwareController { /** @var ChatManager */ private $chatManager; + /** @var AttendeeMapper */ + private $attendeeMapper; + /** @var GuestManager */ private $guestManager; @@ -103,6 +107,7 @@ class ChatController extends AEnvironmentAwareController { TalkSession $session, IAppManager $appManager, ChatManager $chatManager, + AttendeeMapper $attendeeMapper, GuestManager $guestManager, MessageParser $messageParser, IManager $autoCompleteManager, @@ -119,6 +124,7 @@ class ChatController extends AEnvironmentAwareController { $this->session = $session; $this->appManager = $appManager; $this->chatManager = $chatManager; + $this->attendeeMapper = $attendeeMapper; $this->guestManager = $guestManager; $this->messageParser = $messageParser; $this->autoCompleteManager = $autoCompleteManager; @@ -206,7 +212,9 @@ class ChatController extends AEnvironmentAwareController { return new DataResponse([], Http::STATUS_CREATED); } - $this->participant->setLastReadMessage((int) $comment->getId()); + $attendee = $this->participant->getAttendee(); + $attendee->setLastReadMessage((int) $comment->getId()); + $this->attendeeMapper->update($attendee); $data = $chatMessage->toArray(); if ($parentMessage instanceof Message) { @@ -299,9 +307,12 @@ class ChatController extends AEnvironmentAwareController { * we only update the read marker to the last known id, when it is higher * then the current read marker. */ + + $attendee = $this->participant->getAttendee(); if ($lookIntoFuture && $setReadMarker === 1 && - $lastKnownMessageId > $this->participant->getLastReadMessage()) { - $this->participant->setLastReadMessage($lastKnownMessageId); + $lastKnownMessageId > $attendee->getLastReadMessage()) { + $attendee->setLastReadMessage($lastKnownMessageId); + $this->attendeeMapper->update($attendee); } $currentUser = $this->userManager->get($this->userId); @@ -393,14 +404,16 @@ class ChatController extends AEnvironmentAwareController { if ($newLastKnown instanceof IComment) { $response->addHeader('X-Chat-Last-Given', $newLastKnown->getId()); /** - * This false set the read marker on new messages although you + * This falsely set the read marker on new messages although you * navigated away to a different chat already. So we removed this * and instead update the read marker before your next waiting. * So when you are still there, it will just have a wrong read * marker for the time until your next request starts, while it will * not update the value, when you actually left the chat already. * if ($setReadMarker === 1 && $lookIntoFuture) { - * $this->participant->setLastReadMessage((int) $newLastKnown->getId()); + * $attendee = $this->participant->getAttendee(); + * $attendee->setLastReadMessage((int) $newLastKnown->getId()); + * $this->attendeeMapper->update($attendee); * } */ } @@ -416,7 +429,9 @@ class ChatController extends AEnvironmentAwareController { * @return DataResponse */ public function setReadMarker(int $lastReadMessage): DataResponse { - $this->participant->setLastReadMessage($lastReadMessage); + $attendee = $this->participant->getAttendee(); + $attendee->setLastReadMessage($lastReadMessage); + $this->attendeeMapper->update($attendee); return new DataResponse(); } @@ -464,7 +479,9 @@ class ChatController extends AEnvironmentAwareController { $results = $this->prepareResultArray($results, $statuses); - $roomDisplayName = $this->room->getDisplayName($this->participant->getUser()); + $attendee = $this->participant->getAttendee(); + $userId = $attendee->getActorType() === 'users' ? $attendee->getActorId() : ''; + $roomDisplayName = $this->room->getDisplayName($userId); if (($search === '' || strpos('all', $search) !== false || stripos($roomDisplayName, $search) !== false) && $this->room->getType() !== Room::ONE_TO_ONE_CALL) { if ($search === '' || stripos($roomDisplayName, $search) === 0 || diff --git a/lib/Controller/RoomController.php b/lib/Controller/RoomController.php index 54e1edda6..30a0de3fd 100644 --- a/lib/Controller/RoomController.php +++ b/lib/Controller/RoomController.php @@ -40,6 +40,8 @@ use OCA\Talk\Exceptions\RoomNotFoundException; use OCA\Talk\Exceptions\UnauthorizedException; use OCA\Talk\GuestManager; use OCA\Talk\Manager; +use OCA\Talk\Model\AttendeeMapper; +use OCA\Talk\Model\Session; use OCA\Talk\Participant; use OCA\Talk\Room; use OCA\Talk\Service\RoomService; @@ -79,6 +81,8 @@ class RoomController extends AEnvironmentAwareController { protected $manager; /** @var RoomService */ protected $roomService; + /** @var AttendeeMapper */ + protected $attendeeMapper; /** @var GuestManager */ protected $guestManager; /** @var IUserStatusManager */ @@ -107,6 +111,7 @@ class RoomController extends AEnvironmentAwareController { IGroupManager $groupManager, Manager $manager, RoomService $roomService, + AttendeeMapper $attendeeMapper, GuestManager $guestManager, IUserStatusManager $statusManager, ChatManager $chatManager, @@ -124,6 +129,7 @@ class RoomController extends AEnvironmentAwareController { $this->groupManager = $groupManager; $this->manager = $manager; $this->roomService = $roomService; + $this->attendeeMapper = $attendeeMapper; $this->guestManager = $guestManager; $this->statusManager = $statusManager; $this->chatManager = $chatManager; @@ -332,6 +338,9 @@ class RoomController extends AEnvironmentAwareController { return $roomData; } + $attendee = $currentParticipant->getAttendee(); + $userId = $attendee->getActorType() === 'users' ? $attendee->getActorId() : ''; + $lastActivity = $room->getLastActivity(); if ($lastActivity instanceof \DateTimeInterface) { $lastActivity = $lastActivity->getTimestamp(); @@ -348,25 +357,31 @@ class RoomController extends AEnvironmentAwareController { $roomData = array_merge($roomData, [ 'name' => $room->getName(), - 'displayName' => $room->getDisplayName($currentParticipant->getUser()), + 'displayName' => $room->getDisplayName($userId), 'objectType' => $room->getObjectType(), 'objectId' => $room->getObjectId(), - 'participantType' => $currentParticipant->getParticipantType(), - // Deprecated, use participantFlags instead. - 'participantInCall' => ($currentParticipant->getInCallFlags() & Participant::FLAG_IN_CALL) !== 0, - 'participantFlags' => $currentParticipant->getInCallFlags(), + 'participantType' => $attendee->getParticipantType(), 'readOnly' => $room->getReadOnly(), 'count' => 0, // Deprecated, remove in future API version 'hasCall' => $room->getActiveSince() instanceof \DateTimeInterface, 'lastActivity' => $lastActivity, - 'isFavorite' => $currentParticipant->isFavorite(), - 'notificationLevel' => $currentParticipant->getNotificationLevel(), + 'isFavorite' => $attendee->isFavorite(), + 'notificationLevel' => $attendee->getNotificationLevel(), 'lobbyState' => $room->getLobbyState(), 'lobbyTimer' => $lobbyTimer, - 'lastPing' => $currentParticipant->getLastPing(), - 'sessionId' => $currentParticipant->getSessionId(), ]); + $session = $currentParticipant->getSession(); + if ($session instanceof Session) { + $roomData = array_merge($roomData, [ + // Deprecated, use participantFlags instead. + 'participantInCall' => ($session->getInCall() & Participant::FLAG_IN_CALL) !== 0, + 'participantFlags' => $session->getInCall(), + 'lastPing' => $session->getLastPing(), + 'sessionId' => $session->getSessionId(), + ]); + } + if ($roomData['notificationLevel'] === Participant::NOTIFY_DEFAULT) { if ($currentParticipant->isGuest()) { $roomData['notificationLevel'] = Participant::NOTIFY_NEVER; @@ -390,62 +405,65 @@ class RoomController extends AEnvironmentAwareController { $roomData['canStartCall'] = $currentParticipant->canStartCall(); - $currentUser = $this->userManager->get($currentParticipant->getUser()); - if ($currentUser instanceof IUser) { - $lastReadMessage = $currentParticipant->getLastReadMessage(); - if ($lastReadMessage === -1) { - /* - * Because the migration from the old comment_read_markers was - * not possible in a programmatic way with a reasonable O(1) or O(n) - * but only with O(user×chat), we do the conversion here. - */ - $lastReadMessage = $this->chatManager->getLastReadMessageFromLegacy($room, $currentUser); - $currentParticipant->setLastReadMessage($lastReadMessage); - } - $roomData['unreadMessages'] = $this->chatManager->getUnreadCount($room, $lastReadMessage); + if ($userId !== '') { + $currentUser = $this->userManager->get($userId); + if ($currentUser instanceof IUser) { + $lastReadMessage = $attendee->getLastReadMessage(); + if ($lastReadMessage === -1) { + /* + * Because the migration from the old comment_read_markers was + * not possible in a programmatic way with a reasonable O(1) or O(n) + * but only with O(user×chat), we do the conversion here. + */ + $lastReadMessage = $this->chatManager->getLastReadMessageFromLegacy($room, $currentUser); + $attendee->setLastReadMessage($lastReadMessage); + $this->attendeeMapper->update($attendee); + } + $roomData['unreadMessages'] = $this->chatManager->getUnreadCount($room, $lastReadMessage); - $lastMention = $currentParticipant->getLastMentionMessage(); - $roomData['unreadMention'] = $lastMention !== 0 && $lastReadMessage < $lastMention; - $roomData['lastReadMessage'] = $lastReadMessage; + $lastMention = $attendee->getLastMentionMessage(); + $roomData['unreadMention'] = $lastMention !== 0 && $lastReadMessage < $lastMention; + $roomData['lastReadMessage'] = $lastReadMessage; + } } $numActiveGuests = 0; $cleanGuests = false; $participantList = []; $participants = $room->getParticipants(); - uasort($participants, function (Participant $participant1, Participant $participant2) { - return $participant2->getLastPing() - $participant1->getLastPing(); - }); - - foreach ($participants as $participant) { - if ($participant->isGuest()) { - if ($participant->getLastPing() <= $this->timeFactory->getTime() - 100) { - $cleanGuests = true; - } else { - $numActiveGuests++; - } - } else { - $user = $this->userManager->get($participant->getUser()); - if ($user instanceof IUser) { - $participantList[(string)$user->getUID()] = [ - 'name' => $user->getDisplayName(), - 'type' => $participant->getParticipantType(), - 'call' => $participant->getInCallFlags(), - 'sessionId' => $participant->getSessionId(), - ]; - - if ($room->getType() === Room::ONE_TO_ONE_CALL && - $user->getUID() !== $currentParticipant->getUser()) { - // FIXME This should not be done, but currently all the clients use it to get the avatar of the user … - $roomData['name'] = $user->getUID(); - } - } - - if ($participant->getSessionId() !== '0' && $participant->getLastPing() <= $this->timeFactory->getTime() - 100) { - $room->leaveRoom($participant->getUser()); - } - } - } +// uasort($participants, function (Participant $participant1, Participant $participant2) { +// return $participant2->getLastPing() - $participant1->getLastPing(); +// }); +// +// foreach ($participants as $participant) { +// if ($participant->isGuest()) { +// if ($participant->getLastPing() <= $this->timeFactory->getTime() - 100) { +// $cleanGuests = true; +// } else { +// $numActiveGuests++; +// } +// } else { +// $user = $this->userManager->get($participant->getUser()); +// if ($user instanceof IUser) { +// $participantList[(string)$user->getUID()] = [ +// 'name' => $user->getDisplayName(), +// 'type' => $participant->getParticipantType(), +// 'call' => $participant->getInCallFlags(), +// 'sessionId' => $participant->getSessionId(), +// ]; +// +// if ($room->getType() === Room::ONE_TO_ONE_CALL && +// $user->getUID() !== $currentParticipant->getUser()) { +// // FIXME This should not be done, but currently all the clients use it to get the avatar of the user … +// $roomData['name'] = $user->getUID(); +// } +// } +// +// if ($participant->getSessionId() !== '0' && $participant->getLastPing() <= $this->timeFactory->getTime() - 100) { +// $room->leaveRoom($participant->getUser()); +// } +// } +// } if ($cleanGuests) { $room->cleanGuestParticipants(); @@ -539,25 +557,34 @@ class RoomController extends AEnvironmentAwareController { return $roomData; } + $attendee = $currentParticipant->getAttendee(); + $userId = $attendee->getActorType() === 'users' ? $attendee->getActorId() : ''; + $roomData = array_merge($roomData, [ 'name' => $room->getName(), - 'displayName' => $room->getDisplayName($currentParticipant->getUser()), + 'displayName' => $room->getDisplayName($userId), 'objectType' => $room->getObjectType(), 'objectId' => $room->getObjectId(), - 'participantType' => $currentParticipant->getParticipantType(), - 'participantFlags' => $currentParticipant->getInCallFlags(), + 'participantType' => $attendee->getParticipantType(), 'readOnly' => $room->getReadOnly(), 'hasCall' => $room->getActiveSince() instanceof \DateTimeInterface, 'lastActivity' => $lastActivity, - 'isFavorite' => $currentParticipant->isFavorite(), - 'notificationLevel' => $currentParticipant->getNotificationLevel(), + 'isFavorite' => $attendee->isFavorite(), + 'notificationLevel' => $attendee->getNotificationLevel(), 'lobbyState' => $room->getLobbyState(), 'lobbyTimer' => $lobbyTimer, 'sipEnabled' => $room->getSIPEnabled(), - 'lastPing' => $currentParticipant->getLastPing(), - 'sessionId' => $currentParticipant->getSessionId(), ]); + $session = $currentParticipant->getSession(); + if ($session instanceof Session) { + $roomData = array_merge($roomData, [ + 'participantFlags' => $session->getInCall(), + 'lastPing' => $session->getLastPing(), + 'sessionId' => $session->getSessionId(), + ]); + } + if ($roomData['notificationLevel'] === Participant::NOTIFY_DEFAULT) { if ($currentParticipant->isGuest()) { $roomData['notificationLevel'] = Participant::NOTIFY_NEVER; @@ -581,40 +608,43 @@ class RoomController extends AEnvironmentAwareController { $roomData['canStartCall'] = $currentParticipant->canStartCall(); - $currentUser = $this->userManager->get($currentParticipant->getUser()); - if ($currentUser instanceof IUser) { - $lastReadMessage = $currentParticipant->getLastReadMessage(); - if ($lastReadMessage === -1) { - /* - * Because the migration from the old comment_read_markers was - * not possible in a programmatic way with a reasonable O(1) or O(n) - * but only with O(user×chat), we do the conversion here. - */ - $lastReadMessage = $this->chatManager->getLastReadMessageFromLegacy($room, $currentUser); - $currentParticipant->setLastReadMessage($lastReadMessage); - } - if ($room->getLastMessage() && $lastReadMessage === (int) $room->getLastMessage()->getId()) { - // When the last message is the last read message, there are no unread messages, - // so we can save the query. - $roomData['unreadMessages'] = 0; - } else { - $roomData['unreadMessages'] = $this->chatManager->getUnreadCount($room, $lastReadMessage); - } + if ($attendee->getActorType() === 'users') { + $currentUser = $this->userManager->get($attendee->getActorId()); + if ($currentUser instanceof IUser) { + $lastReadMessage = $attendee->getLastReadMessage(); + if ($lastReadMessage === -1) { + /* + * Because the migration from the old comment_read_markers was + * not possible in a programmatic way with a reasonable O(1) or O(n) + * but only with O(user×chat), we do the conversion here. + */ + $lastReadMessage = $this->chatManager->getLastReadMessageFromLegacy($room, $currentUser); + $attendee->setLastReadMessage($lastReadMessage); + $this->attendeeMapper->update($attendee); + } + if ($room->getLastMessage() && $lastReadMessage === (int) $room->getLastMessage()->getId()) { + // When the last message is the last read message, there are no unread messages, + // so we can save the query. + $roomData['unreadMessages'] = 0; + } else { + $roomData['unreadMessages'] = $this->chatManager->getUnreadCount($room, $lastReadMessage); + } - $lastMention = $currentParticipant->getLastMentionMessage(); - $roomData['unreadMention'] = $lastMention !== 0 && $lastReadMessage < $lastMention; - $roomData['lastReadMessage'] = $lastReadMessage; + $lastMention = $attendee->getLastMentionMessage(); + $roomData['unreadMention'] = $lastMention !== 0 && $lastReadMessage < $lastMention; + $roomData['lastReadMessage'] = $lastReadMessage; - $roomData['canDeleteConversation'] = $room->getType() !== Room::ONE_TO_ONE_CALL - && $currentParticipant->hasModeratorPermissions(false); - $roomData['canLeaveConversation'] = true; + $roomData['canDeleteConversation'] = $room->getType() !== Room::ONE_TO_ONE_CALL + && $currentParticipant->hasModeratorPermissions(false); + $roomData['canLeaveConversation'] = true; + } } // FIXME This should not be done, but currently all the clients use it to get the avatar of the user … if ($room->getType() === Room::ONE_TO_ONE_CALL) { $participants = json_decode($room->getName(), true); foreach ($participants as $participant) { - if ($participant !== $currentParticipant->getUser()) { + if ($participant !== $attendee->getActorId()) { $roomData['name'] = $participant; } } @@ -861,7 +891,9 @@ class RoomController extends AEnvironmentAwareController { * @return DataResponse */ public function addToFavorites(): DataResponse { - $this->participant->setFavorite(true); + $attendee = $this->participant->getAttendee(); + $attendee->setFavorite(true); + $this->attendeeMapper->update($attendee); return new DataResponse([]); } @@ -872,7 +904,9 @@ class RoomController extends AEnvironmentAwareController { * @return DataResponse */ public function removeFromFavorites(): DataResponse { - $this->participant->setFavorite(false); + $attendee = $this->participant->getAttendee(); + $attendee->setFavorite(false); + $this->attendeeMapper->update($attendee); return new DataResponse([]); } @@ -884,10 +918,18 @@ class RoomController extends AEnvironmentAwareController { * @return DataResponse */ public function setNotificationLevel(int $level): DataResponse { - if (!$this->participant->setNotificationLevel($level)) { + if (!\in_array($level, [ + Participant::NOTIFY_ALWAYS, + Participant::NOTIFY_MENTION, + Participant::NOTIFY_NEVER + ], true)) { return new DataResponse([], Http::STATUS_BAD_REQUEST); } + $attendee = $this->participant->getAttendee(); + $attendee->setNotificationLevel($level); + $this->attendeeMapper->update($attendee); + return new DataResponse(); } diff --git a/lib/Controller/SignalingController.php b/lib/Controller/SignalingController.php index 4f75a818f..5ab3c5aee 100644 --- a/lib/Controller/SignalingController.php +++ b/lib/Controller/SignalingController.php @@ -32,6 +32,7 @@ use OCA\Talk\Exceptions\ParticipantNotFoundException; use OCA\Talk\Manager; use OCA\Talk\Participant; use OCA\Talk\Room; +use OCA\Talk\Service\SessionService; use OCA\Talk\Signaling\Messages; use OCA\Talk\TalkSession; use OCP\AppFramework\Http; @@ -60,6 +61,8 @@ class SignalingController extends OCSController { private $session; /** @var Manager */ private $manager; + /** @var SessionService */ + private $sessionService; /** @var IDBConnection */ private $dbConnection; /** @var Messages */ @@ -81,6 +84,7 @@ class SignalingController extends OCSController { \OCA\Talk\Signaling\Manager $signalingManager, TalkSession $session, Manager $manager, + SessionService $sessionService, IDBConnection $connection, Messages $messages, IUserManager $userManager, @@ -94,6 +98,7 @@ class SignalingController extends OCSController { $this->session = $session; $this->dbConnection = $connection; $this->manager = $manager; + $this->sessionService = $sessionService; $this->messages = $messages; $this->userManager = $userManager; $this->dispatcher = $dispatcher; @@ -597,7 +602,7 @@ class SignalingController extends OCSController { } // Ping all active sessions with one query - $room->pingSessionIds($pingSessionIds, $now); + $this->sessionService->updateMultipleLastPings($pingSessionIds, $now); $response = [ 'type' => 'room', diff --git a/lib/Manager.php b/lib/Manager.php index 091c70368..a92aff209 100644 --- a/lib/Manager.php +++ b/lib/Manager.php @@ -27,6 +27,8 @@ use OCA\Talk\Chat\CommentsManager; use OCA\Talk\Events\RoomEvent; use OCA\Talk\Exceptions\ParticipantNotFoundException; use OCA\Talk\Exceptions\RoomNotFoundException; +use OCA\Talk\Model\AttendeeMapper; +use OCA\Talk\Model\SessionMapper; use OCP\AppFramework\Utility\ITimeFactory; use OCP\Comments\IComment; use OCP\Comments\ICommentsManager; @@ -51,6 +53,10 @@ class Manager { private $config; /** @var Config */ private $talkConfig; + /** @var AttendeeMapper */ + private $attendeeMapper; + /** @var SessionMapper */ + private $sessionMapper; /** @var ISecureRandom */ private $secureRandom; /** @var IUserManager */ @@ -71,6 +77,8 @@ class Manager { public function __construct(IDBConnection $db, IConfig $config, Config $talkConfig, + AttendeeMapper $attendeeMapper, + SessionMapper $sessionMapper, ISecureRandom $secureRandom, IUserManager $userManager, CommentsManager $commentsManager, @@ -82,6 +90,8 @@ class Manager { $this->db = $db; $this->config = $config; $this->talkConfig = $talkConfig; + $this->attendeeMapper = $attendeeMapper; + $this->sessionMapper = $sessionMapper; $this->secureRandom = $secureRandom; $this->userManager = $userManager; $this->commentsManager = $commentsManager; @@ -147,7 +157,7 @@ class Manager { $this->dispatcher, $this->timeFactory, $this->hasher, - (int) $row['id'], + (int) $row['r_id'], (int) $row['type'], (int) $row['read_only'], (int) $row['lobby_state'], @@ -173,25 +183,18 @@ class Manager { * @return Participant */ public function createParticipantObject(Room $room, array $row): Participant { - $lastJoinedCall = null; - if (!empty($row['last_joined_call'])) { - $lastJoinedCall = $this->timeFactory->getDateTime($row['last_joined_call']); + $attendee = $this->attendeeMapper->createAttendeeFromRow($row); + $session = null; + if (!empty($row['s_id'])) { + $session = $this->sessionMapper->createSessionFromRow($row); } return new Participant( $this->db, $this->config, $room, - (string) $row['actor_id'], - (int) $row['participant_type'], - 0, // FIXME this is in talk_sessions now (int) $row['last_ping'], - '0', // FIXME this is in talk_sessions now (string) $row['session_id'], - Participant::FLAG_DISCONNECTED, // FIXME this is in talk_sessions now (int) $row['in_call'], - (int) $row['notification_level'], - (bool) $row['favorite'], - (int) $row['last_read_message'], - (int) $row['last_mention_message'], - $lastJoinedCall + $attendee, + $session ); } @@ -249,6 +252,7 @@ class Manager { public function searchRoomsByToken(string $searchToken = '', int $limit = null, int $offset = null): array { $query = $this->db->getQueryBuilder(); $query->select('*') + ->selectAlias('id', 'r_id') ->from('talk_rooms') ->setMaxResults(1); @@ -293,7 +297,10 @@ class Manager { */ public function getRoomsForUser(string $userId, bool $includeLastMessage = false): array { $query = $this->db->getQueryBuilder(); - $query->select('r.*')->addSelect('a.*') + $query->select('r.*') + ->addSelect('a.*') + ->selectAlias('r.id', 'r_id') + ->selectAlias('a.id', 'a_id') ->from('talk_rooms', 'r') ->leftJoin('r', 'talk_attendees', 'a', $query->expr()->andX( $query->expr()->eq('a.actor_id', $query->createNamedParameter($userId)), @@ -346,12 +353,15 @@ class Manager { */ public function getRoomForUser(int $roomId, ?string $userId): Room { $query = $this->db->getQueryBuilder(); - $query->select('*') + $query->select('r.*') + ->selectAlias('r.id', 'r_id') ->from('talk_rooms', 'r') ->where($query->expr()->eq('r.id', $query->createNamedParameter($roomId, IQueryBuilder::PARAM_INT))); if ($userId !== null) { // Non guest user + $query->addSelect('a.*') + ->selectAlias('a.id', 'a_id'); $query->leftJoin('r', 'talk_attendees', 'a', $query->expr()->andX( $query->expr()->eq('a.actor_id', $query->createNamedParameter($userId)), $query->expr()->eq('a.actor_type', $query->createNamedParameter('users')), @@ -411,14 +421,16 @@ class Manager { public function getRoomForUserByToken(string $token, ?string $userId, bool $includeLastMessage = false): Room { $query = $this->db->getQueryBuilder(); $query->select('r.*') + ->selectAlias('r.id', 'r_id') ->from('talk_rooms', 'r') ->where($query->expr()->eq('r.token', $query->createNamedParameter($token))) ->setMaxResults(1); if ($userId !== null) { // Non guest user - $query->addSelect('p.*') - ->leftJoin('r', 'talk_attendees', 'a', $query->expr()->andX( + $query->addSelect('a.*') + ->selectAlias('a.id', 'a_id'); + $query->leftJoin('r', 'talk_attendees', 'a', $query->expr()->andX( $query->expr()->eq('a.actor_id', $query->createNamedParameter($userId)), $query->expr()->eq('a.actor_type', $query->createNamedParameter('users')), $query->expr()->eq('a.room_id', 'r.id') @@ -466,6 +478,7 @@ class Manager { public function getRoomById(int $roomId): Room { $query = $this->db->getQueryBuilder(); $query->select('*') + ->selectAlias('id', 'r_id') ->from('talk_rooms') ->where($query->expr()->eq('id', $query->createNamedParameter($roomId, IQueryBuilder::PARAM_INT))); @@ -496,12 +509,15 @@ class Manager { $query = $this->db->getQueryBuilder(); $query->select('r.*') + ->selectAlias('r.id', 'r_id') ->from('talk_rooms', 'r') ->where($query->expr()->eq('r.token', $query->createNamedParameter($token))); if ($preloadUserId !== null) { + $query->addSelect('a.*') - ->leftJoin('r', 'talk_attendees', 'a', $query->expr()->andX( + ->selectAlias('a.id', 'a_id'); + $query->leftJoin('r', 'talk_attendees', 'a', $query->expr()->andX( $query->expr()->eq('a.actor_id', $query->createNamedParameter($preloadUserId)), $query->expr()->eq('a.actor_type', $query->createNamedParameter('users')), $query->expr()->eq('a.room_id', 'r.id') @@ -538,6 +554,7 @@ class Manager { public function getRoomByObject(string $objectType, string $objectId): Room { $query = $this->db->getQueryBuilder(); $query->select('*') + ->selectAlias('id', 'r_id') ->from('talk_rooms') ->where($query->expr()->eq('object_type', $query->createNamedParameter($objectType))) ->andWhere($query->expr()->eq('object_id', $query->createNamedParameter($objectId))); @@ -617,6 +634,7 @@ class Manager { $query = $this->db->getQueryBuilder(); $query->select('*') + ->selectAlias('id', 'r_id') ->from('talk_rooms') ->where($query->expr()->eq('type', $query->createNamedParameter(Room::ONE_TO_ONE_CALL, IQueryBuilder::PARAM_INT))) ->andWhere($query->expr()->eq('name', $query->createNamedParameter($name))); @@ -646,6 +664,7 @@ class Manager { public function getChangelogRoom(string $userId): Room { $query = $this->db->getQueryBuilder(); $query->select('*') + ->selectAlias('id', 'r_id') ->from('talk_rooms') ->where($query->expr()->eq('type', $query->createNamedParameter(Room::CHANGELOG_CONVERSATION, IQueryBuilder::PARAM_INT))) ->andWhere($query->expr()->eq('name', $query->createNamedParameter($userId))); diff --git a/lib/Middleware/InjectionMiddleware.php b/lib/Middleware/InjectionMiddleware.php index 9b7e89427..5ef6d17ba 100644 --- a/lib/Middleware/InjectionMiddleware.php +++ b/lib/Middleware/InjectionMiddleware.php @@ -117,7 +117,7 @@ class InjectionMiddleware extends Middleware { */ protected function getLoggedIn(AEnvironmentAwareController $controller, bool $moderatorRequired): void { $token = $this->request->getParam('token'); - $room = $this->manager->getRoomForParticipantByToken($token, $this->userId); + $room = $this->manager->getRoomForUserByToken($token, $this->userId); $controller->setRoom($room); $participant = $room->getParticipant($this->userId); @@ -136,7 +136,7 @@ class InjectionMiddleware extends Middleware { */ protected function getLoggedInOrGuest(AEnvironmentAwareController $controller, bool $moderatorRequired): void { $token = $this->request->getParam('token'); - $room = $this->manager->getRoomForParticipantByToken($token, $this->userId); + $room = $this->manager->getRoomForUserByToken($token, $this->userId); $controller->setRoom($room); if ($this->userId !== null) { diff --git a/lib/Migration/Version10000Date20201015134000.php b/lib/Migration/Version10000Date20201015134000.php index b4b19ff36..4ed340a14 100644 --- a/lib/Migration/Version10000Date20201015134000.php +++ b/lib/Migration/Version10000Date20201015134000.php @@ -101,8 +101,11 @@ class Version10000Date20201015134000 extends SimpleMigrationStep { 'default' => Participant::NOTIFY_DEFAULT, 'notnull' => false, ]); - $table->addColumn('last_joined_call', Type::DATETIME, [ - 'notnull' => false, + $table->addColumn('last_joined_call', Type::INTEGER, [ + 'notnull' => true, + 'length' => 11, + 'default' => 0, + 'unsigned' => true, ]); $table->addColumn('last_read_message', Type::BIGINT, [ 'default' => 0, @@ -194,9 +197,9 @@ class Version10000Date20201015134000 extends SimpleMigrationStep { $result = $query->execute(); while ($row = $result->fetch()) { - $lastJoinedCall = null; + $lastJoinedCall = 0; if (!empty($row['last_joined_call'])) { - $lastJoinedCall = $this->timeFactory->getDateTime($row['last_joined_call']); + $lastJoinedCall = $this->timeFactory->getDateTime($row['last_joined_call'])->getTimestamp(); } $insert @@ -206,7 +209,7 @@ class Version10000Date20201015134000 extends SimpleMigrationStep { ->setParameter('participant_type', (int) $row['participant_type'], IQueryBuilder::PARAM_INT) ->setParameter('favorite', (bool) $row['favorite'], IQueryBuilder::PARAM_BOOL) ->setParameter('notification_level', (int) $row['notification_level'], IQueryBuilder::PARAM_INT) - ->setParameter('last_joined_call', $lastJoinedCall, IQueryBuilder::PARAM_DATE) + ->setParameter('last_joined_call', $lastJoinedCall, IQueryBuilder::PARAM_INT) ->setParameter('last_read_message', (int) $row['last_read_message'], IQueryBuilder::PARAM_INT) ->setParameter('last_mention_message', (int) $row['last_mention_message'], IQueryBuilder::PARAM_INT) ; diff --git a/lib/Model/Attendee.php b/lib/Model/Attendee.php new file mode 100644 index 000000000..6c5690803 --- /dev/null +++ b/lib/Model/Attendee.php @@ -0,0 +1,113 @@ +<?php + +declare(strict_types=1); +/** + * @copyright Copyright (c) 2020 Joas Schilling <coding@schilljs.com> + * + * @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 <http://www.gnu.org/licenses/>. + * + */ + +namespace OCA\Talk\Model; + +use OCP\AppFramework\Db\Entity; + +/** + * @method void setRoomId(int $roomId) + * @method string getRoomId() + * @method void setActorType(string $actorType) + * @method string getActorType() + * @method void setActorId(string $actorId) + * @method string getActorId() + * @method void setPin(string $pin) + * @method string getPin() + * @method void setParticipantType(int $participantType) + * @method int getParticipantType() + * @method void setFavorite(bool $favorite) + * @method bool isFavorite() + * @method void setNotificationLevel(int $notificationLevel) + * @method int getNotificationLevel() + * @method void setLastJoinedCall(int $lastJoinedCall) + * @method int getLastJoinedCall() + * @method void setLastReadMessage(int $lastReadMessage) + * @method int getLastReadMessage() + * @method void setLastMentionMessage(int $lastMentionMessage) + * @method int getLastMentionMessage() + */ +class Attendee extends Entity { + + /** @var int */ + protected $roomId; + + /** @var string */ + protected $actorType; + + /** @var string */ + protected $actorId; + + /** @var string */ + protected $pin; + + /** @var int */ + protected $participantType; + + /** @var bool */ + protected $favorite; + + /** @var int */ + protected $notificationLevel; + + /** @var int */ + protected $lastJoinedCall; + + /** @var int */ + protected $lastReadMessage; + + /** @var int */ + protected $lastMentionMessage; + + public function __construct() { + $this->addType('room_id', 'int'); + $this->addType('actor_type', 'string'); + $this->addType('actor_id', 'string'); + $this->addType('pin', 'string'); + $this->addType('participant_type', 'int'); + $this->addType('favorite', 'bool'); + $this->addType('notification_level', 'int'); + $this->addType('last_joined_call', 'int'); + $this->addType('last_read_message', 'int'); + $this->addType('last_mention_message', 'int'); + } + + /** + * @return array + */ + public function asArray(): array { + return [ + 'id' => $this->getId(), + 'room_id' => $this->getRoomId(), + 'actor_type' => $this->getActorType(), + 'actor_id' => $this->getActorId(), + 'pin' => $this->getPin(), + 'participant_type' => $this->getParticipantType(), + 'favorite' => $this->isFavorite(), + 'notification_level' => $this->getNotificationLevel(), + 'last_joined_call' => $this->getLastJoinedCall(), + 'last_read_message' => $this->getLastReadMessage(), + 'last_mention_message' => $this->getLastMentionMessage(), + ]; + } +} diff --git a/lib/Model/AttendeeMapper.php b/lib/Model/AttendeeMapper.php new file mode 100644 index 000000000..4c7e7dcd8 --- /dev/null +++ b/lib/Model/AttendeeMapper.php @@ -0,0 +1,72 @@ +<?php + +declare(strict_types=1); +/** + * @copyright Copyright (c) 2020 Joas Schilling <coding@schilljs.com> + * + * @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 <http://www.gnu.org/licenses/>. + * + */ + +namespace OCA\Talk\Model; + +use OCP\AppFramework\Db\QBMapper; +use OCP\IDBConnection; + +/** + * @method Attendee mapRowToEntity(array $row) + */ +class AttendeeMapper extends QBMapper { + + /** + * @param IDBConnection $db + */ + public function __construct(IDBConnection $db) { + parent::__construct($db, 'talk_attendees', Attendee::class); + } + + /** + * @param string $actorType + * @param string $actorId + * @return Attendee + * @throws \OCP\AppFramework\Db\DoesNotExistException + */ + public function findByActor(string $actorType, string $actorId): Attendee { + $query = $this->db->getQueryBuilder(); + $query->select('*') + ->from($this->getTableName()) + ->where($query->expr()->eq('actor_type', $query->createNamedParameter($actorType))) + ->andWhere($query->expr()->eq('actor_id', $query->createNamedParameter($actorId))); + + return $this->findEntity($query); + } + + public function createAttendeeFromRow(array $row): Attendee { + return $this->mapRowToEntity([ + 'id' => $row['a_id'], + 'room_id' => $row['id'], + 'actor_type' => $row['actor_type'], + 'actor_id' => $row['actor_id'], + 'pin' => $row['pin'], + 'participant_type' => (int) $row['participant_type'], + 'favorite' => (bool) $row['favorite'], + 'notification_level' => (int) $row['notification_level'], + 'last_joined_call' => (int) $row['last_joined_call'], + 'last_read_message' => (int) $row['last_read_message'], + 'last_mention_message' => (int) $row['last_mention_message'], + ]); + } +} diff --git a/lib/Model/Session.php b/lib/Model/Session.php new file mode 100644 index 000000000..c647e7082 --- /dev/null +++ b/lib/Model/Session.php @@ -0,0 +1,71 @@ +<?php + +declare(strict_types=1); +/** + * @copyright Copyright (c) 2020 Joas Schilling <coding@schilljs.com> + * + * @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 <http://www.gnu.org/licenses/>. + * + */ + +namespace OCA\Talk\Model; + +use OCP\AppFramework\Db\Entity; + +/** + * @method void setAttendeeId(int $attendeeId) + * @method string getAttendeeId() + * @method void setSessionId(string $sessionId) + * @method string getSessionId() + * @method void setInCall(int $inCall) + * @method int getInCall() + * @method void setLastPing(int $lastPing) + * @method int getLastPing() + */ +class Session extends Entity { + + /** @var int */ + protected $attendeeId; + + /** @var string */ + protected $sessionId; + + /** @var int */ + protected $inCall; + + /** @var int */ + protected $lastPing; + + public function __construct() { + $this->addType('attendee_id', 'int'); + $this->addType('session_id', 'string'); + $this->addType('in_call', 'int'); + $this->addType('last_ping', 'int'); + } + + /** + * @return array + */ + public function asArray(): array { + return [ + 'id' => $this->getId(), + 'attendee_id' => $this->getAttendeeId(), + 'session_id' => $this->getSessionId(), + 'in_call' => $this->getInCall(), + 'last_ping' => $this->getLastPing(), + ]; + } +} diff --git a/lib/Model/SessionMapper.php b/lib/Model/SessionMapper.php new file mode 100644 index 000000000..c45cafd90 --- /dev/null +++ b/lib/Model/SessionMapper.php @@ -0,0 +1,64 @@ +<?php + +declare(strict_types=1); +/** + * @copyright Copyright (c) 2020 Joas Schilling <coding@schilljs.com> + * + * @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 <http://www.gnu.org/licenses/>. + * + */ + +namespace OCA\Talk\Model; + +use OCP\AppFramework\Db\QBMapper; +use OCP\IDBConnection; + +/** + * @method Session mapRowToEntity(array $row) + */ +class SessionMapper extends QBMapper { + + /** + * @param IDBConnection $db + */ + public function __construct(IDBConnection $db) { + parent::__construct($db, 'talk_sessions', Session::class); + } + + /** + * @param string $sessionId + * @return Session + * @throws \OCP\AppFramework\Db\DoesNotExistException + */ + public function findBySessionId(string $sessionId): Session { + $query = $this->db->getQueryBuilder(); + $query->select('*') + ->from($this->getTableName()) + ->where($query->expr()->eq('session_id', $query->createNamedParameter($sessionId))); + + return $this->findEntity($query); + } + + public function createSessionFromRow(array $row): Session { + return $this->mapRowToEntity([ + 'id' => $row['s_id'], + 'session_id' => $row['session_id'], + 'attendee_id' => (int) $row['a_id'], + 'in_call' => (int) $row['in_call'], + 'last_ping' => (int) $row['last_ping'], + ]); + } +} diff --git a/lib/Participant.php b/lib/Participant.php index 3b6d61c12..f8bd34a53 100644 --- a/lib/Participant.php +++ b/lib/Participant.php @@ -25,7 +25,8 @@ declare(strict_types=1); namespace OCA\Talk; -use OCP\DB\QueryBuilder\IQueryBuilder; +use OCA\Talk\Model\Attendee; +use OCA\Talk\Model\Session; use OCP\IConfig; use OCP\IDBConnection; @@ -54,180 +55,43 @@ class Participant { protected $config; /** @var Room */ protected $room; - /** @var string */ - protected $user; - /** @var int */ - protected $participantType; - /** @var int */ - protected $lastPing; - /** @var string */ - protected $sessionId; - /** @var int */ - protected $inCall; - /** @var int */ - protected $notificationLevel; - /** @var bool */ - private $isFavorite; - /** @var int */ - private $lastReadMessage; - /** @var int */ - private $lastMentionMessage; - /** @var \DateTime|null */ - private $lastJoinedCall; + /** @var Attendee */ + protected $attendee; + /** @var Session|null */ + protected $session; public function __construct(IDBConnection $db, IConfig $config, Room $room, - string $user, - int $participantType, - int $lastPing, - string $sessionId, - int $inCall, - int $notificationLevel, - bool $isFavorite, - int $lastReadMessage, - int $lastMentionMessage, - \DateTime $lastJoinedCall = null) { + Attendee $attendee, + ?Session $session) { $this->db = $db; $this->config = $config; $this->room = $room; - $this->user = $user; - $this->participantType = $participantType; - $this->lastPing = $lastPing; - $this->sessionId = $sessionId; - $this->inCall = $inCall; - $this->notificationLevel = $notificationLevel; - $this->isFavorite = $isFavorite; - $this->lastReadMessage = $lastReadMessage; - $this->lastMentionMessage = $lastMentionMessage; - $this->lastJoinedCall = $lastJoinedCall; + $this->attendee = $attendee; + $this->session = $session; } - public function getUser(): string { - return $this->user; + public function getAttendee(): Attendee { + return $this->attendee; } - public function getParticipantType(): int { - return $this->participantType; + public function getSession(): ?Session { + return $this->session; } public function isGuest(): bool { - return \in_array($this->participantType, [self::GUEST, self::GUEST_MODERATOR], true); + $participantType = $this->attendee->getParticipantType(); + return \in_array($participantType, [self::GUEST, self::GUEST_MODERATOR], true); } public function hasModeratorPermissions(bool $guestModeratorAllowed = true): bool { + $participantType = $this->attendee->getParticipantType(); if (!$guestModeratorAllowed) { - return \in_array($this->participantType, [self::OWNER, self::MODERATOR], true); + return \in_array($participantType, [self::OWNER, self::MODERATOR], true); } - return \in_array($this->participantType, [self::OWNER, self::MODERATOR, self::GUEST_MODERATOR], true); - } - - public function getLastPing(): int { - return $this->lastPing; - } - - public function getSessionId(): string { - return $this->sessionId; - } - - public function getInCallFlags(): int { - return $this->inCall; - } - - /** - * @return \DateTime|null - */ - public function getJoinedCall(): ?\DateTime { - return $this->lastJoinedCall; - } - - public function isFavorite(): bool { - return $this->isFavorite; - } - - public function setFavorite(bool $favor): bool { - if (!$this->user) { - return false; - } - - $query = $this->db->getQueryBuilder(); - $query->update('talk_participants') - ->set('favorite', $query->createNamedParameter((int) $favor, IQueryBuilder::PARAM_INT)) - ->where($query->expr()->eq('user_id', $query->createNamedParameter($this->user))) - ->andWhere($query->expr()->eq('room_id', $query->createNamedParameter($this->room->getId()))); - $query->execute(); - - $this->isFavorite = $favor; - return true; - } - - public function getNotificationLevel(): int { - return $this->notificationLevel; - } - - public function setNotificationLevel(int $notificationLevel): bool { - if (!$this->user) { - return false; - } - - if (!\in_array($notificationLevel, [ - self::NOTIFY_ALWAYS, - self::NOTIFY_MENTION, - self::NOTIFY_NEVER - ], true)) { - return false; - } - - $query = $this->db->getQueryBuilder(); - $query->update('talk_participants') - ->set('notification_level', $query->createNamedParameter($notificationLevel, IQueryBuilder::PARAM_INT)) - ->where($query->expr()->eq('user_id', $query->createNamedParameter($this->user))) - ->andWhere($query->expr()->eq('room_id', $query->createNamedParameter($this->room->getId()))); - $query->execute(); - - $this->notificationLevel = $notificationLevel; - return true; - } - - public function getLastReadMessage(): int { - return $this->lastReadMessage; - } - - public function setLastReadMessage(int $messageId): bool { - if (!$this->user) { - return false; - } - - $query = $this->db->getQueryBuilder(); - $query->update('talk_participants') - ->set('last_read_message', $query->createNamedParameter($messageId, IQueryBuilder::PARAM_INT)) - ->where($query->expr()->eq('user_id', $query->createNamedParameter($this->user))) - ->andWhere($query->expr()->eq('room_id', $query->createNamedParameter($this->room->getId()))); - $query->execute(); - - $this->lastReadMessage = $messageId; - return true; - } - - public function getLastMentionMessage(): int { - return $this->lastMentionMessage; - } - - public function setLastMentionMessage(int $messageId): bool { - if (!$this->user) { - return false; - } - - $query = $this->db->getQueryBuilder(); - $query->update('talk_participants') - ->set('last_mention_message', $query->createNamedParameter($messageId, IQueryBuilder::PARAM_INT)) - ->where($query->expr()->eq('user_id', $query->createNamedParameter($this->user))) - ->andWhere($query->expr()->eq('room_id', $query->createNamedParameter($this->room->getId()))); - $query->execute(); - - $this->lastMentionMessage = $messageId; - return true; + return \in_array($participantType, [self::OWNER, self::MODERATOR, self::GUEST_MODERATOR], true); } public function canStartCall(): bool { diff --git a/lib/Room.php b/lib/Room.php index 622620224..824f2e9a7 100644 --- a/lib/Room.php +++ b/lib/Room.php @@ -403,8 +403,8 @@ class Room { $this->dispatcher->dispatch(self::EVENT_BEFORE_ROOM_DELETE, $event); $query = $this->db->getQueryBuilder(); - // Delete all participants - $query->delete('talk_participants') + // Delete attendees + $query->delete('talk_attendees') ->where($query->expr()->eq('room_id', $query->createNamedParameter($this->getId(), IQueryBuilder::PARAM_INT))); $query->execute(); @@ -583,7 +583,7 @@ class Room { if ($oldType === self::PUBLIC_CALL) { // Kick all guests and users that were not invited $query = $this->db->getQueryBuilder(); - $query->delete('talk_participants') + $query->delete('talk_attendees') ->where($query->expr()->eq('room_id', $query->createNamedParameter($this->getId(), IQueryBuilder::PARAM_INT))) ->andWhere($query->expr()->in('participant_type', $query->createNamedParameter([Participant::GUEST, Participant::USER_SELF_JOINED], IQueryBuilder::PARAM_INT_ARRAY))); $query->execute(); @@ -785,12 +785,14 @@ class Room { $this->dispatcher->dispatch(self::EVENT_BEFORE_PARTICIPANT_TYPE_SET, $event); $query = $this->db->getQueryBuilder(); - $query->update('talk_participants') + $query->update('talk_attendees') ->set('participant_type', $query->createNamedParameter($participantType, IQueryBuilder::PARAM_INT)) ->where($query->expr()->eq('room_id', $query->createNamedParameter($this->getId(), IQueryBuilder::PARAM_INT))) - ->andWhere($query->expr()->eq('user_id', $query->createNamedParameter($participant->getUser()))); + ->andWhere($query->expr()->eq('actor_id', $query->createNamedParameter($participant->getUser()))) + ->andWhere($query->expr()->eq('actor_type', $query->createNamedParameter('users'))); if ($participant->getUser() === '') { + // FIXME $query->andWhere($query->expr()->eq('session_id', $query->createNamedParameter($participant->getSessionId()))); } @@ -814,9 +816,10 @@ class Room { $this->dispatcher->dispatch(self::EVENT_BEFORE_USER_REMOVE, $event); $query = $this->db->getQueryBuilder(); - $query->delete('talk_participants') + $query->delete('talk_attendees') ->where($query->expr()->eq('room_id', $query->createNamedParameter($this->getId(), IQueryBuilder::PARAM_INT))) - ->andWhere($query->expr()->eq('user_id', $query->createNamedParameter($user->getUID()))); + ->andWhere($query->expr()->eq('actor_id', $query->createNamedParameter($user->getUID()))) + ->andWhere($query->expr()->eq('actor_type', $query->createNamedParameter('users'))); $query->execute(); $this->dispatcher->dispatch(self::EVENT_AFTER_USER_REMOVE, $event); @@ -929,8 +932,9 @@ class Room { // And kill session when leaving a self joined room $query = $this->db->getQueryBuilder(); - $query->delete('talk_participants') - ->where($query->expr()->eq('user_id', $query->createNamedParameter($participant->getUser()))) + $query->delete('talk_attendees') + ->where($query->expr()->eq('actor_id', $query->createNamedParameter($participant->getUser()))) + ->andWhere($query->expr()->eq('actor_type', $query->createNamedParameter('users'))) ->andWhere($query->expr()->eq('room_id', $query->createNamedParameter($this->getId(), IQueryBuilder::PARAM_INT))) ->andWhere($query->expr()->eq('participant_type', $query->createNamedParameter(Participant::USER_SELF_JOINED, IQueryBuilder::PARAM_INT))); if ($sessionId !== null && $sessionId !== '0') { @@ -1388,17 +1392,4 @@ class Room { $query->execute(); } - - /** - * @param string[] $sessionIds - * @param int $timestamp - */ - public function pingSessionIds(array $sessionIds, int $timestamp): void { - $query = $this->db->getQueryBuilder(); - $query->update('talk_participants') - ->set('last_ping', $query->createNamedParameter($timestamp, IQueryBuilder::PARAM_INT)) - ->where($query->expr()->in('session_id', $query->createNamedParameter($sessionIds, IQueryBuilder::PARAM_STR_ARRAY))); - - $query->execute(); - } } diff --git a/lib/Service/SessionService.php b/lib/Service/SessionService.php new file mode 100644 index 000000000..822a7b710 --- /dev/null +++ b/lib/Service/SessionService.php @@ -0,0 +1,60 @@ +<?php + +declare(strict_types=1); +/** + * @copyright Copyright (c) 2020 Joas Schilling <coding@schilljs.com> + * + * @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 <http://www.gnu.org/licenses/>. + * + */ + +namespace OCA\Talk\Service; + +use OCA\Talk\Model\SessionMapper; +use OCP\DB\QueryBuilder\IQueryBuilder; +use OCP\IDBConnection; + +class SessionService { + /** @var SessionMapper */ + protected $mapper; + /** @var IDBConnection */ + protected $connection; + + public function __construct(SessionMapper $mapper, + IDBConnection $connection) { + $this->mapper = $mapper; + $this->connection = $connection; + } + + /** + * Update last ping for multiple sessions + * + * Since this function is called by the HPB with potentially hundreds of + * sessions, we do not use the SessionMapper to get the entities first, as + * that would just not scale good enough. + * + * @param string[] $sessionIds + * @param int $lastPing + */ + public function updateMultipleLastPings(array $sessionIds, int $lastPing): void { + $query = $this->connection->getQueryBuilder(); + $query->update('talk_sessions') + ->set('last_ping', $query->createNamedParameter($lastPing, IQueryBuilder::PARAM_INT)) + ->where($query->expr()->in('session_id', $query->createNamedParameter($sessionIds, IQueryBuilder::PARAM_STR_ARRAY))); + + $query->execute(); + } +} |