You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
230 lines
7.6 KiB
230 lines
7.6 KiB
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
/**
|
|
* SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
|
|
* SPDX-License-Identifier: AGPL-3.0-or-later
|
|
*/
|
|
|
|
namespace OCA\Talk\Federation\Proxy\TalkV1;
|
|
|
|
use OCA\Talk\Model\Attendee;
|
|
use OCA\Talk\ResponseDefinitions;
|
|
use OCA\Talk\Room;
|
|
use OCA\Talk\Service\AvatarService;
|
|
use OCA\Talk\Service\ParticipantService;
|
|
|
|
/**
|
|
* @psalm-import-type TalkChatMessageWithParent from ResponseDefinitions
|
|
* @psalm-import-type TalkPoll from ResponseDefinitions
|
|
* @psalm-import-type TalkPollDraft from ResponseDefinitions
|
|
* @psalm-import-type TalkReaction from ResponseDefinitions
|
|
*/
|
|
class UserConverter {
|
|
/**
|
|
* @var array<string, array<string, array{userId: string, displayName: string}>>
|
|
*/
|
|
protected array $participantsPerRoom = [];
|
|
|
|
public function __construct(
|
|
protected ParticipantService $participantService,
|
|
protected AvatarService $avatarService,
|
|
) {
|
|
}
|
|
|
|
/**
|
|
* @return array{type: string, id: string}
|
|
*/
|
|
public function convertTypeAndId(Room $room, string $type, string $id): array {
|
|
if ($type === Attendee::ACTOR_USERS) {
|
|
$type = Attendee::ACTOR_FEDERATED_USERS;
|
|
$id = $this->createCloudIdFromUserIdAndFullServerUrl($id, $room->getRemoteServer());
|
|
} elseif ($type === Attendee::ACTOR_FEDERATED_USERS) {
|
|
$localParticipants = $this->getLocalParticipants($room);
|
|
if (isset($localParticipants[$id])) {
|
|
$local = $localParticipants[$id];
|
|
|
|
$type = Attendee::ACTOR_USERS;
|
|
$id = $local['userId'];
|
|
}
|
|
}
|
|
|
|
return ['type' => $type, 'id' => $id];
|
|
}
|
|
|
|
public function convertAttendee(Room $room, array $entry, string $typeField, string $idField, string $displayNameField): array {
|
|
if (!isset($entry[$typeField])) {
|
|
return $entry;
|
|
}
|
|
|
|
if ($entry[$typeField] === Attendee::ACTOR_USERS) {
|
|
$entry[$typeField] = Attendee::ACTOR_FEDERATED_USERS;
|
|
$entry[$idField] = $this->createCloudIdFromUserIdAndFullServerUrl($entry[$idField], $room->getRemoteServer());
|
|
} elseif ($entry[$typeField] === Attendee::ACTOR_FEDERATED_USERS) {
|
|
$localParticipants = $this->getLocalParticipants($room);
|
|
if (isset($localParticipants[$entry[$idField]])) {
|
|
$local = $localParticipants[$entry[$idField]];
|
|
|
|
$entry[$typeField] = Attendee::ACTOR_USERS;
|
|
$entry[$idField] = $local['userId'];
|
|
$entry[$displayNameField] = $local['displayName'];
|
|
}
|
|
}
|
|
return $entry;
|
|
}
|
|
|
|
public function convertAttendees(Room $room, array $entries, string $typeField, string $idField, string $displayNameField): array {
|
|
return array_map(
|
|
fn (array $entry): array => $this->convertAttendee($room, $entry, $typeField, $idField, $displayNameField),
|
|
$entries
|
|
);
|
|
}
|
|
|
|
protected function convertMessageParameter(Room $room, array $parameter): array {
|
|
if ($parameter['type'] === 'user') { // RichObjectDefinition, not Attendee::ACTOR_USERS
|
|
if (!isset($parameter['server'])) {
|
|
$parameter['server'] = $room->getRemoteServer();
|
|
if (!isset($parameter['mention-id'])) {
|
|
$parameter['mention-id'] = $parameter['id'];
|
|
}
|
|
} elseif ($parameter['server']) {
|
|
$localParticipants = $this->getLocalParticipants($room);
|
|
$cloudId = $this->createCloudIdFromUserIdAndFullServerUrl($parameter['id'], $parameter['server']);
|
|
if (!isset($parameter['mention-id'])) {
|
|
$parameter['mention-id'] = 'federated_user/' . $parameter['id'] . '@' . $parameter['server'];
|
|
}
|
|
if (isset($localParticipants[$cloudId])) {
|
|
unset($parameter['server']);
|
|
$parameter['name'] = $localParticipants[$cloudId]['displayName'];
|
|
}
|
|
}
|
|
} elseif ($parameter['type'] === 'call' && $parameter['id'] === $room->getRemoteToken()) {
|
|
$parameter['id'] = $room->getToken();
|
|
$parameter['icon-url'] = $this->avatarService->getAvatarUrl($room);
|
|
if (!isset($parameter['mention-id'])) {
|
|
$parameter['mention-id'] = 'all';
|
|
}
|
|
} elseif ($parameter['type'] === 'circle') {
|
|
if (!isset($parameter['mention-id'])) {
|
|
$parameter['mention-id'] = 'team/' . $parameter['id'];
|
|
}
|
|
} elseif ($parameter['type'] === 'user-group') {
|
|
if (!isset($parameter['mention-id'])) {
|
|
$parameter['mention-id'] = 'group/' . $parameter['id'];
|
|
}
|
|
} elseif ($parameter['type'] === 'email' || $parameter['type'] === 'guest') {
|
|
if (!isset($parameter['mention-id'])) {
|
|
$parameter['mention-id'] = $parameter['type'] . '/' . $parameter['id'];
|
|
}
|
|
}
|
|
return $parameter;
|
|
}
|
|
|
|
public function convertMessageParameters(Room $room, array $message): array {
|
|
$message['messageParameters'] = array_map(
|
|
fn (array $message): array => $this->convertMessageParameter($room, $message),
|
|
$message['messageParameters']
|
|
);
|
|
return $message;
|
|
}
|
|
|
|
/**
|
|
* @param Room $room
|
|
* @param TalkChatMessageWithParent $message
|
|
* @return TalkChatMessageWithParent
|
|
*/
|
|
public function convertMessage(Room $room, array $message): array {
|
|
$message['token'] = $room->getToken();
|
|
$message = $this->convertAttendee($room, $message, 'actorType', 'actorId', 'actorDisplayName');
|
|
$message = $this->convertAttendee($room, $message, 'lastEditActorType', 'lastEditActorId', 'lastEditActorDisplayName');
|
|
$message = $this->convertMessageParameters($room, $message);
|
|
|
|
if (isset($message['parent'])) {
|
|
$message['parent'] = $this->convertMessage($room, $message['parent']);
|
|
}
|
|
return $message;
|
|
}
|
|
|
|
/**
|
|
* @param Room $room
|
|
* @param TalkChatMessageWithParent[] $messages
|
|
* @return TalkChatMessageWithParent[]
|
|
*/
|
|
public function convertMessages(Room $room, array $messages): array {
|
|
return array_map(
|
|
fn (array $message): array => $this->convertMessage($room, $message),
|
|
$messages
|
|
);
|
|
}
|
|
|
|
/**
|
|
* @template T of TalkPoll|TalkPollDraft
|
|
* @param Room $room
|
|
* @param TalkPoll|TalkPollDraft $poll
|
|
* @psalm-param T $poll
|
|
* @return TalkPoll|TalkPollDraft
|
|
* @psalm-return T
|
|
*/
|
|
public function convertPoll(Room $room, array $poll): array {
|
|
$poll = $this->convertAttendee($room, $poll, 'actorType', 'actorId', 'actorDisplayName');
|
|
if (isset($poll['details'])) {
|
|
$poll['details'] = array_map(
|
|
fn (array $vote): array => $this->convertAttendee($room, $vote, 'actorType', 'actorId', 'actorDisplayName'),
|
|
$poll['details']
|
|
);
|
|
}
|
|
return $poll;
|
|
}
|
|
|
|
/**
|
|
* @param Room $room
|
|
* @param TalkReaction[] $reactions
|
|
* @return TalkReaction[]
|
|
*/
|
|
protected function convertReactions(Room $room, array $reactions): array {
|
|
return array_map(
|
|
fn (array $reaction): array => $this->convertAttendee($room, $reaction, 'actorType', 'actorId', 'actorDisplayName'),
|
|
$reactions
|
|
);
|
|
}
|
|
|
|
/**
|
|
* @param Room $room
|
|
* @param array<string, TalkReaction[]> $reactionsList
|
|
* @return array<string, TalkReaction[]>
|
|
*/
|
|
public function convertReactionsList(Room $room, array $reactionsList): array {
|
|
return array_map(
|
|
fn (array $reactions): array => $this->convertReactions($room, $reactions),
|
|
$reactionsList
|
|
);
|
|
}
|
|
|
|
/**
|
|
* @return array<string, array{userId: string, displayName: string}>
|
|
*/
|
|
protected function getLocalParticipants(Room $room): array {
|
|
if (array_key_exists($room->getToken(), $this->participantsPerRoom)) {
|
|
return $this->participantsPerRoom[$room->getToken()];
|
|
}
|
|
|
|
$this->participantsPerRoom[$room->getToken()] = [];
|
|
$localParticipants = $this->participantService->getActorsByType($room, Attendee::ACTOR_USERS);
|
|
foreach ($localParticipants as $participant) {
|
|
$this->participantsPerRoom[$room->getToken()][$participant->getInvitedCloudId()] = [
|
|
'userId' => $participant->getActorId(),
|
|
'displayName' => $participant->getDisplayName(),
|
|
];
|
|
}
|
|
|
|
return $this->participantsPerRoom[$room->getToken()];
|
|
}
|
|
|
|
protected function createCloudIdFromUserIdAndFullServerUrl(string $userId, string $serverUrl): string {
|
|
if (str_starts_with($serverUrl, 'https://')) {
|
|
$serverUrl = substr($serverUrl, strlen('https://'));
|
|
}
|
|
return $userId . '@' . $serverUrl;
|
|
}
|
|
}
|