Skip to content

Commit a9aa8f0

Browse files
authored
Merge pull request #6995 from LibreSign/backport/6993/stable33
[stable33] feat: vue3 typescript migration
2 parents 3b821d8 + 2944d98 commit a9aa8f0

295 files changed

Lines changed: 15314 additions & 13451 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.devcontainer/setup.sh

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
git config --global --add safe.directory /var/www/html
1313
git config --global --add safe.directory /var/www/html/apps-extra/libresign
1414
cd /var/www/html/apps-extra/libresign
15+
git submodule update --init --recursive
1516
if [[ ! -d "vendor" ]]; then
1617
composer install
1718
fi

.github/copilot-instructions.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -163,7 +163,7 @@ The second example is clear without comments because the method names describe e
163163
- **Db**: `OCA\Libresign\Db\*` - Entities extend `Entity`, Mappers extend `QBMapper`
164164

165165
### Frontend Architecture
166-
- **Vue 2** with Composition API patterns via `@vueuse/core`
166+
- **Vue 3** with Composition API patterns via `@vueuse/core`
167167
- **Pinia stores** for state (not Vuex)
168168
- **Router**: `src/router/router.js` defines SPA routes
169169
- **OpenAPI integration**: TypeScript types generated from OpenAPI spec via `npm run typescript:generate`
Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
# This workflow is provided via the organization template repository
2+
#
3+
# https://github.com/nextcloud/.github
4+
# https://docs.github.com/en/actions/learn-github-actions/sharing-workflows-with-your-organization
5+
#
6+
# SPDX-FileCopyrightText: 2023-2024 Nextcloud GmbH and Nextcloud contributors
7+
# SPDX-License-Identifier: MIT
8+
9+
name: Type checking
10+
11+
on:
12+
pull_request:
13+
push:
14+
branches:
15+
- main
16+
- master
17+
- stable*
18+
19+
permissions:
20+
contents: read
21+
22+
concurrency:
23+
group: lint-typescript-${{ github.head_ref || github.run_id }}
24+
cancel-in-progress: true
25+
26+
jobs:
27+
changes:
28+
runs-on: ubuntu-latest-low
29+
permissions:
30+
contents: read
31+
pull-requests: read
32+
33+
outputs:
34+
src: ${{ steps.changes.outputs.src}}
35+
36+
steps:
37+
- uses: dorny/paths-filter@de90cc6fb38fc0963ad72b210f1f284cd68cea36 # v3.0.2
38+
id: changes
39+
continue-on-error: true
40+
with:
41+
filters: |
42+
src:
43+
- '.github/workflows/lint-typescript.yml'
44+
- 'package.json'
45+
- 'package-lock.json'
46+
- 'tsconfig.json'
47+
- '**.ts'
48+
- '**.vue'
49+
50+
test:
51+
runs-on: ubuntu-latest
52+
53+
needs: changes
54+
if: needs.changes.outputs.src != 'false'
55+
56+
steps:
57+
- name: Checkout
58+
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
59+
with:
60+
persist-credentials: false
61+
62+
- name: Read package.json node and npm engines version
63+
uses: skjnldsv/read-package-engines-version-actions@06d6baf7d8f41934ab630e97d9e6c0bc9c9ac5e4 # v3
64+
id: versions
65+
with:
66+
fallbackNode: '^24'
67+
fallbackNpm: '^11.3'
68+
69+
- name: Set up node ${{ steps.versions.outputs.nodeVersion }}
70+
uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6.2.0
71+
with:
72+
node-version: ${{ steps.versions.outputs.nodeVersion }}
73+
74+
- name: Set up npm ${{ steps.versions.outputs.npmVersion }}
75+
run: npm i -g 'npm@${{ steps.versions.outputs.npmVersion }}'
76+
77+
- name: Install dependencies
78+
env:
79+
CYPRESS_INSTALL_BINARY: 0
80+
run: |
81+
npm ci
82+
83+
- name: Check types
84+
run: |
85+
npm run --if-present check-types
86+
npm run --if-present ts:check
87+
88+
summary:
89+
permissions:
90+
contents: none
91+
runs-on: ubuntu-latest-low
92+
needs: [changes, test]
93+
94+
if: always()
95+
96+
name: typescript-summary
97+
98+
steps:
99+
- name: Summary status
100+
run: if ${{ needs.changes.outputs.src != 'false' && needs.test.result != 'success' }}; then exit 1; fi

