Skip to content

Commit

Permalink
feat(mentions): Add mention @ALL permission for rooms
Browse files Browse the repository at this point in the history
Signed-off-by: Sanskar Soni <sanskarsoni300@gmail.com>
  • Loading branch information
sanskar-soni-9 committed Jul 5, 2024
1 parent 8b6f00f commit ab7a1b6
Show file tree
Hide file tree
Showing 13 changed files with 112 additions and 9 deletions.
2 changes: 2 additions & 0 deletions appinfo/routes/routesRoomController.php
Original file line number Diff line number Diff line change
Expand Up @@ -107,5 +107,7 @@
['name' => 'Room#setMessageExpiration', 'url' => '/api/{apiVersion}/room/{token}/message-expiration', 'verb' => 'POST', 'requirements' => $requirementsWithToken],
/** @see \OCA\Talk\Controller\RoomController::getCapabilities() */
['name' => 'Room#getCapabilities', 'url' => '/api/{apiVersion}/room/{token}/capabilities', 'verb' => 'GET', 'requirements' => $requirementsWithToken],
/** @see \OCA\Talk\Controller\RoomController::setMentionPermissions() */
['name' => 'Room#setMentionPermissions', 'url' => '/api/{apiVersion}/room/{token}/mention-permissions', 'verb' => 'PUT', 'requirements' => $requirementsWithToken],
],
];
15 changes: 11 additions & 4 deletions lib/Chat/ChatManager.php
Original file line number Diff line number Diff line change
Expand Up @@ -320,11 +320,14 @@ public function sendMessage(
}
}

$metadata = [];
if ($silent) {
$comment->setMetaData([
Message::METADATA_SILENT => true,
]);
$metadata[Message::METADATA_SILENT] = true;
}
if ($chat->getMentionPermissions() === Room::MENTION_PERMISSIONS_EVERYONE || $participant?->hasModeratorPermissions()) {
$metadata[Message::METADATA_CAN_MENTION_ALL] = true;
}
$comment->setMetaData($metadata);

$event = new BeforeChatMessageSentEvent($chat, $comment, $participant, $silent, $replyTo);
$this->dispatcher->dispatchTyped($event);
Expand Down Expand Up @@ -359,7 +362,7 @@ public function sendMessage(
}
}

