Skip to content

Commit

Permalink
Merge pull request #3898 from LibreSign/backport/3746/stable30
Browse files Browse the repository at this point in the history
[stable30] feat: rewrite file list
  • Loading branch information
vitormattos authored Nov 6, 2024
2 parents 859d235 + 9f959ee commit 1eb9ba1
Show file tree
Hide file tree
Showing 43 changed files with 3,236 additions and 424 deletions.
74 changes: 71 additions & 3 deletions lib/Controller/FileController.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@

use OCA\Files_Sharing\SharedStorage;
use OCA\Libresign\AppInfo\Application;
use OCA\Libresign\Db\File as FileEntity;
use OCA\Libresign\Db\SignRequestMapper;
use OCA\Libresign\Exception\LibresignException;
use OCA\Libresign\Helper\JSActions;
Expand All @@ -19,6 +20,7 @@
use OCA\Libresign\Service\AccountService;
use OCA\Libresign\Service\FileService;
use OCA\Libresign\Service\IdentifyMethodService;
use OCA\Libresign\Service\RequestSignatureService;
use OCA\Libresign\Service\SessionService;
use OCP\AppFramework\Db\DoesNotExistException;
use OCP\AppFramework\Http;
Expand Down Expand Up @@ -59,6 +61,7 @@ public function __construct(
private SessionService $sessionService,
private SignRequestMapper $signRequestMapper,
private IdentifyMethodService $identifyMethodService,
private RequestSignatureService $requestSignatureService,
private AccountService $accountService,
private IRootFolder $root,
private IPreview $preview,
Expand Down Expand Up @@ -192,9 +195,13 @@ public function validate(?string $type = null, $identifier = null): DataResponse
*
* @param string|null $signer_uuid Signer UUID
* @param string|null $nodeId The nodeId (also called fileId). Is the id of a file at Nextcloud
* @param int|null $status Status could be one of 0 = draft, 1 = able to sign, 2 = partial signed, 3 = signed, 4 = deleted.
* @param list<int>|null $status Status could be none or many of 0 = draft, 1 = able to sign, 2 = partial signed, 3 = signed, 4 = deleted.
* @param int|null $page the number of page to return
* @param int|null $length Total of elements to return
* @param int|null $start Start date of signature request (UNIX timestamp)
* @param int|null $end End date of signature request (UNIX timestamp)
* @param string|null $sortBy Name of the column to sort by
* @param string|null $sortDirection Ascending or descending order
* @return DataResponse<Http::STATUS_OK, array{pagination: LibresignPagination, data: ?LibresignFile[]}, array{}>
*
* 200: OK
Expand All @@ -207,16 +214,26 @@ public function list(
?int $length = null,
?string $signer_uuid = null,
?string $nodeId = null,
?int $status = null,
?array $status = null,
?int $start = null,
?int $end = null,
?string $sortBy = null,
?string $sortDirection = null,
): DataResponse {
$filter = array_filter([
'signer_uuid' => $signer_uuid,
'nodeId' => $nodeId,
'status' => $status,
'start' => $start,
'end' => $end,
], static function ($var) { return $var !== null; });
$sort = [
'sortBy' => $sortBy,
'sortDirection' => $sortDirection,
];
$return = $this->fileService
->setMe($this->userSession->getUser())
->listAssociatedFilesOfSignFlow($page, $length, $filter);
->listAssociatedFilesOfSignFlow($page, $length, $filter, $sort);
return new DataResponse($return, Http::STATUS_OK);
}

Expand Down Expand Up @@ -356,6 +373,15 @@ public function save(array $file, string $name = '', array $settings = []): Data
'file' => $file,
'settings' => $settings
]);
$data = [
'file' => [
'fileNode' => $node,
],
'name' => $name,
'userManager' => $this->userSession->getUser(),
'status' => FileEntity::STATUS_DRAFT,
];
$file = $this->requestSignatureService->save($data);

