Compare commits

..
12 Commits
124 changed files with 1711 additions and 40973 deletions
+23 -9
View File
@@ -185,22 +185,16 @@ jobs:
flags: frontend-node-${{ matrix.node-version }} flags: frontend-node-${{ matrix.node-version }}
directory: src-ui/coverage/ directory: src-ui/coverage/
e2e-tests: e2e-tests:
name: "E2E Tests (${{ matrix.shard-index }}/${{ matrix.shard-count }})" name: E2E Tests
needs: [changes, install-dependencies] needs: [changes, install-dependencies]
if: needs.changes.outputs.frontend_changed == 'true' if: needs.changes.outputs.frontend_changed == 'true'
runs-on: ubuntu-24.04 runs-on: ubuntu-24.04
permissions: permissions:
contents: read contents: read
container: mcr.microsoft.com/playwright:v1.62.0-noble container: mcr.microsoft.com/playwright:v1.62.1-noble
env: env:
PLAYWRIGHT_BROWSERS_PATH: /ms-playwright PLAYWRIGHT_BROWSERS_PATH: /ms-playwright
PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD: 1 PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD: 1
strategy:
fail-fast: false
matrix:
node-version: [24.x]
shard-index: [1, 2]
shard-count: [2]
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
@@ -216,6 +210,17 @@ jobs:
node-version: 24.x node-version: 24.x
cache: 'pnpm' cache: 'pnpm'
cache-dependency-path: 'src-ui/pnpm-lock.yaml' cache-dependency-path: 'src-ui/pnpm-lock.yaml'
- name: Set up Python
id: setup-python
uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
with:
python-version: '3.12'
- name: Install uv
uses: astral-sh/setup-uv@c771a70e6277c0a99b617c7a806ffedaca235ff9 # v9.0.0
with:
version: '0.12.x'
enable-cache: false
python-version: ${{ steps.setup-python.outputs.python-version }}
- name: Cache frontend dependencies - name: Cache frontend dependencies
uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
with: with:
@@ -225,8 +230,17 @@ jobs:
key: ${{ runner.os }}-frontend-${{ hashFiles('src-ui/pnpm-lock.yaml') }} key: ${{ runner.os }}-frontend-${{ hashFiles('src-ui/pnpm-lock.yaml') }}
- name: Install dependencies - name: Install dependencies
run: cd src-ui && pnpm install --frozen-lockfile run: cd src-ui && pnpm install --frozen-lockfile
- name: Install backend system dependencies
run: |
apt-get update
apt-get install --yes --quiet --no-install-recommends libmagic1
- name: Install backend dependencies
env:
PYTHON_VERSION: ${{ steps.setup-python.outputs.python-version }}
# The frozen repository lockfile and its build hooks are trusted.
run: uv sync --python "${PYTHON_VERSION}" --no-dev --frozen # NOSONAR
- name: Run Playwright E2E tests - name: Run Playwright E2E tests
run: cd src-ui && pnpm exec playwright test --shard ${{ matrix.shard-index }}/${{ matrix.shard-count }} run: cd src-ui && pnpm exec playwright test
frontend-build: frontend-build:
name: Frontend Build name: Frontend Build
needs: [changes, unit-tests, e2e-tests] needs: [changes, unit-tests, e2e-tests]
Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 MiB

After

Width:  |  Height:  |  Size: 1.4 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 501 KiB

After

Width:  |  Height:  |  Size: 487 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 21 KiB

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.2 MiB

After

Width:  |  Height:  |  Size: 558 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 644 KiB

After

Width:  |  Height:  |  Size: 1.1 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 667 KiB

After

Width:  |  Height:  |  Size: 1.4 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1003 KiB

After

Width:  |  Height:  |  Size: 1.2 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 MiB

After

Width:  |  Height:  |  Size: 1.4 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.1 MiB

After

Width:  |  Height:  |  Size: 1.5 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 MiB

After

Width:  |  Height:  |  Size: 1.4 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 925 KiB

After

Width:  |  Height:  |  Size: 972 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 MiB

After

Width:  |  Height:  |  Size: 1.4 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 MiB

After

Width:  |  Height:  |  Size: 1.4 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.3 MiB

After

Width:  |  Height:  |  Size: 558 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 726 KiB

After

Width:  |  Height:  |  Size: 1.3 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 169 KiB

After

Width:  |  Height:  |  Size: 294 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 432 KiB

After

Width:  |  Height:  |  Size: 298 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 280 KiB

After

Width:  |  Height:  |  Size: 322 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 246 KiB

After

Width:  |  Height:  |  Size: 205 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 27 KiB

After

Width:  |  Height:  |  Size: 43 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 29 KiB

After

Width:  |  Height:  |  Size: 44 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 48 KiB

After

Width:  |  Height:  |  Size: 57 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 45 KiB

After

Width:  |  Height:  |  Size: 65 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 559 KiB

After

Width:  |  Height:  |  Size: 516 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 116 KiB

After

Width:  |  Height:  |  Size: 230 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 87 KiB

After

Width:  |  Height:  |  Size: 333 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 792 KiB

After

Width:  |  Height:  |  Size: 1.2 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 137 KiB

After

Width:  |  Height:  |  Size: 291 KiB

