Merge branch 'main' into dev
							
								
								
									
										14
									
								
								docs/api.md
									
									
									
									
									
								
							
							
						
						@ -14,14 +14,15 @@ The API provides 7 main endpoints:
 | 
			
		||||
- `/api/document_types/`: Full CRUD support.
 | 
			
		||||
- `/api/logs/`: Read-Only.
 | 
			
		||||
- `/api/tags/`: Full CRUD support.
 | 
			
		||||
- `/api/tasks/`: Read-only.
 | 
			
		||||
- `/api/mail_accounts/`: Full CRUD support.
 | 
			
		||||
- `/api/mail_rules/`: Full CRUD support.
 | 
			
		||||
- `/api/users/`: Full CRUD support.
 | 
			
		||||
- `/api/groups/`: Full CRUD support.
 | 
			
		||||
 | 
			
		||||
All of these endpoints except for the logging endpoint allow you to
 | 
			
		||||
fetch, edit and delete individual objects by appending their primary key
 | 
			
		||||
to the path, for example `/api/documents/454/`.
 | 
			
		||||
fetch (and edit and delete where appropriate) individual objects by
 | 
			
		||||
appending their primary key to the path, e.g. `/api/documents/454/`.
 | 
			
		||||
 | 
			
		||||
The objects served by the document endpoint contain the following
 | 
			
		||||
fields:
 | 
			
		||||
@ -261,10 +262,11 @@ The endpoint supports the following optional form fields:
 | 
			
		||||
 | 
			
		||||
The endpoint will immediately return HTTP 200 if the document consumption
 | 
			
		||||
process was started successfully, with the UUID of the consumption task
 | 
			
		||||
as the data. No additional status information about
 | 
			
		||||
the consumption process itself is available immediately, since that happens in a
 | 
			
		||||
different process. Querying the tasks endpoint with the returned UUID will
 | 
			
		||||
provide information on the state of the consumption.
 | 
			
		||||
as the data. No additional status information about the consumption process
 | 
			
		||||
itself is available immediately, since that happens in a different process.
 | 
			
		||||
However, querying the tasks endpoint with the returned UUID e.g.
 | 
			
		||||
`/api/tasks/?task_id={uuid}` will provide information on the state of the
 | 
			
		||||
consumption including the ID of a created document if consumption succeeded.
 | 
			
		||||
 | 
			
		||||
## API Versioning
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
| 
		 Before Width: | Height: | Size: 661 KiB After Width: | Height: | Size: 740 KiB  | 
| 
		 Before Width: | Height: | Size: 457 KiB After Width: | Height: | Size: 383 KiB  | 
| 
		 Before Width: | Height: | Size: 890 KiB After Width: | Height: | Size: 704 KiB  | 
| 
		 Before Width: | Height: | Size: 462 KiB After Width: | Height: | Size: 474 KiB  | 
| 
		 Before Width: | Height: | Size: 608 KiB After Width: | Height: | Size: 616 KiB  | 
| 
		 Before Width: | Height: | Size: 698 KiB After Width: | Height: | Size: 708 KiB  | 
| 
		 Before Width: | Height: | Size: 706 KiB After Width: | Height: | Size: 705 KiB  | 
| 
		 Before Width: | Height: | Size: 480 KiB After Width: | Height: | Size: 480 KiB  | 
| 
		 Before Width: | Height: | Size: 680 KiB After Width: | Height: | Size: 689 KiB  | 
| 
		 Before Width: | Height: | Size: 686 KiB After Width: | Height: | Size: 685 KiB  | 
| 
		 Before Width: | Height: | Size: 848 KiB After Width: | Height: | Size: 859 KiB  | 
| 
		 Before Width: | Height: | Size: 703 KiB After Width: | Height: | Size: 706 KiB  | 
| 
		 Before Width: | Height: | Size: 388 KiB After Width: | Height: | Size: 393 KiB  | 
| 
		 Before Width: | Height: | Size: 517 KiB After Width: | Height: | Size: 516 KiB  | 
@ -1,5 +1,188 @@
 | 
			
		||||
# Changelog
 | 
			
		||||
 | 
			
		||||
## paperless-ngx 1.14.0
 | 
			
		||||
 | 
			
		||||
### Notable Changes
 | 
			
		||||
 | 
			
		||||