$alreadyNotifiedUsers = $this->notifier->notifyMentionedUsers($chat, $comment, $alreadyNotifiedUsers, $silent);
$alreadyNotifiedUsers = $this->notifier->notifyMentionedUsers($chat, $comment, $alreadyNotifiedUsers, $silent, $participant);
if (!empty($alreadyNotifiedUsers)) {
$userIds = array_column($alreadyNotifiedUsers, 'id');
$this->participantService->markUsersAsMentioned($chat, Attendee::ACTOR_USERS, $userIds, (int) $comment->getId(), $usersDirectlyMentioned);
Expand Down Expand Up @@ -942,6 +945,10 @@ public function addConversationNotify(array $results, string $search, Room $room
if ($room->getType() === Room::TYPE_ONE_TO_ONE) {
return $results;
}
if ($room->getMentionPermissions() === Room::MENTION_PERMISSIONS_MODERATORS && !$participant->hasModeratorPermissions()) {
return $results;
}

$attendee = $participant->getAttendee();
if ($attendee->getActorType() === Attendee::ACTOR_USERS) {
$roomDisplayName = $room->getDisplayName($attendee->getActorId());
Expand Down
19 changes: 14 additions & 5 deletions lib/Chat/Notifier.php
Original file line number Diff line number Diff line change
Expand Up @@ -53,13 +53,17 @@ public function __construct(
* Not every user mentioned in the message is notified, but only those that
* are able to participate in the room.
*
* @param Room $chat
* @param IComment $comment
* @param array[] $alreadyNotifiedUsers
* @psalm-param array<int, array{id: string, type: string, reason: string, sourceId?: string, attendee?: Attendee}> $alreadyNotifiedUsers
* @param bool $silent
* @param Participant|null $participant
* @return string[] Users that were mentioned
* @psalm-return array<int, array{id: string, type: string, reason: string, sourceId?: string, attendee?: Attendee}>
*/
public function notifyMentionedUsers(Room $chat, IComment $comment, array $alreadyNotifiedUsers, bool $silent): array {
$usersToNotify = $this->getUsersToNotify($chat, $comment, $alreadyNotifiedUsers);
public function notifyMentionedUsers(Room $chat, IComment $comment, array $alreadyNotifiedUsers, bool $silent, ?Participant $participant): array {
$usersToNotify = $this->getUsersToNotify($chat, $comment, $alreadyNotifiedUsers, $participant);

if (!$usersToNotify) {
return $alreadyNotifiedUsers;
Expand Down Expand Up @@ -102,13 +106,14 @@ public function notifyMentionedUsers(Room $chat, IComment $comment, array $alrea
* @param IComment $comment
* @param array $alreadyNotifiedUsers
* @psalm-param array<int, array{id: string, type: string, reason: string, sourceId?: string, attendee?: Attendee}> $alreadyNotifiedUsers
* @param Participant|null $participant
* @return array
* @psalm-return array<int, array{id: string, type: string, reason: string, sourceId?: string, attendee?: Attendee}>
*/
public function getUsersToNotify(Room $chat, IComment $comment, array $alreadyNotifiedUsers): array {
public function getUsersToNotify(Room $chat, IComment $comment, array $alreadyNotifiedUsers, ?Participant $participant): array {
$usersToNotify = $this->getMentionedUsers($comment);
$usersToNotify = $this->getMentionedGroupMembers($chat, $comment, $usersToNotify);
$usersToNotify = $this->addMentionAllToList($chat, $usersToNotify);
$usersToNotify = $this->addMentionAllToList($chat, $usersToNotify, $participant);
$usersToNotify = $this->removeAlreadyNotifiedUsers($usersToNotify, $alreadyNotifiedUsers);

return $usersToNotify;
Expand Down Expand Up @@ -137,17 +142,21 @@ private function removeAlreadyNotifiedUsers(array $usersToNotify, array $already
* @param Room $chat
* @param array $list
* @psalm-param array<int, array{id: string, type: string, reason: string, sourceId?: string}> $list
* @param Participant|null $participant
* @return array
* @psalm-return array<int, array{id: string, type: string, reason: string, sourceId?: string, attendee?: Attendee}>
*/
private function addMentionAllToList(Room $chat, array $list): array {
private function addMentionAllToList(Room $chat, array $list, ?Participant $participant): array {
$usersToNotify = array_filter($list, static function (array $entry): bool {
return $entry['type'] !== Attendee::ACTOR_USERS || $entry['id'] !== 'all';
});

if (count($list) === count($usersToNotify)) {
return $usersToNotify;
}
if ($chat->getMentionPermissions() === Room::MENTION_PERMISSIONS_MODERATORS && (!$participant instanceof Participant || !$participant->hasModeratorPermissions())) {
return $usersToNotify;
}

$attendees = $this->participantService->getActorsByType($chat, Attendee::ACTOR_USERS);
foreach ($attendees as $attendee) {
Expand Down
5 changes: 5 additions & 0 deletions lib/Chat/Parser/UserMention.php
Original file line number Diff line number Diff line change
Expand Up @@ -90,8 +90,13 @@ protected function parseMessage(Message $chatMessage): void {
return mb_strlen($m2['id']) <=> mb_strlen($m1['id']);
});

$metadata = $comment->getMetaData() ?? [];
foreach ($mentions as $mention) {
if ($mention['type'] === 'user' && $mention['id'] === 'all') {
if (!isset($metadata[Message::METADATA_CAN_MENTION_ALL])) {
continue;
}

$mention['type'] = 'call';
}

Expand Down
20 changes: 20 additions & 0 deletions lib/Controller/RoomController.php
Original file line number Diff line number Diff line change
Expand Up @@ -1438,6 +1438,26 @@ public function setListable(int $scope): DataResponse {
return new DataResponse();
}

/**
* Update the mention permissoins for a room
*
* @param 0|1 $mentionPermissions New mention permissions
* @psalm-param Room::MENTION_PERMISSIONS_* $mentionPermissions
* @return DataResponse<Http::STATUS_OK, TalkRoom, array{}>|DataResponse<Http::STATUS_BAD_REQUEST, array<empty>, array{}>
*
* 200: Permissions updated successfully
* 400: Updating permissions is not possible
*/
#[NoAdminRequired]
#[RequireModeratorParticipant]
public function setMentionPermissions(int $mentionPermissions): DataResponse {
if (!$this->roomService->setMentionPermissions($this->room, $mentionPermissions)) {
return new DataResponse([], Http::STATUS_BAD_REQUEST);
}

return new DataResponse($this->formatRoom($this->room, $this->participant));
}

/**
* Set a password for a room
*
Expand Down
1 change: 1 addition & 0 deletions lib/Events/ARoomModifiedEvent.php
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ abstract class ARoomModifiedEvent extends ARoomEvent {
public const PROPERTY_RECORDING_CONSENT = 'recordingConsent';
public const PROPERTY_SIP_ENABLED = 'sipEnabled';
public const PROPERTY_TYPE = 'type';
public const PROPERTY_MENTION_PERMISSIONS = 'mentionPermissions';

/**
* @param self::PROPERTY_* $property
Expand Down
2 changes: 2 additions & 0 deletions lib/Manager.php
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,7 @@ public function createRoomObjectFromData(array $data): Room {
'call_recording' => 0,
'recording_consent' => 0,
'has_federation' => 0,
'mention_permissions' => 0,
], $data));
}

Expand Down Expand Up @@ -189,6 +190,7 @@ public function createRoomObject(array $row): Room {
(int) $row['call_recording'],
(int) $row['recording_consent'],
(int) $row['has_federation'],
(int) $row['mention_permissions'],
);
}

Expand Down
1 change: 1 addition & 0 deletions lib/Model/Message.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ class Message {
public const METADATA_LAST_EDITED_BY_ID = 'last_edited_by_id';
public const METADATA_LAST_EDITED_TIME = 'last_edited_time';
public const METADATA_SILENT = 'silent';
public const METADATA_CAN_MENTION_ALL = 'can_mention_all';

/** @var bool */
protected $visible = true;
Expand Down
1 change: 1 addition & 0 deletions lib/Model/SelectHelper.php
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ public function selectRoomsTable(IQueryBuilder $query, string $alias = 'r'): voi
->addSelect($alias . 'call_recording')
->addSelect($alias . 'recording_consent')
->addSelect($alias . 'has_federation')
->addSelect($alias . 'mention_permissions')
->selectAlias($alias . 'id', 'r_id');
}

Expand Down
1 change: 1 addition & 0 deletions lib/ResponseDefinitions.php
Original file line number Diff line number Diff line change
Expand Up @@ -244,6 +244,7 @@
* listable: int,
* lobbyState: int,
* lobbyTimer: int,
* mentionPermissions: int,
* messageExpiration: int,
* name: string,
* notificationCalls: int,
Expand Down
12 changes: 12 additions & 0 deletions lib/Room.php
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,9 @@ class Room {
public const HAS_FEDERATION_NONE = 0;
public const HAS_FEDERATION_TALKv1 = 1;

public const MENTION_PERMISSIONS_EVERYONE = 0;
public const MENTION_PERMISSIONS_MODERATORS = 1;

protected ?string $currentUser = null;
protected ?Participant $participant = null;

Expand Down Expand Up @@ -124,6 +127,7 @@ public function __construct(
private int $callRecording,
private int $recordingConsent,
private int $hasFederation,
private int $mentionPermissions,
) {
}

Expand Down Expand Up @@ -559,4 +563,12 @@ public function hasFederatedParticipants(): int {
public function setFederatedParticipants(int $hasFederation): void {
$this->hasFederation = $hasFederation;
}

public function getMentionPermissions(): int {
return $this->mentionPermissions;
}

public function setMentionPermissions(int $mentionPermissions): void {
$this->mentionPermissions = $mentionPermissions;
}
}
2 changes: 2 additions & 0 deletions lib/Service/RoomFormatter.php
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,7 @@ public function formatRoomV4(
'breakoutRoomMode' => BreakoutRoom::MODE_NOT_CONFIGURED,
'breakoutRoomStatus' => BreakoutRoom::STATUS_STOPPED,
'recordingConsent' => $this->talkConfig->recordingConsentRequired() === RecordingService::CONSENT_REQUIRED_OPTIONAL ? $room->getRecordingConsent() : $this->talkConfig->recordingConsentRequired(),
'mentionPermissions' => Room::MENTION_PERMISSIONS_EVERYONE,
];

$lastActivity = $room->getLastActivity();
Expand Down Expand Up @@ -217,6 +218,7 @@ public function formatRoomV4(
'messageExpiration' => $room->getMessageExpiration(),
'breakoutRoomMode' => $room->getBreakoutRoomMode(),
'breakoutRoomStatus' => $room->getBreakoutRoomStatus(),
'mentionPermissions' => $room->getMentionPermissions(),
]);

if ($currentParticipant->getAttendee()->getReadPrivacy() === Participant::PRIVACY_PUBLIC) {
Expand Down
40 changes: 40 additions & 0 deletions lib/Service/RoomService.php
Original file line number Diff line number Diff line change
Expand Up @@ -603,6 +603,46 @@ public function setListable(Room $room, int $newState): bool {
return true;
}

/**
* @param Room $room
* @param int $newState New mention permissions from self::MENTION_PERMISSIONS_*
* @return bool True when the change was valid, false otherwise
*/
public function setMentionPermissions(Room $room, int $newState): bool {
$oldState = $room->getMentionPermissions();
if ($newState === $oldState) {
return true;
}

if (!in_array($room->getType(), [Room::TYPE_GROUP, Room::TYPE_PUBLIC], true)) {
return false;
}

if ($room->getObjectType() === BreakoutRoom::PARENT_OBJECT_TYPE) {
return false;
}

if (!in_array($newState, [Room::MENTION_PERMISSIONS_EVERYONE, Room::MENTION_PERMISSIONS_MODERATORS])) {
return false;
}

$event = new BeforeRoomModifiedEvent($room, ARoomModifiedEvent::PROPERTY_MENTION_PERMISSIONS, $newState, $oldState);
$this->dispatcher->dispatchTyped($event);

$update = $this->db->getQueryBuilder();
$update->update('talk_rooms')
->set('mention_permissions', $update->createNamedParameter($newState, IQueryBuilder::PARAM_INT))
->where($update->expr()->eq('id', $update->createNamedParameter($room->getId(), IQueryBuilder::PARAM_INT)));
$update->executeStatement();

$room->setMentionPermissions($newState);

$event = new RoomModifiedEvent($room, ARoomModifiedEvent::PROPERTY_MENTION_PERMISSIONS, $newState, $oldState);
$this->dispatcher->dispatchTyped($event);

return true;
}

public function setAssignedSignalingServer(Room $room, ?int $signalingServer): bool {
$update = $this->db->getQueryBuilder();
$update->update('talk_rooms')
Expand Down

0 comments on commit ab7a1b6

Please sign in to comment.