Merge pull request #2424 from LibreSign/bugfix/thumbnail-for-guest

Generate thumbnail when is not my file
This commit is contained in:
Vitor Mattos 2024-03-04 15:51:55 -03:00 committed by GitHub
commit 1af890de63
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 165 additions and 18 deletions

View file

@ -8,6 +8,7 @@ return [
'ocs' => [
['name' => 'File#save', 'url' => '/api/{apiVersion}/file', 'verb' => 'POST', 'requirements' => $requirements],
['name' => 'File#list', 'url' => '/api/{apiVersion}/file/list', 'verb' => 'GET', 'requirements' => $requirements],
['name' => 'File#getThumbnail', 'url' => '/api/{apiVersion}/file/thumbnail/{nodeId}', 'verb' => 'GET', 'requirements' => $requirements],
['name' => 'File#validate', 'url' => '/api/{apiVersion}/file/validate/', 'verb' => 'GET', 'requirements' => $requirements],
['name' => 'File#validateUuid', 'url' => '/api/{apiVersion}/file/validate/uuid/{uuid}', 'verb' => 'GET', 'requirements' => $requirements],
['name' => 'File#validateFileId', 'url' => '/api/{apiVersion}/file/validate/file_id/{fileId}', 'verb' => 'GET', 'requirements' => $requirements],

View file

@ -24,22 +24,35 @@ declare(strict_types=1);
namespace OCA\Libresign\Controller;
use OCA\Files_Sharing\SharedStorage;
use OCA\Libresign\AppInfo\Application;
use OCA\Libresign\Db\SignRequestMapper;
use OCA\Libresign\Exception\LibresignException;
use OCA\Libresign\Helper\JSActions;
use OCA\Libresign\Helper\ValidateHelper;
use OCA\Libresign\Middleware\Attribute\RequireManager;
use OCA\Libresign\Service\FileService;
use OCA\Libresign\Service\IdentifyMethodService;
use OCA\Libresign\Service\SessionService;
use OCP\AppFramework\Controller;
use OCP\AppFramework\Db\DoesNotExistException;
use OCP\AppFramework\Http;
use OCP\AppFramework\Http\Attribute\NoAdminRequired;
use OCP\AppFramework\Http\Attribute\NoCSRFRequired;
use OCP\AppFramework\Http\Attribute\PublicPage;
use OCP\AppFramework\Http\DataResponse;
use OCP\AppFramework\Http\FileDisplayResponse;
use OCP\AppFramework\Http\JSONResponse;
use OCP\AppFramework\Http\RedirectResponse;
use OCP\Files\File;
use OCP\Files\IRootFolder;
use OCP\Files\Node;
use OCP\Files\NotFoundException;
use OCP\IL10N;
use OCP\IPreview;
use OCP\IRequest;
use OCP\IUserSession;
use OCP\Preview\IMimeIconProvider;
use Psr\Log\LoggerInterface;
class FileController extends Controller {
@ -49,6 +62,11 @@ class FileController extends Controller {
private LoggerInterface $logger,
private IUserSession $userSession,
private SessionService $sessionService,
private SignRequestMapper $signRequestMapper,
private IdentifyMethodService $identifyMethodService,
private IRootFolder $root,
private IPreview $preview,
private IMimeIconProvider $mimeIconProvider,
private FileService $fileService,
private ValidateHelper $validateHelper
) {
@ -142,6 +160,86 @@ class FileController extends Controller {
return new JSONResponse($return, Http::STATUS_OK);
}
#[NoAdminRequired]
#[NoCSRFRequired]
public function getThumbnail(
int $nodeId = -1,
int $x = 32,
int $y = 32,
bool $a = false,
bool $forceIcon = true,
string $mode = 'fill',
bool $mimeFallback = false
) {
if ($nodeId === -1 || $x === 0 || $y === 0) {
return new DataResponse([], Http::STATUS_BAD_REQUEST);
}
try {
$myLibreSignFile = $this->fileService
->setMe($this->userSession->getUser())
->getMyLibresignFile($nodeId);
} catch (DoesNotExistException $e) {
return new DataResponse([], Http::STATUS_NOT_FOUND);
}
$userFolder = $this->root->getUserFolder($myLibreSignFile->getUserId());
$nodes = $userFolder->getById($nodeId);
$node = array_pop($nodes);
return $this->fetchPreview($node, $x, $y, $a, $forceIcon, $mode, $mimeFallback);
}
/**
* @return FileDisplayResponse<Http::STATUS_OK, array{Content-Type: string}>|DataResponse<Http::STATUS_BAD_REQUEST|Http::STATUS_FORBIDDEN|Http::STATUS_NOT_FOUND, array<empty>, array{}>|RedirectResponse<Http::STATUS_SEE_OTHER, array{}>
*/
private function fetchPreview(
Node $node,
int $x,
int $y,
bool $a,
bool $forceIcon,
string $mode,
bool $mimeFallback = false,
) : Http\Response {
if (!($node instanceof File) || (!$forceIcon && !$this->preview->isAvailable($node))) {
return new DataResponse([], Http::STATUS_NOT_FOUND);
}
if (!$node->isReadable()) {
return new DataResponse([], Http::STATUS_FORBIDDEN);
}
$storage = $node->getStorage();
if ($storage->instanceOfStorage(SharedStorage::class)) {
/** @var SharedStorage $storage */
$share = $storage->getShare();
$attributes = $share->getAttributes();
if ($attributes !== null && $attributes->getAttribute('permissions', 'download') === false) {
return new DataResponse([], Http::STATUS_FORBIDDEN);
}
}
try {
$f = $this->preview->getPreview($node, $x, $y, !$a, $mode);
$response = new FileDisplayResponse($f, Http::STATUS_OK, [
'Content-Type' => $f->getMimeType(),
]);
$response->cacheFor(3600 * 24, false, true);
return $response;
} catch (NotFoundException $e) {
// If we have no preview enabled, we can redirect to the mime icon if any
if ($mimeFallback) {
if ($url = $this->mimeIconProvider->getMimeIconUrl($node->getMimeType())) {
return new RedirectResponse($url);
}
}
return new DataResponse([], Http::STATUS_NOT_FOUND);
} catch (\InvalidArgumentException $e) {
return new DataResponse([], Http::STATUS_BAD_REQUEST);
}
}
#[NoAdminRequired]
#[NoCSRFRequired]
#[RequireManager]

View file

@ -364,18 +364,25 @@ class SignRequestMapper extends QBMapper {
return $return;
}
private function getFilesAssociatedFilesWithMeStmt(string $userId, ?string $email): Pagination {
public function getMyLibresignFile(string $userId, ?string $email, ?array $filter = []): File {
$qb = $this->getFilesAssociatedFilesWithMeQueryBuilder(
userId: $userId,
email: $email,
filter: $filter,
);
$qb->select('f.*');
$cursor = $qb->executeQuery();
$row = $cursor->fetch();
if (!$row) {
throw new DoesNotExistException('LibreSign file not found');
}
$file = new File();
return $file->fromRow($row);
}
private function getFilesAssociatedFilesWithMeQueryBuilder(string $userId, ?string $email, ?array $filter = []): IQueryBuilder {
$qb = $this->db->getQueryBuilder();
$qb->select(
'f.id',
'f.node_id',
'f.user_id',
'f.uuid',
'f.name',
'f.status'
)
->selectAlias('f.created_at', 'request_date')
->from('libresign_file', 'f')
$qb->from('libresign_file', 'f')
->leftJoin('f', 'libresign_sign_request', 'sr', 'sr.file_id = f.id')
->leftJoin('f', 'libresign_identify_method', 'im', $qb->expr()->eq('sr.id', 'im.sign_request_id'))
->groupBy(
@ -402,6 +409,27 @@ class SignRequestMapper extends QBMapper {
);
}
$qb->where($qb->expr()->orX(...$or));
if ($filter) {
if (isset($filter['nodeId'])) {
$qb->andWhere(
$qb->expr()->eq('f.node_id', $qb->createNamedParameter($filter['nodeId'], IQueryBuilder::PARAM_INT))
);
}
}
return $qb;
}
private function getFilesAssociatedFilesWithMeStmt(string $userId, ?string $email, ?array $filter = []): Pagination {
$qb = $this->getFilesAssociatedFilesWithMeQueryBuilder($userId, $email, $filter);
$qb->selectAlias('f.created_at', 'request_date');
$qb->select(
'f.id',
'f.node_id',
'f.user_id',
'f.uuid',
'f.name',
'f.status'
);
$countQueryBuilderModifier = function (IQueryBuilder &$qb): void {
/** @todo improve this to don't do two queries */

View file

@ -443,14 +443,15 @@ class FileService {
*
* @psalm-return array{data: array, pagination: array}
*/
public function listAssociatedFilesOfSignFlow($page = null, $length = null): array {
public function listAssociatedFilesOfSignFlow($page = null, $length = null, array $filter = []): array {
$page = $page ?? 1;
$length = $length ?? (int) $this->appConfig->getAppValue('length_of_page', '100');
$data = $this->signRequestMapper->getFilesAssociatedFilesWithMeFormatted(
$this->me,
$page,
$length
$length,
$filter,
);
$data['pagination']->setRootPath('/file/list');
return [
@ -458,4 +459,14 @@ class FileService {
'pagination' => $data['pagination']->getPagination($page, $length)
];
}
public function getMyLibresignFile(int $nodeId): File {
return $this->signRequestMapper->getMyLibresignFile(
userId: $this->me->getUID(),
email: $this->me->getEMailAddress(),
filter: [
'nodeId' => $nodeId,
],
);
}
}

View file

@ -20,7 +20,7 @@
<script>
import FileIcon from 'vue-material-design-icons/File.vue'
import { generateUrl } from '@nextcloud/router'
import { generateOcsUrl } from '@nextcloud/router'
import { useFilesStore } from '../../store/files.js'
export default {
@ -58,10 +58,10 @@ export default {
return null
}
try {
const previewUrl = generateUrl('/core/preview?fileId={fileid}', {
fileid: this.currentNodeId,
const previewUrl = generateOcsUrl('/apps/libresign/api/v1/file/thumbnail/{nodeId}', {
nodeId: this.currentNodeId,
})
const url = new URL(window.location.origin + previewUrl)
const url = new URL(previewUrl)
// Request tiny previews
url.searchParams.set('x', this.gridMode ? '128' : '32')
@ -70,7 +70,7 @@ export default {
// Handle cropping
url.searchParams.set('a', this.cropPreviews === true ? '0' : '1')
return url.href
return url
} catch (e) {
return null
}

View file

@ -30,6 +30,15 @@
<code>Base</code>
</MissingDependency>
</file>
<file src="lib/Controller/FileController.php">
<UndefinedClass occurrences="1">
<code>SharedStorage</code>
</UndefinedClass>
<UndefinedDocblockClass occurrences="2">
<code>$share</code>
<code>$storage</code>
</UndefinedDocblockClass>
</file>
<file src="lib/Controller/PageController.php">
<InvalidThrow occurrences="1">
<code>throw new NotLoggedInException();</code>