Merge pull request #1516 from PhrozenByte/feature/commands
Add polls:share:* CLI commands
This commit is contained in:
Коммит
c53aabf354
|
@ -8,6 +8,7 @@ css/*.map
|
|||
js/*
|
||||
nbproject/
|
||||
node_modules/
|
||||
tests/.phpunit.result.cache
|
||||
npm-debug.log
|
||||
vendor
|
||||
Thumbs.db
|
||||
|
|
|
@ -28,6 +28,10 @@
|
|||
<background-jobs>
|
||||
<job>OCA\Polls\Cron\NotificationCron</job>
|
||||
</background-jobs>
|
||||
<commands>
|
||||
<command>OCA\Polls\Command\Share\Add</command>
|
||||
<command>OCA\Polls\Command\Share\Remove</command>
|
||||
</commands>
|
||||
<repair-steps>
|
||||
<pre-migration>
|
||||
<step>OCA\Polls\Migration\DeleteDuplicates</step>
|
||||
|
|
|
@ -0,0 +1,145 @@
|
|||
<?php
|
||||
/**
|
||||
* @copyright Copyright (c) 2021 Daniel Rudolf <nextcloud.com@daniel-rudolf.de>
|
||||
*
|
||||
* @author Daniel Rudolf <nextcloud.com@daniel-rudolf.de>
|
||||
*
|
||||
* @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\Polls\Command\Share;
|
||||
|
||||
use OC\Core\Command\Base;
|
||||
use OCA\Polls\Db\Poll;
|
||||
use OCA\Polls\Exceptions\ShareAlreadyExistsException;
|
||||
use OCA\Polls\Model\Email;
|
||||
use OCA\Polls\Model\Group;
|
||||
use OCA\Polls\Model\User;
|
||||
use OCP\AppFramework\Db\DoesNotExistException;
|
||||
use Stecman\Component\Symfony\Console\BashCompletion\CompletionContext;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
class Add extends Base {
|
||||
use TShareCommand;
|
||||
|
||||
protected function configure(): void {
|
||||
$this
|
||||
->setName('polls:share:add')
|
||||
->setDescription('Invites users to a poll')
|
||||
->addArgument(
|
||||
'id',
|
||||
InputArgument::REQUIRED,
|
||||
'ID of the poll to invite users to'
|
||||
)->addOption(
|
||||
'user',
|
||||
null,
|
||||
InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY,
|
||||
'Invites the given users to the poll'
|
||||
)->addOption(
|
||||
'group',
|
||||
null,
|
||||
InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY,
|
||||
'Invites all members of the given groups to the poll'
|
||||
)->addOption(
|
||||
'email',
|
||||
null,
|
||||
InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY,
|
||||
'Sends invitation e-mails to the given addresses to participate in the poll'
|
||||
);
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int {
|
||||
$pollId = $input->getArgument('id');
|
||||
$users = $input->getOption('user');
|
||||
$groups = $input->getOption('group');
|
||||
$emails = $input->getOption('email');
|
||||
|
||||
try {
|
||||
$poll = $this->pollMapper->find($pollId);
|
||||
} catch (DoesNotExistException $e) {
|
||||
$output->writeln('<error>Poll not found.</error>');
|
||||
return 1;
|
||||
}
|
||||
|
||||
$this->inviteUsers($poll, $users);
|
||||
$this->inviteGroups($poll, $groups);
|
||||
$this->inviteEmails($poll, $emails);
|
||||
|
||||
$output->writeln('<info>Users successfully invited to poll.</info>');
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Poll $poll
|
||||
* @param string[] $userIds
|
||||
*/
|
||||
private function inviteUsers(Poll $poll, array $userIds): void {
|
||||
foreach ($userIds as $userId) {
|
||||
try {
|
||||
$share = $this->shareService->add($poll->getId(), User::TYPE, $userId);
|
||||
$this->shareService->sendInvitation($share->getToken());
|
||||
} catch (ShareAlreadyExistsException $e) {
|
||||
// silently ignore already existing shares
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Poll $poll
|
||||
* @param string[] $groupIds
|
||||
*/
|
||||
private function inviteGroups(Poll $poll, array $groupIds): void {
|
||||
foreach ($groupIds as $groupId) {
|
||||
try {
|
||||
$share = $this->shareService->add($poll->getId(), Group::TYPE, $groupId);
|
||||
$this->shareService->sendInvitation($share->getToken());
|
||||
} catch (ShareAlreadyExistsException $e) {
|
||||
// silently ignore already existing shares
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Poll $poll
|
||||
* @param string[] $emails
|
||||
*/
|
||||
private function inviteEmails(Poll $poll, array $emails): void {
|
||||
foreach ($emails as $email) {
|
||||
try {
|
||||
$share = $this->shareService->add($poll->getId(), Email::TYPE, $email);
|
||||
$this->shareService->sendInvitation($share->getToken());
|
||||
} catch (ShareAlreadyExistsException $e) {
|
||||
// silently ignore already existing shares
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function completeOptionValues($optionName, CompletionContext $context) {
|
||||
switch ($optionName) {
|
||||
case 'user':
|
||||
return $this->completeUserValues($context);
|
||||
|
||||
case 'group':
|
||||
return $this->completeGroupValues($context);
|
||||
}
|
||||
|
||||
return parent::completeOptionValues($optionName, $context);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,162 @@
|
|||
<?php
|
||||
/**
|
||||
* @copyright Copyright (c) 2021 Daniel Rudolf <nextcloud.com@daniel-rudolf.de>
|
||||
*
|
||||
* @author Daniel Rudolf <nextcloud.com@daniel-rudolf.de>
|
||||
*
|
||||
* @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\Polls\Command\Share;
|
||||
|
||||
use OC\Core\Command\Base;
|
||||
use OCA\Polls\Db\Poll;
|
||||
use OCA\Polls\Db\Share;
|
||||
use OCA\Polls\Model\Contact;
|
||||
use OCA\Polls\Model\Email;
|
||||
use OCA\Polls\Model\GenericUser;
|
||||
use OCA\Polls\Model\Group;
|
||||
use OCA\Polls\Model\User;
|
||||
use OCP\AppFramework\Db\DoesNotExistException;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
class Remove extends Base {
|
||||
use TShareCommand;
|
||||
|
||||
protected function configure(): void {
|
||||
$this
|
||||
->setName('polls:share:remove')
|
||||
->setDescription('Remove user invitations from a poll')
|
||||
->addArgument(
|
||||
'id',
|
||||
InputArgument::REQUIRED,
|
||||
'ID of the poll to remove invitations from'
|
||||
)->addOption(
|
||||
'user',
|
||||
null,
|
||||
InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY,
|
||||
'Removes invitation of the given users from the poll'
|
||||
)->addOption(
|
||||
'group',
|
||||
null,
|
||||
InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY,
|
||||
'Removes invitations for all members of the given groups from the poll'
|
||||
)->addOption(
|
||||
'email',
|
||||
null,
|
||||
InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY,
|
||||
'Removes invitations for all users with the given e-mail addresses from the poll'
|
||||
);
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int {
|
||||
$pollId = $input->getArgument('id');
|
||||
$users = $input->getOption('user');
|
||||
$groups = $input->getOption('group');
|
||||
$emails = $input->getOption('email');
|
||||
|
||||
try {
|
||||
$poll = $this->pollMapper->find($pollId);
|
||||
} catch (DoesNotExistException $e) {
|
||||
$output->writeln('<error>Poll not found.</error>');
|
||||
return 1;
|
||||
}
|
||||
|
||||
$this->removeUsers($poll, $users);
|
||||
$this->removeGroups($poll, $groups);
|
||||
$this->removeEmails($poll, $emails);
|
||||
|
||||
$output->writeln('<info>Poll invitations successfully revoked.</info>');
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Poll $poll
|
||||
* @param string[] $userIds
|
||||
*/
|
||||
private function removeUsers(Poll $poll, array $userIds): void {
|
||||
foreach ($this->getUserShares($poll) as $share) {
|
||||
if (in_array($share->getUserId(), $userIds, true)) {
|
||||
$this->shareService->delete($share->getToken());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Poll $poll
|
||||
* @param string[] $groupIds
|
||||
*/
|
||||
private function removeGroups(Poll $poll, array $groupIds): void {
|
||||
foreach ($this->getGroupShares($poll) as $share) {
|
||||
if (in_array($share->getUserId(), $groupIds, true)) {
|
||||
$this->shareService->delete($share->getToken());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Poll $poll
|
||||
* @param string[] $emails
|
||||
*/
|
||||
private function removeEmails(Poll $poll, array $emails): void {
|
||||
foreach ($this->getEmailShares($poll) as $share) {
|
||||
if (in_array($share->getEmailAddress(), $emails, true)) {
|
||||
$this->shareService->delete($share->getToken());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Poll $poll
|
||||
* @return Share[]
|
||||
*/
|
||||
private function getUserShares(Poll $poll): array {
|
||||
$shares = $this->shareMapper->findByPoll($poll->getId());
|
||||
return array_values(array_filter($shares, static function (Share $share): bool {
|
||||
return ($share->getType() === User::TYPE);
|
||||
}));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Poll $poll
|
||||
* @return Share[]
|
||||
*/
|
||||
private function getGroupShares(Poll $poll): array {
|
||||
$shares = $this->shareMapper->findByPoll($poll->getId());
|
||||
return array_values(array_filter($shares, static function (Share $share): bool {
|
||||
return ($share->getType() === Group::TYPE);
|
||||
}));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Poll $poll
|
||||
* @return Share[]
|
||||
*/
|
||||
private function getEmailShares(Poll $poll): array {
|
||||
$shares = $this->shareMapper->findByPoll($poll->getId());
|
||||
return array_values(array_filter($shares, static function (Share $share): bool {
|
||||
if (($share->getType() === GenericUser::TYPE) && $share->getEmailAddress()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return (($share->getType() === Email::TYPE) || ($share->getType() === Contact::TYPE));
|
||||
}));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,76 @@
|
|||
<?php
|
||||
/**
|
||||
* @copyright Copyright (c) 2021 Daniel Rudolf <nextcloud.com@daniel-rudolf.de>
|
||||
*
|
||||
* @author Daniel Rudolf <nextcloud.com@daniel-rudolf.de>
|
||||
*
|
||||
* @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\Polls\Command\Share;
|
||||
|
||||
use OCA\Polls\Db\PollMapper;
|
||||
use OCA\Polls\Db\ShareMapper;
|
||||
use OCA\Polls\Service\ShareService;
|
||||
use OCP\IGroup;
|
||||
use OCP\IGroupManager;
|
||||
use OCP\IUser;
|
||||
use OCP\IUserManager;
|
||||
use Stecman\Component\Symfony\Console\BashCompletion\CompletionContext;
|
||||
|
||||
trait TShareCommand {
|
||||
/** @var PollMapper */
|
||||
private $pollMapper;
|
||||
|
||||
/** @var ShareService */
|
||||
private $shareService;
|
||||
|
||||
/** @var ShareMapper */
|
||||
private $shareMapper;
|
||||
|
||||
/** @var IUserManager */
|
||||
private $userManager;
|
||||
|
||||
/** @var IGroupManager */
|
||||
private $groupManager;
|
||||
|
||||
public function __construct(PollMapper $pollMapper,
|
||||
ShareMapper $shareMapper,
|
||||
ShareService $shareService,
|
||||
IUserManager $userManager,
|
||||
IGroupManager $groupManager) {
|
||||
parent::__construct();
|
||||
|
||||
$this->pollMapper = $pollMapper;
|
||||
$this->shareMapper = $shareMapper;
|
||||
$this->shareService = $shareService;
|
||||
$this->userManager = $userManager;
|
||||
$this->groupManager = $groupManager;
|
||||
}
|
||||
|
||||
private function completeUserValues(CompletionContext $context): array {
|
||||
return array_map(function (IUser $user) {
|
||||
return $user->getUID();
|
||||
}, $this->userManager->search($context->getCurrentWord()));
|
||||
}
|
||||
|
||||
private function completeGroupValues(CompletionContext $context): array {
|
||||
return array_map(function (IGroup $group) {
|
||||
return $group->getGID();
|
||||
}, $this->groupManager->search($context->getCurrentWord()));
|
||||
}
|
||||
}
|
|
@ -32,10 +32,8 @@ use OCP\AppFramework\Http\DataResponse;
|
|||
|
||||
use OCA\Polls\Db\Share;
|
||||
use OCA\Polls\Service\MailService;
|
||||
use OCA\Polls\Service\NotificationService;
|
||||
use OCA\Polls\Service\ShareService;
|
||||
use OCA\Polls\Service\SystemService;
|
||||
use OCA\Polls\Model\User;
|
||||
use OCA\Polls\Model\Circle;
|
||||
use OCA\Polls\Model\ContactGroup;
|
||||
|
||||
|
@ -51,22 +49,17 @@ class ShareController extends Controller {
|
|||
/** @var SystemService */
|
||||
private $systemService;
|
||||
|
||||
/** @var NotificationService */
|
||||
private $notificationService;
|
||||
|
||||
public function __construct(
|
||||
string $appName,
|
||||
IRequest $request,
|
||||
MailService $mailService,
|
||||
ShareService $shareService,
|
||||
SystemService $systemService,
|
||||
NotificationService $notificationService
|
||||
SystemService $systemService
|
||||
) {
|
||||
parent::__construct($appName, $request);
|
||||
$this->mailService = $mailService;
|
||||
$this->shareService = $shareService;
|
||||
$this->systemService = $systemService;
|
||||
$this->notificationService = $notificationService;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -144,21 +137,9 @@ class ShareController extends Controller {
|
|||
*/
|
||||
public function sendInvitation($token): DataResponse {
|
||||
return $this->response(function () use ($token) {
|
||||
$share = $this->shareService->get($token);
|
||||
if ($share->getType() === Share::TYPE_USER) {
|
||||
$this->notificationService->sendInvitation($share->getPollId(), $share->getUserId());
|
||||
// TODO: skip this atm, to send invitations as mail too, if user is a site user
|
||||
// $sentResult = ['sentMails' => [new User($share->getuserId())]];
|
||||
// $this->shareService->setInvitationSent($token);
|
||||
} elseif ($share->getType() === Share::TYPE_GROUP) {
|
||||
foreach ($share->getMembers() as $member) {
|
||||
$this->notificationService->sendInvitation($share->getPollId(), $member->getId());
|
||||
}
|
||||
}
|
||||
$sentResult = $this->mailService->sendInvitation($token);
|
||||
return [
|
||||
'share' => $share,
|
||||
'sentResult' => $sentResult
|
||||
'share' => $this->shareService->get($token),
|
||||
'sentResult' => $this->shareService->sendInvitation($token),
|
||||
];
|
||||
});
|
||||
}
|
||||
|
|
|
@ -252,10 +252,11 @@ class Acl implements JsonSerializable {
|
|||
|
||||
/**
|
||||
* hasAdminAccess - Has user administrative rights?
|
||||
* Returns true, if user is in admin group and poll has allowed admins to manage the poll
|
||||
* Returns true, if user is in admin group and poll has allowed admins to manage the poll,
|
||||
* or when running console commands.
|
||||
*/
|
||||
private function hasAdminAccess(): bool {
|
||||
return ($this->getIsAdmin() && $this->poll->getAdminAccess());
|
||||
return (($this->getIsAdmin() && $this->poll->getAdminAccess()) || defined('OC_CONSOLE'));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -67,6 +67,9 @@ class ShareService {
|
|||
/** @var Acl */
|
||||
private $acl;
|
||||
|
||||
/** @var NotificationService */
|
||||
private $notificationService;
|
||||
|
||||
public function __construct(
|
||||
string $AppName,
|
||||
LoggerInterface $logger,
|
||||
|
@ -76,7 +79,8 @@ class ShareService {
|
|||
ShareMapper $shareMapper,
|
||||
Share $share,
|
||||
MailService $mailService,
|
||||
Acl $acl
|
||||
Acl $acl,
|
||||
NotificationService $notificationService
|
||||
) {
|
||||
$this->appName = $AppName;
|
||||
$this->logger = $logger;
|
||||
|
@ -87,6 +91,7 @@ class ShareService {
|
|||
$this->share = $share;
|
||||
$this->mailService = $mailService;
|
||||
$this->acl = $acl;
|
||||
$this->notificationService = $notificationService;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -347,4 +352,25 @@ class ShareService {
|
|||
}
|
||||
return $token;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sent invitation mails for a share
|
||||
* Additionally send notification via notifications
|
||||
*/
|
||||
public function sendInvitation(string $token): array {
|
||||
$share = $this->get($token);
|
||||
if ($share->getType() === Share::TYPE_USER) {
|
||||
$this->notificationService->sendInvitation($share->getPollId(), $share->getUserId());
|
||||
|
||||
// TODO: skip this atm, to send invitations as mail too, if user is a site user
|
||||
// $sentResult = ['sentMails' => [new User($share->getuserId())]];
|
||||
// $this->shareService->setInvitationSent($token);
|
||||
} elseif ($share->getType() === Share::TYPE_GROUP) {
|
||||
foreach ($share->getMembers() as $member) {
|
||||
$this->notificationService->sendInvitation($share->getPollId(), $member->getId());
|
||||
}
|
||||
}
|
||||
|
||||
return $this->mailService->sendInvitation($token);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,7 +21,7 @@
|
|||
*
|
||||
*/
|
||||
|
||||
namespace OCA\Polls\Tests\Integration;
|
||||
namespace OCA\Polls\Tests\Integration\App;
|
||||
|
||||
use OCP\AppFramework\App;
|
||||
use PHPUnit\Framework\TestCase;
|
|
@ -0,0 +1,205 @@
|
|||
<?php
|
||||
/**
|
||||
* @copyright Copyright (c) 2021 Daniel Rudolf <nextcloud.com@daniel-rudolf.de>
|
||||
*
|
||||
* @author Daniel Rudolf <nextcloud.com@daniel-rudolf.de>
|
||||
*
|
||||
* @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\Polls\Tests\Integration\Command\Share;
|
||||
|
||||
use OCA\Polls\Command\Share\Add;
|
||||
use OCA\Polls\Db\Poll;
|
||||
use OCA\Polls\Db\Share;
|
||||
use OCA\Polls\Exceptions\ShareAlreadyExistsException;
|
||||
use OCA\Polls\Model\Email;
|
||||
use OCA\Polls\Model\Group;
|
||||
use OCA\Polls\Model\User;
|
||||
use OCP\AppFramework\Db\DoesNotExistException;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Symfony\Component\Console\Exception\RuntimeException as ConsoleRuntimeException;
|
||||
use Symfony\Component\Console\Tester\CommandTester;
|
||||
|
||||
class AddTest extends TestCase {
|
||||
use TShareCommandTest;
|
||||
|
||||
public function setUp(): void {
|
||||
parent::setUp();
|
||||
|
||||
$this->setUpMocks();
|
||||
}
|
||||
|
||||
public function testMissingArguments(): void {
|
||||
$this->pollMapper
|
||||
->expects($this->never())
|
||||
->method('find');
|
||||
|
||||
$this->expectException(ConsoleRuntimeException::class);
|
||||
$this->expectExceptionMessage('Not enough arguments (missing: "id").');
|
||||
|
||||
$command = new Add(
|
||||
$this->pollMapper,
|
||||
$this->shareMapper,
|
||||
$this->shareService,
|
||||
$this->userManager,
|
||||
$this->groupManager
|
||||
);
|
||||
|
||||
$tester = new CommandTester($command);
|
||||
$tester->execute([]);
|
||||
}
|
||||
|
||||
public function testPollNotFound(): void {
|
||||
$pollId = 123;
|
||||
|
||||
$this->pollMapper
|
||||
->expects($this->once())
|
||||
->method('find')
|
||||
->with($pollId)
|
||||
->willReturnCallback(function (int $id): Poll {
|
||||
throw new DoesNotExistException('');
|
||||
});
|
||||
|
||||
$command = new Add(
|
||||
$this->pollMapper,
|
||||
$this->shareMapper,
|
||||
$this->shareService,
|
||||
$this->userManager,
|
||||
$this->groupManager
|
||||
);
|
||||
|
||||
$tester = new CommandTester($command);
|
||||
$tester->execute(['id' => $pollId]);
|
||||
|
||||
$this->assertEquals("Poll not found.\n", $tester->getDisplay());
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider validProvider
|
||||
*/
|
||||
public function testValid(array $input, array $pollData): void {
|
||||
$expectedShareCount = count($pollData['expectedShares']['user'] ?? [])
|
||||
+ count($pollData['expectedShares']['group'] ?? [])
|
||||
+ count($pollData['expectedShares']['email'] ?? []);
|
||||
$expectedInvitationCount = count($pollData['expectedInvitations']['user'] ?? [])
|
||||
+ count($pollData['expectedInvitations']['group'] ?? [])
|
||||
+ count($pollData['expectedInvitations']['email'] ?? []);
|
||||
|
||||
$expectedInvitationShareTokens = [];
|
||||
foreach ($pollData['expectedInvitations'] ?? [] as $type => $shares) {
|
||||
foreach ($shares as $userId) {
|
||||
$expectedInvitationShareTokens[] = $this->getShareToken($pollData['pollId'], $type, $userId);
|
||||
}
|
||||
}
|
||||
|
||||
$this->pollMapper
|
||||
->expects($this->once())
|
||||
->method('find')
|
||||
->with($pollData['pollId'])
|
||||
->willReturnCallback([$this, 'createPollMock']);
|
||||
|
||||
$this->shareService
|
||||
->expects($this->exactly($expectedShareCount))
|
||||
->method('add')
|
||||
->with($pollData['pollId'], $this->logicalOr(User::TYPE, Group::TYPE, Email::TYPE), $this->anything())
|
||||
->willReturnCallback(function (int $pollId, string $type, string $userId = '') use ($pollData): Share {
|
||||
$userIdConstraint = $this->logicalOr(...$pollData['expectedShares'][$type] ?? []);
|
||||
$userIdConstraint->evaluate($userId);
|
||||
|
||||
if (in_array($userId, $pollData['initialShares'][$type] ?? [])) {
|
||||
throw new ShareAlreadyExistsException();
|
||||
}
|
||||
|
||||
return $this->createShareMock($pollId, $type, $userId);
|
||||
});
|
||||
|
||||
$this->shareService
|
||||
->expects($this->exactly($expectedInvitationCount))
|
||||
->method('sendInvitation')
|
||||
->with($this->logicalOr(...$expectedInvitationShareTokens));
|
||||
|
||||
$command = new Add(
|
||||
$this->pollMapper,
|
||||
$this->shareMapper,
|
||||
$this->shareService,
|
||||
$this->userManager,
|
||||
$this->groupManager
|
||||
);
|
||||
|
||||
$tester = new CommandTester($command);
|
||||
$tester->execute($input);
|
||||
|
||||
$this->assertEquals("Users successfully invited to poll.\n", $tester->getDisplay());
|
||||
}
|
||||
|
||||
public function validProvider(): array {
|
||||
return [
|
||||
[
|
||||
[
|
||||
'id' => 1,
|
||||
],
|
||||
[
|
||||
'pollId' => 1,
|
||||
],
|
||||
],
|
||||
[
|
||||
[
|
||||
'id' => 123,
|
||||
'--user' => ['user1', 'user2'],
|
||||
'--group' => ['group1'],
|
||||
'--email' => ['foo@example.com', 'bar@example.com'],
|
||||
],
|
||||
[
|
||||
'pollId' => 123,
|
||||
'expectedShares' => [
|
||||
'user' => ['user1', 'user2'],
|
||||
'group' => ['group1'],
|
||||
'email' => ['foo@example.com', 'bar@example.com'],
|
||||
],
|
||||
'expectedInvitations' => [
|
||||
'user' => ['user1', 'user2'],
|
||||
'group' => ['group1'],
|
||||
'email' => ['foo@example.com', 'bar@example.com'],
|
||||
],
|
||||
],
|
||||
],
|
||||
[
|
||||
[
|
||||
'id' => 456,
|
||||
'--user' => ['user2', 'user3', 'user4'],
|
||||
'--email' => ['foo@example.com', 'bar@example.com'],
|
||||
],
|
||||
[
|
||||
'pollId' => 456,
|
||||
'initialShares' => [
|
||||
'user' => ['user1', 'user2'],
|
||||
'email' => ['foo@example.com'],
|
||||
],
|
||||
'expectedShares' => [
|
||||
'user' => ['user2', 'user3', 'user4'],
|
||||
'email' => ['foo@example.com', 'bar@example.com'],
|
||||
],
|
||||
'expectedInvitations' => [
|
||||
'user' => ['user3', 'user4'],
|
||||
'email' => ['bar@example.com'],
|
||||
],
|
||||
],
|
||||
],
|
||||
];
|
||||
}
|
||||
}
|
|
@ -0,0 +1,208 @@
|
|||
<?php
|
||||
/**
|
||||
* @copyright Copyright (c) 2021 Daniel Rudolf <nextcloud.com@daniel-rudolf.de>
|
||||
*
|
||||
* @author Daniel Rudolf <nextcloud.com@daniel-rudolf.de>
|
||||
*
|
||||
* @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\Polls\Tests\Integration\Command\Share;
|
||||
|
||||
use OCA\Polls\Command\Share\Remove;
|
||||
use OCA\Polls\Db\Poll;
|
||||
use OCP\AppFramework\Db\DoesNotExistException;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Symfony\Component\Console\Exception\RuntimeException as ConsoleRuntimeException;
|
||||
use Symfony\Component\Console\Tester\CommandTester;
|
||||
|
||||
class RemoveTest extends TestCase {
|
||||
use TShareCommandTest;
|
||||
|
||||
public function setUp(): void {
|
||||
parent::setUp();
|
||||
|
||||
$this->setUpMocks();
|
||||
}
|
||||
|
||||
public function testMissingArguments(): void {
|
||||
$this->pollMapper
|
||||
->expects($this->never())
|
||||
->method('find');
|
||||
|
||||
$this->expectException(ConsoleRuntimeException::class);
|
||||
$this->expectExceptionMessage('Not enough arguments (missing: "id").');
|
||||
|
||||
$command = new Remove(
|
||||
$this->pollMapper,
|
||||
$this->shareMapper,
|
||||
$this->shareService,
|
||||
$this->userManager,
|
||||
$this->groupManager
|
||||
);
|
||||
|
||||
$tester = new CommandTester($command);
|
||||
$tester->execute([]);
|
||||
}
|
||||
|
||||
public function testPollNotFound(): void {
|
||||
$pollId = 123;
|
||||
|
||||
$this->pollMapper
|
||||
->expects($this->once())
|
||||
->method('find')
|
||||
->with($pollId)
|
||||
->willReturnCallback(static function (int $id): Poll {
|
||||
throw new DoesNotExistException('');
|
||||
});
|
||||
|
||||
$command = new Remove(
|
||||
$this->pollMapper,
|
||||
$this->shareMapper,
|
||||
$this->shareService,
|
||||
$this->userManager,
|
||||
$this->groupManager
|
||||
);
|
||||
|
||||
$tester = new CommandTester($command);
|
||||
$tester->execute(['id' => $pollId]);
|
||||
|
||||
$this->assertEquals("Poll not found.\n", $tester->getDisplay());
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider validProvider
|
||||
*/
|
||||
public function testValid(array $input, array $pollData): void {
|
||||
$initialShares = [];
|
||||
$expectedShareCount = 0;
|
||||
$expectedShareTokens = [];
|
||||
foreach ($pollData['initialShares'] ?? [] as $type => $shares) {
|
||||
foreach ($shares as $userId) {
|
||||
$initialShares[] = $this->createShareMock($pollData['pollId'], $type, $userId);
|
||||
|
||||
if (in_array($userId, $pollData['expectedShares'][$type] ?? [])) {
|
||||
$expectedShareTokens[] = $this->getShareToken($pollData['pollId'], $type, $userId);
|
||||
$expectedShareCount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$this->pollMapper
|
||||
->expects($this->once())
|
||||
->method('find')
|
||||
->with($pollData['pollId'])
|
||||
->willReturnCallback([$this, 'createPollMock']);
|
||||
|
||||
$this->shareMapper
|
||||
->method('findByPoll')
|
||||
->with($pollData['pollId'])
|
||||
->willReturn($initialShares);
|
||||
|
||||
$this->shareService
|
||||
->expects($this->exactly($expectedShareCount))
|
||||
->method('delete')
|
||||
->with($this->logicalOr(...$expectedShareTokens));
|
||||
|
||||
$command = new Remove(
|
||||
$this->pollMapper,
|
||||
$this->shareMapper,
|
||||
$this->shareService,
|
||||
$this->userManager,
|
||||
$this->groupManager
|
||||
);
|
||||
|
||||
$tester = new CommandTester($command);
|
||||
$tester->execute($input);
|
||||
|
||||
$this->assertEquals("Poll invitations successfully revoked.\n", $tester->getDisplay());
|
||||
}
|
||||
|
||||
public function validProvider(): array {
|
||||
return [
|
||||
[
|
||||
[
|
||||
'id' => 1,
|
||||
],
|
||||
[
|
||||
'pollId' => 1,
|
||||
],
|
||||
],
|
||||
[
|
||||
[
|
||||
'id' => 123,
|
||||
'--user' => ['user1', 'user2'],
|
||||
'--group' => ['group1'],
|
||||
'--email' => ['foo@example.com'],
|
||||
],
|
||||
[
|
||||
'pollId' => 123,
|
||||
'initialShares' => [
|
||||
'user' => ['user1', 'user2', 'user3'],
|
||||
'group' => ['group1'],
|
||||
'email' => ['foo@example.com', 'bar@example.com'],
|
||||
],
|
||||
'expectedShares' => [
|
||||
'user' => ['user1', 'user2'],
|
||||
'group' => ['group1'],
|
||||
'email' => ['foo@example.com'],
|
||||
],
|
||||
],
|
||||
],
|
||||
[
|
||||
[
|
||||
'id' => 456,
|
||||
'--user' => ['user1', 'user2', 'user3', 'user4'],
|
||||
'--email' => ['foo@example.com', 'bar@example.com'],
|
||||
],
|
||||
[
|
||||
'pollId' => 456,
|
||||
'initialShares' => [
|
||||
'user' => ['user2', 'user3'],
|
||||
'email' => ['foo@example.com', 'baz@example.com'],
|
||||
'contact' => ['bar@example.com'],
|
||||
],
|
||||
'expectedShares' => [
|
||||
'user' => ['user2', 'user3'],
|
||||
'email' => ['foo@example.com'],
|
||||
'contact' => ['bar@example.com'],
|
||||
],
|
||||
]
|
||||
],
|
||||
[
|
||||
[
|
||||
'id' => 789,
|
||||
'--group' => ['group1'],
|
||||
'--email' => ['foo@example.com', 'baz@example.com'],
|
||||
],
|
||||
[
|
||||
'pollId' => 789,
|
||||
'initialShares' => [
|
||||
'user' => ['user1', 'user2'],
|
||||
'email' => ['foo@example.com'],
|
||||
'contact' => ['bar@example.com'],
|
||||
'external' => ['baz@example.com'],
|
||||
],
|
||||
'expectedShares' => [
|
||||
'email' => ['foo@example.com'],
|
||||
'external' => ['baz@example.com'],
|
||||
],
|
||||
]
|
||||
],
|
||||
];
|
||||
}
|
||||
}
|
|
@ -0,0 +1,129 @@
|
|||
<?php
|
||||
/**
|
||||
* @copyright Copyright (c) 2021 Daniel Rudolf <nextcloud.com@daniel-rudolf.de>
|
||||
*
|
||||
* @author Daniel Rudolf <nextcloud.com@daniel-rudolf.de>
|
||||
*
|
||||
* @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\Polls\Tests\Integration\Command\Share;
|
||||
|
||||
use OCA\Polls\Db\Poll;
|
||||
use OCA\Polls\Db\PollMapper;
|
||||
use OCA\Polls\Db\Share;
|
||||
use OCA\Polls\Db\ShareMapper;
|
||||
use OCA\Polls\Service\ShareService;
|
||||
use OCP\IGroupManager;
|
||||
use OCP\IUserManager;
|
||||
use PHPUnit\Framework\MockObject\MockObject;
|
||||
|
||||
trait TShareCommandTest {
|
||||
/** @var PollMapper|MockObject */
|
||||
protected $pollMapper;
|
||||
|
||||
/** @var ShareMapper|MockObject */
|
||||
protected $shareMapper;
|
||||
|
||||
/** @var ShareService|MockObject */
|
||||
protected $shareService;
|
||||
|
||||
/** @var IUserManager|MockObject */
|
||||
protected $userManager;
|
||||
|
||||
/** @var IGroupManager|MockObject */
|
||||
protected $groupManager;
|
||||
|
||||
/** @var int */
|
||||
protected $lastShareId = 0;
|
||||
|
||||
protected function setUpMocks(): void {
|
||||
$this->pollMapper = $this->createMock(PollMapper::class);
|
||||
$this->shareMapper = $this->createMock(ShareMapper::class);
|
||||
$this->shareService = $this->createMock(ShareService::class);
|
||||
$this->userManager = $this->createMock(IUserManager::class);
|
||||
$this->groupManager = $this->createMock(IGroupManager::class);
|
||||
}
|
||||
|
||||
public function createPollMock(int $id): Poll {
|
||||
/** @var Poll|MockObject $poll */
|
||||
$poll = $this->createMock(
|
||||
Poll::class,
|
||||
['getId']
|
||||
);
|
||||
|
||||
$poll->method('getId')
|
||||
->willReturn($id);
|
||||
|
||||
return $poll;
|
||||
}
|
||||
|
||||
public function createShareMock(int $pollId, string $type, string $userId): Share {
|
||||
/** @var Share|MockObject $share */
|
||||
$share = $this->createMock(
|
||||
Share::class,
|
||||
['getId', 'getPollId', 'getType', 'getEmailAddress', 'getToken'],
|
||||
['getUserId']
|
||||
);
|
||||
|
||||
$id = ++$this->lastShareId;
|
||||
$token = $this->getShareToken($pollId, $type, $userId);
|
||||
|
||||
$share->method('getId')
|
||||
->willReturn($id);
|
||||
|
||||
$share->method('getPollId')
|
||||
->willReturn($pollId);
|
||||
|
||||
$share->method('getType')
|
||||
->willReturn($type);
|
||||
|
||||
$share->method('getUserId')
|
||||
->willReturn($userId);
|
||||
|
||||
$share->method('getEmailAddress')
|
||||
->willReturn($userId);
|
||||
|
||||
$share->method('getToken')
|
||||
->willReturn($token);
|
||||
|
||||
return $share;
|
||||
}
|
||||
|
||||
public function getShareToken(int $pollId, string $type, string $userId): string {
|
||||
return substr(md5($pollId . '_' . $type . '_' . $userId), 0, 16);
|
||||
}
|
||||
|
||||
protected function createMock($originalClassName, array $addMethods = null, array $onlyMethods = null): MockObject {
|
||||
$mockBuilder = $this->getMockBuilder($originalClassName)
|
||||
->disableOriginalConstructor()
|
||||
->disableOriginalClone()
|
||||
->disableArgumentCloning()
|
||||
->disallowMockingUnknownTypes()
|
||||
->disableAutoReturnValueGeneration();
|
||||
|
||||
if ($addMethods !== null) {
|
||||
$mockBuilder->addMethods($addMethods);
|
||||
}
|
||||
|
||||
if ($onlyMethods !== null) {
|
||||
$mockBuilder->onlyMethods($onlyMethods);
|
||||
}
|
||||
|
||||
return $mockBuilder->getMock();
|
||||
}
|
||||
}
|
|
@ -1,12 +1,12 @@
|
|||
<phpunit bootstrap="bootstrap.php" colors="true">
|
||||
<testsuites>
|
||||
<testsuite name="integration-app">
|
||||
<directory>Integration/app</directory>
|
||||
</testsuite>
|
||||
</testsuites>
|
||||
<filter>
|
||||
<whitelist>
|
||||
<directory suffix=".php">./../lib</directory>
|
||||
<directory suffix=".php">../lib</directory>
|
||||
</whitelist>
|
||||
</filter>
|
||||
<testsuites>
|
||||
<testsuite name="integration">
|
||||
<directory>./Integration</directory>
|
||||
</testsuite>
|
||||
</testsuites>
|
||||
</phpunit>
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<phpunit bootstrap="./bootstrap.php" colors="true">
|
||||
<phpunit bootstrap="bootstrap.php" colors="true">
|
||||
<filter>
|
||||
<whitelist>
|
||||
<directory suffix=".php">lib</directory>
|
||||
<directory suffix=".php">../lib</directory>
|
||||
</whitelist>
|
||||
</filter>
|
||||
<testsuites>
|
||||
|
|
Загрузка…
Ссылка в новой задаче