mirror of
https://github.com/paperless-ngx/paperless-ngx.git
synced 2025-04-02 13:45:10 -05:00
Basic data retrieval
This commit is contained in:
parent
ea38eb01b2
commit
c3331086d5
@ -216,6 +216,37 @@
|
||||
|
||||
</ng-template>
|
||||
</li>
|
||||
|
||||
<li [ngbNavItem]="4">
|
||||
<a ngbNavLink i18n>Paperless Mail</a>
|
||||
<ng-template ngbNavContent>
|
||||
|
||||
<h4 i18n>Mail accounts</h4>
|
||||
<div formGroupName="mailAccounts">
|
||||
|
||||
<div *ngFor="let account of mailAccounts" [formGroupName]="account.id" class="row">
|
||||
<div class="mb-3 col">
|
||||
{{account.name}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div *ngIf="mailAccounts.length == 0" i18n>No mail accounts defined.</div>
|
||||
</div>
|
||||
|
||||
<h4 i18n>Mail rules</h4>
|
||||
<div formGroupName="mailRules">
|
||||
|
||||
<div *ngFor="let rule of mailRules" [formGroupName]="rule.id" class="row">
|
||||
<div class="mb-3 col">
|
||||
{{rule.name}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div *ngIf="mailRules.length == 0" i18n>No mail rules defined.</div>
|
||||
</div>
|
||||
|
||||
</ng-template>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<div [ngbNavOutlet]="nav" class="border-start border-end border-bottom p-3 mb-3 shadow-sm"></div>
|
||||
|
@ -29,6 +29,10 @@ import { SETTINGS_KEYS } from 'src/app/data/paperless-uisettings'
|
||||
import { ActivatedRoute } from '@angular/router'
|
||||
import { ViewportScroller } from '@angular/common'
|
||||
import { TourService } from 'ngx-ui-tour-ng-bootstrap'
|
||||
import { PaperlessMailAccount } from 'src/app/data/paperless-mail-account'
|
||||
import { PaperlessMailRule } from 'src/app/data/paperless-mail-rule'
|
||||
import { MailAccountService as MailAccountService } from 'src/app/services/rest/mail-account.service'
|
||||
import { MailRuleService } from 'src/app/services/rest/mail-rule.service'
|
||||
|
||||
@Component({
|
||||
selector: 'app-settings',
|
||||
@ -40,6 +44,9 @@ export class SettingsComponent
|
||||
{
|
||||
savedViewGroup = new FormGroup({})
|
||||
|
||||
mailAccountGroup = new FormGroup({})
|
||||
mailRuleGroup = new FormGroup({})
|
||||
|
||||
settingsForm = new FormGroup({
|
||||
bulkEditConfirmationDialogs: new FormControl(null),
|
||||
bulkEditApplyOnClose: new FormControl(null),
|
||||
@ -50,20 +57,28 @@ export class SettingsComponent
|
||||
darkModeInvertThumbs: new FormControl(null),
|
||||
themeColor: new FormControl(null),
|
||||
useNativePdfViewer: new FormControl(null),
|
||||
savedViews: this.savedViewGroup,
|
||||
displayLanguage: new FormControl(null),
|
||||
dateLocale: new FormControl(null),
|
||||
dateFormat: new FormControl(null),
|
||||
commentsEnabled: new FormControl(null),
|
||||
updateCheckingEnabled: new FormControl(null),
|
||||
|
||||
notificationsConsumerNewDocument: new FormControl(null),
|
||||
notificationsConsumerSuccess: new FormControl(null),
|
||||
notificationsConsumerFailed: new FormControl(null),
|
||||
notificationsConsumerSuppressOnDashboard: new FormControl(null),
|
||||
commentsEnabled: new FormControl(null),
|
||||
updateCheckingEnabled: new FormControl(null),
|
||||
|
||||
savedViews: this.savedViewGroup,
|
||||
|
||||
mailAccounts: this.mailAccountGroup,
|
||||
mailRules: this.mailRuleGroup,
|
||||
})
|
||||
|
||||
savedViews: PaperlessSavedView[]
|
||||
|
||||
mailAccounts: PaperlessMailAccount[]
|
||||
mailRules: PaperlessMailRule[]
|
||||
|
||||
store: BehaviorSubject<any>
|
||||
storeSub: Subscription
|
||||
isDirty$: Observable<boolean>
|
||||
@ -81,6 +96,8 @@ export class SettingsComponent
|
||||
|
||||
constructor(
|
||||
public savedViewService: SavedViewService,
|
||||
public mailAccountService: MailAccountService,
|
||||
public mailRuleService: MailRuleService,
|
||||
private documentListViewService: DocumentListViewService,
|
||||
private toastService: ToastService,
|
||||
private settings: SettingsService,
|
||||
@ -123,10 +140,13 @@ export class SettingsComponent
|
||||
useNativePdfViewer: this.settings.get(
|
||||
SETTINGS_KEYS.USE_NATIVE_PDF_VIEWER
|
||||
),
|
||||
savedViews: {},
|
||||
displayLanguage: this.settings.getLanguage(),
|
||||
dateLocale: this.settings.get(SETTINGS_KEYS.DATE_LOCALE),
|
||||
dateFormat: this.settings.get(SETTINGS_KEYS.DATE_FORMAT),
|
||||
commentsEnabled: this.settings.get(SETTINGS_KEYS.COMMENTS_ENABLED),
|
||||
updateCheckingEnabled: this.settings.get(
|
||||
SETTINGS_KEYS.UPDATE_CHECKING_ENABLED
|
||||
),
|
||||
notificationsConsumerNewDocument: this.settings.get(
|
||||
SETTINGS_KEYS.NOTIFICATIONS_CONSUMER_NEW_DOCUMENT
|
||||
),
|
||||
@ -139,17 +159,25 @@ export class SettingsComponent
|
||||
notificationsConsumerSuppressOnDashboard: this.settings.get(
|
||||
SETTINGS_KEYS.NOTIFICATIONS_CONSUMER_SUPPRESS_ON_DASHBOARD
|
||||
),
|
||||
commentsEnabled: this.settings.get(SETTINGS_KEYS.COMMENTS_ENABLED),
|
||||
updateCheckingEnabled: this.settings.get(
|
||||
SETTINGS_KEYS.UPDATE_CHECKING_ENABLED
|
||||
),
|
||||
savedViews: {},
|
||||
mailAccounts: {},
|
||||
mailRules: {},
|
||||
}
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
this.savedViewService.listAll().subscribe((r) => {
|
||||
this.savedViews = r.results
|
||||
this.initialize()
|
||||
|
||||
this.mailAccountService.listAll().subscribe((r) => {
|
||||
this.mailAccounts = r.results
|
||||
|
||||
this.mailRuleService.listAll().subscribe((r) => {
|
||||
this.mailRules = r.results
|
||||
|
||||
this.initialize()
|
||||
})
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
@ -176,6 +204,76 @@ export class SettingsComponent
|
||||
)
|
||||
}
|
||||
|
||||
for (let account of this.mailAccounts) {
|
||||
storeData.mailAccounts[account.id.toString()] = {
|
||||
id: account.id,
|
||||
name: account.name,
|
||||
imap_server: account.imap_server,
|
||||
imap_port: account.imap_port,
|
||||
imap_security: account.imap_security,
|
||||
username: account.username,
|
||||
password: account.password,
|
||||
character_set: account.character_set,
|
||||
}
|
||||
this.mailAccountGroup.addControl(
|
||||
account.id.toString(),
|
||||
new FormGroup({
|
||||
id: new FormControl(null),
|
||||
name: new FormControl(null),
|
||||
imap_server: new FormControl(null),
|
||||
imap_port: new FormControl(null),
|
||||
imap_security: new FormControl(null),
|
||||
username: new FormControl(null),
|
||||
password: new FormControl(null),
|
||||
character_set: new FormControl(null),
|
||||
})
|
||||
)
|
||||
}
|
||||
|
||||
for (let rule of this.mailRules) {
|
||||
storeData.mailRules[rule.id.toString()] = {
|
||||
name: rule.name,
|
||||
order: rule.order,
|
||||
account: rule.account,
|
||||
folder: rule.folder,
|
||||
filter_from: rule.filter_from,
|
||||
filter_subject: rule.filter_subject,
|
||||
filter_body: rule.filter_body,
|
||||
filter_attachment_filename: rule.filter_attachment_filename,
|
||||
maximum_age: rule.maximum_age,
|
||||
attachment_type: rule.attachment_type,
|
||||
action: rule.action,
|
||||
action_parameter: rule.action_parameter,
|
||||
assign_title_from: rule.assign_title_from,
|
||||
assign_tags: rule.assign_tags,
|
||||
assign_document_type: rule.assign_document_type,
|
||||
assign_correspondent_from: rule.assign_correspondent_from,
|
||||
assign_correspondent: rule.assign_correspondent,
|
||||
}
|
||||
this.mailRuleGroup.addControl(
|
||||
rule.id.toString(),
|
||||
new FormGroup({
|
||||
name: new FormControl(null),
|
||||
order: new FormControl(null),
|
||||
account: new FormControl(null),
|
||||
folder: new FormControl(null),
|
||||
filter_from: new FormControl(null),
|
||||
filter_subject: new FormControl(null),
|
||||
filter_body: new FormControl(null),
|
||||
filter_attachment_filename: new FormControl(null),
|
||||
maximum_age: new FormControl(null),
|
||||
attachment_type: new FormControl(null),
|
||||
action: new FormControl(null),
|
||||
action_parameter: new FormControl(null),
|
||||
assign_title_from: new FormControl(null),
|
||||
assign_tags: new FormControl(null),
|
||||
assign_document_type: new FormControl(null),
|
||||
assign_correspondent_from: new FormControl(null),
|
||||
assign_correspondent: new FormControl(null),
|
||||
})
|
||||
)
|
||||
}
|
||||
|
||||
this.store = new BehaviorSubject(storeData)
|
||||
|
||||
this.storeSub = this.store.asObservable().subscribe((state) => {
|
||||
|
23
src-ui/src/app/data/paperless-mail-account.ts
Normal file
23
src-ui/src/app/data/paperless-mail-account.ts
Normal file
@ -0,0 +1,23 @@
|
||||
import { ObjectWithId } from './object-with-id'
|
||||
|
||||
export enum IMAPSecurity {
|
||||
None = 0,
|
||||
SSL = 1,
|
||||
STARTTLS = 2,
|
||||
}
|
||||
|
||||
export interface PaperlessMailAccount extends ObjectWithId {
|
||||
name: string
|
||||
|
||||
imap_server: string
|
||||
|
||||
imap_port: number
|
||||
|
||||
imap_security: IMAPSecurity
|
||||
|
||||
username: string
|
||||
|
||||
password: string
|
||||
|
||||
character_set?: string
|
||||
}
|
66
src-ui/src/app/data/paperless-mail-rule.ts
Normal file
66
src-ui/src/app/data/paperless-mail-rule.ts
Normal file
@ -0,0 +1,66 @@
|
||||
import { ObjectWithId } from './object-with-id'
|
||||
import { PaperlessCorrespondent } from './paperless-correspondent'
|
||||
import { PaperlessDocumentType } from './paperless-document-type'
|
||||
import { PaperlessMailAccount } from './paperless-mail-account'
|
||||
import { PaperlessTag } from './paperless-tag'
|
||||
|
||||
export enum MailFilterAttachmentType {
|
||||
Attachments = 1,
|
||||
Everything = 2,
|
||||
}
|
||||
|
||||
export enum MailAction {
|
||||
Delete = 1,
|
||||
Move = 2,
|
||||
MarkRead = 3,
|
||||
Flag = 4,
|
||||
Tag = 5,
|
||||
}
|
||||
|
||||
export enum MailMetadataTitleOption {
|
||||
FromSubject = 1,
|
||||
FromFilename = 2,
|
||||
}
|
||||
|
||||
export enum MailMetadataCorrespondentOption {
|
||||
FromNothing = 1,
|
||||
FromEmail = 2,
|
||||
FromName = 3,
|
||||
FromCustom = 4,
|
||||
}
|
||||
|
||||
export interface PaperlessMailRule extends ObjectWithId {
|
||||
name: string
|
||||
|
||||
order: number
|
||||
|
||||
account: PaperlessMailAccount
|
||||
|
||||
folder: string
|
||||
|
||||
filter_from: string
|
||||
|
||||
filter_subject: string
|
||||
|
||||
filter_body: string
|
||||
|
||||
filter_attachment_filename: string
|
||||
|
||||
maximum_age: number
|
||||
|
||||
attachment_type: MailFilterAttachmentType
|
||||
|
||||
action: MailAction
|
||||
|
||||
action_parameter?: string
|
||||
|
||||
assign_title_from: MailMetadataTitleOption
|
||||
|
||||
assign_tags?: PaperlessTag[]
|
||||
|
||||
assign_document_type?: PaperlessDocumentType
|
||||
|
||||
assign_correspondent_from?: MailMetadataCorrespondentOption
|
||||
|
||||
assign_correspondent?: PaperlessCorrespondent
|
||||
}
|
52
src-ui/src/app/services/rest/mail-account.service.ts
Normal file
52
src-ui/src/app/services/rest/mail-account.service.ts
Normal file
@ -0,0 +1,52 @@
|
||||
import { HttpClient } from '@angular/common/http'
|
||||
import { Injectable } from '@angular/core'
|
||||
import { combineLatest, Observable } from 'rxjs'
|
||||
import { tap } from 'rxjs/operators'
|
||||
import { PaperlessMailAccount } from 'src/app/data/paperless-mail-account'
|
||||
import { AbstractPaperlessService } from './abstract-paperless-service'
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root',
|
||||
})
|
||||
export class MailAccountService extends AbstractPaperlessService<PaperlessMailAccount> {
|
||||
loading: boolean
|
||||
|
||||
constructor(http: HttpClient) {
|
||||
super(http, 'mail_accounts')
|
||||
this.reload()
|
||||
}
|
||||
|
||||
private reload() {
|
||||
this.loading = true
|
||||
this.listAll().subscribe((r) => {
|
||||
this.mailAccounts = r.results
|
||||
this.loading = false
|
||||
})
|
||||
}
|
||||
|
||||
private mailAccounts: PaperlessMailAccount[] = []
|
||||
|
||||
get allAccounts() {
|
||||
return this.mailAccounts
|
||||
}
|
||||
|
||||
create(o: PaperlessMailAccount) {
|
||||
return super.create(o).pipe(tap(() => this.reload()))
|
||||
}
|
||||
|
||||
update(o: PaperlessMailAccount) {
|
||||
return super.update(o).pipe(tap(() => this.reload()))
|
||||
}
|
||||
|
||||
patchMany(
|
||||
objects: PaperlessMailAccount[]
|
||||
): Observable<PaperlessMailAccount[]> {
|
||||
return combineLatest(objects.map((o) => super.patch(o))).pipe(
|
||||
tap(() => this.reload())
|
||||
)
|
||||
}
|
||||
|
||||
delete(o: PaperlessMailAccount) {
|
||||
return super.delete(o).pipe(tap(() => this.reload()))
|
||||
}
|
||||
}
|
50
src-ui/src/app/services/rest/mail-rule.service.ts
Normal file
50
src-ui/src/app/services/rest/mail-rule.service.ts
Normal file
@ -0,0 +1,50 @@
|
||||
import { HttpClient } from '@angular/common/http'
|
||||
import { Injectable } from '@angular/core'
|
||||
import { combineLatest, Observable } from 'rxjs'
|
||||
import { tap } from 'rxjs/operators'
|
||||
import { PaperlessMailRule } from 'src/app/data/paperless-mail-rule'
|
||||
import { AbstractPaperlessService } from './abstract-paperless-service'
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root',
|
||||
})
|
||||
export class MailRuleService extends AbstractPaperlessService<PaperlessMailRule> {
|
||||
loading: boolean
|
||||
|
||||
constructor(http: HttpClient) {
|
||||
super(http, 'mail_rules')
|
||||
this.reload()
|
||||
}
|
||||
|
||||
private reload() {
|
||||
this.loading = true
|
||||
this.listAll().subscribe((r) => {
|
||||
this.mailRules = r.results
|
||||
this.loading = false
|
||||
})
|
||||
}
|
||||
|
||||
private mailRules: PaperlessMailRule[] = []
|
||||
|
||||
get allRules() {
|
||||
return this.mailRules
|
||||
}
|
||||
|
||||
create(o: PaperlessMailRule) {
|
||||
return super.create(o).pipe(tap(() => this.reload()))
|
||||
}
|
||||
|
||||
update(o: PaperlessMailRule) {
|
||||
return super.update(o).pipe(tap(() => this.reload()))
|
||||
}
|
||||
|
||||
patchMany(objects: PaperlessMailRule[]): Observable<PaperlessMailRule[]> {
|
||||
return combineLatest(objects.map((o) => super.patch(o))).pipe(
|
||||
tap(() => this.reload())
|
||||
)
|
||||
}
|
||||
|
||||
delete(o: PaperlessMailRule) {
|
||||
return super.delete(o).pipe(tap(() => this.reload()))
|
||||
}
|
||||
}
|
@ -28,6 +28,8 @@ from .models import UiSettings
|
||||
from .models import PaperlessTask
|
||||
from .parsers import is_mime_type_supported
|
||||
|
||||
from paperless_mail.models import MailAccount, MailRule
|
||||
|
||||
|
||||
# https://www.django-rest-framework.org/api-guide/serializers/#example
|
||||
class DynamicFieldsModelSerializer(serializers.ModelSerializer):
|
||||
@ -688,3 +690,61 @@ class AcknowledgeTasksViewSerializer(serializers.Serializer):
|
||||
def validate_tasks(self, tasks):
|
||||
self._validate_task_id_list(tasks)
|
||||
return tasks
|
||||
|
||||
|
||||
class MailAccountSerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
model = MailAccount
|
||||
depth = 1
|
||||
fields = [
|
||||
"id",
|
||||
"name",
|
||||
"imap_server",
|
||||
"imap_port",
|
||||
"imap_security",
|
||||
"username",
|
||||
"password",
|
||||
"character_set",
|
||||
]
|
||||
|
||||
def update(self, instance, validated_data):
|
||||
super().update(instance, validated_data)
|
||||
return instance
|
||||
|
||||
def create(self, validated_data):
|
||||
mail_account = MailAccount.objects.create(**validated_data)
|
||||
return mail_account
|
||||
|
||||
|
||||
class MailRuleSerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
model = MailRule
|
||||
depth = 1
|
||||
fields = [
|
||||
"id",
|
||||
"name",
|
||||
"account",
|
||||
"folder",
|
||||
"filter_from",
|
||||
"filter_subject",
|
||||
"filter_body",
|
||||
"filter_attachment_filename",
|
||||
"maximum_age",
|
||||
"action",
|
||||
"action_parameter",
|
||||
"assign_title_from",
|
||||
"assign_tags",
|
||||
"assign_correspondent_from",
|
||||
"assign_correspondent",
|
||||
"assign_document_type",
|
||||
"order",
|
||||
"attachment_type",
|
||||
]
|
||||
|
||||
def update(self, instance, validated_data):
|
||||
super().update(instance, validated_data)
|
||||
return instance
|
||||
|
||||
def create(self, validated_data):
|
||||
mail_rule = MailRule.objects.create(**validated_data)
|
||||
return mail_rule
|
||||
|
@ -33,6 +33,8 @@ from packaging import version as packaging_version
|
||||
from paperless import version
|
||||
from paperless.db import GnuPG
|
||||
from paperless.views import StandardPagination
|
||||
from paperless_mail.models import MailAccount
|
||||
from paperless_mail.models import MailRule
|
||||
from rest_framework import parsers
|
||||
from rest_framework.decorators import action
|
||||
from rest_framework.exceptions import NotFound
|
||||
@ -81,6 +83,8 @@ from .serialisers import CorrespondentSerializer
|
||||
from .serialisers import DocumentListSerializer
|
||||
from .serialisers import DocumentSerializer
|
||||
from .serialisers import DocumentTypeSerializer
|
||||
from .serialisers import MailAccountSerializer
|
||||
from .serialisers import MailRuleSerializer
|
||||
from .serialisers import PostDocumentSerializer
|
||||
from .serialisers import SavedViewSerializer
|
||||
from .serialisers import StoragePathSerializer
|
||||
@ -910,3 +914,37 @@ class AcknowledgeTasksView(GenericAPIView):
|
||||
return Response({"result": result})
|
||||
except Exception:
|
||||
return HttpResponseBadRequest()
|
||||
|
||||
|
||||
class MailAccountViewSet(ModelViewSet):
|
||||
model = MailAccount
|
||||
|
||||
queryset = MailAccount.objects.all()
|
||||
serializer_class = MailAccountSerializer
|
||||
pagination_class = StandardPagination
|
||||
permission_classes = (IsAuthenticated,)
|
||||
|
||||
# TODO: user-scoped
|
||||
# def get_queryset(self):
|
||||
# user = self.request.user
|
||||
# return MailAccount.objects.filter(user=user)
|
||||
|
||||
# def perform_create(self, serializer):
|
||||
# serializer.save(user=self.request.user)
|
||||
|
||||
|
||||
class MailRuleViewSet(ModelViewSet):
|
||||
model = MailRule
|
||||
|
||||
queryset = MailRule.objects.all()
|
||||
serializer_class = MailRuleSerializer
|
||||
pagination_class = StandardPagination
|
||||
permission_classes = (IsAuthenticated,)
|
||||
|
||||
# TODO: user-scoped
|
||||
# def get_queryset(self):
|
||||
# user = self.request.user
|
||||
# return MailRule.objects.filter(user=user)
|
||||
|
||||
# def perform_create(self, serializer):
|
||||
# serializer.save(user=self.request.user)
|
||||
|
@ -14,6 +14,8 @@ from documents.views import CorrespondentViewSet
|
||||
from documents.views import DocumentTypeViewSet
|
||||
from documents.views import IndexView
|
||||
from documents.views import LogViewSet
|
||||
from documents.views import MailAccountViewSet
|
||||
from documents.views import MailRuleViewSet
|
||||
from documents.views import PostDocumentView
|
||||
from documents.views import RemoteVersionView
|
||||
from documents.views import SavedViewViewSet
|
||||
@ -39,6 +41,8 @@ api_router.register(r"tags", TagViewSet)
|
||||
api_router.register(r"saved_views", SavedViewViewSet)
|
||||
api_router.register(r"storage_paths", StoragePathViewSet)
|
||||
api_router.register(r"tasks", TasksViewSet, basename="tasks")
|
||||
api_router.register(r"mail_accounts", MailAccountViewSet)
|
||||
api_router.register(r"mail_rules", MailRuleViewSet)
|
||||
|
||||
|
||||
urlpatterns = [
|
||||
|
Loading…
x
Reference in New Issue
Block a user