Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion appinfo/info.xml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ And in the works for the [coming versions](https://github.com/nextcloud/spreed/m

]]></description>

<version>18.0.0-dev.1</version>
<version>18.0.0-dev.2</version>
<licence>agpl</licence>

<author>Daniel Calviño Sánchez</author>
Expand Down
2 changes: 2 additions & 0 deletions appinfo/routes/routesRoomController.php
Original file line number Diff line number Diff line change
Expand Up @@ -108,5 +108,7 @@
['name' => 'Room#setSIPEnabled', 'url' => '/api/{apiVersion}/room/{token}/webinar/sip', 'verb' => 'PUT', 'requirements' => $requirementsWithToken],
/** @see \OCA\Talk\Controller\RoomController::setMessageExpiration() */
['name' => 'Room#setMessageExpiration', 'url' => '/api/{apiVersion}/room/{token}/message-expiration', 'verb' => 'POST', 'requirements' => $requirementsWithToken],
/** @see \OCA\Talk\Controller\RoomController::setCanMentionEveryone() */
['name' => 'Room#setCanMentionEveryone', 'url' => '/api/{apiVersion}/room/{token}/can-mention-everyone', 'verb' => 'PUT', 'requirements' => $requirementsWithToken],
],
];
3 changes: 3 additions & 0 deletions docs/capabilities.md
Original file line number Diff line number Diff line change
Expand Up @@ -121,3 +121,6 @@
* `config => call => supported-reactions` - A list of emojis supported as call reactions. If the list is absent or empty, clients should not show the emoji reaction option in calls.
* `config => chat => typing-privacy` - User defined numeric value to enable 1 or disable 0 the typing indicator to other users
* `typing-privacy` - Support toggle typing privacy

## 18
* `can-mention-everyone` - Allow non moderators to mention everyone using `@all`
4 changes: 4 additions & 0 deletions docs/constants.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,10 @@
* `0` No lobby
* `1` Lobby for non moderators

### Can mention everyone
* `0` Moderators only
* `1` Everyone (default)

