mirror of
https://github.com/paperless-ngx/paperless-ngx.git
synced 2026-10-06 16:20:30 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6f7ed1d4a7 | ||
|
|
0428bf6955 | ||
|
|
c63afb47b2 |
@@ -80,7 +80,7 @@ jobs:
|
|||||||
needs: changes
|
needs: changes
|
||||||
if: needs.changes.outputs.backend_changed == 'true'
|
if: needs.changes.outputs.backend_changed == 'true'
|
||||||
name: "Python ${{ matrix.python-version }}"
|
name: "Python ${{ matrix.python-version }}"
|
||||||
runs-on: ubuntu-26.04
|
runs-on: ubuntu-24.04
|
||||||
permissions:
|
permissions:
|
||||||
contents: read
|
contents: read
|
||||||
strategy:
|
strategy:
|
||||||
@@ -114,7 +114,7 @@ jobs:
|
|||||||
packages: unpaper tesseract-ocr imagemagick ghostscript poppler-utils
|
packages: unpaper tesseract-ocr imagemagick ghostscript poppler-utils
|
||||||
- name: Configure ImageMagick
|
- name: Configure ImageMagick
|
||||||
run: |
|
run: |
|
||||||
sudo cp docker/rootfs/etc/ImageMagick-6/paperless-policy.xml /etc/ImageMagick-7/policy.xml
|
sudo cp docker/rootfs/etc/ImageMagick-6/paperless-policy.xml /etc/ImageMagick-6/policy.xml
|
||||||
- name: Install Python dependencies
|
- name: Install Python dependencies
|
||||||
env:
|
env:
|
||||||
PYTHON_VERSION: ${{ steps.setup-python.outputs.python-version }}
|
PYTHON_VERSION: ${{ steps.setup-python.outputs.python-version }}
|
||||||
@@ -158,7 +158,7 @@ jobs:
|
|||||||
needs: changes
|
needs: changes
|
||||||
if: needs.changes.outputs.backend_changed == 'true'
|
if: needs.changes.outputs.backend_changed == 'true'
|
||||||
name: Check project typing
|
name: Check project typing
|
||||||
runs-on: ubuntu-26.04
|
runs-on: ubuntu-24.04
|
||||||
permissions:
|
permissions:
|
||||||
contents: read
|
contents: read
|
||||||
env:
|
env:
|
||||||
|
|||||||
@@ -24,10 +24,10 @@ jobs:
|
|||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
include:
|
include:
|
||||||
- runner: ubuntu-26.04
|
- runner: ubuntu-24.04
|
||||||
arch: amd64
|
arch: amd64
|
||||||
platform: linux/amd64
|
platform: linux/amd64
|
||||||
- runner: ubuntu-26.04-arm
|
- runner: ubuntu-24.04-arm
|
||||||
arch: arm64
|
arch: arm64
|
||||||
platform: linux/arm64
|
platform: linux/arm64
|
||||||
runs-on: ${{ matrix.runner }}
|
runs-on: ${{ matrix.runner }}
|
||||||
@@ -163,7 +163,7 @@ jobs:
|
|||||||
archive: false
|
archive: false
|
||||||
merge-and-push:
|
merge-and-push:
|
||||||
name: Merge and Push Manifest
|
name: Merge and Push Manifest
|
||||||
runs-on: ubuntu-26.04
|
runs-on: ubuntu-24.04
|
||||||
needs: build-arch
|
needs: build-arch
|
||||||
if: needs.build-arch.outputs.should-push == 'true'
|
if: needs.build-arch.outputs.should-push == 'true'
|
||||||
environment: image-publishing
|
environment: image-publishing
|
||||||
|
|||||||
@@ -65,7 +65,7 @@ jobs:
|
|||||||
needs: changes
|
needs: changes
|
||||||
if: needs.changes.outputs.docs_changed == 'true'
|
if: needs.changes.outputs.docs_changed == 'true'
|
||||||
name: Build Documentation
|
name: Build Documentation
|
||||||
runs-on: ubuntu-26.04
|
runs-on: ubuntu-24.04
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/configure-pages@45bfe0192ca1faeb007ade9deae92b16b8254a0d # v6.0.0
|
- uses: actions/configure-pages@45bfe0192ca1faeb007ade9deae92b16b8254a0d # v6.0.0
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
@@ -102,7 +102,7 @@ jobs:
|
|||||||
name: Deploy Documentation
|
name: Deploy Documentation
|
||||||
needs: [changes, build]
|
needs: [changes, build]
|
||||||
if: github.event_name == 'push' && github.ref == 'refs/heads/main' && needs.changes.outputs.docs_changed == 'true'
|
if: github.event_name == 'push' && github.ref == 'refs/heads/main' && needs.changes.outputs.docs_changed == 'true'
|
||||||
runs-on: ubuntu-26.04
|
runs-on: ubuntu-24.04
|
||||||
permissions:
|
permissions:
|
||||||
pages: write
|
pages: write
|
||||||
id-token: write
|
id-token: write
|
||||||
|
|||||||
@@ -72,7 +72,7 @@ jobs:
|
|||||||
needs: changes
|
needs: changes
|
||||||
if: needs.changes.outputs.frontend_changed == 'true'
|
if: needs.changes.outputs.frontend_changed == 'true'
|
||||||
name: Install Dependencies
|
name: Install Dependencies
|
||||||
runs-on: ubuntu-26.04
|
runs-on: ubuntu-24.04
|
||||||
permissions:
|
permissions:
|
||||||
contents: read
|
contents: read
|
||||||
steps:
|
steps:
|
||||||
@@ -104,7 +104,7 @@ jobs:
|
|||||||
name: Lint
|
name: Lint
|
||||||
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-26.04
|
runs-on: ubuntu-24.04
|
||||||
permissions:
|
permissions:
|
||||||
contents: read
|
contents: read
|
||||||
steps:
|
steps:
|
||||||
@@ -137,7 +137,7 @@ jobs:
|
|||||||
name: "Unit Tests (${{ matrix.shard-index }}/${{ matrix.shard-count }})"
|
name: "Unit Tests (${{ matrix.shard-index }}/${{ matrix.shard-count }})"
|
||||||
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-26.04
|
runs-on: ubuntu-24.04
|
||||||
permissions:
|
permissions:
|
||||||
contents: read
|
contents: read
|
||||||
strategy:
|
strategy:
|
||||||
@@ -188,10 +188,10 @@ jobs:
|
|||||||
name: E2E Tests
|
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-26.04
|
runs-on: ubuntu-24.04
|
||||||
permissions:
|
permissions:
|
||||||
contents: read
|
contents: read
|
||||||
container: mcr.microsoft.com/playwright:v1.62.1-resolute
|
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
|
||||||
@@ -246,7 +246,7 @@ jobs:
|
|||||||
name: Frontend Build
|
name: Frontend Build
|
||||||
needs: [changes, unit-tests, e2e-tests]
|
needs: [changes, unit-tests, e2e-tests]
|
||||||
if: needs.changes.outputs.frontend_changed == 'true'
|
if: needs.changes.outputs.frontend_changed == 'true'
|
||||||
runs-on: ubuntu-26.04
|
runs-on: ubuntu-24.04
|
||||||
permissions:
|
permissions:
|
||||||
contents: read
|
contents: read
|
||||||
steps:
|
steps:
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ permissions: {}
|
|||||||
jobs:
|
jobs:
|
||||||
wait-for-docker:
|
wait-for-docker:
|
||||||
name: Wait for Docker Build
|
name: Wait for Docker Build
|
||||||
runs-on: ubuntu-26.04
|
runs-on: ubuntu-24.04
|
||||||
permissions:
|
permissions:
|
||||||
checks: read
|
checks: read
|
||||||
statuses: read
|
statuses: read
|
||||||
@@ -30,7 +30,7 @@ jobs:
|
|||||||
build-release:
|
build-release:
|
||||||
name: Build Release
|
name: Build Release
|
||||||
needs: wait-for-docker
|
needs: wait-for-docker
|
||||||
runs-on: ubuntu-26.04
|
runs-on: ubuntu-24.04
|
||||||
permissions:
|
permissions:
|
||||||
contents: read
|
contents: read
|
||||||
steps:
|
steps:
|
||||||
@@ -73,7 +73,7 @@ jobs:
|
|||||||
timeout-minutes: 12
|
timeout-minutes: 12
|
||||||
uses: $/.github/actions/apt-install
|
uses: $/.github/actions/apt-install
|
||||||
with:
|
with:
|
||||||
packages: gettext libleptonica6
|
packages: gettext liblept5
|
||||||
# ---- Build Documentation ----
|
# ---- Build Documentation ----
|
||||||
- name: Build documentation
|
- name: Build documentation
|
||||||
env:
|
env:
|
||||||
@@ -145,7 +145,7 @@ jobs:
|
|||||||
publish-release:
|
publish-release:
|
||||||
name: Publish Release
|
name: Publish Release
|
||||||
needs: build-release
|
needs: build-release
|
||||||
runs-on: ubuntu-26.04
|
runs-on: ubuntu-24.04
|
||||||
permissions:
|
permissions:
|
||||||
contents: write
|
contents: write
|
||||||
pull-requests: write
|
pull-requests: write
|
||||||
@@ -197,7 +197,7 @@ jobs:
|
|||||||
name: Append Changelog
|
name: Append Changelog
|
||||||
needs: publish-release
|
needs: publish-release
|
||||||
if: needs.publish-release.outputs.prerelease == 'false'
|
if: needs.publish-release.outputs.prerelease == 'false'
|
||||||
runs-on: ubuntu-26.04
|
runs-on: ubuntu-24.04
|
||||||
permissions:
|
permissions:
|
||||||
contents: write
|
contents: write
|
||||||
pull-requests: write
|
pull-requests: write
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ permissions:
|
|||||||
jobs:
|
jobs:
|
||||||
zizmor:
|
zizmor:
|
||||||
name: Run zizmor
|
name: Run zizmor
|
||||||
runs-on: ubuntu-26.04
|
runs-on: ubuntu-24.04
|
||||||
permissions:
|
permissions:
|
||||||
contents: read
|
contents: read
|
||||||
actions: read
|
actions: read
|
||||||
@@ -29,7 +29,7 @@ jobs:
|
|||||||
uses: zizmorcore/zizmor-action@cc914d7f3750a2d13d75c7f184a1060aa0e9d482 # v0.6.4
|
uses: zizmorcore/zizmor-action@cc914d7f3750a2d13d75c7f184a1060aa0e9d482 # v0.6.4
|
||||||
semgrep:
|
semgrep:
|
||||||
name: Semgrep CE
|
name: Semgrep CE
|
||||||
runs-on: ubuntu-26.04
|
runs-on: ubuntu-24.04
|
||||||
container:
|
container:
|
||||||
image: semgrep/semgrep:1.155.0@sha256:cc869c685dcc0fe497c86258da9f205397d8108e56d21a86082ea4886e52784d
|
image: semgrep/semgrep:1.155.0@sha256:cc869c685dcc0fe497c86258da9f205397d8108e56d21a86082ea4886e52784d
|
||||||
if: github.actor != 'dependabot[bot]'
|
if: github.actor != 'dependabot[bot]'
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ jobs:
|
|||||||
cleanup-images:
|
cleanup-images:
|
||||||
name: Cleanup Image Tags for ${{ matrix.primary-name }}
|
name: Cleanup Image Tags for ${{ matrix.primary-name }}
|
||||||
if: github.repository_owner == 'paperless-ngx'
|
if: github.repository_owner == 'paperless-ngx'
|
||||||
runs-on: ubuntu-26.04
|
runs-on: ubuntu-24.04
|
||||||
environment: registry-maintenance
|
environment: registry-maintenance
|
||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
@@ -42,7 +42,7 @@ jobs:
|
|||||||
cleanup-untagged-images:
|
cleanup-untagged-images:
|
||||||
name: Cleanup Untagged Images Tags for ${{ matrix.primary-name }}
|
name: Cleanup Untagged Images Tags for ${{ matrix.primary-name }}
|
||||||
if: github.repository_owner == 'paperless-ngx'
|
if: github.repository_owner == 'paperless-ngx'
|
||||||
runs-on: ubuntu-26.04
|
runs-on: ubuntu-24.04
|
||||||
needs:
|
needs:
|
||||||
- cleanup-images
|
- cleanup-images
|
||||||
environment: registry-maintenance
|
environment: registry-maintenance
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ on:
|
|||||||
jobs:
|
jobs:
|
||||||
analyze:
|
analyze:
|
||||||
name: Analyze
|
name: Analyze
|
||||||
runs-on: ubuntu-26.04
|
runs-on: ubuntu-24.04
|
||||||
permissions:
|
permissions:
|
||||||
actions: read
|
actions: read
|
||||||
contents: read
|
contents: read
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ jobs:
|
|||||||
synchronize-with-crowdin:
|
synchronize-with-crowdin:
|
||||||
name: Crowdin Sync
|
name: Crowdin Sync
|
||||||
if: github.repository_owner == 'paperless-ngx'
|
if: github.repository_owner == 'paperless-ngx'
|
||||||
runs-on: ubuntu-26.04
|
runs-on: ubuntu-24.04
|
||||||
environment: translation-sync
|
environment: translation-sync
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ jobs:
|
|||||||
# Note: peakoss/anti-slop does not support the `issues` event yet (all of its
|
# Note: peakoss/anti-slop does not support the `issues` event yet (all of its
|
||||||
# issue inputs are still commented out upstream), so the checks that the PR Bot
|
# issue inputs are still commented out upstream), so the checks that the PR Bot
|
||||||
# workflow gets from the action are implemented manually here.
|
# workflow gets from the action are implemented manually here.
|
||||||
runs-on: ubuntu-slim
|
runs-on: ubuntu-latest
|
||||||
permissions:
|
permissions:
|
||||||
issues: write
|
issues: write
|
||||||
steps:
|
steps:
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ on:
|
|||||||
types: [opened]
|
types: [opened]
|
||||||
jobs:
|
jobs:
|
||||||
Anti-slop:
|
Anti-slop:
|
||||||
runs-on: ubuntu-slim
|
runs-on: ubuntu-latest
|
||||||
permissions:
|
permissions:
|
||||||
contents: read
|
contents: read
|
||||||
issues: read
|
issues: read
|
||||||
@@ -24,7 +24,7 @@ jobs:
|
|||||||
ASLOP-PR-VERIFY
|
ASLOP-PR-VERIFY
|
||||||
pr-bot:
|
pr-bot:
|
||||||
name: Automated PR Bot
|
name: Automated PR Bot
|
||||||
runs-on: ubuntu-slim
|
runs-on: ubuntu-latest
|
||||||
# Runs after Anti-slop so the welcome comment can see whether the PR was closed
|
# Runs after Anti-slop so the welcome comment can see whether the PR was closed
|
||||||
# instead of racing it. Still runs if that job fails, so labeling is not lost.
|
# instead of racing it. Still runs if that job fails, so labeling is not lost.
|
||||||
needs: Anti-slop
|
needs: Anti-slop
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ permissions:
|
|||||||
jobs:
|
jobs:
|
||||||
pr_opened_or_reopened:
|
pr_opened_or_reopened:
|
||||||
name: pr_opened_or_reopened
|
name: pr_opened_or_reopened
|
||||||
runs-on: ubuntu-slim
|
runs-on: ubuntu-24.04
|
||||||
permissions:
|
permissions:
|
||||||
# write permission is required for autolabeler
|
# write permission is required for autolabeler
|
||||||
pull-requests: write
|
pull-requests: write
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ jobs:
|
|||||||
stale:
|
stale:
|
||||||
name: 'Stale'
|
name: 'Stale'
|
||||||
if: github.repository_owner == 'paperless-ngx'
|
if: github.repository_owner == 'paperless-ngx'
|
||||||
runs-on: ubuntu-26.04
|
runs-on: ubuntu-24.04
|
||||||
permissions:
|
permissions:
|
||||||
issues: write
|
issues: write
|
||||||
pull-requests: write
|
pull-requests: write
|
||||||
@@ -34,7 +34,7 @@ jobs:
|
|||||||
lock-threads:
|
lock-threads:
|
||||||
name: 'Lock Old Threads'
|
name: 'Lock Old Threads'
|
||||||
if: github.repository_owner == 'paperless-ngx'
|
if: github.repository_owner == 'paperless-ngx'
|
||||||
runs-on: ubuntu-26.04
|
runs-on: ubuntu-24.04
|
||||||
permissions:
|
permissions:
|
||||||
issues: write
|
issues: write
|
||||||
pull-requests: write
|
pull-requests: write
|
||||||
@@ -58,7 +58,7 @@ jobs:
|
|||||||
close-answered-discussions:
|
close-answered-discussions:
|
||||||
name: 'Close Answered Discussions'
|
name: 'Close Answered Discussions'
|
||||||
if: github.repository_owner == 'paperless-ngx'
|
if: github.repository_owner == 'paperless-ngx'
|
||||||
runs-on: ubuntu-slim
|
runs-on: ubuntu-24.04
|
||||||
permissions:
|
permissions:
|
||||||
discussions: write
|
discussions: write
|
||||||
steps:
|
steps:
|
||||||
@@ -117,7 +117,7 @@ jobs:
|
|||||||
close-outdated-discussions:
|
close-outdated-discussions:
|
||||||
name: 'Close Outdated Discussions'
|
name: 'Close Outdated Discussions'
|
||||||
if: github.repository_owner == 'paperless-ngx'
|
if: github.repository_owner == 'paperless-ngx'
|
||||||
runs-on: ubuntu-slim
|
runs-on: ubuntu-24.04
|
||||||
permissions:
|
permissions:
|
||||||
discussions: write
|
discussions: write
|
||||||
steps:
|
steps:
|
||||||
@@ -211,7 +211,7 @@ jobs:
|
|||||||
close-unsupported-feature-requests:
|
close-unsupported-feature-requests:
|
||||||
name: 'Close Unsupported Feature Requests'
|
name: 'Close Unsupported Feature Requests'
|
||||||
if: github.repository_owner == 'paperless-ngx'
|
if: github.repository_owner == 'paperless-ngx'
|
||||||
runs-on: ubuntu-slim
|
runs-on: ubuntu-24.04
|
||||||
permissions:
|
permissions:
|
||||||
discussions: write
|
discussions: write
|
||||||
steps:
|
steps:
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ env:
|
|||||||
jobs:
|
jobs:
|
||||||
generate-translate-strings:
|
generate-translate-strings:
|
||||||
name: Generate Translation Strings
|
name: Generate Translation Strings
|
||||||
runs-on: ubuntu-26.04
|
runs-on: ubuntu-latest
|
||||||
environment: translation-sync
|
environment: translation-sync
|
||||||
permissions:
|
permissions:
|
||||||
contents: write
|
contents: write
|
||||||
|
|||||||
+3
-1
@@ -76,7 +76,9 @@ is not supported by any of the available parsers.
|
|||||||
|
|
||||||
**A:** Not by default. As of v3, a file whose contents match an existing document is still
|
**A:** Not by default. As of v3, a file whose contents match an existing document is still
|
||||||
consumed, and the duplicate is flagged in the UI — open the document and check the
|
consumed, and the duplicate is flagged in the UI — open the document and check the
|
||||||
**Duplicates** tab to review documents that share the same content. If you prefer the old
|
**Duplicates** tab to review documents that share the same content, or filter the document
|
||||||
|
list by **Duplicates** to find all of them (see
|
||||||
|
[Duplicate documents](usage.md#duplicate-documents)). If you prefer the old
|
||||||
behavior of rejecting duplicates during consumption, set
|
behavior of rejecting duplicates during consumption, set
|
||||||
[`PAPERLESS_CONSUMER_DELETE_DUPLICATES`](configuration.md#PAPERLESS_CONSUMER_DELETE_DUPLICATES)
|
[`PAPERLESS_CONSUMER_DELETE_DUPLICATES`](configuration.md#PAPERLESS_CONSUMER_DELETE_DUPLICATES)
|
||||||
to `true`.
|
to `true`.
|
||||||
|
|||||||
+7
-8
@@ -299,19 +299,18 @@ for details.
|
|||||||
### Duplicate documents
|
### Duplicate documents
|
||||||
|
|
||||||
By default, Paperless-ngx **does not reject duplicates**. If you consume a file whose
|
By default, Paperless-ngx **does not reject duplicates**. If you consume a file whose
|
||||||
contents exactly match an existing document (same checksum), the new copy is still
|
contents match an existing document (same original or archive checksum), the new copy is
|
||||||
consumed and a warning is logged. The task entry for the upload also flags that a
|
still consumed and a warning is logged.
|
||||||
duplicate was detected and links to the existing document(s).
|
|
||||||
|
|
||||||
To review duplicates, open a document and switch to the **Duplicates** tab on the
|
When a document has duplicates, a **Duplicates** tab appears on its detail page, listing
|
||||||
document detail page. It lists other documents that share the same content, including any
|
the other documents you can view that share the same content (including any in the trash).
|
||||||
that are in the trash (shown with a badge), and links to each so you can decide which to
|
To find all documents with duplicates, choose **Duplicates** in the document list's text
|
||||||
keep.
|
filter dropdown, or use `has_duplicates=true` in the REST API.
|
||||||
|
|
||||||
If you would rather reject duplicates at consumption time (the pre-v3 behavior), set
|
If you would rather reject duplicates at consumption time (the pre-v3 behavior), set
|
||||||
[`PAPERLESS_CONSUMER_DELETE_DUPLICATES`](configuration.md#PAPERLESS_CONSUMER_DELETE_DUPLICATES)
|
[`PAPERLESS_CONSUMER_DELETE_DUPLICATES`](configuration.md#PAPERLESS_CONSUMER_DELETE_DUPLICATES)
|
||||||
to `true`. The duplicate file is then deleted instead of consumed, and the task fails with
|
to `true`. The duplicate file is then deleted instead of consumed, and the task fails with
|
||||||
a "document already exists" message.
|
a "Document already exists" message linking to the existing document.
|
||||||
|
|
||||||
## Document Suggestions
|
## Document Suggestions
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
[project]
|
[project]
|
||||||
name = "paperless-ngx"
|
name = "paperless-ngx"
|
||||||
version = "3.2.1"
|
version = "3.3.0"
|
||||||
description = """\
|
description = """\
|
||||||
A community-supported supercharged document management system: scan, index and archive all your physical documents\
|
A community-supported supercharged document management system: scan, index and archive all your physical documents\
|
||||||
"""
|
"""
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "paperless-ngx-ui",
|
"name": "paperless-ngx-ui",
|
||||||
"version": "3.2.1",
|
"version": "3.3.0",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"preinstall": "npx only-allow pnpm",
|
"preinstall": "npx only-allow pnpm",
|
||||||
"ng": "ng",
|
"ng": "ng",
|
||||||
|
|||||||
@@ -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.2.1',
|
version: '3.3.0',
|
||||||
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,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-10-06 15:12+0000\n"
|
"POT-Creation-Date: 2026-10-05 16:26+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"
|
||||||
@@ -1941,8 +1941,25 @@ msgstr ""
|
|||||||
msgid "As a final step, please complete the following form:"
|
msgid "As a final step, please complete the following form:"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#: documents/validators.py:24
|
||||||
|
#, python-brace-format
|
||||||
|
msgid "Unable to parse URI {value}, missing scheme"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: documents/validators.py:29
|
||||||
|
#, python-brace-format
|
||||||
|
msgid "Unable to parse URI {value}, missing net location or path"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: documents/validators.py:36
|
#: documents/validators.py:36
|
||||||
msgid ", "
|
msgid ""
|
||||||
|
"URI scheme '{parts.scheme}' is not allowed. Allowed schemes: {', '."
|
||||||
|
"join(allowed_schemes)}"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: documents/validators.py:45
|
||||||
|
#, python-brace-format
|
||||||
|
msgid "Unable to parse URI {value}"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: documents/views.py:336 documents/views.py:2729
|
#: documents/views.py:336 documents/views.py:2729
|
||||||
|
|||||||
@@ -137,20 +137,9 @@ class TestNginxService:
|
|||||||
reason="No Gotenberg/Tika servers to test with",
|
reason="No Gotenberg/Tika servers to test with",
|
||||||
)
|
)
|
||||||
class TestParserLive:
|
class TestParserLive:
|
||||||
# Rasterizer versions shift a few pixels, so compare perceptual hashes by
|
@staticmethod
|
||||||
# Hamming distance (out of 18 * 18 = 324 bits) rather than for equality
|
def imagehash(file: Path, hash_size: int = 18) -> str:
|
||||||
MAX_HASH_DISTANCE = 8
|
return f"{average_hash(Image.open(file), hash_size)}"
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def assert_thumbnails_similar(cls, generated: Path, expected: Path) -> None:
|
|
||||||
distance = average_hash(Image.open(generated), 18) - average_hash(
|
|
||||||
Image.open(expected),
|
|
||||||
18,
|
|
||||||
)
|
|
||||||
assert distance <= cls.MAX_HASH_DISTANCE, (
|
|
||||||
f"Thumbnail {generated} differs from {expected} by {distance} bits "
|
|
||||||
f"(max {cls.MAX_HASH_DISTANCE})"
|
|
||||||
)
|
|
||||||
|
|
||||||
def test_get_thumbnail(
|
def test_get_thumbnail(
|
||||||
self,
|
self,
|
||||||
@@ -179,7 +168,12 @@ class TestParserLive:
|
|||||||
assert thumb.exists()
|
assert thumb.exists()
|
||||||
assert thumb.is_file()
|
assert thumb.is_file()
|
||||||
|
|
||||||
self.assert_thumbnails_similar(thumb, simple_txt_email_thumbnail_file)
|
assert self.imagehash(thumb) == self.imagehash(
|
||||||
|
simple_txt_email_thumbnail_file,
|
||||||
|
), (
|
||||||
|
f"Created thumbnail {thumb} differs from expected file "
|
||||||
|
f"{simple_txt_email_thumbnail_file}"
|
||||||
|
)
|
||||||
|
|
||||||
def test_tika_parse_successful(self, mail_parser: MailDocumentParser) -> None:
|
def test_tika_parse_successful(self, mail_parser: MailDocumentParser) -> None:
|
||||||
"""
|
"""
|
||||||
@@ -261,7 +255,7 @@ class TestParserLive:
|
|||||||
THEN:
|
THEN:
|
||||||
- Gotenberg shall be called to generate the PDF
|
- Gotenberg shall be called to generate the PDF
|
||||||
- The archive PDF shall contain the expected content
|
- The archive PDF shall contain the expected content
|
||||||
- The generated thumbnail shall be perceptually close to the expected image
|
- The generated thumbnail shall match the expected image hash
|
||||||
"""
|
"""
|
||||||
util_call_with_backoff(mail_parser.parse, [html_email_file, "message/rfc822"])
|
util_call_with_backoff(mail_parser.parse, [html_email_file, "message/rfc822"])
|
||||||
|
|
||||||
@@ -278,4 +272,14 @@ class TestParserLive:
|
|||||||
html_email_file,
|
html_email_file,
|
||||||
"message/rfc822",
|
"message/rfc822",
|
||||||
)
|
)
|
||||||
self.assert_thumbnails_similar(generated_thumbnail, html_email_thumbnail_file)
|
generated_thumbnail_hash = self.imagehash(generated_thumbnail)
|
||||||
|
|
||||||
|
# The created PDF is not reproducible, but the converted image
|
||||||
|
# should always look the same
|
||||||
|
expected_hash = self.imagehash(html_email_thumbnail_file)
|
||||||
|
|
||||||
|
assert generated_thumbnail_hash == expected_hash, (
|
||||||
|
f"PDF thumbnail differs from expected. "
|
||||||
|
f"Generated: {generated_thumbnail}, "
|
||||||
|
f"Hash: {generated_thumbnail_hash} vs {expected_hash}"
|
||||||
|
)
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
from typing import Final
|
from typing import Final
|
||||||
|
|
||||||
__version__: Final[tuple[int, int, int]] = (3, 2, 1)
|
__version__: Final[tuple[int, int, int]] = (3, 3, 0)
|
||||||
# Version string like X.Y.Z
|
# Version string like X.Y.Z
|
||||||
__full_version_str__: Final[str] = ".".join(map(str, __version__))
|
__full_version_str__: Final[str] = ".".join(map(str, __version__))
|
||||||
# Version string like X.Y
|
# Version string like X.Y
|
||||||
|
|||||||
@@ -2971,7 +2971,7 @@ wheels = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "paperless-ngx"
|
name = "paperless-ngx"
|
||||||
version = "3.2.1"
|
version = "3.3.0"
|
||||||
source = { virtual = "." }
|
source = { virtual = "." }
|
||||||
dependencies = [
|
dependencies = [
|
||||||
{ name = "azure-ai-documentintelligence" },
|
{ name = "azure-ai-documentintelligence" },
|
||||||
|
|||||||
Reference in New Issue
Block a user