diff options
author | Joas Schilling <coding@schilljs.com> | 2024-03-13 17:18:55 +0100 |
---|---|---|
committer | Joas Schilling <coding@schilljs.com> | 2024-03-14 09:47:20 +0100 |
commit | 30215a728be86a7ce25355f13f74f5c68425673d (patch) | |
tree | fe807a7907d4a5abfdffcca862767cf1b969213b /lib | |
parent | ec2ce3b97e0a8017b6209b70533331ae3478f05d (diff) |
fix(federation): Cache whether we have federated participants in a conversation
Signed-off-by: Joas Schilling <coding@schilljs.com>
Diffstat (limited to 'lib')
-rw-r--r-- | lib/Manager.php | 2 | ||||
-rw-r--r-- | lib/Migration/Version19000Date20240313134926.php | 102 | ||||
-rw-r--r-- | lib/Model/SelectHelper.php | 1 | ||||
-rw-r--r-- | lib/Room.php | 23 | ||||
-rw-r--r-- | lib/Service/ParticipantService.php | 11 | ||||
-rw-r--r-- | lib/Service/RoomService.php | 13 |
6 files changed, 152 insertions, 0 deletions
diff --git a/lib/Manager.php b/lib/Manager.php index 2761fb872..b9a81c65e 100644 --- a/lib/Manager.php +++ b/lib/Manager.php @@ -134,6 +134,7 @@ class Manager { 'breakout_room_status' => 0, 'call_recording' => 0, 'recording_consent' => 0, + 'has_federation' => 0, ], $data)); } @@ -202,6 +203,7 @@ class Manager { (int) $row['breakout_room_status'], (int) $row['call_recording'], (int) $row['recording_consent'], + (int) $row['has_federation'], ); } diff --git a/lib/Migration/Version19000Date20240313134926.php b/lib/Migration/Version19000Date20240313134926.php new file mode 100644 index 000000000..f3713e293 --- /dev/null +++ b/lib/Migration/Version19000Date20240313134926.php @@ -0,0 +1,102 @@ +<?php + +declare(strict_types=1); + +/** + * @copyright Copyright (c) 2024 Joas Schilling <coding@schilljs.com> + * + * @author 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\Migration; + +use Closure; +use OCA\Talk\Model\Attendee; +use OCA\Talk\Model\Invitation; +use OCP\DB\ISchemaWrapper; +use OCP\DB\Types; +use OCP\IDBConnection; +use OCP\Migration\IOutput; +use OCP\Migration\SimpleMigrationStep; + +/** + * Cache the invite state in the attendees and room table to allow reducing efforts + */ +class Version19000Date20240313134926 extends SimpleMigrationStep { + public function __construct( + protected IDBConnection $connection, + ) { + } + + /** + * @param IOutput $output + * @param Closure(): ISchemaWrapper $schemaClosure + * @param array $options + * @return null|ISchemaWrapper + */ + public function changeSchema(IOutput $output, Closure $schemaClosure, array $options): ?ISchemaWrapper { + /** @var ISchemaWrapper $schema */ + $schema = $schemaClosure(); + + $table = $schema->getTable('talk_attendees'); + $table->addColumn('state', Types::SMALLINT, [ + 'default' => 0, + 'unsigned' => true, + ]); + $table->addColumn('unread_messages', Types::BIGINT, [ + 'default' => 0, + 'unsigned' => true, + ]); + + $table = $schema->getTable('talk_rooms'); + $table->addColumn('has_federation', Types::SMALLINT, [ + 'default' => 0, + 'unsigned' => true, + ]); + + return $schema; + } + + /** + * Set the invitation state to accepted for existing federated users + * Set the "has federation" for rooms with TalkV1 users + */ + public function postSchemaChange(IOutput $output, \Closure $schemaClosure, array $options) { + $query = $this->connection->getQueryBuilder(); + $query->update('talk_attendees') + ->set('state', $query->createNamedParameter(Invitation::STATE_ACCEPTED)) + ->where($query->expr()->eq('actor_type', $query->createNamedParameter(Attendee::ACTOR_FEDERATED_USERS))); + $query->executeStatement(); + + $query = $this->connection->getQueryBuilder(); + $subQuery = $this->connection->getQueryBuilder(); + $subQuery->select('room_id') + ->from('talk_attendees') + ->where($subQuery->expr()->eq('actor_type', $query->createNamedParameter(Attendee::ACTOR_FEDERATED_USERS))) + ->groupBy('room_id'); + + $query = $this->connection->getQueryBuilder(); + $query->update('talk_rooms') + // Don't use const Room::HAS_FEDERATION_TALKv1 because the file might have been loaded with old content before the migration + // ->set('has_federation', $query->createNamedParameter(Room::HAS_FEDERATION_TALKv1)) + ->set('has_federation', $query->createNamedParameter(1)) + ->where($query->expr()->in('id', $query->createFunction($subQuery->getSQL()))); + $query->executeStatement(); + } +} diff --git a/lib/Model/SelectHelper.php b/lib/Model/SelectHelper.php index 11304a0de..537992db4 100644 --- a/lib/Model/SelectHelper.php +++ b/lib/Model/SelectHelper.php @@ -59,6 +59,7 @@ class SelectHelper { ->addSelect($alias . 'breakout_room_status') ->addSelect($alias . 'call_recording') ->addSelect($alias . 'recording_consent') + ->addSelect($alias . 'has_federation') ->selectAlias($alias . 'id', 'r_id'); } diff --git a/lib/Room.php b/lib/Room.php index 3fdaa081f..e00625fda 100644 --- a/lib/Room.php +++ b/lib/Room.php @@ -96,12 +96,16 @@ class Room { public const DESCRIPTION_MAXIMUM_LENGTH = 500; + public const HAS_FEDERATION_NONE = 0; + public const HAS_FEDERATION_TALKv1 = 1; + protected ?string $currentUser = null; protected ?Participant $participant = null; /** * @psalm-param Room::TYPE_* $type * @psalm-param RecordingService::CONSENT_REQUIRED_* $recordingConsent + * @psalm-param int-mask-of<self::HAS_FEDERATION_*> $hasFederation */ public function __construct( private Manager $manager, @@ -138,6 +142,7 @@ class Room { private int $breakoutRoomStatus, private int $callRecording, private int $recordingConsent, + private int $hasFederation, ) { } @@ -410,6 +415,9 @@ class Room { return $this->remoteToken; } + /** + * @deprecated + */ public function isFederatedRemoteRoom(): bool { return $this->remoteServer !== ''; } @@ -558,4 +566,19 @@ class Room { public function setRecordingConsent(int $recordingConsent): void { $this->recordingConsent = $recordingConsent; } + + /** + * @psalm-return int-mask-of<self::HAS_FEDERATION_*> + */ + public function hasFederatedParticipants(): int { + return $this->hasFederation; + } + + /** + * @param int $hasFederation + * @psalm-param int-mask-of<self::HAS_FEDERATION_*> $hasFederation (bit map) + */ + public function setFederatedParticipants(int $hasFederation): void { + $this->hasFederation = $hasFederation; + } } diff --git a/lib/Service/ParticipantService.php b/lib/Service/ParticipantService.php index d68ed521b..f8c0dae7c 100644 --- a/lib/Service/ParticipantService.php +++ b/lib/Service/ParticipantService.php @@ -514,6 +514,7 @@ class ParticipantService { $event = new BeforeAttendeesAddedEvent($room, $attendees); $this->dispatcher->dispatchTyped($event); + $setFederationFlagAlready = $room->hasFederatedParticipants() & Room::HAS_FEDERATION_TALKv1; foreach ($attendees as $attendee) { try { $this->attendeeMapper->insert($attendee); @@ -524,6 +525,16 @@ class ParticipantService { $this->attendeeMapper->delete($attendee); throw new CannotReachRemoteException(); } + + if (!$setFederationFlagAlready) { + $flag = $room->hasFederatedParticipants() | Room::HAS_FEDERATION_TALKv1; + + /** @var RoomService $roomService */ + $roomService = Server::get(RoomService::class); + $roomService->setHasFederation($room, $flag); + + $setFederationFlagAlready = true; + } } } catch (Exception $e) { if ($e->getReason() !== Exception::REASON_UNIQUE_CONSTRAINT_VIOLATION) { diff --git a/lib/Service/RoomService.php b/lib/Service/RoomService.php index d606282dd..9dfae845d 100644 --- a/lib/Service/RoomService.php +++ b/lib/Service/RoomService.php @@ -886,6 +886,19 @@ class RoomService { $room->setLastActivity($dateTime); } + /** + * @psalm-param int-mask-of<Room::HAS_FEDERATION_*> $hasFederation + */ + public function setHasFederation(Room $room, int $hasFederation): void { + $update = $this->db->getQueryBuilder(); + $update->update('talk_rooms') + ->set('has_federation', $update->createNamedParameter($hasFederation, IQueryBuilder::PARAM_INT)) + ->where($update->expr()->eq('id', $update->createNamedParameter($room->getId(), IQueryBuilder::PARAM_INT))); + $update->executeStatement(); + + $room->setFederatedParticipants($hasFederation); + } + public function setLastActivity(Room $room, \DateTime $now): void { $update = $this->db->getQueryBuilder(); $update->update('talk_rooms') |