Merge branch 'dev' into feature-config-from-frontend
This commit is contained in:
commit
8ea6bb770b
16
docs/api.md
16
docs/api.md
@ -8,20 +8,22 @@ most of the available filters and ordering fields.
|
|||||||
|
|
||||||
The API provides the following main endpoints:
|
The API provides the following main endpoints:
|
||||||
|
|
||||||
|
- `/api/consumption_templates/`: Full CRUD support.
|
||||||
|
- `/api/correspondents/`: Full CRUD support.
|
||||||
|
- `/api/custom_fields/`: Full CRUD support.
|
||||||
- `/api/documents/`: Full CRUD support, except POSTing new documents.
|
- `/api/documents/`: Full CRUD support, except POSTing new documents.
|
||||||
See below.
|
See below.
|
||||||
- `/api/correspondents/`: Full CRUD support.
|
|
||||||
- `/api/document_types/`: Full CRUD support.
|
- `/api/document_types/`: Full CRUD support.
|
||||||
|
- `/api/groups/`: Full CRUD support.
|
||||||
- `/api/logs/`: Read-Only.
|
- `/api/logs/`: Read-Only.
|
||||||
- `/api/tags/`: Full CRUD support.
|
|
||||||
- `/api/tasks/`: Read-only.
|
|
||||||
- `/api/mail_accounts/`: Full CRUD support.
|
- `/api/mail_accounts/`: Full CRUD support.
|
||||||
- `/api/mail_rules/`: Full CRUD support.
|
- `/api/mail_rules/`: Full CRUD support.
|
||||||
- `/api/users/`: Full CRUD support.
|
|
||||||
- `/api/groups/`: Full CRUD support.
|
|
||||||
- `/api/share_links/`: Full CRUD support.
|
|
||||||
- `/api/custom_fields/`: Full CRUD support.
|
|
||||||
- `/api/profile/`: GET, PATCH
|
- `/api/profile/`: GET, PATCH
|
||||||
|
- `/api/share_links/`: Full CRUD support.
|
||||||
|
- `/api/storage_paths/`: Full CRUD support.
|
||||||
|
- `/api/tags/`: Full CRUD support.
|
||||||
|
- `/api/tasks/`: Read-only.
|
||||||
|
- `/api/users/`: Full CRUD support.
|
||||||
|
|
||||||
All of these endpoints except for the logging endpoint allow you to
|
All of these endpoints except for the logging endpoint allow you to
|
||||||
fetch (and edit and delete where appropriate) individual objects by
|
fetch (and edit and delete where appropriate) individual objects by
|
||||||
|
@ -54,6 +54,7 @@ export class LogsComponent implements OnInit, AfterViewChecked, OnDestroy {
|
|||||||
ngOnDestroy(): void {
|
ngOnDestroy(): void {
|
||||||
this.unsubscribeNotifier.next(true)
|
this.unsubscribeNotifier.next(true)
|
||||||
this.unsubscribeNotifier.complete()
|
this.unsubscribeNotifier.complete()
|
||||||
|
clearInterval(this.autoRefreshInterval)
|
||||||
}
|
}
|
||||||
|
|
||||||
reloadLogs() {
|
reloadLogs() {
|
||||||
|
@ -46,6 +46,7 @@ export class TasksComponent
|
|||||||
|
|
||||||
ngOnDestroy() {
|
ngOnDestroy() {
|
||||||
this.tasksService.cancelPending()
|
this.tasksService.cancelPending()
|
||||||
|
clearInterval(this.autoRefreshInterval)
|
||||||
}
|
}
|
||||||
|
|
||||||
dismissTask(task: PaperlessTask) {
|
dismissTask(task: PaperlessTask) {
|
||||||
|
@ -34,6 +34,9 @@
|
|||||||
(focus)="clearLastSearchTerm()"
|
(focus)="clearLastSearchTerm()"
|
||||||
(clear)="clearLastSearchTerm()"
|
(clear)="clearLastSearchTerm()"
|
||||||
(blur)="onBlur()">
|
(blur)="onBlur()">
|
||||||
|
<ng-template ng-option-tmp let-item="item">
|
||||||
|
<span [title]="item.name">{{item.name}}</span>
|
||||||
|
</ng-template>
|
||||||
</ng-select>
|
</ng-select>
|
||||||
@if (allowCreateNew) {
|
@if (allowCreateNew) {
|
||||||
<button class="btn btn-outline-secondary" type="button" (click)="addItem()" [disabled]="disabled">
|
<button class="btn btn-outline-secondary" type="button" (click)="addItem()" [disabled]="disabled">
|
||||||
|
@ -105,7 +105,7 @@ class BarcodeReader:
|
|||||||
asn_text = asn_text[len(settings.CONSUMER_ASN_BARCODE_PREFIX) :].strip()
|
asn_text = asn_text[len(settings.CONSUMER_ASN_BARCODE_PREFIX) :].strip()
|
||||||
|
|
||||||
# remove non-numeric parts of the remaining string
|
# remove non-numeric parts of the remaining string
|
||||||
asn_text = re.sub("[^0-9]", "", asn_text)
|
asn_text = re.sub(r"\D", "", asn_text)
|
||||||
|
|
||||||
# now, try parsing the ASN number
|
# now, try parsing the ASN number
|
||||||
try:
|
try:
|
||||||
|
@ -2,12 +2,16 @@ from django.conf import settings
|
|||||||
from django.contrib import auth
|
from django.contrib import auth
|
||||||
from django.contrib.auth.middleware import PersistentRemoteUserMiddleware
|
from django.contrib.auth.middleware import PersistentRemoteUserMiddleware
|
||||||
from django.contrib.auth.models import User
|
from django.contrib.auth.models import User
|
||||||
|
from django.http import HttpRequest
|
||||||
from django.utils.deprecation import MiddlewareMixin
|
from django.utils.deprecation import MiddlewareMixin
|
||||||
from rest_framework import authentication
|
from rest_framework import authentication
|
||||||
|
|
||||||
|
|
||||||
class AutoLoginMiddleware(MiddlewareMixin):
|
class AutoLoginMiddleware(MiddlewareMixin):
|
||||||
def process_request(self, request):
|
def process_request(self, request: HttpRequest):
|
||||||
|
# Dont use auto-login with token request
|
||||||
|
if request.path.startswith("/api/token/") and request.method == "POST":
|
||||||
|
return None
|
||||||
try:
|
try:
|
||||||
request.user = User.objects.get(username=settings.AUTO_LOGIN_USERNAME)
|
request.user = User.objects.get(username=settings.AUTO_LOGIN_USERNAME)
|
||||||
auth.login(
|
auth.login(
|
||||||
|
@ -315,8 +315,8 @@ if DEBUG:
|
|||||||
REST_FRAMEWORK = {
|
REST_FRAMEWORK = {
|
||||||
"DEFAULT_AUTHENTICATION_CLASSES": [
|
"DEFAULT_AUTHENTICATION_CLASSES": [
|
||||||
"rest_framework.authentication.BasicAuthentication",
|
"rest_framework.authentication.BasicAuthentication",
|
||||||
"rest_framework.authentication.SessionAuthentication",
|
|
||||||
"rest_framework.authentication.TokenAuthentication",
|
"rest_framework.authentication.TokenAuthentication",
|
||||||
|
"rest_framework.authentication.SessionAuthentication",
|
||||||
],
|
],
|
||||||
"DEFAULT_VERSIONING_CLASS": "rest_framework.versioning.AcceptHeaderVersioning",
|
"DEFAULT_VERSIONING_CLASS": "rest_framework.versioning.AcceptHeaderVersioning",
|
||||||
"DEFAULT_VERSION": "1",
|
"DEFAULT_VERSION": "1",
|
||||||
|
@ -6,6 +6,7 @@ from django.urls import path
|
|||||||
from django.urls import re_path
|
from django.urls import re_path
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
from django.views.decorators.csrf import csrf_exempt
|
from django.views.decorators.csrf import csrf_exempt
|
||||||
|
from django.views.decorators.csrf import ensure_csrf_cookie
|
||||||
from django.views.generic import RedirectView
|
from django.views.generic import RedirectView
|
||||||
from rest_framework.authtoken import views
|
from rest_framework.authtoken import views
|
||||||
from rest_framework.routers import DefaultRouter
|
from rest_framework.routers import DefaultRouter
|
||||||
@ -180,7 +181,11 @@ urlpatterns = [
|
|||||||
# login, logout
|
# login, logout
|
||||||
path("accounts/", include("django.contrib.auth.urls")),
|
path("accounts/", include("django.contrib.auth.urls")),
|
||||||
# Root of the Frontend
|
# Root of the Frontend
|
||||||
re_path(r".*", login_required(IndexView.as_view()), name="base"),
|
re_path(
|
||||||
|
r".*",
|
||||||
|
login_required(ensure_csrf_cookie(IndexView.as_view())),
|
||||||
|
name="base",
|
||||||
|
),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
@ -703,6 +703,12 @@ class MailAccountHandler(LoggingMixin):
|
|||||||
mime_type = magic.from_buffer(att.payload, mime=True)
|
mime_type = magic.from_buffer(att.payload, mime=True)
|
||||||
|
|
||||||
if is_mime_type_supported(mime_type):
|
if is_mime_type_supported(mime_type):
|
||||||
|
self.log.info(
|
||||||
|
f"Rule {rule}: "
|
||||||
|
f"Consuming attachment {att.filename} from mail "
|
||||||
|
f"{message.subject} from {message.from_}",
|
||||||
|
)
|
||||||
|
|
||||||
os.makedirs(settings.SCRATCH_DIR, exist_ok=True)
|
os.makedirs(settings.SCRATCH_DIR, exist_ok=True)
|
||||||
|
|
||||||
temp_dir = Path(
|
temp_dir = Path(
|
||||||
@ -711,14 +717,15 @@ class MailAccountHandler(LoggingMixin):
|
|||||||
dir=settings.SCRATCH_DIR,
|
dir=settings.SCRATCH_DIR,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
temp_filename = temp_dir / pathvalidate.sanitize_filename(att.filename)
|
|
||||||
temp_filename.write_bytes(att.payload)
|
|
||||||
|
|
||||||
self.log.info(
|
attachment_name = pathvalidate.sanitize_filename(att.filename)
|
||||||
f"Rule {rule}: "
|
if attachment_name:
|
||||||
f"Consuming attachment {att.filename} from mail "
|
temp_filename = temp_dir / attachment_name
|
||||||
f"{message.subject} from {message.from_}",
|
else: # pragma: no cover
|
||||||
)
|
# Some cases may have no name (generally inline)
|
||||||
|
temp_filename = temp_dir / "no-name-attachment"
|
||||||
|
|
||||||
|
temp_filename.write_bytes(att.payload)
|
||||||
|
|
||||||
input_doc = ConsumableDocument(
|
input_doc = ConsumableDocument(
|
||||||
source=DocumentSource.MailFetch,
|
source=DocumentSource.MailFetch,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user