Browse Source

Allow setting publishing permissions for all users

Signed-off-by: Joas Schilling <coding@schilljs.com>
pull/6190/head
Joas Schilling 4 years ago
parent
commit
20d722901f
No known key found for this signature in database GPG Key ID: 7076EA9751AACDDA
  1. 9
      appinfo/routes.php
  2. 29
      lib/Controller/RoomController.php
  3. 82
      lib/Model/AttendeeMapper.php
  4. 4
      lib/Participant.php
  5. 11
      lib/Service/ParticipantService.php
  6. 448
      tests/php/Model/AttendeeMapperTest.php

9
appinfo/routes.php

@ -362,6 +362,15 @@ return [
'token' => '^[a-z0-9]{4,30}$',
],
],
[
'name' => 'Room#setAllAttendeesPublishingPermissions',
'url' => '/api/{apiVersion}/room/{token}/attendees/publishing-permissions/all',
'verb' => 'PUT',
'requirements' => [
'apiVersion' => 'v(4)',
'token' => '^[a-z0-9]{4,30}$',
],
],
[
'name' => 'Room#joinRoom',
'url' => '/api/{apiVersion}/room/{token}/participants/active',

29
lib/Controller/RoomController.php

@ -1521,7 +1521,7 @@ class RoomController extends AEnvironmentAwareController {
return new DataResponse([], Http::STATUS_NOT_FOUND);
}
if ($this->room->getType() === Room::ONE_TO_ONE_CALL) {
if ($this->room->getType() === Room::TYPE_ONE_TO_ONE) {
return new DataResponse([], Http::STATUS_BAD_REQUEST);
}
@ -1530,6 +1530,33 @@ class RoomController extends AEnvironmentAwareController {
return new DataResponse();
}
/**
* @PublicPage
* @RequireModeratorParticipant
*
* @param string $method
* @param int $state
* @param bool $includeModerators
* @return DataResponse
*/
public function setAllAttendeesPublishingPermissions(string $method, int $state, bool $includeModerators): DataResponse {
if (!in_array($method, [
Participant::PERMISSIONS_ADD,
Participant::PERMISSIONS_REMOVE,
Participant::PERMISSIONS_SET
], true)) {
return new DataResponse([], Http::STATUS_BAD_REQUEST);
}
if ($this->room->getType() === Room::TYPE_ONE_TO_ONE) {
return new DataResponse([], Http::STATUS_BAD_REQUEST);
}
$this->participantService->updateAllPublishingPermissions($this->room, $method, $state, $includeModerators);
return new DataResponse();
}
/**
* @NoAdminRequired
* @RequireModeratorParticipant

82
lib/Model/AttendeeMapper.php

@ -23,6 +23,7 @@ declare(strict_types=1);
namespace OCA\Talk\Model;
use OCA\Talk\Participant;
use OCP\AppFramework\Db\DoesNotExistException;
use OCP\AppFramework\Db\MultipleObjectsReturnedException;
use OCP\AppFramework\Db\QBMapper;
@ -197,6 +198,87 @@ class AttendeeMapper extends QBMapper {
return (int) $query->execute();
}
public function modifyPublishingPermissions(int $roomId, string $mode, int $newState, bool $includeModerators): void {
$query = $this->db->getQueryBuilder();
$query->update($this->getTableName())
->where($query->expr()->eq('room_id', $query->createNamedParameter($roomId, IQueryBuilder::PARAM_INT)))
->andWhere($query->expr()->notIn('actor_type', $query->createNamedParameter([
Attendee::ACTOR_CIRCLES,
Attendee::ACTOR_GROUPS,
], IQueryBuilder::PARAM_STR_ARRAY)));
if (!$includeModerators) {
$query->andWhere($query->expr()->notIn('participant_type', $query->createNamedParameter([
Participant::OWNER,
Participant::MODERATOR,
Participant::GUEST_MODERATOR,
], IQueryBuilder::PARAM_INT_ARRAY)));
}
if ($mode === Participant::PERMISSIONS_SET) {
$query->set('publishing_permissions', $query->createNamedParameter($newState, IQueryBuilder::PARAM_INT));
$query->executeStatement();
} else {
foreach ([
Participant::FLAG_IN_CALL,
Participant::FLAG_WITH_AUDIO,
Participant::FLAG_WITH_VIDEO
] as $permission) {
if ($permission & $newState) {
if ($mode === Participant::PERMISSIONS_ADD) {
$this->addSinglePublishingPermission($query, $permission);
} elseif ($mode === Participant::PERMISSIONS_REMOVE) {
$this->removeSinglePublishingPermission($query, $permission);
}
}
}
}
}
protected function addSinglePublishingPermission(IQueryBuilder $query, int $publishingPermission): void {
$query->set('publishing_permissions', $query->func()->add(
'publishing_permissions',
$query->createNamedParameter($publishingPermission, IQueryBuilder::PARAM_INT)
));
$query->andWhere(
$query->expr()->neq(
$query->expr()->castColumn(
$query->expr()->bitwiseAnd(
'publishing_permissions',
$publishingPermission
),
IQueryBuilder::PARAM_INT
),
$query->createNamedParameter($publishingPermission, IQueryBuilder::PARAM_INT)
)
);
$query->executeStatement();
}
protected function removeSinglePublishingPermission(IQueryBuilder $query, int $publishingPermission): void {
$query->set('publishing_permissions', $query->func()->subtract(
'publishing_permissions',
$query->createNamedParameter($publishingPermission, IQueryBuilder::PARAM_INT)
));
$query->andWhere(
$query->expr()->eq(
$query->expr()->castColumn(
$query->expr()->bitwiseAnd(
'publishing_permissions',
$publishingPermission
),
IQueryBuilder::PARAM_INT
),
$query->createNamedParameter($publishingPermission, IQueryBuilder::PARAM_INT)
)
);
$query->executeStatement();
}
public function createAttendeeFromRow(array $row): Attendee {
return $this->mapRowToEntity([
'id' => $row['a_id'],

4
lib/Participant.php

@ -43,6 +43,10 @@ class Participant {
public const FLAG_WITH_VIDEO = 4;
public const FLAG_WITH_PHONE = 8;
public const PERMISSIONS_ADD = 'add';
public const PERMISSIONS_REMOVE = 'remove';
public const PERMISSIONS_SET = 'set';
public const NOTIFY_DEFAULT = 0;
public const NOTIFY_ALWAYS = 1;
public const NOTIFY_MENTION = 2;

11
lib/Service/ParticipantService.php

@ -158,6 +158,17 @@ class ParticipantService {
$this->dispatcher->dispatch(Room::EVENT_AFTER_PARTICIPANT_PUBLISHING_PERMISSIONS_SET, $event);
}
public function updateAllPublishingPermissions(Room $room, string $mode, int $newState, bool $includeModerators): void {
// FIXME Add events after checking what should be sent to the HPB
// $event = new ModifyParticipantEvent($room, $participant, 'publishingPermissions', $newState, $oldState);
// $this->dispatcher->dispatch(Room::EVENT_BEFORE_PARTICIPANT_PUBLISHING_PERMISSIONS_SET, $event);
$this->attendeeMapper->modifyPublishingPermissions($room->getId(), $mode, $newState, $includeModerators);
// FIXME Add events after checking what should be sent to the HPB
// $this->dispatcher->dispatch(Room::EVENT_AFTER_PARTICIPANT_PUBLISHING_PERMISSIONS_SET, $event);
}
public function updateLastReadMessage(Participant $participant, int $lastReadMessage): void {
$attendee = $participant->getAttendee();
$attendee->setLastReadMessage($lastReadMessage);

448
tests/php/Model/AttendeeMapperTest.php

@ -0,0 +1,448 @@
<?php
declare(strict_types=1);
/**
* @copyright Copyright (c) 2021 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\Tests\php\Model;
use OCA\Talk\Model\Attendee;
use OCA\Talk\Model\AttendeeMapper;
use OCA\Talk\Participant;
use OCP\AppFramework\Db\DoesNotExistException;
use Test\TestCase;
/**
* @group DB
*/
class AttendeeMapperTest extends TestCase {
/** @var AttendeeMapper */
protected $attendeeMapper;
public function setUp(): void {
parent::setUp();
$this->attendeeMapper = new AttendeeMapper(
\OC::$server->getDatabaseConnection()
);
}
public function dataModifyPublishingPermissions(): array {
return [
0 => [
[
[
'actor_type' => Attendee::ACTOR_CIRCLES,
'actor_id' => 'c1',
'participant_type' => Participant::USER,
'publishing_permissions' => Participant::FLAG_DISCONNECTED,
],
[
'actor_type' => Attendee::ACTOR_GROUPS,
'actor_id' => 'g1',
'participant_type' => Participant::USER,
'publishing_permissions' => Participant::FLAG_DISCONNECTED,
],
[
'actor_type' => Attendee::ACTOR_USERS,
'actor_id' => 'o1',
'participant_type' => Participant::OWNER,
'publishing_permissions' => Participant::FLAG_DISCONNECTED,
],
[
'actor_type' => Attendee::ACTOR_USERS,
'actor_id' => 'm1',
'participant_type' => Participant::MODERATOR,
'publishing_permissions' => Participant::FLAG_DISCONNECTED,
],
[
'actor_type' => Attendee::ACTOR_USERS,
'actor_id' => 'u1',
'participant_type' => Participant::USER,
'publishing_permissions' => Participant::FLAG_DISCONNECTED,
],
],
Participant::PERMISSIONS_SET,
Participant::FLAG_IN_CALL,
false,
[
[
'actor_type' => Attendee::ACTOR_CIRCLES,
'actor_id' => 'c1',
'participant_type' => Participant::USER,
'publishing_permissions' => Participant::FLAG_DISCONNECTED,
],
[
'actor_type' => Attendee::ACTOR_GROUPS,
'actor_id' => 'g1',
'participant_type' => Participant::USER,
'publishing_permissions' => Participant::FLAG_DISCONNECTED,
],
[
'actor_type' => Attendee::ACTOR_USERS,
'actor_id' => 'o1',
'participant_type' => Participant::OWNER,
'publishing_permissions' => Participant::FLAG_DISCONNECTED,
],
[
'actor_type' => Attendee::ACTOR_USERS,
'actor_id' => 'm1',
'participant_type' => Participant::MODERATOR,
'publishing_permissions' => Participant::FLAG_DISCONNECTED,
],
[
'actor_type' => Attendee::ACTOR_USERS,
'actor_id' => 'u1',
'participant_type' => Participant::USER,
'publishing_permissions' => Participant::FLAG_IN_CALL,
],
],
],
1 => [
[
[
'actor_type' => Attendee::ACTOR_CIRCLES,
'actor_id' => 'c1',
'participant_type' => Participant::USER,
'publishing_permissions' => Participant::FLAG_DISCONNECTED,
],
[
'actor_type' => Attendee::ACTOR_GROUPS,
'actor_id' => 'g1',
'participant_type' => Participant::USER,
'publishing_permissions' => Participant::FLAG_DISCONNECTED,
],
[
'actor_type' => Attendee::ACTOR_USERS,
'actor_id' => 'o1',
'participant_type' => Participant::OWNER,
'publishing_permissions' => Participant::FLAG_DISCONNECTED,
],
[
'actor_type' => Attendee::ACTOR_USERS,
'actor_id' => 'm1',
'participant_type' => Participant::MODERATOR,
'publishing_permissions' => Participant::FLAG_DISCONNECTED,
],
[
'actor_type' => Attendee::ACTOR_USERS,
'actor_id' => 'u1',
'participant_type' => Participant::USER,
'publishing_permissions' => Participant::FLAG_DISCONNECTED,
],
],
Participant::PERMISSIONS_SET,
Participant::FLAG_IN_CALL,
true,
[
[
'actor_type' => Attendee::ACTOR_CIRCLES,
'actor_id' => 'c1',
'participant_type' => Participant::USER,
'publishing_permissions' => Participant::FLAG_DISCONNECTED,
],
[
'actor_type' => Attendee::ACTOR_GROUPS,
'actor_id' => 'g1',
'participant_type' => Participant::USER,
'publishing_permissions' => Participant::FLAG_DISCONNECTED,
],
[
'actor_type' => Attendee::ACTOR_USERS,
'actor_id' => 'o1',
'participant_type' => Participant::OWNER,
'publishing_permissions' => Participant::FLAG_IN_CALL,
],
[
'actor_type' => Attendee::ACTOR_USERS,
'actor_id' => 'm1',
'participant_type' => Participant::MODERATOR,
'publishing_permissions' => Participant::FLAG_IN_CALL,
],
[
'actor_type' => Attendee::ACTOR_USERS,
'actor_id' => 'u1',
'participant_type' => Participant::USER,
'publishing_permissions' => Participant::FLAG_IN_CALL,
],
],
],
2 => [
[
[
'actor_type' => Attendee::ACTOR_USERS,
'actor_id' => 'o1',
'participant_type' => Participant::OWNER,
'publishing_permissions' => Participant::FLAG_WITH_AUDIO + Participant::FLAG_WITH_VIDEO,
],
[
'actor_type' => Attendee::ACTOR_USERS,
'actor_id' => 'm1',
'participant_type' => Participant::MODERATOR,
'publishing_permissions' => Participant::FLAG_WITH_AUDIO + Participant::FLAG_WITH_VIDEO,
],
[
'actor_type' => Attendee::ACTOR_USERS,
'actor_id' => 'u1',
'participant_type' => Participant::USER,
'publishing_permissions' => Participant::FLAG_WITH_AUDIO + Participant::FLAG_WITH_VIDEO,
],
],
Participant::PERMISSIONS_SET,
Participant::FLAG_IN_CALL,
false,
[
[
'actor_type' => Attendee::ACTOR_USERS,
'actor_id' => 'o1',
'participant_type' => Participant::OWNER,
'publishing_permissions' => Participant::FLAG_WITH_AUDIO + Participant::FLAG_WITH_VIDEO,
],
[
'actor_type' => Attendee::ACTOR_USERS,
'actor_id' => 'm1',
'participant_type' => Participant::MODERATOR,
'publishing_permissions' => Participant::FLAG_WITH_AUDIO + Participant::FLAG_WITH_VIDEO,
],
[
'actor_type' => Attendee::ACTOR_USERS,
'actor_id' => 'u1',
'participant_type' => Participant::USER,
'publishing_permissions' => Participant::FLAG_IN_CALL,
],
],
],
3 => [
[
[
'actor_type' => Attendee::ACTOR_USERS,
'actor_id' => 'o1',
'participant_type' => Participant::OWNER,
'publishing_permissions' => Participant::FLAG_WITH_AUDIO + Participant::FLAG_WITH_VIDEO,
],
[
'actor_type' => Attendee::ACTOR_USERS,
'actor_id' => 'm1',
'participant_type' => Participant::MODERATOR,
'publishing_permissions' => Participant::FLAG_WITH_AUDIO + Participant::FLAG_WITH_VIDEO,
],
[
'actor_type' => Attendee::ACTOR_USERS,
'actor_id' => 'u1',
'participant_type' => Participant::USER,
'publishing_permissions' => Participant::FLAG_WITH_AUDIO + Participant::FLAG_WITH_VIDEO,
],
],
Participant::PERMISSIONS_SET,
Participant::FLAG_IN_CALL,
true,
[
[
'actor_type' => Attendee::ACTOR_USERS,
'actor_id' => 'o1',
'participant_type' => Participant::OWNER,
'publishing_permissions' => Participant::FLAG_IN_CALL,
],
[
'actor_type' => Attendee::ACTOR_USERS,
'actor_id' => 'm1',
'participant_type' => Participant::MODERATOR,
'publishing_permissions' => Participant::FLAG_IN_CALL,
],
[
'actor_type' => Attendee::ACTOR_USERS,
'actor_id' => 'u1',
'participant_type' => Participant::USER,
'publishing_permissions' => Participant::FLAG_IN_CALL,
],
],
],
4 => [
[
[
'actor_type' => Attendee::ACTOR_USERS,
'actor_id' => 'o1',
'participant_type' => Participant::OWNER,
'publishing_permissions' => Participant::FLAG_WITH_AUDIO + Participant::FLAG_WITH_VIDEO,
],
[
'actor_type' => Attendee::ACTOR_USERS,
'actor_id' => 'm1',
'participant_type' => Participant::MODERATOR,
'publishing_permissions' => Participant::FLAG_WITH_VIDEO,
],
[
'actor_type' => Attendee::ACTOR_USERS,
'actor_id' => 'u1',
'participant_type' => Participant::USER,
'publishing_permissions' => Participant::FLAG_WITH_AUDIO,
],
[
'actor_type' => Attendee::ACTOR_USERS,
'actor_id' => 'u2',
'participant_type' => Participant::USER,
'publishing_permissions' => Participant::FLAG_IN_CALL,
],
],
Participant::PERMISSIONS_ADD,
Participant::FLAG_IN_CALL,
true,
[
[
'actor_type' => Attendee::ACTOR_USERS,
'actor_id' => 'o1',
'participant_type' => Participant::OWNER,
'publishing_permissions' => Participant::FLAG_WITH_AUDIO + Participant::FLAG_WITH_VIDEO + Participant::FLAG_IN_CALL,
],
[
'actor_type' => Attendee::ACTOR_USERS,
'actor_id' => 'm1',
'participant_type' => Participant::MODERATOR,
'publishing_permissions' => Participant::FLAG_WITH_VIDEO + Participant::FLAG_IN_CALL,
],
[
'actor_type' => Attendee::ACTOR_USERS,
'actor_id' => 'u1',
'participant_type' => Participant::USER,
'publishing_permissions' => Participant::FLAG_WITH_AUDIO + Participant::FLAG_IN_CALL,
],
[
'actor_type' => Attendee::ACTOR_USERS,
'actor_id' => 'u2',
'participant_type' => Participant::USER,
'publishing_permissions' => Participant::FLAG_IN_CALL,
],
],
],
5 => [
[
[
'actor_type' => Attendee::ACTOR_USERS,
'actor_id' => 'o1',
'participant_type' => Participant::OWNER,
'publishing_permissions' => Participant::FLAG_WITH_AUDIO + Participant::FLAG_WITH_VIDEO + Participant::FLAG_IN_CALL,
],
[
'actor_type' => Attendee::ACTOR_USERS,
'actor_id' => 'm1',
'participant_type' => Participant::MODERATOR,
'publishing_permissions' => Participant::FLAG_WITH_VIDEO + Participant::FLAG_IN_CALL,
],
[
'actor_type' => Attendee::ACTOR_USERS,
'actor_id' => 'u1',
'participant_type' => Participant::USER,
'publishing_permissions' => Participant::FLAG_WITH_AUDIO + Participant::FLAG_IN_CALL,
],
[
'actor_type' => Attendee::ACTOR_USERS,
'actor_id' => 'u2',
'participant_type' => Participant::USER,
'publishing_permissions' => Participant::FLAG_IN_CALL,
],
[
'actor_type' => Attendee::ACTOR_USERS,
'actor_id' => 'u3',
'participant_type' => Participant::USER,
'publishing_permissions' => Participant::FLAG_WITH_AUDIO + Participant::FLAG_WITH_VIDEO,
],
],
Participant::PERMISSIONS_REMOVE,
Participant::FLAG_IN_CALL,
true,
[
[
'actor_type' => Attendee::ACTOR_USERS,
'actor_id' => 'o1',
'participant_type' => Participant::OWNER,
'publishing_permissions' => Participant::FLAG_WITH_AUDIO + Participant::FLAG_WITH_VIDEO,
],
[
'actor_type' => Attendee::ACTOR_USERS,
'actor_id' => 'm1',
'participant_type' => Participant::MODERATOR,
'publishing_permissions' => Participant::FLAG_WITH_VIDEO,
],
[
'actor_type' => Attendee::ACTOR_USERS,
'actor_id' => 'u1',
'participant_type' => Participant::USER,
'publishing_permissions' => Participant::FLAG_WITH_AUDIO,
],
[
'actor_type' => Attendee::ACTOR_USERS,
'actor_id' => 'u2',
'participant_type' => Participant::USER,
'publishing_permissions' => Participant::FLAG_DISCONNECTED,
],
[
'actor_type' => Attendee::ACTOR_USERS,
'actor_id' => 'u3',
'participant_type' => Participant::USER,
'publishing_permissions' => Participant::FLAG_WITH_AUDIO + Participant::FLAG_WITH_VIDEO,
],
],
],
];
}
/**
* @dataProvider dataModifyPublishingPermissions
* @param array $attendees
* @param string $mode
* @param int $permission
* @param bool $includeModerators
* @param array $expected
*/
public function testModifyPublishingPermissions(array $attendees, string $mode, int $permission, bool $includeModerators, array $expected): void {
$roomId = 12345678;
foreach ($attendees as $attendeeData) {
try {
$attendee = $this->attendeeMapper->findByActor($roomId, $attendeeData['actor_type'], $attendeeData['actor_id']);
$this->attendeeMapper->delete($attendee);
} catch (DoesNotExistException $e) {
}
$attendee = new Attendee();
$attendee->setRoomId($roomId);
$attendee->setActorType($attendeeData['actor_type']);
$attendee->setActorId($attendeeData['actor_id']);
$attendee->setParticipantType($attendeeData['participant_type']);
$attendee->setPublishingPermissions($attendeeData['publishing_permissions']);
$this->attendeeMapper->insert($attendee);
}
$this->attendeeMapper->modifyPublishingPermissions($roomId, $mode, $permission, $includeModerators);
foreach ($expected as $attendeeData) {
$attendee = $this->attendeeMapper->findByActor($roomId, $attendeeData['actor_type'], $attendeeData['actor_id']);
$this->assertEquals(
$attendeeData['publishing_permissions'],
$attendee->getPublishingPermissions(),
'Publishing permissions mismatch for ' . $attendeeData['actor_type'] . '#' . $attendeeData['actor_id']
);
$this->attendeeMapper->delete($attendee);
}
}
}
Loading…
Cancel
Save