.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
/tests/integration/vendor
1212
/tests/integration/output
1313
/js/
14+
/css/
1415
/build/
1516
node_modules/
1617
/.php-cs-fixer.cache
@@ -20,4 +21,4 @@ node_modules/
2021
/appinfo/install-*.json
2122
/lib/Vendor/
2223
/coverage
23-
24+
/dist/

lib/Controller/IdentifyController.php

Lines changed: 3 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -19,28 +19,23 @@
1919
use OCA\Libresign\Service\Identify\ResultFilter;
2020
use OCA\Libresign\Service\Identify\ResultFormatter;
2121
use OCA\Libresign\Service\Identify\SearchNormalizer;
22+
use OCA\Libresign\Service\Identify\ShareTypeResolver;
2223
use OCA\Libresign\Service\Identify\SignerSearchContext;
23-
use OCA\Libresign\Service\IdentifyMethod\Account;
24-
use OCA\Libresign\Service\IdentifyMethod\Email;
2524
use OCP\AppFramework\Http;
2625
use OCP\AppFramework\Http\Attribute\ApiRoute;
2726
use OCP\AppFramework\Http\Attribute\NoAdminRequired;
2827
use OCP\AppFramework\Http\DataResponse;
2928
use OCP\Collaboration\Collaborators\ISearch;
3029
use OCP\IRequest;
31-
use OCP\Share\IShare;
3230

