diff --git a/appinfo/routes.php b/appinfo/routes.php index fc874c6a175..2dde2935a59 100644 --- a/appinfo/routes.php +++ b/appinfo/routes.php @@ -649,6 +649,42 @@ ], ], + /** + * Block + */ + [ + 'name' => 'Block#block', + 'url' => '/api/{apiVersion}/block', + 'verb' => 'POST', + 'requirements' => [ + 'apiVersion' => 'v1' + ] + ], + [ + 'name' => 'Block#unblock', + 'url' => '/api/{apiVersion}/block', + 'verb' => 'DELETE', + 'requirements' => [ + 'apiVersion' => 'v1' + ] + ], + [ + 'name' => 'Block#listBlocked', + 'url' => '/api/{apiVersion}/block', + 'verb' => 'GET', + 'requirements' => [ + 'apiVersion' => 'v1' + ] + ], + [ + 'name' => 'Block#listBlockedByType', + 'url' => '/api/{apiVersion}/block/type/{type}', + 'verb' => 'GET', + 'requirements' => [ + 'apiVersion' => 'v1' + ] + ], + /** * HostedSignalingServer */ diff --git a/lib/Chat/AutoComplete/SearchPlugin.php b/lib/Chat/AutoComplete/SearchPlugin.php index aed0b589ccb..b498d3bf85f 100644 --- a/lib/Chat/AutoComplete/SearchPlugin.php +++ b/lib/Chat/AutoComplete/SearchPlugin.php @@ -27,6 +27,7 @@ use OCA\Talk\GuestManager; use OCA\Talk\Model\Attendee; use OCA\Talk\Room; +use OCA\Talk\Service\BlockActorService; use OCA\Talk\Service\ParticipantService; use OCA\Talk\TalkSession; use OCP\Collaboration\Collaborators\ISearchPlugin; @@ -46,6 +47,8 @@ class SearchPlugin implements ISearchPlugin { protected $talkSession; /** @var ParticipantService */ protected $participantService; + /** @var BlockActorService */ + protected $blockActorService; /** @var Util */ protected $util; /** @var string|null */ @@ -60,6 +63,7 @@ public function __construct(IUserManager $userManager, GuestManager $guestManager, TalkSession $talkSession, ParticipantService $participantService, + BlockActorService $blockActorService, Util $util, ?string $userId, IL10N $l) { @@ -67,6 +71,7 @@ public function __construct(IUserManager $userManager, $this->guestManager = $guestManager; $this->talkSession = $talkSession; $this->participantService = $participantService; + $this->blockActorService = $blockActorService; $this->util = $util; $this->userId = $userId; $this->l = $l; @@ -133,6 +138,10 @@ protected function searchUsers(string $search, array $userIds, ISearchResult $se continue; } + if ($this->userId !== '' && $this->blockActorService->user1BlockedUser2($this->userId, $userId)) { + continue; + } + if ($search === '') { $matches[] = $this->createResult('user', $userId, ''); continue; diff --git a/lib/Controller/BlockController.php b/lib/Controller/BlockController.php new file mode 100644 index 00000000000..ab652f0a13a --- /dev/null +++ b/lib/Controller/BlockController.php @@ -0,0 +1,90 @@ + + * + * @author Vitor Mattos + * + * @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 . + * + */ + +namespace OCA\Talk\Controller; + +use OCA\Talk\Model\Attendee; +use OCA\Talk\Service\BlockActorService; +use OCP\AppFramework\Http; +use OCP\AppFramework\Http\DataResponse; +use OCP\IRequest; +use OCP\IUserSession; + +class BlockController extends AEnvironmentAwareController { + /** @var BlockActorService */ + protected $blockActorService; + /** @var IUserSession */ + protected $userSession; + + public function __construct(string $appName, + IRequest $request, + BlockActorService $blockActorService, + IUserSession $userSession + ) { + parent::__construct($appName, $request); + $this->blockActorService = $blockActorService; + $this->userSession = $userSession; + } + + /** + * @NoAdminRequired + */ + public function block(string $blockedId, string $type = Attendee::ACTOR_USERS): DataResponse { + $this->blockActorService->block(Attendee::ACTOR_USERS, $this->userSession->getUser()->getUID(), $type, $blockedId); + return new DataResponse([], Http::STATUS_OK); + } + + /** + * @NoAdminRequired + */ + public function unblock(string $blockedId, string $type = Attendee::ACTOR_USERS): DataResponse { + $this->blockActorService->unblock(Attendee::ACTOR_USERS, $this->userSession->getUser()->getUID(), $type, $blockedId); + return new DataResponse([], Http::STATUS_OK); + } + + /** + * @NoAdminRequired + */ + public function listBlocked(): DataResponse { + $typedList = $this->blockActorService->listBlocked($this->userSession->getUser()->getUID()); + $return = []; + foreach ($typedList as $blockActor) { + $return[] = $blockActor->asArray(); + } + return new DataResponse($return, Http::STATUS_OK); + } + + /** + * @NoAdminRequired + */ + public function listBlockedByType(string $type): DataResponse { + $typedList = $this->blockActorService->listBlockedByType($this->userSession->getUser()->getUID(), $type); + $return = []; + foreach ($typedList as $blockActor) { + $return[] = $blockActor->asArray(); + } + return new DataResponse($return, Http::STATUS_OK); + } +} diff --git a/lib/Migration/Version13000Date20211102171628.php b/lib/Migration/Version13000Date20211102171628.php new file mode 100644 index 00000000000..89f1355dab9 --- /dev/null +++ b/lib/Migration/Version13000Date20211102171628.php @@ -0,0 +1,78 @@ + + * + * @author Vitor Mattos + * + * @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 . + * + */ + +namespace OCA\Talk\Migration; + +use Closure; +use Doctrine\DBAL\Types\Types; +use OCP\DB\ISchemaWrapper; +use OCP\Migration\IOutput; +use OCP\Migration\SimpleMigrationStep; + +/** + * Auto-generated migration step: Please modify to your needs! + */ +class Version13000Date20211102171628 extends SimpleMigrationStep { + /** + * @param IOutput $output + * @param Closure $schemaClosure The `\Closure` returns a `ISchemaWrapper` + * @param array $options + * @return null|ISchemaWrapper + */ + public function changeSchema(IOutput $output, Closure $schemaClosure, array $options): ?ISchemaWrapper { + /** @var ISchemaWrapper $schema */ + $schema = $schemaClosure(); + + if (!$schema->hasTable('talk_block_actor')) { + $table = $schema->createTable('talk_block_actor'); + $table->addColumn('id', Types::BIGINT, [ + 'autoincrement' => true, + 'notnull' => true, + ]); + $table->addColumn('actor_type', Types::STRING, [ + 'notnull' => true, + 'length' => 32, + ]); + $table->addColumn('actor_id', Types::STRING, [ + 'notnull' => true, + 'length' => 255, + ]); + $table->addColumn('blocked_type', Types::STRING, [ + 'notnull' => true, + 'length' => 32, + ]); + $table->addColumn('blocked_id', Types::STRING, [ + 'notnull' => true, + 'length' => 255, + ]); + $table->addColumn('datetime', Types::DATETIME_MUTABLE, [ + 'notnull' => false, + ]); + $table->setPrimaryKey(['id']); + $table->addUniqueIndex(['actor_type', 'actor_id', 'blocked_type', 'blocked_id'], 'unq_block_actor'); + } + return $schema; + } +} diff --git a/lib/Model/BlockActor.php b/lib/Model/BlockActor.php new file mode 100644 index 00000000000..6dde1a67739 --- /dev/null +++ b/lib/Model/BlockActor.php @@ -0,0 +1,81 @@ + + * + * @author Vitor Mattos + * + * @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 . + * + */ + +namespace OCA\Talk\Model; + +use OCP\AppFramework\Db\Entity; + +/** + * @method void setActorType(string $actorType) + * @method string getActorType() + * @method void setActorId(string $actorId) + * @method string getActorId() + * @method void setBlockedType(string $blockedType) + * @method string getBlockedType() + * @method void setBlockedId(string $blockedId) + * @method string getBlockedId() + * @method void setDatetime(\DateTime $datetime) + * @method \DateTime getDatetime() + */ +class BlockActor extends Entity { + /** @var string */ + protected $actorType; + /** @var string */ + protected $actorId; + /** @var string */ + protected $blockedType; + /** @var string */ + protected $blockedId; + /** @var \DateTime */ + protected $datetime; + public function __construct() { + $this->addType('actorType', 'string'); + $this->addType('actorId', 'string'); + $this->addType('blockedType', 'string'); + $this->addType('blockedId', 'string'); + $this->addType('datetime', 'datetime'); + } + + public function setDatetime($datetime): void { + if (!$datetime instanceof \DateTime) { + $datetime = new \DateTime($datetime); + } + $this->datetime = $datetime; + $this->markFieldUpdated('datetime'); + } + + /** + * @return array + */ + public function asArray(): array { + return [ + 'actorType' => $this->getActorType(), + 'actorId' => $this->getActorId(), + 'blockedType' => $this->getBlockedType(), + 'blockedId' => $this->getBlockedId(), + 'datetime' => $this->getDatetime() + ]; + } +} diff --git a/lib/Model/BlockActorMapper.php b/lib/Model/BlockActorMapper.php new file mode 100644 index 00000000000..bf2ad06ab7a --- /dev/null +++ b/lib/Model/BlockActorMapper.php @@ -0,0 +1,94 @@ + + * + * @author Vitor Mattos + * + * @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 . + * + */ + +namespace OCA\Talk\Model; + +use OCP\AppFramework\Db\Entity; +use OCP\AppFramework\Db\QBMapper; +use OCP\DB\Types; +use OCP\IDBConnection; + +class BlockActorMapper extends QBMapper { + /** + * @param IDBConnection $db + */ + public function __construct(IDBConnection $db) { + parent::__construct($db, 'talk_block_actor', BlockActor::class); + } + + public function getBlockListByBlocker($blocker) { + $query = $this->db->getQueryBuilder(); + $query->select('*') + ->from($this->getTableName()) + ->where($query->expr()->eq('actor_id', $query->createNamedParameter($blocker))); + + return $this->findEntities($query); + } + + public function getBlockListByBlockerAndTypeOfBlocked(string $blocker, string $type) { + $query = $this->db->getQueryBuilder(); + $query->select('*') + ->from($this->getTableName()) + ->where($query->expr()->eq('actor_id', $query->createNamedParameter($blocker))) + ->andWhere($query->expr()->eq('blocked_type', $query->createNamedParameter($type))); + + return $this->findEntities($query); + } + + public function delete(Entity $entity): Entity { + if ($entity->getId()) { + return parent::delete($entity); + } + $qb = $this->db->getQueryBuilder(); + + $qb->delete($this->tableName) + ->andWhere( + $qb->expr()->eq('actor_type', $qb->createNamedParameter($entity->getActorType(), Types::STRING)), + $qb->expr()->eq('actor_id', $qb->createNamedParameter($entity->getActorId(), Types::STRING)), + $qb->expr()->eq('blocked_type', $qb->createNamedParameter($entity->getBlockedType(), Types::STRING)), + $qb->expr()->eq('blocked_id', $qb->createNamedParameter($entity->getBlockedId(), Types::STRING)) + ); + $qb->executeStatement(); + return $entity; + } + + public function createBlockActorFromRow($row): BlockActor { + if (isset($row['id'])) { + $blockActor = $this->mapRowToEntity([ + 'id' => $row['id'], + 'actor_type' => $row['actorType'], + 'actor_id' => $row['actorId'], + 'blocked_type' => $row['blockedType'], + 'blocked_id' => $row['blockedId'] + ]); + } else { + $blockActor = new BlockActor(); + foreach ($row as $key => $value) { + $blockActor->{'set' . ucfirst($key)}($value); + } + } + return $blockActor; + } +} diff --git a/lib/Service/BlockActorService.php b/lib/Service/BlockActorService.php new file mode 100644 index 00000000000..f4dc72ef101 --- /dev/null +++ b/lib/Service/BlockActorService.php @@ -0,0 +1,89 @@ + + * + * @author Vitor Mattos + * + * @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 . + * + */ + +namespace OCA\Talk\Service; + +use OCA\Talk\Model\BlockActorMapper; +use OCP\AppFramework\Utility\ITimeFactory; +use OCP\DB\Exception; + +class BlockActorService { + + /** @var BlockActorMapper */ + private $blockActorMapper; + /** @var ITimeFactory */ + private $timeFactory; + + public function __construct(BlockActorMapper $blockActorMapper, + ITimeFactory $timeFactory) { + $this->blockActorMapper = $blockActorMapper; + $this->timeFactory = $timeFactory; + } + + public function block(string $actorType, string $actorId, string $blockedType, string $blockedId): void { + $blockActor = $this->blockActorMapper->createBlockActorFromRow([ + 'actorType' => $actorType, + 'actorId' => $actorId, + 'blockedType' => $blockedType, + 'blockedId' => $blockedId + ]); + $blockActor->setDatetime($this->timeFactory->getDateTime()); + try { + $this->blockActorMapper->insert($blockActor); + } catch (Exception $e) { + if ($e->getReason() !== Exception::REASON_UNIQUE_CONSTRAINT_VIOLATION) { + throw $e; + } + } + } + + public function unblock(string $actorType, string $actorId, string $blockedType, string $blockedId): void { + $blockActor = $this->blockActorMapper->createBlockActorFromRow([ + 'actorType' => $actorType, + 'actorId' => $actorId, + 'blockedType' => $blockedType, + 'blockedId' => $blockedId + ]); + $this->blockActorMapper->delete($blockActor); + } + + public function listBlocked(string $actorId): array { + return $this->blockActorMapper->getBlockListByBlocker($actorId); + } + + public function listBlockedByType(string $actorId, string $type): array { + return $this->blockActorMapper->getBlockListByBlockerAndTypeOfBlocked($actorId, $type); + } + + public function user1BlockedUser2($user1, $user2): bool { + $blockedList = $this->listBlocked($user2); + foreach ($blockedList as $list) { + if (isset($list[$user2])) { + return true; + } + } + return false; + } +} diff --git a/tests/integration/features/actor/block.feature b/tests/integration/features/actor/block.feature new file mode 100644 index 00000000000..8789ebdde0c --- /dev/null +++ b/tests/integration/features/actor/block.feature @@ -0,0 +1,32 @@ +Feature: actor/block + + Background: + Given user "participant1" exists + Given user "participant2" exists + Given user "participant3" exists + + Scenario: user 1 block user 2 and list all blocked users + When user "participant1" unblock user "participant2" with 200 (v1) + And user "participant1" unblock user "participant3" with 200 (v1) + And user "participant1" list all blocked with 200 (v1) + And user "participant1" list all blocked users with 200 (v1) + And user "participant1" block user "participant2" with 200 (v1) + And user "participant1" list all blocked with 200 (v1) + | actorType | actorId | blockedType | blockedId | + | users | participant1 | users | participant2 | + And user "participant1" list all blocked users with 200 (v1) + | actorType | actorId | blockedType | blockedId | + | users | participant1 | users | participant2 | + And user "participant1" block user "participant3" with 200 (v1) + And user "participant1" list all blocked with 200 (v1) + | actorType | actorId | blockedType | blockedId | + | users | participant1 | users | participant2 | + | users | participant1 | users | participant3 | + And user "participant1" list all blocked users with 200 (v1) + | actorType | actorId | blockedType | blockedId | + | users | participant1 | users | participant2 | + | users | participant1 | users | participant3 | + And user "participant1" unblock user "participant2" with 200 (v1) + And user "participant1" unblock user "participant3" with 200 (v1) + And user "participant1" list all blocked with 200 (v1) + And user "participant1" list all blocked users with 200 (v1) \ No newline at end of file diff --git a/tests/integration/features/actor/mention-blocked.feature b/tests/integration/features/actor/mention-blocked.feature new file mode 100644 index 00000000000..cd08fa02ed7 --- /dev/null +++ b/tests/integration/features/actor/mention-blocked.feature @@ -0,0 +1,23 @@ +Feature: actor/mention-blocked + + Background: + Given user "participant1" exists + Given user "participant2" exists + Given user "participant3" exists + + Scenario: user 1 block user 2 and get candidate mentions + When user "participant1" creates room "group room" (v4) + | roomType | 2 | + | roomName | room | + And user "participant1" adds user "participant2" to room "group room" with 200 (v4) + And user "participant1" adds user "participant3" to room "group room" with 200 (v4) + And user "participant1" gets the following candidate mentions in room "group room" for "" with 200 + | id | label | source | + | all | room | calls | + | participant2 | participant2-displayname | users | + | participant3 | participant3-displayname | users | + And user "participant1" block user "participant2" with 200 (v1) + Then user "participant1" gets the following candidate mentions in room "group room" for "" with 200 + | id | label | source | + | all | room | calls | + | participant3 | participant3-displayname | users | \ No newline at end of file diff --git a/tests/integration/features/bootstrap/FeatureContext.php b/tests/integration/features/bootstrap/FeatureContext.php index 601ac55f70c..d1021875478 100644 --- a/tests/integration/features/bootstrap/FeatureContext.php +++ b/tests/integration/features/bootstrap/FeatureContext.php @@ -86,6 +86,9 @@ class FeatureContext implements Context, SnippetAcceptingContext { /** @var array */ protected $createdGuestAccountUsers = []; + /** @var array */ + protected $blockedUsers = []; + /** @var array */ protected $changedConfigs = []; @@ -139,6 +142,7 @@ public function setUp() { $this->createdUsers = []; $this->createdGroups = []; $this->createdGuestAccountUsers = []; + $this->blockedUsers = []; } /** @@ -163,6 +167,11 @@ public function tearDown() { foreach ($this->createdGuestAccountUsers as $user) { $this->deleteUser($user); } + foreach ($this->blockedUsers as $blocker => $blockedList) { + foreach ($blockedList as $blocked) { + $this->userUnblock($blocker, $blocked['type'], $blocked['blockedId']); + } + } } /** @@ -2126,4 +2135,99 @@ protected function getUserCookieJar($user) { protected function assertStatusCode(ResponseInterface $response, int $statusCode, string $message = '') { Assert::assertEquals($statusCode, $response->getStatusCode(), $message); } + + /** + * @When /^user "([^"]*)" block (user|group|email|circle) "([^"]*)" with (\d+) \((v1)\)$/ + * + * @param string $user + * @param string $type + * @param string $blockedId + * @param int $statusCode + * @param string $apiVersion + */ + public function userBlockUser(string $user, string $type, string $blockedId, int $statusCode, string $apiVersion) { + $this->setCurrentUser($user); + $this->sendRequest( + 'POST', '/apps/spreed/api/' . $apiVersion . '/block', [ + 'type' => $type . 's', + 'blockedId' => $blockedId + ] + ); + $this->assertStatusCode($this->response, $statusCode); + $this->blockedUsers[$user][] = [ + 'type' => $type, + 'blockedId' => $blockedId + ]; + } + + + /** + * @When /^user "([^"]*)" unblock (user|group|email|circle) "([^"]*)" with (\d+) \((v1)\)$/ + */ + public function userUnblock($blocker, $blockedType, $blockedId, int $statusCode = 200, $apiVersion = 'v1') { + $this->setCurrentUser($blocker); + $this->sendRequest( + 'DELETE', '/apps/spreed/api/' . $apiVersion . '/block', [ + 'type' => $blockedType . 's', + 'blockedId' => $blockedId + ] + ); + Assert::assertEquals($this->response->getStatusCode(), 200); + } + + /** + * @When /^user "([^"]*)" list all blocked (users|groups|emails|circles) with (\d+) \((v1)\)$/ + */ + public function userListAllBlockedByType(string $user, string $blockedType, int $statusCode, string $apiVersion, TableNode $formData = null) { + $this->setCurrentUser($user); + $this->sendRequest( + 'GET', '/apps/spreed/api/' . $apiVersion . '/block/type/' . $blockedType + ); + $this->assertStatusCode($this->response, $statusCode); + + $response = $this->getDataFromResponse($this->response); + + if ($formData === null) { + Assert::assertEmpty($response); + return; + } + + Assert::assertCount(count($formData->getHash()), $response, 'Blocked actors count does not match'); + Assert::assertEquals($formData->getHash(), array_map(function ($row) { + return [ + 'actorType' => $row['actorType'], + 'actorId' => $row['actorId'], + 'blockedType' => $row['blockedType'], + 'blockedId' => $row['blockedId'] + ]; + }, $response, $formData->getHash()), 'Expected list don\'t mach with returned list'); + } + + /** + * @When /^user "([^"]*)" list all blocked with (\d+) \((v1)\)$/ + */ + public function userListAllBlocked(string $user, int $statusCode, string $apiVersion, TableNode $formData = null) { + $this->setCurrentUser($user); + $this->sendRequest( + 'GET', '/apps/spreed/api/' . $apiVersion . '/block' + ); + $this->assertStatusCode($this->response, $statusCode); + + $response = $this->getDataFromResponse($this->response); + + if ($formData === null) { + Assert::assertEmpty($response); + return; + } + + Assert::assertCount(count($formData->getHash()), $response, 'Blocked actors count does not match'); + Assert::assertEquals($formData->getHash(), array_map(function ($row) { + return [ + 'actorType' => $row['actorType'], + 'actorId' => $row['actorId'], + 'blockedType' => $row['blockedType'], + 'blockedId' => $row['blockedId'] + ]; + }, $response, $formData->getHash()), 'Expected list don\'t mach with returned list'); + } } diff --git a/tests/php/Chat/AutoComplete/SearchPluginTest.php b/tests/php/Chat/AutoComplete/SearchPluginTest.php index e1a832934e4..a7da2d648e9 100644 --- a/tests/php/Chat/AutoComplete/SearchPluginTest.php +++ b/tests/php/Chat/AutoComplete/SearchPluginTest.php @@ -28,6 +28,7 @@ use OCA\Talk\Model\Session; use OCA\Talk\Participant; use OCA\Talk\Room; +use OCA\Talk\Service\BlockActorService; use OCA\Talk\Service\ParticipantService; use OCA\Talk\TalkSession; use OCP\Collaboration\Collaborators\ISearchResult; @@ -46,6 +47,8 @@ class SearchPluginTest extends \Test\TestCase { protected $talkSession; /** @var ParticipantService|MockObject */ protected $participantService; + /** @var BlockActorService|MockObject */ + protected $blockActorService; /** @var Util|MockObject */ protected $util; /** @var IL10N|MockObject */ @@ -62,6 +65,7 @@ public function setUp(): void { $this->guestManager = $this->createMock(GuestManager::class); $this->talkSession = $this->createMock(TalkSession::class); $this->participantService = $this->createMock(ParticipantService::class); + $this->blockActorService = $this->createMock(BlockActorService::class); $this->util = $this->createMock(Util::class); $this->userId = 'current'; $this->l = $this->createMock(IL10N::class); @@ -83,6 +87,7 @@ protected function getPlugin(array $methods = []) { $this->guestManager, $this->talkSession, $this->participantService, + $this->blockActorService, $this->util, $this->userId, $this->l @@ -95,6 +100,7 @@ protected function getPlugin(array $methods = []) { $this->guestManager, $this->talkSession, $this->participantService, + $this->blockActorService, $this->util, $this->userId, $this->l,