summaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
authorJoas Schilling <coding@schilljs.com>2024-03-13 17:18:55 +0100
committerJoas Schilling <coding@schilljs.com>2024-03-14 09:47:20 +0100
commit30215a728be86a7ce25355f13f74f5c68425673d (patch)
treefe807a7907d4a5abfdffcca862767cf1b969213b /lib
parentec2ce3b97e0a8017b6209b70533331ae3478f05d (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.php2
-rw-r--r--lib/Migration/Version19000Date20240313134926.php102
-rw-r--r--lib/Model/SelectHelper.php1
-rw-r--r--lib/Room.php23
-rw-r--r--lib/Service/ParticipantService.php11
-rw-r--r--lib/Service/RoomService.php13
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')