mirror of
https://github.com/paperless-ngx/paperless-ngx.git
synced 2025-07-26 18:14:37 -05:00
Compare commits
14 Commits
e35dad81d9
...
d956269d5f
Author | SHA1 | Date | |
---|---|---|---|
![]() |
d956269d5f | ||
![]() |
f269919410 | ||
![]() |
5f00066dff | ||
![]() |
705f542129 | ||
![]() |
f036292b72 | ||
![]() |
f8a43d5dab | ||
![]() |
53c106d448 | ||
![]() |
0f37186c88 | ||
![]() |
0fb55f3ae8 | ||
![]() |
78822f6121 | ||
![]() |
2ee1d7540e | ||
![]() |
43b2527275 | ||
![]() |
248b573c03 | ||
![]() |
b9f7428f2f |
@ -81,7 +81,7 @@ Some notes about translation:
|
|||||||
|
|
||||||
If a language has already been added, and you would like to contribute new translations or change existing translations, please read the "Translation" section in the README.md file for further details on that.
|
If a language has already been added, and you would like to contribute new translations or change existing translations, please read the "Translation" section in the README.md file for further details on that.
|
||||||
|
|
||||||
If you would like the project to be translated to another language, first head over to https://crwd.in/paperless-ngx to check if that language has already been enabled for translation.
|
If you would like the project to be translated to another language, first head over to https://crowdin.com/project/paperless-ngx to check if that language has already been enabled for translation.
|
||||||
If not, please request the language to be added by creating an issue on GitHub. The issue should contain:
|
If not, please request the language to be added by creating an issue on GitHub. The issue should contain:
|
||||||
|
|
||||||
- English name of the language (the localized name can be added on Crowdin).
|
- English name of the language (the localized name can be added on Crowdin).
|
||||||
|
@ -32,7 +32,7 @@ RUN set -eux \
|
|||||||
# Purpose: Installs s6-overlay and rootfs
|
# Purpose: Installs s6-overlay and rootfs
|
||||||
# Comments:
|
# Comments:
|
||||||
# - Don't leave anything extra in here either
|
# - Don't leave anything extra in here either
|
||||||
FROM ghcr.io/astral-sh/uv:0.6.11-python3.12-bookworm-slim AS s6-overlay-base
|
FROM ghcr.io/astral-sh/uv:0.6.13-python3.12-bookworm-slim AS s6-overlay-base
|
||||||
|
|
||||||
WORKDIR /usr/src/s6
|
WORKDIR /usr/src/s6
|
||||||
|
|
||||||
|
@ -83,7 +83,7 @@ People interested in continuing the work on paperless-ngx are encouraged to reac
|
|||||||
|
|
||||||
## Translation
|
## Translation
|
||||||
|
|
||||||
Paperless-ngx is available in many languages that are coordinated on Crowdin. If you want to help out by translating paperless-ngx into your language, please head over to https://crwd.in/paperless-ngx, and thank you! More details can be found in [CONTRIBUTING.md](https://github.com/paperless-ngx/paperless-ngx/blob/main/CONTRIBUTING.md#translating-paperless-ngx).
|
Paperless-ngx is available in many languages that are coordinated on Crowdin. If you want to help out by translating paperless-ngx into your language, please head over to https://crowdin.com/project/paperless-ngx, and thank you! More details can be found in [CONTRIBUTING.md](https://github.com/paperless-ngx/paperless-ngx/blob/main/CONTRIBUTING.md#translating-paperless-ngx).
|
||||||
|
|
||||||
## Feature Requests
|
## Feature Requests
|
||||||
|
|
||||||
|
@ -17,6 +17,9 @@ if find /run/s6/container_environment/*"_FILE" -maxdepth 1 > /dev/null 2>&1; the
|
|||||||
if [[ -f ${SECRETFILE} ]]; then
|
if [[ -f ${SECRETFILE} ]]; then
|
||||||
# Trim off trailing _FILE
|
# Trim off trailing _FILE
|
||||||
FILESTRIP=${FILENAME//_FILE/}
|
FILESTRIP=${FILENAME//_FILE/}
|
||||||
|
if [[ $(tail -n1 "${SECRETFILE}" | wc -l) != 0 ]]; then
|
||||||
|
echo "${log_prefix} Your secret: ${FILENAME##*/} contains a trailing newline and may not work as expected"
|
||||||
|
fi
|
||||||
# Set environment variable
|
# Set environment variable
|
||||||
cat "${SECRETFILE}" > "${FILESTRIP}"
|
cat "${SECRETFILE}" > "${FILESTRIP}"
|
||||||
echo "${log_prefix} ${FILESTRIP##*/} set from ${FILENAME##*/}"
|
echo "${log_prefix} ${FILESTRIP##*/} set from ${FILENAME##*/}"
|
||||||
|
7
docker/rootfs/etc/s6-overlay/s6-rc.d/init-migrations/migrate.sh
Executable file
7
docker/rootfs/etc/s6-overlay/s6-rc.d/init-migrations/migrate.sh
Executable file
@ -0,0 +1,7 @@
|
|||||||
|
#!/command/with-contenv /usr/bin/bash
|
||||||
|
# shellcheck shell=bash
|
||||||
|
declare -r data_dir="${PAPERLESS_DATA_DIR:-/usr/src/paperless/data}"
|
||||||
|
|
||||||
|
# shellcheck disable=SC2164
|
||||||
|
cd "${PAPERLESS_SRC_DIR}"
|
||||||
|
exec s6-setlock -n "${data_dir}/migration_lock" python3 manage.py migrate --skip-checks --no-input
|
@ -1,20 +1,12 @@
|
|||||||
#!/command/with-contenv /usr/bin/bash
|
#!/command/with-contenv /usr/bin/bash
|
||||||
# shellcheck shell=bash
|
# shellcheck shell=bash
|
||||||
declare -r log_prefix="[init-migrations]"
|
declare -r log_prefix="[init-migrations]"
|
||||||
declare -r data_dir="${PAPERLESS_DATA_DIR:-/usr/src/paperless/data}"
|
|
||||||
|
|
||||||
(
|
echo "${log_prefix} Apply database migrations..."
|
||||||
# flock is in place to prevent multiple containers from doing migrations
|
|
||||||
# simultaneously. This also ensures that the db is ready when the command
|
|
||||||
# of the current container starts.
|
|
||||||
flock 200
|
|
||||||
echo "${log_prefix} Apply database migrations..."
|
|
||||||
cd "${PAPERLESS_SRC_DIR}"
|
|
||||||
|
|
||||||
if [[ -n "${USER_IS_NON_ROOT}" ]]; then
|
# The whole migrate, with flock, needs to run as the right user
|
||||||
exec python3 manage.py migrate --skip-checks --no-input
|
if [[ -n "${USER_IS_NON_ROOT}" ]]; then
|
||||||
else
|
exec /etc/s6-overlay/s6-rc.d/init-migrations/migrate.sh
|
||||||
exec s6-setuidgid paperless python3 manage.py migrate --skip-checks --no-input
|
else
|
||||||
fi
|
exec s6-setuidgid paperless /etc/s6-overlay/s6-rc.d/init-migrations/migrate.sh
|
||||||
|
fi
|
||||||
) 200>"${data_dir}/migration_lock"
|
|
||||||
|
@ -1,5 +1,34 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
## paperless-ngx 2.15.1
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
- Fix: Run migration lock as the correct user [@stumpylog](https://github.com/stumpylog) ([#9604](https://github.com/paperless-ngx/paperless-ngx/pull/9604))
|
||||||
|
- Fix: Adds a warning to the user if their secret file includes a trailing newline [@stumpylog](https://github.com/stumpylog) ([#9601](https://github.com/paperless-ngx/paperless-ngx/pull/9601))
|
||||||
|
- Fix: correct download filename in 2.15.0 [@shamoon](https://github.com/shamoon) ([#9599](https://github.com/paperless-ngx/paperless-ngx/pull/9599))
|
||||||
|
- Fix: dont exclude matching check for scheduled workflows [@shamoon](https://github.com/shamoon) ([#9594](https://github.com/paperless-ngx/paperless-ngx/pull/9594))
|
||||||
|
|
||||||
|
### Maintenance
|
||||||
|
|
||||||
|
- docker(deps): Bump astral-sh/uv from 0.6.9-python3.12-bookworm-slim to 0.6.13-python3.12-bookworm-slim @[dependabot[bot]](https://github.com/apps/dependabot) ([#9573](https://github.com/paperless-ngx/paperless-ngx/pull/9573))
|
||||||
|
|
||||||
|
### Dependencies
|
||||||
|
|
||||||
|
- docker(deps): Bump astral-sh/uv from 0.6.9-python3.12-bookworm-slim to 0.6.13-python3.12-bookworm-slim @[dependabot[bot]](https://github.com/apps/dependabot) ([#9573](https://github.com/paperless-ngx/paperless-ngx/pull/9573))
|
||||||
|
- Chore: move to whoosh-reloaded, for now [@shamoon](https://github.com/shamoon) ([#9605](https://github.com/paperless-ngx/paperless-ngx/pull/9605))
|
||||||
|
|
||||||
|
### All App Changes
|
||||||
|
|
||||||
|
<details>
|
||||||
|
<summary>4 changes</summary>
|
||||||
|
|
||||||
|
- Fix: Run migration lock as the correct user [@stumpylog](https://github.com/stumpylog) ([#9604](https://github.com/paperless-ngx/paperless-ngx/pull/9604))
|
||||||
|
- Fix: Adds a warning to the user if their secret file includes a trailing newline [@stumpylog](https://github.com/stumpylog) ([#9601](https://github.com/paperless-ngx/paperless-ngx/pull/9601))
|
||||||
|
- Fix: correct download filename in 2.15.0 [@shamoon](https://github.com/shamoon) ([#9599](https://github.com/paperless-ngx/paperless-ngx/pull/9599))
|
||||||
|
- Fix: dont exclude matching check for scheduled workflows [@shamoon](https://github.com/shamoon) ([#9594](https://github.com/paperless-ngx/paperless-ngx/pull/9594))
|
||||||
|
</details>
|
||||||
|
|
||||||
## paperless-ngx 2.15.0
|
## paperless-ngx 2.15.0
|
||||||
|
|
||||||
### Features
|
### Features
|
||||||
|
24
docs/faq.md
24
docs/faq.md
@ -112,30 +112,6 @@ able to run paperless, you're a bit on your own. If you can't run the
|
|||||||
docker image, the documentation has instructions for bare metal
|
docker image, the documentation has instructions for bare metal
|
||||||
installs.
|
installs.
|
||||||
|
|
||||||
## _How do I proxy this with NGINX?_
|
|
||||||
|
|
||||||
**A:** See [the wiki](https://github.com/paperless-ngx/paperless-ngx/wiki/Using-a-Reverse-Proxy-with-Paperless-ngx#nginx).
|
|
||||||
|
|
||||||
## _How do I get WebSocket support with Apache mod_wsgi_?
|
|
||||||
|
|
||||||
**A:** `mod_wsgi` by itself does not support ASGI. Paperless will
|
|
||||||
continue to work with WSGI, but certain features such as status
|
|
||||||
notifications about document consumption won't be available.
|
|
||||||
|
|
||||||
If you want to continue using `mod_wsgi`, you will have to run an
|
|
||||||
ASGI-enabled web server as well that processes WebSocket connections,
|
|
||||||
and configure Apache to redirect WebSocket connections to this server.
|
|
||||||
Multiple options for ASGI servers exist:
|
|
||||||
|
|
||||||
- `gunicorn` with `uvicorn` as the worker implementation (the default
|
|
||||||
of paperless)
|
|
||||||
- `daphne` as a standalone server, which is the reference
|
|
||||||
implementation for ASGI.
|
|
||||||
- `uvicorn` as a standalone server
|
|
||||||
|
|
||||||
You may also find the [Django documentation](https://docs.djangoproject.com/en/5.1/howto/deployment/asgi/) on ASGI
|
|
||||||
useful to review.
|
|
||||||
|
|
||||||
## _What about the Redis licensing change and using one of the open source forks_?
|
## _What about the Redis licensing change and using one of the open source forks_?
|
||||||
|
|
||||||
Currently (October 2024), forks of Redis such as Valkey or Redirect are not officially supported by our upstream
|
Currently (October 2024), forks of Redis such as Valkey or Redirect are not officially supported by our upstream
|
||||||
|
@ -197,7 +197,7 @@ People interested in continuing the work on paperless-ngx are encouraged to reac
|
|||||||
|
|
||||||
### Translation
|
### Translation
|
||||||
|
|
||||||
Paperless-ngx is available in many languages that are coordinated on [Crowdin](https://crwd.in/paperless-ngx). If you want to help out by translating paperless-ngx into your language, please head over to the [Paperless-ngx project at Crowdin](https://crwd.in/paperless-ngx), and thank you!
|
Paperless-ngx is available in many languages that are coordinated on [Crowdin](https://crowdin.com/project/paperless-ngx). If you want to help out by translating paperless-ngx into your language, please head over to the [Paperless-ngx project at Crowdin](https://crowdin.com/project/paperless-ngx), and thank you!
|
||||||
|
|
||||||
## Scanners & Software
|
## Scanners & Software
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
[project]
|
[project]
|
||||||
name = "paperless-ngx"
|
name = "paperless-ngx"
|
||||||
version = "2.15.0"
|
version = "2.15.1"
|
||||||
description = "A community-supported supercharged version of paperless: scan, index and archive all your physical documents"
|
description = "A community-supported supercharged version of paperless: scan, index and archive all your physical documents"
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
requires-python = ">=3.10"
|
requires-python = ">=3.10"
|
||||||
@ -65,7 +65,7 @@ dependencies = [
|
|||||||
"tqdm~=4.67.1",
|
"tqdm~=4.67.1",
|
||||||
"watchdog~=6.0",
|
"watchdog~=6.0",
|
||||||
"whitenoise~=6.9",
|
"whitenoise~=6.9",
|
||||||
"whoosh~=2.7",
|
"whoosh-reloaded>=2.7.5",
|
||||||
"zxing-cpp~=2.3.0",
|
"zxing-cpp~=2.3.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -1,5 +1,10 @@
|
|||||||
import { DatePipe } from '@angular/common'
|
import { DatePipe } from '@angular/common'
|
||||||
import { provideHttpClient, withInterceptorsFromDi } from '@angular/common/http'
|
import {
|
||||||
|
HttpHeaders,
|
||||||
|
HttpResponse,
|
||||||
|
provideHttpClient,
|
||||||
|
withInterceptorsFromDi,
|
||||||
|
} from '@angular/common/http'
|
||||||
import {
|
import {
|
||||||
HttpTestingController,
|
HttpTestingController,
|
||||||
provideHttpClientTesting,
|
provideHttpClientTesting,
|
||||||
@ -1331,6 +1336,34 @@ describe('DocumentDetailComponent', () => {
|
|||||||
expect(urlRevokeSpy).toHaveBeenCalled()
|
expect(urlRevokeSpy).toHaveBeenCalled()
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it('should download a file with the correct filename', () => {
|
||||||
|
const mockBlob = new Blob(['test content'], { type: 'text/plain' })
|
||||||
|
const mockResponse = new HttpResponse({
|
||||||
|
body: mockBlob,
|
||||||
|
headers: new HttpHeaders({
|
||||||
|
'Content-Disposition': 'attachment; filename="test-file.txt"',
|
||||||
|
}),
|
||||||
|
})
|
||||||
|
|
||||||
|
const downloadUrl = 'http://example.com/download'
|
||||||
|
component.documentId = 123
|
||||||
|
jest.spyOn(documentService, 'getDownloadUrl').mockReturnValue(downloadUrl)
|
||||||
|
|
||||||
|
const createSpy = jest.spyOn(document, 'createElement')
|
||||||
|
const anchor: HTMLAnchorElement = {} as HTMLAnchorElement
|
||||||
|
createSpy.mockReturnValueOnce(anchor)
|
||||||
|
|
||||||
|
component.download(false)
|
||||||
|
|
||||||
|
httpTestingController
|
||||||
|
.expectOne(downloadUrl)
|
||||||
|
.flush(mockBlob, { headers: mockResponse.headers })
|
||||||
|
|
||||||
|
expect(createSpy).toHaveBeenCalledWith('a')
|
||||||
|
expect(anchor.download).toBe('test-file.txt')
|
||||||
|
createSpy.mockClear()
|
||||||
|
})
|
||||||
|
|
||||||
it('should get email enabled status from settings', () => {
|
it('should get email enabled status from settings', () => {
|
||||||
jest.spyOn(settingsService, 'get').mockReturnValue(true)
|
jest.spyOn(settingsService, 'get').mockReturnValue(true)
|
||||||
expect(component.emailEnabled).toBeTruthy()
|
expect(component.emailEnabled).toBeTruthy()
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { AsyncPipe, NgTemplateOutlet } from '@angular/common'
|
import { AsyncPipe, NgTemplateOutlet } from '@angular/common'
|
||||||
import { HttpClient } from '@angular/common/http'
|
import { HttpClient, HttpResponse } from '@angular/common/http'
|
||||||
import { Component, OnDestroy, OnInit, ViewChild } from '@angular/core'
|
import { Component, OnDestroy, OnInit, ViewChild } from '@angular/core'
|
||||||
import {
|
import {
|
||||||
FormArray,
|
FormArray,
|
||||||
@ -995,44 +995,48 @@ export class DocumentDetailComponent
|
|||||||
this.documentId,
|
this.documentId,
|
||||||
original
|
original
|
||||||
)
|
)
|
||||||
this.http.get(downloadUrl, { responseType: 'blob' }).subscribe({
|
this.http
|
||||||
next: (blob) => {
|
.get(downloadUrl, { observe: 'response', responseType: 'blob' })
|
||||||
this.downloading = false
|
.subscribe({
|
||||||
const blobParts = [blob]
|
next: (response: HttpResponse<Blob>) => {
|
||||||
const file = new File(
|
const filename = response.headers
|
||||||
blobParts,
|
.get('Content-Disposition')
|
||||||
original
|
?.split(';')
|
||||||
? this.document.original_file_name
|
?.find((part) => part.trim().startsWith('filename='))
|
||||||
: this.document.archived_file_name,
|
?.split('=')[1]
|
||||||
{
|
?.replace(/['"]/g, '')
|
||||||
type: original ? this.document.mime_type : 'application/pdf',
|
const blob = new Blob([response.body], {
|
||||||
}
|
type: response.body.type,
|
||||||
)
|
|
||||||
if (
|
|
||||||
!this.deviceDetectorService.isDesktop() &&
|
|
||||||
navigator.canShare &&
|
|
||||||
navigator.canShare({ files: [file] })
|
|
||||||
) {
|
|
||||||
navigator.share({
|
|
||||||
files: [file],
|
|
||||||
})
|
})
|
||||||
} else {
|
this.downloading = false
|
||||||
const url = URL.createObjectURL(blob)
|
const file = new File([blob], filename, {
|
||||||
const a = document.createElement('a')
|
type: response.body.type,
|
||||||
a.href = url
|
})
|
||||||
a.download = this.document.title
|
if (
|
||||||
a.click()
|
!this.deviceDetectorService.isDesktop() &&
|
||||||
URL.revokeObjectURL(url)
|
navigator.canShare &&
|
||||||
}
|
navigator.canShare({ files: [file] })
|
||||||
},
|
) {
|
||||||
error: (error) => {
|
navigator.share({
|
||||||
this.downloading = false
|
files: [file],
|
||||||
this.toastService.showError(
|
})
|
||||||
$localize`Error downloading document`,
|
} else {
|
||||||
error
|
const url = URL.createObjectURL(blob)
|
||||||
)
|
const a = document.createElement('a')
|
||||||
},
|
a.href = url
|
||||||
})
|
a.download = filename
|
||||||
|
a.click()
|
||||||
|
URL.revokeObjectURL(url)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
error: (error) => {
|
||||||
|
this.downloading = false
|
||||||
|
this.toastService.showError(
|
||||||
|
$localize`Error downloading document`,
|
||||||
|
error
|
||||||
|
)
|
||||||
|
},
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
hasNext() {
|
hasNext() {
|
||||||
|
@ -5,7 +5,7 @@ export const environment = {
|
|||||||
apiBaseUrl: document.baseURI + 'api/',
|
apiBaseUrl: document.baseURI + 'api/',
|
||||||
apiVersion: '7',
|
apiVersion: '7',
|
||||||
appTitle: 'Paperless-ngx',
|
appTitle: 'Paperless-ngx',
|
||||||
version: '2.15.0',
|
version: '2.15.1',
|
||||||
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/',
|
||||||
|
@ -556,7 +556,7 @@
|
|||||||
<context context-type="sourcefile">src/app/components/admin/config/config.component.html</context>
|
<context context-type="sourcefile">src/app/components/admin/config/config.component.html</context>
|
||||||
<context context-type="linenumber">2</context>
|
<context context-type="linenumber">2</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
<target state="translated">應用程式設定</target>
|
<target state="translated">系統配置</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="8528041182664173532" datatype="html">
|
<trans-unit id="8528041182664173532" datatype="html">
|
||||||
<source>Global app configuration options which apply to <strong>every</strong> user of this install of Paperless-ngx. Options can also be set using environment variables or the configuration file but the value here will always take precedence.</source>
|
<source>Global app configuration options which apply to <strong>every</strong> user of this install of Paperless-ngx. Options can also be set using environment variables or the configuration file but the value here will always take precedence.</source>
|
||||||
@ -564,7 +564,7 @@
|
|||||||
<context context-type="sourcefile">src/app/components/admin/config/config.component.html</context>
|
<context context-type="sourcefile">src/app/components/admin/config/config.component.html</context>
|
||||||
<context context-type="linenumber">4</context>
|
<context context-type="linenumber">4</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
<target state="translated">全域應用程式設定選項適用於此安裝版本的<strong>每位</strong>使用者。雖然也可以透過環境變數或設定檔來設定,但這裡的設定將始終優先於其他設定。</target>
|
<target state="translated">全域系統配置會套用至該系統的<strong>每一位</strong>使用者。雖然環境變數或設定檔也可以調整相關設定,但此處的設定將優先於他處的設定。</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="7991430199894172363" datatype="html">
|
<trans-unit id="7991430199894172363" datatype="html">
|
||||||
<source>Read the documentation about this setting</source>
|
<source>Read the documentation about this setting</source>
|
||||||
@ -864,7 +864,7 @@
|
|||||||
<context context-type="sourcefile">src/app/components/admin/settings/settings.component.html</context>
|
<context context-type="sourcefile">src/app/components/admin/settings/settings.component.html</context>
|
||||||
<context context-type="linenumber">4</context>
|
<context context-type="linenumber">4</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
<target state="translated">自訂外觀、通知等選項。設定只適用於<strong>目前使用者</strong>。</target>
|
<target state="translated">自訂外觀、通知等選項。這些設定只套用於<strong>目前的使用者</strong>。</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="1685061484835793745" datatype="html">
|
<trans-unit id="1685061484835793745" datatype="html">
|
||||||
<source>Start tour</source>
|
<source>Start tour</source>
|
||||||
|
@ -1225,14 +1225,7 @@ def run_workflows(
|
|||||||
document.refresh_from_db()
|
document.refresh_from_db()
|
||||||
doc_tag_ids = list(document.tags.values_list("pk", flat=True))
|
doc_tag_ids = list(document.tags.values_list("pk", flat=True))
|
||||||
|
|
||||||
# If a workflow is supplied, we don't need to check if it matches
|
if matching.document_matches_workflow(document, workflow, trigger_type):
|
||||||
matches = (
|
|
||||||
matching.document_matches_workflow(document, workflow, trigger_type)
|
|
||||||
if workflow_to_run is None
|
|
||||||
else True
|
|
||||||
)
|
|
||||||
|
|
||||||
if matches:
|
|
||||||
action: WorkflowAction
|
action: WorkflowAction
|
||||||
for action in workflow.actions.all():
|
for action in workflow.actions.all():
|
||||||
message = f"Applying {action} from {workflow}"
|
message = f"Applying {action} from {workflow}"
|
||||||
|
@ -2376,9 +2376,13 @@ def serve_file(*, doc: Document, use_archive: bool, disposition: str):
|
|||||||
# RFC 5987 addresses this issue
|
# RFC 5987 addresses this issue
|
||||||
# see https://datatracker.ietf.org/doc/html/rfc5987#section-4.2
|
# see https://datatracker.ietf.org/doc/html/rfc5987#section-4.2
|
||||||
# Chromium cannot handle commas in the filename
|
# Chromium cannot handle commas in the filename
|
||||||
filename_normalized = normalize("NFKD", filename.replace(",", "_")).encode(
|
filename_normalized = (
|
||||||
"ascii",
|
normalize("NFKD", filename.replace(",", "_"))
|
||||||
"ignore",
|
.encode(
|
||||||
|
"ascii",
|
||||||
|
"ignore",
|
||||||
|
)
|
||||||
|
.decode("ascii")
|
||||||
)
|
)
|
||||||
filename_encoded = quote(filename)
|
filename_encoded = quote(filename)
|
||||||
content_disposition = (
|
content_disposition = (
|
||||||
|
@ -3,7 +3,7 @@ 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: 2025-03-26 21:04-0700\n"
|
"POT-Creation-Date: 2025-03-26 21:04-0700\n"
|
||||||
"PO-Revision-Date: 2025-04-02 00:33\n"
|
"PO-Revision-Date: 2025-04-09 12:12\n"
|
||||||
"Last-Translator: \n"
|
"Last-Translator: \n"
|
||||||
"Language-Team: French\n"
|
"Language-Team: French\n"
|
||||||
"Language: fr_FR\n"
|
"Language: fr_FR\n"
|
||||||
@ -582,7 +582,7 @@ msgstr "Fichier à consommer"
|
|||||||
|
|
||||||
#: documents/models.py:540
|
#: documents/models.py:540
|
||||||
msgid "Train Classifier"
|
msgid "Train Classifier"
|
||||||
msgstr ""
|
msgstr "Entrainer le classificateur"
|
||||||
|
|
||||||
#: documents/models.py:541
|
#: documents/models.py:541
|
||||||
msgid "Check Sanity"
|
msgid "Check Sanity"
|
||||||
|
@ -3,7 +3,7 @@ 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: 2025-03-26 21:04-0700\n"
|
"POT-Creation-Date: 2025-03-26 21:04-0700\n"
|
||||||
"PO-Revision-Date: 2025-03-29 17:14\n"
|
"PO-Revision-Date: 2025-04-09 21:44\n"
|
||||||
"Last-Translator: \n"
|
"Last-Translator: \n"
|
||||||
"Language-Team: Dutch\n"
|
"Language-Team: Dutch\n"
|
||||||
"Language: nl_NL\n"
|
"Language: nl_NL\n"
|
||||||
@ -23,7 +23,7 @@ msgstr "Documenten"
|
|||||||
|
|
||||||
#: documents/filters.py:374
|
#: documents/filters.py:374
|
||||||
msgid "Value must be valid JSON."
|
msgid "Value must be valid JSON."
|
||||||
msgstr ""
|
msgstr "Waarde moet een geldige JSON zijn."
|
||||||
|
|
||||||
#: documents/filters.py:393
|
#: documents/filters.py:393
|
||||||
msgid "Invalid custom field query expression"
|
msgid "Invalid custom field query expression"
|
||||||
@ -766,7 +766,7 @@ msgstr "aangepaste velden"
|
|||||||
|
|
||||||
#: documents/models.py:766
|
#: documents/models.py:766
|
||||||
msgid "custom fields"
|
msgid "custom fields"
|
||||||
msgstr "Aangepaste velden"
|
msgstr "aangepaste velden"
|
||||||
|
|
||||||
#: documents/models.py:863
|
#: documents/models.py:863
|
||||||
msgid "custom field instance"
|
msgid "custom field instance"
|
||||||
|
@ -3,7 +3,7 @@ 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: 2025-03-26 21:04-0700\n"
|
"POT-Creation-Date: 2025-03-26 21:04-0700\n"
|
||||||
"PO-Revision-Date: 2025-03-31 12:13\n"
|
"PO-Revision-Date: 2025-04-09 21:44\n"
|
||||||
"Last-Translator: \n"
|
"Last-Translator: \n"
|
||||||
"Language-Team: Chinese Traditional\n"
|
"Language-Team: Chinese Traditional\n"
|
||||||
"Language: zh_TW\n"
|
"Language: zh_TW\n"
|
||||||
|
@ -565,6 +565,10 @@ if DEBUG:
|
|||||||
# Allow access from the angular development server during debugging
|
# Allow access from the angular development server during debugging
|
||||||
CORS_ALLOWED_ORIGINS.append("http://localhost:4200")
|
CORS_ALLOWED_ORIGINS.append("http://localhost:4200")
|
||||||
|
|
||||||
|
CORS_EXPOSE_HEADERS = [
|
||||||
|
"Content-Disposition",
|
||||||
|
]
|
||||||
|
|
||||||
ALLOWED_HOSTS = __get_list("PAPERLESS_ALLOWED_HOSTS", ["*"])
|
ALLOWED_HOSTS = __get_list("PAPERLESS_ALLOWED_HOSTS", ["*"])
|
||||||
if ALLOWED_HOSTS != ["*"]:
|
if ALLOWED_HOSTS != ["*"]:
|
||||||
# always allow localhost. Necessary e.g. for healthcheck in docker.
|
# always allow localhost. Necessary e.g. for healthcheck in docker.
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
from typing import Final
|
from typing import Final
|
||||||
|
|
||||||
__version__: Final[tuple[int, int, int]] = (2, 15, 0)
|
__version__: Final[tuple[int, int, int]] = (2, 15, 1)
|
||||||
# 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
|
||||||
|
28
uv.lock
generated
28
uv.lock
generated
@ -1,4 +1,5 @@
|
|||||||
version = 1
|
version = 1
|
||||||
|
revision = 1
|
||||||
requires-python = ">=3.10"
|
requires-python = ">=3.10"
|
||||||
resolution-markers = [
|
resolution-markers = [
|
||||||
"sys_platform == 'darwin'",
|
"sys_platform == 'darwin'",
|
||||||
@ -197,6 +198,15 @@ wheels = [
|
|||||||
{ url = "https://files.pythonhosted.org/packages/af/85/a94e5cfaa0ca449d8f91c3d6f78313ebf919a0dbd55a100c711c6e9655bc/Brotli-1.1.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:832436e59afb93e1836081a20f324cb185836c617659b07b129141a8426973c7", size = 2930206 },
|
{ url = "https://files.pythonhosted.org/packages/af/85/a94e5cfaa0ca449d8f91c3d6f78313ebf919a0dbd55a100c711c6e9655bc/Brotli-1.1.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:832436e59afb93e1836081a20f324cb185836c617659b07b129141a8426973c7", size = 2930206 },
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cached-property"
|
||||||
|
version = "2.0.1"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/76/4b/3d870836119dbe9a5e3c9a61af8cc1a8b69d75aea564572e385882d5aefb/cached_property-2.0.1.tar.gz", hash = "sha256:484d617105e3ee0e4f1f58725e72a8ef9e93deee462222dbd51cd91230897641", size = 10574 }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/11/0e/7d8225aab3bc1a0f5811f8e1b557aa034ac04bdf641925b30d3caf586b28/cached_property-2.0.1-py3-none-any.whl", hash = "sha256:f617d70ab1100b7bcf6e42228f9ddcb78c676ffa167278d9f730d1c2fba69ccb", size = 7428 },
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "celery"
|
name = "celery"
|
||||||
version = "5.4.0"
|
version = "5.4.0"
|
||||||
@ -1856,7 +1866,7 @@ wheels = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "paperless-ngx"
|
name = "paperless-ngx"
|
||||||
version = "2.15.0"
|
version = "2.15.1"
|
||||||
source = { virtual = "." }
|
source = { virtual = "." }
|
||||||
dependencies = [
|
dependencies = [
|
||||||
{ name = "bleach", marker = "sys_platform == 'darwin' or sys_platform == 'linux'" },
|
{ name = "bleach", marker = "sys_platform == 'darwin' or sys_platform == 'linux'" },
|
||||||
@ -1907,7 +1917,7 @@ dependencies = [
|
|||||||
{ name = "tqdm", marker = "sys_platform == 'darwin' or sys_platform == 'linux'" },
|
{ name = "tqdm", marker = "sys_platform == 'darwin' or sys_platform == 'linux'" },
|
||||||
{ name = "watchdog", marker = "sys_platform == 'darwin' or sys_platform == 'linux'" },
|
{ name = "watchdog", marker = "sys_platform == 'darwin' or sys_platform == 'linux'" },
|
||||||
{ name = "whitenoise", marker = "sys_platform == 'darwin' or sys_platform == 'linux'" },
|
{ name = "whitenoise", marker = "sys_platform == 'darwin' or sys_platform == 'linux'" },
|
||||||
{ name = "whoosh", marker = "sys_platform == 'darwin' or sys_platform == 'linux'" },
|
{ name = "whoosh-reloaded", marker = "sys_platform == 'darwin' or sys_platform == 'linux'" },
|
||||||
{ name = "zxing-cpp", version = "2.3.0", source = { registry = "https://pypi.org/simple" }, marker = "(python_full_version != '3.12.*' and platform_machine == 'aarch64' and sys_platform == 'linux') or (python_full_version != '3.12.*' and platform_machine == 'x86_64' and sys_platform == 'linux') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and sys_platform == 'linux') or sys_platform == 'darwin'" },
|
{ name = "zxing-cpp", version = "2.3.0", source = { registry = "https://pypi.org/simple" }, marker = "(python_full_version != '3.12.*' and platform_machine == 'aarch64' and sys_platform == 'linux') or (python_full_version != '3.12.*' and platform_machine == 'x86_64' and sys_platform == 'linux') or (platform_machine != 'aarch64' and platform_machine != 'x86_64' and sys_platform == 'linux') or sys_platform == 'darwin'" },
|
||||||
{ name = "zxing-cpp", version = "2.3.0", source = { url = "https://github.com/paperless-ngx/builder/releases/download/zxing-2.3.0/zxing_cpp-2.3.0-cp312-cp312-linux_aarch64.whl" }, marker = "python_full_version == '3.12.*' and platform_machine == 'aarch64' and sys_platform == 'linux'" },
|
{ name = "zxing-cpp", version = "2.3.0", source = { url = "https://github.com/paperless-ngx/builder/releases/download/zxing-2.3.0/zxing_cpp-2.3.0-cp312-cp312-linux_aarch64.whl" }, marker = "python_full_version == '3.12.*' and platform_machine == 'aarch64' and sys_platform == 'linux'" },
|
||||||
{ name = "zxing-cpp", version = "2.3.0", source = { url = "https://github.com/paperless-ngx/builder/releases/download/zxing-2.3.0/zxing_cpp-2.3.0-cp312-cp312-linux_x86_64.whl" }, marker = "python_full_version == '3.12.*' and platform_machine == 'x86_64' and sys_platform == 'linux'" },
|
{ name = "zxing-cpp", version = "2.3.0", source = { url = "https://github.com/paperless-ngx/builder/releases/download/zxing-2.3.0/zxing_cpp-2.3.0-cp312-cp312-linux_x86_64.whl" }, marker = "python_full_version == '3.12.*' and platform_machine == 'x86_64' and sys_platform == 'linux'" },
|
||||||
@ -2043,11 +2053,12 @@ requires-dist = [
|
|||||||
{ name = "tqdm", specifier = "~=4.67.1" },
|
{ name = "tqdm", specifier = "~=4.67.1" },
|
||||||
{ name = "watchdog", specifier = "~=6.0" },
|
{ name = "watchdog", specifier = "~=6.0" },
|
||||||
{ name = "whitenoise", specifier = "~=6.9" },
|
{ name = "whitenoise", specifier = "~=6.9" },
|
||||||
{ name = "whoosh", specifier = "~=2.7" },
|
{ name = "whoosh-reloaded", specifier = ">=2.7.5" },
|
||||||
{ name = "zxing-cpp", marker = "(python_full_version != '3.12.*' and platform_machine == 'aarch64') or (python_full_version != '3.12.*' and platform_machine == 'x86_64') or (platform_machine != 'aarch64' and platform_machine != 'x86_64') or sys_platform != 'linux'", specifier = "~=2.3.0" },
|
{ name = "zxing-cpp", marker = "(python_full_version != '3.12.*' and platform_machine == 'aarch64') or (python_full_version != '3.12.*' and platform_machine == 'x86_64') or (platform_machine != 'aarch64' and platform_machine != 'x86_64') or sys_platform != 'linux'", specifier = "~=2.3.0" },
|
||||||
{ name = "zxing-cpp", marker = "python_full_version == '3.12.*' and platform_machine == 'aarch64' and sys_platform == 'linux'", url = "https://github.com/paperless-ngx/builder/releases/download/zxing-2.3.0/zxing_cpp-2.3.0-cp312-cp312-linux_aarch64.whl" },
|
{ name = "zxing-cpp", marker = "python_full_version == '3.12.*' and platform_machine == 'aarch64' and sys_platform == 'linux'", url = "https://github.com/paperless-ngx/builder/releases/download/zxing-2.3.0/zxing_cpp-2.3.0-cp312-cp312-linux_aarch64.whl" },
|
||||||
{ name = "zxing-cpp", marker = "python_full_version == '3.12.*' and platform_machine == 'x86_64' and sys_platform == 'linux'", url = "https://github.com/paperless-ngx/builder/releases/download/zxing-2.3.0/zxing_cpp-2.3.0-cp312-cp312-linux_x86_64.whl" },
|
{ name = "zxing-cpp", marker = "python_full_version == '3.12.*' and platform_machine == 'x86_64' and sys_platform == 'linux'", url = "https://github.com/paperless-ngx/builder/releases/download/zxing-2.3.0/zxing_cpp-2.3.0-cp312-cp312-linux_x86_64.whl" },
|
||||||
]
|
]
|
||||||
|
provides-extras = ["mariadb", "postgres", "webserver"]
|
||||||
|
|
||||||
[package.metadata.requires-dev]
|
[package.metadata.requires-dev]
|
||||||
dev = [
|
dev = [
|
||||||
@ -3708,12 +3719,15 @@ wheels = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "whoosh"
|
name = "whoosh-reloaded"
|
||||||
version = "2.7.4"
|
version = "2.7.5"
|
||||||
source = { registry = "https://pypi.org/simple" }
|
source = { registry = "https://pypi.org/simple" }
|
||||||
sdist = { url = "https://files.pythonhosted.org/packages/25/2b/6beed2107b148edc1321da0d489afc4617b9ed317ef7b72d4993cad9b684/Whoosh-2.7.4.tar.gz", hash = "sha256:7ca5633dbfa9e0e0fa400d3151a8a0c4bec53bd2ecedc0a67705b17565c31a83", size = 968741 }
|
dependencies = [
|
||||||
|
{ name = "cached-property", marker = "sys_platform == 'darwin' or sys_platform == 'linux'" },
|
||||||
|
]
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/17/51/3fb4b9fdeaaf96512514ccf2871186333ce41a0de2ea48236a4056a5f6af/Whoosh-Reloaded-2.7.5.tar.gz", hash = "sha256:39ed7dfbd1fec97af33933107bdf78110728375ed0f2abb25dec6dbfdcb279d8", size = 1061606 }
|
||||||
wheels = [
|
wheels = [
|
||||||
{ url = "https://files.pythonhosted.org/packages/ba/19/24d0f1f454a2c1eb689ca28d2f178db81e5024f42d82729a4ff6771155cf/Whoosh-2.7.4-py2.py3-none-any.whl", hash = "sha256:aa39c3c3426e3fd107dcb4bde64ca1e276a65a889d9085a6e4b54ba82420a852", size = 468790 },
|
{ url = "https://files.pythonhosted.org/packages/69/90/866dfe421f188217ecd7339585e961034a7f4fdc96b62cec3b40a50dbdef/Whoosh_Reloaded-2.7.5-py2.py3-none-any.whl", hash = "sha256:2ab6aeeafb359fbff4beb3c704b960fd88240354f3363f1c5bdb5c2325cae80e", size = 551793 },
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
Loading…
x
Reference in New Issue
Block a user