Skip to content

Commit

Permalink
feat: Allow listening to form submissions via events and webhooks
Browse files Browse the repository at this point in the history
requires Nextcloud 30

Signed-off-by: Marcel Klehr <mklehr@gmx.net>
  • Loading branch information
marcelklehr committed Sep 3, 2024
1 parent 3a85a74 commit eab4d7d
Show file tree
Hide file tree
Showing 5 changed files with 93 additions and 5 deletions.
2 changes: 1 addition & 1 deletion lib/Controller/ApiController.php
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
46 changes: 46 additions & 0 deletions lib/Events/AbstractFormEvent.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
<?php

namespace OCA\Forms\Events;

use OCA\Forms\Db\Form;
use OCP\EventDispatcher\Event;
use OCP\EventDispatcher\IWebhookCompatibleEvent;

if (interface_exists(\OCP\EventDispatcher\IWebhookCompatibleEvent::class)) {
abstract class AbstractFormEvent extends Event implements IWebhookCompatibleEvent {
public function __construct(
protected Form $form,
) {
parent::__construct();
}

public function getForm(): Form {
return $this->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();
}
}
}
23 changes: 23 additions & 0 deletions lib/Events/FormSubmittedEvent.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<?php

namespace OCA\Forms\Events;

use OCA\Forms\Db\Form;
use OCA\Forms\Db\Submission;
use OCP\EventDispatcher\IWebhookCompatibleEvent;

class FormSubmittedEvent extends AbstractFormEvent {
public function __construct(
Form $form,
private Submission $submission,
) {
parent::__construct($form);
}

public function getWebhookSerializable(): array {
return [
'form' => $this->form->read(),
'submission' => $this->submission->read(),
];
}
}
12 changes: 9 additions & 3 deletions lib/Service/FormsService.php
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -72,6 +75,7 @@ public function __construct(
private IRootFolder $storage,
private IL10N $l10n,
private IMimeTypeDetector $mimeTypeDetector,
private IEventDispatcher $eventDispatcher,
) {
$this->currentUser = $userSession->getUser();
}
Expand Down Expand Up @@ -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));
}

/**
Expand Down
15 changes: 14 additions & 1 deletion tests/Unit/Service/FormsServiceTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -182,6 +184,7 @@ public function setUp(): void {
$this->storage,
$this->l10n,
$this->mimeTypeDetector,
\OCP\Server::get(IEventDispatcher::class),
);
}

Expand Down Expand Up @@ -656,6 +659,7 @@ public function testGetPermissions_NotLoggedIn() {
$this->storage,
$this->l10n,
$this->mimeTypeDetector,
\OCP\Server::get(IEventDispatcher::class),
);

$form = new Form();
Expand Down Expand Up @@ -896,6 +900,7 @@ public function testPublicCanSubmit() {
$this->storage,
$this->l10n,
$this->mimeTypeDetector,
\OCP\Server::get(IEventDispatcher::class),
);

$this->assertEquals(true, $formsService->canSubmit($form));
Expand Down Expand Up @@ -1008,6 +1013,7 @@ public function testHasUserAccess_NotLoggedIn() {
$this->storage,
$this->l10n,
$this->mimeTypeDetector,
\OCP\Server::get(IEventDispatcher::class),
);

$form = new Form();
Expand Down Expand Up @@ -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([
Expand All @@ -1236,6 +1246,7 @@ public function testNotifyNewSubmission($shares, $shareNotifications) {
$this->storage,
$this->l10n,
$this->mimeTypeDetector,
$eventDispatcher,
])
->getMock();

Expand All @@ -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);
}

/**
Expand Down

0 comments on commit eab4d7d

Please sign in to comment.