Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 12 additions & 8 deletions lib/Service/RequestSignatureService.php
Original file line number Diff line number Diff line change
Expand Up @@ -612,13 +612,15 @@ public function validateSigners(array $data): void {
}
}

public function unassociateToUser(int $fileId, int $signRequestId): void {
public function unassociateToUser(int $fileId, int $signRequestId, bool $notify = true): void {
$file = $this->fileMapper->getById($fileId);
$signRequest = $this->signRequestMapper->getByFileIdAndSignRequestId($fileId, $signRequestId);
$deletedOrder = $signRequest->getSigningOrder();
$groupedIdentifyMethods = $this->identifyMethod->getIdentifyMethodsFromSignRequestId($signRequestId);

$this->dispatchCancellationEventIfNeeded($signRequest, $file, $groupedIdentifyMethods);
if ($notify) {
$this->dispatchCancellationEventIfNeeded($signRequest, $file, $groupedIdentifyMethods);
}

try {
$this->signRequestMapper->delete($signRequest);
Expand All @@ -632,7 +634,7 @@ public function unassociateToUser(int $fileId, int $signRequestId): void {
->setFile($file)
->reorderAfterDeletion($file->getId(), $deletedOrder);

$this->propagateSignerDeletionToChildren($file, $signRequest);
$this->propagateSignerDeletionToChildren($file, $groupedIdentifyMethods);
Comment thread
YvesCesar marked this conversation as resolved.
$this->revertStatusToDraftIfNoSignersRemain($file);
} catch (\Throwable) {
}
Expand All @@ -647,18 +649,20 @@ private function revertStatusToDraftIfNoSignersRemain(FileEntity $file): void {
}
}

private function propagateSignerDeletionToChildren(FileEntity $envelope, SignRequestEntity $deletedSignRequest): void {
/**
* @param array<string, array<IIdentifyMethod>> $identifyMethods
*/
private function propagateSignerDeletionToChildren(FileEntity $envelope, array $identifyMethods): void {
Comment thread
YvesCesar marked this conversation as resolved.
if ($envelope->getNodeType() !== 'envelope') {
return;
}

$children = $this->fileMapper->getChildrenFiles($envelope->getId());

$identifyMethods = $this->identifyMethod->getIdentifyMethodsFromSignRequestId($deletedSignRequest->getId());
if (empty($identifyMethods)) {
return;
}

$children = $this->fileMapper->getChildrenFiles($envelope->getId());

foreach ($children as $child) {
try {
$this->identifyMethod->clearCache();
Expand All @@ -668,7 +672,7 @@ private function propagateSignerDeletionToChildren(FileEntity $envelope, SignReq
);

if ($childSignRequest->getId()) {
$this->unassociateToUser($child->getId(), $childSignRequest->getId());
$this->unassociateToUser($child->getId(), $childSignRequest->getId(), notify: false);
}
} catch (\Throwable) {
continue;
Expand Down
177 changes: 177 additions & 0 deletions tests/integration/features/sign/cancel.feature
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,14 @@ Feature: sign-request-cancel
And sending "get" to ocs "/apps/libresign/api/v1/file/list?details=1"
And fetch field "(FILE_ID)ocs.data.data.0.id" from previous JSON response
And fetch field "(SIGN_REQUEST_ID)ocs.data.data.0.signers.0.signRequestId" from previous JSON response
And reset notifications of user "signer1"
When sending "delete" to ocs "/apps/libresign/api/v1/sign/file_id/<FILE_ID>/<SIGN_REQUEST_ID>"
Then the response should have a status code 200
When as user "signer1"
And sending "get" to ocs "/apps/notifications/api/v2/notifications"
Then the response should be a JSON array with the following mandatory values
| key | value |
| (jq).ocs.data \| length | 1 |
| (jq).ocs.data[0].subject | admin canceled the signature request for document |

Scenario: Delete draft request does not send cancellation notification
Expand Down Expand Up @@ -79,3 +81,178 @@ Feature: sign-request-cancel
Then the response should be a JSON array with the following mandatory values
| key | value |
| (jq).ocs.data.data[0].status | 0 |

Scenario: Delete envelope signer removes only that signer from both documents
Given as user "admin"
And user "signer1" exists
And user "signer2" exists
And run the command "libresign:configure:openssl --cn test" with result code 0
And sending "post" to ocs "/apps/libresign/api/v1/request-signature"
| files | [{"base64":"<SMALL_VALID_PDF_BASE64>","name":"First.pdf"},{"base64":"<SMALL_VALID_PDF_BASE64>","name":"Second.pdf"}] |
| signers | [{"identifyMethods":[{"method":"account","value":"signer1"}]},{"identifyMethods":[{"method":"account","value":"signer2"}]}] |
| name | Envelope cancellation |
| status | 0 |
And the response should have a status code 200
And fetch field "(ENVELOPE_UUID)ocs.data.uuid" from previous JSON response
And sending "patch" to ocs "/apps/libresign/api/v1/request-signature"
| uuid | <ENVELOPE_UUID> |
| signers | [{"identifyMethods":[{"method":"account","value":"signer1"}]},{"identifyMethods":[{"method":"account","value":"signer2"}]}] |
| status | 1 |
And the response should have a status code 200
And sending "get" to ocs "/apps/libresign/api/v1/file/validate/uuid/<ENVELOPE_UUID>"
And the response should have a status code 200
And the response should be a JSON array with the following mandatory values
| key | value |
| (jq).ocs.data.nodeType | envelope |
| (jq).ocs.data.files \| length | 2 |
| (jq)[.ocs.data, .ocs.data.files[]] \| map(.status) | [1,1,1] |
| (jq)[.ocs.data, .ocs.data.files[]] \| map([.signers[].identifyMethods[] \| select(.method == "account").value] \| sort) | [["signer1","signer2"],["signer1","signer2"],["signer1","signer2"]] |
And fetch field "(ENVELOPE_ID)ocs.data.id" from previous JSON response
And fetch field '(SIGN_REQUEST_ID)(jq).ocs.data.signers[] | select(any(.identifyMethods[]; .method == "account" and .value == "signer1")) | .signRequestId' from previous JSON response
And fetch field "(FIRST_UUID)ocs.data.files.0.uuid" from previous JSON response
And fetch field "(SECOND_UUID)ocs.data.files.1.uuid" from previous JSON response
And reset notifications of user "signer1"
And reset activity of user "signer1"
And set the email of user "signer1" to "signer1@domain.test"
And activity preference "notify_email_libresign_sign_request_canceled" for user "signer1" is set to "1"
And my inbox is empty
When sending "delete" to ocs "/apps/libresign/api/v1/sign/file_id/<ENVELOPE_ID>/<SIGN_REQUEST_ID>"
Then the response should have a status code 200
When sending "get" to ocs "/apps/libresign/api/v1/file/validate/uuid/<ENVELOPE_UUID>"
Then the response should have a status code 200
And the response should be a JSON array with the following mandatory values
| key | value |
| (jq).ocs.data.files \| length | 2 |
| (jq)[.ocs.data, .ocs.data.files[]] \| map(.status) | [1,1,1] |
| (jq)[.ocs.data, .ocs.data.files[]] \| map(.signers \| length) | [1,1,1] |
| (jq)[.ocs.data, .ocs.data.files[]] \| map([.signers[].identifyMethods[] \| select(.method == "account").value]) | [["signer2"],["signer2"],["signer2"]] |
When sending "get" to ocs "/apps/libresign/api/v1/file/validate/uuid/<FIRST_UUID>"
Then the response should have a status code 200
And the response should be a JSON array with the following mandatory values
| key | value |
| (jq).ocs.data.signers \| length | 1 |
| (jq)[.ocs.data.signers[].identifyMethods[] \| select(.method == "account").value] | ["signer2"] |
When sending "get" to ocs "/apps/libresign/api/v1/file/validate/uuid/<SECOND_UUID>"
Then the response should have a status code 200
And the response should be a JSON array with the following mandatory values
| key | value |
| (jq).ocs.data.signers \| length | 1 |
| (jq)[.ocs.data.signers[].identifyMethods[] \| select(.method == "account").value] | ["signer2"] |
When as user "signer1"
And sending "get" to ocs "/apps/notifications/api/v2/notifications"
Then the response should be a JSON array with the following mandatory values
| key | value |
| (jq).ocs.data \| length | 1 |
| (jq).ocs.data[0].subject | admin canceled the signature request for Envelope cancellation |
And there should be 1 emails in my inbox
When sending "get" to ocs "/apps/activity/api/v2/activity/libresign?since=0"
Then the response should have a status code 200
And the response should be a JSON array with the following mandatory values
| key | value |
| (jq).ocs.data \| length | 1 |

Scenario: Delete last envelope signer reverts both documents to draft without orphan requests
Given as user "admin"
And user "signer1" exists
And run the command "libresign:configure:openssl --cn test" with result code 0
And sending "post" to ocs "/apps/libresign/api/v1/request-signature"
| files | [{"base64":"<SMALL_VALID_PDF_BASE64>","name":"First.pdf"},{"base64":"<SMALL_VALID_PDF_BASE64>","name":"Second.pdf"}] |
| signers | [{"identifyMethods":[{"method":"account","value":"signer1"}]}] |
| name | Last envelope signer |
| status | 0 |
And the response should have a status code 200
And fetch field "(ENVELOPE_UUID)ocs.data.uuid" from previous JSON response
And sending "patch" to ocs "/apps/libresign/api/v1/request-signature"
| uuid | <ENVELOPE_UUID> |
| signers | [{"identifyMethods":[{"method":"account","value":"signer1"}]}] |
| status | 1 |
And the response should have a status code 200
And sending "get" to ocs "/apps/libresign/api/v1/file/validate/uuid/<ENVELOPE_UUID>"
And the response should have a status code 200
And the response should be a JSON array with the following mandatory values
| key | value |
| (jq).ocs.data.nodeType | envelope |
| (jq).ocs.data.files \| length | 2 |
| (jq)[.ocs.data, .ocs.data.files[]] \| map(.status) | [1,1,1] |
| (jq)[.ocs.data, .ocs.data.files[]] \| map([.signers[].identifyMethods[] \| select(.method == "account").value]) | [["signer1"],["signer1"],["signer1"]] |
And fetch field "(ENVELOPE_ID)ocs.data.id" from previous JSON response
And fetch field '(SIGN_REQUEST_ID)(jq).ocs.data.signers[] | select(any(.identifyMethods[]; .method == "account" and .value == "signer1")) | .signRequestId' from previous JSON response
And fetch field "(FIRST_UUID)ocs.data.files.0.uuid" from previous JSON response
And fetch field "(SECOND_UUID)ocs.data.files.1.uuid" from previous JSON response
And reset notifications of user "signer1"
And reset activity of user "signer1"
And set the email of user "signer1" to "signer1@domain.test"
And activity preference "notify_email_libresign_sign_request_canceled" for user "signer1" is set to "1"
And my inbox is empty
When sending "delete" to ocs "/apps/libresign/api/v1/sign/file_id/<ENVELOPE_ID>/<SIGN_REQUEST_ID>"
Then the response should have a status code 200
When sending "get" to ocs "/apps/libresign/api/v1/file/validate/uuid/<ENVELOPE_UUID>"
Then the response should have a status code 200
And the response should be a JSON array with the following mandatory values
| key | value |
| (jq).ocs.data.files \| length | 2 |
| (jq)[.ocs.data, .ocs.data.files[]] \| map(.signers) | [[],[],[]] |
| (jq)[.ocs.data, .ocs.data.files[]] \| map(.status) | [0,0,0] |
When sending "get" to ocs "/apps/libresign/api/v1/file/validate/uuid/<FIRST_UUID>"
Then the response should have a status code 200
And the response should be a JSON array with the following mandatory values
| key | value |
| (jq).ocs.data.signers | [] |
| (jq).ocs.data.status | 0 |
When sending "get" to ocs "/apps/libresign/api/v1/file/validate/uuid/<SECOND_UUID>"
Then the response should have a status code 200
And the response should be a JSON array with the following mandatory values
| key | value |
| (jq).ocs.data.signers | [] |
| (jq).ocs.data.status | 0 |
When as user "signer1"
And sending "get" to ocs "/apps/notifications/api/v2/notifications"
Then the response should be a JSON array with the following mandatory values
| key | value |
| (jq).ocs.data \| length | 1 |
| (jq).ocs.data[0].subject | admin canceled the signature request for Last envelope signer |
And there should be 1 emails in my inbox
When sending "get" to ocs "/apps/activity/api/v2/activity/libresign?since=0"
Then the response should have a status code 200
And the response should be a JSON array with the following mandatory values
| key | value |
| (jq).ocs.data \| length | 1 |

Scenario: Directly deleting a child signer still sends its cancellation notification
Given as user "admin"
And user "signer1" exists
And run the command "libresign:configure:openssl --cn test" with result code 0
And sending "post" to ocs "/apps/libresign/api/v1/request-signature"
| files | [{"base64":"<SMALL_VALID_PDF_BASE64>","name":"First.pdf"},{"base64":"<SMALL_VALID_PDF_BASE64>","name":"Second.pdf"}] |
| signers | [{"identifyMethods":[{"method":"account","value":"signer1"}]}] |
| name | Direct child cancellation |
| status | 0 |
And the response should have a status code 200
And fetch field "(ENVELOPE_UUID)ocs.data.uuid" from previous JSON response
And sending "patch" to ocs "/apps/libresign/api/v1/request-signature"
| uuid | <ENVELOPE_UUID> |
| signers | [{"identifyMethods":[{"method":"account","value":"signer1"}]}] |
| status | 1 |
And the response should have a status code 200
And sending "get" to ocs "/apps/libresign/api/v1/file/validate/uuid/<ENVELOPE_UUID>"
And the response should have a status code 200
And the response should be a JSON array with the following mandatory values
| key | value |
| (jq)[.ocs.data, .ocs.data.files[]] \| map(.status) | [1,1,1] |
And fetch field "(CHILD_ID)ocs.data.files.0.id" from previous JSON response
And fetch field '(SIGN_REQUEST_ID)(jq).ocs.data.files[0].signers[] | select(any(.identifyMethods[]; .method == "account" and .value == "signer1")) | .signRequestId' from previous JSON response
And reset notifications of user "signer1"
When sending "delete" to ocs "/apps/libresign/api/v1/sign/file_id/<CHILD_ID>/<SIGN_REQUEST_ID>"
Then the response should have a status code 200
When sending "get" to ocs "/apps/libresign/api/v1/file/validate/uuid/<ENVELOPE_UUID>"
Then the response should have a status code 200
And the response should be a JSON array with the following mandatory values
| key | value |
| (jq)[.ocs.data, .ocs.data.files[]] \| map(.signers \| length) | [1,0,1] |
| (jq)[.ocs.data, .ocs.data.files[]] \| map(.status) | [1,0,1] |
When as user "signer1"
And sending "get" to ocs "/apps/notifications/api/v2/notifications"
Then the response should be a JSON array with the following mandatory values
| key | value |
| (jq).ocs.data \| length | 1 |
| (jq).ocs.data[0].subject | admin canceled the signature request for First |
Loading