+36
View File
@@ -1,5 +1,41 @@
# Changelog # Changelog
## paperless-ngx 3.1.1
### Bug Fixes
- Fix: 3.1.0 llm suggestions remove existing metadata from prompt, dont drop name suggestions [@shamoon](https://github.com/shamoon) ([#13866](https://github.com/paperless-ngx/paperless-ngx/pull/13866))
- Fix: set global search earlier to avoid awaiting debounce [@shamoon](https://github.com/shamoon) ([#13865](https://github.com/paperless-ngx/paperless-ngx/pull/13865))
- Fix: responsive sidebar, centralize and make sizes saner [@shamoon](https://github.com/shamoon) ([#13863](https://github.com/paperless-ngx/paperless-ngx/pull/13863))
- Tweak/fix: show existing count for ai suggestions [@shamoon](https://github.com/shamoon) ([#13861](https://github.com/paperless-ngx/paperless-ngx/pull/13861))
- Fix: 3.1.0 llm suggestions simplify schema, fix docstrings [@shamoon](https://github.com/shamoon) ([#13850](https://github.com/paperless-ngx/paperless-ngx/pull/13850))
- Fix: ensure ui reset of suggestionsLoading when changing docs [@shamoon](https://github.com/shamoon) ([#13840](https://github.com/paperless-ngx/paperless-ngx/pull/13840))
- Fix: always pass a non-empty api key for OpenAI-like servers [@shamoon](https://github.com/shamoon) ([#13838](https://github.com/paperless-ngx/paperless-ngx/pull/13838))
- Fix: hide slim sidebar scrollbar in browsers with stupid scrollbars [@shamoon](https://github.com/shamoon) ([#13837](https://github.com/paperless-ngx/paperless-ngx/pull/13837))
- Fix: correct sharelink bundle + document link permissions display bugs [@shamoon](https://github.com/shamoon) ([#13827](https://github.com/paperless-ngx/paperless-ngx/pull/13827))
- Fix: immediately re-add doc to index after trash restore [@shamoon](https://github.com/shamoon) ([#13818](https://github.com/paperless-ngx/paperless-ngx/pull/13818))
- Fix: navbar brand anchor size + Safari position jitter [@shamoon](https://github.com/shamoon) ([#13810](https://github.com/paperless-ngx/paperless-ngx/pull/13810))
### All App Changes
<details>
<summary>12 changes</summary>
- Fix: 3.1.0 llm suggestions remove existing metadata from prompt, dont drop name suggestions [@shamoon](https://github.com/shamoon) ([#13866](https://github.com/paperless-ngx/paperless-ngx/pull/13866))
- Fix: set global search earlier to avoid awaiting debounce [@shamoon](https://github.com/shamoon) ([#13865](https://github.com/paperless-ngx/paperless-ngx/pull/13865))
- Fix: responsive sidebar, centralize and make sizes saner [@shamoon](https://github.com/shamoon) ([#13863](https://github.com/paperless-ngx/paperless-ngx/pull/13863))
- Tweak/fix: show existing count for ai suggestions [@shamoon](https://github.com/shamoon) ([#13861](https://github.com/paperless-ngx/paperless-ngx/pull/13861))
- Fix: 3.1.0 llm suggestions simplify schema, fix docstrings [@shamoon](https://github.com/shamoon) ([#13850](https://github.com/paperless-ngx/paperless-ngx/pull/13850))
- Fixhancement: make imap port required, better error display [@shamoon](https://github.com/shamoon) ([#13845](https://github.com/paperless-ngx/paperless-ngx/pull/13845))
- Fix: ensure ui reset of suggestionsLoading when changing docs [@shamoon](https://github.com/shamoon) ([#13840](https://github.com/paperless-ngx/paperless-ngx/pull/13840))
- Fix: always pass a non-empty api key for OpenAI-like servers [@shamoon](https://github.com/shamoon) ([#13838](https://github.com/paperless-ngx/paperless-ngx/pull/13838))
- Fix: hide slim sidebar scrollbar in browsers with stupid scrollbars [@shamoon](https://github.com/shamoon) ([#13837](https://github.com/paperless-ngx/paperless-ngx/pull/13837))
- Fix: correct sharelink bundle + document link permissions display bugs [@shamoon](https://github.com/shamoon) ([#13827](https://github.com/paperless-ngx/paperless-ngx/pull/13827))
- Fix: immediately re-add doc to index after trash restore [@shamoon](https://github.com/shamoon) ([#13818](https://github.com/paperless-ngx/paperless-ngx/pull/13818))
- Fix: navbar brand anchor size + Safari position jitter [@shamoon](https://github.com/shamoon) ([#13810](https://github.com/paperless-ngx/paperless-ngx/pull/13810))
</details>
## paperless-ngx 3.1.0 ## paperless-ngx 3.1.0
### Features / Enhancements ### Features / Enhancements
+8 -2
View File
@@ -224,13 +224,19 @@ respectively, can be run non-interactively with:
```bash ```bash
pnpm ng test pnpm ng test
pnpm playwright test pnpm e2e
``` ```
The Playwright suite starts both the Angular development server and a disposable
Paperless instance on port 8001. The instance uses SQLite, temporary data and
media directories, and deterministic sample documents; it is removed when the
test run finishes. This requires the back-end Python dependencies from the
regular development setup to be installed with `uv sync`.
Playwright also includes a UI which can be run with: Playwright also includes a UI which can be run with:
```bash ```bash
pnpm playwright test --ui pnpm e2e:ui
``` ```
### Building the frontend ### Building the frontend
+1 -1
View File
@@ -1,6 +1,6 @@
[project] [project]
name = "paperless-ngx" name = "paperless-ngx"
version = "3.1.1" version = "3.1.2"
description = "A community-supported supercharged document management system: scan, index and archive all your physical documents" description = "A community-supported supercharged document management system: scan, index and archive all your physical documents"
readme = "README.md" readme = "README.md"
requires-python = ">=3.11" requires-python = ">=3.11"
+14
View File
@@ -139,6 +139,17 @@
} }
] ]
}, },
"e2e": {
"fileReplacements": [
{
"replace": "src/environments/environment.ts",
"with": "src/environments/environment.e2e.ts"
}
],
"localize": [
"en-US"
]
},
"en-US": { "en-US": {
"localize": [ "localize": [
"en-US" "en-US"
@@ -155,6 +166,9 @@
"configurations": { "configurations": {
"production": { "production": {
"buildTarget": "paperless-ui:build:production" "buildTarget": "paperless-ui:build:production"
},
"e2e": {
"buildTarget": "paperless-ui:build:e2e"
} }
} }
}, },
-194
View File
@@ -1,194 +0,0 @@
{
"log": {
"version": "1.2",
"creator": {
"name": "Playwright",
"version": "1.33.0"
},
"browser": {
"name": "chromium",
"version": "113.0.5672.53"
},
"entries": [
{
"startedDateTime": "2023-05-14T07:18:59.856Z",
"time": 6.025,
"request": {
"method": "GET",
"url": "http://localhost:8000/api/ui_settings/",
"httpVersion": "HTTP/1.1",
"cookies": [],
"headers": [
{ "name": "Accept", "value": "application/json; version=3" },
{ "name": "Accept-Encoding", "value": "gzip, deflate, br" },
{ "name": "Accept-Language", "value": "en-US" },
{ "name": "Connection", "value": "keep-alive" },
{ "name": "Host", "value": "localhost:8000" },
{ "name": "Origin", "value": "http://localhost:4200" },
{ "name": "Referer", "value": "http://localhost:4200/" },
{ "name": "Sec-Fetch-Dest", "value": "empty" },
{ "name": "Sec-Fetch-Mode", "value": "cors" },
{ "name": "Sec-Fetch-Site", "value": "same-site" },
{ "name": "User-Agent", "value": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/113.0.5672.53 Safari/537.36" }
],
"queryString": [],
"headersSize": -1,
"bodySize": -1
},
"response": {
"status": 200,
"statusText": "OK",
"httpVersion": "HTTP/1.1",
"cookies": [],
"headers": [
{ "name": "Access-Control-Allow-Origin", "value": "http://localhost:4200" },
{ "name": "Allow", "value": "GET, POST, HEAD, OPTIONS" },
{ "name": "Content-Encoding", "value": "br" },
{ "name": "Content-Language", "value": "en-us" },
{ "name": "Content-Length", "value": "953" },
{ "name": "Content-Type", "value": "application/json" },
{ "name": "Cross-Origin-Opener-Policy", "value": "same-origin" },
{ "name": "Referrer-Policy", "value": "same-origin" },
{ "name": "Vary", "value": "Accept, Accept-Language, Origin, Cookie, Accept-Encoding" },
{ "name": "X-Api-Version", "value": "3" },
{ "name": "X-Content-Type-Options", "value": "nosniff" },
{ "name": "X-Frame-Options", "value": "ANY" },
{ "name": "X-Version", "value": "1.14.4" }
],
"content": {
"size": -1,
"mimeType": "application/json",
"text": "{\"user\":{\"id\":2,\"username\":\"testuser\",\"is_superuser\":false,\"groups\":[]},\"settings\":{\"language\":\"\",\"bulk_edit\":{\"confirmation_dialogs\":true,\"apply_on_close\":false},\"documentListSize\":50,\"dark_mode\":{\"use_system\":true,\"enabled\":\"false\",\"thumb_inverted\":\"true\"},\"theme\":{\"color\":\"#9fbf2f\"},\"document_details\":{\"native_pdf_viewer\":false},\"date_display\":{\"date_locale\":\"\",\"date_format\":\"mediumDate\"},\"notifications\":{\"consumer_new_documents\":true,\"consumer_success\":true,\"consumer_failed\":true,\"consumer_suppress_on_dashboard\":true},\"comments_enabled\":true,\"slim_sidebar\":false,\"update_checking\":{\"enabled\":false,\"backend_setting\":\"default\"},\"saved_views\":{\"warn_on_unsaved_change\":true},\"notes_enabled\":true,\"tour_complete\":true},\"permissions\":[\"change_savedview\",\"change_schedule\",\"change_failure\",\"delete_token\",\"add_mailrule\",\"view_failure\",\"view_groupresult\",\"add_note\",\"change_taskresult\",\"view_tag\",\"view_user\",\"add_tag\",\"change_processedmail\",\"change_session\",\"view_taskattributes\",\"delete_groupresult\",\"delete_correspondent\",\"delete_schedule\",\"delete_contenttype\",\"view_chordcounter\",\"view_success\",\"delete_documenttype\",\"add_tokenproxy\",\"delete_paperlesstask\",\"add_log\",\"view_mailaccount\",\"add_uisettings\",\"view_savedview\",\"view_uisettings\",\"delete_storagepath\",\"delete_frontendsettings\",\"change_paperlesstask\",\"view_taskresult\",\"delete_processedmail\",\"view_processedmail\",\"view_session\",\"delete_chordcounter\",\"view_note\",\"delete_session\",\"view_document\",\"change_mailaccount\",\"delete_taskattributes\",\"add_groupobjectpermission\",\"view_mailrule\",\"change_savedviewfilterrule\",\"change_log\",\"change_comment\",\"add_mailaccount\",\"add_frontendsettings\",\"add_userobjectpermission\",\"delete_note\",\"view_token\",\"add_failure\",\"delete_user\",\"add_success\",\"view_ormq\",\"view_tokenproxy\",\"delete_uisettings\",\"change_groupobjectpermission\",\"add_logentry\",\"add_ormq\",\"view_frontendsettings\",\"view_schedule\",\"change_taskattributes\",\"view_documenttype\",\"view_logentry\",\"change_correspondent\",\"add_groupresult\",\"delete_groupobjectpermission\",\"change_mailrule\",\"change_permission\",\"delete_log\",\"view_userobjectpermission\",\"view_correspondent\",\"delete_document\",\"change_uisettings\",\"change_storagepath\",\"change_document\",\"delete_tokenproxy\",\"change_note\",\"delete_permission\",\"change_contenttype\",\"add_token\",\"change_success\",\"delete_logentry\",\"view_savedviewfilterrule\",\"delete_task\",\"add_savedview\",\"add_paperlesstask\",\"add_task\",\"change_documenttype\",\"add_documenttype\",\"change_token\",\"view_task\",\"view_permission\",\"change_task\",\"delete_userobjectpermission\",\"change_group\",\"add_group\",\"change_tag\",\"change_chordcounter\",\"add_storagepath\",\"delete_group\",\"add_taskattributes\",\"delete_mailaccount\",\"delete_tag\",\"add_schedule\",\"delete_failure\",\"delete_mailrule\",\"add_savedviewfilterrule\",\"change_ormq\",\"change_logentry\",\"add_taskresult\",\"view_group\",\"delete_comment\",\"add_contenttype\",\"add_document\",\"change_tokenproxy\",\"delete_success\",\"add_comment\",\"delete_ormq\",\"add_processedmail\",\"view_paperlesstask\",\"delete_savedview\",\"change_user\",\"add_session\",\"view_groupobjectpermission\",\"add_user\",\"add_correspondent\",\"delete_taskresult\",\"view_contenttype\",\"view_storagepath\",\"add_permission\",\"change_userobjectpermission\",\"delete_savedviewfilterrule\",\"change_groupresult\",\"add_chordcounter\",\"view_log\",\"view_comment\",\"change_frontendsettings\"]}"
},
"headersSize": -1,
"bodySize": -1,
"redirectURL": ""
},
"cache": {},
"timings": { "send": -1, "wait": -1, "receive": 6.025 }
},
{
"startedDateTime": "2023-05-14T07:18:59.990Z",
"time": 1.082,
"request": {
"method": "GET",
"url": "http://localhost:8000/api/saved_views/?page=1&page_size=100000",
"httpVersion": "HTTP/1.1",
"cookies": [],
"headers": [
{ "name": "Accept", "value": "application/json; version=3" },
{ "name": "Accept-Encoding", "value": "gzip, deflate, br" },
{ "name": "Accept-Language", "value": "en-US" },
{ "name": "Connection", "value": "keep-alive" },
{ "name": "Host", "value": "localhost:8000" },
{ "name": "Origin", "value": "http://localhost:4200" },
{ "name": "Referer", "value": "http://localhost:4200/" },
{ "name": "Sec-Fetch-Dest", "value": "empty" },
{ "name": "Sec-Fetch-Mode", "value": "cors" },
{ "name": "Sec-Fetch-Site", "value": "same-site" },
{ "name": "User-Agent", "value": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/113.0.5672.53 Safari/537.36" }
],
"queryString": [
{
"name": "page",
"value": "1"
},
{
"name": "page_size",
"value": "100000"
}
],
"headersSize": -1,
"bodySize": -1
},
"response": {
"status": 200,
"statusText": "OK",
"httpVersion": "HTTP/1.1",
"cookies": [],
"headers": [
{ "name": "Access-Control-Allow-Origin", "value": "http://localhost:4200" },
{ "name": "Allow", "value": "GET, POST, HEAD, OPTIONS" },
{ "name": "Content-Encoding", "value": "br" },
{ "name": "Content-Language", "value": "en-us" },
{ "name": "Content-Length", "value": "851" },
{ "name": "Content-Type", "value": "application/json" },
{ "name": "Cross-Origin-Opener-Policy", "value": "same-origin" },
{ "name": "Referrer-Policy", "value": "same-origin" },
{ "name": "Vary", "value": "Accept, Accept-Language, Origin, Cookie, Accept-Encoding" },
{ "name": "X-Api-Version", "value": "3" },
{ "name": "X-Content-Type-Options", "value": "nosniff" },
{ "name": "X-Frame-Options", "value": "ANY" },
{ "name": "X-Version", "value": "1.14.4" }
],
"content": {
"size": -1,
"mimeType": "application/json",
"text": "{\"count\":6,\"next\":null,\"previous\":null,\"all\":[8,17,7,4,11,15],\"results\":[{\"id\":8,\"name\":\"Correspondent 2\",\"show_on_dashboard\":false,\"show_in_sidebar\":false,\"sort_field\":\"created\",\"sort_reverse\":true,\"filter_rules\":[{\"rule_type\":3,\"value\":\"2\"}],\"owner\":\"2\",\"user_can_change\":true},{\"id\":17,\"name\":\"In the Last Month\",\"show_on_dashboard\":false,\"show_in_sidebar\":false,\"sort_field\":\"created\",\"sort_reverse\":true,\"filter_rules\":[{\"rule_type\":20,\"value\":\"created:[-1 month to now]\"}],\"owner\":\"2\",\"user_can_change\":true},{\"id\":7,\"name\":\"Inbox\",\"show_on_dashboard\":true,\"show_in_sidebar\":true,\"sort_field\":\"created\",\"sort_reverse\":true,\"filter_rules\":[{\"rule_type\":6,\"value\":\"9\"}],\"owner\":\"2\",\"user_can_change\":true},{\"id\":4,\"name\":\"Recently Added\",\"show_on_dashboard\":true,\"show_in_sidebar\":true,\"sort_field\":\"created\",\"sort_reverse\":true,\"filter_rules\":[],\"owner\":\"2\",\"user_can_change\":true},{\"id\":11,\"name\":\"Tag: Another Sample Tag\",\"show_on_dashboard\":false,\"show_in_sidebar\":true,\"sort_field\":\"created\",\"sort_reverse\":true,\"filter_rules\":[{\"rule_type\":6,\"value\":\"4\"}],\"owner\":\"2\",\"user_can_change\":true},{\"id\":15,\"name\":\"View ASN not empty\",\"show_on_dashboard\":false,\"show_in_sidebar\":false,\"sort_field\":\"created\",\"sort_reverse\":true,\"filter_rules\":[{\"rule_type\":18,\"value\":\"false\"}],\"owner\":\"2\",\"user_can_change\":true}]}"
},
"headersSize": -1,
"bodySize": -1,
"redirectURL": ""
},
"cache": {},
"timings": { "send": -1, "wait": -1, "receive": 1.082 }
},
{
"startedDateTime": "2023-05-14T07:18:59.990Z",
"time": 0.647,
"request": {
"method": "GET",
"url": "http://localhost:8000/api/tasks/",
"httpVersion": "HTTP/1.1",
"cookies": [],
"headers": [
{ "name": "Accept", "value": "application/json; version=3" },
{ "name": "Accept-Encoding", "value": "gzip, deflate, br" },
{ "name": "Accept-Language", "value": "en-US" },
{ "name": "Connection", "value": "keep-alive" },
{ "name": "Host", "value": "localhost:8000" },
{ "name": "Origin", "value": "http://localhost:4200" },
{ "name": "Referer", "value": "http://localhost:4200/" },
{ "name": "Sec-Fetch-Dest", "value": "empty" },
{ "name": "Sec-Fetch-Mode", "value": "cors" },
{ "name": "Sec-Fetch-Site", "value": "same-site" },
{ "name": "User-Agent", "value": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/113.0.5672.53 Safari/537.36" }
],
"queryString": [],
"headersSize": -1,
"bodySize": -1
},
"response": {
"status": 200,
"statusText": "OK",
"httpVersion": "HTTP/1.1",
"cookies": [],
"headers": [
{ "name": "Access-Control-Allow-Origin", "value": "http://localhost:4200" },
{ "name": "Allow", "value": "GET, HEAD, OPTIONS" },
{ "name": "Content-Language", "value": "en-us" },
{ "name": "Content-Length", "value": "2" },
{ "name": "Content-Type", "value": "application/json" },
{ "name": "Cross-Origin-Opener-Policy", "value": "same-origin" },
{ "name": "Referrer-Policy", "value": "same-origin" },
{ "name": "Vary", "value": "Accept, Accept-Language, Origin, Cookie" },
{ "name": "X-Api-Version", "value": "3" },
{ "name": "X-Content-Type-Options", "value": "nosniff" },
{ "name": "X-Frame-Options", "value": "ANY" },
{ "name": "X-Version", "value": "1.14.4" }
],
"content": {
"size": -1,
"mimeType": "application/json",
"text": "[]"
},
"headersSize": -1,
"bodySize": -1,
"redirectURL": ""
},
"cache": {},
"timings": { "send": -1, "wait": -1, "receive": 0.647 }
}
]
}
}
+16 -5
View File
@@ -1,12 +1,25 @@
import { expect, test } from '@playwright/test' import { expect, test } from '@playwright/test'
import path from 'node:path'
const REQUESTS_HAR = path.join(__dirname, 'requests/api-settings.har') test.beforeEach(async ({ page }) => {
await page.route('**/api/status/', (route) =>
route.fulfill({
json: {
database: { status: 'OK' },
tasks: {
redis_status: 'DISABLED',
celery_status: 'DISABLED',
index_status: 'OK',
classifier_status: 'OK',
sanity_check_status: 'OK',
},
},
})
)
})
test('should activate / deactivate save button when settings change', async ({ test('should activate / deactivate save button when settings change', async ({
page, page,
}) => { }) => {
await page.routeFromHAR(REQUESTS_HAR, { notFound: 'fallback' })
await page.goto('/settings') await page.goto('/settings')
await expect(page.getByRole('button', { name: 'Save' })).toBeDisabled() await expect(page.getByRole('button', { name: 'Save' })).toBeDisabled()
await page.getByLabel('Use system setting').click() await page.getByLabel('Use system setting').click()
@@ -15,7 +28,6 @@ test('should activate / deactivate save button when settings change', async ({
}) })
test('should warn on unsaved changes', async ({ page }) => { test('should warn on unsaved changes', async ({ page }) => {
await page.routeFromHAR(REQUESTS_HAR, { notFound: 'fallback' })
await page.goto('/settings') await page.goto('/settings')
await page.getByLabel('Use system setting').click() await page.getByLabel('Use system setting').click()
await page.getByRole('link', { name: 'Dashboard' }).click() await page.getByRole('link', { name: 'Dashboard' }).click()
@@ -27,7 +39,6 @@ test('should warn on unsaved changes', async ({ page }) => {
}) })
test('should apply appearance changes when set', async ({ page }) => { test('should apply appearance changes when set', async ({ page }) => {
await page.routeFromHAR(REQUESTS_HAR, { notFound: 'fallback' })
await page.goto('/settings') await page.goto('/settings')
await expect(page.locator('html')).toHaveAttribute('data-bs-theme', /auto/) await expect(page.locator('html')).toHaveAttribute('data-bs-theme', /auto/)
await page.getByLabel('Use system setting').click() await page.getByLabel('Use system setting').click()
+237
View File
@@ -0,0 +1,237 @@
"""Start a disposable Paperless instance for the Playwright test suite."""
# ruff: noqa: INP001, T201
from __future__ import annotations
import datetime
import logging
import logging.config
import os
import shutil
import sys
import tempfile
import time
from pathlib import Path
REPOSITORY_ROOT = Path(__file__).resolve().parents[2]
SOURCE_ROOT = REPOSITORY_ROOT / "src"
def configure_environment(instance_root: Path) -> None:
paths = {
"PAPERLESS_CONSUMPTION_DIR": instance_root / "consume",
"PAPERLESS_DATA_DIR": instance_root / "data",
"PAPERLESS_MEDIA_ROOT": instance_root / "media",
"PAPERLESS_SCRATCH_DIR": instance_root / "scratch",
}
for name, path in paths.items():
path.mkdir(parents=True)
os.environ[name] = str(path)
(paths["PAPERLESS_DATA_DIR"] / "index").mkdir()
os.environ.update(
{
"DJANGO_SETTINGS_MODULE": "paperless.settings",
"PAPERLESS_AI_ENABLED": "false",
"PAPERLESS_CHANNELS_BACKEND": "channels.layers.InMemoryChannelLayer",
"PAPERLESS_DEBUG": "true",
"PAPERLESS_SECRET_KEY": "playwright-only-not-a-real-secret",
},
)
sys.path.insert(0, str(SOURCE_ROOT))
def seed_database() -> None:
from django.contrib.auth.models import User
from django.core.management import call_command
from django.utils import timezone
from documents.models import Correspondent
from documents.models import Document
from documents.models import DocumentType
from documents.models import Note
from documents.models import SavedView
from documents.models import SavedViewFilterRule
from documents.models import StoragePath
from documents.models import Tag
from documents.models import UiSettings
# Fixed credentials are safe within this disposable, localhost-only instance.
admin = User.objects.create_superuser(
username="playwright",
password="playwright", # NOSONAR
)
User.objects.create_user(
username="viewer",
password="viewer", # NOSONAR
)
inbox = Tag.objects.create(name="Inbox", is_inbox_tag=True, owner=admin)
quick_filter = Tag.objects.create(name="Another Sample Tag", owner=admin)
Tag.objects.create(name="TagWithPartial", owner=admin)
invoice = DocumentType.objects.create(name="Invoice Test", owner=admin)
correspondent_1 = Correspondent.objects.create(
name="Test Correspondent 1",
owner=admin,
)
correspondent_2 = Correspondent.objects.create(name="Correspondent 9", owner=admin)
storage_path = StoragePath.objects.create(
name="Testing 12",
path="e2e/{created_year}/{title}",
owner=admin,
)
today = timezone.localdate()
documents = []
for number in range(1, 62):
title = f"test document {number}" if number <= 9 else f"document {number}"
content = (
f"Playwright test content for document {number}"
if number <= 32
else f"Seeded content for document {number}"
)
created = today if number == 1 else datetime.date(2021, 1, 1)
if number in (2, 3):
created = datetime.date(2022, 12, 11)
documents.append(
Document(
title=title,
content=content,
checksum=f"{number:064x}",
mime_type="application/pdf",
filename=f"{number:07}.pdf",
original_filename=f"document-{number}.pdf",
archive_serial_number=1122 + number if number <= 6 else None,
created=created,
owner=admin,
document_type=invoice if number <= 3 else None,
correspondent=(
correspondent_1
if number <= 4
else correspondent_2
if number <= 7
else None
),
storage_path=storage_path if number <= 8 else None,
),
)
Document.objects.bulk_create(documents)
originals = Path(os.environ["PAPERLESS_MEDIA_ROOT"]) / "documents" / "originals"
originals.mkdir(parents=True)
thumbnails = Path(os.environ["PAPERLESS_MEDIA_ROOT"]) / "documents" / "thumbnails"
thumbnails.mkdir(parents=True)
sample_pdf = SOURCE_ROOT / "documents" / "tests" / "samples" / "simple.pdf"
for document in documents:
shutil.copyfile(sample_pdf, originals / document.filename)
shutil.copyfile(
SOURCE_ROOT / "documents" / "resources" / "document.webp",
thumbnails / f"{document.pk:07}.webp",
)
for document in documents[:8]:
document.tags.add(inbox)
documents[0].tags.add(quick_filter)
for number in range(1, 5):
Note.objects.create(
note=f"Playwright note {number}",
document=documents[0],
user=admin,
)
inbox_view = SavedView.objects.create(
name="Inbox",
owner=admin,
sort_field="created",
sort_reverse=True,
page_size=10,
display_mode=SavedView.DisplayMode.TABLE,
display_fields=["created", "title", "tag", "documenttype"],
)
SavedViewFilterRule.objects.create(
saved_view=inbox_view,
rule_type=6,
value=str(inbox.pk),
)
UiSettings.objects.create(
user=admin,
settings={
"language": "",
"bulk_edit": {"confirmation_dialogs": True, "apply_on_close": False},
"documentListSize": 50,
"dark_mode": {
"use_system": True,
"enabled": False,
"thumb_inverted": True,
},
"theme": {"color": "#9fbf2f"},
"document_details": {"native_pdf_viewer": False},
"date_display": {"date_locale": "", "date_format": "mediumDate"},
"comments_enabled": True,
"slim_sidebar": False,
"update_checking": {"enabled": False},
"saved_views": {
"warn_on_unsaved_change": True,
"dashboard_views_visible_ids": [inbox_view.pk],
"sidebar_views_visible_ids": [inbox_view.pk],
},
"notes_enabled": True,
"tour_complete": True,
},
)
call_command(
"document_index",
"reindex",
recreate=True,
heap_size_mb=16,
verbosity=0,
)
def main() -> None:
started = time.monotonic()
with tempfile.TemporaryDirectory(prefix="paperless-playwright-") as instance:
configure_environment(Path(instance))
os.chdir(SOURCE_ROOT)
print("Loading the Paperless backend...", flush=True)
import django
django.setup()
from django.conf import settings
from django.core.management import call_command
settings.CELERY_TASK_ALWAYS_EAGER = True
settings.CELERY_TASK_EAGER_PROPAGATES = True
print("Migrating the disposable database...", flush=True)
call_command("migrate", interactive=False, verbosity=0)
print("Seeding Playwright data...", flush=True)
seed_database()
elapsed = time.monotonic() - started
print(f"Playwright backend ready in {elapsed:.1f}s", flush=True)
settings.LOGGING["handlers"]["console"]["level"] = "WARNING"
settings.LOGGING["handlers"]["playwright_null"] = {
"class": "logging.NullHandler",
}
settings.LOGGING["loggers"]["django.server"] = {
"handlers": ["playwright_null"],
"propagate": False,
}
logging.config.dictConfig(settings.LOGGING)
call_command(
"runserver",
"localhost:8001",
use_reloader=False,
verbosity=1,
)
if __name__ == "__main__":
main()
+3 -14
View File
@@ -1,21 +1,13 @@
import { expect, test } from '@playwright/test' import { expect, test } from '@playwright/test'
import path from 'node:path'
const REQUESTS_HAR1 = path.join(__dirname, 'requests/api-dashboard1.har')
const REQUESTS_HAR2 = path.join(__dirname, 'requests/api-dashboard2.har')
const REQUESTS_HAR3 = path.join(__dirname, 'requests/api-dashboard3.har')
const REQUESTS_HAR4 = path.join(__dirname, 'requests/api-dashboard4.har')
test('dashboard inbox link', async ({ page }) => { test('dashboard inbox link', async ({ page }) => {
await page.routeFromHAR(REQUESTS_HAR1, { notFound: 'fallback' })
await page.goto('/dashboard') await page.goto('/dashboard')
await page.getByRole('link', { name: 'Documents in inbox' }).click() await page.getByRole('link', { name: 'Documents in inbox' }).click()
await expect(page).toHaveURL(/tags__id__in=9/) await expect(page).toHaveURL(/tags__id__in=1/)
await expect(page.locator('pngx-document-list')).toHaveText(/8 documents/) await expect(page.locator('pngx-document-list')).toHaveText(/8 documents/)
}) })
test('dashboard total documents link', async ({ page }) => { test('dashboard total documents link', async ({ page }) => {
await page.routeFromHAR(REQUESTS_HAR2, { notFound: 'fallback' })
await page.goto('/dashboard') await page.goto('/dashboard')
await page.getByRole('link').filter({ hasText: 'Total documents' }).click() await page.getByRole('link').filter({ hasText: 'Total documents' }).click()
await expect(page).toHaveURL(/documents/) await expect(page).toHaveURL(/documents/)
@@ -24,7 +16,6 @@ test('dashboard total documents link', async ({ page }) => {
}) })
test('dashboard saved view show all', async ({ page }) => { test('dashboard saved view show all', async ({ page }) => {
await page.routeFromHAR(REQUESTS_HAR3, { notFound: 'fallback' })
await page.goto('/dashboard') await page.goto('/dashboard')
await page await page
.locator('pngx-widget-frame') .locator('pngx-widget-frame')
@@ -32,12 +23,11 @@ test('dashboard saved view show all', async ({ page }) => {
.getByRole('link', { name: 'Show all' }) .getByRole('link', { name: 'Show all' })
.first() .first()
.click() .click()
await expect(page).toHaveURL(/view\/7/) await expect(page).toHaveURL(/view\/1/)
await expect(page.locator('pngx-document-list')).toHaveText(/8 documents/) await expect(page.locator('pngx-document-list')).toHaveText(/8 documents/)
}) })
test('dashboard saved view document links', async ({ page }) => { test('dashboard saved view document links', async ({ page }) => {
await page.routeFromHAR(REQUESTS_HAR4, { notFound: 'fallback' })
await page.goto('/dashboard') await page.goto('/dashboard')
await page await page
.locator('pngx-widget-frame') .locator('pngx-widget-frame')
@@ -46,11 +36,10 @@ test('dashboard saved view document links', async ({ page }) => {
.getByRole('link', { name: /test/ }) .getByRole('link', { name: /test/ })
.first() .first()
.click({ position: { x: 0, y: 0 } }) .click({ position: { x: 0, y: 0 } })
await expect(page).toHaveURL(/documents\/310\/details/) await expect(page).toHaveURL(/documents\/1\/details/)
}) })
test('test slim sidebar', async ({ page }) => { test('test slim sidebar', async ({ page }) => {
await page.routeFromHAR(REQUESTS_HAR1, { notFound: 'fallback' })
await page.goto('/dashboard') await page.goto('/dashboard')
await page.locator('.sidebar-slim-toggler').click() await page.locator('.sidebar-slim-toggler').click()
await expect( await expect(
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1,14 +1,9 @@
import { expect, test, type WebSocketRoute } from '@playwright/test' import { expect, test } from '@playwright/test'
import path from 'node:path'
const REQUESTS_HAR = path.join(__dirname, 'requests/api-document-detail.har')
const REQUESTS_HAR2 = path.join(__dirname, 'requests/api-document-detail2.har')
test('should activate / deactivate save button when changes are saved', async ({ test('should activate / deactivate save button when changes are saved', async ({
page, page,
}) => { }) => {
await page.routeFromHAR(REQUESTS_HAR, { notFound: 'fallback' }) await page.goto('/documents/1/')
await page.goto('/documents/175/')
await page.waitForSelector('pngx-document-detail pngx-input-text:first-child') await page.waitForSelector('pngx-document-detail pngx-input-text:first-child')
await expect(page.getByTitle('Storage path', { exact: true })).toHaveText( await expect(page.getByTitle('Storage path', { exact: true })).toHaveText(
/\w+/ /\w+/
@@ -19,8 +14,7 @@ test('should activate / deactivate save button when changes are saved', async ({
}) })
test('should warn on unsaved changes', async ({ page }) => { test('should warn on unsaved changes', async ({ page }) => {
await page.routeFromHAR(REQUESTS_HAR, { notFound: 'fallback' }) await page.goto('/documents/1/')
await page.goto('/documents/175/')
await expect(page.getByTitle('Correspondent', { exact: true })).toHaveText( await expect(page.getByTitle('Correspondent', { exact: true })).toHaveText(
/\w+/ /\w+/
) )
@@ -38,28 +32,27 @@ test('should warn on unsaved changes', async ({ page }) => {
}) })
test('should support tab direct navigation', async ({ page }) => { test('should support tab direct navigation', async ({ page }) => {
await page.routeFromHAR(REQUESTS_HAR, { notFound: 'fallback' }) await page.goto('/documents/1/details')
await page.goto('/documents/175/details')
await expect(page.getByRole('tab', { name: 'Details' })).toHaveAttribute( await expect(page.getByRole('tab', { name: 'Details' })).toHaveAttribute(
'aria-selected', 'aria-selected',
'true' 'true'
) )
await page.goto('/documents/175/content') await page.goto('/documents/1/content')
await expect(page.getByRole('tab', { name: 'Content' })).toHaveAttribute( await expect(page.getByRole('tab', { name: 'Content' })).toHaveAttribute(
'aria-selected', 'aria-selected',
'true' 'true'
) )
await page.goto('/documents/175/metadata') await page.goto('/documents/1/metadata')
await expect(page.getByRole('tab', { name: 'Metadata' })).toHaveAttribute( await expect(page.getByRole('tab', { name: 'Metadata' })).toHaveAttribute(
'aria-selected', 'aria-selected',
'true' 'true'
) )
await page.goto('/documents/175/notes') await page.goto('/documents/1/notes')
await expect(page.getByRole('tab', { name: 'Notes' })).toHaveAttribute( await expect(page.getByRole('tab', { name: 'Notes' })).toHaveAttribute(
'aria-selected', 'aria-selected',
'true' 'true'
) )
await page.goto('/documents/175/permissions') await page.goto('/documents/1/permissions')
await expect(page.getByRole('tab', { name: 'Permissions' })).toHaveAttribute( await expect(page.getByRole('tab', { name: 'Permissions' })).toHaveAttribute(
'aria-selected', 'aria-selected',
'true' 'true'
@@ -67,8 +60,7 @@ test('should support tab direct navigation', async ({ page }) => {
}) })
test('should show a mobile preview', async ({ page }) => { test('should show a mobile preview', async ({ page }) => {
await page.routeFromHAR(REQUESTS_HAR, { notFound: 'fallback' }) await page.goto('/documents/1/')
await page.goto('/documents/175/')
await page.setViewportSize({ width: 400, height: 1000 }) await page.setViewportSize({ width: 400, height: 1000 })
await expect(page.getByRole('tab', { name: 'Preview' })).toBeVisible() await expect(page.getByRole('tab', { name: 'Preview' })).toBeVisible()
await page.getByRole('tab', { name: 'Preview' }).click() await page.getByRole('tab', { name: 'Preview' }).click()
@@ -76,8 +68,7 @@ test('should show a mobile preview', async ({ page }) => {
}) })
test('should show a list of notes', async ({ page }) => { test('should show a list of notes', async ({ page }) => {
await page.routeFromHAR(REQUESTS_HAR, { notFound: 'fallback' }) await page.goto('/documents/1/notes')
await page.goto('/documents/175/notes')
await expect(page.locator('pngx-document-notes')).toBeVisible() await expect(page.locator('pngx-document-notes')).toBeVisible()
await expect( await expect(
await page.getByRole('button', { await page.getByRole('button', {
@@ -88,32 +79,25 @@ test('should show a list of notes', async ({ page }) => {
}) })
test('should support quick filters', async ({ page }) => { test('should support quick filters', async ({ page }) => {
await page.routeFromHAR(REQUESTS_HAR2, { notFound: 'fallback' }) await page.goto('/documents/1/details')
await page.goto('/documents/175/details')
await page await page
.getByRole('button', { name: 'Filter documents with these Tags' }) .getByRole('button', { name: 'Filter documents with these Tags' })
.click() .click()
await expect(page).toHaveURL(/tags__id__all=4&sort=created&reverse=1&page=1/) await expect(page).toHaveURL(
/tags__id__all=2,1&sort=created&reverse=1&page=1/
)
}) })
test('should finish reloading the preview after a remote document update', async ({ test('should finish reloading the preview after a remote document update', async ({
page, page,
}) => { }) => {
let resolveStatusSocket: (socket: WebSocketRoute) => void
const statusSocketReady = new Promise<WebSocketRoute>((resolve) => {
resolveStatusSocket = resolve
})
await page.routeWebSocket(/\/ws\/status\/$/, (socket) => {
resolveStatusSocket(socket)
})
await page.routeFromHAR(REQUESTS_HAR, { notFound: 'fallback' })
let previewRequestCount = 0 let previewRequestCount = 0
page.on('request', (request) => { page.on('request', (request) => {
if (request.url().includes('/api/documents/175/preview/')) { if (request.url().includes('/api/documents/1/preview/')) {
previewRequestCount++ previewRequestCount++
} }
}) })
await page.goto('/documents/175/details') await page.goto('/documents/1/details')
await page.locator('pngx-document-detail').waitFor() await page.locator('pngx-document-detail').waitFor()
await expect(page.getByTitle('Storage path', { exact: true })).toHaveText( await expect(page.getByTitle('Storage path', { exact: true })).toHaveText(
@@ -128,27 +112,37 @@ test('should finish reloading the preview after a remote document update', async
expect(previewWasLoaded).toBe(true) expect(previewWasLoaded).toBe(true)
const previewRequestsBeforeReload = previewRequestCount const previewRequestsBeforeReload = previewRequestCount
const statusSocket = await statusSocketReady await expect
.poll(() =>
page.evaluate(() => {
const detail = document.querySelector('pngx-document-detail')
return (window as any).ng.getComponent(detail).networkActive()
})
)
.toBe(false)
const documentReloaded = page.waitForResponse( const documentReloaded = page.waitForResponse(
(response) => (response) =>
response.url().includes('/api/documents/175/?full_perms=true') && response.url().includes('/api/documents/1/?full_perms=true') &&
response.request().method() === 'GET' response.request().method() === 'GET'
) )
statusSocket.send( await page.evaluate(() => {
JSON.stringify({ const detail = document.querySelector('pngx-document-detail')
type: 'document_updated', const component = (window as any).ng.getComponent(detail)
data: { component.handleIncomingDocumentUpdated({
document_id: 175, document_id: 1,
modified: '2026-07-26T20:00:00Z', modified: '2099-07-26T20:00:00Z',
},
}) })
) })
await documentReloaded await documentReloaded
await expect(
page.getByText('Document reloaded with latest changes.').first()
).toBeVisible()
await expect await expect
.poll(() => previewRequestCount) .poll(() => previewRequestCount)
.toBeGreaterThan(previewRequestsBeforeReload + 1) .toBeGreaterThan(previewRequestsBeforeReload)
await expect
.poll(() =>
page.evaluate(() => {
const detail = document.querySelector('pngx-document-detail')
return (window as any).ng.getComponent(detail).previewLoaded()
})
)
.toBe(true)
}) })
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+41 -31
View File
@@ -1,19 +1,10 @@
import { expect, test } from '@playwright/test' import { expect, test } from '@playwright/test'
import path from 'node:path'
const REQUESTS_HAR1 = path.join(__dirname, 'requests/api-document-list1.har')
const REQUESTS_HAR2 = path.join(__dirname, 'requests/api-document-list2.har')
const REQUESTS_HAR3 = path.join(__dirname, 'requests/api-document-list3.har')
const REQUESTS_HAR4 = path.join(__dirname, 'requests/api-document-list4.har')
const REQUESTS_HAR5 = path.join(__dirname, 'requests/api-document-list5.har')
const REQUESTS_HAR6 = path.join(__dirname, 'requests/api-document-list6.har')
test('basic filtering', async ({ page }) => { test('basic filtering', async ({ page }) => {
await page.routeFromHAR(REQUESTS_HAR1, { notFound: 'fallback' })
await page.goto('/documents') await page.goto('/documents')
await page.getByRole('button', { name: 'Tags' }).click() await page.getByRole('button', { name: 'Tags' }).click()
await page.getByRole('menuitem', { name: 'Inbox' }).click() await page.getByRole('menuitem', { name: 'Inbox' }).click()
await expect(page).toHaveURL(/tags__id__all=9/) await expect(page).toHaveURL(/tags__id__all=1/)
await expect(page.locator('pngx-document-list')).toHaveText(/8 documents/) await expect(page.locator('pngx-document-list')).toHaveText(/8 documents/)
await page.getByRole('button', { name: 'Document type' }).click() await page.getByRole('button', { name: 'Document type' }).click()
await page.getByRole('menuitem', { name: /^Invoice Test/ }).click() await page.getByRole('menuitem', { name: /^Invoice Test/ }).click()
@@ -23,28 +14,27 @@ test('basic filtering', async ({ page }) => {
await page.getByRole('button', { name: 'Correspondent' }).click() await page.getByRole('button', { name: 'Correspondent' }).click()
await page.getByRole('menuitem', { name: 'Test Correspondent 1' }).click() await page.getByRole('menuitem', { name: 'Test Correspondent 1' }).click()
await page.getByRole('menuitem', { name: 'Correspondent 9' }).click() await page.getByRole('menuitem', { name: 'Correspondent 9' }).click()
await expect(page).toHaveURL(/correspondent__id__in=12,1/) await expect(page).toHaveURL(/correspondent__id__in=(?:1,2|2,1)/)
await expect(page.locator('pngx-document-list')).toHaveText(/7 documents/) await expect(page.locator('pngx-document-list')).toHaveText(/7 documents/)
await page await page
.locator('pngx-filter-editor') .locator('pngx-filter-editor')
.getByTitle('Correspondent') .getByTitle('Correspondent')
.getByText('Exclude') .getByText('Exclude')
.click() .click()
await expect(page).toHaveURL(/correspondent__id__none=12,1/) await expect(page).toHaveURL(/correspondent__id__none=(?:1,2|2,1)/)
await expect(page.locator('pngx-document-list')).toHaveText(/54 documents/) await expect(page.locator('pngx-document-list')).toHaveText(/54 documents/)
// clear button // clear button
await page.getByRole('button', { name: '2 selected', exact: true }).click() await page.getByRole('button', { name: '2 selected', exact: true }).click()
await expect(page.locator('pngx-document-list')).toHaveText(/61 documents/) await expect(page.locator('pngx-document-list')).toHaveText(/61 documents/)
await page.getByRole('button', { name: 'Storage path' }).click() await page.getByRole('button', { name: 'Storage path' }).click()
await page.getByRole('menuitem', { name: 'Testing 12' }).click() await page.getByRole('menuitem', { name: 'Testing 12' }).click()
await expect(page).toHaveURL(/storage_path__id__in=5/) await expect(page).toHaveURL(/storage_path__id__in=1/)
await expect(page.locator('pngx-document-list')).toHaveText(/8 documents/) await expect(page.locator('pngx-document-list')).toHaveText(/8 documents/)
await page.getByRole('button', { name: 'Reset filters' }).first().click() await page.getByRole('button', { name: 'Reset filters' }).first().click()
await expect(page.locator('pngx-document-list')).toHaveText(/61 documents/) await expect(page.locator('pngx-document-list')).toHaveText(/61 documents/)
}) })
test('text filtering', async ({ page }) => { test('text filtering', async ({ page }) => {
await page.routeFromHAR(REQUESTS_HAR2, { notFound: 'fallback' })
await page.goto('/documents') await page.goto('/documents')
await page.getByRole('main').getByRole('combobox').click() await page.getByRole('main').getByRole('combobox').click()
await page.getByRole('main').getByRole('combobox').fill('test') await page.getByRole('main').getByRole('combobox').fill('test')
@@ -57,7 +47,7 @@ test('text filtering', async ({ page }) => {
await page.getByRole('button', { name: 'Title', exact: true }).click() await page.getByRole('button', { name: 'Title', exact: true }).click()
await page.getByRole('button', { name: 'Advanced search' }).click() await page.getByRole('button', { name: 'Advanced search' }).click()
await expect(page).toHaveURL(/query=test/) await expect(page).toHaveURL(/query=test/)
await expect(page.locator('pngx-document-list')).toHaveText(/26 documents/) await expect(page.locator('pngx-document-list')).toHaveText(/32 documents/)
await page.getByRole('button', { name: 'Advanced search' }).click() await page.getByRole('button', { name: 'Advanced search' }).click()
await page.getByRole('button', { name: 'ASN' }).click() await page.getByRole('button', { name: 'ASN' }).click()
await page.getByRole('main').getByRole('combobox').nth(1).fill('1123') await page.getByRole('main').getByRole('combobox').nth(1).fill('1123')
@@ -80,7 +70,6 @@ test('text filtering', async ({ page }) => {
}) })
test('date filtering', async ({ page }) => { test('date filtering', async ({ page }) => {
await page.routeFromHAR(REQUESTS_HAR3, { notFound: 'fallback' })
await page.goto('/documents') await page.goto('/documents')
await page.getByRole('button', { name: 'Dates' }).click() await page.getByRole('button', { name: 'Dates' }).click()
await page.locator('.ng-arrow-wrapper').first().click() await page.locator('.ng-arrow-wrapper').first().click()
@@ -94,15 +83,14 @@ test('date filtering', async ({ page }) => {
await page.getByRole('option', { name: 'Within 3 months' }).click() await page.getByRole('option', { name: 'Within 3 months' }).click()
await page.getByLabel('Dates selected').locator('button').first().click() await page.getByLabel('Dates selected').locator('button').first().click()
await page.getByLabel('Dates selected').locator('button').first().click() await page.getByLabel('Dates selected').locator('button').first().click()
await page.getByRole('combobox', { name: 'Select month' }).selectOption('12') const createdFrom = page.getByRole('textbox', { name: 'mm/dd/yyyy' }).first()
await page.getByRole('combobox', { name: 'Select year' }).selectOption('2022') await createdFrom.fill('12/11/2022')
await page.getByText('11', { exact: true }).click() await createdFrom.press('Enter')
await page.getByRole('button', { name: 'Title & content' }).click() await page.getByRole('button', { name: 'Title & content' }).click()
await expect(page.locator('pngx-document-list')).toHaveText(/2 documents/) await expect(page.locator('pngx-document-list')).toHaveText(/3 documents/)
}) })
test('sorting', async ({ page }) => { test('sorting', async ({ page }) => {
await page.routeFromHAR(REQUESTS_HAR4, { notFound: 'fallback' })
await page.goto('/documents') await page.goto('/documents')
await page.getByRole('button', { name: 'Sort' }).click() await page.getByRole('button', { name: 'Sort' }).click()
await page.getByRole('button', { name: 'ASN' }).click() await page.getByRole('button', { name: 'ASN' }).click()
@@ -140,7 +128,6 @@ test('sorting', async ({ page }) => {
}) })
test('change views', async ({ page }) => { test('change views', async ({ page }) => {
await page.routeFromHAR(REQUESTS_HAR5, { notFound: 'fallback' })
await page.goto('/documents') await page.goto('/documents')
await page.locator('.btn-group > label').first().click() await page.locator('.btn-group > label').first().click()
await expect(page.locator('pngx-document-list table')).toBeVisible() await expect(page.locator('pngx-document-list table')).toBeVisible()
@@ -151,12 +138,18 @@ test('change views', async ({ page }) => {
}) })
test('bulk edit', async ({ page }) => { test('bulk edit', async ({ page }) => {
await page.routeFromHAR(REQUESTS_HAR6, { notFound: 'fallback' }) const uiSettingsLoaded = page.waitForResponse(
(response) => response.url().includes('/api/ui_settings/') && response.ok()
)
await page.goto('/documents') await page.goto('/documents')
await uiSettingsLoaded
await page.locator('pngx-document-card-small').nth(0).click()
await page await page
.locator('pngx-document-card-small') .locator('pngx-document-card-small .doc-img-container')
.nth(0)
.click()
await page
.locator('pngx-document-card-small .doc-img-container')
.nth(3) .nth(3)
.click({ .click({
modifiers: ['Shift'], modifiers: ['Shift'],
@@ -176,8 +169,14 @@ test('bulk edit', async ({ page }) => {
) )
await page.getByRole('button', { name: 'None' }).click() await page.getByRole('button', { name: 'None' }).click()
await page.locator('pngx-document-card-small').nth(1).click() await page
await page.locator('pngx-document-card-small').nth(2).click() .locator('pngx-document-card-small .doc-img-container')
.nth(1)
.click()
await page
.locator('pngx-document-card-small .doc-img-container')
.nth(2)
.click()
await page.getByRole('button', { name: 'Tags' }).click() await page.getByRole('button', { name: 'Tags' }).click()
await page await page
@@ -185,15 +184,26 @@ test('bulk edit', async ({ page }) => {
.fill('TagWithPartial') .fill('TagWithPartial')
await page.getByRole('menuitem', { name: 'TagWithPartial' }).click() await page.getByRole('menuitem', { name: 'TagWithPartial' }).click()
await page.getByRole('button', { name: 'Apply' }).click()
const bulkEditPromise = page.waitForRequest((request) => { const bulkEditPromise = page.waitForRequest((request) => {
if (
!request.url().includes('/api/documents/bulk_edit/') ||
request.method() !== 'POST'
) {
return false
}
const postData = request.postDataJSON() const postData = request.postDataJSON()
let isValid = postData['method'] == 'modify_tags' let isValid = postData['method'] == 'modify_tags'
isValid = isValid && postData['parameters']['add_tags'].includes(5) isValid =
return request.url().toString().includes('bulk_edit') && isValid isValid &&
[
...postData['parameters']['add_tags'],
...postData['parameters']['remove_tags'],
].includes(3)
return isValid
}) })
await page.getByRole('button', { name: 'Apply' }).click()
await expect(page.getByRole('button', { name: 'Confirm' })).toBeVisible()
await page.getByRole('button', { name: 'Confirm' }).click() await page.getByRole('button', { name: 'Confirm' }).click()
await bulkEditPromise await bulkEditPromise
}) })
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1,10 +1,12 @@
import { expect, test } from '@playwright/test' import { expect, test } from '@playwright/test'
import path from 'node:path'
const REQUESTS_HAR = path.join(__dirname, 'requests/api-global-permissions.har') test.use({
extraHTTPHeaders: {
Authorization: `Basic ${Buffer.from('viewer:viewer').toString('base64')}`,
},
})
test('should not allow user to edit settings', async ({ page }) => { test('should not allow user to edit settings', async ({ page }) => {
await page.routeFromHAR(REQUESTS_HAR, { notFound: 'fallback' })
await page.goto('/dashboard') await page.goto('/dashboard')
await expect(page.getByRole('link', { name: 'Settings' })).not.toBeAttached() await expect(page.getByRole('link', { name: 'Settings' })).not.toBeAttached()
await page.goto('/settings') await page.goto('/settings')
@@ -14,7 +16,6 @@ test('should not allow user to edit settings', async ({ page }) => {
}) })
test('should not allow user to view documents', async ({ page }) => { test('should not allow user to view documents', async ({ page }) => {
await page.routeFromHAR(REQUESTS_HAR, { notFound: 'fallback' })
await page.goto('/dashboard') await page.goto('/dashboard')
await expect( await expect(
page.locator('nav').getByRole('link', { name: 'Documents' }) page.locator('nav').getByRole('link', { name: 'Documents' })
@@ -30,7 +31,6 @@ test('should not allow user to view documents', async ({ page }) => {
}) })
test('should not allow user to view correspondents', async ({ page }) => { test('should not allow user to view correspondents', async ({ page }) => {
await page.routeFromHAR(REQUESTS_HAR, { notFound: 'fallback' })
await page.goto('/dashboard') await page.goto('/dashboard')
await expect( await expect(
page.getByRole('link', { name: 'Attributes' }) page.getByRole('link', { name: 'Attributes' })
@@ -42,7 +42,6 @@ test('should not allow user to view correspondents', async ({ page }) => {
}) })
test('should not allow user to view tags', async ({ page }) => { test('should not allow user to view tags', async ({ page }) => {
await page.routeFromHAR(REQUESTS_HAR, { notFound: 'fallback' })
await page.goto('/dashboard') await page.goto('/dashboard')
await expect( await expect(
page.getByRole('link', { name: 'Attributes' }) page.getByRole('link', { name: 'Attributes' })
@@ -54,7 +53,6 @@ test('should not allow user to view tags', async ({ page }) => {
}) })
test('should not allow user to view document types', async ({ page }) => { test('should not allow user to view document types', async ({ page }) => {
await page.routeFromHAR(REQUESTS_HAR, { notFound: 'fallback' })
await page.goto('/dashboard') await page.goto('/dashboard')
await expect( await expect(
page.getByRole('link', { name: 'Attributes' }) page.getByRole('link', { name: 'Attributes' })
@@ -66,7 +64,6 @@ test('should not allow user to view document types', async ({ page }) => {
}) })
test('should not allow user to view storage paths', async ({ page }) => { test('should not allow user to view storage paths', async ({ page }) => {
await page.routeFromHAR(REQUESTS_HAR, { notFound: 'fallback' })
await page.goto('/dashboard') await page.goto('/dashboard')
await expect( await expect(
page.getByRole('link', { name: 'Attributes' }) page.getByRole('link', { name: 'Attributes' })
@@ -78,7 +75,6 @@ test('should not allow user to view storage paths', async ({ page }) => {
}) })
test('should not allow user to view logs', async ({ page }) => { test('should not allow user to view logs', async ({ page }) => {
await page.routeFromHAR(REQUESTS_HAR, { notFound: 'fallback' })
await page.goto('/dashboard') await page.goto('/dashboard')
await expect(page.getByRole('link', { name: 'Logs' })).not.toBeAttached() await expect(page.getByRole('link', { name: 'Logs' })).not.toBeAttached()
await page.goto('/logs') await page.goto('/logs')
@@ -88,7 +84,6 @@ test('should not allow user to view logs', async ({ page }) => {
}) })
test('should not allow user to view tasks', async ({ page }) => { test('should not allow user to view tasks', async ({ page }) => {
await page.routeFromHAR(REQUESTS_HAR, { notFound: 'fallback' })
await page.goto('/dashboard') await page.goto('/dashboard')
await expect(page.getByRole('link', { name: 'Tasks' })).not.toBeAttached() await expect(page.getByRole('link', { name: 'Tasks' })).not.toBeAttached()
await page.goto('/tasks') await page.goto('/tasks')
@@ -1,353 +0,0 @@
{
"log": {
"version": "1.2",
"creator": {
"name": "Playwright",
"version": "1.33.0"
},
"browser": {
"name": "chromium",
"version": "113.0.5672.53"
},
"entries": [
{
"startedDateTime": "2023-05-14T07:16:51.455Z",
"time": 5.787,
"request": {
"method": "GET",
"url": "http://localhost:8000/api/ui_settings/",
"httpVersion": "HTTP/1.1",
"cookies": [],
"headers": [
{ "name": "Accept", "value": "application/json; version=3" },
{ "name": "Accept-Encoding", "value": "gzip, deflate, br" },
{ "name": "Accept-Language", "value": "en-US" },
{ "name": "Connection", "value": "keep-alive" },
{ "name": "Host", "value": "localhost:8000" },
{ "name": "Origin", "value": "http://localhost:4200" },
{ "name": "Referer", "value": "http://localhost:4200/" },
{ "name": "Sec-Fetch-Dest", "value": "empty" },
{ "name": "Sec-Fetch-Mode", "value": "cors" },
{ "name": "Sec-Fetch-Site", "value": "same-site" },
{ "name": "User-Agent", "value": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/113.0.5672.53 Safari/537.36" }
],
"queryString": [],
"headersSize": -1,
"bodySize": -1
},
"response": {
"status": 200,
"statusText": "OK",
"httpVersion": "HTTP/1.1",
"cookies": [],
"headers": [
{ "name": "Access-Control-Allow-Origin", "value": "http://localhost:4200" },
{ "name": "Allow", "value": "GET, POST, HEAD, OPTIONS" },
{ "name": "Content-Encoding", "value": "br" },
{ "name": "Content-Language", "value": "en-us" },
{ "name": "Content-Length", "value": "385" },
{ "name": "Content-Type", "value": "application/json" },
{ "name": "Cross-Origin-Opener-Policy", "value": "same-origin" },
{ "name": "Referrer-Policy", "value": "same-origin" },
{ "name": "Vary", "value": "Accept, Accept-Language, Origin, Cookie, Accept-Encoding" },
{ "name": "X-Api-Version", "value": "3" },
{ "name": "X-Content-Type-Options", "value": "nosniff" },
{ "name": "X-Frame-Options", "value": "ANY" },
{ "name": "X-Version", "value": "1.14.4" }
],
"content": {
"size": -1,
"mimeType": "application/json",
"text": "{\"user\":{\"id\":2,\"username\":\"testuser\",\"is_superuser\":false,\"groups\":[]},\"settings\":{\"language\":\"\",\"bulk_edit\":{\"confirmation_dialogs\":true,\"apply_on_close\":false},\"documentListSize\":50,\"dark_mode\":{\"use_system\":false,\"enabled\":\"false\",\"thumb_inverted\":\"true\"},\"theme\":{\"color\":\"#9fbf2f\"},\"document_details\":{\"native_pdf_viewer\":false},\"date_display\":{\"date_locale\":\"\",\"date_format\":\"mediumDate\"},\"notifications\":{\"consumer_new_documents\":true,\"consumer_success\":true,\"consumer_failed\":true,\"consumer_suppress_on_dashboard\":true},\"comments_enabled\":true,\"slim_sidebar\":false,\"update_checking\":{\"enabled\":false,\"backend_setting\":\"default\"},\"saved_views\":{\"warn_on_unsaved_change\":true},\"notes_enabled\":true,\"tour_complete\":true},\"permissions\":[]}"
},
"headersSize": -1,
"bodySize": -1,
"redirectURL": ""
},
"cache": {},
"timings": { "send": -1, "wait": -1, "receive": 5.787 }
},
{
"startedDateTime": "2023-05-14T07:16:51.578Z",
"time": 0.566,
"request": {
"method": "GET",
"url": "http://localhost:8000/api/tasks/",
"httpVersion": "HTTP/1.1",
"cookies": [],
"headers": [
{ "name": "Accept", "value": "application/json; version=3" },
{ "name": "Accept-Encoding", "value": "gzip, deflate, br" },
{ "name": "Accept-Language", "value": "en-US" },
{ "name": "Connection", "value": "keep-alive" },
{ "name": "Host", "value": "localhost:8000" },
{ "name": "Origin", "value": "http://localhost:4200" },
{ "name": "Referer", "value": "http://localhost:4200/" },
{ "name": "Sec-Fetch-Dest", "value": "empty" },
{ "name": "Sec-Fetch-Mode", "value": "cors" },
{ "name": "Sec-Fetch-Site", "value": "same-site" },
{ "name": "User-Agent", "value": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/113.0.5672.53 Safari/537.36" }
],
"queryString": [],
"headersSize": -1,
"bodySize": -1
},
"response": {
"status": 200,
"statusText": "OK",
"httpVersion": "HTTP/1.1",
"cookies": [],
"headers": [
{ "name": "Access-Control-Allow-Origin", "value": "http://localhost:4200" },
{ "name": "Allow", "value": "GET, HEAD, OPTIONS" },
{ "name": "Content-Language", "value": "en-us" },
{ "name": "Content-Length", "value": "2" },
{ "name": "Content-Type", "value": "application/json" },
{ "name": "Cross-Origin-Opener-Policy", "value": "same-origin" },
{ "name": "Referrer-Policy", "value": "same-origin" },
{ "name": "Vary", "value": "Accept, Accept-Language, Origin, Cookie" },
{ "name": "X-Api-Version", "value": "3" },
{ "name": "X-Content-Type-Options", "value": "nosniff" },
{ "name": "X-Frame-Options", "value": "ANY" },
{ "name": "X-Version", "value": "1.14.4" }
],
"content": {
"size": -1,
"mimeType": "application/json",
"text": "[]"
},
"headersSize": -1,
"bodySize": -1,
"redirectURL": ""
},
"cache": {},
"timings": { "send": -1, "wait": -1, "receive": 0.566 }
},
{
"startedDateTime": "2023-05-14T07:16:51.578Z",
"time": 0.452,
"request": {
"method": "GET",
"url": "http://localhost:8000/api/statistics/",
"httpVersion": "HTTP/1.1",
"cookies": [],
"headers": [
{ "name": "Accept", "value": "application/json; version=3" },
{ "name": "Accept-Encoding", "value": "gzip, deflate, br" },
{ "name": "Accept-Language", "value": "en-US" },
{ "name": "Connection", "value": "keep-alive" },
{ "name": "Host", "value": "localhost:8000" },
{ "name": "Origin", "value": "http://localhost:4200" },
{ "name": "Referer", "value": "http://localhost:4200/" },
{ "name": "Sec-Fetch-Dest", "value": "empty" },
{ "name": "Sec-Fetch-Mode", "value": "cors" },
{ "name": "Sec-Fetch-Site", "value": "same-site" },
{ "name": "User-Agent", "value": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/113.0.5672.53 Safari/537.36" }
],
"queryString": [],
"headersSize": -1,
"bodySize": -1
},
"response": {
"status": 200,
"statusText": "OK",
"httpVersion": "HTTP/1.1",
"cookies": [],
"headers": [
{ "name": "Access-Control-Allow-Origin", "value": "http://localhost:4200" },
{ "name": "Allow", "value": "GET, HEAD, OPTIONS" },
{ "name": "Content-Language", "value": "en-us" },
{ "name": "Content-Length", "value": "257" },
{ "name": "Content-Type", "value": "application/json" },
{ "name": "Cross-Origin-Opener-Policy", "value": "same-origin" },
{ "name": "Referrer-Policy", "value": "same-origin" },
{ "name": "Vary", "value": "Accept, Accept-Language, Origin, Cookie" },
{ "name": "X-Api-Version", "value": "3" },
{ "name": "X-Content-Type-Options", "value": "nosniff" },
{ "name": "X-Frame-Options", "value": "ANY" },
{ "name": "X-Version", "value": "1.14.4" }
],
"content": {
"size": -1,
"mimeType": "application/json",
"text": "{\"documents_total\":61,\"documents_inbox\":8,\"inbox_tag\":9,\"document_file_type_counts\":[{\"mime_type\":\"application/pdf\",\"mime_type_count\":57},{\"mime_type\":\"text/plain\",\"mime_type_count\":3},{\"mime_type\":\"text/csv\",\"mime_type_count\":1}],\"character_count\":2407053}"
},
"headersSize": -1,
"bodySize": -1,
"redirectURL": ""
},
"cache": {},
"timings": { "send": -1, "wait": -1, "receive": 0.452 }
},
{
"startedDateTime": "2023-05-14T07:16:51.691Z",
"time": 0.891,
"request": {
"method": "GET",
"url": "http://localhost:8000/api/ui_settings/",
"httpVersion": "HTTP/1.1",
"cookies": [],
"headers": [
{ "name": "Accept", "value": "application/json; version=3" },
{ "name": "Accept-Encoding", "value": "gzip, deflate, br" },
{ "name": "Accept-Language", "value": "en-US" },
{ "name": "Connection", "value": "keep-alive" },
{ "name": "Host", "value": "localhost:8000" },
{ "name": "Origin", "value": "http://localhost:4200" },
{ "name": "Referer", "value": "http://localhost:4200/" },
{ "name": "Sec-Fetch-Dest", "value": "empty" },
{ "name": "Sec-Fetch-Mode", "value": "cors" },
{ "name": "Sec-Fetch-Site", "value": "same-site" },
{ "name": "User-Agent", "value": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/113.0.5672.53 Safari/537.36" }
],
"queryString": [],
"headersSize": -1,
"bodySize": -1
},
"response": {
"status": 200,
"statusText": "OK",
"httpVersion": "HTTP/1.1",
"cookies": [],
"headers": [
{ "name": "Access-Control-Allow-Origin", "value": "http://localhost:4200" },
{ "name": "Allow", "value": "GET, POST, HEAD, OPTIONS" },
{ "name": "Content-Encoding", "value": "br" },
{ "name": "Content-Language", "value": "en-us" },
{ "name": "Content-Length", "value": "385" },
{ "name": "Content-Type", "value": "application/json" },
{ "name": "Cross-Origin-Opener-Policy", "value": "same-origin" },
{ "name": "Referrer-Policy", "value": "same-origin" },
{ "name": "Vary", "value": "Accept, Accept-Language, Origin, Cookie, Accept-Encoding" },
{ "name": "X-Api-Version", "value": "3" },
{ "name": "X-Content-Type-Options", "value": "nosniff" },
{ "name": "X-Frame-Options", "value": "ANY" },
{ "name": "X-Version", "value": "1.14.4" }
],
"content": {
"size": -1,
"mimeType": "application/json",
"text": "{\"user\":{\"id\":2,\"username\":\"testuser\",\"is_superuser\":false,\"groups\":[]},\"settings\":{\"language\":\"\",\"bulk_edit\":{\"confirmation_dialogs\":true,\"apply_on_close\":false},\"documentListSize\":50,\"dark_mode\":{\"use_system\":false,\"enabled\":\"false\",\"thumb_inverted\":\"true\"},\"theme\":{\"color\":\"#9fbf2f\"},\"document_details\":{\"native_pdf_viewer\":false},\"date_display\":{\"date_locale\":\"\",\"date_format\":\"mediumDate\"},\"notifications\":{\"consumer_new_documents\":true,\"consumer_success\":true,\"consumer_failed\":true,\"consumer_suppress_on_dashboard\":true},\"comments_enabled\":true,\"slim_sidebar\":false,\"update_checking\":{\"enabled\":false,\"backend_setting\":\"default\"},\"saved_views\":{\"warn_on_unsaved_change\":true},\"notes_enabled\":true,\"tour_complete\":true},\"permissions\":[]}"
},
"headersSize": -1,
"bodySize": -1,
"redirectURL": ""
},
"cache": {},
"timings": { "send": -1, "wait": -1, "receive": 0.891 }
},
{
"startedDateTime": "2023-05-14T07:16:51.739Z",
"time": 0.405,
"request": {
"method": "GET",
"url": "http://localhost:8000/api/tasks/",
"httpVersion": "HTTP/1.1",
"cookies": [],
"headers": [
{ "name": "Accept", "value": "application/json; version=3" },
{ "name": "Accept-Encoding", "value": "gzip, deflate, br" },
{ "name": "Accept-Language", "value": "en-US" },
{ "name": "Connection", "value": "keep-alive" },
{ "name": "Host", "value": "localhost:8000" },
{ "name": "Origin", "value": "http://localhost:4200" },
{ "name": "Referer", "value": "http://localhost:4200/" },
{ "name": "Sec-Fetch-Dest", "value": "empty" },
{ "name": "Sec-Fetch-Mode", "value": "cors" },
{ "name": "Sec-Fetch-Site", "value": "same-site" },
{ "name": "User-Agent", "value": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/113.0.5672.53 Safari/537.36" }
],
"queryString": [],
"headersSize": -1,
"bodySize": -1
},
"response": {
"status": 200,
"statusText": "OK",
"httpVersion": "HTTP/1.1",
"cookies": [],
"headers": [
{ "name": "Access-Control-Allow-Origin", "value": "http://localhost:4200" },
{ "name": "Allow", "value": "GET, HEAD, OPTIONS" },
{ "name": "Content-Language", "value": "en-us" },
{ "name": "Content-Length", "value": "2" },
{ "name": "Content-Type", "value": "application/json" },
{ "name": "Cross-Origin-Opener-Policy", "value": "same-origin" },
{ "name": "Referrer-Policy", "value": "same-origin" },
{ "name": "Vary", "value": "Accept, Accept-Language, Origin, Cookie" },
{ "name": "X-Api-Version", "value": "3" },
{ "name": "X-Content-Type-Options", "value": "nosniff" },
{ "name": "X-Frame-Options", "value": "ANY" },
{ "name": "X-Version", "value": "1.14.4" }
],
"content": {
"size": -1,
"mimeType": "application/json",
"text": "[]"
},
"headersSize": -1,
"bodySize": -1,
"redirectURL": ""
},
"cache": {},
"timings": { "send": -1, "wait": -1, "receive": 0.405 }
},
{
"startedDateTime": "2023-05-14T07:16:51.739Z",
"time": 0.665,
"request": {
"method": "GET",
"url": "http://localhost:8000/api/statistics/",
"httpVersion": "HTTP/1.1",
"cookies": [],
"headers": [
{ "name": "Accept", "value": "application/json; version=3" },
{ "name": "Accept-Encoding", "value": "gzip, deflate, br" },
{ "name": "Accept-Language", "value": "en-US" },
{ "name": "Connection", "value": "keep-alive" },
{ "name": "Host", "value": "localhost:8000" },
{ "name": "Origin", "value": "http://localhost:4200" },
{ "name": "Referer", "value": "http://localhost:4200/" },
{ "name": "Sec-Fetch-Dest", "value": "empty" },
{ "name": "Sec-Fetch-Mode", "value": "cors" },
{ "name": "Sec-Fetch-Site", "value": "same-site" },
{ "name": "User-Agent", "value": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/113.0.5672.53 Safari/537.36" }
],
"queryString": [],
"headersSize": -1,
"bodySize": -1
},
"response": {
"status": 200,
"statusText": "OK",
"httpVersion": "HTTP/1.1",
"cookies": [],
"headers": [
{ "name": "Access-Control-Allow-Origin", "value": "http://localhost:4200" },
{ "name": "Allow", "value": "GET, HEAD, OPTIONS" },
{ "name": "Content-Language", "value": "en-us" },
{ "name": "Content-Length", "value": "257" },
{ "name": "Content-Type", "value": "application/json" },
{ "name": "Cross-Origin-Opener-Policy", "value": "same-origin" },
{ "name": "Referrer-Policy", "value": "same-origin" },
{ "name": "Vary", "value": "Accept, Accept-Language, Origin, Cookie" },
{ "name": "X-Api-Version", "value": "3" },
{ "name": "X-Content-Type-Options", "value": "nosniff" },
{ "name": "X-Frame-Options", "value": "ANY" },
{ "name": "X-Version", "value": "1.14.4" }
],
"content": {
"size": -1,
"mimeType": "application/json",
"text": "{\"documents_total\":61,\"documents_inbox\":8,\"inbox_tag\":9,\"document_file_type_counts\":[{\"mime_type\":\"application/pdf\",\"mime_type_count\":57},{\"mime_type\":\"text/plain\",\"mime_type_count\":3},{\"mime_type\":\"text/csv\",\"mime_type_count\":1}],\"character_count\":2407053}"
},
"headersSize": -1,
"bodySize": -1,
"redirectURL": ""
},
"cache": {},
"timings": { "send": -1, "wait": -1, "receive": 0.665 }
}
]
}
}
+5 -1
View File
@@ -1,11 +1,15 @@
{ {
"name": "paperless-ngx-ui", "name": "paperless-ngx-ui",
"version": "3.1.1", "version": "3.1.2",
"scripts": { "scripts": {
"preinstall": "npx only-allow pnpm", "preinstall": "npx only-allow pnpm",
"ng": "ng", "ng": "ng",
"start": "ng serve", "start": "ng serve",
"build": "ng build", "build": "ng build",
"e2e": "playwright test",
"e2e:backend": "uv run --project .. --no-sync python e2e/backend.py",
"e2e:ui": "playwright test --ui",
"start:e2e": "ng serve --configuration=e2e",
"test": "ng test", "test": "ng test",
"lint": "ng lint" "lint": "ng lint"
}, },
+17 -9
View File
@@ -14,17 +14,25 @@ export default defineConfig({
forbidOnly: !!process.env.CI, forbidOnly: !!process.env.CI,
/* Retry on CI only */ /* Retry on CI only */
retries: process.env.CI ? 3 : 0, retries: process.env.CI ? 3 : 0,
/* Opt out of parallel tests on CI. */ /* Keep parallelism modest for the shared SQLite backend. */
workers: process.env.CI ? 1 : undefined, workers: 2,
/* Reporter to use. See https://playwright.dev/docs/test-reporters */ /* Reporter to use. See https://playwright.dev/docs/test-reporters */
reporter: 'html', reporter: 'html',
/* Run your local dev server before starting the tests */ /* Run the disposable backend and local UI before starting the tests. */
webServer: { webServer: [
port, {
command: 'pnpm run start', url: 'http://localhost:8001/accounts/login/',
reuseExistingServer: !process.env.CI, command: 'npm run e2e:backend',
timeout: 2 * 60 * 1000, reuseExistingServer: false,
}, timeout: 2 * 60 * 1000,
},
{
port,
command: 'npm run start:e2e',
reuseExistingServer: !process.env.CI,
timeout: 2 * 60 * 1000,
},
],
/* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */ /* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */
use: { use: {
/* Base URL to use in actions like `await page.goto('/')`. */ /* Base URL to use in actions like `await page.goto('/')`. */
@@ -3,6 +3,7 @@
<div class="d-flex flex-wrap flex-row gap-2 w-100 mh-1" style="min-height: 1em;" <div class="d-flex flex-wrap flex-row gap-2 w-100 mh-1" style="min-height: 1em;"
cdkDropList #selectedList="cdkDropList" cdkDropList #selectedList="cdkDropList"
cdkDropListOrientation="mixed" cdkDropListOrientation="mixed"
[cdkDropListDisabled]="disabled"
(cdkDropListDropped)="drop($event)" (cdkDropListDropped)="drop($event)"
[cdkDropListConnectedTo]="[unselectedList]"> [cdkDropListConnectedTo]="[unselectedList]">
@for (item of selectedItems; track item.id) { @for (item of selectedItems; track item.id) {
@@ -17,6 +18,7 @@
<div class="d-flex flex-wrap flex-row gap-2 w-100" style="min-height: 1em;" <div class="d-flex flex-wrap flex-row gap-2 w-100" style="min-height: 1em;"
cdkDropList #unselectedList="cdkDropList" cdkDropList #unselectedList="cdkDropList"
cdkDropListOrientation="mixed" cdkDropListOrientation="mixed"
[cdkDropListDisabled]="disabled"
(cdkDropListDropped)="drop($event)" (cdkDropListDropped)="drop($event)"
[cdkDropListConnectedTo]="[selectedList]"> [cdkDropListConnectedTo]="[selectedList]">
@for (item of unselectedItems; track item.id) { @for (item of unselectedItems; track item.id) {
@@ -1,3 +1,11 @@
.badge { .badge {
cursor: move; cursor: move;
} }
.cdk-drop-list-disabled {
cursor: not-allowed !important;
* {
pointer-events: none !important;
}
}
@@ -98,4 +98,29 @@ describe('DragDropSelectComponent', () => {
{ id: '3', name: 'Item 3' }, { id: '3', name: 'Item 3' },
]) ])
}) })
it('should disable drag and drop when the control is disabled', () => {
component.items = [
{ id: '1', name: 'Item 1' },
{ id: '2', name: 'Item 2' },
]
component.writeValue(['1', '2'])
component.setDisabledState(true)
fixture.detectChanges()
expect(component.selectedList.disabled).toBe(true)
expect(component.unselectedList.disabled).toBe(true)
component.drop({
previousContainer: component.selectedList,
container: component.selectedList,
previousIndex: 0,
currentIndex: 1,
} as any)
expect(component.selectedItems).toEqual([
{ id: '1', name: 'Item 1' },
{ id: '2', name: 'Item 2' },
])
})
}) })
@@ -46,6 +46,8 @@ export class DragDropSelectComponent extends AbstractInputComponent<string[]> {
} }
public drop(event: CdkDragDrop<string[]>) { public drop(event: CdkDragDrop<string[]>) {
if (this.disabled) return
if ( if (
event.previousContainer === event.container && event.previousContainer === event.container &&
event.container === this.selectedList event.container === this.selectedList
@@ -14,7 +14,7 @@
</div> </div>
<div class="d-none d-sm-flex flex-fill me-3"> <div class="d-none d-sm-flex flex-fill me-3">
<div class="input-group input-group-sm"> <div class="input-group input-group-sm">
<span class="input-group-text border-0" i18n>Select:</span> <span class="input-group-text bg-transparent border-0" i18n>Select:</span>
</div> </div>
<div class="btn-group btn-group-sm flex-nowrap"> <div class="btn-group btn-group-sm flex-nowrap">
@if (list.hasSelection) { @if (list.hasSelection) {
@@ -61,7 +61,7 @@
</div> </div>
<div class="col"> <div class="col">
<label class="form-label" for="display_mode_{{view.id}}" i18n>Display as</label> <label class="form-label" for="display_mode_{{view.id}}" i18n>Display as</label>
<select class="form-select" formControlName="display_mode"> <select class="form-select form-control" formControlName="display_mode">
<option [ngValue]="DisplayMode.TABLE" i18n>Table</option> <option [ngValue]="DisplayMode.TABLE" i18n>Table</option>
<option [ngValue]="DisplayMode.SMALL_CARDS" i18n>Small Cards</option> <option [ngValue]="DisplayMode.SMALL_CARDS" i18n>Small Cards</option>
<option [ngValue]="DisplayMode.LARGE_CARDS" i18n>Large Cards</option> <option [ngValue]="DisplayMode.LARGE_CARDS" i18n>Large Cards</option>
@@ -0,0 +1,13 @@
export const DEFAULT_APP_TITLE = 'Paperless-ngx'
export const environment = {
production: false,
apiBaseUrl: 'http://localhost:8001/api/',
apiVersion: '10',
appTitle: DEFAULT_APP_TITLE,
tag: 'e2e',
version: 'E2E',
webSocketHost: 'localhost:8001',
webSocketProtocol: 'ws:',
webSocketBaseUrl: '/ws/',
}
+1 -1
View File
@@ -8,7 +8,7 @@ export const environment = {
apiVersion: '10', // match src/paperless/settings.py apiVersion: '10', // match src/paperless/settings.py
appTitle: DEFAULT_APP_TITLE, appTitle: DEFAULT_APP_TITLE,
tag: 'prod', tag: 'prod',
version: '3.1.1', version: '3.1.2',
webSocketHost: window.location.host, webSocketHost: window.location.host,
webSocketProtocol: window.location.protocol == 'https:' ? 'wss:' : 'ws:', webSocketProtocol: window.location.protocol == 'https:' ? 'wss:' : 'ws:',
webSocketBaseUrl: base_url.pathname + 'ws/', webSocketBaseUrl: base_url.pathname + 'ws/',
+2
View File
@@ -103,6 +103,8 @@ $form-check-radio-checked-bg-image-dark: url("data:image/svg+xml,%3csvg xmlns='h
--bs-danger-rgb: 183, 22, 49; --bs-danger-rgb: 183, 22, 49;
--bs-body-bg: #161618; --bs-body-bg: #161618;
--bs-body-bg-rgb: 22, 22, 24; --bs-body-bg-rgb: 22, 22, 24;
--bs-secondary-bg: var(--pngx-bg-disabled);
--bs-secondary-bg-rgb: 36, 37, 41;
--bs-light: #1c1c1f; --bs-light: #1c1c1f;
--bs-light-rgb: 28, 28, 31; --bs-light-rgb: 28, 28, 31;
--bs-info: var(--pngx-bg-alt); --bs-info: var(--pngx-bg-alt);
+9
View File
@@ -25,6 +25,7 @@ from documents.data_models import DocumentMetadataOverrides
from documents.file_handling import create_source_path_directory from documents.file_handling import create_source_path_directory
from documents.file_handling import generate_filename from documents.file_handling import generate_filename
from documents.file_handling import generate_unique_filename from documents.file_handling import generate_unique_filename
from documents.file_handling import validate_path_in_root
from documents.loggers import LoggingMixin from documents.loggers import LoggingMixin
from documents.models import Correspondent from documents.models import Correspondent
from documents.models import CustomField from documents.models import CustomField
@@ -695,6 +696,10 @@ class ConsumerPlugin(
use_format=False, use_format=False,
) )
document.filename = generated_filename document.filename = generated_filename
validate_path_in_root(
document.source_path,
settings.ORIGINALS_DIR,
)
create_source_path_directory(document.source_path) create_source_path_directory(document.source_path)
self._write( self._write(
@@ -727,6 +732,10 @@ class ConsumerPlugin(
use_format=False, use_format=False,
) )
document.archive_filename = generated_archive_filename document.archive_filename = generated_archive_filename
validate_path_in_root(
document.archive_path,
settings.ARCHIVE_DIR,
)
create_source_path_directory(document.archive_path) create_source_path_directory(document.archive_path)
self._write( self._write(
archive_path, archive_path,
+29
View File
@@ -1,12 +1,33 @@
import logging
import os import os
from pathlib import Path from pathlib import Path
from django.conf import settings from django.conf import settings
from documents.models import Document from documents.models import Document
from documents.templating.filepath import is_safe_relative_path
from documents.templating.filepath import validate_filepath_template_and_render from documents.templating.filepath import validate_filepath_template_and_render
from documents.templating.utils import convert_format_str_to_template_format from documents.templating.utils import convert_format_str_to_template_format
logger = logging.getLogger("paperless.filehandling")
class UnsafeFilePathError(Exception):
"""
Raised when a path generated for a document would land outside of its root.
"""
def validate_path_in_root(path: Path, root: Path) -> None:
"""
Ensures the given absolute path is contained within root, the
equivalent guard for the later move.
"""
if not path.resolve().is_relative_to(root.resolve()):
msg = f"Refusing to write file outside of root {root}: {path}."
logger.warning(msg)
raise UnsafeFilePathError(msg)
def create_source_path_directory(source_path: Path) -> None: def create_source_path_directory(source_path: Path) -> None:
source_path.parent.mkdir(parents=True, exist_ok=True) source_path.parent.mkdir(parents=True, exist_ok=True)
@@ -121,6 +142,14 @@ def format_filename(document: Document, template_str: str) -> str | None:
"none", "none",
) # backward compatibility ) # backward compatibility
# Validate again after remove none
if not is_safe_relative_path(rendered_filename):
logger.warning(
"Filename became unsafe after placeholder removal, "
"falling back to default naming",
)
return None
return rendered_filename return rendered_filename
+3
View File
@@ -81,6 +81,7 @@ from documents.permissions import get_document_count_filter_for_user
from documents.permissions import get_groups_with_only_permission from documents.permissions import get_groups_with_only_permission
from documents.permissions import has_perms_owner_aware from documents.permissions import has_perms_owner_aware
from documents.permissions import permitted_document_ids from documents.permissions import permitted_document_ids
from documents.permissions import restrict_queryset_to_visible
from documents.permissions import set_permissions_for_object from documents.permissions import set_permissions_for_object
from documents.regex import validate_regex_pattern from documents.regex import validate_regex_pattern
from documents.templating.filepath import validate_filepath_template_and_render from documents.templating.filepath import validate_filepath_template_and_render
@@ -661,6 +662,8 @@ class TagSerializer(MatchingModelSerializer, OwnedObjectSerializer):
.select_related("owner") .select_related("owner")
.annotate(document_count=Count("documents", filter=filter_q)) .annotate(document_count=Count("documents", filter=filter_q))
) )
user = getattr(request, "user", None) if request else self.user
children = restrict_queryset_to_visible(children, user, "view_tag")
view = self.context.get("view") view = self.context.get("view")
ordering = ( ordering = (
+2 -2
View File
@@ -340,7 +340,7 @@ def get_custom_fields_context(
return field_data return field_data
def _is_safe_relative_path(value: str) -> bool: def is_safe_relative_path(value: str) -> bool:
if value == "": if value == "":
return True return True
@@ -398,7 +398,7 @@ def validate_filepath_template_and_render(
) )
rendered_template = template.render(context) rendered_template = template.render(context)
if not _is_safe_relative_path(rendered_template): if not is_safe_relative_path(rendered_template):
logger.warning( logger.warning(
"Template rendered an unsafe path (absolute or containing traversal).", "Template rendered an unsafe path (absolute or containing traversal).",
) )
+2 -1
View File
@@ -7,9 +7,10 @@ from rest_framework import status
from rest_framework.test import APITestCase from rest_framework.test import APITestCase
from documents.models import Document from documents.models import Document
from documents.tests.utils import DirectoriesMixin
class TestTrashAPI(APITestCase): class TestTrashAPI(DirectoriesMixin, APITestCase):
def setUp(self) -> None: def setUp(self) -> None:
super().setUp() super().setUp()
+23
View File
@@ -1179,6 +1179,29 @@ class TestConsumer(
produce_archive=True, produce_archive=True,
) )
@mock.patch("documents.consumer.generate_unique_filename")
def test_consume_refuses_to_write_outside_originals_dir(
self,
m: mock.Mock,
) -> None:
"""
GIVEN:
- Filename generation produces a path outside of the originals directory
WHEN:
- The document is consumed
THEN:
- The consumption fails and no file is written outside of the root
"""
m.return_value = Path("../../pwned.pdf")
escaped = (settings.ORIGINALS_DIR / ".." / ".." / "pwned.pdf").resolve()
with self.get_consumer(self.get_test_file()) as consumer:
with self.assertRaises(ConsumerError):
consumer.run()
self.assertIsNotFile(escaped)
self.assertEqual(Document.objects.count(), 0)
@mock.patch("documents.consumer.magic.from_file", fake_magic_from_file) @mock.patch("documents.consumer.magic.from_file", fake_magic_from_file)
class TestConsumerCreatedDate(DirectoriesMixin, GetConsumerMixin, TestCase): class TestConsumerCreatedDate(DirectoriesMixin, GetConsumerMixin, TestCase):
+97
View File
@@ -16,10 +16,12 @@ from django.test import override_settings
from django.test.utils import CaptureQueriesContext from django.test.utils import CaptureQueriesContext
from django.utils import timezone from django.utils import timezone
from documents.file_handling import UnsafeFilePathError
from documents.file_handling import create_source_path_directory from documents.file_handling import create_source_path_directory
from documents.file_handling import delete_empty_directories from documents.file_handling import delete_empty_directories
from documents.file_handling import generate_filename from documents.file_handling import generate_filename
from documents.file_handling import generate_unique_filename from documents.file_handling import generate_unique_filename
from documents.file_handling import validate_path_in_root
from documents.models import Correspondent from documents.models import Correspondent
from documents.models import CustomField from documents.models import CustomField
from documents.models import CustomFieldInstance from documents.models import CustomFieldInstance
@@ -1511,6 +1513,101 @@ class TestFilenameGeneration(DirectoriesMixin, TestCase):
document.filename = generate_filename(document) document.filename = generate_filename(document)
self.assertEqual(document.filename, Path("XX/doc1.pdf")) self.assertEqual(document.filename, Path("XX/doc1.pdf"))
@override_settings(FILENAME_FORMAT_REMOVE_NONE=True)
def test_remove_none_cannot_create_traversal(self) -> None:
"""
GIVEN:
- A storage path whose components are safe when validated, but become
".." once the -none- placeholder is stripped out
- FILENAME_FORMAT_REMOVE_NONE is True
WHEN:
- the filename is generated for the document
THEN:
- The unsafe filename is rejected and the default naming is used
"""
sp = StoragePath.objects.create(
name="sp1",
path=".-none-./.-none-./tmp/pwned",
)
document = Document.objects.create(
title="doc1",
mime_type="application/pdf",
storage_path=sp,
)
filename = generate_filename(document)
self.assertNotIn("..", filename.parts)
self.assertEqual(filename, Path(f"{document.pk:07}.pdf"))
@override_settings(FILENAME_FORMAT_REMOVE_NONE=True)
def test_remove_none_still_removes_placeholder(self) -> None:
"""
GIVEN:
- A storage path with a placeholder for a value the document does not have
- FILENAME_FORMAT_REMOVE_NONE is True
WHEN:
- the filename is generated for the document
THEN:
- The placeholder is still removed as before
"""
sp = StoragePath.objects.create(
name="sp1",
path="{{ correspondent }}/{{ title }}",
)
document = Document.objects.create(
title="doc1",
mime_type="application/pdf",
storage_path=sp,
)
self.assertEqual(generate_filename(document), Path("doc1.pdf"))
@override_settings(
FILENAME_FORMAT="{{ correspondent }}/{{ title }}/{{ doc_pk }}",
FILENAME_FORMAT_REMOVE_NONE=True,
)
def test_remove_none_cannot_create_traversal_from_metadata(self) -> None:
"""
GIVEN:
- A global filename format with directory components
- A document whose title becomes ".." once -none- is stripped out
- FILENAME_FORMAT_REMOVE_NONE is True
WHEN:
- the filename is generated for the document
THEN:
- The unsafe filename is rejected and the default naming is used
"""
document = Document.objects.create(
title=".-none-.",
mime_type="application/pdf",
)
filename = generate_filename(document)
self.assertNotIn("..", filename.parts)
self.assertEqual(filename, Path(f"{document.pk:07}.pdf"))
def test_validate_path_in_root(self) -> None:
"""
GIVEN:
- A path inside of the root and a path outside of it
WHEN:
- The path is validated against the root
THEN:
- Only the path outside of the root is rejected
"""
validate_path_in_root(
settings.ORIGINALS_DIR / "0000001.pdf",
settings.ORIGINALS_DIR,
)
with self.assertRaises(UnsafeFilePathError):
validate_path_in_root(
(settings.ORIGINALS_DIR / ".." / ".." / "pwned.pdf"),
settings.ORIGINALS_DIR,
)
def test_complex_template_strings(self) -> None: def test_complex_template_strings(self) -> None:
""" """
GIVEN: GIVEN:
@@ -409,6 +409,7 @@ class TestBulkDownloadPermissionChecksRootDocument:
@pytest.mark.django_db @pytest.mark.django_db
@pytest.mark.usefixtures("_search_index")
class TestTrashRestorePermissionBoundary: class TestTrashRestorePermissionBoundary:
def test_restore_rejects_document_without_delete_permission( def test_restore_rejects_document_without_delete_permission(
self, self,
+31
View File
@@ -1,5 +1,6 @@
from unittest import mock from unittest import mock
from django.contrib.auth.models import Permission
from django.contrib.auth.models import User from django.contrib.auth.models import User
from rest_framework.test import APITestCase from rest_framework.test import APITestCase
@@ -14,6 +15,36 @@ from documents.signals.handlers import run_workflows
from documents.tests.utils import DirectoriesMixin from documents.tests.utils import DirectoriesMixin
class TestTagHierarchyPermissions(APITestCase):
def test_children_only_include_visible_tags(self) -> None:
owner = User.objects.create_user(username="owner")
requester = User.objects.create_user(username="requester")
requester.user_permissions.add(
Permission.objects.get(codename="view_tag"),
)
parent = Tag.objects.create(name="Visible parent", owner=requester)
hidden_child = Tag.objects.create(
name="Hidden child",
owner=owner,
tn_parent=parent,
)
self.client.force_authenticate(user=requester)
response = self.client.get("/api/tags/")
assert response.status_code == 200
parent_result = next(
tag for tag in response.data["results"] if tag["id"] == parent.pk
)
assert parent_result["children"] == []
assert hidden_child.pk not in response.data.get("all", [])
response = self.client.get(f"/api/tags/{parent.pk}/")
assert response.status_code == 200
assert response.data["children"] == []
class TestTagHierarchy(DirectoriesMixin, APITestCase): class TestTagHierarchy(DirectoriesMixin, APITestCase):
def setUp(self) -> None: def setUp(self) -> None:
super().setUp() super().setUp()
+3 -1
View File
@@ -635,7 +635,9 @@ class TagViewSet(PermissionsAwareDocumentCountMixin, ModelViewSet[Tag]):
annotate_document_count_for_related_queryset( annotate_document_count_for_related_queryset(
Tag.objects.filter( Tag.objects.filter(
pk__in=descendant_pks | {t.pk for t in all_tags}, pk__in=descendant_pks | {t.pk for t in all_tags},
).select_related("owner"), )
.filter(pk__in=permitted_object_ids(user, Tag, "view_tag"))
.select_related("owner"),
through_model=self.document_count_through, through_model=self.document_count_through,
related_object_field=self._get_document_count_source_field(), related_object_field=self._get_document_count_source_field(),
user=user, user=user,
+21 -21
View File
@@ -2,8 +2,8 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: paperless-ngx\n" "Project-Id-Version: paperless-ngx\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2026-08-29 20:02+0000\n" "POT-Creation-Date: 2026-09-01 14:47+0000\n"
"PO-Revision-Date: 2026-08-29 20:04\n" "PO-Revision-Date: 2026-09-01 14:48\n"
"Last-Translator: \n" "Last-Translator: \n"
"Language-Team: Afrikaans\n" "Language-Team: Afrikaans\n"
"Language: af_ZA\n" "Language: af_ZA\n"
@@ -1610,48 +1610,48 @@ msgstr ""
msgid "workflow runs" msgid "workflow runs"
msgstr "" msgstr ""
#: documents/serialisers.py:523 documents/serialisers.py:875 #: documents/serialisers.py:524 documents/serialisers.py:878
#: documents/serialisers.py:2827 documents/views.py:313 documents/views.py:2611 #: documents/serialisers.py:2830 documents/views.py:313 documents/views.py:2613
#: paperless_mail/serialisers.py:156 #: paperless_mail/serialisers.py:156
msgid "Insufficient permissions." msgid "Insufficient permissions."
msgstr "" msgstr ""
#: documents/serialisers.py:711 #: documents/serialisers.py:714
msgid "Invalid color." msgid "Invalid color."
msgstr "Ongeldige kleur." msgstr "Ongeldige kleur."
#: documents/serialisers.py:2304 #: documents/serialisers.py:2307
#, python-format #, python-format
msgid "File type %(type)s not supported" msgid "File type %(type)s not supported"
msgstr "Lêertipe %(type)s word nie ondersteun nie" msgstr "Lêertipe %(type)s word nie ondersteun nie"
#: documents/serialisers.py:2348 #: documents/serialisers.py:2351
#, python-format #, python-format
msgid "Custom field id must be an integer: %(id)s" msgid "Custom field id must be an integer: %(id)s"
msgstr "" msgstr ""
#: documents/serialisers.py:2355 #: documents/serialisers.py:2358
#, python-format #, python-format
msgid "Custom field with id %(id)s does not exist" msgid "Custom field with id %(id)s does not exist"
msgstr "" msgstr ""
#: documents/serialisers.py:2372 documents/serialisers.py:2382 #: documents/serialisers.py:2375 documents/serialisers.py:2385
msgid "Custom fields must be a list of integers or an object mapping ids to values." msgid "Custom fields must be a list of integers or an object mapping ids to values."
msgstr "" msgstr ""
#: documents/serialisers.py:2377 #: documents/serialisers.py:2380
msgid "Some custom fields don't exist or were specified twice." msgid "Some custom fields don't exist or were specified twice."
msgstr "" msgstr ""
#: documents/serialisers.py:2524 #: documents/serialisers.py:2527
msgid "Invalid variable detected." msgid "Invalid variable detected."
msgstr "Ongeldige veranderlike bespeur." msgstr "Ongeldige veranderlike bespeur."
#: documents/serialisers.py:2883 #: documents/serialisers.py:2886
msgid "Duplicate document identifiers are not allowed." msgid "Duplicate document identifiers are not allowed."
msgstr "" msgstr ""
#: documents/serialisers.py:2913 documents/views.py:4608 #: documents/serialisers.py:2916 documents/views.py:4610
#, python-format #, python-format
msgid "Documents not found: %(ids)s" msgid "Documents not found: %(ids)s"
msgstr "" msgstr ""
@@ -1906,36 +1906,36 @@ msgstr ""
msgid "Unable to parse URI {value}" msgid "Unable to parse URI {value}"
msgstr "" msgstr ""
#: documents/views.py:306 documents/views.py:2608 #: documents/views.py:306 documents/views.py:2610
msgid "Invalid more_like_id" msgid "Invalid more_like_id"
msgstr "" msgstr ""
#: documents/views.py:1582 #: documents/views.py:1584
msgid "Invalid AI configuration." msgid "Invalid AI configuration."
msgstr "" msgstr ""
#: documents/views.py:1593 #: documents/views.py:1595
msgid "AI backend request timed out." msgid "AI backend request timed out."
msgstr "" msgstr ""
#: documents/views.py:2433 documents/views.py:2754 #: documents/views.py:2435 documents/views.py:2756
msgid "Specify only one of text, title_search, query, or more_like_id." msgid "Specify only one of text, title_search, query, or more_like_id."
msgstr "" msgstr ""
#: documents/views.py:4621 #: documents/views.py:4623
#, python-format #, python-format
msgid "Insufficient permissions to share document %(id)s." msgid "Insufficient permissions to share document %(id)s."
msgstr "" msgstr ""
#: documents/views.py:4667 #: documents/views.py:4669
msgid "Bundle is already being processed." msgid "Bundle is already being processed."
msgstr "" msgstr ""
#: documents/views.py:4728 #: documents/views.py:4730
msgid "The share link bundle is still being prepared. Please try again later." msgid "The share link bundle is still being prepared. Please try again later."
msgstr "" msgstr ""
#: documents/views.py:4738 #: documents/views.py:4740
msgid "The share link bundle is unavailable." msgid "The share link bundle is unavailable."
msgstr "" msgstr ""
+21 -21
View File
@@ -2,8 +2,8 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: paperless-ngx\n" "Project-Id-Version: paperless-ngx\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2026-08-29 20:02+0000\n" "POT-Creation-Date: 2026-09-01 14:47+0000\n"
"PO-Revision-Date: 2026-08-29 20:04\n" "PO-Revision-Date: 2026-09-01 14:48\n"
"Last-Translator: \n" "Last-Translator: \n"
"Language-Team: Amharic\n" "Language-Team: Amharic\n"
"Language: am_ET\n" "Language: am_ET\n"
@@ -1610,48 +1610,48 @@ msgstr ""
msgid "workflow runs" msgid "workflow runs"
msgstr "" msgstr ""
#: documents/serialisers.py:523 documents/serialisers.py:875 #: documents/serialisers.py:524 documents/serialisers.py:878
#: documents/serialisers.py:2827 documents/views.py:313 documents/views.py:2611 #: documents/serialisers.py:2830 documents/views.py:313 documents/views.py:2613
#: paperless_mail/serialisers.py:156 #: paperless_mail/serialisers.py:156
msgid "Insufficient permissions." msgid "Insufficient permissions."
msgstr "" msgstr ""
#: documents/serialisers.py:711 #: documents/serialisers.py:714
msgid "Invalid color." msgid "Invalid color."
msgstr "" msgstr ""
#: documents/serialisers.py:2304 #: documents/serialisers.py:2307
#, python-format #, python-format
msgid "File type %(type)s not supported" msgid "File type %(type)s not supported"
msgstr "" msgstr ""
#: documents/serialisers.py:2348 #: documents/serialisers.py:2351
#, python-format #, python-format
msgid "Custom field id must be an integer: %(id)s" msgid "Custom field id must be an integer: %(id)s"
msgstr "" msgstr ""
#: documents/serialisers.py:2355 #: documents/serialisers.py:2358
#, python-format #, python-format
msgid "Custom field with id %(id)s does not exist" msgid "Custom field with id %(id)s does not exist"
msgstr "" msgstr ""
#: documents/serialisers.py:2372 documents/serialisers.py:2382 #: documents/serialisers.py:2375 documents/serialisers.py:2385
msgid "Custom fields must be a list of integers or an object mapping ids to values." msgid "Custom fields must be a list of integers or an object mapping ids to values."
msgstr "" msgstr ""
#: documents/serialisers.py:2377 #: documents/serialisers.py:2380
msgid "Some custom fields don't exist or were specified twice." msgid "Some custom fields don't exist or were specified twice."
msgstr "" msgstr ""
#: documents/serialisers.py:2524 #: documents/serialisers.py:2527
msgid "Invalid variable detected." msgid "Invalid variable detected."
msgstr "" msgstr ""
#: documents/serialisers.py:2883 #: documents/serialisers.py:2886
msgid "Duplicate document identifiers are not allowed." msgid "Duplicate document identifiers are not allowed."
msgstr "" msgstr ""
#: documents/serialisers.py:2913 documents/views.py:4608 #: documents/serialisers.py:2916 documents/views.py:4610
#, python-format #, python-format
msgid "Documents not found: %(ids)s" msgid "Documents not found: %(ids)s"
msgstr "" msgstr ""
@@ -1906,36 +1906,36 @@ msgstr ""
msgid "Unable to parse URI {value}" msgid "Unable to parse URI {value}"
msgstr "" msgstr ""
#: documents/views.py:306 documents/views.py:2608 #: documents/views.py:306 documents/views.py:2610
msgid "Invalid more_like_id" msgid "Invalid more_like_id"
msgstr "" msgstr ""
#: documents/views.py:1582 #: documents/views.py:1584
msgid "Invalid AI configuration." msgid "Invalid AI configuration."
msgstr "" msgstr ""
#: documents/views.py:1593 #: documents/views.py:1595
msgid "AI backend request timed out." msgid "AI backend request timed out."
msgstr "" msgstr ""
#: documents/views.py:2433 documents/views.py:2754 #: documents/views.py:2435 documents/views.py:2756
msgid "Specify only one of text, title_search, query, or more_like_id." msgid "Specify only one of text, title_search, query, or more_like_id."
msgstr "" msgstr ""
#: documents/views.py:4621 #: documents/views.py:4623
#, python-format #, python-format
msgid "Insufficient permissions to share document %(id)s." msgid "Insufficient permissions to share document %(id)s."
msgstr "" msgstr ""
#: documents/views.py:4667 #: documents/views.py:4669
msgid "Bundle is already being processed." msgid "Bundle is already being processed."
msgstr "" msgstr ""
#: documents/views.py:4728 #: documents/views.py:4730
msgid "The share link bundle is still being prepared. Please try again later." msgid "The share link bundle is still being prepared. Please try again later."
msgstr "" msgstr ""
#: documents/views.py:4738 #: documents/views.py:4740
msgid "The share link bundle is unavailable." msgid "The share link bundle is unavailable."
msgstr "" msgstr ""
+21 -21
View File
@@ -2,8 +2,8 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: paperless-ngx\n" "Project-Id-Version: paperless-ngx\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2026-08-29 20:02+0000\n" "POT-Creation-Date: 2026-09-01 14:47+0000\n"
"PO-Revision-Date: 2026-08-29 20:04\n" "PO-Revision-Date: 2026-09-01 14:48\n"
"Last-Translator: \n" "Last-Translator: \n"
"Language-Team: Arabic\n" "Language-Team: Arabic\n"
"Language: ar_SA\n" "Language: ar_SA\n"
@@ -1610,48 +1610,48 @@ msgstr ""
msgid "workflow runs" msgid "workflow runs"
msgstr "" msgstr ""
#: documents/serialisers.py:523 documents/serialisers.py:875 #: documents/serialisers.py:524 documents/serialisers.py:878
#: documents/serialisers.py:2827 documents/views.py:313 documents/views.py:2611 #: documents/serialisers.py:2830 documents/views.py:313 documents/views.py:2613
#: paperless_mail/serialisers.py:156 #: paperless_mail/serialisers.py:156
msgid "Insufficient permissions." msgid "Insufficient permissions."
msgstr "" msgstr ""
#: documents/serialisers.py:711 #: documents/serialisers.py:714
msgid "Invalid color." msgid "Invalid color."
msgstr "لون خاطئ." msgstr "لون خاطئ."
#: documents/serialisers.py:2304 #: documents/serialisers.py:2307
#, python-format #, python-format
msgid "File type %(type)s not supported" msgid "File type %(type)s not supported"
msgstr "نوع الملف %(type)s غير مدعوم" msgstr "نوع الملف %(type)s غير مدعوم"
#: documents/serialisers.py:2348 #: documents/serialisers.py:2351
#, python-format #, python-format
msgid "Custom field id must be an integer: %(id)s" msgid "Custom field id must be an integer: %(id)s"
msgstr "" msgstr ""
#: documents/serialisers.py:2355 #: documents/serialisers.py:2358
#, python-format #, python-format
msgid "Custom field with id %(id)s does not exist" msgid "Custom field with id %(id)s does not exist"
msgstr "" msgstr ""
#: documents/serialisers.py:2372 documents/serialisers.py:2382 #: documents/serialisers.py:2375 documents/serialisers.py:2385
msgid "Custom fields must be a list of integers or an object mapping ids to values." msgid "Custom fields must be a list of integers or an object mapping ids to values."
msgstr "" msgstr ""
#: documents/serialisers.py:2377 #: documents/serialisers.py:2380
msgid "Some custom fields don't exist or were specified twice." msgid "Some custom fields don't exist or were specified twice."
msgstr "" msgstr ""
#: documents/serialisers.py:2524 #: documents/serialisers.py:2527
msgid "Invalid variable detected." msgid "Invalid variable detected."
msgstr "اكتشاف متغير خاطئ." msgstr "اكتشاف متغير خاطئ."
#: documents/serialisers.py:2883 #: documents/serialisers.py:2886
msgid "Duplicate document identifiers are not allowed." msgid "Duplicate document identifiers are not allowed."
msgstr "" msgstr ""
#: documents/serialisers.py:2913 documents/views.py:4608 #: documents/serialisers.py:2916 documents/views.py:4610
#, python-format #, python-format
msgid "Documents not found: %(ids)s" msgid "Documents not found: %(ids)s"
msgstr "" msgstr ""
@@ -1907,36 +1907,36 @@ msgstr ""
msgid "Unable to parse URI {value}" msgid "Unable to parse URI {value}"
msgstr "" msgstr ""
#: documents/views.py:306 documents/views.py:2608 #: documents/views.py:306 documents/views.py:2610
msgid "Invalid more_like_id" msgid "Invalid more_like_id"
msgstr "" msgstr ""
#: documents/views.py:1582 #: documents/views.py:1584
msgid "Invalid AI configuration." msgid "Invalid AI configuration."
msgstr "" msgstr ""
#: documents/views.py:1593 #: documents/views.py:1595
msgid "AI backend request timed out." msgid "AI backend request timed out."
msgstr "" msgstr ""
#: documents/views.py:2433 documents/views.py:2754 #: documents/views.py:2435 documents/views.py:2756
msgid "Specify only one of text, title_search, query, or more_like_id." msgid "Specify only one of text, title_search, query, or more_like_id."
msgstr "" msgstr ""
#: documents/views.py:4621 #: documents/views.py:4623
#, python-format #, python-format
msgid "Insufficient permissions to share document %(id)s." msgid "Insufficient permissions to share document %(id)s."
msgstr "" msgstr ""
#: documents/views.py:4667 #: documents/views.py:4669
msgid "Bundle is already being processed." msgid "Bundle is already being processed."
msgstr "" msgstr ""
#: documents/views.py:4728 #: documents/views.py:4730
msgid "The share link bundle is still being prepared. Please try again later." msgid "The share link bundle is still being prepared. Please try again later."
msgstr "" msgstr ""
#: documents/views.py:4738 #: documents/views.py:4740
msgid "The share link bundle is unavailable." msgid "The share link bundle is unavailable."
msgstr "" msgstr ""
+21 -21
View File
@@ -2,8 +2,8 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: paperless-ngx\n" "Project-Id-Version: paperless-ngx\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2026-08-29 20:02+0000\n" "POT-Creation-Date: 2026-09-01 14:47+0000\n"
"PO-Revision-Date: 2026-08-29 20:04\n" "PO-Revision-Date: 2026-09-01 14:48\n"
"Last-Translator: \n" "Last-Translator: \n"
"Language-Team: Belarusian\n" "Language-Team: Belarusian\n"
"Language: be_BY\n" "Language: be_BY\n"
@@ -1610,48 +1610,48 @@ msgstr ""
msgid "workflow runs" msgid "workflow runs"
msgstr "" msgstr ""
#: documents/serialisers.py:523 documents/serialisers.py:875 #: documents/serialisers.py:524 documents/serialisers.py:878
#: documents/serialisers.py:2827 documents/views.py:313 documents/views.py:2611 #: documents/serialisers.py:2830 documents/views.py:313 documents/views.py:2613
#: paperless_mail/serialisers.py:156 #: paperless_mail/serialisers.py:156
msgid "Insufficient permissions." msgid "Insufficient permissions."
msgstr "" msgstr ""
#: documents/serialisers.py:711 #: documents/serialisers.py:714
msgid "Invalid color." msgid "Invalid color."
msgstr "Няправільны колер." msgstr "Няправільны колер."
#: documents/serialisers.py:2304 #: documents/serialisers.py:2307
#, python-format #, python-format
msgid "File type %(type)s not supported" msgid "File type %(type)s not supported"
msgstr "Тып файла %(type)s не падтрымліваецца" msgstr "Тып файла %(type)s не падтрымліваецца"
#: documents/serialisers.py:2348 #: documents/serialisers.py:2351
#, python-format #, python-format
msgid "Custom field id must be an integer: %(id)s" msgid "Custom field id must be an integer: %(id)s"
msgstr "" msgstr ""
#: documents/serialisers.py:2355 #: documents/serialisers.py:2358
#, python-format #, python-format
msgid "Custom field with id %(id)s does not exist" msgid "Custom field with id %(id)s does not exist"
msgstr "" msgstr ""
#: documents/serialisers.py:2372 documents/serialisers.py:2382 #: documents/serialisers.py:2375 documents/serialisers.py:2385
msgid "Custom fields must be a list of integers or an object mapping ids to values." msgid "Custom fields must be a list of integers or an object mapping ids to values."
msgstr "" msgstr ""
#: documents/serialisers.py:2377 #: documents/serialisers.py:2380
msgid "Some custom fields don't exist or were specified twice." msgid "Some custom fields don't exist or were specified twice."
msgstr "" msgstr ""
#: documents/serialisers.py:2524 #: documents/serialisers.py:2527
msgid "Invalid variable detected." msgid "Invalid variable detected."
msgstr "Выяўлена няправільная зменная." msgstr "Выяўлена няправільная зменная."
#: documents/serialisers.py:2883 #: documents/serialisers.py:2886
msgid "Duplicate document identifiers are not allowed." msgid "Duplicate document identifiers are not allowed."
msgstr "" msgstr ""
#: documents/serialisers.py:2913 documents/views.py:4608 #: documents/serialisers.py:2916 documents/views.py:4610
#, python-format #, python-format
msgid "Documents not found: %(ids)s" msgid "Documents not found: %(ids)s"
msgstr "" msgstr ""
@@ -1906,36 +1906,36 @@ msgstr ""
msgid "Unable to parse URI {value}" msgid "Unable to parse URI {value}"
msgstr "" msgstr ""
#: documents/views.py:306 documents/views.py:2608 #: documents/views.py:306 documents/views.py:2610
msgid "Invalid more_like_id" msgid "Invalid more_like_id"
msgstr "" msgstr ""
#: documents/views.py:1582 #: documents/views.py:1584
msgid "Invalid AI configuration." msgid "Invalid AI configuration."
msgstr "" msgstr ""
#: documents/views.py:1593 #: documents/views.py:1595
msgid "AI backend request timed out." msgid "AI backend request timed out."
msgstr "" msgstr ""
#: documents/views.py:2433 documents/views.py:2754 #: documents/views.py:2435 documents/views.py:2756
msgid "Specify only one of text, title_search, query, or more_like_id." msgid "Specify only one of text, title_search, query, or more_like_id."
msgstr "" msgstr ""
#: documents/views.py:4621 #: documents/views.py:4623
#, python-format #, python-format
msgid "Insufficient permissions to share document %(id)s." msgid "Insufficient permissions to share document %(id)s."
msgstr "" msgstr ""
#: documents/views.py:4667 #: documents/views.py:4669
msgid "Bundle is already being processed." msgid "Bundle is already being processed."
msgstr "" msgstr ""
#: documents/views.py:4728 #: documents/views.py:4730
msgid "The share link bundle is still being prepared. Please try again later." msgid "The share link bundle is still being prepared. Please try again later."
msgstr "" msgstr ""
#: documents/views.py:4738 #: documents/views.py:4740
msgid "The share link bundle is unavailable." msgid "The share link bundle is unavailable."
msgstr "" msgstr ""
+21 -21
View File
@@ -2,8 +2,8 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: paperless-ngx\n" "Project-Id-Version: paperless-ngx\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2026-08-29 20:02+0000\n" "POT-Creation-Date: 2026-09-01 14:47+0000\n"
"PO-Revision-Date: 2026-08-29 20:04\n" "PO-Revision-Date: 2026-09-01 14:48\n"
"Last-Translator: \n" "Last-Translator: \n"
"Language-Team: Bulgarian\n" "Language-Team: Bulgarian\n"
"Language: bg_BG\n" "Language: bg_BG\n"
@@ -1610,48 +1610,48 @@ msgstr "стартиране на работния процес"
msgid "workflow runs" msgid "workflow runs"
msgstr "стартиране на работните процеси" msgstr "стартиране на работните процеси"
#: documents/serialisers.py:523 documents/serialisers.py:875 #: documents/serialisers.py:524 documents/serialisers.py:878
#: documents/serialisers.py:2827 documents/views.py:313 documents/views.py:2611 #: documents/serialisers.py:2830 documents/views.py:313 documents/views.py:2613
#: paperless_mail/serialisers.py:156 #: paperless_mail/serialisers.py:156
msgid "Insufficient permissions." msgid "Insufficient permissions."
msgstr "" msgstr ""
#: documents/serialisers.py:711 #: documents/serialisers.py:714
msgid "Invalid color." msgid "Invalid color."
msgstr "Невалиден цвят." msgstr "Невалиден цвят."
#: documents/serialisers.py:2304 #: documents/serialisers.py:2307
#, python-format #, python-format
msgid "File type %(type)s not supported" msgid "File type %(type)s not supported"
msgstr "Файловия тип %(type)s не се поддържа" msgstr "Файловия тип %(type)s не се поддържа"
#: documents/serialisers.py:2348 #: documents/serialisers.py:2351
#, python-format #, python-format
msgid "Custom field id must be an integer: %(id)s" msgid "Custom field id must be an integer: %(id)s"
msgstr "" msgstr ""
#: documents/serialisers.py:2355 #: documents/serialisers.py:2358
#, python-format #, python-format
msgid "Custom field with id %(id)s does not exist" msgid "Custom field with id %(id)s does not exist"
msgstr "" msgstr ""
#: documents/serialisers.py:2372 documents/serialisers.py:2382 #: documents/serialisers.py:2375 documents/serialisers.py:2385
msgid "Custom fields must be a list of integers or an object mapping ids to values." msgid "Custom fields must be a list of integers or an object mapping ids to values."
msgstr "" msgstr ""
#: documents/serialisers.py:2377 #: documents/serialisers.py:2380
msgid "Some custom fields don't exist or were specified twice." msgid "Some custom fields don't exist or were specified twice."
msgstr "" msgstr ""
#: documents/serialisers.py:2524 #: documents/serialisers.py:2527
msgid "Invalid variable detected." msgid "Invalid variable detected."
msgstr "Засечена е невалидна променлива." msgstr "Засечена е невалидна променлива."
#: documents/serialisers.py:2883 #: documents/serialisers.py:2886
msgid "Duplicate document identifiers are not allowed." msgid "Duplicate document identifiers are not allowed."
msgstr "" msgstr ""
#: documents/serialisers.py:2913 documents/views.py:4608 #: documents/serialisers.py:2916 documents/views.py:4610
#, python-format #, python-format
msgid "Documents not found: %(ids)s" msgid "Documents not found: %(ids)s"
msgstr "" msgstr ""
@@ -1907,36 +1907,36 @@ msgstr ""
msgid "Unable to parse URI {value}" msgid "Unable to parse URI {value}"
msgstr "" msgstr ""
#: documents/views.py:306 documents/views.py:2608 #: documents/views.py:306 documents/views.py:2610
msgid "Invalid more_like_id" msgid "Invalid more_like_id"
msgstr "" msgstr ""
#: documents/views.py:1582 #: documents/views.py:1584
msgid "Invalid AI configuration." msgid "Invalid AI configuration."
msgstr "" msgstr ""
#: documents/views.py:1593 #: documents/views.py:1595
msgid "AI backend request timed out." msgid "AI backend request timed out."
msgstr "" msgstr ""
#: documents/views.py:2433 documents/views.py:2754 #: documents/views.py:2435 documents/views.py:2756
msgid "Specify only one of text, title_search, query, or more_like_id." msgid "Specify only one of text, title_search, query, or more_like_id."
msgstr "" msgstr ""
#: documents/views.py:4621 #: documents/views.py:4623
#, python-format #, python-format
msgid "Insufficient permissions to share document %(id)s." msgid "Insufficient permissions to share document %(id)s."
msgstr "" msgstr ""
#: documents/views.py:4667 #: documents/views.py:4669
msgid "Bundle is already being processed." msgid "Bundle is already being processed."
msgstr "" msgstr ""
#: documents/views.py:4728 #: documents/views.py:4730
msgid "The share link bundle is still being prepared. Please try again later." msgid "The share link bundle is still being prepared. Please try again later."
msgstr "" msgstr ""
#: documents/views.py:4738 #: documents/views.py:4740
msgid "The share link bundle is unavailable." msgid "The share link bundle is unavailable."
msgstr "" msgstr ""
+21 -21
View File
@@ -2,8 +2,8 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: paperless-ngx\n" "Project-Id-Version: paperless-ngx\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2026-08-29 20:02+0000\n" "POT-Creation-Date: 2026-09-01 14:47+0000\n"
"PO-Revision-Date: 2026-08-29 20:04\n" "PO-Revision-Date: 2026-09-01 14:48\n"
"Last-Translator: \n" "Last-Translator: \n"
"Language-Team: Catalan\n" "Language-Team: Catalan\n"
"Language: ca_ES\n" "Language: ca_ES\n"
@@ -1610,48 +1610,48 @@ msgstr "data del flux"
msgid "workflow runs" msgid "workflow runs"
msgstr "flux corrents" msgstr "flux corrents"
#: documents/serialisers.py:523 documents/serialisers.py:875 #: documents/serialisers.py:524 documents/serialisers.py:878
#: documents/serialisers.py:2827 documents/views.py:313 documents/views.py:2611 #: documents/serialisers.py:2830 documents/views.py:313 documents/views.py:2613
#: paperless_mail/serialisers.py:156 #: paperless_mail/serialisers.py:156
msgid "Insufficient permissions." msgid "Insufficient permissions."
msgstr "Permisos insuficients." msgstr "Permisos insuficients."
#: documents/serialisers.py:711 #: documents/serialisers.py:714
msgid "Invalid color." msgid "Invalid color."
msgstr "Color Invàlid." msgstr "Color Invàlid."
#: documents/serialisers.py:2304 #: documents/serialisers.py:2307
#, python-format #, python-format
msgid "File type %(type)s not supported" msgid "File type %(type)s not supported"
msgstr "Tipus arxiu %(type)s no suportat" msgstr "Tipus arxiu %(type)s no suportat"
#: documents/serialisers.py:2348 #: documents/serialisers.py:2351
#, python-format #, python-format
msgid "Custom field id must be an integer: %(id)s" msgid "Custom field id must be an integer: %(id)s"
msgstr "ID de camp personalizat ha de ser enter: %(id)s" msgstr "ID de camp personalizat ha de ser enter: %(id)s"
#: documents/serialisers.py:2355 #: documents/serialisers.py:2358
#, python-format #, python-format
msgid "Custom field with id %(id)s does not exist" msgid "Custom field with id %(id)s does not exist"
msgstr "Camp personalitzat amb ID %(id)s no existeix" msgstr "Camp personalitzat amb ID %(id)s no existeix"
#: documents/serialisers.py:2372 documents/serialisers.py:2382 #: documents/serialisers.py:2375 documents/serialisers.py:2385
msgid "Custom fields must be a list of integers or an object mapping ids to values." msgid "Custom fields must be a list of integers or an object mapping ids to values."
msgstr "Camps personalitzats han de ser una llista d'enters o un objecte que mapegi els identificadors amb els valors." msgstr "Camps personalitzats han de ser una llista d'enters o un objecte que mapegi els identificadors amb els valors."
#: documents/serialisers.py:2377 #: documents/serialisers.py:2380
msgid "Some custom fields don't exist or were specified twice." msgid "Some custom fields don't exist or were specified twice."
msgstr "Alguns camps personalitzats no existeixen o s'han especificat dues vegades." msgstr "Alguns camps personalitzats no existeixen o s'han especificat dues vegades."
#: documents/serialisers.py:2524 #: documents/serialisers.py:2527
msgid "Invalid variable detected." msgid "Invalid variable detected."
msgstr "Variable detectada invàlida." msgstr "Variable detectada invàlida."
#: documents/serialisers.py:2883 #: documents/serialisers.py:2886
msgid "Duplicate document identifiers are not allowed." msgid "Duplicate document identifiers are not allowed."
msgstr "Duplicat d'identificadors de documents no permès." msgstr "Duplicat d'identificadors de documents no permès."
#: documents/serialisers.py:2913 documents/views.py:4608 #: documents/serialisers.py:2916 documents/views.py:4610
#, python-format #, python-format
msgid "Documents not found: %(ids)s" msgid "Documents not found: %(ids)s"
msgstr "Documents no trobats: %(ids)s" msgstr "Documents no trobats: %(ids)s"
@@ -1907,36 +1907,36 @@ msgstr "L'esquema d'URI '{parts.scheme}' no està permès. Esquemes permesos: {'
msgid "Unable to parse URI {value}" msgid "Unable to parse URI {value}"
msgstr "No s'ha pogut analitzar l'URI {value}" msgstr "No s'ha pogut analitzar l'URI {value}"
#: documents/views.py:306 documents/views.py:2608 #: documents/views.py:306 documents/views.py:2610
msgid "Invalid more_like_id" msgid "Invalid more_like_id"
msgstr "Invalid more_like_id" msgstr "Invalid more_like_id"
#: documents/views.py:1582 #: documents/views.py:1584
msgid "Invalid AI configuration." msgid "Invalid AI configuration."
msgstr "Configuració AI invàlida." msgstr "Configuració AI invàlida."
#: documents/views.py:1593 #: documents/views.py:1595
msgid "AI backend request timed out." msgid "AI backend request timed out."
msgstr "" msgstr ""
#: documents/views.py:2433 documents/views.py:2754 #: documents/views.py:2435 documents/views.py:2756
msgid "Specify only one of text, title_search, query, or more_like_id." msgid "Specify only one of text, title_search, query, or more_like_id."
msgstr "Especifica només un dels següents valors: text, title_search, query o more_like_id." msgstr "Especifica només un dels següents valors: text, title_search, query o more_like_id."
#: documents/views.py:4621 #: documents/views.py:4623
#, python-format #, python-format
msgid "Insufficient permissions to share document %(id)s." msgid "Insufficient permissions to share document %(id)s."
msgstr "Permisos insuficients per compartir document %(id)s." msgstr "Permisos insuficients per compartir document %(id)s."
#: documents/views.py:4667 #: documents/views.py:4669
msgid "Bundle is already being processed." msgid "Bundle is already being processed."
msgstr "Paquet ja s'està processant." msgstr "Paquet ja s'està processant."
#: documents/views.py:4728 #: documents/views.py:4730
msgid "The share link bundle is still being prepared. Please try again later." msgid "The share link bundle is still being prepared. Please try again later."
msgstr "El paquet de link encarà s'està preparant. Prova de nou més tard." msgstr "El paquet de link encarà s'està preparant. Prova de nou més tard."
#: documents/views.py:4738 #: documents/views.py:4740
msgid "The share link bundle is unavailable." msgid "The share link bundle is unavailable."
msgstr "El paquet d'enllaç no està disponible." msgstr "El paquet d'enllaç no està disponible."
+21 -21
View File
@@ -2,8 +2,8 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: paperless-ngx\n" "Project-Id-Version: paperless-ngx\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2026-08-29 20:02+0000\n" "POT-Creation-Date: 2026-09-01 14:47+0000\n"
"PO-Revision-Date: 2026-08-29 20:04\n" "PO-Revision-Date: 2026-09-01 14:48\n"
"Last-Translator: \n" "Last-Translator: \n"
"Language-Team: Czech\n" "Language-Team: Czech\n"
"Language: cs_CZ\n" "Language: cs_CZ\n"
@@ -1610,48 +1610,48 @@ msgstr "spuštění pracovního postupu"
msgid "workflow runs" msgid "workflow runs"
msgstr "spuštění pracovních postupů" msgstr "spuštění pracovních postupů"
#: documents/serialisers.py:523 documents/serialisers.py:875 #: documents/serialisers.py:524 documents/serialisers.py:878
#: documents/serialisers.py:2827 documents/views.py:313 documents/views.py:2611 #: documents/serialisers.py:2830 documents/views.py:313 documents/views.py:2613
#: paperless_mail/serialisers.py:156 #: paperless_mail/serialisers.py:156
msgid "Insufficient permissions." msgid "Insufficient permissions."
msgstr "Nedostatečná oprávnění." msgstr "Nedostatečná oprávnění."
#: documents/serialisers.py:711 #: documents/serialisers.py:714
msgid "Invalid color." msgid "Invalid color."
msgstr "Neplatná barva." msgstr "Neplatná barva."
#: documents/serialisers.py:2304 #: documents/serialisers.py:2307
#, python-format #, python-format
msgid "File type %(type)s not supported" msgid "File type %(type)s not supported"
msgstr "Typ souboru %(type)s není podporován" msgstr "Typ souboru %(type)s není podporován"
#: documents/serialisers.py:2348 #: documents/serialisers.py:2351
#, python-format #, python-format
msgid "Custom field id must be an integer: %(id)s" msgid "Custom field id must be an integer: %(id)s"
msgstr "Vlastní ID pole musí být celé číslo: %(id)s" msgstr "Vlastní ID pole musí být celé číslo: %(id)s"
#: documents/serialisers.py:2355 #: documents/serialisers.py:2358
#, python-format #, python-format
msgid "Custom field with id %(id)s does not exist" msgid "Custom field with id %(id)s does not exist"
msgstr "Vlastní pole s ID %(id)s neexistuje" msgstr "Vlastní pole s ID %(id)s neexistuje"
#: documents/serialisers.py:2372 documents/serialisers.py:2382 #: documents/serialisers.py:2375 documents/serialisers.py:2385
msgid "Custom fields must be a list of integers or an object mapping ids to values." msgid "Custom fields must be a list of integers or an object mapping ids to values."
msgstr "Vlastní pole musí být seznam celých čísel nebo ID pro mapování objektů na hodnoty." msgstr "Vlastní pole musí být seznam celých čísel nebo ID pro mapování objektů na hodnoty."
#: documents/serialisers.py:2377 #: documents/serialisers.py:2380
msgid "Some custom fields don't exist or were specified twice." msgid "Some custom fields don't exist or were specified twice."
msgstr "Některá vlastní pole neexistují nebo byla zadána dvakrát." msgstr "Některá vlastní pole neexistují nebo byla zadána dvakrát."
#: documents/serialisers.py:2524 #: documents/serialisers.py:2527
msgid "Invalid variable detected." msgid "Invalid variable detected."
msgstr "Zjištěna neplatná proměnná." msgstr "Zjištěna neplatná proměnná."
#: documents/serialisers.py:2883 #: documents/serialisers.py:2886
msgid "Duplicate document identifiers are not allowed." msgid "Duplicate document identifiers are not allowed."
msgstr "" msgstr ""
#: documents/serialisers.py:2913 documents/views.py:4608 #: documents/serialisers.py:2916 documents/views.py:4610
#, python-format #, python-format
msgid "Documents not found: %(ids)s" msgid "Documents not found: %(ids)s"
msgstr "" msgstr ""
@@ -1908,36 +1908,36 @@ msgstr "URI schéma '{parts.scheme}' není povoleno. Povolená schémata: {',\n"
msgid "Unable to parse URI {value}" msgid "Unable to parse URI {value}"
msgstr "Nelze zpracovat URI {value}" msgstr "Nelze zpracovat URI {value}"
#: documents/views.py:306 documents/views.py:2608 #: documents/views.py:306 documents/views.py:2610
msgid "Invalid more_like_id" msgid "Invalid more_like_id"
msgstr "" msgstr ""
#: documents/views.py:1582 #: documents/views.py:1584
msgid "Invalid AI configuration." msgid "Invalid AI configuration."
msgstr "" msgstr ""
#: documents/views.py:1593 #: documents/views.py:1595
msgid "AI backend request timed out." msgid "AI backend request timed out."
msgstr "" msgstr ""
#: documents/views.py:2433 documents/views.py:2754 #: documents/views.py:2435 documents/views.py:2756
msgid "Specify only one of text, title_search, query, or more_like_id." msgid "Specify only one of text, title_search, query, or more_like_id."
msgstr "" msgstr ""
#: documents/views.py:4621 #: documents/views.py:4623
#, python-format #, python-format
msgid "Insufficient permissions to share document %(id)s." msgid "Insufficient permissions to share document %(id)s."
msgstr "Nedostatečná oprávnění ke sdílení dokumentu %(id)s." msgstr "Nedostatečná oprávnění ke sdílení dokumentu %(id)s."
#: documents/views.py:4667 #: documents/views.py:4669
msgid "Bundle is already being processed." msgid "Bundle is already being processed."
msgstr "" msgstr ""
#: documents/views.py:4728 #: documents/views.py:4730
msgid "The share link bundle is still being prepared. Please try again later." msgid "The share link bundle is still being prepared. Please try again later."
msgstr "" msgstr ""
#: documents/views.py:4738 #: documents/views.py:4740
msgid "The share link bundle is unavailable." msgid "The share link bundle is unavailable."
msgstr "" msgstr ""
+21 -21
View File
@@ -2,8 +2,8 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: paperless-ngx\n" "Project-Id-Version: paperless-ngx\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2026-08-29 20:02+0000\n" "POT-Creation-Date: 2026-09-01 14:47+0000\n"
"PO-Revision-Date: 2026-08-29 20:04\n" "PO-Revision-Date: 2026-09-01 14:48\n"
"Last-Translator: \n" "Last-Translator: \n"
"Language-Team: Danish\n" "Language-Team: Danish\n"
"Language: da_DK\n" "Language: da_DK\n"
@@ -1610,48 +1610,48 @@ msgstr "workflow-kørsel"
msgid "workflow runs" msgid "workflow runs"
msgstr "workflow-kørsler" msgstr "workflow-kørsler"
#: documents/serialisers.py:523 documents/serialisers.py:875 #: documents/serialisers.py:524 documents/serialisers.py:878
#: documents/serialisers.py:2827 documents/views.py:313 documents/views.py:2611 #: documents/serialisers.py:2830 documents/views.py:313 documents/views.py:2613
#: paperless_mail/serialisers.py:156 #: paperless_mail/serialisers.py:156
msgid "Insufficient permissions." msgid "Insufficient permissions."
msgstr "" msgstr ""
#: documents/serialisers.py:711 #: documents/serialisers.py:714
msgid "Invalid color." msgid "Invalid color."
msgstr "Ugyldig farve." msgstr "Ugyldig farve."
#: documents/serialisers.py:2304 #: documents/serialisers.py:2307
#, python-format #, python-format
msgid "File type %(type)s not supported" msgid "File type %(type)s not supported"
msgstr "Filtype %(type)s understøttes ikke" msgstr "Filtype %(type)s understøttes ikke"
#: documents/serialisers.py:2348 #: documents/serialisers.py:2351
#, python-format #, python-format
msgid "Custom field id must be an integer: %(id)s" msgid "Custom field id must be an integer: %(id)s"
msgstr "" msgstr ""
#: documents/serialisers.py:2355 #: documents/serialisers.py:2358
#, python-format #, python-format
msgid "Custom field with id %(id)s does not exist" msgid "Custom field with id %(id)s does not exist"
msgstr "" msgstr ""
#: documents/serialisers.py:2372 documents/serialisers.py:2382 #: documents/serialisers.py:2375 documents/serialisers.py:2385
msgid "Custom fields must be a list of integers or an object mapping ids to values." msgid "Custom fields must be a list of integers or an object mapping ids to values."
msgstr "" msgstr ""
#: documents/serialisers.py:2377 #: documents/serialisers.py:2380
msgid "Some custom fields don't exist or were specified twice." msgid "Some custom fields don't exist or were specified twice."
msgstr "" msgstr ""
#: documents/serialisers.py:2524 #: documents/serialisers.py:2527
msgid "Invalid variable detected." msgid "Invalid variable detected."
msgstr "Ugyldig variabel fundet." msgstr "Ugyldig variabel fundet."
#: documents/serialisers.py:2883 #: documents/serialisers.py:2886
msgid "Duplicate document identifiers are not allowed." msgid "Duplicate document identifiers are not allowed."
msgstr "" msgstr ""
#: documents/serialisers.py:2913 documents/views.py:4608 #: documents/serialisers.py:2916 documents/views.py:4610
#, python-format #, python-format
msgid "Documents not found: %(ids)s" msgid "Documents not found: %(ids)s"
msgstr "" msgstr ""
@@ -1907,36 +1907,36 @@ msgstr ""
msgid "Unable to parse URI {value}" msgid "Unable to parse URI {value}"
msgstr "" msgstr ""
#: documents/views.py:306 documents/views.py:2608 #: documents/views.py:306 documents/views.py:2610
msgid "Invalid more_like_id" msgid "Invalid more_like_id"
msgstr "" msgstr ""
#: documents/views.py:1582 #: documents/views.py:1584
msgid "Invalid AI configuration." msgid "Invalid AI configuration."
msgstr "" msgstr ""
#: documents/views.py:1593 #: documents/views.py:1595
msgid "AI backend request timed out." msgid "AI backend request timed out."
msgstr "" msgstr ""
#: documents/views.py:2433 documents/views.py:2754 #: documents/views.py:2435 documents/views.py:2756
msgid "Specify only one of text, title_search, query, or more_like_id." msgid "Specify only one of text, title_search, query, or more_like_id."
msgstr "" msgstr ""
#: documents/views.py:4621 #: documents/views.py:4623
#, python-format #, python-format
msgid "Insufficient permissions to share document %(id)s." msgid "Insufficient permissions to share document %(id)s."
msgstr "" msgstr ""
#: documents/views.py:4667 #: documents/views.py:4669
msgid "Bundle is already being processed." msgid "Bundle is already being processed."
msgstr "" msgstr ""
#: documents/views.py:4728 #: documents/views.py:4730
msgid "The share link bundle is still being prepared. Please try again later." msgid "The share link bundle is still being prepared. Please try again later."
msgstr "" msgstr ""
#: documents/views.py:4738 #: documents/views.py:4740
msgid "The share link bundle is unavailable." msgid "The share link bundle is unavailable."
msgstr "" msgstr ""
+21 -21
View File
@@ -2,8 +2,8 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: paperless-ngx\n" "Project-Id-Version: paperless-ngx\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2026-08-29 20:02+0000\n" "POT-Creation-Date: 2026-09-01 14:47+0000\n"
"PO-Revision-Date: 2026-08-29 20:04\n" "PO-Revision-Date: 2026-09-01 14:48\n"
"Last-Translator: \n" "Last-Translator: \n"
"Language-Team: German, Switzerland\n" "Language-Team: German, Switzerland\n"
"Language: de_CH\n" "Language: de_CH\n"
@@ -1610,48 +1610,48 @@ msgstr "Arbeitsablauf-Ausführung"
msgid "workflow runs" msgid "workflow runs"
msgstr "Arbeitsablauf wird ausgeführt" msgstr "Arbeitsablauf wird ausgeführt"
#: documents/serialisers.py:523 documents/serialisers.py:875 #: documents/serialisers.py:524 documents/serialisers.py:878
#: documents/serialisers.py:2827 documents/views.py:313 documents/views.py:2611 #: documents/serialisers.py:2830 documents/views.py:313 documents/views.py:2613
#: paperless_mail/serialisers.py:156 #: paperless_mail/serialisers.py:156
msgid "Insufficient permissions." msgid "Insufficient permissions."
msgstr "Unzureichende Berechtigungen." msgstr "Unzureichende Berechtigungen."
#: documents/serialisers.py:711 #: documents/serialisers.py:714
msgid "Invalid color." msgid "Invalid color."
msgstr "Ungültige Farbe." msgstr "Ungültige Farbe."
#: documents/serialisers.py:2304 #: documents/serialisers.py:2307
#, python-format #, python-format
msgid "File type %(type)s not supported" msgid "File type %(type)s not supported"
msgstr "Dateityp %(type)s nicht unterstützt" msgstr "Dateityp %(type)s nicht unterstützt"
#: documents/serialisers.py:2348 #: documents/serialisers.py:2351
#, python-format #, python-format
msgid "Custom field id must be an integer: %(id)s" msgid "Custom field id must be an integer: %(id)s"
msgstr "Feld-ID eines benutzerdefinierten Felds muss eine Ganzzahl sein: %(id)s" msgstr "Feld-ID eines benutzerdefinierten Felds muss eine Ganzzahl sein: %(id)s"
#: documents/serialisers.py:2355 #: documents/serialisers.py:2358
#, python-format #, python-format
msgid "Custom field with id %(id)s does not exist" msgid "Custom field with id %(id)s does not exist"
msgstr "Benutzerdefiniertes Feld mit ID %(id)s existiert nicht" msgstr "Benutzerdefiniertes Feld mit ID %(id)s existiert nicht"
#: documents/serialisers.py:2372 documents/serialisers.py:2382 #: documents/serialisers.py:2375 documents/serialisers.py:2385
msgid "Custom fields must be a list of integers or an object mapping ids to values." msgid "Custom fields must be a list of integers or an object mapping ids to values."
msgstr "Benutzerdefinierte Felder müssen eine Liste von Ganzzahlen oder ein Objekt mit Zuordnung von IDs zu Werten sein." msgstr "Benutzerdefinierte Felder müssen eine Liste von Ganzzahlen oder ein Objekt mit Zuordnung von IDs zu Werten sein."
#: documents/serialisers.py:2377 #: documents/serialisers.py:2380
msgid "Some custom fields don't exist or were specified twice." msgid "Some custom fields don't exist or were specified twice."
msgstr "Einige benutzerdefinierte Felder existieren nicht oder wurden zweimal angegeben." msgstr "Einige benutzerdefinierte Felder existieren nicht oder wurden zweimal angegeben."
#: documents/serialisers.py:2524 #: documents/serialisers.py:2527
msgid "Invalid variable detected." msgid "Invalid variable detected."
msgstr "Ungültige Variable erkannt." msgstr "Ungültige Variable erkannt."
#: documents/serialisers.py:2883 #: documents/serialisers.py:2886
msgid "Duplicate document identifiers are not allowed." msgid "Duplicate document identifiers are not allowed."
msgstr "Doppelte Dokumentbezeichner sind nicht erlaubt." msgstr "Doppelte Dokumentbezeichner sind nicht erlaubt."
#: documents/serialisers.py:2913 documents/views.py:4608 #: documents/serialisers.py:2916 documents/views.py:4610
#, python-format #, python-format
msgid "Documents not found: %(ids)s" msgid "Documents not found: %(ids)s"
msgstr "Dokumente nicht gefunden: %(ids)s" msgstr "Dokumente nicht gefunden: %(ids)s"
@@ -1907,36 +1907,36 @@ msgstr "URI-Schema „{parts.scheme}“ ist nicht erlaubt. Erlaubte Schemata: {'
msgid "Unable to parse URI {value}" msgid "Unable to parse URI {value}"
msgstr "URI {value} kann nicht gelesen werden" msgstr "URI {value} kann nicht gelesen werden"
#: documents/views.py:306 documents/views.py:2608 #: documents/views.py:306 documents/views.py:2610
msgid "Invalid more_like_id" msgid "Invalid more_like_id"
msgstr "Ungültige more_like_id" msgstr "Ungültige more_like_id"
#: documents/views.py:1582 #: documents/views.py:1584
msgid "Invalid AI configuration." msgid "Invalid AI configuration."
msgstr "Ungültige KI-Konfiguration." msgstr "Ungültige KI-Konfiguration."
#: documents/views.py:1593 #: documents/views.py:1595
msgid "AI backend request timed out." msgid "AI backend request timed out."
msgstr "" msgstr ""
#: documents/views.py:2433 documents/views.py:2754 #: documents/views.py:2435 documents/views.py:2756
msgid "Specify only one of text, title_search, query, or more_like_id." msgid "Specify only one of text, title_search, query, or more_like_id."
msgstr "Geben Sie nur einen von text, title_search, query, oder more_like_id an." msgstr "Geben Sie nur einen von text, title_search, query, oder more_like_id an."
#: documents/views.py:4621 #: documents/views.py:4623
#, python-format #, python-format
msgid "Insufficient permissions to share document %(id)s." msgid "Insufficient permissions to share document %(id)s."
msgstr "Unzureichende Berechtigungen, um Dokument %(id)s zu teilen." msgstr "Unzureichende Berechtigungen, um Dokument %(id)s zu teilen."
#: documents/views.py:4667 #: documents/views.py:4669
msgid "Bundle is already being processed." msgid "Bundle is already being processed."
msgstr "Paket wird bereits verarbeitet." msgstr "Paket wird bereits verarbeitet."
#: documents/views.py:4728 #: documents/views.py:4730
msgid "The share link bundle is still being prepared. Please try again later." msgid "The share link bundle is still being prepared. Please try again later."
msgstr "Das Freigabelink-Paket wird noch vorbereitet. Bitte versuchen Sie es später erneut." msgstr "Das Freigabelink-Paket wird noch vorbereitet. Bitte versuchen Sie es später erneut."
#: documents/views.py:4738 #: documents/views.py:4740
msgid "The share link bundle is unavailable." msgid "The share link bundle is unavailable."
msgstr "Das Freigabelink-Paket ist nicht verfügbar." msgstr "Das Freigabelink-Paket ist nicht verfügbar."
+21 -21
View File
@@ -2,8 +2,8 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: paperless-ngx\n" "Project-Id-Version: paperless-ngx\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2026-08-29 20:02+0000\n" "POT-Creation-Date: 2026-09-01 14:47+0000\n"
"PO-Revision-Date: 2026-08-29 20:04\n" "PO-Revision-Date: 2026-09-01 14:48\n"
"Last-Translator: \n" "Last-Translator: \n"
"Language-Team: German\n" "Language-Team: German\n"
"Language: de_DE\n" "Language: de_DE\n"
@@ -1610,48 +1610,48 @@ msgstr "Arbeitsablauf-Ausführung"
msgid "workflow runs" msgid "workflow runs"
msgstr "Arbeitsablauf wird ausgeführt" msgstr "Arbeitsablauf wird ausgeführt"
#: documents/serialisers.py:523 documents/serialisers.py:875 #: documents/serialisers.py:524 documents/serialisers.py:878
#: documents/serialisers.py:2827 documents/views.py:313 documents/views.py:2611 #: documents/serialisers.py:2830 documents/views.py:313 documents/views.py:2613
#: paperless_mail/serialisers.py:156 #: paperless_mail/serialisers.py:156
msgid "Insufficient permissions." msgid "Insufficient permissions."
msgstr "Unzureichende Berechtigungen." msgstr "Unzureichende Berechtigungen."
#: documents/serialisers.py:711 #: documents/serialisers.py:714
msgid "Invalid color." msgid "Invalid color."
msgstr "Ungültige Farbe." msgstr "Ungültige Farbe."
#: documents/serialisers.py:2304 #: documents/serialisers.py:2307
#, python-format #, python-format
msgid "File type %(type)s not supported" msgid "File type %(type)s not supported"
msgstr "Dateityp %(type)s nicht unterstützt" msgstr "Dateityp %(type)s nicht unterstützt"
#: documents/serialisers.py:2348 #: documents/serialisers.py:2351
#, python-format #, python-format
msgid "Custom field id must be an integer: %(id)s" msgid "Custom field id must be an integer: %(id)s"
msgstr "Zusatzfeld-ID muss eine Ganzzahl sein: %(id)s" msgstr "Zusatzfeld-ID muss eine Ganzzahl sein: %(id)s"
#: documents/serialisers.py:2355 #: documents/serialisers.py:2358
#, python-format #, python-format
msgid "Custom field with id %(id)s does not exist" msgid "Custom field with id %(id)s does not exist"
msgstr "Zusatzfeld mit ID %(id)s existiert nicht" msgstr "Zusatzfeld mit ID %(id)s existiert nicht"
#: documents/serialisers.py:2372 documents/serialisers.py:2382 #: documents/serialisers.py:2375 documents/serialisers.py:2385
msgid "Custom fields must be a list of integers or an object mapping ids to values." msgid "Custom fields must be a list of integers or an object mapping ids to values."
msgstr "Zusatzfelder müssen eine Liste von Ganzzahlen oder ein Objekt mit Zuordnung von IDs zu Werten sein." msgstr "Zusatzfelder müssen eine Liste von Ganzzahlen oder ein Objekt mit Zuordnung von IDs zu Werten sein."
#: documents/serialisers.py:2377 #: documents/serialisers.py:2380
msgid "Some custom fields don't exist or were specified twice." msgid "Some custom fields don't exist or were specified twice."
msgstr "Einige Zusatzfelder existieren nicht oder wurden zweimal angegeben." msgstr "Einige Zusatzfelder existieren nicht oder wurden zweimal angegeben."
#: documents/serialisers.py:2524 #: documents/serialisers.py:2527
msgid "Invalid variable detected." msgid "Invalid variable detected."
msgstr "Ungültige Variable erkannt." msgstr "Ungültige Variable erkannt."
#: documents/serialisers.py:2883 #: documents/serialisers.py:2886
msgid "Duplicate document identifiers are not allowed." msgid "Duplicate document identifiers are not allowed."
msgstr "Doppelte Dokumentbezeichner sind nicht erlaubt." msgstr "Doppelte Dokumentbezeichner sind nicht erlaubt."
#: documents/serialisers.py:2913 documents/views.py:4608 #: documents/serialisers.py:2916 documents/views.py:4610
#, python-format #, python-format
msgid "Documents not found: %(ids)s" msgid "Documents not found: %(ids)s"
msgstr "Dokumente nicht gefunden: %(ids)s" msgstr "Dokumente nicht gefunden: %(ids)s"
@@ -1907,36 +1907,36 @@ msgstr "URI-Schema „{parts.scheme}“ ist nicht erlaubt. Erlaubte Schemata: {'
msgid "Unable to parse URI {value}" msgid "Unable to parse URI {value}"
msgstr "URI {value} kann nicht gelesen werden" msgstr "URI {value} kann nicht gelesen werden"
#: documents/views.py:306 documents/views.py:2608 #: documents/views.py:306 documents/views.py:2610
msgid "Invalid more_like_id" msgid "Invalid more_like_id"
msgstr "Ungültige more_like_id" msgstr "Ungültige more_like_id"
#: documents/views.py:1582 #: documents/views.py:1584
msgid "Invalid AI configuration." msgid "Invalid AI configuration."
msgstr "Ungültige KI-Konfiguration." msgstr "Ungültige KI-Konfiguration."
#: documents/views.py:1593 #: documents/views.py:1595
msgid "AI backend request timed out." msgid "AI backend request timed out."
msgstr "Zeitüberschreitung bei der KI-Backendanfrage." msgstr "Zeitüberschreitung bei der KI-Backendanfrage."
#: documents/views.py:2433 documents/views.py:2754 #: documents/views.py:2435 documents/views.py:2756
msgid "Specify only one of text, title_search, query, or more_like_id." msgid "Specify only one of text, title_search, query, or more_like_id."
msgstr "Geben Sie nur einen von text, title_search, query, oder more_like_id an." msgstr "Geben Sie nur einen von text, title_search, query, oder more_like_id an."
#: documents/views.py:4621 #: documents/views.py:4623
#, python-format #, python-format
msgid "Insufficient permissions to share document %(id)s." msgid "Insufficient permissions to share document %(id)s."
msgstr "Unzureichende Berechtigungen, um Dokument %(id)s zu teilen." msgstr "Unzureichende Berechtigungen, um Dokument %(id)s zu teilen."
#: documents/views.py:4667 #: documents/views.py:4669
msgid "Bundle is already being processed." msgid "Bundle is already being processed."
msgstr "Paket wird bereits verarbeitet." msgstr "Paket wird bereits verarbeitet."
#: documents/views.py:4728 #: documents/views.py:4730
msgid "The share link bundle is still being prepared. Please try again later." msgid "The share link bundle is still being prepared. Please try again later."
msgstr "Das Freigabelink-Paket wird noch vorbereitet. Bitte versuchen Sie es später erneut." msgstr "Das Freigabelink-Paket wird noch vorbereitet. Bitte versuchen Sie es später erneut."
#: documents/views.py:4738 #: documents/views.py:4740
msgid "The share link bundle is unavailable." msgid "The share link bundle is unavailable."
msgstr "Das Freigabelink-Paket ist nicht verfügbar." msgstr "Das Freigabelink-Paket ist nicht verfügbar."
+21 -21
View File
@@ -2,8 +2,8 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: paperless-ngx\n" "Project-Id-Version: paperless-ngx\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2026-08-29 20:02+0000\n" "POT-Creation-Date: 2026-09-01 14:47+0000\n"
"PO-Revision-Date: 2026-08-29 20:04\n" "PO-Revision-Date: 2026-09-01 14:48\n"
"Last-Translator: \n" "Last-Translator: \n"
"Language-Team: Greek\n" "Language-Team: Greek\n"
"Language: el_GR\n" "Language: el_GR\n"
@@ -1610,48 +1610,48 @@ msgstr "εκτέλεση ροής εργασίας"
msgid "workflow runs" msgid "workflow runs"
msgstr "εκτελέσεις ροής εργασίας" msgstr "εκτελέσεις ροής εργασίας"
#: documents/serialisers.py:523 documents/serialisers.py:875 #: documents/serialisers.py:524 documents/serialisers.py:878
#: documents/serialisers.py:2827 documents/views.py:313 documents/views.py:2611 #: documents/serialisers.py:2830 documents/views.py:313 documents/views.py:2613
#: paperless_mail/serialisers.py:156 #: paperless_mail/serialisers.py:156
msgid "Insufficient permissions." msgid "Insufficient permissions."
msgstr "" msgstr ""
#: documents/serialisers.py:711 #: documents/serialisers.py:714
msgid "Invalid color." msgid "Invalid color."
msgstr "Άκυρο χρώμα." msgstr "Άκυρο χρώμα."
#: documents/serialisers.py:2304 #: documents/serialisers.py:2307
#, python-format #, python-format
msgid "File type %(type)s not supported" msgid "File type %(type)s not supported"
msgstr "Ο τύπος αρχείου %(type)s δεν υποστηρίζεται" msgstr "Ο τύπος αρχείου %(type)s δεν υποστηρίζεται"
#: documents/serialisers.py:2348 #: documents/serialisers.py:2351
#, python-format #, python-format
msgid "Custom field id must be an integer: %(id)s" msgid "Custom field id must be an integer: %(id)s"
msgstr "" msgstr ""
#: documents/serialisers.py:2355 #: documents/serialisers.py:2358
#, python-format #, python-format
msgid "Custom field with id %(id)s does not exist" msgid "Custom field with id %(id)s does not exist"
msgstr "" msgstr ""
#: documents/serialisers.py:2372 documents/serialisers.py:2382 #: documents/serialisers.py:2375 documents/serialisers.py:2385
msgid "Custom fields must be a list of integers or an object mapping ids to values." msgid "Custom fields must be a list of integers or an object mapping ids to values."
msgstr "" msgstr ""
#: documents/serialisers.py:2377 #: documents/serialisers.py:2380
msgid "Some custom fields don't exist or were specified twice." msgid "Some custom fields don't exist or were specified twice."
msgstr "" msgstr ""
#: documents/serialisers.py:2524 #: documents/serialisers.py:2527
msgid "Invalid variable detected." msgid "Invalid variable detected."
msgstr "Εντοπίστηκε μη έγκυρη μεταβλητή." msgstr "Εντοπίστηκε μη έγκυρη μεταβλητή."
#: documents/serialisers.py:2883 #: documents/serialisers.py:2886
msgid "Duplicate document identifiers are not allowed." msgid "Duplicate document identifiers are not allowed."
msgstr "" msgstr ""
#: documents/serialisers.py:2913 documents/views.py:4608 #: documents/serialisers.py:2916 documents/views.py:4610
#, python-format #, python-format
msgid "Documents not found: %(ids)s" msgid "Documents not found: %(ids)s"
msgstr "" msgstr ""
@@ -1907,36 +1907,36 @@ msgstr ""
msgid "Unable to parse URI {value}" msgid "Unable to parse URI {value}"
msgstr "" msgstr ""
#: documents/views.py:306 documents/views.py:2608 #: documents/views.py:306 documents/views.py:2610
msgid "Invalid more_like_id" msgid "Invalid more_like_id"
msgstr "" msgstr ""
#: documents/views.py:1582 #: documents/views.py:1584
msgid "Invalid AI configuration." msgid "Invalid AI configuration."
msgstr "" msgstr ""
#: documents/views.py:1593 #: documents/views.py:1595
msgid "AI backend request timed out." msgid "AI backend request timed out."
msgstr "" msgstr ""
#: documents/views.py:2433 documents/views.py:2754 #: documents/views.py:2435 documents/views.py:2756
msgid "Specify only one of text, title_search, query, or more_like_id." msgid "Specify only one of text, title_search, query, or more_like_id."
msgstr "" msgstr ""
#: documents/views.py:4621 #: documents/views.py:4623
#, python-format #, python-format
msgid "Insufficient permissions to share document %(id)s." msgid "Insufficient permissions to share document %(id)s."
msgstr "" msgstr ""
#: documents/views.py:4667 #: documents/views.py:4669
msgid "Bundle is already being processed." msgid "Bundle is already being processed."
msgstr "" msgstr ""
#: documents/views.py:4728 #: documents/views.py:4730
msgid "The share link bundle is still being prepared. Please try again later." msgid "The share link bundle is still being prepared. Please try again later."
msgstr "" msgstr ""
#: documents/views.py:4738 #: documents/views.py:4740
msgid "The share link bundle is unavailable." msgid "The share link bundle is unavailable."
msgstr "" msgstr ""
+20 -20
View File
@@ -2,7 +2,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: paperless-ngx\n" "Project-Id-Version: paperless-ngx\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2026-08-29 20:02+0000\n" "POT-Creation-Date: 2026-09-01 14:47+0000\n"
"PO-Revision-Date: 2022-02-17 04:17\n" "PO-Revision-Date: 2022-02-17 04:17\n"
"Last-Translator: \n" "Last-Translator: \n"
"Language-Team: English\n" "Language-Team: English\n"
@@ -1627,49 +1627,49 @@ msgstr ""
msgid "workflow runs" msgid "workflow runs"
msgstr "" msgstr ""
#: documents/serialisers.py:523 documents/serialisers.py:875 #: documents/serialisers.py:524 documents/serialisers.py:878
#: documents/serialisers.py:2827 documents/views.py:313 documents/views.py:2611 #: documents/serialisers.py:2830 documents/views.py:313 documents/views.py:2613
#: paperless_mail/serialisers.py:156 #: paperless_mail/serialisers.py:156
msgid "Insufficient permissions." msgid "Insufficient permissions."
msgstr "" msgstr ""
#: documents/serialisers.py:711 #: documents/serialisers.py:714
msgid "Invalid color." msgid "Invalid color."
msgstr "" msgstr ""
#: documents/serialisers.py:2304 #: documents/serialisers.py:2307
#, python-format #, python-format
msgid "File type %(type)s not supported" msgid "File type %(type)s not supported"
msgstr "" msgstr ""
#: documents/serialisers.py:2348 #: documents/serialisers.py:2351
#, python-format #, python-format
msgid "Custom field id must be an integer: %(id)s" msgid "Custom field id must be an integer: %(id)s"
msgstr "" msgstr ""
#: documents/serialisers.py:2355 #: documents/serialisers.py:2358
#, python-format #, python-format
msgid "Custom field with id %(id)s does not exist" msgid "Custom field with id %(id)s does not exist"
msgstr "" msgstr ""
#: documents/serialisers.py:2372 documents/serialisers.py:2382 #: documents/serialisers.py:2375 documents/serialisers.py:2385
msgid "" msgid ""
"Custom fields must be a list of integers or an object mapping ids to values." "Custom fields must be a list of integers or an object mapping ids to values."
msgstr "" msgstr ""
#: documents/serialisers.py:2377 #: documents/serialisers.py:2380
msgid "Some custom fields don't exist or were specified twice." msgid "Some custom fields don't exist or were specified twice."
msgstr "" msgstr ""
#: documents/serialisers.py:2524 #: documents/serialisers.py:2527
msgid "Invalid variable detected." msgid "Invalid variable detected."
msgstr "" msgstr ""
#: documents/serialisers.py:2883 #: documents/serialisers.py:2886
msgid "Duplicate document identifiers are not allowed." msgid "Duplicate document identifiers are not allowed."
msgstr "" msgstr ""
#: documents/serialisers.py:2913 documents/views.py:4608 #: documents/serialisers.py:2916 documents/views.py:4610
#, python-format #, python-format
msgid "Documents not found: %(ids)s" msgid "Documents not found: %(ids)s"
msgstr "" msgstr ""
@@ -1937,36 +1937,36 @@ msgstr ""
msgid "Unable to parse URI {value}" msgid "Unable to parse URI {value}"
msgstr "" msgstr ""
#: documents/views.py:306 documents/views.py:2608 #: documents/views.py:306 documents/views.py:2610
msgid "Invalid more_like_id" msgid "Invalid more_like_id"
msgstr "" msgstr ""
#: documents/views.py:1582 #: documents/views.py:1584
msgid "Invalid AI configuration." msgid "Invalid AI configuration."
msgstr "" msgstr ""
#: documents/views.py:1593 #: documents/views.py:1595
msgid "AI backend request timed out." msgid "AI backend request timed out."
msgstr "" msgstr ""
#: documents/views.py:2433 documents/views.py:2754 #: documents/views.py:2435 documents/views.py:2756
msgid "Specify only one of text, title_search, query, or more_like_id." msgid "Specify only one of text, title_search, query, or more_like_id."
msgstr "" msgstr ""
#: documents/views.py:4621 #: documents/views.py:4623
#, python-format #, python-format
msgid "Insufficient permissions to share document %(id)s." msgid "Insufficient permissions to share document %(id)s."
msgstr "" msgstr ""
#: documents/views.py:4667 #: documents/views.py:4669
msgid "Bundle is already being processed." msgid "Bundle is already being processed."
msgstr "" msgstr ""
#: documents/views.py:4728 #: documents/views.py:4730
msgid "The share link bundle is still being prepared. Please try again later." msgid "The share link bundle is still being prepared. Please try again later."
msgstr "" msgstr ""
#: documents/views.py:4738 #: documents/views.py:4740
msgid "The share link bundle is unavailable." msgid "The share link bundle is unavailable."
msgstr "" msgstr ""
+21 -21
View File
@@ -2,8 +2,8 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: paperless-ngx\n" "Project-Id-Version: paperless-ngx\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2026-08-29 20:02+0000\n" "POT-Creation-Date: 2026-09-01 14:47+0000\n"
"PO-Revision-Date: 2026-08-29 20:04\n" "PO-Revision-Date: 2026-09-01 14:48\n"
"Last-Translator: \n" "Last-Translator: \n"
"Language-Team: Spanish\n" "Language-Team: Spanish\n"
"Language: es_ES\n" "Language: es_ES\n"
@@ -1610,48 +1610,48 @@ msgstr "ejecución del flujo de trabajo"
msgid "workflow runs" msgid "workflow runs"
msgstr "ejecuciones de flujo de trabajo" msgstr "ejecuciones de flujo de trabajo"
#: documents/serialisers.py:523 documents/serialisers.py:875 #: documents/serialisers.py:524 documents/serialisers.py:878
#: documents/serialisers.py:2827 documents/views.py:313 documents/views.py:2611 #: documents/serialisers.py:2830 documents/views.py:313 documents/views.py:2613
#: paperless_mail/serialisers.py:156 #: paperless_mail/serialisers.py:156
msgid "Insufficient permissions." msgid "Insufficient permissions."
msgstr "Permisos insuficientes." msgstr "Permisos insuficientes."
#: documents/serialisers.py:711 #: documents/serialisers.py:714
msgid "Invalid color." msgid "Invalid color."
msgstr "Color inválido." msgstr "Color inválido."
#: documents/serialisers.py:2304 #: documents/serialisers.py:2307
#, python-format #, python-format
msgid "File type %(type)s not supported" msgid "File type %(type)s not supported"
msgstr "Tipo de fichero %(type)s no suportado" msgstr "Tipo de fichero %(type)s no suportado"
#: documents/serialisers.py:2348 #: documents/serialisers.py:2351
#, python-format #, python-format
msgid "Custom field id must be an integer: %(id)s" msgid "Custom field id must be an integer: %(id)s"
msgstr "El id del campo personalizado debe ser un entero: %(id)s" msgstr "El id del campo personalizado debe ser un entero: %(id)s"
#: documents/serialisers.py:2355 #: documents/serialisers.py:2358
#, python-format #, python-format
msgid "Custom field with id %(id)s does not exist" msgid "Custom field with id %(id)s does not exist"
msgstr "El campo personalizado con identificador %(id)s no existe" msgstr "El campo personalizado con identificador %(id)s no existe"
#: documents/serialisers.py:2372 documents/serialisers.py:2382 #: documents/serialisers.py:2375 documents/serialisers.py:2385
msgid "Custom fields must be a list of integers or an object mapping ids to values." msgid "Custom fields must be a list of integers or an object mapping ids to values."
msgstr "Los campos personalizados deben ser una lista de enteros o un identificador de mapeo de objetos a valores." msgstr "Los campos personalizados deben ser una lista de enteros o un identificador de mapeo de objetos a valores."
#: documents/serialisers.py:2377 #: documents/serialisers.py:2380
msgid "Some custom fields don't exist or were specified twice." msgid "Some custom fields don't exist or were specified twice."
msgstr "Algunos campos personalizados no existen o fueron especificados dos veces." msgstr "Algunos campos personalizados no existen o fueron especificados dos veces."
#: documents/serialisers.py:2524 #: documents/serialisers.py:2527
msgid "Invalid variable detected." msgid "Invalid variable detected."
msgstr "Variable inválida." msgstr "Variable inválida."
#: documents/serialisers.py:2883 #: documents/serialisers.py:2886
msgid "Duplicate document identifiers are not allowed." msgid "Duplicate document identifiers are not allowed."
msgstr "No se permiten identificadores de documento duplicados." msgstr "No se permiten identificadores de documento duplicados."
#: documents/serialisers.py:2913 documents/views.py:4608 #: documents/serialisers.py:2916 documents/views.py:4610
#, python-format #, python-format
msgid "Documents not found: %(ids)s" msgid "Documents not found: %(ids)s"
msgstr "Documentos no encontrados: %(ids)s" msgstr "Documentos no encontrados: %(ids)s"
@@ -1907,36 +1907,36 @@ msgstr "El esquema URI '{parts.scheme}' no está permitido. Esquemas permitidos:
msgid "Unable to parse URI {value}" msgid "Unable to parse URI {value}"
msgstr "No se puede analizar la URI {value}" msgstr "No se puede analizar la URI {value}"
#: documents/views.py:306 documents/views.py:2608 #: documents/views.py:306 documents/views.py:2610
msgid "Invalid more_like_id" msgid "Invalid more_like_id"
msgstr "" msgstr ""
#: documents/views.py:1582 #: documents/views.py:1584
msgid "Invalid AI configuration." msgid "Invalid AI configuration."
msgstr "Configuración de IA inválida." msgstr "Configuración de IA inválida."
#: documents/views.py:1593 #: documents/views.py:1595
msgid "AI backend request timed out." msgid "AI backend request timed out."
msgstr "" msgstr ""
#: documents/views.py:2433 documents/views.py:2754 #: documents/views.py:2435 documents/views.py:2756
msgid "Specify only one of text, title_search, query, or more_like_id." msgid "Specify only one of text, title_search, query, or more_like_id."
msgstr "Especifique solo uno entre text, title_search, query, o more_like_id." msgstr "Especifique solo uno entre text, title_search, query, o more_like_id."
#: documents/views.py:4621 #: documents/views.py:4623
#, python-format #, python-format
msgid "Insufficient permissions to share document %(id)s." msgid "Insufficient permissions to share document %(id)s."
msgstr "Permisos insuficientes para compartir el documento %(id)s." msgstr "Permisos insuficientes para compartir el documento %(id)s."
#: documents/views.py:4667 #: documents/views.py:4669
msgid "Bundle is already being processed." msgid "Bundle is already being processed."
msgstr "El paquete ya está siendo procesado." msgstr "El paquete ya está siendo procesado."
#: documents/views.py:4728 #: documents/views.py:4730
msgid "The share link bundle is still being prepared. Please try again later." msgid "The share link bundle is still being prepared. Please try again later."
msgstr "El paquete de enlace compartido aún está siendo preparado. Por favor, inténtalo de nuevo más tarde." msgstr "El paquete de enlace compartido aún está siendo preparado. Por favor, inténtalo de nuevo más tarde."
#: documents/views.py:4738 #: documents/views.py:4740
msgid "The share link bundle is unavailable." msgid "The share link bundle is unavailable."
msgstr "El paquete de enlace compartido no está disponible." msgstr "El paquete de enlace compartido no está disponible."
+21 -21
View File
@@ -2,8 +2,8 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: paperless-ngx\n" "Project-Id-Version: paperless-ngx\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2026-08-29 20:02+0000\n" "POT-Creation-Date: 2026-09-01 14:47+0000\n"
"PO-Revision-Date: 2026-08-29 20:04\n" "PO-Revision-Date: 2026-09-01 14:48\n"
"Last-Translator: \n" "Last-Translator: \n"
"Language-Team: Estonian\n" "Language-Team: Estonian\n"
"Language: et_EE\n" "Language: et_EE\n"
@@ -1610,48 +1610,48 @@ msgstr ""
msgid "workflow runs" msgid "workflow runs"
msgstr "" msgstr ""
#: documents/serialisers.py:523 documents/serialisers.py:875 #: documents/serialisers.py:524 documents/serialisers.py:878
#: documents/serialisers.py:2827 documents/views.py:313 documents/views.py:2611 #: documents/serialisers.py:2830 documents/views.py:313 documents/views.py:2613
#: paperless_mail/serialisers.py:156 #: paperless_mail/serialisers.py:156
msgid "Insufficient permissions." msgid "Insufficient permissions."
msgstr "" msgstr ""
#: documents/serialisers.py:711 #: documents/serialisers.py:714
msgid "Invalid color." msgid "Invalid color."
msgstr "" msgstr ""
#: documents/serialisers.py:2304 #: documents/serialisers.py:2307
#, python-format #, python-format
msgid "File type %(type)s not supported" msgid "File type %(type)s not supported"
msgstr "" msgstr ""
#: documents/serialisers.py:2348 #: documents/serialisers.py:2351
#, python-format #, python-format
msgid "Custom field id must be an integer: %(id)s" msgid "Custom field id must be an integer: %(id)s"
msgstr "" msgstr ""
#: documents/serialisers.py:2355 #: documents/serialisers.py:2358
#, python-format #, python-format
msgid "Custom field with id %(id)s does not exist" msgid "Custom field with id %(id)s does not exist"
msgstr "" msgstr ""
#: documents/serialisers.py:2372 documents/serialisers.py:2382 #: documents/serialisers.py:2375 documents/serialisers.py:2385
msgid "Custom fields must be a list of integers or an object mapping ids to values." msgid "Custom fields must be a list of integers or an object mapping ids to values."
msgstr "" msgstr ""
#: documents/serialisers.py:2377 #: documents/serialisers.py:2380
msgid "Some custom fields don't exist or were specified twice." msgid "Some custom fields don't exist or were specified twice."
msgstr "" msgstr ""
#: documents/serialisers.py:2524 #: documents/serialisers.py:2527
msgid "Invalid variable detected." msgid "Invalid variable detected."
msgstr "" msgstr ""
#: documents/serialisers.py:2883 #: documents/serialisers.py:2886
msgid "Duplicate document identifiers are not allowed." msgid "Duplicate document identifiers are not allowed."
msgstr "" msgstr ""
#: documents/serialisers.py:2913 documents/views.py:4608 #: documents/serialisers.py:2916 documents/views.py:4610
#, python-format #, python-format
msgid "Documents not found: %(ids)s" msgid "Documents not found: %(ids)s"
msgstr "" msgstr ""
@@ -1906,36 +1906,36 @@ msgstr ""
msgid "Unable to parse URI {value}" msgid "Unable to parse URI {value}"
msgstr "" msgstr ""
#: documents/views.py:306 documents/views.py:2608 #: documents/views.py:306 documents/views.py:2610
msgid "Invalid more_like_id" msgid "Invalid more_like_id"
msgstr "" msgstr ""
#: documents/views.py:1582 #: documents/views.py:1584
msgid "Invalid AI configuration." msgid "Invalid AI configuration."
msgstr "" msgstr ""
#: documents/views.py:1593 #: documents/views.py:1595
msgid "AI backend request timed out." msgid "AI backend request timed out."
msgstr "" msgstr ""
#: documents/views.py:2433 documents/views.py:2754 #: documents/views.py:2435 documents/views.py:2756
msgid "Specify only one of text, title_search, query, or more_like_id." msgid "Specify only one of text, title_search, query, or more_like_id."
msgstr "" msgstr ""
#: documents/views.py:4621 #: documents/views.py:4623
#, python-format #, python-format
msgid "Insufficient permissions to share document %(id)s." msgid "Insufficient permissions to share document %(id)s."
msgstr "" msgstr ""
#: documents/views.py:4667 #: documents/views.py:4669
msgid "Bundle is already being processed." msgid "Bundle is already being processed."
msgstr "" msgstr ""
#: documents/views.py:4728 #: documents/views.py:4730
msgid "The share link bundle is still being prepared. Please try again later." msgid "The share link bundle is still being prepared. Please try again later."
msgstr "" msgstr ""
#: documents/views.py:4738 #: documents/views.py:4740
msgid "The share link bundle is unavailable." msgid "The share link bundle is unavailable."
msgstr "" msgstr ""
+21 -21
View File
@@ -2,8 +2,8 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: paperless-ngx\n" "Project-Id-Version: paperless-ngx\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2026-08-29 20:02+0000\n" "POT-Creation-Date: 2026-09-01 14:47+0000\n"
"PO-Revision-Date: 2026-08-29 20:04\n" "PO-Revision-Date: 2026-09-01 14:48\n"
"Last-Translator: \n" "Last-Translator: \n"
"Language-Team: Persian\n" "Language-Team: Persian\n"
"Language: fa_IR\n" "Language: fa_IR\n"
@@ -1610,48 +1610,48 @@ msgstr "گردش کار"
msgid "workflow runs" msgid "workflow runs"
msgstr "گردش کار اجرا می شود" msgstr "گردش کار اجرا می شود"
#: documents/serialisers.py:523 documents/serialisers.py:875 #: documents/serialisers.py:524 documents/serialisers.py:878
#: documents/serialisers.py:2827 documents/views.py:313 documents/views.py:2611 #: documents/serialisers.py:2830 documents/views.py:313 documents/views.py:2613
#: paperless_mail/serialisers.py:156 #: paperless_mail/serialisers.py:156
msgid "Insufficient permissions." msgid "Insufficient permissions."
msgstr "" msgstr ""
#: documents/serialisers.py:711 #: documents/serialisers.py:714
msgid "Invalid color." msgid "Invalid color."
msgstr "رنگ نامعتبر" msgstr "رنگ نامعتبر"
#: documents/serialisers.py:2304 #: documents/serialisers.py:2307
#, python-format #, python-format
msgid "File type %(type)s not supported" msgid "File type %(type)s not supported"
msgstr "" msgstr ""
#: documents/serialisers.py:2348 #: documents/serialisers.py:2351
#, python-format #, python-format
msgid "Custom field id must be an integer: %(id)s" msgid "Custom field id must be an integer: %(id)s"
msgstr "" msgstr ""
#: documents/serialisers.py:2355 #: documents/serialisers.py:2358
#, python-format #, python-format
msgid "Custom field with id %(id)s does not exist" msgid "Custom field with id %(id)s does not exist"
msgstr "" msgstr ""
#: documents/serialisers.py:2372 documents/serialisers.py:2382 #: documents/serialisers.py:2375 documents/serialisers.py:2385
msgid "Custom fields must be a list of integers or an object mapping ids to values." msgid "Custom fields must be a list of integers or an object mapping ids to values."
msgstr "" msgstr ""
#: documents/serialisers.py:2377 #: documents/serialisers.py:2380
msgid "Some custom fields don't exist or were specified twice." msgid "Some custom fields don't exist or were specified twice."
msgstr "" msgstr ""
#: documents/serialisers.py:2524 #: documents/serialisers.py:2527
msgid "Invalid variable detected." msgid "Invalid variable detected."
msgstr "متغیر نامعتبر شناسایی شده است." msgstr "متغیر نامعتبر شناسایی شده است."
#: documents/serialisers.py:2883 #: documents/serialisers.py:2886
msgid "Duplicate document identifiers are not allowed." msgid "Duplicate document identifiers are not allowed."
msgstr "" msgstr ""
#: documents/serialisers.py:2913 documents/views.py:4608 #: documents/serialisers.py:2916 documents/views.py:4610
#, python-format #, python-format
msgid "Documents not found: %(ids)s" msgid "Documents not found: %(ids)s"
msgstr "" msgstr ""
@@ -1906,36 +1906,36 @@ msgstr ""
msgid "Unable to parse URI {value}" msgid "Unable to parse URI {value}"
msgstr "" msgstr ""
#: documents/views.py:306 documents/views.py:2608 #: documents/views.py:306 documents/views.py:2610
msgid "Invalid more_like_id" msgid "Invalid more_like_id"
msgstr "" msgstr ""
#: documents/views.py:1582 #: documents/views.py:1584
msgid "Invalid AI configuration." msgid "Invalid AI configuration."
msgstr "" msgstr ""
#: documents/views.py:1593 #: documents/views.py:1595
msgid "AI backend request timed out." msgid "AI backend request timed out."
msgstr "" msgstr ""
#: documents/views.py:2433 documents/views.py:2754 #: documents/views.py:2435 documents/views.py:2756
msgid "Specify only one of text, title_search, query, or more_like_id." msgid "Specify only one of text, title_search, query, or more_like_id."
msgstr "" msgstr ""
#: documents/views.py:4621 #: documents/views.py:4623
#, python-format #, python-format
msgid "Insufficient permissions to share document %(id)s." msgid "Insufficient permissions to share document %(id)s."
msgstr "" msgstr ""
#: documents/views.py:4667 #: documents/views.py:4669
msgid "Bundle is already being processed." msgid "Bundle is already being processed."
msgstr "" msgstr ""
#: documents/views.py:4728 #: documents/views.py:4730
msgid "The share link bundle is still being prepared. Please try again later." msgid "The share link bundle is still being prepared. Please try again later."
msgstr "" msgstr ""
#: documents/views.py:4738 #: documents/views.py:4740
msgid "The share link bundle is unavailable." msgid "The share link bundle is unavailable."
msgstr "" msgstr ""
+21 -21
View File
@@ -2,8 +2,8 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: paperless-ngx\n" "Project-Id-Version: paperless-ngx\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2026-08-29 20:02+0000\n" "POT-Creation-Date: 2026-09-01 14:47+0000\n"
"PO-Revision-Date: 2026-08-29 20:04\n" "PO-Revision-Date: 2026-09-01 14:48\n"
"Last-Translator: \n" "Last-Translator: \n"
"Language-Team: Finnish\n" "Language-Team: Finnish\n"
"Language: fi_FI\n" "Language: fi_FI\n"
@@ -1610,48 +1610,48 @@ msgstr ""
msgid "workflow runs" msgid "workflow runs"
msgstr "" msgstr ""
#: documents/serialisers.py:523 documents/serialisers.py:875 #: documents/serialisers.py:524 documents/serialisers.py:878
#: documents/serialisers.py:2827 documents/views.py:313 documents/views.py:2611 #: documents/serialisers.py:2830 documents/views.py:313 documents/views.py:2613
#: paperless_mail/serialisers.py:156 #: paperless_mail/serialisers.py:156
msgid "Insufficient permissions." msgid "Insufficient permissions."
msgstr "" msgstr ""
#: documents/serialisers.py:711 #: documents/serialisers.py:714
msgid "Invalid color." msgid "Invalid color."
msgstr "Virheellinen väri." msgstr "Virheellinen väri."
#: documents/serialisers.py:2304 #: documents/serialisers.py:2307
#, python-format #, python-format
msgid "File type %(type)s not supported" msgid "File type %(type)s not supported"
msgstr "Tiedostotyyppiä %(type)s ei tueta" msgstr "Tiedostotyyppiä %(type)s ei tueta"
#: documents/serialisers.py:2348 #: documents/serialisers.py:2351
#, python-format #, python-format
msgid "Custom field id must be an integer: %(id)s" msgid "Custom field id must be an integer: %(id)s"
msgstr "" msgstr ""
#: documents/serialisers.py:2355 #: documents/serialisers.py:2358
#, python-format #, python-format
msgid "Custom field with id %(id)s does not exist" msgid "Custom field with id %(id)s does not exist"
msgstr "" msgstr ""
#: documents/serialisers.py:2372 documents/serialisers.py:2382 #: documents/serialisers.py:2375 documents/serialisers.py:2385
msgid "Custom fields must be a list of integers or an object mapping ids to values." msgid "Custom fields must be a list of integers or an object mapping ids to values."
msgstr "" msgstr ""
#: documents/serialisers.py:2377 #: documents/serialisers.py:2380
msgid "Some custom fields don't exist or were specified twice." msgid "Some custom fields don't exist or were specified twice."
msgstr "" msgstr ""
#: documents/serialisers.py:2524 #: documents/serialisers.py:2527
msgid "Invalid variable detected." msgid "Invalid variable detected."
msgstr "Virheellinen muuttuja havaittu." msgstr "Virheellinen muuttuja havaittu."
#: documents/serialisers.py:2883 #: documents/serialisers.py:2886
msgid "Duplicate document identifiers are not allowed." msgid "Duplicate document identifiers are not allowed."
msgstr "" msgstr ""
#: documents/serialisers.py:2913 documents/views.py:4608 #: documents/serialisers.py:2916 documents/views.py:4610
#, python-format #, python-format
msgid "Documents not found: %(ids)s" msgid "Documents not found: %(ids)s"
msgstr "" msgstr ""
@@ -1907,36 +1907,36 @@ msgstr ""
msgid "Unable to parse URI {value}" msgid "Unable to parse URI {value}"
msgstr "" msgstr ""
#: documents/views.py:306 documents/views.py:2608 #: documents/views.py:306 documents/views.py:2610
msgid "Invalid more_like_id" msgid "Invalid more_like_id"
msgstr "" msgstr ""
#: documents/views.py:1582 #: documents/views.py:1584
msgid "Invalid AI configuration." msgid "Invalid AI configuration."
msgstr "" msgstr ""
#: documents/views.py:1593 #: documents/views.py:1595
msgid "AI backend request timed out." msgid "AI backend request timed out."
msgstr "" msgstr ""
#: documents/views.py:2433 documents/views.py:2754 #: documents/views.py:2435 documents/views.py:2756
msgid "Specify only one of text, title_search, query, or more_like_id." msgid "Specify only one of text, title_search, query, or more_like_id."
msgstr "" msgstr ""
#: documents/views.py:4621 #: documents/views.py:4623
#, python-format #, python-format
msgid "Insufficient permissions to share document %(id)s." msgid "Insufficient permissions to share document %(id)s."
msgstr "" msgstr ""
#: documents/views.py:4667 #: documents/views.py:4669
msgid "Bundle is already being processed." msgid "Bundle is already being processed."
msgstr "" msgstr ""
#: documents/views.py:4728 #: documents/views.py:4730
msgid "The share link bundle is still being prepared. Please try again later." msgid "The share link bundle is still being prepared. Please try again later."
msgstr "" msgstr ""
#: documents/views.py:4738 #: documents/views.py:4740
msgid "The share link bundle is unavailable." msgid "The share link bundle is unavailable."
msgstr "" msgstr ""
+21 -21
View File
@@ -2,8 +2,8 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: paperless-ngx\n" "Project-Id-Version: paperless-ngx\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2026-08-29 20:02+0000\n" "POT-Creation-Date: 2026-09-01 14:47+0000\n"
"PO-Revision-Date: 2026-08-29 20:04\n" "PO-Revision-Date: 2026-09-01 14:48\n"
"Last-Translator: \n" "Last-Translator: \n"
"Language-Team: French\n" "Language-Team: French\n"
"Language: fr_FR\n" "Language: fr_FR\n"
@@ -1610,48 +1610,48 @@ msgstr "exécution du workflow"
msgid "workflow runs" msgid "workflow runs"
msgstr "le flux de travail s'exécute" msgstr "le flux de travail s'exécute"
#: documents/serialisers.py:523 documents/serialisers.py:875 #: documents/serialisers.py:524 documents/serialisers.py:878
#: documents/serialisers.py:2827 documents/views.py:313 documents/views.py:2611 #: documents/serialisers.py:2830 documents/views.py:313 documents/views.py:2613
#: paperless_mail/serialisers.py:156 #: paperless_mail/serialisers.py:156
msgid "Insufficient permissions." msgid "Insufficient permissions."
msgstr "Droits insuffisants." msgstr "Droits insuffisants."
#: documents/serialisers.py:711 #: documents/serialisers.py:714
msgid "Invalid color." msgid "Invalid color."
msgstr "Couleur incorrecte." msgstr "Couleur incorrecte."
#: documents/serialisers.py:2304 #: documents/serialisers.py:2307
#, python-format #, python-format
msgid "File type %(type)s not supported" msgid "File type %(type)s not supported"
msgstr "Type de fichier %(type)s non pris en charge" msgstr "Type de fichier %(type)s non pris en charge"
#: documents/serialisers.py:2348 #: documents/serialisers.py:2351
#, python-format #, python-format
msgid "Custom field id must be an integer: %(id)s" msgid "Custom field id must be an integer: %(id)s"
msgstr "L'id du champ personnalisé doit être un entier : %(id)s" msgstr "L'id du champ personnalisé doit être un entier : %(id)s"
#: documents/serialisers.py:2355 #: documents/serialisers.py:2358
#, python-format #, python-format
msgid "Custom field with id %(id)s does not exist" msgid "Custom field with id %(id)s does not exist"
msgstr "Le champ personnalisé avec l'id %(id)s n'existe pas" msgstr "Le champ personnalisé avec l'id %(id)s n'existe pas"
#: documents/serialisers.py:2372 documents/serialisers.py:2382 #: documents/serialisers.py:2375 documents/serialisers.py:2385
msgid "Custom fields must be a list of integers or an object mapping ids to values." msgid "Custom fields must be a list of integers or an object mapping ids to values."
msgstr "Les champs personnalisés doivent être une liste d'entiers ou un mappage d'identifiants à des valeurs." msgstr "Les champs personnalisés doivent être une liste d'entiers ou un mappage d'identifiants à des valeurs."
#: documents/serialisers.py:2377 #: documents/serialisers.py:2380
msgid "Some custom fields don't exist or were specified twice." msgid "Some custom fields don't exist or were specified twice."
msgstr "Certains champs personnalisés n'existent pas ou ont été spécifiés deux fois." msgstr "Certains champs personnalisés n'existent pas ou ont été spécifiés deux fois."
#: documents/serialisers.py:2524 #: documents/serialisers.py:2527
msgid "Invalid variable detected." msgid "Invalid variable detected."
msgstr "Variable invalide détectée." msgstr "Variable invalide détectée."
#: documents/serialisers.py:2883 #: documents/serialisers.py:2886
msgid "Duplicate document identifiers are not allowed." msgid "Duplicate document identifiers are not allowed."
msgstr "Les identificateurs de document en double ne sont pas autorisés." msgstr "Les identificateurs de document en double ne sont pas autorisés."
#: documents/serialisers.py:2913 documents/views.py:4608 #: documents/serialisers.py:2916 documents/views.py:4610
#, python-format #, python-format
msgid "Documents not found: %(ids)s" msgid "Documents not found: %(ids)s"
msgstr "Documents introuvables : %(ids)s" msgstr "Documents introuvables : %(ids)s"
@@ -1906,36 +1906,36 @@ msgstr "Le schéma d'URI « {parts.scheme} » n'est pas autorisé. Schémas aut
msgid "Unable to parse URI {value}" msgid "Unable to parse URI {value}"
msgstr "Impossible d'analyser l'URI {value}" msgstr "Impossible d'analyser l'URI {value}"
#: documents/views.py:306 documents/views.py:2608 #: documents/views.py:306 documents/views.py:2610
msgid "Invalid more_like_id" msgid "Invalid more_like_id"
msgstr "More_like_id invalide" msgstr "More_like_id invalide"
#: documents/views.py:1582 #: documents/views.py:1584
msgid "Invalid AI configuration." msgid "Invalid AI configuration."
msgstr "Configuration IA invalide." msgstr "Configuration IA invalide."
#: documents/views.py:1593 #: documents/views.py:1595
msgid "AI backend request timed out." msgid "AI backend request timed out."
msgstr "La requête d'arrière-plan IA a expiré." msgstr "La requête d'arrière-plan IA a expiré."
#: documents/views.py:2433 documents/views.py:2754 #: documents/views.py:2435 documents/views.py:2756
msgid "Specify only one of text, title_search, query, or more_like_id." msgid "Specify only one of text, title_search, query, or more_like_id."
msgstr "Spécifiez seulement un texte, titre, recherche ou more_like_id." msgstr "Spécifiez seulement un texte, titre, recherche ou more_like_id."
#: documents/views.py:4621 #: documents/views.py:4623
#, python-format #, python-format
msgid "Insufficient permissions to share document %(id)s." msgid "Insufficient permissions to share document %(id)s."
msgstr "Droits d'accès insuffisant pour partager %(id)s document." msgstr "Droits d'accès insuffisant pour partager %(id)s document."
#: documents/views.py:4667 #: documents/views.py:4669
msgid "Bundle is already being processed." msgid "Bundle is already being processed."
msgstr "Le paquet est déjà en cours de traitement." msgstr "Le paquet est déjà en cours de traitement."
#: documents/views.py:4728 #: documents/views.py:4730
msgid "The share link bundle is still being prepared. Please try again later." msgid "The share link bundle is still being prepared. Please try again later."
msgstr "Le lot de liens de partage est en cours de préparation. Veuillez réessayer plus tard." msgstr "Le lot de liens de partage est en cours de préparation. Veuillez réessayer plus tard."
#: documents/views.py:4738 #: documents/views.py:4740
msgid "The share link bundle is unavailable." msgid "The share link bundle is unavailable."
msgstr "Le lot de liens de partage n'est pas disponible." msgstr "Le lot de liens de partage n'est pas disponible."
+21 -21
View File
@@ -2,8 +2,8 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: paperless-ngx\n" "Project-Id-Version: paperless-ngx\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2026-08-29 20:02+0000\n" "POT-Creation-Date: 2026-09-01 14:47+0000\n"
"PO-Revision-Date: 2026-08-29 20:04\n" "PO-Revision-Date: 2026-09-01 14:48\n"
"Last-Translator: \n" "Last-Translator: \n"
"Language-Team: Hebrew\n" "Language-Team: Hebrew\n"
"Language: he_IL\n" "Language: he_IL\n"
@@ -1611,48 +1611,48 @@ msgstr "הרצת זרימת עבודה"
msgid "workflow runs" msgid "workflow runs"
msgstr "הרצות זרימת עבודה" msgstr "הרצות זרימת עבודה"
#: documents/serialisers.py:523 documents/serialisers.py:875 #: documents/serialisers.py:524 documents/serialisers.py:878
#: documents/serialisers.py:2827 documents/views.py:313 documents/views.py:2611 #: documents/serialisers.py:2830 documents/views.py:313 documents/views.py:2613
#: paperless_mail/serialisers.py:156 #: paperless_mail/serialisers.py:156
msgid "Insufficient permissions." msgid "Insufficient permissions."
msgstr "הרשאות אינן מספיקות." msgstr "הרשאות אינן מספיקות."
#: documents/serialisers.py:711 #: documents/serialisers.py:714
msgid "Invalid color." msgid "Invalid color."
msgstr "צבע לא חוקי." msgstr "צבע לא חוקי."
#: documents/serialisers.py:2304 #: documents/serialisers.py:2307
#, python-format #, python-format
msgid "File type %(type)s not supported" msgid "File type %(type)s not supported"
msgstr "סוג קובץ %(type)s לא נתמך" msgstr "סוג קובץ %(type)s לא נתמך"
#: documents/serialisers.py:2348 #: documents/serialisers.py:2351
#, python-format #, python-format
msgid "Custom field id must be an integer: %(id)s" msgid "Custom field id must be an integer: %(id)s"
msgstr "שדה מותאם אישית id חייב להיות מספרי: %(id)s" msgstr "שדה מותאם אישית id חייב להיות מספרי: %(id)s"
#: documents/serialisers.py:2355 #: documents/serialisers.py:2358
#, python-format #, python-format
msgid "Custom field with id %(id)s does not exist" msgid "Custom field with id %(id)s does not exist"
msgstr "שדה מותאם אישית עם מזהה %(id)s איננו קיים" msgstr "שדה מותאם אישית עם מזהה %(id)s איננו קיים"
#: documents/serialisers.py:2372 documents/serialisers.py:2382 #: documents/serialisers.py:2375 documents/serialisers.py:2385
msgid "Custom fields must be a list of integers or an object mapping ids to values." msgid "Custom fields must be a list of integers or an object mapping ids to values."
msgstr "שדות מותאמים אישית חייבים להיות רשימה של מספרים שלמים או אובייקט הממפה מזהים לערכים." msgstr "שדות מותאמים אישית חייבים להיות רשימה של מספרים שלמים או אובייקט הממפה מזהים לערכים."
#: documents/serialisers.py:2377 #: documents/serialisers.py:2380
msgid "Some custom fields don't exist or were specified twice." msgid "Some custom fields don't exist or were specified twice."
msgstr "חלק מהשדות המותאמים אישית אינם קיימים או שהוגדרו פעמיים." msgstr "חלק מהשדות המותאמים אישית אינם קיימים או שהוגדרו פעמיים."
#: documents/serialisers.py:2524 #: documents/serialisers.py:2527
msgid "Invalid variable detected." msgid "Invalid variable detected."
msgstr "משתנה לא חוקי זוהה." msgstr "משתנה לא חוקי זוהה."
#: documents/serialisers.py:2883 #: documents/serialisers.py:2886
msgid "Duplicate document identifiers are not allowed." msgid "Duplicate document identifiers are not allowed."
msgstr "מזהי מסמכים כפולים אינם מורשים." msgstr "מזהי מסמכים כפולים אינם מורשים."
#: documents/serialisers.py:2913 documents/views.py:4608 #: documents/serialisers.py:2916 documents/views.py:4610
#, python-format #, python-format
msgid "Documents not found: %(ids)s" msgid "Documents not found: %(ids)s"
msgstr "מסמכים לא נמצאו: %(ids)s" msgstr "מסמכים לא נמצאו: %(ids)s"
@@ -1908,36 +1908,36 @@ msgstr "פרוטוקול ה-URI '{parts.scheme}' אינו מורשה. הפר
msgid "Unable to parse URI {value}" msgid "Unable to parse URI {value}"
msgstr "לא ניתן לפענח את ה URI {value}" msgstr "לא ניתן לפענח את ה URI {value}"
#: documents/views.py:306 documents/views.py:2608 #: documents/views.py:306 documents/views.py:2610
msgid "Invalid more_like_id" msgid "Invalid more_like_id"
msgstr "מזהה more_like_id אינו תקין" msgstr "מזהה more_like_id אינו תקין"
#: documents/views.py:1582 #: documents/views.py:1584
msgid "Invalid AI configuration." msgid "Invalid AI configuration."
msgstr "הגדרות בינה מלאכותית שגויות." msgstr "הגדרות בינה מלאכותית שגויות."
#: documents/views.py:1593 #: documents/views.py:1595
msgid "AI backend request timed out." msgid "AI backend request timed out."
msgstr "" msgstr ""
#: documents/views.py:2433 documents/views.py:2754 #: documents/views.py:2435 documents/views.py:2756
msgid "Specify only one of text, title_search, query, or more_like_id." msgid "Specify only one of text, title_search, query, or more_like_id."
msgstr "יש לציין רק אחד מהבאים: text, title_search, query או more_like_id." msgstr "יש לציין רק אחד מהבאים: text, title_search, query או more_like_id."
#: documents/views.py:4621 #: documents/views.py:4623
#, python-format #, python-format
msgid "Insufficient permissions to share document %(id)s." msgid "Insufficient permissions to share document %(id)s."
msgstr "הרשאות לא מספיקות לשיתוף מסמך %(id)s." msgstr "הרשאות לא מספיקות לשיתוף מסמך %(id)s."
#: documents/views.py:4667 #: documents/views.py:4669
msgid "Bundle is already being processed." msgid "Bundle is already being processed."
msgstr "החבילה (Bundle) כבר נמצאת בתהליך עיבוד." msgstr "החבילה (Bundle) כבר נמצאת בתהליך עיבוד."
#: documents/views.py:4728 #: documents/views.py:4730
msgid "The share link bundle is still being prepared. Please try again later." msgid "The share link bundle is still being prepared. Please try again later."
msgstr "חבילת קישור השיתוף עדיין בהכנה. נא לנסות שוב מאוחר יותר." msgstr "חבילת קישור השיתוף עדיין בהכנה. נא לנסות שוב מאוחר יותר."
#: documents/views.py:4738 #: documents/views.py:4740
msgid "The share link bundle is unavailable." msgid "The share link bundle is unavailable."
msgstr "חבילת קישור השיתוף אינה זמינה." msgstr "חבילת קישור השיתוף אינה זמינה."
+21 -21
View File
@@ -2,8 +2,8 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: paperless-ngx\n" "Project-Id-Version: paperless-ngx\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2026-08-29 20:02+0000\n" "POT-Creation-Date: 2026-09-01 14:47+0000\n"
"PO-Revision-Date: 2026-08-29 20:04\n" "PO-Revision-Date: 2026-09-01 14:48\n"
"Last-Translator: \n" "Last-Translator: \n"
"Language-Team: Hindi\n" "Language-Team: Hindi\n"
"Language: hi_IN\n" "Language: hi_IN\n"
@@ -1610,48 +1610,48 @@ msgstr ""
msgid "workflow runs" msgid "workflow runs"
msgstr "" msgstr ""
#: documents/serialisers.py:523 documents/serialisers.py:875 #: documents/serialisers.py:524 documents/serialisers.py:878
#: documents/serialisers.py:2827 documents/views.py:313 documents/views.py:2611 #: documents/serialisers.py:2830 documents/views.py:313 documents/views.py:2613
#: paperless_mail/serialisers.py:156 #: paperless_mail/serialisers.py:156
msgid "Insufficient permissions." msgid "Insufficient permissions."
msgstr "" msgstr ""
#: documents/serialisers.py:711 #: documents/serialisers.py:714
msgid "Invalid color." msgid "Invalid color."
msgstr "" msgstr ""
#: documents/serialisers.py:2304 #: documents/serialisers.py:2307
#, python-format #, python-format
msgid "File type %(type)s not supported" msgid "File type %(type)s not supported"
msgstr "" msgstr ""
#: documents/serialisers.py:2348 #: documents/serialisers.py:2351
#, python-format #, python-format
msgid "Custom field id must be an integer: %(id)s" msgid "Custom field id must be an integer: %(id)s"
msgstr "" msgstr ""
#: documents/serialisers.py:2355 #: documents/serialisers.py:2358
#, python-format #, python-format
msgid "Custom field with id %(id)s does not exist" msgid "Custom field with id %(id)s does not exist"
msgstr "" msgstr ""
#: documents/serialisers.py:2372 documents/serialisers.py:2382 #: documents/serialisers.py:2375 documents/serialisers.py:2385
msgid "Custom fields must be a list of integers or an object mapping ids to values." msgid "Custom fields must be a list of integers or an object mapping ids to values."
msgstr "" msgstr ""
#: documents/serialisers.py:2377 #: documents/serialisers.py:2380
msgid "Some custom fields don't exist or were specified twice." msgid "Some custom fields don't exist or were specified twice."
msgstr "" msgstr ""
#: documents/serialisers.py:2524 #: documents/serialisers.py:2527
msgid "Invalid variable detected." msgid "Invalid variable detected."
msgstr "" msgstr ""
#: documents/serialisers.py:2883 #: documents/serialisers.py:2886
msgid "Duplicate document identifiers are not allowed." msgid "Duplicate document identifiers are not allowed."
msgstr "" msgstr ""
#: documents/serialisers.py:2913 documents/views.py:4608 #: documents/serialisers.py:2916 documents/views.py:4610
#, python-format #, python-format
msgid "Documents not found: %(ids)s" msgid "Documents not found: %(ids)s"
msgstr "" msgstr ""
@@ -1906,36 +1906,36 @@ msgstr ""
msgid "Unable to parse URI {value}" msgid "Unable to parse URI {value}"
msgstr "" msgstr ""
#: documents/views.py:306 documents/views.py:2608 #: documents/views.py:306 documents/views.py:2610
msgid "Invalid more_like_id" msgid "Invalid more_like_id"
msgstr "" msgstr ""
#: documents/views.py:1582 #: documents/views.py:1584
msgid "Invalid AI configuration." msgid "Invalid AI configuration."
msgstr "" msgstr ""
#: documents/views.py:1593 #: documents/views.py:1595
msgid "AI backend request timed out." msgid "AI backend request timed out."
msgstr "" msgstr ""
#: documents/views.py:2433 documents/views.py:2754 #: documents/views.py:2435 documents/views.py:2756
msgid "Specify only one of text, title_search, query, or more_like_id." msgid "Specify only one of text, title_search, query, or more_like_id."
msgstr "" msgstr ""
#: documents/views.py:4621 #: documents/views.py:4623
#, python-format #, python-format
msgid "Insufficient permissions to share document %(id)s." msgid "Insufficient permissions to share document %(id)s."
msgstr "" msgstr ""
#: documents/views.py:4667 #: documents/views.py:4669
msgid "Bundle is already being processed." msgid "Bundle is already being processed."
msgstr "" msgstr ""
#: documents/views.py:4728 #: documents/views.py:4730
msgid "The share link bundle is still being prepared. Please try again later." msgid "The share link bundle is still being prepared. Please try again later."
msgstr "" msgstr ""
#: documents/views.py:4738 #: documents/views.py:4740
msgid "The share link bundle is unavailable." msgid "The share link bundle is unavailable."
msgstr "" msgstr ""
+21 -21
View File
@@ -2,8 +2,8 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: paperless-ngx\n" "Project-Id-Version: paperless-ngx\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2026-08-29 20:02+0000\n" "POT-Creation-Date: 2026-09-01 14:47+0000\n"
"PO-Revision-Date: 2026-08-29 20:04\n" "PO-Revision-Date: 2026-09-01 14:48\n"
"Last-Translator: \n" "Last-Translator: \n"
"Language-Team: Croatian\n" "Language-Team: Croatian\n"
"Language: hr_HR\n" "Language: hr_HR\n"
@@ -1610,48 +1610,48 @@ msgstr "pokretanje tijeka rada"
msgid "workflow runs" msgid "workflow runs"
msgstr "tijek rada pokrenut" msgstr "tijek rada pokrenut"
#: documents/serialisers.py:523 documents/serialisers.py:875 #: documents/serialisers.py:524 documents/serialisers.py:878
#: documents/serialisers.py:2827 documents/views.py:313 documents/views.py:2611 #: documents/serialisers.py:2830 documents/views.py:313 documents/views.py:2613
#: paperless_mail/serialisers.py:156 #: paperless_mail/serialisers.py:156
msgid "Insufficient permissions." msgid "Insufficient permissions."
msgstr "Nedovoljne ovlasti." msgstr "Nedovoljne ovlasti."
#: documents/serialisers.py:711 #: documents/serialisers.py:714
msgid "Invalid color." msgid "Invalid color."
msgstr "Nevažeća boja." msgstr "Nevažeća boja."
#: documents/serialisers.py:2304 #: documents/serialisers.py:2307
#, python-format #, python-format
msgid "File type %(type)s not supported" msgid "File type %(type)s not supported"
msgstr "Vrsta datoteke %(type)s nije podržana" msgstr "Vrsta datoteke %(type)s nije podržana"
#: documents/serialisers.py:2348 #: documents/serialisers.py:2351
#, python-format #, python-format
msgid "Custom field id must be an integer: %(id)s" msgid "Custom field id must be an integer: %(id)s"
msgstr "ID prilagođenog polja mora biti cijeli broj: %(id)s" msgstr "ID prilagođenog polja mora biti cijeli broj: %(id)s"
#: documents/serialisers.py:2355 #: documents/serialisers.py:2358
#, python-format #, python-format
msgid "Custom field with id %(id)s does not exist" msgid "Custom field with id %(id)s does not exist"
msgstr "Prilagođeno polje s ID-om %(id)s ne postoji" msgstr "Prilagođeno polje s ID-om %(id)s ne postoji"
#: documents/serialisers.py:2372 documents/serialisers.py:2382 #: documents/serialisers.py:2375 documents/serialisers.py:2385
msgid "Custom fields must be a list of integers or an object mapping ids to values." msgid "Custom fields must be a list of integers or an object mapping ids to values."
msgstr "Prilagođena polja moraju biti popis cijelih brojeva ili ID-ova objekata koji preslikavaju vrijednosti." msgstr "Prilagođena polja moraju biti popis cijelih brojeva ili ID-ova objekata koji preslikavaju vrijednosti."
#: documents/serialisers.py:2377 #: documents/serialisers.py:2380
msgid "Some custom fields don't exist or were specified twice." msgid "Some custom fields don't exist or were specified twice."
msgstr "Neka prilagođena polja ne postoje ili su navedena dvaput." msgstr "Neka prilagođena polja ne postoje ili su navedena dvaput."
#: documents/serialisers.py:2524 #: documents/serialisers.py:2527
msgid "Invalid variable detected." msgid "Invalid variable detected."
msgstr "Otkrivena je nevaljana vrsta datoteke." msgstr "Otkrivena je nevaljana vrsta datoteke."
#: documents/serialisers.py:2883 #: documents/serialisers.py:2886
msgid "Duplicate document identifiers are not allowed." msgid "Duplicate document identifiers are not allowed."
msgstr "Duplicirani identifikatori dokumenata nisu dopušteni." msgstr "Duplicirani identifikatori dokumenata nisu dopušteni."
#: documents/serialisers.py:2913 documents/views.py:4608 #: documents/serialisers.py:2916 documents/views.py:4610
#, python-format #, python-format
msgid "Documents not found: %(ids)s" msgid "Documents not found: %(ids)s"
msgstr "Dokumenti nisu pronađeni: %(ids)s" msgstr "Dokumenti nisu pronađeni: %(ids)s"
@@ -1907,36 +1907,36 @@ msgstr "URI shema '{parts.scheme}' nije dopuštena. Dopuštene sheme: {', '.join
msgid "Unable to parse URI {value}" msgid "Unable to parse URI {value}"
msgstr "Nije moguće raščlaniti URI {value}" msgstr "Nije moguće raščlaniti URI {value}"
#: documents/views.py:306 documents/views.py:2608 #: documents/views.py:306 documents/views.py:2610
msgid "Invalid more_like_id" msgid "Invalid more_like_id"
msgstr "Nevažeći more_like_id" msgstr "Nevažeći more_like_id"
#: documents/views.py:1582 #: documents/views.py:1584
msgid "Invalid AI configuration." msgid "Invalid AI configuration."
msgstr "Nevažeća AI konfiguracija." msgstr "Nevažeća AI konfiguracija."
#: documents/views.py:1593 #: documents/views.py:1595
msgid "AI backend request timed out." msgid "AI backend request timed out."
msgstr "" msgstr ""
#: documents/views.py:2433 documents/views.py:2754 #: documents/views.py:2435 documents/views.py:2756
msgid "Specify only one of text, title_search, query, or more_like_id." msgid "Specify only one of text, title_search, query, or more_like_id."
msgstr "Navedite samo jedno od: text, title_search, query ili more_like_id." msgstr "Navedite samo jedno od: text, title_search, query ili more_like_id."
#: documents/views.py:4621 #: documents/views.py:4623
#, python-format #, python-format
msgid "Insufficient permissions to share document %(id)s." msgid "Insufficient permissions to share document %(id)s."
msgstr "Nedovoljne ovlasti za dijeljenje dokumenta %(id)s." msgstr "Nedovoljne ovlasti za dijeljenje dokumenta %(id)s."
#: documents/views.py:4667 #: documents/views.py:4669
msgid "Bundle is already being processed." msgid "Bundle is already being processed."
msgstr "Paket se već obrađuje." msgstr "Paket se već obrađuje."
#: documents/views.py:4728 #: documents/views.py:4730
msgid "The share link bundle is still being prepared. Please try again later." msgid "The share link bundle is still being prepared. Please try again later."
msgstr "Paket linka za dijeljenje se još priprema. Pokušajte ponovo kasnije." msgstr "Paket linka za dijeljenje se još priprema. Pokušajte ponovo kasnije."
#: documents/views.py:4738 #: documents/views.py:4740
msgid "The share link bundle is unavailable." msgid "The share link bundle is unavailable."
msgstr "Paket linka za dijeljenje nije dostupan." msgstr "Paket linka za dijeljenje nije dostupan."
+21 -21
View File
@@ -2,8 +2,8 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: paperless-ngx\n" "Project-Id-Version: paperless-ngx\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2026-08-29 20:02+0000\n" "POT-Creation-Date: 2026-09-01 14:47+0000\n"
"PO-Revision-Date: 2026-08-29 20:04\n" "PO-Revision-Date: 2026-09-01 14:48\n"
"Last-Translator: \n" "Last-Translator: \n"
"Language-Team: Hungarian\n" "Language-Team: Hungarian\n"
"Language: hu_HU\n" "Language: hu_HU\n"
@@ -1610,48 +1610,48 @@ msgstr "munkafolyamat futtatás"
msgid "workflow runs" msgid "workflow runs"
msgstr "munkafolyamat futtatások" msgstr "munkafolyamat futtatások"
#: documents/serialisers.py:523 documents/serialisers.py:875 #: documents/serialisers.py:524 documents/serialisers.py:878
#: documents/serialisers.py:2827 documents/views.py:313 documents/views.py:2611 #: documents/serialisers.py:2830 documents/views.py:313 documents/views.py:2613
#: paperless_mail/serialisers.py:156 #: paperless_mail/serialisers.py:156
msgid "Insufficient permissions." msgid "Insufficient permissions."
msgstr "Nincs jogosúltsága." msgstr "Nincs jogosúltsága."
#: documents/serialisers.py:711 #: documents/serialisers.py:714
msgid "Invalid color." msgid "Invalid color."
msgstr "Érvénytelen szín." msgstr "Érvénytelen szín."
#: documents/serialisers.py:2304 #: documents/serialisers.py:2307
#, python-format #, python-format
msgid "File type %(type)s not supported" msgid "File type %(type)s not supported"
msgstr "%(type)s fájltípus nem támogatott" msgstr "%(type)s fájltípus nem támogatott"
#: documents/serialisers.py:2348 #: documents/serialisers.py:2351
#, python-format #, python-format
msgid "Custom field id must be an integer: %(id)s" msgid "Custom field id must be an integer: %(id)s"
msgstr "Az egyéni mező azonosítójának egész számnak kell lennie: %(id)s" msgstr "Az egyéni mező azonosítójának egész számnak kell lennie: %(id)s"
#: documents/serialisers.py:2355 #: documents/serialisers.py:2358
#, python-format #, python-format
msgid "Custom field with id %(id)s does not exist" msgid "Custom field with id %(id)s does not exist"
msgstr "A(z) %(id)s azonosítójú egyéni mező nem létezik" msgstr "A(z) %(id)s azonosítójú egyéni mező nem létezik"
#: documents/serialisers.py:2372 documents/serialisers.py:2382 #: documents/serialisers.py:2375 documents/serialisers.py:2385
msgid "Custom fields must be a list of integers or an object mapping ids to values." msgid "Custom fields must be a list of integers or an object mapping ids to values."
msgstr "Az egyéni mezőknek egész számok listájának vagy azonosítókat értékekhez rendelő objektumnak kell lenniük." msgstr "Az egyéni mezőknek egész számok listájának vagy azonosítókat értékekhez rendelő objektumnak kell lenniük."
#: documents/serialisers.py:2377 #: documents/serialisers.py:2380
msgid "Some custom fields don't exist or were specified twice." msgid "Some custom fields don't exist or were specified twice."
msgstr "Néhány egyéni mező nem létezik, vagy kétszer lett megadva." msgstr "Néhány egyéni mező nem létezik, vagy kétszer lett megadva."
#: documents/serialisers.py:2524 #: documents/serialisers.py:2527
msgid "Invalid variable detected." msgid "Invalid variable detected."
msgstr "Érvénytelen változó észlelve." msgstr "Érvénytelen változó észlelve."
#: documents/serialisers.py:2883 #: documents/serialisers.py:2886
msgid "Duplicate document identifiers are not allowed." msgid "Duplicate document identifiers are not allowed."
msgstr "A dokumentumazonosítók duplikálása nem megengedett." msgstr "A dokumentumazonosítók duplikálása nem megengedett."
#: documents/serialisers.py:2913 documents/views.py:4608 #: documents/serialisers.py:2916 documents/views.py:4610
#, python-format #, python-format
msgid "Documents not found: %(ids)s" msgid "Documents not found: %(ids)s"
msgstr "Dokumentumok nem találhatók: %(ids)s" msgstr "Dokumentumok nem találhatók: %(ids)s"
@@ -1907,36 +1907,36 @@ msgstr "A '{parts.scheme}' séma nem engedélyezett. Engedélyezett sémák: {',
msgid "Unable to parse URI {value}" msgid "Unable to parse URI {value}"
msgstr "A {value} URI értelmezése sikertelen" msgstr "A {value} URI értelmezése sikertelen"
#: documents/views.py:306 documents/views.py:2608 #: documents/views.py:306 documents/views.py:2610
msgid "Invalid more_like_id" msgid "Invalid more_like_id"
msgstr "Érvénytelen more_like_id" msgstr "Érvénytelen more_like_id"
#: documents/views.py:1582 #: documents/views.py:1584
msgid "Invalid AI configuration." msgid "Invalid AI configuration."
msgstr "Érvénytelen MI konfiguráció." msgstr "Érvénytelen MI konfiguráció."
#: documents/views.py:1593 #: documents/views.py:1595
msgid "AI backend request timed out." msgid "AI backend request timed out."
msgstr "" msgstr ""
#: documents/views.py:2433 documents/views.py:2754 #: documents/views.py:2435 documents/views.py:2756
msgid "Specify only one of text, title_search, query, or more_like_id." msgid "Specify only one of text, title_search, query, or more_like_id."
msgstr "A text, title_search, query, vagy more_like_id közül csak egyet adjon meg." msgstr "A text, title_search, query, vagy more_like_id közül csak egyet adjon meg."
#: documents/views.py:4621 #: documents/views.py:4623
#, python-format #, python-format
msgid "Insufficient permissions to share document %(id)s." msgid "Insufficient permissions to share document %(id)s."
msgstr "Nincs megfelelő jogosultság a %(id)s dokumentum megosztásához." msgstr "Nincs megfelelő jogosultság a %(id)s dokumentum megosztásához."
#: documents/views.py:4667 #: documents/views.py:4669
msgid "Bundle is already being processed." msgid "Bundle is already being processed."
msgstr "A csomag feldolgozása már folyamatban van." msgstr "A csomag feldolgozása már folyamatban van."
#: documents/views.py:4728 #: documents/views.py:4730
msgid "The share link bundle is still being prepared. Please try again later." msgid "The share link bundle is still being prepared. Please try again later."
msgstr "A megosztási linkcsomag készítése folyamatban. Kérjük, próbálja meg később." msgstr "A megosztási linkcsomag készítése folyamatban. Kérjük, próbálja meg később."
#: documents/views.py:4738 #: documents/views.py:4740
msgid "The share link bundle is unavailable." msgid "The share link bundle is unavailable."
msgstr "A megosztási linkcsomag nem elérhető." msgstr "A megosztási linkcsomag nem elérhető."
+21 -21
View File
@@ -2,8 +2,8 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: paperless-ngx\n" "Project-Id-Version: paperless-ngx\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2026-08-29 20:02+0000\n" "POT-Creation-Date: 2026-09-01 14:47+0000\n"
"PO-Revision-Date: 2026-08-29 20:04\n" "PO-Revision-Date: 2026-09-01 14:48\n"
"Last-Translator: \n" "Last-Translator: \n"
"Language-Team: Indonesian\n" "Language-Team: Indonesian\n"
"Language: id_ID\n" "Language: id_ID\n"
@@ -1610,48 +1610,48 @@ msgstr "jalankan alur kerja"
msgid "workflow runs" msgid "workflow runs"
msgstr "daftar jalankan alur kerja" msgstr "daftar jalankan alur kerja"
#: documents/serialisers.py:523 documents/serialisers.py:875 #: documents/serialisers.py:524 documents/serialisers.py:878
#: documents/serialisers.py:2827 documents/views.py:313 documents/views.py:2611 #: documents/serialisers.py:2830 documents/views.py:313 documents/views.py:2613
#: paperless_mail/serialisers.py:156 #: paperless_mail/serialisers.py:156
msgid "Insufficient permissions." msgid "Insufficient permissions."
msgstr "Izin tidak mencukupi" msgstr "Izin tidak mencukupi"
#: documents/serialisers.py:711 #: documents/serialisers.py:714
msgid "Invalid color." msgid "Invalid color."
msgstr "Warna tidak sesuai." msgstr "Warna tidak sesuai."
#: documents/serialisers.py:2304 #: documents/serialisers.py:2307
#, python-format #, python-format
msgid "File type %(type)s not supported" msgid "File type %(type)s not supported"
msgstr "Jenis berkas %(type)s tidak didukung" msgstr "Jenis berkas %(type)s tidak didukung"
#: documents/serialisers.py:2348 #: documents/serialisers.py:2351
#, python-format #, python-format
msgid "Custom field id must be an integer: %(id)s" msgid "Custom field id must be an integer: %(id)s"
msgstr "Id kolom kustom harus berupa bilangan bulat: %(id)s" msgstr "Id kolom kustom harus berupa bilangan bulat: %(id)s"
#: documents/serialisers.py:2355 #: documents/serialisers.py:2358
#, python-format #, python-format
msgid "Custom field with id %(id)s does not exist" msgid "Custom field with id %(id)s does not exist"
msgstr "Kolom kustom dengan id %(id)s tidak ada" msgstr "Kolom kustom dengan id %(id)s tidak ada"
#: documents/serialisers.py:2372 documents/serialisers.py:2382 #: documents/serialisers.py:2375 documents/serialisers.py:2385
msgid "Custom fields must be a list of integers or an object mapping ids to values." msgid "Custom fields must be a list of integers or an object mapping ids to values."
msgstr "Kolom kustom harus berupa daftar bilangan bulat atau objek yang memetakan id ke nilai." msgstr "Kolom kustom harus berupa daftar bilangan bulat atau objek yang memetakan id ke nilai."
#: documents/serialisers.py:2377 #: documents/serialisers.py:2380
msgid "Some custom fields don't exist or were specified twice." msgid "Some custom fields don't exist or were specified twice."
msgstr "Beberapa kolom kustom tidak ada atau ditentukan dua kali." msgstr "Beberapa kolom kustom tidak ada atau ditentukan dua kali."
#: documents/serialisers.py:2524 #: documents/serialisers.py:2527
msgid "Invalid variable detected." msgid "Invalid variable detected."
msgstr "Variabel ilegal terdeteksi." msgstr "Variabel ilegal terdeteksi."
#: documents/serialisers.py:2883 #: documents/serialisers.py:2886
msgid "Duplicate document identifiers are not allowed." msgid "Duplicate document identifiers are not allowed."
msgstr "Penggunaan pengenal dokumen ganda tidak diperbolehkan." msgstr "Penggunaan pengenal dokumen ganda tidak diperbolehkan."
#: documents/serialisers.py:2913 documents/views.py:4608 #: documents/serialisers.py:2916 documents/views.py:4610
#, python-format #, python-format
msgid "Documents not found: %(ids)s" msgid "Documents not found: %(ids)s"
msgstr "Dokumen tidak ditemukan: %(ids)s" msgstr "Dokumen tidak ditemukan: %(ids)s"
@@ -1907,36 +1907,36 @@ msgstr "Skema URI '{parts.scheme}' tidak diizinkan. Skema yang diizinkan: {', '.
msgid "Unable to parse URI {value}" msgid "Unable to parse URI {value}"
msgstr "Gagal membaca URI {value}" msgstr "Gagal membaca URI {value}"
#: documents/views.py:306 documents/views.py:2608 #: documents/views.py:306 documents/views.py:2610
msgid "Invalid more_like_id" msgid "Invalid more_like_id"
msgstr "" msgstr ""
#: documents/views.py:1582 #: documents/views.py:1584
msgid "Invalid AI configuration." msgid "Invalid AI configuration."
msgstr "" msgstr ""
#: documents/views.py:1593 #: documents/views.py:1595
msgid "AI backend request timed out." msgid "AI backend request timed out."
msgstr "" msgstr ""
#: documents/views.py:2433 documents/views.py:2754 #: documents/views.py:2435 documents/views.py:2756
msgid "Specify only one of text, title_search, query, or more_like_id." msgid "Specify only one of text, title_search, query, or more_like_id."
msgstr "" msgstr ""
#: documents/views.py:4621 #: documents/views.py:4623
#, python-format #, python-format
msgid "Insufficient permissions to share document %(id)s." msgid "Insufficient permissions to share document %(id)s."
msgstr "Izin tidak mencukupi untuk berbagi dokumen %(id)s" msgstr "Izin tidak mencukupi untuk berbagi dokumen %(id)s"
#: documents/views.py:4667 #: documents/views.py:4669
msgid "Bundle is already being processed." msgid "Bundle is already being processed."
msgstr "Paket sedang diproses." msgstr "Paket sedang diproses."
#: documents/views.py:4728 #: documents/views.py:4730
msgid "The share link bundle is still being prepared. Please try again later." msgid "The share link bundle is still being prepared. Please try again later."
msgstr "Bundel tautan berbagi masih dalam proses persiapan. Silakan coba lagi nanti." msgstr "Bundel tautan berbagi masih dalam proses persiapan. Silakan coba lagi nanti."
#: documents/views.py:4738 #: documents/views.py:4740
msgid "The share link bundle is unavailable." msgid "The share link bundle is unavailable."
msgstr "Bundel tautan berbagi tidak tersedia." msgstr "Bundel tautan berbagi tidak tersedia."
+21 -21
View File
@@ -2,8 +2,8 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: paperless-ngx\n" "Project-Id-Version: paperless-ngx\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2026-08-29 20:02+0000\n" "POT-Creation-Date: 2026-09-01 14:47+0000\n"
"PO-Revision-Date: 2026-08-30 14:53\n" "PO-Revision-Date: 2026-09-01 14:48\n"
"Last-Translator: \n" "Last-Translator: \n"
"Language-Team: Italian\n" "Language-Team: Italian\n"
"Language: it_IT\n" "Language: it_IT\n"
@@ -1610,48 +1610,48 @@ msgstr "esecuzione del flusso di lavoro"
msgid "workflow runs" msgid "workflow runs"
msgstr "esecuzioni del flusso di lavoro" msgstr "esecuzioni del flusso di lavoro"
#: documents/serialisers.py:523 documents/serialisers.py:875 #: documents/serialisers.py:524 documents/serialisers.py:878
#: documents/serialisers.py:2827 documents/views.py:313 documents/views.py:2611 #: documents/serialisers.py:2830 documents/views.py:313 documents/views.py:2613
#: paperless_mail/serialisers.py:156 #: paperless_mail/serialisers.py:156
msgid "Insufficient permissions." msgid "Insufficient permissions."
msgstr "Autorizzazioni insufficienti." msgstr "Autorizzazioni insufficienti."
#: documents/serialisers.py:711 #: documents/serialisers.py:714
msgid "Invalid color." msgid "Invalid color."
msgstr "Colore non valido." msgstr "Colore non valido."
#: documents/serialisers.py:2304 #: documents/serialisers.py:2307
#, python-format #, python-format
msgid "File type %(type)s not supported" msgid "File type %(type)s not supported"
msgstr "Il tipo di file %(type)s non è supportato" msgstr "Il tipo di file %(type)s non è supportato"
#: documents/serialisers.py:2348 #: documents/serialisers.py:2351
#, python-format #, python-format
msgid "Custom field id must be an integer: %(id)s" msgid "Custom field id must be an integer: %(id)s"
msgstr "L'ID del campo personalizzato deve essere un numero intero: %(id)s" msgstr "L'ID del campo personalizzato deve essere un numero intero: %(id)s"
#: documents/serialisers.py:2355 #: documents/serialisers.py:2358
#, python-format #, python-format
msgid "Custom field with id %(id)s does not exist" msgid "Custom field with id %(id)s does not exist"
msgstr "Il campo personalizzato con ID %(id)s non esiste" msgstr "Il campo personalizzato con ID %(id)s non esiste"
#: documents/serialisers.py:2372 documents/serialisers.py:2382 #: documents/serialisers.py:2375 documents/serialisers.py:2385
msgid "Custom fields must be a list of integers or an object mapping ids to values." msgid "Custom fields must be a list of integers or an object mapping ids to values."
msgstr "I campi personalizzati devono essere un elenco di numeri interi o un oggetto che mappa gli ID ai valori." msgstr "I campi personalizzati devono essere un elenco di numeri interi o un oggetto che mappa gli ID ai valori."
#: documents/serialisers.py:2377 #: documents/serialisers.py:2380
msgid "Some custom fields don't exist or were specified twice." msgid "Some custom fields don't exist or were specified twice."
msgstr "Alcuni campi personalizzati non esistono o sono stati specificati due volte." msgstr "Alcuni campi personalizzati non esistono o sono stati specificati due volte."
#: documents/serialisers.py:2524 #: documents/serialisers.py:2527
msgid "Invalid variable detected." msgid "Invalid variable detected."
msgstr "Variabile non valida rilevata." msgstr "Variabile non valida rilevata."
#: documents/serialisers.py:2883 #: documents/serialisers.py:2886
msgid "Duplicate document identifiers are not allowed." msgid "Duplicate document identifiers are not allowed."
msgstr "Non sono consentiti identificatori di documenti duplicati." msgstr "Non sono consentiti identificatori di documenti duplicati."
#: documents/serialisers.py:2913 documents/views.py:4608 #: documents/serialisers.py:2916 documents/views.py:4610
#, python-format #, python-format
msgid "Documents not found: %(ids)s" msgid "Documents not found: %(ids)s"
msgstr "Documenti non trovati: %(ids)s" msgstr "Documenti non trovati: %(ids)s"
@@ -1907,36 +1907,36 @@ msgstr "Lo schema URI '{parts.scheme}' non è consentito. Schemi consentiti: {',
msgid "Unable to parse URI {value}" msgid "Unable to parse URI {value}"
msgstr "Impossibile analizzare l'URI {value}" msgstr "Impossibile analizzare l'URI {value}"
#: documents/views.py:306 documents/views.py:2608 #: documents/views.py:306 documents/views.py:2610
msgid "Invalid more_like_id" msgid "Invalid more_like_id"
msgstr "more_like_id non valido" msgstr "more_like_id non valido"
#: documents/views.py:1582 #: documents/views.py:1584
msgid "Invalid AI configuration." msgid "Invalid AI configuration."
msgstr "Configurazione AI non valida." msgstr "Configurazione AI non valida."
#: documents/views.py:1593 #: documents/views.py:1595
msgid "AI backend request timed out." msgid "AI backend request timed out."
msgstr "Richiesta di backend AI scaduta." msgstr "Richiesta di backend AI scaduta."
#: documents/views.py:2433 documents/views.py:2754 #: documents/views.py:2435 documents/views.py:2756
msgid "Specify only one of text, title_search, query, or more_like_id." msgid "Specify only one of text, title_search, query, or more_like_id."
msgstr "Specificare solo uno tra text, title_search, query o more_like_id." msgstr "Specificare solo uno tra text, title_search, query o more_like_id."
#: documents/views.py:4621 #: documents/views.py:4623
#, python-format #, python-format
msgid "Insufficient permissions to share document %(id)s." msgid "Insufficient permissions to share document %(id)s."
msgstr "Autorizzazioni insufficienti per condividere il documento %(id)s." msgstr "Autorizzazioni insufficienti per condividere il documento %(id)s."
#: documents/views.py:4667 #: documents/views.py:4669
msgid "Bundle is already being processed." msgid "Bundle is already being processed."
msgstr "Il pacchetto è già in fase di elaborazione." msgstr "Il pacchetto è già in fase di elaborazione."
#: documents/views.py:4728 #: documents/views.py:4730
msgid "The share link bundle is still being prepared. Please try again later." msgid "The share link bundle is still being prepared. Please try again later."
msgstr "Il pacchetto di link di condivisione è ancora in fase di preparazione. Riprova più tardi." msgstr "Il pacchetto di link di condivisione è ancora in fase di preparazione. Riprova più tardi."
#: documents/views.py:4738 #: documents/views.py:4740
msgid "The share link bundle is unavailable." msgid "The share link bundle is unavailable."
msgstr "Il pacchetto di link di condivisione non è disponibile." msgstr "Il pacchetto di link di condivisione non è disponibile."
+21 -21
View File
@@ -2,8 +2,8 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: paperless-ngx\n" "Project-Id-Version: paperless-ngx\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2026-08-29 20:02+0000\n" "POT-Creation-Date: 2026-09-01 14:47+0000\n"
"PO-Revision-Date: 2026-08-29 20:04\n" "PO-Revision-Date: 2026-09-01 14:48\n"
"Last-Translator: \n" "Last-Translator: \n"
"Language-Team: Japanese\n" "Language-Team: Japanese\n"
"Language: ja_JP\n" "Language: ja_JP\n"
@@ -1610,48 +1610,48 @@ msgstr "ワークフローの実行"
msgid "workflow runs" msgid "workflow runs"
msgstr "ワークフローの実行" msgstr "ワークフローの実行"
#: documents/serialisers.py:523 documents/serialisers.py:875 #: documents/serialisers.py:524 documents/serialisers.py:878
#: documents/serialisers.py:2827 documents/views.py:313 documents/views.py:2611 #: documents/serialisers.py:2830 documents/views.py:313 documents/views.py:2613
#: paperless_mail/serialisers.py:156 #: paperless_mail/serialisers.py:156
msgid "Insufficient permissions." msgid "Insufficient permissions."
msgstr "" msgstr ""
#: documents/serialisers.py:711 #: documents/serialisers.py:714
msgid "Invalid color." msgid "Invalid color."
msgstr "無効な色" msgstr "無効な色"
#: documents/serialisers.py:2304 #: documents/serialisers.py:2307
#, python-format #, python-format
msgid "File type %(type)s not supported" msgid "File type %(type)s not supported"
msgstr "ファイルタイプ %(type)s はサポートされていません" msgstr "ファイルタイプ %(type)s はサポートされていません"
#: documents/serialisers.py:2348 #: documents/serialisers.py:2351
#, python-format #, python-format
msgid "Custom field id must be an integer: %(id)s" msgid "Custom field id must be an integer: %(id)s"
msgstr "" msgstr ""
#: documents/serialisers.py:2355 #: documents/serialisers.py:2358
#, python-format #, python-format
msgid "Custom field with id %(id)s does not exist" msgid "Custom field with id %(id)s does not exist"
msgstr "" msgstr ""
#: documents/serialisers.py:2372 documents/serialisers.py:2382 #: documents/serialisers.py:2375 documents/serialisers.py:2385
msgid "Custom fields must be a list of integers or an object mapping ids to values." msgid "Custom fields must be a list of integers or an object mapping ids to values."
msgstr "" msgstr ""
#: documents/serialisers.py:2377 #: documents/serialisers.py:2380
msgid "Some custom fields don't exist or were specified twice." msgid "Some custom fields don't exist or were specified twice."
msgstr "" msgstr ""
#: documents/serialisers.py:2524 #: documents/serialisers.py:2527
msgid "Invalid variable detected." msgid "Invalid variable detected."
msgstr "無効な変数を検出しました" msgstr "無効な変数を検出しました"
#: documents/serialisers.py:2883 #: documents/serialisers.py:2886
msgid "Duplicate document identifiers are not allowed." msgid "Duplicate document identifiers are not allowed."
msgstr "" msgstr ""
#: documents/serialisers.py:2913 documents/views.py:4608 #: documents/serialisers.py:2916 documents/views.py:4610
#, python-format #, python-format
msgid "Documents not found: %(ids)s" msgid "Documents not found: %(ids)s"
msgstr "" msgstr ""
@@ -1907,36 +1907,36 @@ msgstr ""
msgid "Unable to parse URI {value}" msgid "Unable to parse URI {value}"
msgstr "" msgstr ""
#: documents/views.py:306 documents/views.py:2608 #: documents/views.py:306 documents/views.py:2610
msgid "Invalid more_like_id" msgid "Invalid more_like_id"
msgstr "" msgstr ""
#: documents/views.py:1582 #: documents/views.py:1584
msgid "Invalid AI configuration." msgid "Invalid AI configuration."
msgstr "" msgstr ""
#: documents/views.py:1593 #: documents/views.py:1595
msgid "AI backend request timed out." msgid "AI backend request timed out."
msgstr "" msgstr ""
#: documents/views.py:2433 documents/views.py:2754 #: documents/views.py:2435 documents/views.py:2756
msgid "Specify only one of text, title_search, query, or more_like_id." msgid "Specify only one of text, title_search, query, or more_like_id."
msgstr "" msgstr ""
#: documents/views.py:4621 #: documents/views.py:4623
#, python-format #, python-format
msgid "Insufficient permissions to share document %(id)s." msgid "Insufficient permissions to share document %(id)s."
msgstr "" msgstr ""
#: documents/views.py:4667 #: documents/views.py:4669
msgid "Bundle is already being processed." msgid "Bundle is already being processed."
msgstr "" msgstr ""
#: documents/views.py:4728 #: documents/views.py:4730
msgid "The share link bundle is still being prepared. Please try again later." msgid "The share link bundle is still being prepared. Please try again later."
msgstr "" msgstr ""
#: documents/views.py:4738 #: documents/views.py:4740
msgid "The share link bundle is unavailable." msgid "The share link bundle is unavailable."
msgstr "" msgstr ""
+21 -21
View File
@@ -2,8 +2,8 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: paperless-ngx\n" "Project-Id-Version: paperless-ngx\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2026-08-29 20:02+0000\n" "POT-Creation-Date: 2026-09-01 14:47+0000\n"
"PO-Revision-Date: 2026-08-29 20:04\n" "PO-Revision-Date: 2026-09-01 14:48\n"
"Last-Translator: \n" "Last-Translator: \n"
"Language-Team: Korean\n" "Language-Team: Korean\n"
"Language: ko_KR\n" "Language: ko_KR\n"
@@ -1610,48 +1610,48 @@ msgstr "워크플로 실행"
msgid "workflow runs" msgid "workflow runs"
msgstr "워크플로우 실행" msgstr "워크플로우 실행"
#: documents/serialisers.py:523 documents/serialisers.py:875 #: documents/serialisers.py:524 documents/serialisers.py:878
#: documents/serialisers.py:2827 documents/views.py:313 documents/views.py:2611 #: documents/serialisers.py:2830 documents/views.py:313 documents/views.py:2613
#: paperless_mail/serialisers.py:156 #: paperless_mail/serialisers.py:156
msgid "Insufficient permissions." msgid "Insufficient permissions."
msgstr "" msgstr ""
#: documents/serialisers.py:711 #: documents/serialisers.py:714
msgid "Invalid color." msgid "Invalid color."
msgstr "" msgstr ""
#: documents/serialisers.py:2304 #: documents/serialisers.py:2307
#, python-format #, python-format
msgid "File type %(type)s not supported" msgid "File type %(type)s not supported"
msgstr "" msgstr ""
#: documents/serialisers.py:2348 #: documents/serialisers.py:2351
#, python-format #, python-format
msgid "Custom field id must be an integer: %(id)s" msgid "Custom field id must be an integer: %(id)s"
msgstr "사용자 정의 ID 필드는 반드시 정수여야 합니다: %(id)s" msgstr "사용자 정의 ID 필드는 반드시 정수여야 합니다: %(id)s"
#: documents/serialisers.py:2355 #: documents/serialisers.py:2358
#, python-format #, python-format
msgid "Custom field with id %(id)s does not exist" msgid "Custom field with id %(id)s does not exist"
msgstr "%(id)s를 ID로 가지는 사용자 정의 필드가 존재하지 않습니다." msgstr "%(id)s를 ID로 가지는 사용자 정의 필드가 존재하지 않습니다."
#: documents/serialisers.py:2372 documents/serialisers.py:2382 #: documents/serialisers.py:2375 documents/serialisers.py:2385
msgid "Custom fields must be a list of integers or an object mapping ids to values." msgid "Custom fields must be a list of integers or an object mapping ids to values."
msgstr "사용자 정의 필드는 정수 리스트이거나, ID를 값에 매핑하는 객체여야 합니다." msgstr "사용자 정의 필드는 정수 리스트이거나, ID를 값에 매핑하는 객체여야 합니다."
#: documents/serialisers.py:2377 #: documents/serialisers.py:2380
msgid "Some custom fields don't exist or were specified twice." msgid "Some custom fields don't exist or were specified twice."
msgstr "존재하지 않거나 중복된 사용자 정의 필드가 있습니다." msgstr "존재하지 않거나 중복된 사용자 정의 필드가 있습니다."
#: documents/serialisers.py:2524 #: documents/serialisers.py:2527
msgid "Invalid variable detected." msgid "Invalid variable detected."
msgstr "잘못된 변수가 감지되었습니다." msgstr "잘못된 변수가 감지되었습니다."
#: documents/serialisers.py:2883 #: documents/serialisers.py:2886
msgid "Duplicate document identifiers are not allowed." msgid "Duplicate document identifiers are not allowed."
msgstr "" msgstr ""
#: documents/serialisers.py:2913 documents/views.py:4608 #: documents/serialisers.py:2916 documents/views.py:4610
#, python-format #, python-format
msgid "Documents not found: %(ids)s" msgid "Documents not found: %(ids)s"
msgstr "" msgstr ""
@@ -1907,36 +1907,36 @@ msgstr "URI 스킴 '{parts.scheme}'는 허용되지 않습니다. 허용된 스
msgid "Unable to parse URI {value}" msgid "Unable to parse URI {value}"
msgstr "{value} URI를 파싱할 수 없음" msgstr "{value} URI를 파싱할 수 없음"
#: documents/views.py:306 documents/views.py:2608 #: documents/views.py:306 documents/views.py:2610
msgid "Invalid more_like_id" msgid "Invalid more_like_id"
msgstr "" msgstr ""
#: documents/views.py:1582 #: documents/views.py:1584
msgid "Invalid AI configuration." msgid "Invalid AI configuration."
msgstr "" msgstr ""
#: documents/views.py:1593 #: documents/views.py:1595
msgid "AI backend request timed out." msgid "AI backend request timed out."
msgstr "" msgstr ""
#: documents/views.py:2433 documents/views.py:2754 #: documents/views.py:2435 documents/views.py:2756
msgid "Specify only one of text, title_search, query, or more_like_id." msgid "Specify only one of text, title_search, query, or more_like_id."
msgstr "" msgstr ""
#: documents/views.py:4621 #: documents/views.py:4623
#, python-format #, python-format
msgid "Insufficient permissions to share document %(id)s." msgid "Insufficient permissions to share document %(id)s."
msgstr "" msgstr ""
#: documents/views.py:4667 #: documents/views.py:4669
msgid "Bundle is already being processed." msgid "Bundle is already being processed."
msgstr "" msgstr ""
#: documents/views.py:4728 #: documents/views.py:4730
msgid "The share link bundle is still being prepared. Please try again later." msgid "The share link bundle is still being prepared. Please try again later."
msgstr "" msgstr ""
#: documents/views.py:4738 #: documents/views.py:4740
msgid "The share link bundle is unavailable." msgid "The share link bundle is unavailable."
msgstr "" msgstr ""
+21 -21
View File
@@ -2,8 +2,8 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: paperless-ngx\n" "Project-Id-Version: paperless-ngx\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2026-08-29 20:02+0000\n" "POT-Creation-Date: 2026-09-01 14:47+0000\n"
"PO-Revision-Date: 2026-08-29 20:04\n" "PO-Revision-Date: 2026-09-01 14:48\n"
"Last-Translator: \n" "Last-Translator: \n"
"Language-Team: Luxembourgish\n" "Language-Team: Luxembourgish\n"
"Language: lb_LU\n" "Language: lb_LU\n"
@@ -1610,48 +1610,48 @@ msgstr ""
msgid "workflow runs" msgid "workflow runs"
msgstr "" msgstr ""
#: documents/serialisers.py:523 documents/serialisers.py:875 #: documents/serialisers.py:524 documents/serialisers.py:878
#: documents/serialisers.py:2827 documents/views.py:313 documents/views.py:2611 #: documents/serialisers.py:2830 documents/views.py:313 documents/views.py:2613
#: paperless_mail/serialisers.py:156 #: paperless_mail/serialisers.py:156
msgid "Insufficient permissions." msgid "Insufficient permissions."
msgstr "" msgstr ""
#: documents/serialisers.py:711 #: documents/serialisers.py:714
msgid "Invalid color." msgid "Invalid color."
msgstr "Ongëlteg Faarf." msgstr "Ongëlteg Faarf."
#: documents/serialisers.py:2304 #: documents/serialisers.py:2307
#, python-format #, python-format
msgid "File type %(type)s not supported" msgid "File type %(type)s not supported"
msgstr "Fichierstyp %(type)s net ënnerstëtzt" msgstr "Fichierstyp %(type)s net ënnerstëtzt"
#: documents/serialisers.py:2348 #: documents/serialisers.py:2351
#, python-format #, python-format
msgid "Custom field id must be an integer: %(id)s" msgid "Custom field id must be an integer: %(id)s"
msgstr "" msgstr ""
#: documents/serialisers.py:2355 #: documents/serialisers.py:2358
#, python-format #, python-format
msgid "Custom field with id %(id)s does not exist" msgid "Custom field with id %(id)s does not exist"
msgstr "" msgstr ""
#: documents/serialisers.py:2372 documents/serialisers.py:2382 #: documents/serialisers.py:2375 documents/serialisers.py:2385
msgid "Custom fields must be a list of integers or an object mapping ids to values." msgid "Custom fields must be a list of integers or an object mapping ids to values."
msgstr "" msgstr ""
#: documents/serialisers.py:2377 #: documents/serialisers.py:2380
msgid "Some custom fields don't exist or were specified twice." msgid "Some custom fields don't exist or were specified twice."
msgstr "" msgstr ""
#: documents/serialisers.py:2524 #: documents/serialisers.py:2527
msgid "Invalid variable detected." msgid "Invalid variable detected."
msgstr "Ongëlteg Zeechen detektéiert." msgstr "Ongëlteg Zeechen detektéiert."
#: documents/serialisers.py:2883 #: documents/serialisers.py:2886
msgid "Duplicate document identifiers are not allowed." msgid "Duplicate document identifiers are not allowed."
msgstr "" msgstr ""
#: documents/serialisers.py:2913 documents/views.py:4608 #: documents/serialisers.py:2916 documents/views.py:4610
#, python-format #, python-format
msgid "Documents not found: %(ids)s" msgid "Documents not found: %(ids)s"
msgstr "" msgstr ""
@@ -1906,36 +1906,36 @@ msgstr ""
msgid "Unable to parse URI {value}" msgid "Unable to parse URI {value}"
msgstr "" msgstr ""
#: documents/views.py:306 documents/views.py:2608 #: documents/views.py:306 documents/views.py:2610
msgid "Invalid more_like_id" msgid "Invalid more_like_id"
msgstr "" msgstr ""
#: documents/views.py:1582 #: documents/views.py:1584
msgid "Invalid AI configuration." msgid "Invalid AI configuration."
msgstr "" msgstr ""
#: documents/views.py:1593 #: documents/views.py:1595
msgid "AI backend request timed out." msgid "AI backend request timed out."
msgstr "" msgstr ""
#: documents/views.py:2433 documents/views.py:2754 #: documents/views.py:2435 documents/views.py:2756
msgid "Specify only one of text, title_search, query, or more_like_id." msgid "Specify only one of text, title_search, query, or more_like_id."
msgstr "" msgstr ""
#: documents/views.py:4621 #: documents/views.py:4623
#, python-format #, python-format
msgid "Insufficient permissions to share document %(id)s." msgid "Insufficient permissions to share document %(id)s."
msgstr "" msgstr ""
#: documents/views.py:4667 #: documents/views.py:4669
msgid "Bundle is already being processed." msgid "Bundle is already being processed."
msgstr "" msgstr ""
#: documents/views.py:4728 #: documents/views.py:4730
msgid "The share link bundle is still being prepared. Please try again later." msgid "The share link bundle is still being prepared. Please try again later."
msgstr "" msgstr ""
#: documents/views.py:4738 #: documents/views.py:4740
msgid "The share link bundle is unavailable." msgid "The share link bundle is unavailable."
msgstr "" msgstr ""

Some files were not shown because too many files have changed in this diff Show More