return new DataResponse(
[
Expand All @@ -377,4 +403,46 @@ public function save(array $file, string $name = '', array $settings = []): Data
);
}
}

/**
* Delete File
*
* This will delete the file and all data
*
* @param integer $fileId Node id of a Nextcloud file
* @return DataResponse<Http::STATUS_OK, array{message: string}, array{}>|DataResponse<Http::STATUS_UNAUTHORIZED, array{message: string}, array{}>|DataResponse<Http::STATUS_UNPROCESSABLE_ENTITY, array{action: integer, errors: string[]}, array{}>
*
* 200: OK
* 401: Failed
* 422: Failed
*/
#[NoAdminRequired]
#[NoCSRFRequired]
#[RequireManager]
#[ApiRoute(verb: 'DELETE', url: '/api/{apiVersion}/file/file_id/{fileId}', requirements: ['apiVersion' => '(v1)'])]
public function deleteAllRequestSignatureUsingFileId(int $fileId): DataResponse {
try {
$data = [
'userManager' => $this->userSession->getUser(),
'file' => [
'fileId' => $fileId
]
];
$this->validateHelper->validateExistingFile($data);
$this->fileService->delete($fileId);
} catch (\Throwable $th) {
return new DataResponse(
[
'message' => $th->getMessage(),
],
Http::STATUS_UNAUTHORIZED
);
}
return new DataResponse(
[
'message' => $this->l10n->t('Success')
],
Http::STATUS_OK
);
}
}
2 changes: 1 addition & 1 deletion lib/Db/AccountFileMapper.php
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,7 @@ private function getUserAccountFile(array $filter = []): Pagination {
$qb->setMaxResults($filter['length']);
}

$pagination = new Pagination($qb);
$pagination = new Pagination($qb, $this->urlGenerator);
return $pagination;
}

