diff --git a/appinfo/info.xml b/appinfo/info.xml
index c5a69243a..8826b338b 100644
--- a/appinfo/info.xml
+++ b/appinfo/info.xml
@@ -39,6 +39,7 @@
OCA\Polls\Command\Share\Add
OCA\Polls\Command\Share\Remove
OCA\Polls\Command\Db\Rebuild
+ OCA\Polls\Command\Poll\TransferOwnership
OCA\Polls\Settings\AdminSection
diff --git a/appinfo/routes.php b/appinfo/routes.php
index b620c85e7..0d43de069 100644
--- a/appinfo/routes.php
+++ b/appinfo/routes.php
@@ -67,6 +67,8 @@ return [
['name' => 'poll#clone', 'url' => '/poll/{pollId}/clone', 'verb' => 'GET'],
['name' => 'poll#getParticipantsEmailAddresses', 'url' => '/poll/{pollId}/addresses', 'verb' => 'GET'],
+ ['name' => 'poll#transfer_polls', 'url' => '/polls/transfer/{sourceUser}/{destinationUser}', 'verb' => 'PUT'],
+
['name' => 'option#list', 'url' => '/poll/{pollId}/options', 'verb' => 'GET'],
['name' => 'option#add', 'url' => '/option', 'verb' => 'POST'],
['name' => 'option#addBulk', 'url' => '/option/bulk', 'verb' => 'POST'],
@@ -118,6 +120,7 @@ return [
// REST-API calls
['name' => 'poll_api#list', 'url' => '/api/v1.0/polls', 'verb' => 'GET'],
+ ['name' => 'poll_api#transfer_polls', 'url' => '/api/v1.0/polls/transfer/{sourceUser}/{destinationUser}', 'verb' => 'PUT'],
['name' => 'poll_api#add', 'url' => '/api/v1.0/poll', 'verb' => 'POST'],
['name' => 'poll_api#get', 'url' => '/api/v1.0/poll/{pollId}', 'verb' => 'GET'],
['name' => 'poll_api#update', 'url' => '/api/v1.0/poll/{pollId}', 'verb' => 'PUT'],
diff --git a/lib/AppInfo/Application.php b/lib/AppInfo/Application.php
index 0c6840024..73aff0ad2 100644
--- a/lib/AppInfo/Application.php
+++ b/lib/AppInfo/Application.php
@@ -47,6 +47,7 @@ use OCA\Polls\Event\PollArchivedEvent;
use OCA\Polls\Event\PollCreatedEvent;
use OCA\Polls\Event\PollDeletedEvent;
use OCA\Polls\Event\PollExpiredEvent;
+use OCA\Polls\Event\PollOwnerChangeEvent;
use OCA\Polls\Event\PollRestoredEvent;
use OCA\Polls\Event\PollTakeoverEvent;
use OCA\Polls\Event\PollUpdatedEvent;
@@ -98,6 +99,7 @@ class Application extends App implements IBootstrap {
$context->registerEventListener(PollDeletedEvent::class, PollListener::class);
$context->registerEventListener(PollExpiredEvent::class, PollListener::class);
$context->registerEventListener(PollRestoredEvent::class, PollListener::class);
+ $context->registerEventListener(PollOwnerChangeEvent::class, PollListener::class);
$context->registerEventListener(PollTakeoverEvent::class, PollListener::class);
$context->registerEventListener(PollUpdatedEvent::class, PollListener::class);
$context->registerEventListener(ShareChangedEmailEvent::class, ShareListener::class);
diff --git a/lib/Command/Poll/TransferOwnership.php b/lib/Command/Poll/TransferOwnership.php
new file mode 100644
index 000000000..93de1449f
--- /dev/null
+++ b/lib/Command/Poll/TransferOwnership.php
@@ -0,0 +1,110 @@
+
+ *
+ * @author René Gieling
+ *
+ * @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\Polls\Command\Poll;
+
+use OCA\Polls\Service\PollService;
+use OCP\IUser;
+use OCP\IUserManager;
+use Symfony\Component\Console\Command\Command;
+use Symfony\Component\Console\Input\InputArgument;
+use Symfony\Component\Console\Input\InputInterface;
+use Symfony\Component\Console\Output\OutputInterface;
+use Symfony\Component\Console\Question\ConfirmationQuestion;
+
+class TransferOwnership extends Command {
+ /** @var PollService */
+ private $pollService;
+
+ /** @var IUserManager */
+ private $userManager;
+
+ public function __construct(
+ IUserManager $userManager,
+ PollService $pollService
+ ) {
+ parent::__construct();
+ $this->pollService = $pollService;
+ $this->userManager = $userManager;
+ }
+
+ protected function configure(): void {
+ $this
+ ->setName('polls:poll:transfer-ownership')
+ ->setDescription('Transfer the ownership of one user\'s polls to another user.')
+ ->addArgument(
+ 'source-user',
+ InputArgument::REQUIRED,
+ 'User id to transfer the polls from'
+ )
+ ->addArgument(
+ 'target-user',
+ InputArgument::REQUIRED,
+ 'User id to transfer the polls to'
+ );
+ }
+
+ protected function execute(InputInterface $input, OutputInterface $output): int {
+ if ($this->requestConfirmation($input, $output)) {
+ return 1;
+ }
+
+ if (!$this->userManager->get($input->getArgument('target-user')) instanceof IUser) {
+ $output->writeln(' Unknown destination user ' . $input->getArgument('target-user') . '');
+ return 1;
+ }
+
+ $transferredPolls = $this->pollService->transferPolls($input->getArgument('source-user'), $input->getArgument('target-user'));
+
+ if (sizeof($transferredPolls) < 1) {
+ $output->writeln('No polls were transferred from ' . $input->getArgument('source-user') . '');
+
+ } else if (sizeof($transferredPolls) === 1) {
+ $output->writeln('One poll was transferred from ' . $input->getArgument('source-user') . ' to ' . $input->getArgument('target-user') . '');
+ $output->writeln(' * ' . $transferredPolls[0]->getId() . ' - ' . $transferredPolls[0]->getTitle() . '');
+
+ } else {
+ $output->writeln('' . sizeof($transferredPolls) . ' polls were transferred from ' . $input->getArgument('source-user') . ' to ' . $input->getArgument('target-user') . '');
+ foreach ($transferredPolls as $poll) {
+ $output->writeln(' * ' . $poll->getId() . ' - ' . $poll->getTitle() . '');
+ }
+ }
+
+ return 0;
+ }
+
+ private function requestConfirmation(InputInterface $input, OutputInterface $output): int {
+ if ($input->isInteractive()) {
+ $helper = $this->getHelper('question');
+ $output->writeln('This command will change the ownership of all polls of ' . $input->getArgument('source-user') . ' to ' . $input->getArgument('target-user') . '.');
+ $output->writeln('NO notifications will be sent to the users.');
+ $output->writeln('');
+
+ $question = new ConfirmationQuestion('Continue with the transfer (y/n)? [n] ', false);
+ if (!$helper->ask($input, $output, $question)) {
+ return 1;
+ }
+ }
+ return 0;
+ }
+}
diff --git a/lib/Controller/PollApiController.php b/lib/Controller/PollApiController.php
index b9d7afe54..9bd5f810d 100644
--- a/lib/Controller/PollApiController.php
+++ b/lib/Controller/PollApiController.php
@@ -168,6 +168,19 @@ class PollApiController extends ApiController {
}
}
+ /**
+ * Clone poll
+ * @CORS
+ * @NoCSRFRequired
+ */
+ public function transferPolls(string $sourceUser, string $targetUser): JSONResponse {
+ try {
+ return new JSONResponse(['transferred' => $this->pollService->transferPolls($sourceUser, $targetUser)], Http::STATUS_CREATED);
+ } catch (Exception $e) {
+ return new JSONResponse(['message' => $e->getMessage()], $e->getStatus());
+ }
+ }
+
/**
* Collect email addresses from particitipants
* @NoAdminRequired
diff --git a/lib/Controller/PollController.php b/lib/Controller/PollController.php
index 8ccd20afb..16c75a3c1 100644
--- a/lib/Controller/PollController.php
+++ b/lib/Controller/PollController.php
@@ -138,6 +138,13 @@ class PollController extends Controller {
return $this->get($pollId);
}
+ /**
+ * Transfer polls between users
+ */
+ public function transferPolls(string $sourceUser, string $targetUser): JSONResponse {
+ return $this->response(fn () => $this->pollService->transferPolls($sourceUser, $targetUser));
+ }
+
/**
* Collect email addresses from particitipants
* @NoAdminRequired
diff --git a/lib/Db/PollMapper.php b/lib/Db/PollMapper.php
index 4e9de1852..ff2c4ba26 100644
--- a/lib/Db/PollMapper.php
+++ b/lib/Db/PollMapper.php
@@ -94,6 +94,18 @@ class PollMapper extends QBMapper {
return $this->findEntities($qb);
}
+ /**
+ * @throws \OCP\AppFramework\Db\DoesNotExistException if not found
+ * @return Poll[]
+ */
+ public function findOwner(string $userId): array {
+ $qb = $this->db->getQueryBuilder();
+ $qb->select('*')
+ ->from($this->getTableName())
+ ->where($qb->expr()->eq('owner', $qb->createNamedParameter($userId, IQueryBuilder::PARAM_STR)));
+ return $this->findEntities($qb);
+ }
+
/**
* @throws \OCP\AppFramework\Db\DoesNotExistException if not found
* @return Poll[]
diff --git a/lib/Event/PollOwnerChangeEvent.php b/lib/Event/PollOwnerChangeEvent.php
new file mode 100644
index 000000000..01905f507
--- /dev/null
+++ b/lib/Event/PollOwnerChangeEvent.php
@@ -0,0 +1,35 @@
+
+ *
+ * @author René Gieling
+ *
+ * @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\Polls\Event;
+
+use OCA\Polls\Db\Poll;
+
+class PollOwnerChangeEvent extends PollEvent {
+ public function __construct(
+ Poll $poll
+ ) {
+ parent::__construct($poll);
+ $this->activitySubject = self::OWNER_CHANGE;
+ }
+}
diff --git a/lib/Event/PollTakeoverEvent.php b/lib/Event/PollTakeoverEvent.php
index 23b945f50..819b5741d 100644
--- a/lib/Event/PollTakeoverEvent.php
+++ b/lib/Event/PollTakeoverEvent.php
@@ -26,12 +26,11 @@ namespace OCA\Polls\Event;
use OCA\Polls\Notification\Notifier;
use OCA\Polls\Db\Poll;
-class PollTakeoverEvent extends PollEvent {
+class PollTakeoverEvent extends PollOwnerChangeEvent {
public function __construct(
Poll $poll
) {
parent::__construct($poll);
- $this->activitySubject = self::OWNER_CHANGE;
}
public function getNotification(): array {
diff --git a/lib/Listener/BaseListener.php b/lib/Listener/BaseListener.php
index 915277f6e..5e2e20d1a 100644
--- a/lib/Listener/BaseListener.php
+++ b/lib/Listener/BaseListener.php
@@ -80,6 +80,7 @@ abstract class BaseListener implements IEventListener {
public function handle(Event $event) : void {
$this->event = $event;
+
try {
$this->checkClass();
$this->addLog();
@@ -111,7 +112,6 @@ abstract class BaseListener implements IEventListener {
throw $e;
}
}
-
// add a cron job, if necessary (i.e. for removed users and groups)
$this->addCronJob();
diff --git a/lib/Service/PollService.php b/lib/Service/PollService.php
index ce54116e0..662102346 100644
--- a/lib/Service/PollService.php
+++ b/lib/Service/PollService.php
@@ -41,11 +41,15 @@ use OCA\Polls\Db\Vote;
use OCA\Polls\Event\PollArchivedEvent;
use OCA\Polls\Event\PollCreatedEvent;
use OCA\Polls\Event\PollDeletedEvent;
+use OCA\Polls\Event\PollOwnerChangeEvent;
use OCA\Polls\Event\PollRestoredEvent;
use OCA\Polls\Event\PollTakeoverEvent;
use OCA\Polls\Event\PollUpdatedEvent;
+use OCA\Polls\Exceptions\InvalidUsernameException;
use OCA\Polls\Model\Acl;
use OCA\Polls\Model\Settings\AppSettings;
+use OCP\IUser;
+use OCP\IUserManager;
class PollService {
@@ -54,6 +58,9 @@ class PollService {
/** @var IEventDispatcher */
private $eventDispatcher;
+
+ /** @var IUserManager */
+ private $userManager;
/** @var IUserSession */
private $userSession;
@@ -87,6 +94,7 @@ class PollService {
AppSettings $appSettings,
IEventDispatcher $eventDispatcher,
IGroupManager $groupManager,
+ IUserManager $userManager,
IUserSession $userSession,
MailService $mailService,
Poll $poll,
@@ -103,6 +111,7 @@ class PollService {
$this->poll = $poll;
$this->pollMapper = $pollMapper;
$this->userId = $UserId;
+ $this->userManager = $userManager;
$this->userSession = $userSession;
$this->voteMapper = $voteMapper;
$this->vote = $vote;
@@ -191,6 +200,20 @@ class PollService {
return $this->poll;
}
+ public function transferPolls(string $sourceUser, string $targetUser) {
+ if ($this->userManager->get($targetUser) instanceof IUser) {
+ $pollsToTransfer = $this->pollMapper->findOwner($sourceUser);
+ foreach ($pollsToTransfer as $poll) {
+ $poll->setOwner($targetUser);
+ $this->pollMapper->update($poll);
+ $this->eventDispatcher->dispatchTyped(new PollOwnerChangeEvent($poll));
+ }
+ return $pollsToTransfer;
+ }
+ throw new InvalidUsernameException('The user id "' . $targetUser . '" is not valid.');
+ }
+
+
/**
* get poll configuration
*/