3331
/**
3432
* @psalm-import-type LibresignIdentifyAccount from ResponseDefinitions
3533
*/
3634
class IdentifyController extends AEnvironmentAwareController {
37-
private const PHONE_METHODS = ['whatsapp', 'sms', 'telegram', 'signal'];
38-
3935
public function __construct(
4036
IRequest $request,
4137
private ISearch $collaboratorSearch,
42-
private Email $identifyEmailMethod,
43-
private Account $identifyAccountMethod,
38+
private ShareTypeResolver $shareTypeResolver,
4439
private SearchNormalizer $searchNormalizer,
4540
private SignerSearchContext $signerSearchContext,
4641
private ResultFilter $resultFilter,
@@ -76,7 +71,7 @@ public function search(string $search = '', string $method = '', int $page = 1,
7671
return new DataResponse([]);
7772
}
7873

79-
$shareTypes = $this->getShareTypes();
74+
$shareTypes = $this->shareTypeResolver->resolve($method);
8075
$offset = $limit * ($page - 1);
8176

8277
$this->signerSearchContext->set($method, $search, $rawSearch);
@@ -112,21 +107,4 @@ private function registerPlugin(): void {
112107
$refProperty->setValue($this->collaboratorSearch, $plugins);
113108
}
114109

115-
private function getShareTypes(): array {
116-
$shareTypes = [];
117-
$settings = $this->identifyEmailMethod->getSettings();
118-
if ($settings['enabled']) {
119-
$shareTypes[] = IShare::TYPE_EMAIL;
120-
}
121-
$settings = $this->identifyAccountMethod->getSettings();
122-
if ($settings['enabled']) {
123-
$shareTypes[] = IShare::TYPE_USER;
124-
}
125-
126-
$shareTypes[] = SignerPlugin::TYPE_SIGNER;
127-
$shareTypes[] = AccountPhonePlugin::TYPE_SIGNER_ACCOUNT_PHONE;
128-
$shareTypes[] = ContactPhonePlugin::TYPE_SIGNER_CONTACT_PHONE;
129-
$shareTypes[] = ManualPhonePlugin::TYPE_SIGNER_MANUAL_PHONE;
130-
return $shareTypes;
131-
}
132110
}

lib/Controller/PageController.php

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,7 @@ public function index(): TemplateResponse {
111111
$this->initialState->provideInitialState('legal_information', $this->appConfig->getValueString(Application::APP_ID, 'legal_information'));
112112

113113
Util::addScript(Application::APP_ID, 'libresign-main');
114+
Util::addStyle(Application::APP_ID, 'libresign-main');
114115

115116
if (class_exists(LoadViewer::class)) {
116117
$this->eventDispatcher->dispatchTyped(new LoadViewer());
@@ -156,6 +157,7 @@ public function indexF(): TemplateResponse {
156157
#[FrontpageRoute(verb: 'GET', url: '/f/incomplete')]
157158
public function incomplete(): TemplateResponse {
158159
Util::addScript(Application::APP_ID, 'libresign-main');
160+
Util::addStyle(Application::APP_ID, 'libresign-main');
159161
$response = new TemplateResponse(Application::APP_ID, 'main');
160162
return $response;
161163
}
@@ -172,6 +174,7 @@ public function incomplete(): TemplateResponse {
172174
#[FrontpageRoute(verb: 'GET', url: '/p/incomplete')]
173175
public function incompleteP(): TemplateResponse {
174176
Util::addScript(Application::APP_ID, 'libresign-main');
177+
Util::addStyle(Application::APP_ID, 'libresign-main');
175178
$response = new TemplateResponse(Application::APP_ID, 'main', [], TemplateResponse::RENDER_AS_BASE);
176179
return $response;
177180
}
@@ -378,6 +381,7 @@ public function sign(string $uuid): TemplateResponse {
378381
$this->initialState->provideInitialState('nodeType', $this->getFileEntity()->getNodeType());
379382

380383
Util::addScript(Application::APP_ID, 'libresign-external');
384+
Util::addStyle(Application::APP_ID, 'libresign-external');
381385
if (class_exists(LoadViewer::class)) {
382386
$this->eventDispatcher->dispatchTyped(new LoadViewer());
383387
}
@@ -532,6 +536,7 @@ public function validation(): TemplateResponse {
532536
}
533537

534538
Util::addScript(Application::APP_ID, 'libresign-validation');
539+
Util::addStyle(Application::APP_ID, 'libresign-validation');
535540
$response = new TemplateResponse(Application::APP_ID, 'validation', [], TemplateResponse::RENDER_AS_BASE);
536541

537542
return $response;
@@ -580,6 +585,7 @@ public function resetPassword(): TemplateResponse {
580585
);
581586

582587
Util::addScript(Application::APP_ID, 'libresign-main');
588+
Util::addStyle(Application::APP_ID, 'libresign-main');
583589
$response = new TemplateResponse(Application::APP_ID, 'reset_password');
584590

585591
return $response;

lib/Files/TemplateLoader.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ public function handle(Event $event): void {
5858
}
5959

6060
Util::addScript(Application::APP_ID, 'libresign-tab');
61+
Util::addStyle(Application::APP_ID, 'libresign-tab');
6162
Util::addStyle(Application::APP_ID, 'icons');
6263
}
6364

lib/Middleware/InjectionMiddleware.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -317,6 +317,7 @@ public function afterException($controller, $methodName, \Exception $exception):
317317
}
318318

319319
Util::addScript(Application::APP_ID, 'libresign-' . $template);
320+
Util::addStyle(Application::APP_ID, 'libresign-' . $template);
320321
$response = new TemplateResponse(
321322
appName: Application::APP_ID,
322323
templateName: $template,

lib/Service/DocMdp/ConfigService.php

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -24,18 +24,23 @@ public function __construct(
2424
}
2525

2626
public function isEnabled(): bool {
27-
return $this->appConfig->hasKey(Application::APP_ID, self::CONFIG_KEY_LEVEL);
27+
return $this->getLevel()->isCertifying();
2828
}
2929

3030
public function setEnabled(bool $enabled): void {
31-
if (!$enabled) {
32-
$this->appConfig->deleteKey(Application::APP_ID, self::CONFIG_KEY_LEVEL);
31+
if ($enabled) {
32+
if (!$this->getLevel()->isCertifying()) {
33+
$this->setLevel(DocMdpLevel::CERTIFIED_FORM_FILLING);
34+
}
35+
return;
3336
}
37+
38+
$this->setLevel(DocMdpLevel::NOT_CERTIFIED);
3439
}
3540

3641
public function getLevel(): DocMdpLevel {
37-
$level = $this->appConfig->getValueInt(Application::APP_ID, self::CONFIG_KEY_LEVEL, DocMdpLevel::NOT_CERTIFIED->value);
38-
return DocMdpLevel::from($level);
42+
$level = $this->appConfig->getValueInt(Application::APP_ID, self::CONFIG_KEY_LEVEL, DocMdpLevel::CERTIFIED_FORM_FILLING->value);
43+
return DocMdpLevel::tryFrom($level) ?? DocMdpLevel::CERTIFIED_FORM_FILLING;
3944
}
4045

4146
public function setLevel(DocMdpLevel $level): void {

lib/Service/File/FileContentProvider.php

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -32,25 +32,32 @@ public function __construct(
3232
*/
3333
public function getContentFromUrl(string $url): string {
3434
if (!filter_var($url, FILTER_VALIDATE_URL)) {
35-
throw new \Exception($this->l10n->t('Invalid URL file'));
35+
throw new LibresignException($this->l10n->t('Invalid URL file'), 422);
3636
}
3737

3838
try {
3939
$response = $this->client->newClient()->get($url);
4040
} catch (\Throwable) {
41-
throw new \Exception($this->l10n->t('Invalid URL file'));
41+
throw new LibresignException($this->l10n->t('Invalid URL file'), 422);
4242
}
4343

44-
$mimetypeFromHeader = $response->getHeader('Content-Type');
4544
$content = (string)$response->getBody();
4645

4746
if (!$content) {
48-
throw new \Exception($this->l10n->t('Empty file'));
47+
throw new LibresignException($this->l10n->t('Empty file'), 422);
48+
}
49+
50+
$mimetypeFromHeader = $response->getHeader('Content-Type');
51+
// Strip parameters like "; charset=utf-8"
52+
if (str_contains($mimetypeFromHeader, ';')) {
53+
$mimetypeFromHeader = trim(explode(';', $mimetypeFromHeader)[0]);
4954
}
5055

5156
$mimeTypeFromContent = $this->mimeService->getMimeType($content);
52-
if ($mimetypeFromHeader !== $mimeTypeFromContent) {
53-
throw new \Exception($this->l10n->t('Invalid URL file'));
57+
58+
// application/octet-stream is a generic fallback — trust content detection
59+
if ($mimetypeFromHeader !== 'application/octet-stream' && $mimetypeFromHeader !== $mimeTypeFromContent) {
60+
throw new LibresignException($this->l10n->t('Invalid URL file'), 422);
5461
}
5562

5663
return $content;
@@ -75,7 +82,7 @@ public function getContentFromBase64(string $base64): string {
7582
$mimeTypeFromContent = $this->mimeService->getMimeType($content);
7683

7784
if ($mimeTypeFromType !== $mimeTypeFromContent) {
78-
throw new \Exception($this->l10n->t('Invalid URL file'));
85+
throw new LibresignException($this->l10n->t('Invalid URL file'), 422);
7986
}
8087

8188
$this->mimeService->setMimeType($mimeTypeFromContent);
@@ -103,7 +110,7 @@ public function getContentFromData(array $data): string {
103110
return $this->getContentFromBase64($data['file']['base64']);
104111
}
105112

106-
throw new \Exception($this->l10n->t('No file source provided'));
113+
throw new LibresignException($this->l10n->t('No file source provided'), 422);
107114
}
108115

109116
/**

0 commit comments

Comments
 (0)