From eab4d7de43d34644c53a9fbf0f6d25cb36b7bc4b Mon Sep 17 00:00:00 2001 From: Marcel Klehr Date: Tue, 6 Aug 2024 11:40:35 +0200 Subject: [PATCH] feat: Allow listening to form submissions via events and webhooks requires Nextcloud 30 Signed-off-by: Marcel Klehr --- lib/Controller/ApiController.php | 2 +- lib/Events/AbstractFormEvent.php | 46 +++++++++++++++++++++++++ lib/Events/FormSubmittedEvent.php | 23 +++++++++++++ lib/Service/FormsService.php | 12 +++++-- tests/Unit/Service/FormsServiceTest.php | 15 +++++++- 5 files changed, 93 insertions(+), 5 deletions(-) create mode 100644 lib/Events/AbstractFormEvent.php create mode 100644 lib/Events/FormSubmittedEvent.php diff --git a/lib/Controller/ApiController.php b/lib/Controller/ApiController.php index b8b8e2227a..dbe04dbcc3 100644 --- a/lib/Controller/ApiController.php +++ b/lib/Controller/ApiController.php @@ -1180,7 +1180,7 @@ public function insertSubmission(int $formId, array $answers, string $shareHash $this->formsService->setLastUpdatedTimestamp($formId); //Create Activity - $this->formsService->notifyNewSubmission($form, $submission->getUserId()); + $this->formsService->notifyNewSubmission($form, $submission); if ($form->getFileId() !== null) { try { diff --git a/lib/Events/AbstractFormEvent.php b/lib/Events/AbstractFormEvent.php new file mode 100644 index 0000000000..4e5529994a --- /dev/null +++ b/lib/Events/AbstractFormEvent.php @@ -0,0 +1,46 @@ +form; + } + + /** + * @inheritDoc + */ + public function getWebhookSerializable(): array { + return $this->form->read(); + } + } + +} else { + // need this block as long as NC < 30 is supported + abstract class AbstractFormEvent extends Event { + public function __construct( + protected Form $form, + ) { + parent::__construct(); + } + + public function getForm(): Form { + return $this->form; + } + + public function getWebhookSerializable(): array { + return $this->form->read(); + } + } +} diff --git a/lib/Events/FormSubmittedEvent.php b/lib/Events/FormSubmittedEvent.php new file mode 100644 index 0000000000..be01f4d010 --- /dev/null +++ b/lib/Events/FormSubmittedEvent.php @@ -0,0 +1,23 @@ + $this->form->read(), + 'submission' => $this->submission->read(), + ]; + } +} diff --git a/lib/Service/FormsService.php b/lib/Service/FormsService.php index 2186db9676..04d803d194 100644 --- a/lib/Service/FormsService.php +++ b/lib/Service/FormsService.php @@ -33,9 +33,12 @@ use OCA\Forms\Db\QuestionMapper; use OCA\Forms\Db\Share; use OCA\Forms\Db\ShareMapper; +use OCA\Forms\Db\Submission; use OCA\Forms\Db\SubmissionMapper; +use OCA\Forms\Events\FormSubmittedEvent; use OCP\AppFramework\Db\DoesNotExistException; use OCP\AppFramework\Db\IMapperException; +use OCP\EventDispatcher\IEventDispatcher; use OCP\Files\IMimeTypeDetector; use OCP\Files\IRootFolder; use OCP\Files\NotFoundException; @@ -72,6 +75,7 @@ public function __construct( private IRootFolder $storage, private IL10N $l10n, private IMimeTypeDetector $mimeTypeDetector, + private IEventDispatcher $eventDispatcher, ) { $this->currentUser = $userSession->getUser(); } @@ -529,17 +533,19 @@ public function notifyNewShares(Form $form, Share $share): void { * @param Form $form Related Form * @param string $submitter The ID of the user who submitted the form. Can also be our 'anon-user-'-ID */ - public function notifyNewSubmission(Form $form, string $submitter): void { + public function notifyNewSubmission(Form $form, Submission $submission): void { $shares = $this->getShares($form->getId()); - $this->activityManager->publishNewSubmission($form, $submitter); + $this->activityManager->publishNewSubmission($form, $submission->getUserId()); foreach ($shares as $share) { if (!in_array(Constants::PERMISSION_RESULTS, $share['permissions'])) { continue; } - $this->activityManager->publishNewSharedSubmission($form, $share['shareType'], $share['shareWith'], $submitter); + $this->activityManager->publishNewSharedSubmission($form, $share['shareType'], $share['shareWith'], $submission->getUserId()); } + + $this->eventDispatcher->dispatchTyped(new FormSubmittedEvent($form, $submission)); } /** diff --git a/tests/Unit/Service/FormsServiceTest.php b/tests/Unit/Service/FormsServiceTest.php index a2697fcd88..3ac88e9420 100644 --- a/tests/Unit/Service/FormsServiceTest.php +++ b/tests/Unit/Service/FormsServiceTest.php @@ -57,11 +57,13 @@ function microtime(bool|float $asFloat = false) { use OCA\Forms\Db\QuestionMapper; use OCA\Forms\Db\Share; use OCA\Forms\Db\ShareMapper; +use OCA\Forms\Db\Submission; use OCA\Forms\Db\SubmissionMapper; use OCA\Forms\Service\CirclesService; use OCA\Forms\Service\ConfigService; use OCA\Forms\Service\FormsService; use OCP\AppFramework\Db\DoesNotExistException; +use OCP\EventDispatcher\IEventDispatcher; use OCP\Files\Folder; use OCP\Files\IMimeTypeDetector; use OCP\Files\IRootFolder; @@ -182,6 +184,7 @@ public function setUp(): void { $this->storage, $this->l10n, $this->mimeTypeDetector, + \OCP\Server::get(IEventDispatcher::class), ); } @@ -656,6 +659,7 @@ public function testGetPermissions_NotLoggedIn() { $this->storage, $this->l10n, $this->mimeTypeDetector, + \OCP\Server::get(IEventDispatcher::class), ); $form = new Form(); @@ -896,6 +900,7 @@ public function testPublicCanSubmit() { $this->storage, $this->l10n, $this->mimeTypeDetector, + \OCP\Server::get(IEventDispatcher::class), ); $this->assertEquals(true, $formsService->canSubmit($form)); @@ -1008,6 +1013,7 @@ public function testHasUserAccess_NotLoggedIn() { $this->storage, $this->l10n, $this->mimeTypeDetector, + \OCP\Server::get(IEventDispatcher::class), ); $form = new Form(); @@ -1213,10 +1219,14 @@ public function dataNotifyNewSubmission() { public function testNotifyNewSubmission($shares, $shareNotifications) { $owner = 'ownerUser'; $submitter = 'someUser'; + $submission = $this->getMockBuilder(Submission::class)->getMock(); + $submission->method('getUserId')->willReturn($submitter); $userSession = $this->createMock(IUserSession::class); $userSession->method('getUser')->willReturn(null); + $eventDispatcher = $this->createMock(IEventDispatcher::class); + $formsService = $this->getMockBuilder(FormsService::class) ->onlyMethods(['getShares']) ->setConstructorArgs([ @@ -1236,6 +1246,7 @@ public function testNotifyNewSubmission($shares, $shareNotifications) { $this->storage, $this->l10n, $this->mimeTypeDetector, + $eventDispatcher, ]) ->getMock(); @@ -1250,7 +1261,9 @@ public function testNotifyNewSubmission($shares, $shareNotifications) { $this->activityManager->expects($this->exactly($shareNotifications)) ->method('publishNewSharedSubmission'); - $formsService->notifyNewSubmission($form, $submitter); + $eventDispatcher->expects($this->exactly(1))->method('dispatchTyped')->withAnyParameters(); + + $formsService->notifyNewSubmission($form, $submission); } /**