### SIP states
* `0` Disabled
* `1` Enabled (Each participant needs a unique PIN)
Expand Down
19 changes: 19 additions & 0 deletions docs/conversation.md
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@
| `isCustomAvatar` | bool | v4 | | Flag if the conversation has a custom avatar (only available with `avatar` capability) |
| `callStartTime` | int | v4 | | Timestamp when the call was started (only available with `recording-v1` capability) |
| `callRecording` | int | v4 | | Type of call recording (see [Constants - Call recording status](constants.md#call-recording-status)) (only available with `recording-v1` capability) |
| `canMentionEveryone` | int | v4 | | Flag if non moderators can mention everyone (see [Constants - Can mention everyone](constants.md#can-mention-everyone)) (only available with `can-mention-everyone` capability) |

## Creating a new conversation

Expand Down Expand Up @@ -425,3 +426,21 @@ Get all (for moderators and in case of "free selection") or the assigned breakou
+ `400 Bad Request` When the conversation is a breakout room
+ `403 Forbidden` When the current user is not a moderator/owner or the conversation is not a public conversation
+ `404 Not Found` When the conversation could not be found for the participant

## Change the permission to mention everyone using `@all`
* Required capability: `can-mention-everyone`
* Method: `PUT`
* Endpoint: `/room/{token}/can-mention-everyone`
* Data:

| field | type | Description |
|----------|------|---------------------------------------------------------------------------|
| `config` | int | See [Constants - Can mention everyone](constants.md#can-mention-everyone) |

* Response:
- Status code:
+ `200 OK`
+ `400 Bad Request` Error: `config`: When the provided config value is invalid
+ `400 Bad Request` Error: `room`: When the conversation is a one-to-one conversation
+ `403 Forbidden` When the current user is not a moderator/owner or the conversation is not a one-to-one conversation
+ `404 Not Found` When the conversation could not be found for the participant
10 changes: 9 additions & 1 deletion lib/Chat/ChatManager.php
Original file line number Diff line number Diff line change
Expand Up @@ -297,7 +297,7 @@ public function sendMessage(Room $chat, Participant $participant, string $actorT
}
}

$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, $userIds, (int) $comment->getId(), $usersDirectlyMentioned);
Expand Down Expand Up @@ -756,6 +756,14 @@ public function addConversationNotify(array $results, string $search, Room $room
} else {
$roomDisplayName = $room->getDisplayName('');
}
switch ($room->getCanMentionEveryone()) {
case Room::CAN_MENTION_EVERYONE_ALL:
break;
case Room::CAN_MENTION_EVERYONE_MODERATORS:
if (!$participant->hasModeratorPermissions(true)) {
return $results;
}
}
if ($search === '' || $this->searchIsPartOfConversationNameOrAtAll($search, $roomDisplayName)) {
array_unshift($results, [
'id' => 'all',
Expand Down
30 changes: 25 additions & 5 deletions lib/Chat/Notifier.php
Original file line number Diff line number Diff line change
Expand Up @@ -92,11 +92,17 @@ public function __construct(
* @param IComment $comment
* @param array[] $alreadyNotifiedUsers
* @psalm-param array<int, array{id: string, type: string, reason: string}> $alreadyNotifiedUsers
* @param Participant $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 @@ -139,13 +145,18 @@ 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}> $alreadyNotifiedUsers
* @param Participant $participant
* @return array
* @psalm-return array<int, array{id: string, type: string, reason?: string, sourceId?: string, attendee?: Attendee}>
*/
private function getUsersToNotify(Room $chat, IComment $comment, array $alreadyNotifiedUsers): array {
private 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 @@ -177,7 +188,7 @@ private function removeAlreadyNotifiedUsers(array $usersToNotify, array $already
* @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';
});
Expand All @@ -186,6 +197,15 @@ private function addMentionAllToList(Room $chat, array $list): array {
return $usersToNotify;
}

switch ($chat->getCanMentionEveryone()) {
case Room::CAN_MENTION_EVERYONE_ALL:
break;
case Room::CAN_MENTION_EVERYONE_MODERATORS:
if (!$participant->hasModeratorPermissions(true)) {
return $usersToNotify;
}
}

$attendees = $this->participantService->getActorsByType($chat, Attendee::ACTOR_USERS);
foreach ($attendees as $attendee) {
$alreadyAddedToNotify = array_filter($list, static function ($user) use ($attendee): bool {
Expand Down
11 changes: 11 additions & 0 deletions lib/Controller/RoomController.php
Original file line number Diff line number Diff line change
Expand Up @@ -1491,4 +1491,15 @@ public function setMessageExpiration(int $seconds): DataResponse {

return new DataResponse();
}

#[NoAdminRequired]
#[RequireLoggedInModeratorParticipant]
public function setCanMentionEveryone(int $config): DataResponse {
try {
$this->roomService->setCanMentionEveryone($this->room, $config);
} catch (\InvalidArgumentException $e) {
return new DataResponse(['error' => $e->getMessage()], Http::STATUS_BAD_REQUEST);
}
return new DataResponse();
}
}
4 changes: 3 additions & 1 deletion lib/Manager.php
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,7 @@ public function createRoomObjectFromData(array $data): Room {
'breakout_room_mode' => 0,
'breakout_room_status' => 0,
'call_recording' => 0,
'can_mention_everyone' => 1,
], $data));
}

Expand Down Expand Up @@ -228,7 +229,8 @@ public function createRoomObject(array $row): Room {
(string) $row['object_id'],
(int) $row['breakout_room_mode'],
(int) $row['breakout_room_status'],
(int) $row['call_recording']
(int) $row['call_recording'],
(int) $row['can_mention_everyone'],
);
}

Expand Down
56 changes: 56 additions & 0 deletions lib/Migration/Version18000Date20230505122109.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
<?php

declare(strict_types=1);

/**
* @copyright Copyright (c) 2023 Vitor Mattos <[email protected]>
*
* @author Vitor Mattos <[email protected]>
*
* @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 OCP\DB\ISchemaWrapper;
use OCP\DB\Types;
use OCP\Migration\IOutput;
use OCP\Migration\SimpleMigrationStep;

class Version18000Date20230505122109 extends SimpleMigrationStep {

/**
* @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_rooms');
if (!$table->hasColumn('can_mention_everyone')) {
$table->addColumn('can_mention_everyone', Types::INTEGER, [
'default' => 1,
]);
return $schema;
}
return null;
}
}
1 change: 1 addition & 0 deletions lib/Model/SelectHelper.php
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ public function selectRoomsTable(IQueryBuilder $query, string $alias = 'r'): voi
->addSelect($alias . 'breakout_room_mode')
->addSelect($alias . 'breakout_room_status')
->addSelect($alias . 'call_recording')
->addSelect($alias . 'can_mention_everyone')
->selectAlias($alias . 'id', 'r_id');
}

Expand Down
16 changes: 16 additions & 0 deletions lib/Room.php
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,9 @@ class Room {
public const PARTICIPANT_REMOVED_ALL = 'remove_all';
public const PARTICIPANT_LEFT = 'leave';

public const CAN_MENTION_EVERYONE_MODERATORS = 0;
public const CAN_MENTION_EVERYONE_ALL = 1;

public const EVENT_AFTER_ROOM_CREATE = self::class . '::createdRoom';
public const EVENT_BEFORE_ROOM_DELETE = self::class . '::preDeleteRoom';
public const EVENT_AFTER_ROOM_DELETE = self::class . '::postDeleteRoom';
Expand Down Expand Up @@ -160,6 +163,8 @@ class Room {
public const EVENT_AFTER_SET_CALL_RECORDING = self::class . '::afterSetCallRecording';
public const EVENT_BEFORE_AVATAR_SET = self::class . '::preSetAvatar';
public const EVENT_AFTER_AVATAR_SET = self::class . '::postSetAvatar';
public const EVENT_BEFORE_SET_CAN_MENTION_EVERYONE = self::class . '::preCanMentionEveryone';
public const EVENT_AFTER_SET_CAN_MENTION_EVERYONE = self::class . '::postCanMentionEveryone';

public const DESCRIPTION_MAXIMUM_LENGTH = 500;

Expand Down Expand Up @@ -197,6 +202,7 @@ class Room {
private int $breakoutRoomMode;
private int $breakoutRoomStatus;
private int $callRecording;
private int $canMentionEveryone;

protected ?string $currentUser = null;
protected ?Participant $participant = null;
Expand Down Expand Up @@ -235,6 +241,7 @@ public function __construct(
int $breakoutRoomMode,
int $breakoutRoomStatus,
int $callRecording,
int $canMentionEveryone,
) {
$this->manager = $manager;
$this->db = $db;
Expand Down Expand Up @@ -269,6 +276,7 @@ public function __construct(
$this->breakoutRoomMode = $breakoutRoomMode;
$this->breakoutRoomStatus = $breakoutRoomStatus;
$this->callRecording = $callRecording;
$this->canMentionEveryone = $canMentionEveryone;
}

public function getId(): int {
Expand Down Expand Up @@ -656,4 +664,12 @@ public function getCallRecording(): int {
public function setCallRecording(int $callRecording): void {
$this->callRecording = $callRecording;
}

public function setCanMentionEveryone(int $canMentionEveryone): void {
$this->canMentionEveryone = $canMentionEveryone;
}

public function getCanMentionEveryone(): int {
return $this->canMentionEveryone;
}
}
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(
'isCustomAvatar' => $this->avatarService->isCustomAvatar($room),
'breakoutRoomMode' => BreakoutRoom::MODE_NOT_CONFIGURED,
'breakoutRoomStatus' => BreakoutRoom::STATUS_STOPPED,
'canMentionEveryone' => Room::CAN_MENTION_EVERYONE_ALL,
];

$lastActivity = $room->getLastActivity();
Expand Down Expand Up @@ -215,6 +216,7 @@ public function formatRoomV4(
'messageExpiration' => $room->getMessageExpiration(),
'breakoutRoomMode' => $room->getBreakoutRoomMode(),
'breakoutRoomStatus' => $room->getBreakoutRoomStatus(),
'canMentionEveryone' => $room->getCanMentionEveryone(),
]);

if ($currentParticipant->getAttendee()->getReadPrivacy() === Participant::PRIVACY_PUBLIC) {
Expand Down
33 changes: 33 additions & 0 deletions lib/Service/RoomService.php
Original file line number Diff line number Diff line change
Expand Up @@ -851,4 +851,37 @@ public function deleteRoom(Room $room): void {
));
}
}

public function setCanMentionEveryone(Room $room, int $config): void {
$allowedValues = [
Room::CAN_MENTION_EVERYONE_MODERATORS,
Room::CAN_MENTION_EVERYONE_ALL
];
if (!in_array($config, $allowedValues)) {
throw new InvalidArgumentException('config');
}
if ($room->getType() !== Room::TYPE_GROUP
&& $room->getType() !== Room::TYPE_PUBLIC
) {
throw new InvalidArgumentException('room');
}

$old = $room->getCanMentionEveryone();
if ($old === $config) {
return;
}

$event = new ModifyRoomEvent($room, 'canMentionEveryone', $config, $old);
$this->dispatcher->dispatch(Room::EVENT_BEFORE_SET_CAN_MENTION_EVERYONE, $event);

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

$room->setCanMentionEveryone($config);

$this->dispatcher->dispatch(Room::EVENT_AFTER_SET_CAN_MENTION_EVERYONE, $event);
}
}
16 changes: 16 additions & 0 deletions tests/integration/features/bootstrap/FeatureContext.php
Original file line number Diff line number Diff line change
Expand Up @@ -3154,6 +3154,22 @@ public function userSetTheMessageExpirationToXWithStatusCode(string $user, int $
$this->assertStatusCode($this->response, $statusCode);
}

/**
* @Given /^user "([^"]*)" set can mention everyone to (all|moderators) of room "([^"]*)" with (\d+)(?: \((v4)\))?$/
*/
public function userSetMentionEveryoneOfRoomWithStatus(string $user, string $who, string $identifier, int $statusCode, string $apiVersion = 'v1'): void {
if ($who === 'all') {
$config = 1;
} elseif ($who === 'moderators') {
$config = 0;
}
$this->setCurrentUser($user);
$this->sendRequest('PUT', '/apps/spreed/api/' . $apiVersion . '/room/' . self::$identifierToToken[$identifier] . '/can-mention-everyone', [
'config' => $config,
]);
$this->assertStatusCode($this->response, $statusCode);
}

/**
* @When wait for :seconds (second|seconds)
*/
Expand Down
Loading