Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
20d7229
Allow setting publishing permissions for all users
nickvergessen Sep 1, 2021
d2967ce
Rename and extend constants and methods for the new permissions
nickvergessen Sep 20, 2021
a0e1168
Allow users individually into the lobby
nickvergessen Sep 21, 2021
390ae65
Introduce different layers for permissions
nickvergessen Sep 22, 2021
1b13f80
Allow to remove all permissions without falling back to the next level
nickvergessen Sep 22, 2021
6a1b510
Allow to explicitly set the default and call permissions
nickvergessen Sep 23, 2021
f18aa00
Reset call permissions when the call ended
nickvergessen Sep 23, 2021
3b4f960
Fix permission handling in unit tests
nickvergessen Sep 23, 2021
3f54ae8
Fix integration tests
nickvergessen Sep 24, 2021
b575c8e
Don't allow to set individual permissions for moderators
nickvergessen Sep 24, 2021
1c641f8
Add integration tests for default and call permissions
nickvergessen Sep 24, 2021
e115e96
Remove moderator option and clear custom permissions when setting the…
nickvergessen Sep 27, 2021
118a6d2
Split publishing media into audio and video after clarifying with the…
nickvergessen Sep 28, 2021
984c8bd
Unify the endpoints and permissions update handling
nickvergessen Sep 29, 2021
0985260
Move PERMISSIONS_MOFIDY_* constants to Attendee class
nickvergessen Sep 29, 2021
31d0d2a
Fix documentation
nickvergessen Oct 4, 2021
d53c3d8
Fix integration tests
nickvergessen Oct 6, 2021
c407c64
Simplify the cases so the events we have to do for the HPB are easier
nickvergessen Oct 6, 2021
916906c
Improve validation
nickvergessen Oct 7, 2021
007ba46
Doc fixes
nickvergessen Oct 7, 2021
76852c4
Remove unused import
nickvergessen Oct 7, 2021
24b6037
Fix integration tests
nickvergessen Oct 7, 2021
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>13.0.0-dev.2</version>
<version>13.0.0-dev.3</version>
<licence>agpl</licence>