Expand Down
29 changes: 25 additions & 4 deletions lib/Db/SignRequestMapper.php
Original file line number Diff line number Diff line change
Expand Up @@ -345,11 +345,12 @@ public function getFilesAssociatedFilesWithMeFormatted(
array $filter,
?int $page = null,
?int $length = null,
?array $sort = [],
): array {
$filter['email'] = $user->getEMailAddress();
$filter['length'] = $length;
$filter['page'] = $page;
$pagination = $this->getFilesAssociatedFilesWithMeStmt($user->getUID(), $filter);
$pagination = $this->getFilesAssociatedFilesWithMeStmt($user->getUID(), $filter, $sort);
$pagination->setMaxPerPage($length);
$pagination->setCurrentPage($page);
$currentPageResults = $pagination->getCurrentPageResults();
Expand Down Expand Up @@ -488,7 +489,17 @@ private function getFilesAssociatedFilesWithMeQueryBuilder(string $userId, ?arra
}
if (!empty($filter['status'])) {
$qb->andWhere(
$qb->expr()->eq('f.status', $qb->createNamedParameter($filter['status'], IQueryBuilder::PARAM_INT))
$qb->expr()->in('f.status', $qb->createNamedParameter($filter['status'], IQueryBuilder::PARAM_INT_ARRAY))
);
}
if (!empty($filter['start'])) {
$qb->andWhere(
$qb->expr()->gte('f.created_at', $qb->createNamedParameter($filter['start'], IQueryBuilder::PARAM_INT))
);
}
if (!empty($filter['end'])) {
$qb->andWhere(
$qb->expr()->lte('f.created_at', $qb->createNamedParameter($filter['end'], IQueryBuilder::PARAM_INT))
);
}
if (isset($filter['length']) && isset($filter['page'])) {
Expand All @@ -499,7 +510,11 @@ private function getFilesAssociatedFilesWithMeQueryBuilder(string $userId, ?arra
return $qb;
}

private function getFilesAssociatedFilesWithMeStmt(string $userId, ?array $filter = []): Pagination {
private function getFilesAssociatedFilesWithMeStmt(
string $userId,
?array $filter = [],
?array $sort = [],
): Pagination {
$qb = $this->getFilesAssociatedFilesWithMeQueryBuilder($userId, $filter);
$qb->select(
'f.id',
Expand All @@ -510,6 +525,12 @@ private function getFilesAssociatedFilesWithMeStmt(string $userId, ?array $filte
'f.status',
'f.metadata',
);
if (!empty($sort) && in_array($sort['sortBy'], ['name', 'status', 'created_at'])) {
$qb->orderBy(
$qb->func()->lower('f.' . $sort['sortBy']),
$sort['sortDirection'] == 'asc' ? 'asc' : 'desc'
);
}
$qb->selectAlias('f.created_at', 'request_date');

$countQueryBuilderModifier = function (IQueryBuilder $qb): int {
Expand All @@ -521,7 +542,7 @@ private function getFilesAssociatedFilesWithMeStmt(string $userId, ?array $filte
return (int)$qb->executeQuery()->fetchOne();
};

$pagination = new Pagination($qb);
$pagination = new Pagination($qb, $this->urlGenerator);
return $pagination;
}

Expand Down
71 changes: 52 additions & 19 deletions lib/Helper/Pagination.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,14 @@

use OCA\Libresign\Db\PagerFantaQueryAdapter;
use OCP\DB\QueryBuilder\IQueryBuilder;
use OCP\IURLGenerator;
use Pagerfanta\Pagerfanta;

class Pagination extends Pagerfanta {
/** @var string */
private $rootPath;
private string $routeName;
public function __construct(
IQueryBuilder $queryBuilder,
private IURLGenerator $urlGenerator,
) {
$adapter = new PagerFantaQueryAdapter($queryBuilder);
parent::__construct($adapter);
Expand All @@ -25,27 +26,59 @@ public function __construct(
/**
* @return static
*/
public function setRootPath(string $rootPath = ''): self {
$this->rootPath = $rootPath;
public function setRouteName(string $routeName = ''): self {
$this->routeName = $routeName;
return $this;
}

public function getPagination(?int $page, ?int $length): array {
public function getPagination(int $page, int $length, array $filter = []): array {
$this->setMaxPerPage($length);
$pagination['total'] = $this->count();
if ($pagination['total'] > $length) {
$pagination['current'] = $this->rootPath . '?page=' . $page . '&length=' . $length;
$pagination['next'] = $this->hasNextPage() ? $this->rootPath . '?page=' . $this->getNextPage() . '&length=' . $length : null;
$pagination['prev'] = $this->hasPreviousPage() ? $this->rootPath . '?page=' . $this->getPreviousPage() . '&length=' . $length : null;
$pagination['last'] = $this->hasNextPage() ? $this->rootPath . '?page=' . $this->getNbPages() . '&length=' . $length : null;
$pagination['first'] = $this->hasPreviousPage() ? $this->rootPath . '?page=1&length=' . $length : null;
} else {
$pagination['current'] = null;
$pagination['next'] = null;
$pagination['prev'] = null;
$pagination['last'] = null;
$pagination['first'] = null;
$total = $this->count();
if ($total > $length) {
return [
'total' => $total,
'current' => $this->linkToRoute(true, $page, $length, $filter),
'next' => $this->linkToRoute($this->hasNextPage(), 'getNextPage', $length, $filter),
'prev' => $this->linkToRoute($this->hasPreviousPage(), 'getPreviousPage', $length, $filter),
'last' => $this->linkToRoute($this->hasNextPage(), 'getNbPages', $length, $filter),
'first' => $this->linkToRoute($this->hasPreviousPage(), 1, $length, $filter),
];
}
return $pagination;
return [
'total' => $total,
'current' => null,
'next' => null,
'prev' => null,
'last' => null,
'first' => null,
];
}

private function linkToRoute(bool $condition, int|string $page, int $length, array $filter): ?string {
if (!$condition) {
return null;
}
if (is_string($page)) {
$page = $this->$page();
}
$url = $this->urlGenerator->linkToRouteAbsolute(
$this->routeName,
array_merge(['page' => $page, 'length' => $length, 'apiVersion' => 'v1'], $filter)
);
$url = $this->sortParameters($url);
return $url;
}

/**
* This is necessary to fix problem at integration tests because the method linkToRoute change the order of parameters
*/
private function sortParameters(?string $url): ?string {
if (!$url) {
return $url;
}
parse_str(parse_url($url, PHP_URL_QUERY), $query);
ksort($query);
$url = strtok($url, '?') . '?' . http_build_query($query);
return $url;
}
}
4 changes: 2 additions & 2 deletions lib/Service/AccountFileService.php
Original file line number Diff line number Diff line change
Expand Up @@ -49,10 +49,10 @@ public function accountFileList(array $filter, ?int $page = null, ?int $length =
$page = $page ?? 1;
$length = $length ?? (int)$this->appConfig->getAppValue('length_of_page', '100');
$data = $this->accountFileMapper->accountFileList($filter, $page, $length);
$data['pagination']->setRootPath('/file/list');
$data['pagination']->setRouteName('ocs.libresign.File.list');
return [
'data' => $data['data'],
'pagination' => $data['pagination']->getPagination($page, $length)
'pagination' => $data['pagination']->getPagination($page, $length, $filter)
];
}
}
28 changes: 25 additions & 3 deletions lib/Service/FileService.php
Original file line number Diff line number Diff line change
Expand Up @@ -432,7 +432,12 @@ public function setFileByPath(string $path): self {
*
* @psalm-return array{data: array, pagination: array}
*/
public function listAssociatedFilesOfSignFlow($page = null, $length = null, array $filter = []): array {
public function listAssociatedFilesOfSignFlow(
$page = null,
$length = null,
array $filter = [],
array $sort = [],
): array {
$page = $page ?? 1;
$length = $length ?? (int)$this->appConfig->getAppValue('length_of_page', '100');

Expand All @@ -441,17 +446,18 @@ public function listAssociatedFilesOfSignFlow($page = null, $length = null, arra
$filter,
$page,
$length,
$sort,
);

$signers = $this->signRequestMapper->getByMultipleFileId(array_column($return['data'], 'id'));
$identifyMethods = $this->signRequestMapper->getIdentifyMethodsFromSigners($signers);
$visibleElements = $this->signRequestMapper->getVisibleElementsFromSigners($signers);
$return['data'] = $this->associateAllAndFormat($this->me, $return['data'], $signers, $identifyMethods, $visibleElements);

$return['pagination']->setRootPath('/file/list');
$return['pagination']->setRouteName('ocs.libresign.File.list');
return [
'data' => $return['data'],
'pagination' => $return['pagination']->getPagination($page, $length)
'pagination' => $return['pagination']->getPagination($page, $length, $filter)
];
}

Expand Down Expand Up @@ -585,4 +591,20 @@ public function getMyLibresignFile(int $nodeId): File {
],
);
}

public function delete(int $fileId): void {
$file = $this->fileMapper->getByFileId($fileId);
$this->fileElementService->deleteVisibleElements($file->getId());
$list = $this->signRequestMapper->getByFileId($file->getId());
foreach ($list as $signRequest) {
$this->signRequestMapper->delete($signRequest);
}
$this->fileMapper->delete($file);
if ($file->getSignedNodeId()) {
$signedNextcloudFile = $this->folderService->getFileById($file->getSignedNodeId());
$signedNextcloudFile->delete();
}
$nextcloudFile = $this->folderService->getFileById($fileId);
$nextcloudFile->delete();
}
}
Loading

0 comments on commit 1eb9ba1

Please sign in to comment.