Compare commits

...

14 Commits

Author SHA1 Message Date
shamoon
d956269d5f
Update faq 2025-04-10 20:25:16 -07:00
github-actions[bot]
f269919410
Documentation: Add v2.15.1 changelog (#9606)
---------

Co-authored-by: github-actions <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: shamoon <4887959+shamoon@users.noreply.github.com>
2025-04-09 15:48:56 -07:00
shamoon
5f00066dff
Manually bump version in uv.lock 2025-04-09 15:48:20 -07:00
Trenton Holmes
705f542129 Bumps the version to 2.15.1 2025-04-09 14:55:02 -07:00
Trenton Holmes
f036292b72 Merge remote-tracking branch 'origin/dev' 2025-04-09 14:53:31 -07:00
Crowdin Bot
f8a43d5dab New Crowdin translations by GitHub Action 2025-04-09 21:44:21 +00:00
dependabot[bot]
53c106d448
docker(deps): Bump astral-sh/uv (#9573)
Bumps [astral-sh/uv](https://github.com/astral-sh/uv) from 0.6.9-python3.12-bookworm-slim to 0.6.13-python3.12-bookworm-slim.
- [Release notes](https://github.com/astral-sh/uv/releases)
- [Changelog](https://github.com/astral-sh/uv/blob/main/CHANGELOG.md)
- [Commits](https://github.com/astral-sh/uv/compare/0.6.9...0.6.13)

---
updated-dependencies:
- dependency-name: astral-sh/uv
  dependency-version: 0.6.13-python3.12-bookworm-slim
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-04-09 21:43:12 +00:00
shamoon
0f37186c88
Chore: use whoosh-reloaded (#9605) 2025-04-09 21:31:29 +00:00
Trenton H
0fb55f3ae8
Fix: Run migration lock as the correct user (#9604) 2025-04-09 21:15:38 +00:00
Trenton H
78822f6121
Fix: Adds a warning to the user if their secret file includes a trailing newline (#9601) 2025-04-09 21:05:26 +00:00
shamoon
2ee1d7540e
Chore: add coverage for frontend download content-disposition parsing 2025-04-09 13:23:40 -07:00
shamoon
43b2527275
Fix: correct download filename in 2.15.0 (#9599)
---------

Co-authored-by: Trenton H <797416+stumpylog@users.noreply.github.com>
2025-04-09 16:03:38 +00:00
Nathanaël Houn
248b573c03
Documentation: update crowdin links (#9595) 2025-04-09 08:01:21 -07:00
shamoon
b9f7428f2f
Fix: include matching check for scheduled workflows (#9594) 2025-04-09 02:12:42 -07:00
22 changed files with 172 additions and 113 deletions

View File

@ -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).

View File

@ -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

View File

@ -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

View File

@ -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##*/}"

View 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

View File

@ -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"

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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",
] ]

View File

@ -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()

View File

@ -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() {

View File

@ -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/',

View File

@ -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 &lt;strong&gt;every&lt;/strong&gt; 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 &lt;strong&gt;every&lt;/strong&gt; 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">全域應用程式設定選項適用於此安裝版本的&lt;strong&gt;每位&lt;/strong&gt;使用者。雖然也可以透過環境變數或設定檔來設定,但這裡的設定將始終優先於其他設定。</target> <target state="translated">全域系統配置會套用至該系統的&lt;strong&gt;每一位&lt;/strong&gt;使用者。雖然環境變數或設定檔也可以調整相關設定,但此處的設定將優先於他處的設定。</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">自訂外觀、通知等選項。設定只適用於&lt;strong&gt;目前使用者&lt;/strong&gt;。</target> <target state="translated">自訂外觀、通知等選項。這些設定只套用於&lt;strong&gt;目前的使用者&lt;/strong&gt;。</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>

View File

@ -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}"

View File

@ -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 = (

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -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.

View File

@ -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
View File

@ -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]]