<author>Daniel Calviño Sánchez</author>
Expand Down
23 changes: 21 additions & 2 deletions appinfo/routes.php
Original file line number Diff line number Diff line change
Expand Up @@ -317,6 +317,16 @@
'token' => '^[a-z0-9]{4,30}$',
],
],
[
'name' => 'Room#setPermissions',
'url' => '/api/{apiVersion}/room/{token}/permissions/{mode}',
'verb' => 'PUT',
'requirements' => [
'apiVersion' => 'v(4)',
'token' => '^[a-z0-9]{4,30}$',
'mode' => '^(call|default)$',
],
],
[
'name' => 'Room#getParticipants',
'url' => '/api/{apiVersion}/room/{token}/participants',
Expand Down Expand Up @@ -354,8 +364,17 @@
],
],
[
'name' => 'Room#setAttendeePublishingPermissions',
'url' => '/api/{apiVersion}/room/{token}/attendees/publishing-permissions',
'name' => 'Room#setAttendeePermissions',
'url' => '/api/{apiVersion}/room/{token}/attendees/permissions',
'verb' => 'PUT',
'requirements' => [
'apiVersion' => 'v(4)',
'token' => '^[a-z0-9]{4,30}$',
],
],
[
'name' => 'Room#setAllAttendeesPermissions',
'url' => '/api/{apiVersion}/room/{token}/attendees/permissions/all',
'verb' => 'PUT',
'requirements' => [
'apiVersion' => 'v(4)',
Expand Down
25 changes: 17 additions & 8 deletions docs/constants.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,11 +57,20 @@ title: Constants
* `guests` - Guest without a login
* `emails` - A guest invited by email address

### Attendee publishing permissions
* `0` None
* `1` Audio
* `2` Video
* `4` Screensharing
### Attendee permissions
* `0` Default permissions (will pick the one from the next level of: user, call, conversation)
* `1` Custom permissions (this is required to be able to remove all other permissions)
* `2` Start call
* `4` Join call
* `8` Can ignore lobby
* `16` Can publish audio stream
* `32` Can publish video stream
* `64` Can publish screenshare stream

### Attendee permission modifications
* `set` - Setting this permission set.
* `add` - Add the given flags to the permissions.
* `remove` - Remove the given flags from the permissions.

### Actor types of chat messages
* `users` - Logged-in users
Expand All @@ -70,6 +79,6 @@ title: Constants
* `bridged` - Users whose messages are bridged in by the [Matterbridge integration](matterbridge.md)

## Signaling modes
* `internal` No external signaling server is used
* `external` A single external signaling server is used
* `conversation_cluster` An external signaling server is assigned per conversation
* `internal` - No external signaling server is used
* `external` - A single external signaling server is used
* `conversation_cluster` - An external signaling server is assigned per conversation.
21 changes: 20 additions & 1 deletion docs/conversation.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@
`attendeePin` | string | v3 | | Unique dial-in authentication code for this user, when the conversation has SIP enabled (see `sipEnabled` attribute)
`actorType` | string | v3 | | Currently known `users|guests|emails|groups|circles`
`actorId` | string | v3 | | The unique identifier for the given actor type
`publishingPermissions` | int | v4 | | Publishing permissions for the current participant (see [constants list](constants.md#attendee-publishing-permissions))
`permissions` | int | v4 | | Publishing permissions for the current participant (see [constants list](constants.md#attendee-permissions))
`participantInCall` | bool | v1 | v2 | **Removed:** use `participantFlags` instead
`participantFlags` | int | v1 | | "In call" flags of the user's session making the request (only available with `in-call-flags` capability)
`readOnly` | int | v1 | | Read-only state for the current user (only available with `read-only-rooms` capability)
Expand Down Expand Up @@ -248,6 +248,25 @@
+ `403 Forbidden` When the conversation is not a public conversation
+ `404 Not Found` When the conversation could not be found for the participant

## Set default or call permissions for a conversation

* Method: `PUT`
* Endpoint: `/room/{token}/permissions/{mode}`
* Data:

field | type | Description
---|---|---
`mode` | string | `default` or `call`, in case of call the permissions will be reset to `0` (default) after the end of a call.
`permissions` | int | New permissions for the attendees, see [constants list](constants.md#attendee-permissions). If permissions are not `0` (default), the `1` (custom) permission will always be added. Note that this will reset all custom permissions that have been given to attendees so far.

* Response:
- Status code:
+ `200 OK`
+ `400 Bad Request` When the conversation type does not support setting publishing permissions, e.g. one-to-one conversations
+ `400 Bad Request` When the mode is invalid
+ `403 Forbidden` When the current user is not a moderator, owner or guest moderator
+ `404 Not Found` When the conversation could not be found for the participant

## Add conversation to favorites

* Required capability: `favorites`
Expand Down
32 changes: 27 additions & 5 deletions docs/participant.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@
`participantType` | int | v1 | | Permissions level of the participant (see [constants list](constants.md#participant-types))
`lastPing` | int | v1 | | Timestamp of the last ping of the user (should be used for sorting)
`inCall` | int | v1 | | Call flags the user joined with (see [constants list](constants.md#participant-in-call-flag))
`publishingPermissions` | int | v4 | | Publishing permissions for the participant (see [constants list](constants.md#attendee-publishing-permissions))
`permissions` | int | v4 | | Publishing permissions for the participant (see [constants list](constants.md#attendee-permissions))
`sessionId` | string | v1 | v4 | `'0'` if not connected, otherwise a 512 character long string
`sessionIds` | array | v4 | | array of session ids, each are 512 character long strings, or empty if no session
`status` | string | v2 | | Optional: Only available with `includeStatus=true`, for users with a set status and when there are less than 100 participants in the conversation
Expand Down Expand Up @@ -191,25 +191,47 @@
+ `404 Not Found` When the conversation could not be found for the participant
+ `404 Not Found` When the participant to demote could not be found

## Set publishing permissions for an attendee
## Set permissions for an attendee

* Method: `PUT`
* Endpoint: `/room/{token}/attendees/publishing-permissions`
* Endpoint: `/room/{token}/attendees/permissions`
* Data:

field | type | Description
---|---|---
`attendeeId` | int | Attendee id can be used for guests and users
`state` | int | New state for the attendee, see [constants list](constants.md#attendee-publishing-permissions)
`mode` | string | Mode of how permissions should be manipulated [constants list](constants.md#attendee-permission-modifications). If the permissions were `0` (default) and the modification is `add` or `remove`, they will be initialised with the call or default conversation permissions before, falling back to `126` for moderators and `118` for normal participants.
`permissions` | int | New permissions for the attendee, see [constants list](constants.md#attendee-permissions). If permissions are not `0` (default), the `1` (custom) permission will always be added.

* Response:
- Status code:
+ `200 OK`
+ `400 Bad Request` When the conversation type does not support setting publishing permissions (only group and public conversations)
+ `400 Bad Request` When the conversation type does not support setting publishing permissions, e.g. one-to-one conversations
+ `400 Bad Request` When the attendee type is `groups` or `circles`
+ `400 Bad Request` When the mode is invalid
+ `403 Forbidden` When the current user is not a moderator, owner or guest moderator
+ `404 Not Found` When the conversation could not be found for the participant
+ `404 Not Found` When the attendee to set publishing permissions could not be found

## Set permissions for all attendees

* Method: `PUT`
* Endpoint: `/room/{token}/attendees/permissions/all`
* Data:

field | type | Description
---|---|---
`mode` | string | Mode of how permissions should be manipulated [constants list](constants.md#attendee-permission-modifications). If the permissions were `0` (default) and the modification is `add` or `remove`, they will be initialised with the call or default conversation permissions before, falling back to `126` for moderators and `118` for normal participants.
`permissions` | int | New permissions for the attendees, see [constants list](constants.md#attendee-permissions). If permissions are not `0` (default), the `1` (custom) permission will always be added.

* Response:
- Status code:
+ `200 OK`
+ `400 Bad Request` When the conversation type does not support setting publishing permissions, e.g. one-to-one conversations
+ `400 Bad Request` When the mode is invalid
+ `403 Forbidden` When the current user is not a moderator, owner or guest moderator
+ `404 Not Found` When the conversation could not be found for the participant

## Get a participant by their pin

Note: This is only allowed with validate SIP bridge requests
Expand Down
7 changes: 6 additions & 1 deletion lib/Controller/CallController.php
Original file line number Diff line number Diff line change
Expand Up @@ -106,9 +106,10 @@ public function getPeersForCall(): DataResponse {
* @RequireModeratorOrNoLobby
*
* @param int|null $flags
* @param int|null $forcePermissions
* @return DataResponse
*/
public function joinCall(?int $flags): DataResponse {
public function joinCall(?int $flags = null, ?int $forcePermissions = null): DataResponse {
$this->participantService->ensureOneToOneRoomIsFilled($this->room);

$session = $this->participant->getSession();
Expand All @@ -121,6 +122,10 @@ public function joinCall(?int $flags): DataResponse {
$flags = Participant::FLAG_IN_CALL | Participant::FLAG_WITH_AUDIO | Participant::FLAG_WITH_VIDEO;
}

if ($forcePermissions !== null && $this->participant->hasModeratorPermissions()) {
$this->room->setPermissions('call', $forcePermissions);
}

$this->participantService->changeInCall($this->room, $this->participant, $flags);

return new DataResponse();
Expand Down
56 changes: 47 additions & 9 deletions lib/Controller/RoomController.php
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
use OCA\Talk\Chat\MessageParser;
use OCA\Talk\Config;
use OCA\Talk\Events\UserEvent;
use OCA\Talk\Exceptions\ForbiddenException;
use OCA\Talk\Exceptions\InvalidPasswordException;
use OCA\Talk\Exceptions\ParticipantNotFoundException;
use OCA\Talk\Exceptions\RoomNotFoundException;
Expand Down Expand Up @@ -405,7 +406,7 @@ protected function formatRoomV4(Room $room, ?Participant $currentParticipant, ar
'actorType' => '',
'actorId' => '',
'attendeeId' => 0,
'publishingPermissions' => Attendee::PUBLISHING_PERMISSIONS_NONE,
'permissions' => Attendee::PERMISSIONS_CUSTOM,
'canEnableSIP' => false,
'attendeePin' => '',
'description' => '',
Expand Down Expand Up @@ -471,7 +472,7 @@ protected function formatRoomV4(Room $room, ?Participant $currentParticipant, ar
'actorType' => $attendee->getActorType(),
'actorId' => $attendee->getActorId(),
'attendeeId' => $attendee->getId(),
'publishingPermissions' => $attendee->getPublishingPermissions(),
'permissions' => $currentParticipant->getPermissions(),
'description' => $room->getDescription(),
'listable' => $room->getListable(),
]);
Expand Down Expand Up @@ -519,7 +520,8 @@ protected function formatRoomV4(Room $room, ?Participant $currentParticipant, ar
}

if ($room->getLobbyState() === Webinary::LOBBY_NON_MODERATORS &&
!$currentParticipant->hasModeratorPermissions()) {
!$currentParticipant->hasModeratorPermissions() &&
!($currentParticipant->getPermissions() & Attendee::PERMISSIONS_LOBBY_IGNORE)) {
// No participants and chat messages for users in the lobby.
$roomData['hasCall'] = false;
return $roomData;
Expand Down Expand Up @@ -954,7 +956,7 @@ public function getParticipants(bool $includeStatus = false): DataResponse {
'actorId' => $participant->getAttendee()->getActorId(),
'actorType' => $participant->getAttendee()->getActorType(),
'displayName' => $participant->getAttendee()->getActorId(),
'publishingPermissions' => $participant->getAttendee()->getPublishingPermissions(),
'permissions' => $participant->getPermissions(),
'attendeePin' => '',
];
if ($this->talkConfig->isSIPConfigured()
Expand Down Expand Up @@ -1506,30 +1508,66 @@ protected function changeParticipantType(int $attendeeId, bool $promote): DataR
return new DataResponse();
}

/**
* @PublicPage
* @RequireModeratorParticipant
*
* @param int $permissions
* @return DataResponse
*/
public function setPermissions(string $mode, int $permissions): DataResponse {
if (!$this->roomService->setPermissions($this->room, $mode, Attendee::PERMISSIONS_MODIFY_SET, $permissions, true)) {
return new DataResponse([], Http::STATUS_BAD_REQUEST);
}

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

/**
* @PublicPage
* @RequireModeratorParticipant
*
* @param int $attendeeId
* @param int $state
* @param string $method
* @param int $permissions
* @return DataResponse
*/
public function setAttendeePublishingPermissions(int $attendeeId, int $state): DataResponse {
public function setAttendeePermissions(int $attendeeId, string $method, int $permissions): DataResponse {
try {
$targetParticipant = $this->room->getParticipantByAttendeeId($attendeeId);
} catch (ParticipantNotFoundException $e) {
return new DataResponse([], Http::STATUS_NOT_FOUND);
}

if ($this->room->getType() === Room::ONE_TO_ONE_CALL) {
return new DataResponse([], Http::STATUS_BAD_REQUEST);
try {
$result = $this->participantService->updatePermissions($this->room, $targetParticipant, $method, $permissions);
} catch (ForbiddenException $e) {
return new DataResponse([], Http::STATUS_FORBIDDEN);
}

$this->participantService->updatePublishingPermissions($this->room, $targetParticipant, $state);
if (!$result) {
return new DataResponse([], Http::STATUS_BAD_REQUEST);
}

return new DataResponse();
}

/**
* @PublicPage
* @RequireModeratorParticipant
*
* @param string $method
* @param int $permissions
* @return DataResponse
*/
public function setAllAttendeesPermissions(string $method, int $permissions): DataResponse {
if (!$this->roomService->setPermissions($this->room, 'call', $method, $permissions, false)) {
return new DataResponse([], Http::STATUS_BAD_REQUEST);
}

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

/**
* @NoAdminRequired
* @RequireModeratorParticipant
Expand Down
11 changes: 7 additions & 4 deletions lib/Controller/SignalingController.php
Original file line number Diff line number Diff line change
Expand Up @@ -404,7 +404,7 @@ protected function getUsersInRoom(Room $room, int $pingTimestamp): array {
'lastPing' => $session->getLastPing(),
'sessionId' => $session->getSessionId(),
'inCall' => $session->getInCall(),
'publishingPermissions' => $participant->getAttendee()->getPublishingPermissions(),
'permissions' => $participant->getPermissions(),
];
}

Expand Down Expand Up @@ -687,10 +687,13 @@ private function backendRoom(array $roomRequest): DataResponse {
'app' => 'spreed-hpb',
]);

if ($participant->getAttendee()->getPublishingPermissions() & (Attendee::PUBLISHING_PERMISSIONS_AUDIO | Attendee::PUBLISHING_PERMISSIONS_VIDEO)) {
$permissions[] = 'publish-media';
if ($participant->getPermissions() & Attendee::PERMISSIONS_PUBLISH_AUDIO) {
$permissions[] = 'publish-audio';
}
if ($participant->getAttendee()->getPublishingPermissions() & Attendee::PUBLISHING_PERMISSIONS_SCREENSHARING) {
if ($participant->getPermissions() & Attendee::PERMISSIONS_PUBLISH_VIDEO) {
$permissions[] = 'publish-video';
}
if ($participant->getPermissions() & Attendee::PERMISSIONS_PUBLISH_SCREEN) {
$permissions[] = 'publish-screen';
}
if ($participant->hasModeratorPermissions(false)) {
Expand Down
2 changes: 2 additions & 0 deletions lib/Manager.php
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,8 @@ public function createRoomObject(array $row): Room {
(string) $row['password'],
(string) $row['server_url'],
(int) $row['active_guests'],
(int) $row['default_permissions'],
(int) $row['call_permissions'],
(int) $row['call_flag'],
$activeSince,
$lastActivity,
Expand Down
8 changes: 8 additions & 0 deletions lib/Middleware/InjectionMiddleware.php
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@
use OCA\Talk\Middleware\Exceptions\LobbyException;
use OCA\Talk\Middleware\Exceptions\NotAModeratorException;
use OCA\Talk\Middleware\Exceptions\ReadOnlyException;
use OCA\Talk\Model\Attendee;
use OCA\Talk\Participant;
use OCA\Talk\Room;
use OCA\Talk\TalkSession;
use OCA\Talk\Webinary;
Expand Down Expand Up @@ -198,6 +200,12 @@ protected function checkLobbyState(AEnvironmentAwareController $controller): voi
} catch (ParticipantNotFoundException $e) {
}

$participant = $controller->getParticipant();
if ($participant instanceof Participant &&
$participant->getPermissions() & Attendee::PERMISSIONS_LOBBY_IGNORE) {
return;
}

$room = $controller->getRoom();
if (!$room instanceof Room || $room->getLobbyState() !== Webinary::LOBBY_NONE) {
throw new LobbyException();
Expand Down
Loading