Skip to content

Commit

Permalink
Merge pull request #2657 from LibreSign/feat/implement-sign-tab
Browse files Browse the repository at this point in the history
feat: implement sign tab at right sidebar
  • Loading branch information
vitormattos authored Apr 11, 2024
2 parents 7d08d35 + 30671e8 commit da9a30f
Show file tree
Hide file tree
Showing 46 changed files with 898 additions and 752 deletions.
8 changes: 4 additions & 4 deletions appinfo/routes/routesAccountController.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,9 @@
['name' => 'account#accountFileListToApproval', 'url' => '/api/{apiVersion}/account/files/approval/list', 'verb' => 'GET', 'requirements' => $requirements],
['name' => 'account#createSignatureElement', 'url' => '/api/{apiVersion}/account/signature/elements', 'verb' => 'POST', 'requirements' => $requirements],
['name' => 'account#getSignatureElements', 'url' => '/api/{apiVersion}/account/signature/elements', 'verb' => 'GET', 'requirements' => $requirements],
['name' => 'account#getSignatureElementPreview','url' => '/api/{apiVersion}/account/signature/elements/preview/{fileId}', 'verb' => 'GET', 'requirements' => $requirements],
['name' => 'account#getSignatureElement', 'url' => '/api/{apiVersion}/account/signature/elements/{elementId}', 'verb' => 'GET', 'requirements' => $requirements],
['name' => 'account#patchSignatureElement', 'url' => '/api/{apiVersion}/account/signature/elements/{elementId}', 'verb' => 'PATCH', 'requirements' => $requirements],
['name' => 'account#deleteSignatureElement', 'url' => '/api/{apiVersion}/account/signature/elements/{elementId}', 'verb' => 'DELETE', 'requirements' => $requirements],
['name' => 'account#getSignatureElementPreview','url' => '/api/{apiVersion}/account/signature/elements/preview/{nodeId}', 'verb' => 'GET', 'requirements' => $requirements],
['name' => 'account#getSignatureElement', 'url' => '/api/{apiVersion}/account/signature/elements/{nodeId}', 'verb' => 'GET', 'requirements' => $requirements],
['name' => 'account#patchSignatureElement', 'url' => '/api/{apiVersion}/account/signature/elements/{nodeId}', 'verb' => 'PATCH', 'requirements' => $requirements],
['name' => 'account#deleteSignatureElement', 'url' => '/api/{apiVersion}/account/signature/elements/{nodeId}', 'verb' => 'DELETE', 'requirements' => $requirements],
],
];
Binary file removed img/application-pdf.png
Binary file not shown.
Binary file removed img/frame4.png
Binary file not shown.
22 changes: 13 additions & 9 deletions lib/Controller/AccountController.php
Original file line number Diff line number Diff line change
Expand Up @@ -324,10 +324,10 @@ public function getSignatureElements(): JSONResponse {
#[NoAdminRequired]
#[PublicPage]
#[NoCSRFRequired]
public function getSignatureElementPreview(int $fileId) {
public function getSignatureElementPreview(int $nodeId) {
try {
$node = $this->accountService->getFileByNodeIdAndSessionId(
$fileId,
$nodeId,
$this->sessionService->getSessionId()
);
} catch (DoesNotExistException $th) {
Expand All @@ -346,11 +346,11 @@ public function getSignatureElementPreview(int $fileId) {

#[NoAdminRequired]
#[NoCSRFRequired]
public function getSignatureElement(int $elementId): JSONResponse {
public function getSignatureElement(int $nodeId): JSONResponse {
$userId = $this->userSession->getUser()->getUID();
try {
return new JSONResponse(
$this->signerElementsService->getUserElementByElementId($userId, $elementId),
$this->signerElementsService->getUserElementByNodeId($userId, $nodeId),
Http::STATUS_OK
);
} catch (\Throwable $th) {
Expand All @@ -365,9 +365,9 @@ public function getSignatureElement(int $elementId): JSONResponse {

#[NoAdminRequired]
#[NoCSRFRequired]
public function patchSignatureElement($elementId, string $type = '', array $file = []): JSONResponse {
public function patchSignatureElement($nodeId, string $type = '', array $file = []): JSONResponse {
try {
$element['elementId'] = $elementId;
$element['nodeId'] = $nodeId;
if ($type) {
$element['type'] = $type;
}
Expand All @@ -394,10 +394,14 @@ public function patchSignatureElement($elementId, string $type = '', array $file

#[NoAdminRequired]
#[NoCSRFRequired]
public function deleteSignatureElement(int $elementId): JSONResponse {
$userId = $this->userSession->getUser()->getUID();
#[PublicPage]
public function deleteSignatureElement(int $nodeId): JSONResponse {
try {
$this->accountService->deleteSignatureElement($userId, $elementId);
$this->accountService->deleteSignatureElement(
user: $this->userSession->getUser(),
nodeId: $nodeId,
sessionId: $this->sessionService->getSessionId(),
);
} catch (\Throwable $th) {
return new JSONResponse(
[
Expand Down
3 changes: 1 addition & 2 deletions lib/Controller/PageController.php
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ public function index(): TemplateResponse {
$this->initialState->provideInitialState('can_request_sign', false);
}

$this->provideSignerSignatues();
$this->initialState->provideInitialState('file_info', $this->fileService->formatFile());
$this->initialState->provideInitialState('identify_methods', $this->identifyMethodService->getIdentifyMethodsSettings());
$this->initialState->provideInitialState('legal_information', $this->appConfig->getAppValue('legal_information'));
Expand Down Expand Up @@ -173,8 +174,6 @@ public function sign(string $uuid): TemplateResponse {
$this->initialState->provideInitialState('statusText', $file['statusText']);
$this->initialState->provideInitialState('signers', $file['signers']);
$this->provideSignerSignatues();
$signatureMethods = $this->identifyMethodService->getSignMethodsOfIdentifiedFactors($this->getSignRequestEntity()->getId());
$this->initialState->provideInitialState('signature_methods', $signatureMethods);
$this->initialState->provideInitialState('token_length', TokenService::TOKEN_LENGTH);
$this->initialState->provideInitialState('description', $this->getSignRequestEntity()->getDescription() ?? '');
$this->initialState->provideInitialState('pdf',
Expand Down
12 changes: 6 additions & 6 deletions lib/Db/FileMapper.php
Original file line number Diff line number Diff line change
Expand Up @@ -118,15 +118,15 @@ public function getBySignerUuid(?string $uuid = null): File {
}

/**
* Return LibreSign file by fileId
* Return LibreSign file by nodeId
*/
public function getByFileId(?int $fileId = null): File {
$exists = array_filter($this->file, fn ($f) => $f->getNodeId() === $fileId || $f->getSignedNodeId() === $fileId);
public function getByFileId(?int $nodeId = null): File {
$exists = array_filter($this->file, fn ($f) => $f->getNodeId() === $nodeId || $f->getSignedNodeId() === $nodeId);
if (!empty($exists)) {
return current($exists);
}
foreach ($this->file as $file) {
if ($file->getNodeId() === $fileId) {
if ($file->getNodeId() === $nodeId) {
return $file;
}
}
Expand All @@ -136,8 +136,8 @@ public function getByFileId(?int $fileId = null): File {
->from($this->getTableName())
->where(
$qb->expr()->orX(
$qb->expr()->eq('node_id', $qb->createNamedParameter($fileId, IQueryBuilder::PARAM_INT)),
$qb->expr()->eq('signed_node_id', $qb->createNamedParameter($fileId, IQueryBuilder::PARAM_INT))
$qb->expr()->eq('node_id', $qb->createNamedParameter($nodeId, IQueryBuilder::PARAM_INT)),
$qb->expr()->eq('signed_node_id', $qb->createNamedParameter($nodeId, IQueryBuilder::PARAM_INT))
)
);

Expand Down
119 changes: 3 additions & 116 deletions lib/Db/SignRequestMapper.php
Original file line number Diff line number Diff line change
Expand Up @@ -361,16 +361,10 @@ public function getFilesAssociatedFilesWithMeFormatted(
$currentPageResults = $pagination->getCurrentPageResults();

$data = [];
$fileIds = [];

foreach ($currentPageResults as $row) {
$fileIds[] = $row['id'];
$data[] = $this->formatListRow($row);
}
$signers = $this->getByMultipleFileId($fileIds);
$identifyMethods = $this->getIdentifyMethodsFromSigners($signers);
$visibleElements = $this->getVisibleElementsFromSigners($signers);
$return['data'] = $this->associateAllAndFormat($user, $data, $signers, $identifyMethods, $visibleElements);
$return['data'] = $data;
$return['pagination'] = $pagination;
return $return;
}
Expand All @@ -379,7 +373,7 @@ public function getFilesAssociatedFilesWithMeFormatted(
* @param array<SignRequest> $signRequests
* @return FileElement[][]
*/
private function getVisibleElementsFromSigners(array $signRequests): array {
public function getVisibleElementsFromSigners(array $signRequests): array {
$signRequestIds = array_map(function (SignRequest $signRequest): int {
return $signRequest->getId();
}, $signRequests);
Expand Down Expand Up @@ -408,7 +402,7 @@ private function getVisibleElementsFromSigners(array $signRequests): array {
* @param array<SignRequest> $signRequests
* @return array<array-key, array<array-key, \OCP\AppFramework\Db\Entity&\OCA\Libresign\Db\IdentifyMethod>>
*/
private function getIdentifyMethodsFromSigners(array $signRequests): array {
public function getIdentifyMethodsFromSigners(array $signRequests): array {
$signRequestIds = array_map(function (SignRequest $signRequest): int {
return $signRequest->getId();
}, $signRequests);
Expand Down Expand Up @@ -531,113 +525,6 @@ private function getFilesAssociatedFilesWithMeStmt(string $userId, ?string $emai
return $pagination;
}

/**
* @param IUser $userId
* @param array $files
* @param array<SignRequest> $signers
* @param array<array-key, array<array-key, \OCP\AppFramework\Db\Entity&\OCA\Libresign\Db\IdentifyMethod>> $identifyMethods
* @param SignRequest[][]
*/
private function associateAllAndFormat(IUser $user, array $files, array $signers, array $identifyMethods, array $visibleElements): array {
foreach ($files as $key => $file) {
$totalSigned = 0;
foreach ($signers as $signerKey => $signer) {
if ($signer->getFileId() === $file['id']) {
/** @var array<IdentifyMethod> */
$identifyMethodsOfSigner = $identifyMethods[$signer->getId()] ?? [];
$data = [
'email' => array_reduce($identifyMethodsOfSigner, function (string $carry, IdentifyMethod $identifyMethod): string {
if ($identifyMethod->getIdentifierKey() === IdentifyMethodService::IDENTIFY_EMAIL) {
return $identifyMethod->getIdentifierValue();
}
return $carry;
}, ''),
'description' => $signer->getDescription(),
'displayName' =>
array_reduce($identifyMethodsOfSigner, function (string $carry, IdentifyMethod $identifyMethod): string {
if (!$carry && $identifyMethod->getMandatory()) {
return $identifyMethod->getIdentifierValue();
}
return $carry;
}, $signer->getDisplayName()),
'request_sign_date' => (new \DateTime())
->setTimestamp($signer->getCreatedAt())
->format('Y-m-d H:i:s'),
'signed' => null,
'signRequestId' => $signer->getId(),
'me' => array_reduce($identifyMethodsOfSigner, function (bool $carry, IdentifyMethod $identifyMethod) use ($user): bool {
if ($identifyMethod->getIdentifierKey() === IdentifyMethodService::IDENTIFY_ACCOUNT) {
if ($user->getUID() === $identifyMethod->getIdentifierValue()) {
return true;
}
} elseif ($identifyMethod->getIdentifierKey() === IdentifyMethodService::IDENTIFY_EMAIL) {
if (!$user->getEMailAddress()) {
return false;
}
if ($user->getEMailAddress() === $identifyMethod->getIdentifierValue()) {
return true;
}
}
return $carry;
}, false),
'visibleElements' => array_map(function (FileElement $visibleElement) use ($file) {
$element = [
'elementId' => $visibleElement->getId(),
'signRequestId' => $visibleElement->getSignRequestId(),
'type' => $visibleElement->getType(),
'coordinates' => [
'page' => $visibleElement->getPage(),
'urx' => $visibleElement->getUrx(),
'ury' => $visibleElement->getUry(),
'llx' => $visibleElement->getLlx(),
'lly' => $visibleElement->getLly()
]
];
$metadata = json_decode($file['metadata'], true);
$dimension = $metadata['d'][$element['coordinates']['page'] - 1];

$element['coordinates']['left'] = $element['coordinates']['llx'];
$element['coordinates']['height'] = abs($element['coordinates']['ury'] - $element['coordinates']['lly']);
$element['coordinates']['top'] = $dimension['h'] - $element['coordinates']['ury'];
$element['coordinates']['width'] = $element['coordinates']['urx'] - $element['coordinates']['llx'];

return $element;
}, $visibleElements[$signer->getId()] ?? []),
'identifyMethods' => array_map(function (IdentifyMethod $identifyMethod) use ($signer): array {
return [
'method' => $identifyMethod->getIdentifierKey(),
'value' => $identifyMethod->getIdentifierValue(),
'mandatory' => $identifyMethod->getMandatory(),
];
}, array_values($identifyMethodsOfSigner)),
];

if ($data['me']) {
$data['sign_uuid'] = $signer->getUuid();
$files[$key]['url'] = $this->urlGenerator->linkToRoute('libresign.page.getPdfFile', ['uuid' => $signer->getuuid()]);
}

if ($signer->getSigned()) {
$data['signed'] = $this->dateTimeFormatter->formatDateTime($signer->getSigned());
$totalSigned++;
}
ksort($data);
$files[$key]['signers'][] = $data;
unset($signers[$signerKey]);
}
}
if (empty($files[$key]['signers'])) {
$files[$key]['signers'] = [];
$files[$key]['statusText'] = $this->l10n->t('no signers');
} else {
$files[$key]['statusText'] = $this->fileMapper->getTextOfStatus((int) $files[$key]['status']);
}
unset($files[$key]['id']);
ksort($files[$key]);
}
return $files;
}

private function formatListRow(array $row): array {
$row['id'] = (int) $row['id'];
$row['status'] = (int) $row['status'];
Expand Down
8 changes: 4 additions & 4 deletions lib/Helper/ValidateHelper.php
Original file line number Diff line number Diff line change
Expand Up @@ -295,15 +295,15 @@ public function validateVisibleElementsRelation(array $list, SignRequest $signRe
if (!array_key_exists('documentElementId', $elements)) {
throw new LibresignException($this->l10n->t('Field %s not found', ['documentElementId']));
}
if (!array_key_exists('profileFileId', $elements)) {
throw new LibresignException($this->l10n->t('Field %s not found', ['profileFileId']));
if (!array_key_exists('profileNodeId', $elements)) {
throw new LibresignException($this->l10n->t('Field %s not found', ['profileNodeId']));
}
$this->validateSignerIsOwnerOfPdfVisibleElement($elements['documentElementId'], $signRequest);
if ($user instanceof IUser) {
try {
$this->userElementMapper->findOne(['file_id' => $elements['profileFileId'], 'user_id' => $user->getUID()]);
$this->userElementMapper->findOne(['file_id' => $elements['profileNodeId'], 'user_id' => $user->getUID()]);
} catch (\Throwable $th) {
throw new LibresignException($this->l10n->t('Field %s does not belong to user', $elements['profileFileId']));
throw new LibresignException($this->l10n->t('Field %s does not belong to user', $elements['profileNodeId']));
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion lib/Middleware/GlobalInjectionMiddleware.php
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ class GlobalInjectionMiddleware extends Middleware {
public function afterController(Controller $controller, string $methodName, Response $response) {
if ($controller instanceof ViewController) {
$policy = new ContentSecurityPolicy();
$policy->allowEvalScript(true);
$policy->addAllowedFrameDomain("'self'");
$response->setContentSecurityPolicy($policy);
}
return $response;
Expand Down
29 changes: 24 additions & 5 deletions lib/Service/AccountService.php
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@
use OCP\Files\Config\IMountProviderCollection;
use OCP\Files\Config\IUserMountCache;
use OCP\Files\File;
use OCP\Files\Folder;
use OCP\Files\IMimeTypeDetector;
use OCP\Files\IRootFolder;
use OCP\Http\Client\IClientService;
Expand Down Expand Up @@ -405,9 +406,12 @@ private function saveFileOfVisibleElementUsingSession(array $data, string $sessi
$rootSignatureFolder = $this->folderService->getFolder();
$folderName = $sessionId;
if ($rootSignatureFolder->nodeExists($folderName)) {
throw new \Exception($this->l10n->t('File already exists'));
/** @var Folder $folderToFile */
$folderToFile = $rootSignatureFolder->get($folderName);
} else {
/** @var Folder $folderToFile */
$folderToFile = $rootSignatureFolder->newFolder($folderName);
}
$folderToFile = $rootSignatureFolder->newFolder($folderName);
$filename = implode(
'_',
[
Expand Down Expand Up @@ -461,9 +465,24 @@ private function getFileRaw(array $data) {
return $content;
}

public function deleteSignatureElement(string $userId, int $elementId): void {
$element = $this->userElementMapper->findOne(['id' => $elementId, 'user_id' => $userId]);
$this->userElementMapper->delete($element);
public function deleteSignatureElement(?IUser $user, string $sessionId, int $nodeId): void {
if ($user instanceof IUser) {
$element = $this->userElementMapper->findOne([
'file_id' => $nodeId,
'user_id' => $user->getUID(),
]);
$this->userElementMapper->delete($element);
$file = $this->root->getById($element->getFileId());
if ($file) {
current($file)->delete();
}
} else {
$rootSignatureFolder = $this->folderService->getFolder();
$folderName = $sessionId;
if ($rootSignatureFolder->nodeExists($folderName)) {
$rootSignatureFolder->delete($folderName);
}
}
}

/**
Expand Down
Loading

0 comments on commit da9a30f

Please sign in to comment.