- Feature: multi-user permissions [@shamoon](https://github.com/shamoon) ([#2147](https://github.com/paperless-ngx/paperless-ngx/pull/2147))
 | 
			
		||||
 | 
			
		||||
### Features
 | 
			
		||||
 | 
			
		||||
- Feature: Stronger typing for file consumption [@stumpylog](https://github.com/stumpylog) ([#2744](https://github.com/paperless-ngx/paperless-ngx/pull/2744))
 | 
			
		||||
- Feature: double-click docs [@shamoon](https://github.com/shamoon) ([#2966](https://github.com/paperless-ngx/paperless-ngx/pull/2966))
 | 
			
		||||
- feature: Add support for zxing as barcode scanning lib [@margau](https://github.com/margau) ([#2907](https://github.com/paperless-ngx/paperless-ngx/pull/2907))
 | 
			
		||||
- Feature: Enable images to be released on Quay.io [@stumpylog](https://github.com/stumpylog) ([#2972](https://github.com/paperless-ngx/paperless-ngx/pull/2972))
 | 
			
		||||
- Feature: test mail account [@shamoon](https://github.com/shamoon) ([#2949](https://github.com/paperless-ngx/paperless-ngx/pull/2949))
 | 
			
		||||
- Feature: Capture celery and kombu logs to a file [@stumpylog](https://github.com/stumpylog) ([#2954](https://github.com/paperless-ngx/paperless-ngx/pull/2954))
 | 
			
		||||
- Fix: Resolve Redis connection issues with ACLs [@stumpylog](https://github.com/stumpylog) ([#2939](https://github.com/paperless-ngx/paperless-ngx/pull/2939))
 | 
			
		||||
- Feature: Allow mail account to use access tokens [@stumpylog](https://github.com/stumpylog) ([#2930](https://github.com/paperless-ngx/paperless-ngx/pull/2930))
 | 
			
		||||
- Fix: Consumer polling could overwhelm database [@stumpylog](https://github.com/stumpylog) ([#2922](https://github.com/paperless-ngx/paperless-ngx/pull/2922))
 | 
			
		||||
- Feature: Improved statistics widget [@shamoon](https://github.com/shamoon) ([#2910](https://github.com/paperless-ngx/paperless-ngx/pull/2910))
 | 
			
		||||
- Enhancement: rename comments to notes and improve notes UI [@shamoon](https://github.com/shamoon) ([#2904](https://github.com/paperless-ngx/paperless-ngx/pull/2904))
 | 
			
		||||
- Allow psql client certificate authentication [@Ongy](https://github.com/Ongy) ([#2899](https://github.com/paperless-ngx/paperless-ngx/pull/2899))
 | 
			
		||||
- Enhancement: support filtering multiple correspondents, doctypes \& storage paths [@shamoon](https://github.com/shamoon) ([#2893](https://github.com/paperless-ngx/paperless-ngx/pull/2893))
 | 
			
		||||
- Feature: Change celery serializer to pickle [@stumpylog](https://github.com/stumpylog) ([#2861](https://github.com/paperless-ngx/paperless-ngx/pull/2861))
 | 
			
		||||
- Feature: Allow naming to include owner and original name [@stumpylog](https://github.com/stumpylog) ([#2873](https://github.com/paperless-ngx/paperless-ngx/pull/2873))
 | 
			
		||||
- Feature: Allows filtering email by the TO value(s) as well [@stumpylog](https://github.com/stumpylog) ([#2871](https://github.com/paperless-ngx/paperless-ngx/pull/2871))
 | 
			
		||||
- Feature: owner-aware unique model name constraint [@shamoon](https://github.com/shamoon) ([#2827](https://github.com/paperless-ngx/paperless-ngx/pull/2827))
 | 
			
		||||
- Feature/2396 better mail actions [@jonaswinkler](https://github.com/jonaswinkler) ([#2718](https://github.com/paperless-ngx/paperless-ngx/pull/2718))
 | 
			
		||||
- Feature: Reduce classifier memory usage somewhat during training [@stumpylog](https://github.com/stumpylog) ([#2733](https://github.com/paperless-ngx/paperless-ngx/pull/2733))
 | 
			
		||||
- Feature: Add PAPERLESS_OCR_SKIP_ARCHIVE_FILE config setting [@bdr99](https://github.com/bdr99) ([#2743](https://github.com/paperless-ngx/paperless-ngx/pull/2743))
 | 
			
		||||
- Feature: dynamic document counts in dropdowns [@shamoon](https://github.com/shamoon) ([#2704](https://github.com/paperless-ngx/paperless-ngx/pull/2704))
 | 
			
		||||
- Allow setting the ASN on document upload [@stumpylog](https://github.com/stumpylog) ([#2713](https://github.com/paperless-ngx/paperless-ngx/pull/2713))
 | 
			
		||||
- Feature: Log failed login attempts [@shamoon](https://github.com/shamoon) ([#2359](https://github.com/paperless-ngx/paperless-ngx/pull/2359))
 | 
			
		||||
- Feature: Rename documents when storage path format changes [@stumpylog](https://github.com/stumpylog) ([#2696](https://github.com/paperless-ngx/paperless-ngx/pull/2696))
 | 
			
		||||
- Feature: update error message colors \& show on document failures [@shamoon](https://github.com/shamoon) ([#2689](https://github.com/paperless-ngx/paperless-ngx/pull/2689))
 | 
			
		||||
- Feature: multi-user permissions [@shamoon](https://github.com/shamoon) ([#2147](https://github.com/paperless-ngx/paperless-ngx/pull/2147))
 | 
			
		||||
 | 
			
		||||
### Bug Fixes
 | 
			
		||||
 | 
			
		||||
- Fix: Allow setting additional Django settings for proxies [@stumpylog](https://github.com/stumpylog) ([#3135](https://github.com/paperless-ngx/paperless-ngx/pull/3135))
 | 
			
		||||
- Fix: Use exclude instead of difference for mariadb [@shamoon](https://github.com/shamoon) ([#2983](https://github.com/paperless-ngx/paperless-ngx/pull/2983))
 | 
			
		||||
- Fix: permissions display should not show users with inherited permissions \& unable to change owner [@shamoon](https://github.com/shamoon) ([#2818](https://github.com/paperless-ngx/paperless-ngx/pull/2818))
 | 
			
		||||
- Fix: Resolve Redis connection issues with ACLs [@stumpylog](https://github.com/stumpylog) ([#2939](https://github.com/paperless-ngx/paperless-ngx/pull/2939))
 | 
			
		||||
- Fix: unable to edit correspondents (in ) [@shamoon](https://github.com/shamoon) ([#2938](https://github.com/paperless-ngx/paperless-ngx/pull/2938))
 | 
			
		||||
- Fix: Consumer polling could overwhelm database [@stumpylog](https://github.com/stumpylog) ([#2922](https://github.com/paperless-ngx/paperless-ngx/pull/2922))
 | 
			
		||||
- Fix: Chrome struggles with commas [@stumpylog](https://github.com/stumpylog) ([#2892](https://github.com/paperless-ngx/paperless-ngx/pull/2892))
 | 
			
		||||
- Fix formatting in Setup documentation page [@igrybkov](https://github.com/igrybkov) ([#2880](https://github.com/paperless-ngx/paperless-ngx/pull/2880))
 | 
			
		||||
- Fix: logout on change password via frontend [@shamoon](https://github.com/shamoon) ([#2863](https://github.com/paperless-ngx/paperless-ngx/pull/2863))
 | 
			
		||||
- Fix: give superuser full doc perms [@shamoon](https://github.com/shamoon) ([#2820](https://github.com/paperless-ngx/paperless-ngx/pull/2820))
 | 
			
		||||
- Fix: Append Gmail labels instead of replacing [@stumpylog](https://github.com/stumpylog) ([#2860](https://github.com/paperless-ngx/paperless-ngx/pull/2860))
 | 
			
		||||
- Fix: Ensure email date is made aware during action processing [@stumpylog](https://github.com/stumpylog) ([#2837](https://github.com/paperless-ngx/paperless-ngx/pull/2837))
 | 
			
		||||
- Fix: disable bulk edit dialog buttons during operation [@shamoon](https://github.com/shamoon) ([#2819](https://github.com/paperless-ngx/paperless-ngx/pull/2819))
 | 
			
		||||
- fix database locked error [@jonaswinkler](https://github.com/jonaswinkler) ([#2808](https://github.com/paperless-ngx/paperless-ngx/pull/2808))
 | 
			
		||||
- Fix: Disable suggestions for read-only docs [@shamoon](https://github.com/shamoon) ([#2813](https://github.com/paperless-ngx/paperless-ngx/pull/2813))
 | 
			
		||||
- Update processed mail migration [@shamoon](https://github.com/shamoon) ([#2804](https://github.com/paperless-ngx/paperless-ngx/pull/2804))
 | 
			
		||||
- Fix: Ensure scratch directory exists before using [@stumpylog](https://github.com/stumpylog) ([#2775](https://github.com/paperless-ngx/paperless-ngx/pull/2775))
 | 
			
		||||
- Don't submit owner via API on document upload [@jonaswinkler](https://github.com/jonaswinkler) ([#2777](https://github.com/paperless-ngx/paperless-ngx/pull/2777))
 | 
			
		||||
- Fix: only offer log files that exist [@shamoon](https://github.com/shamoon) ([#2739](https://github.com/paperless-ngx/paperless-ngx/pull/2739))
 | 
			
		||||
- Fix: permissions editing and initial view issues [@shamoon](https://github.com/shamoon) ([#2717](https://github.com/paperless-ngx/paperless-ngx/pull/2717))
 | 
			
		||||
- Fix: reset saved view ID on quickFilter [@shamoon](https://github.com/shamoon) ([#2703](https://github.com/paperless-ngx/paperless-ngx/pull/2703))
 | 
			
		||||
- Fix: bulk edit reset apply button state [@shamoon](https://github.com/shamoon) ([#2701](https://github.com/paperless-ngx/paperless-ngx/pull/2701))
 | 
			
		||||
- Fix: add missing i18n for mobile preview tab title [@nathanaelhoun](https://github.com/nathanaelhoun) ([#2692](https://github.com/paperless-ngx/paperless-ngx/pull/2692))
 | 
			
		||||
 | 
			
		||||
### Documentation
 | 
			
		||||
 | 
			
		||||
- Whitespace changes, making sure the example is correcly aligned [@denilsonsa](https://github.com/denilsonsa) ([#3089](https://github.com/paperless-ngx/paperless-ngx/pull/3089))
 | 
			
		||||
- Docs: Include additional information about barcodes [@stumpylog](https://github.com/stumpylog) ([#2889](https://github.com/paperless-ngx/paperless-ngx/pull/2889))
 | 
			
		||||
- Fix formatting in Setup documentation page [@igrybkov](https://github.com/igrybkov) ([#2880](https://github.com/paperless-ngx/paperless-ngx/pull/2880))
 | 
			
		||||
- [Documentation] Update docker-compose steps to support podman [@white-gecko](https://github.com/white-gecko) ([#2855](https://github.com/paperless-ngx/paperless-ngx/pull/2855))
 | 
			
		||||
- docs: better language code help [@tooomm](https://github.com/tooomm) ([#2830](https://github.com/paperless-ngx/paperless-ngx/pull/2830))
 | 
			
		||||
- Feature: Add an option to disable matching [@bdr99](https://github.com/bdr99) ([#2727](https://github.com/paperless-ngx/paperless-ngx/pull/2727))
 | 
			
		||||
- Docs: Remove outdated PAPERLESS_WORKER_RETRY [@shamoon](https://github.com/shamoon) ([#2694](https://github.com/paperless-ngx/paperless-ngx/pull/2694))
 | 
			
		||||
- Fix: add missing i18n for mobile preview tab title [@nathanaelhoun](https://github.com/nathanaelhoun) ([#2692](https://github.com/paperless-ngx/paperless-ngx/pull/2692))
 | 
			
		||||
 | 
			
		||||
### Maintenance
 | 
			
		||||
 | 
			
		||||
- Chore: Configure ruff as the primary linter for Python [@stumpylog](https://github.com/stumpylog) ([#2988](https://github.com/paperless-ngx/paperless-ngx/pull/2988))
 | 
			
		||||
- Feature: Enable images to be released on Quay.io [@stumpylog](https://github.com/stumpylog) ([#2972](https://github.com/paperless-ngx/paperless-ngx/pull/2972))
 | 
			
		||||
- Chore: Updates locked pipenv to latest version [@stumpylog](https://github.com/stumpylog) ([#2943](https://github.com/paperless-ngx/paperless-ngx/pull/2943))
 | 
			
		||||
- Chore: Properly collapse section in releases [@tooomm](https://github.com/tooomm) ([#2838](https://github.com/paperless-ngx/paperless-ngx/pull/2838))
 | 
			
		||||
- Chore: Don't include changelog PR for different releases [@tooomm](https://github.com/tooomm) ([#2832](https://github.com/paperless-ngx/paperless-ngx/pull/2832))
 | 
			
		||||
- Chore: Speed up frontend CI testing [@stumpylog](https://github.com/stumpylog) ([#2796](https://github.com/paperless-ngx/paperless-ngx/pull/2796))
 | 
			
		||||
- Bump leonsteinhaeuser/project-beta-automations from 2.0.1 to 2.1.0 [@dependabot](https://github.com/dependabot) ([#2789](https://github.com/paperless-ngx/paperless-ngx/pull/2789))
 | 
			
		||||
 | 
			
		||||
### Dependencies
 | 
			
		||||
 | 
			
		||||
<details>
 | 
			
		||||
<summary>15 changes</summary>
 | 
			
		||||
 | 
			
		||||
- Bump ng2-pdf-viewer from 9.1.4 to 9.1.5 in /src-ui [@dependabot](https://github.com/dependabot) ([#3109](https://github.com/paperless-ngx/paperless-ngx/pull/3109))
 | 
			
		||||
- Grouped bump angular packages from 15.2.6 to 15.2.7 in /src-ui [@dependabot](https://github.com/dependabot) ([#3108](https://github.com/paperless-ngx/paperless-ngx/pull/3108))
 | 
			
		||||
- Bump typescript from 4.8.4 to 4.9.5 in /src-ui [@dependabot](https://github.com/dependabot) ([#3071](https://github.com/paperless-ngx/paperless-ngx/pull/3071))
 | 
			
		||||
- Bulk Bump npm packages 04.23 [@dependabot](https://github.com/dependabot) ([#3068](https://github.com/paperless-ngx/paperless-ngx/pull/3068))
 | 
			
		||||
- Bump wait-on from 6.0.1 to 7.0.1 in /src-ui [@dependabot](https://github.com/dependabot) ([#2990](https://github.com/paperless-ngx/paperless-ngx/pull/2990))
 | 
			
		||||
- Bulk bump angular packages to 15.2.5 in /src-ui [@dependabot](https://github.com/dependabot) ([#2991](https://github.com/paperless-ngx/paperless-ngx/pull/2991))
 | 
			
		||||
- Bump [@<!---->types/node from 18.11.18 to 18.15.11 in /src-ui @dependabot](https://github.com/<!---->types/node from 18.11.18 to 18.15.11 in /src-ui @dependabot) ([#2993](https://github.com/paperless-ngx/paperless-ngx/pull/2993))
 | 
			
		||||
- Bump [@<!---->ng-select/ng-select from 10.0.3 to 10.0.4 in /src-ui @dependabot](https://github.com/<!---->ng-select/ng-select from 10.0.3 to 10.0.4 in /src-ui @dependabot) ([#2992](https://github.com/paperless-ngx/paperless-ngx/pull/2992))
 | 
			
		||||
- Bump [@<!---->typescript-eslint/eslint-plugin from 5.50.0 to 5.57.0 in /src-ui @dependabot](https://github.com/<!---->typescript-eslint/eslint-plugin from 5.50.0 to 5.57.0 in /src-ui @dependabot) ([#2989](https://github.com/paperless-ngx/paperless-ngx/pull/2989))
 | 
			
		||||
- Chore: Update cryptography to latest version [@stumpylog](https://github.com/stumpylog) ([#2891](https://github.com/paperless-ngx/paperless-ngx/pull/2891))
 | 
			
		||||
- Chore: Update to qpdf 11.3.0 in Docker image [@stumpylog](https://github.com/stumpylog) ([#2862](https://github.com/paperless-ngx/paperless-ngx/pull/2862))
 | 
			
		||||
- Bump leonsteinhaeuser/project-beta-automations from 2.0.1 to 2.1.0 [@dependabot](https://github.com/dependabot) ([#2789](https://github.com/paperless-ngx/paperless-ngx/pull/2789))
 | 
			
		||||
- Bump zone.js from 0.11.8 to 0.12.0 in /src-ui [@dependabot](https://github.com/dependabot) ([#2793](https://github.com/paperless-ngx/paperless-ngx/pull/2793))
 | 
			
		||||
- Bump [@<!---->typescript-eslint/parser from 5.50.0 to 5.54.0 in /src-ui @dependabot](https://github.com/<!---->typescript-eslint/parser from 5.50.0 to 5.54.0 in /src-ui @dependabot) ([#2792](https://github.com/paperless-ngx/paperless-ngx/pull/2792))
 | 
			
		||||
- Bulk Bump angular packages to 15.2.1 in /src-ui [@dependabot](https://github.com/dependabot) ([#2788](https://github.com/paperless-ngx/paperless-ngx/pull/2788))
 | 
			
		||||
</details>
 | 
			
		||||
 | 
			
		||||
### All App Changes
 | 
			
		||||
 | 
			
		||||
<details>
 | 
			
		||||
<summary>72 changes</summary>
 | 
			
		||||
 | 
			
		||||
- Feature: Catalan translation [@shamoon](https://github.com/shamoon) ([#3146](https://github.com/paperless-ngx/paperless-ngx/pull/3146))
 | 
			
		||||
- Fix: Allow setting additional Django settings for proxies [@stumpylog](https://github.com/stumpylog) ([#3135](https://github.com/paperless-ngx/paperless-ngx/pull/3135))
 | 
			
		||||
- Fix: Increase mail account password field length [@stumpylog](https://github.com/stumpylog) ([#3134](https://github.com/paperless-ngx/paperless-ngx/pull/3134))
 | 
			
		||||
- Fix: respect permissions for matching suggestions [@shamoon](https://github.com/shamoon) ([#3103](https://github.com/paperless-ngx/paperless-ngx/pull/3103))
 | 
			
		||||
- Bump ng2-pdf-viewer from 9.1.4 to 9.1.5 in /src-ui [@dependabot](https://github.com/dependabot) ([#3109](https://github.com/paperless-ngx/paperless-ngx/pull/3109))
 | 
			
		||||
- Grouped bump angular packages from 15.2.6 to 15.2.7 in /src-ui [@dependabot](https://github.com/dependabot) ([#3108](https://github.com/paperless-ngx/paperless-ngx/pull/3108))
 | 
			
		||||
- Fix: update PaperlessTask on hard failures [@shamoon](https://github.com/shamoon) ([#3062](https://github.com/paperless-ngx/paperless-ngx/pull/3062))
 | 
			
		||||
- Bump typescript from 4.8.4 to 4.9.5 in /src-ui [@dependabot](https://github.com/dependabot) ([#3071](https://github.com/paperless-ngx/paperless-ngx/pull/3071))
 | 
			
		||||
- Bulk Bump npm packages 04.23 [@dependabot](https://github.com/dependabot) ([#3068](https://github.com/paperless-ngx/paperless-ngx/pull/3068))
 | 
			
		||||
- Fix: Hide UI tour steps if user doesnt have permissions [@shamoon](https://github.com/shamoon) ([#3060](https://github.com/paperless-ngx/paperless-ngx/pull/3060))
 | 
			
		||||
- Fix: Hide Permissions tab if user cannot view users [@shamoon](https://github.com/shamoon) ([#3061](https://github.com/paperless-ngx/paperless-ngx/pull/3061))
 | 
			
		||||
- v1.14.0 delete document fixes [@shamoon](https://github.com/shamoon) ([#3020](https://github.com/paperless-ngx/paperless-ngx/pull/3020))
 | 
			
		||||
- Bump wait-on from 6.0.1 to 7.0.1 in /src-ui [@dependabot](https://github.com/dependabot) ([#2990](https://github.com/paperless-ngx/paperless-ngx/pull/2990))
 | 
			
		||||
- Fix: inline plaintext docs to enforce styling [@shamoon](https://github.com/shamoon) ([#3013](https://github.com/paperless-ngx/paperless-ngx/pull/3013))
 | 
			
		||||
- Chore: Configure ruff as the primary linter for Python [@stumpylog](https://github.com/stumpylog) ([#2988](https://github.com/paperless-ngx/paperless-ngx/pull/2988))
 | 
			
		||||
- Bulk bump angular packages to 15.2.5 in /src-ui [@dependabot](https://github.com/dependabot) ([#2991](https://github.com/paperless-ngx/paperless-ngx/pull/2991))
 | 
			
		||||
- Bump [@<!---->types/node from 18.11.18 to 18.15.11 in /src-ui @dependabot](https://github.com/<!---->types/node from 18.11.18 to 18.15.11 in /src-ui @dependabot) ([#2993](https://github.com/paperless-ngx/paperless-ngx/pull/2993))
 | 
			
		||||
- Bump [@<!---->ng-select/ng-select from 10.0.3 to 10.0.4 in /src-ui @dependabot](https://github.com/<!---->ng-select/ng-select from 10.0.3 to 10.0.4 in /src-ui @dependabot) ([#2992](https://github.com/paperless-ngx/paperless-ngx/pull/2992))
 | 
			
		||||
- Bump [@<!---->typescript-eslint/eslint-plugin from 5.50.0 to 5.57.0 in /src-ui @dependabot](https://github.com/<!---->typescript-eslint/eslint-plugin from 5.50.0 to 5.57.0 in /src-ui @dependabot) ([#2989](https://github.com/paperless-ngx/paperless-ngx/pull/2989))
 | 
			
		||||
- Feature: Stronger typing for file consumption [@stumpylog](https://github.com/stumpylog) ([#2744](https://github.com/paperless-ngx/paperless-ngx/pull/2744))
 | 
			
		||||
- Fix: Use exclude instead of difference for mariadb [@shamoon](https://github.com/shamoon) ([#2983](https://github.com/paperless-ngx/paperless-ngx/pull/2983))
 | 
			
		||||
- Fix: permissions display should not show users with inherited permissions \& unable to change owner [@shamoon](https://github.com/shamoon) ([#2818](https://github.com/paperless-ngx/paperless-ngx/pull/2818))
 | 
			
		||||
- Feature: double-click docs [@shamoon](https://github.com/shamoon) ([#2966](https://github.com/paperless-ngx/paperless-ngx/pull/2966))
 | 
			
		||||
- feature: Add support for zxing as barcode scanning lib [@margau](https://github.com/margau) ([#2907](https://github.com/paperless-ngx/paperless-ngx/pull/2907))
 | 
			
		||||
- Feature: test mail account [@shamoon](https://github.com/shamoon) ([#2949](https://github.com/paperless-ngx/paperless-ngx/pull/2949))
 | 
			
		||||
- Feature: Capture celery and kombu logs to a file [@stumpylog](https://github.com/stumpylog) ([#2954](https://github.com/paperless-ngx/paperless-ngx/pull/2954))
 | 
			
		||||
- Fix: Resolve Redis connection issues with ACLs [@stumpylog](https://github.com/stumpylog) ([#2939](https://github.com/paperless-ngx/paperless-ngx/pull/2939))
 | 
			
		||||
- Feature: Allow mail account to use access tokens [@stumpylog](https://github.com/stumpylog) ([#2930](https://github.com/paperless-ngx/paperless-ngx/pull/2930))
 | 
			
		||||
- Fix: Consumer polling could overwhelm database [@stumpylog](https://github.com/stumpylog) ([#2922](https://github.com/paperless-ngx/paperless-ngx/pull/2922))
 | 
			
		||||
- Feature: Improved statistics widget [@shamoon](https://github.com/shamoon) ([#2910](https://github.com/paperless-ngx/paperless-ngx/pull/2910))
 | 
			
		||||
- Enhancement: rename comments to notes and improve notes UI [@shamoon](https://github.com/shamoon) ([#2904](https://github.com/paperless-ngx/paperless-ngx/pull/2904))
 | 
			
		||||
- Allow psql client certificate authentication [@Ongy](https://github.com/Ongy) ([#2899](https://github.com/paperless-ngx/paperless-ngx/pull/2899))
 | 
			
		||||
- Enhancement: support filtering multiple correspondents, doctypes \& storage paths [@shamoon](https://github.com/shamoon) ([#2893](https://github.com/paperless-ngx/paperless-ngx/pull/2893))
 | 
			
		||||
- Fix: frontend handle private tags, doctypes, correspondents [@shamoon](https://github.com/shamoon) ([#2839](https://github.com/paperless-ngx/paperless-ngx/pull/2839))
 | 
			
		||||
- Fix: Chrome struggles with commas [@stumpylog](https://github.com/stumpylog) ([#2892](https://github.com/paperless-ngx/paperless-ngx/pull/2892))
 | 
			
		||||
- Feature: Change celery serializer to pickle [@stumpylog](https://github.com/stumpylog) ([#2861](https://github.com/paperless-ngx/paperless-ngx/pull/2861))
 | 
			
		||||
- Feature: Allow naming to include owner and original name [@stumpylog](https://github.com/stumpylog) ([#2873](https://github.com/paperless-ngx/paperless-ngx/pull/2873))
 | 
			
		||||
- Feature: Allows filtering email by the TO value(s) as well [@stumpylog](https://github.com/stumpylog) ([#2871](https://github.com/paperless-ngx/paperless-ngx/pull/2871))
 | 
			
		||||
- Fix: logout on change password via frontend [@shamoon](https://github.com/shamoon) ([#2863](https://github.com/paperless-ngx/paperless-ngx/pull/2863))
 | 
			
		||||
- Fix: give superuser full doc perms [@shamoon](https://github.com/shamoon) ([#2820](https://github.com/paperless-ngx/paperless-ngx/pull/2820))
 | 
			
		||||
- Fix: Append Gmail labels instead of replacing [@stumpylog](https://github.com/stumpylog) ([#2860](https://github.com/paperless-ngx/paperless-ngx/pull/2860))
 | 
			
		||||
- Feature: owner-aware unique model name constraint [@shamoon](https://github.com/shamoon) ([#2827](https://github.com/paperless-ngx/paperless-ngx/pull/2827))
 | 
			
		||||
- Chore: Create list parsing utility for settings [@stumpylog](https://github.com/stumpylog) ([#2816](https://github.com/paperless-ngx/paperless-ngx/pull/2816))
 | 
			
		||||
- Fix: Ensure email date is made aware during action processing [@stumpylog](https://github.com/stumpylog) ([#2837](https://github.com/paperless-ngx/paperless-ngx/pull/2837))
 | 
			
		||||
- Chore: Convert more code to pathlib [@stumpylog](https://github.com/stumpylog) ([#2817](https://github.com/paperless-ngx/paperless-ngx/pull/2817))
 | 
			
		||||
- Fix: disable bulk edit dialog buttons during operation [@shamoon](https://github.com/shamoon) ([#2819](https://github.com/paperless-ngx/paperless-ngx/pull/2819))
 | 
			
		||||
- fix database locked error [@jonaswinkler](https://github.com/jonaswinkler) ([#2808](https://github.com/paperless-ngx/paperless-ngx/pull/2808))
 | 
			
		||||
- Fix: Disable suggestions for read-only docs [@shamoon](https://github.com/shamoon) ([#2813](https://github.com/paperless-ngx/paperless-ngx/pull/2813))
 | 
			
		||||
- update django.po messages [@jonaswinkler](https://github.com/jonaswinkler) ([#2806](https://github.com/paperless-ngx/paperless-ngx/pull/2806))
 | 
			
		||||
- Update processed mail migration [@shamoon](https://github.com/shamoon) ([#2804](https://github.com/paperless-ngx/paperless-ngx/pull/2804))
 | 
			
		||||
- Feature/2396 better mail actions [@jonaswinkler](https://github.com/jonaswinkler) ([#2718](https://github.com/paperless-ngx/paperless-ngx/pull/2718))
 | 
			
		||||
- Bump zone.js from 0.11.8 to 0.12.0 in /src-ui [@dependabot](https://github.com/dependabot) ([#2793](https://github.com/paperless-ngx/paperless-ngx/pull/2793))
 | 
			
		||||
- Bump [@<!---->typescript-eslint/parser from 5.50.0 to 5.54.0 in /src-ui @dependabot](https://github.com/<!---->typescript-eslint/parser from 5.50.0 to 5.54.0 in /src-ui @dependabot) ([#2792](https://github.com/paperless-ngx/paperless-ngx/pull/2792))
 | 
			
		||||
- Bulk Bump angular packages to 15.2.1 in /src-ui [@dependabot](https://github.com/dependabot) ([#2788](https://github.com/paperless-ngx/paperless-ngx/pull/2788))
 | 
			
		||||
- Fix: Ensure scratch directory exists before using [@stumpylog](https://github.com/stumpylog) ([#2775](https://github.com/paperless-ngx/paperless-ngx/pull/2775))
 | 
			
		||||
- Don't submit owner via API on document upload [@jonaswinkler](https://github.com/jonaswinkler) ([#2777](https://github.com/paperless-ngx/paperless-ngx/pull/2777))
 | 
			
		||||
- Feature: Reduce classifier memory usage somewhat during training [@stumpylog](https://github.com/stumpylog) ([#2733](https://github.com/paperless-ngx/paperless-ngx/pull/2733))
 | 
			
		||||
- Chore: Setup for mypy typing checks [@stumpylog](https://github.com/stumpylog) ([#2742](https://github.com/paperless-ngx/paperless-ngx/pull/2742))
 | 
			
		||||
- Feature: Add PAPERLESS_OCR_SKIP_ARCHIVE_FILE config setting [@bdr99](https://github.com/bdr99) ([#2743](https://github.com/paperless-ngx/paperless-ngx/pull/2743))
 | 
			
		||||
- Fix: only offer log files that exist [@shamoon](https://github.com/shamoon) ([#2739](https://github.com/paperless-ngx/paperless-ngx/pull/2739))
 | 
			
		||||
- Feature: dynamic document counts in dropdowns [@shamoon](https://github.com/shamoon) ([#2704](https://github.com/paperless-ngx/paperless-ngx/pull/2704))
 | 
			
		||||
- Fix: permissions editing and initial view issues [@shamoon](https://github.com/shamoon) ([#2717](https://github.com/paperless-ngx/paperless-ngx/pull/2717))
 | 
			
		||||
- Fix: reset saved view ID on quickFilter [@shamoon](https://github.com/shamoon) ([#2703](https://github.com/paperless-ngx/paperless-ngx/pull/2703))
 | 
			
		||||
- Feature: Add an option to disable matching [@bdr99](https://github.com/bdr99) ([#2727](https://github.com/paperless-ngx/paperless-ngx/pull/2727))
 | 
			
		||||
- Chore: Improve clarity of some test asserting [@stumpylog](https://github.com/stumpylog) ([#2714](https://github.com/paperless-ngx/paperless-ngx/pull/2714))
 | 
			
		||||
- Allow setting the ASN on document upload [@stumpylog](https://github.com/stumpylog) ([#2713](https://github.com/paperless-ngx/paperless-ngx/pull/2713))
 | 
			
		||||
- Fix: bulk edit reset apply button state [@shamoon](https://github.com/shamoon) ([#2701](https://github.com/paperless-ngx/paperless-ngx/pull/2701))
 | 
			
		||||
- Feature: Log failed login attempts [@shamoon](https://github.com/shamoon) ([#2359](https://github.com/paperless-ngx/paperless-ngx/pull/2359))
 | 
			
		||||
- Feature: Rename documents when storage path format changes [@stumpylog](https://github.com/stumpylog) ([#2696](https://github.com/paperless-ngx/paperless-ngx/pull/2696))
 | 
			
		||||
- Feature: update error message colors \& show on document failures [@shamoon](https://github.com/shamoon) ([#2689](https://github.com/paperless-ngx/paperless-ngx/pull/2689))
 | 
			
		||||
- Feature: multi-user permissions [@shamoon](https://github.com/shamoon) ([#2147](https://github.com/paperless-ngx/paperless-ngx/pull/2147))
 | 
			
		||||
- Fix: add missing i18n for mobile preview tab title [@nathanaelhoun](https://github.com/nathanaelhoun) ([#2692](https://github.com/paperless-ngx/paperless-ngx/pull/2692))
 | 
			
		||||
</details>
 | 
			
		||||
 | 
			
		||||
## paperless-ngx 1.13.0
 | 
			
		||||
 | 
			
		||||
### Features
 | 
			
		||||
 | 
			
		||||
@ -453,6 +453,33 @@ redirect the user back to the SSO application's logout page.
 | 
			
		||||
 | 
			
		||||
    Defaults to None, which disables this feature.
 | 
			
		||||
 | 
			
		||||
`PAPERLESS_USE_X_FORWARD_HOST=<bool>`
 | 
			
		||||
 | 
			
		||||
: Configures the Django setting [USE_X_FORWARDED_HOST](https://docs.djangoproject.com/en/4.2/ref/settings/#use-x-forwarded-host)
 | 
			
		||||
which may be needed for hosting behind a proxy.
 | 
			
		||||
 | 
			
		||||
    Defaults to False
 | 
			
		||||
 | 
			
		||||
`PAPERLESS_USE_X_FORWARD_PORT=<bool>`
 | 
			
		||||
 | 
			
		||||
: Configures the Django setting [USE_X_FORWARDED_PORT](https://docs.djangoproject.com/en/4.2/ref/settings/#use-x-forwarded-port)
 | 
			
		||||
which may be needed for hosting behind a proxy.
 | 
			
		||||
 | 
			
		||||
    Defaults to False
 | 
			
		||||
 | 
			
		||||
`PAPERLESS_PROXY_SSL_HEADER=<json-list>`
 | 
			
		||||
 | 
			
		||||
: Configures the Django setting [SECURE_PROXY_SSL_HEADER](https://docs.djangoproject.com/en/4.2/ref/settings/#secure-proxy-ssl-header)
 | 
			
		||||
which may be needed for hosting behind a proxy. The two values in the list will form the tuple of
 | 
			
		||||
HTTP header/value expected by Django, eg `'["HTTP_X_FORWARDED_PROTO", "https"]'`.
 | 
			
		||||
 | 
			
		||||
    Defaults to None
 | 
			
		||||
 | 
			
		||||
!!! warning
 | 
			
		||||
 | 
			
		||||
    Settings this value has security implications.  Read the Django documentation
 | 
			
		||||
    and be sure you understand its usage before setting it.
 | 
			
		||||
 | 
			
		||||
## OCR settings {#ocr}
 | 
			
		||||
 | 
			
		||||
Paperless uses [OCRmyPDF](https://ocrmypdf.readthedocs.io/en/latest/)
 | 
			
		||||
 | 
			
		||||
@ -169,6 +169,12 @@ steps described in [Docker setup](#docker_hub) automatically.
 | 
			
		||||
    $ docker-compose run --rm webserver createsuperuser
 | 
			
		||||
    ```
 | 
			
		||||
 | 
			
		||||
    or using docker exec from within the container:
 | 
			
		||||
 | 
			
		||||
    ```shell-session
 | 
			
		||||
    $ python3 manage.py createsuperuser
 | 
			
		||||
    ```
 | 
			
		||||
 | 
			
		||||
    This will prompt you to set a username, an optional e-mail address
 | 
			
		||||
    and finally a password (at least 8 characters).
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -56,8 +56,6 @@ describe('settings', () => {
 | 
			
		||||
            'GET',
 | 
			
		||||
            'http://localhost:8000/api/mail_accounts/*',
 | 
			
		||||
            (req) => {
 | 
			
		||||
              console.log(req, this.newMailAccounts)
 | 
			
		||||
 | 
			
		||||
              let response = { ...mailAccountsJson }
 | 
			
		||||
              if (this.newMailAccounts.length) {
 | 
			
		||||
                response.results = response.results.concat(this.newMailAccounts)
 | 
			
		||||
@ -142,7 +140,7 @@ describe('settings', () => {
 | 
			
		||||
    cy.get('app-saved-view-widget').contains('Inbox').should('not.exist')
 | 
			
		||||
  })
 | 
			
		||||
 | 
			
		||||
  it('should show a list of mail accounts & rules & support creation', () => {
 | 
			
		||||
  it('should show a list of mail accounts & support creation', () => {
 | 
			
		||||
    cy.contains('a', 'Mail').click()
 | 
			
		||||
    cy.get('app-settings .tab-content ul li').its('length').should('eq', 5) // 2 headers, 2 accounts, 1 rule
 | 
			
		||||
    cy.contains('button', 'Add Account').click()
 | 
			
		||||
@ -162,6 +160,13 @@ describe('settings', () => {
 | 
			
		||||
      .wait('@getAccounts')
 | 
			
		||||
    cy.contains('Saved account')
 | 
			
		||||
 | 
			
		||||
    cy.get('app-settings .tab-content ul li').its('length').should('eq', 6)
 | 
			
		||||
  })
 | 
			
		||||
 | 
			
		||||
  it('should show a list of mail rules & support creation', () => {
 | 
			
		||||
    cy.contains('a', 'Mail').click()
 | 
			
		||||
    cy.get('app-settings .tab-content ul li').its('length').should('eq', 5) // 2 headers, 2 accounts, 1 rule
 | 
			
		||||
 | 
			
		||||
    cy.wait(1000)
 | 
			
		||||
    cy.contains('button', 'Add Rule').click()
 | 
			
		||||
    cy.contains('Create new mail rule')
 | 
			
		||||
@ -177,6 +182,6 @@ describe('settings', () => {
 | 
			
		||||
      .wait('@getRules')
 | 
			
		||||
    cy.contains('Saved rule').wait(1000)
 | 
			
		||||
 | 
			
		||||
    cy.get('app-settings .tab-content ul li').its('length').should('eq', 7)
 | 
			
		||||
    cy.get('app-settings .tab-content ul li').its('length').should('eq', 6)
 | 
			
		||||
  })
 | 
			
		||||
})
 | 
			
		||||
 | 
			
		||||
@ -155,6 +155,7 @@ export class AppComponent implements OnInit, OnDestroy {
 | 
			
		||||
        content: $localize`Drag-and-drop documents here to start uploading or place them in the consume folder. You can also drag-and-drop documents anywhere on all other pages of the web app. Once you do, Paperless-ngx will start training its machine learning algorithms.`,
 | 
			
		||||
        route: '/dashboard',
 | 
			
		||||
        enableBackdrop: true,
 | 
			
		||||
        isOptional: true,
 | 
			
		||||
        prevBtnTitle,
 | 
			
		||||
        nextBtnTitle,
 | 
			
		||||
        endBtnTitle,
 | 
			
		||||
@ -167,6 +168,7 @@ export class AppComponent implements OnInit, OnDestroy {
 | 
			
		||||
        placement: 'bottom',
 | 
			
		||||
        enableBackdrop: true,
 | 
			
		||||
        disableScrollToAnchor: true,
 | 
			
		||||
        isOptional: true,
 | 
			
		||||
        prevBtnTitle,
 | 
			
		||||
        nextBtnTitle,
 | 
			
		||||
        endBtnTitle,
 | 
			
		||||
@ -177,6 +179,7 @@ export class AppComponent implements OnInit, OnDestroy {
 | 
			
		||||
        route: '/documents?sort=created&reverse=1&page=1',
 | 
			
		||||
        placement: 'bottom',
 | 
			
		||||
        enableBackdrop: true,
 | 
			
		||||
        isOptional: true,
 | 
			
		||||
        prevBtnTitle,
 | 
			
		||||
        nextBtnTitle,
 | 
			
		||||
        endBtnTitle,
 | 
			
		||||
@ -186,6 +189,7 @@ export class AppComponent implements OnInit, OnDestroy {
 | 
			
		||||
        content: $localize`Any combination of filters can be saved as a 'view' which can then be displayed on the dashboard and / or sidebar.`,
 | 
			
		||||
        route: '/documents?sort=created&reverse=1&page=1',
 | 
			
		||||
        enableBackdrop: true,
 | 
			
		||||
        isOptional: true,
 | 
			
		||||
        prevBtnTitle,
 | 
			
		||||
        nextBtnTitle,
 | 
			
		||||
        endBtnTitle,
 | 
			
		||||
@ -195,6 +199,7 @@ export class AppComponent implements OnInit, OnDestroy {
 | 
			
		||||
        content: $localize`Tags, correspondents, document types and storage paths can all be managed using these pages. They can also be created from the document edit view.`,
 | 
			
		||||
        route: '/tags',
 | 
			
		||||
        enableBackdrop: true,
 | 
			
		||||
        isOptional: true,
 | 
			
		||||
        prevBtnTitle,
 | 
			
		||||
        nextBtnTitle,
 | 
			
		||||
        endBtnTitle,
 | 
			
		||||
@ -204,6 +209,7 @@ export class AppComponent implements OnInit, OnDestroy {
 | 
			
		||||
        content: $localize`File Tasks shows you documents that have been consumed, are waiting to be, or may have failed during the process.`,
 | 
			
		||||
        route: '/tasks',
 | 
			
		||||
        enableBackdrop: true,
 | 
			
		||||
        isOptional: true,
 | 
			
		||||
        prevBtnTitle,
 | 
			
		||||
        nextBtnTitle,
 | 
			
		||||
        endBtnTitle,
 | 
			
		||||
@ -213,6 +219,7 @@ export class AppComponent implements OnInit, OnDestroy {
 | 
			
		||||
        content: $localize`Check out the settings for various tweaks to the web app, toggle settings for saved views or setup e-mail checking.`,
 | 
			
		||||
        route: '/settings',
 | 
			
		||||
        enableBackdrop: true,
 | 
			
		||||
        isOptional: true,
 | 
			
		||||
        prevBtnTitle,
 | 
			
		||||
        nextBtnTitle,
 | 
			
		||||
        endBtnTitle,
 | 
			
		||||
 | 
			
		||||
@ -5,7 +5,7 @@
 | 
			
		||||
      <div class="input-group-text" i18n>of {{previewNumPages}}</div>
 | 
			
		||||
    </div>
 | 
			
		||||
 | 
			
		||||
    <button type="button" class="btn btn-sm btn-outline-danger me-2 ms-auto" (click)="delete()" [disabled]="!userIsOwner">
 | 
			
		||||
    <button type="button" class="btn btn-sm btn-outline-danger me-2 ms-auto" (click)="delete()" [disabled]="!userIsOwner" *appIfPermissions="{ action: PermissionAction.Delete, type: PermissionType.Document }">
 | 
			
		||||
        <svg class="buttonicon" fill="currentColor">
 | 
			
		||||
            <use xlink:href="assets/bootstrap-icons.svg#trash" />
 | 
			
		||||
        </svg><span class="d-none d-lg-inline ps-1" i18n>Delete</span>
 | 
			
		||||
@ -178,7 +178,7 @@
 | 
			
		||||
                    </ng-template>
 | 
			
		||||
                </li>
 | 
			
		||||
 | 
			
		||||
                <li [ngbNavItem]="DocumentDetailNavIDs.Permissions" *appIfOwner="document">
 | 
			
		||||
                <li [ngbNavItem]="DocumentDetailNavIDs.Permissions" *ngIf="showPermissions">
 | 
			
		||||
                    <a ngbNavLink i18n>Permissions</a>
 | 
			
		||||
                    <ng-template ngbNavContent>
 | 
			
		||||
                        <div class="mb-3">
 | 
			
		||||
 | 
			
		||||
@ -496,7 +496,7 @@ export class DocumentDetailComponent
 | 
			
		||||
            this.toastService.showError(
 | 
			
		||||
              $localize`Error saving document` +
 | 
			
		||||
                ': ' +
 | 
			
		||||
                (error.message ?? error.toString())
 | 
			
		||||
                (error.error?.detail ?? error.message ?? JSON.stringify(error))
 | 
			
		||||
            )
 | 
			
		||||
          }
 | 
			
		||||
        },
 | 
			
		||||
@ -541,7 +541,7 @@ export class DocumentDetailComponent
 | 
			
		||||
          this.toastService.showError(
 | 
			
		||||
            $localize`Error saving document` +
 | 
			
		||||
              ': ' +
 | 
			
		||||
              (error.message ?? error.toString())
 | 
			
		||||
              (error.error?.detail ?? error.message ?? JSON.stringify(error))
 | 
			
		||||
          )
 | 
			
		||||
        },
 | 
			
		||||
      })
 | 
			
		||||
@ -573,6 +573,10 @@ export class DocumentDetailComponent
 | 
			
		||||
    modal.componentInstance.message = $localize`The files for this document will be deleted permanently. This operation cannot be undone.`
 | 
			
		||||
    modal.componentInstance.btnClass = 'btn-danger'
 | 
			
		||||
    modal.componentInstance.btnCaption = $localize`Delete document`
 | 
			
		||||
    this.subscribeModalDelete(modal) // so can be re-subscribed if error
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  subscribeModalDelete(modal) {
 | 
			
		||||
    modal.componentInstance.confirmClicked
 | 
			
		||||
      .pipe(
 | 
			
		||||
        switchMap(() => {
 | 
			
		||||
@ -581,18 +585,21 @@ export class DocumentDetailComponent
 | 
			
		||||
        })
 | 
			
		||||
      )
 | 
			
		||||
      .pipe(takeUntil(this.unsubscribeNotifier))
 | 
			
		||||
      .subscribe(
 | 
			
		||||
        () => {
 | 
			
		||||
      .subscribe({
 | 
			
		||||
        next: () => {
 | 
			
		||||
          modal.close()
 | 
			
		||||
          this.close()
 | 
			
		||||
        },
 | 
			
		||||
        (error) => {
 | 
			
		||||
        error: (error) => {
 | 
			
		||||
          this.toastService.showError(
 | 
			
		||||
            $localize`Error deleting document: ${JSON.stringify(error)}`
 | 
			
		||||
            $localize`Error deleting document: ${
 | 
			
		||||
              error.error?.detail ?? error.message ?? JSON.stringify(error)
 | 
			
		||||
            }`
 | 
			
		||||
          )
 | 
			
		||||
          modal.componentInstance.buttonsEnabled = true
 | 
			
		||||
        }
 | 
			
		||||
      )
 | 
			
		||||
          this.subscribeModalDelete(modal)
 | 
			
		||||
        },
 | 
			
		||||
      })
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  moreLike() {
 | 
			
		||||
@ -681,12 +688,21 @@ export class DocumentDetailComponent
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  get showPermissions(): boolean {
 | 
			
		||||
    return (
 | 
			
		||||
      this.permissionsService.currentUserCan(
 | 
			
		||||
        PermissionAction.View,
 | 
			
		||||
        PermissionType.User
 | 
			
		||||
      ) && this.userIsOwner
 | 
			
		||||
    )
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  get notesEnabled(): boolean {
 | 
			
		||||
    return (
 | 
			
		||||
      this.settings.get(SETTINGS_KEYS.NOTES_ENABLED) &&
 | 
			
		||||
      this.permissionsService.currentUserCan(
 | 
			
		||||
        PermissionAction.View,
 | 
			
		||||
        PermissionType.Document
 | 
			
		||||
        PermissionType.Note
 | 
			
		||||
      )
 | 
			
		||||
    )
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
@ -8,13 +8,15 @@ import {
 | 
			
		||||
import { Injectable } from '@angular/core'
 | 
			
		||||
import { PermissionsService } from '../services/permissions.service'
 | 
			
		||||
import { ToastService } from '../services/toast.service'
 | 
			
		||||
import { TourService } from 'ngx-ui-tour-ng-bootstrap'
 | 
			
		||||
 | 
			
		||||
@Injectable()
 | 
			
		||||
export class PermissionsGuard implements CanActivate {
 | 
			
		||||
  constructor(
 | 
			
		||||
    private permissionsService: PermissionsService,
 | 
			
		||||
    private router: Router,
 | 
			
		||||
    private toastService: ToastService
 | 
			
		||||
    private toastService: ToastService,
 | 
			
		||||
    private tourService: TourService
 | 
			
		||||
  ) {}
 | 
			
		||||
 | 
			
		||||
  canActivate(
 | 
			
		||||
@ -27,9 +29,12 @@ export class PermissionsGuard implements CanActivate {
 | 
			
		||||
        route.data.requiredPermission.type
 | 
			
		||||
      )
 | 
			
		||||
    ) {
 | 
			
		||||
      // Check if tour is running 1 = TourState.ON
 | 
			
		||||
      if (this.tourService.getStatus() !== 1) {
 | 
			
		||||
        this.toastService.showError(
 | 
			
		||||
          $localize`You don't have permissions to do that`
 | 
			
		||||
        )
 | 
			
		||||
      }
 | 
			
		||||
      return this.router.parseUrl('/dashboard')
 | 
			
		||||
    } else {
 | 
			
		||||
      return true
 | 
			
		||||
 | 
			
		||||
@ -5,7 +5,7 @@ export const environment = {
 | 
			
		||||
  apiBaseUrl: document.baseURI + 'api/',
 | 
			
		||||
  apiVersion: '2',
 | 
			
		||||
  appTitle: 'Paperless-ngx',
 | 
			
		||||
  version: '1.14.0-beta.rc1',
 | 
			
		||||
  version: '1.14.0',
 | 
			
		||||
  webSocketHost: window.location.host,
 | 
			
		||||
  webSocketProtocol: window.location.protocol == 'https:' ? 'wss:' : 'ws:',
 | 
			
		||||
  webSocketBaseUrl: base_url.pathname + 'ws/',
 | 
			
		||||
 | 
			
		||||
@ -6,6 +6,7 @@ from documents.models import DocumentType
 | 
			
		||||
from documents.models import MatchingModel
 | 
			
		||||
from documents.models import StoragePath
 | 
			
		||||
from documents.models import Tag
 | 
			
		||||
from documents.permissions import get_objects_for_user_owner_aware
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
logger = logging.getLogger("paperless.matching")
 | 
			
		||||
@ -19,9 +20,16 @@ def log_reason(matching_model, document, reason):
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def match_correspondents(document, classifier):
 | 
			
		||||
def match_correspondents(document, classifier, user=None):
 | 
			
		||||
    pred_id = classifier.predict_correspondent(document.content) if classifier else None
 | 
			
		||||
 | 
			
		||||
    if user is not None:
 | 
			
		||||
        correspondents = get_objects_for_user_owner_aware(
 | 
			
		||||
            user,
 | 
			
		||||
            "documents.view_correspondent",
 | 
			
		||||
            Correspondent,
 | 
			
		||||
        )
 | 
			
		||||
    else:
 | 
			
		||||
        correspondents = Correspondent.objects.all()
 | 
			
		||||
 | 
			
		||||
    return list(
 | 
			
		||||
@ -29,9 +37,16 @@ def match_correspondents(document, classifier):
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def match_document_types(document, classifier):
 | 
			
		||||
def match_document_types(document, classifier, user=None):
 | 
			
		||||
    pred_id = classifier.predict_document_type(document.content) if classifier else None
 | 
			
		||||
 | 
			
		||||
    if user is not None:
 | 
			
		||||
        document_types = get_objects_for_user_owner_aware(
 | 
			
		||||
            user,
 | 
			
		||||
            "documents.view_documenttype",
 | 
			
		||||
            DocumentType,
 | 
			
		||||
        )
 | 
			
		||||
    else:
 | 
			
		||||
        document_types = DocumentType.objects.all()
 | 
			
		||||
 | 
			
		||||
    return list(
 | 
			
		||||
@ -39,9 +54,12 @@ def match_document_types(document, classifier):
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def match_tags(document, classifier):
 | 
			
		||||
def match_tags(document, classifier, user=None):
 | 
			
		||||
    predicted_tag_ids = classifier.predict_tags(document.content) if classifier else []
 | 
			
		||||
 | 
			
		||||
    if user is not None:
 | 
			
		||||
        tags = get_objects_for_user_owner_aware(user, "documents.view_tag", Tag)
 | 
			
		||||
    else:
 | 
			
		||||
        tags = Tag.objects.all()
 | 
			
		||||
 | 
			
		||||
    return list(
 | 
			
		||||
@ -49,9 +67,16 @@ def match_tags(document, classifier):
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def match_storage_paths(document, classifier):
 | 
			
		||||
def match_storage_paths(document, classifier, user=None):
 | 
			
		||||
    pred_id = classifier.predict_storage_path(document.content) if classifier else None
 | 
			
		||||
 | 
			
		||||
    if user is not None:
 | 
			
		||||
        storage_paths = get_objects_for_user_owner_aware(
 | 
			
		||||
            user,
 | 
			
		||||
            "documents.view_storagepath",
 | 
			
		||||
            StoragePath,
 | 
			
		||||
        )
 | 
			
		||||
    else:
 | 
			
		||||
        storage_paths = StoragePath.objects.all()
 | 
			
		||||
 | 
			
		||||
    return list(
 | 
			
		||||
 | 
			
		||||
@ -4,6 +4,7 @@ from django.contrib.auth.models import User
 | 
			
		||||
from django.contrib.contenttypes.models import ContentType
 | 
			
		||||
from guardian.models import GroupObjectPermission
 | 
			
		||||
from guardian.shortcuts import assign_perm
 | 
			
		||||
from guardian.shortcuts import get_objects_for_user
 | 
			
		||||
from guardian.shortcuts import get_users_with_perms
 | 
			
		||||
from guardian.shortcuts import remove_perm
 | 
			
		||||
from rest_framework.permissions import BasePermission
 | 
			
		||||
@ -101,3 +102,15 @@ def set_permissions_for_object(permissions, object):
 | 
			
		||||
                        group,
 | 
			
		||||
                        object,
 | 
			
		||||
                    )
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def get_objects_for_user_owner_aware(user, perms, Model):
 | 
			
		||||
    objects_owned = Model.objects.filter(owner=user)
 | 
			
		||||
    objects_unowned = Model.objects.filter(owner__isnull=True)
 | 
			
		||||
    objects_with_perms = get_objects_for_user(
 | 
			
		||||
        user=user,
 | 
			
		||||
        perms=perms,
 | 
			
		||||
        klass=Model,
 | 
			
		||||
        accept_global_perms=False,
 | 
			
		||||
    )
 | 
			
		||||
    return objects_owned | objects_unowned | objects_with_perms
 | 
			
		||||
 | 
			
		||||
@ -4,6 +4,7 @@ import shutil
 | 
			
		||||
 | 
			
		||||
from celery import states
 | 
			
		||||
from celery.signals import before_task_publish
 | 
			
		||||
from celery.signals import task_failure
 | 
			
		||||
from celery.signals import task_postrun
 | 
			
		||||
from celery.signals import task_prerun
 | 
			
		||||
from django.conf import settings
 | 
			
		||||
@ -591,3 +592,29 @@ def task_postrun_handler(
 | 
			
		||||
        # Don't let an exception in the signal handlers prevent
 | 
			
		||||
        # a document from being consumed.
 | 
			
		||||
        logger.exception("Updating PaperlessTask failed")
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@task_failure.connect
 | 
			
		||||
def task_failure_handler(
 | 
			
		||||
    sender=None,
 | 
			
		||||
    task_id=None,
 | 
			
		||||
    exception=None,
 | 
			
		||||
    args=None,
 | 
			
		||||
    traceback=None,
 | 
			
		||||
    **kwargs,
 | 
			
		||||
):
 | 
			
		||||
    """
 | 
			
		||||
    Updates the result of a failed PaperlessTask.
 | 
			
		||||
 | 
			
		||||
    https://docs.celeryq.dev/en/stable/userguide/signals.html#task-failure
 | 
			
		||||
    """
 | 
			
		||||
    try:
 | 
			
		||||
        task_instance = PaperlessTask.objects.filter(task_id=task_id).first()
 | 
			
		||||
 | 
			
		||||
        if task_instance is not None and task_instance.result is None:
 | 
			
		||||
            task_instance.status = states.FAILURE
 | 
			
		||||
            task_instance.result = traceback
 | 
			
		||||
            task_instance.date_done = timezone.now()
 | 
			
		||||
            task_instance.save()
 | 
			
		||||
    except Exception:  # pragma: no cover
 | 
			
		||||
        logger.exception("Updating PaperlessTask failed")
 | 
			
		||||
 | 
			
		||||
@ -9,6 +9,7 @@ from documents.models import PaperlessTask
 | 
			
		||||
from documents.signals.handlers import before_task_publish_handler
 | 
			
		||||
from documents.signals.handlers import task_postrun_handler
 | 
			
		||||
from documents.signals.handlers import task_prerun_handler
 | 
			
		||||
from documents.signals.handlers import task_failure_handler
 | 
			
		||||
from documents.tests.test_consumer import fake_magic_from_file
 | 
			
		||||
from documents.tests.utils import DirectoriesMixin
 | 
			
		||||
 | 
			
		||||
@ -146,3 +147,44 @@ class TestTaskSignalHandler(DirectoriesMixin, TestCase):
 | 
			
		||||
        task = PaperlessTask.objects.get()
 | 
			
		||||
 | 
			
		||||
        self.assertEqual(celery.states.SUCCESS, task.status)
 | 
			
		||||
 | 
			
		||||
    def test_task_failure_handler(self):
 | 
			
		||||
        """
 | 
			
		||||
        GIVEN:
 | 
			
		||||
            - A celery task is started via the consume folder
 | 
			
		||||
        WHEN:
 | 
			
		||||
            - Task failed execution
 | 
			
		||||
        THEN:
 | 
			
		||||
            - The task is marked as failed
 | 
			
		||||
        """
 | 
			
		||||
        headers = {
 | 
			
		||||
            "id": str(uuid.uuid4()),
 | 
			
		||||
            "task": "documents.tasks.consume_file",
 | 
			
		||||
        }
 | 
			
		||||
        body = (
 | 
			
		||||
            # args
 | 
			
		||||
            (
 | 
			
		||||
                ConsumableDocument(
 | 
			
		||||
                    source=DocumentSource.ConsumeFolder,
 | 
			
		||||
                    original_file="/consume/hello-9.pdf",
 | 
			
		||||
                ),
 | 
			
		||||
                None,
 | 
			
		||||
            ),
 | 
			
		||||
            # kwargs
 | 
			
		||||
            {},
 | 
			
		||||
            # celery stuff
 | 
			
		||||
            {"callbacks": None, "errbacks": None, "chain": None, "chord": None},
 | 
			
		||||
        )
 | 
			
		||||
        self.util_call_before_task_publish_handler(
 | 
			
		||||
            headers_to_use=headers,
 | 
			
		||||
            body_to_use=body,
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
        task_failure_handler(
 | 
			
		||||
            task_id=headers["id"],
 | 
			
		||||
            exception="Example failure",
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
        task = PaperlessTask.objects.get()
 | 
			
		||||
 | 
			
		||||
        self.assertEqual(celery.states.FAILURE, task.status)
 | 
			
		||||
 | 
			
		||||
@ -401,12 +401,16 @@ class DocumentViewSet(
 | 
			
		||||
 | 
			
		||||
        return Response(
 | 
			
		||||
            {
 | 
			
		||||
                "correspondents": [c.id for c in match_correspondents(doc, classifier)],
 | 
			
		||||
                "tags": [t.id for t in match_tags(doc, classifier)],
 | 
			
		||||
                "document_types": [
 | 
			
		||||
                    dt.id for dt in match_document_types(doc, classifier)
 | 
			
		||||
                "correspondents": [
 | 
			
		||||
                    c.id for c in match_correspondents(doc, classifier, request.user)
 | 
			
		||||
                ],
 | 
			
		||||
                "tags": [t.id for t in match_tags(doc, classifier, request.user)],
 | 
			
		||||
                "document_types": [
 | 
			
		||||
                    dt.id for dt in match_document_types(doc, classifier, request.user)
 | 
			
		||||
                ],
 | 
			
		||||
                "storage_paths": [
 | 
			
		||||
                    dt.id for dt in match_storage_paths(doc, classifier, request.user)
 | 
			
		||||
                ],
 | 
			
		||||
                "storage_paths": [dt.id for dt in match_storage_paths(doc, classifier)],
 | 
			
		||||
                "dates": [
 | 
			
		||||
                    date.strftime("%Y-%m-%d") for date in dates if date is not None
 | 
			
		||||
                ],
 | 
			
		||||
 | 
			
		||||
@ -431,6 +431,14 @@ if _paperless_url:
 | 
			
		||||
# For use with trusted proxies
 | 
			
		||||
TRUSTED_PROXIES = __get_list("PAPERLESS_TRUSTED_PROXIES")
 | 
			
		||||
 | 
			
		||||
USE_X_FORWARDED_HOST = __get_boolean("PAPERLESS_USE_X_FORWARD_HOST", "false")
 | 
			
		||||
USE_X_FORWARDED_PORT = __get_boolean("PAPERLESS_USE_X_FORWARD_PORT", "false")
 | 
			
		||||
SECURE_PROXY_SSL_HEADER = (
 | 
			
		||||
    tuple(json.loads(os.environ["PAPERLESS_PROXY_SSL_HEADER"]))
 | 
			
		||||
    if "PAPERLESS_PROXY_SSL_HEADER" in os.environ
 | 
			
		||||
    else None
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
# The secret key has a default that should be fine so long as you're hosting
 | 
			
		||||
# Paperless on a closed network.  However, if you're putting this anywhere
 | 
			
		||||
# public, you should change the key to something unique and verbose.
 | 
			
		||||
 | 
			
		||||
@ -0,0 +1,17 @@
 | 
			
		||||
# Generated by Django 4.1.7 on 2023-04-20 15:03
 | 
			
		||||
 | 
			
		||||
from django.db import migrations, models
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class Migration(migrations.Migration):
 | 
			
		||||
    dependencies = [
 | 
			
		||||
        ("paperless_mail", "0020_mailaccount_is_token"),
 | 
			
		||||
    ]
 | 
			
		||||
 | 
			
		||||
    operations = [
 | 
			
		||||
        migrations.AlterField(
 | 
			
		||||
            model_name="mailaccount",
 | 
			
		||||
            name="password",
 | 
			
		||||
            field=models.CharField(max_length=2048, verbose_name="password"),
 | 
			
		||||
        ),
 | 
			
		||||
    ]
 | 
			
		||||
@ -36,7 +36,7 @@ class MailAccount(document_models.ModelWithOwner):
 | 
			
		||||
 | 
			
		||||
    username = models.CharField(_("username"), max_length=256)
 | 
			
		||||
 | 
			
		||||
    password = models.CharField(_("password"), max_length=256)
 | 
			
		||||
    password = models.CharField(_("password"), max_length=2048)
 | 
			
		||||
 | 
			
		||||
    is_token = models.BooleanField(_("Is token authentication"), default=False)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||