Get storage path explorer somewhat working
This commit is contained in:
parent
5ae5777467
commit
10ab272df7
@ -370,7 +370,7 @@
|
|||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<a
|
<a
|
||||||
routerLink="/explorer/{{ d.id }}"
|
routerLink="/explorer?spid={{ d.id }}"
|
||||||
title="Edit document"
|
title="Edit document"
|
||||||
i18n-title
|
i18n-title
|
||||||
style="overflow-wrap: anywhere"
|
style="overflow-wrap: anywhere"
|
||||||
@ -386,20 +386,6 @@
|
|||||||
(click)="clickTag(t.id); $event.stopPropagation()"
|
(click)="clickTag(t.id); $event.stopPropagation()"
|
||||||
></app-tag>
|
></app-tag>
|
||||||
</td>
|
</td>
|
||||||
<td *ngIf="notesEnabled" class="d-none d-xl-table-cell">
|
|
||||||
<a
|
|
||||||
*ngIf="d.notes.length"
|
|
||||||
routerLink="/documents/{{ d.id }}/notes"
|
|
||||||
class="btn btn-sm p-0"
|
|
||||||
>
|
|
||||||
<span class="badge rounded-pill bg-light border text-primary">
|
|
||||||
<svg class="metadata-icon ms-1 me-1" fill="currentColor">
|
|
||||||
<use xlink:href="assets/bootstrap-icons.svg#chat-left-text" />
|
|
||||||
</svg>
|
|
||||||
{{ d.notes.length }}</span
|
|
||||||
>
|
|
||||||
</a>
|
|
||||||
</td>
|
|
||||||
<td class="d-none d-xl-table-cell">
|
<td class="d-none d-xl-table-cell">
|
||||||
<ng-container *ngIf="d.document_type">
|
<ng-container *ngIf="d.document_type">
|
||||||
<a
|
<a
|
||||||
|
@ -8,7 +8,16 @@ import {
|
|||||||
} from '@angular/core'
|
} from '@angular/core'
|
||||||
import { ActivatedRoute, Router, convertToParamMap } from '@angular/router'
|
import { ActivatedRoute, Router, convertToParamMap } from '@angular/router'
|
||||||
import { NgbModal } from '@ng-bootstrap/ng-bootstrap'
|
import { NgbModal } from '@ng-bootstrap/ng-bootstrap'
|
||||||
import { Subject, filter, first, map, switchMap, takeUntil } from 'rxjs'
|
import {
|
||||||
|
Subject,
|
||||||
|
filter,
|
||||||
|
first,
|
||||||
|
map,
|
||||||
|
switchMap,
|
||||||
|
take,
|
||||||
|
takeUntil,
|
||||||
|
tap,
|
||||||
|
} from 'rxjs'
|
||||||
import {
|
import {
|
||||||
FilterRule,
|
FilterRule,
|
||||||
filterRulesDiffer,
|
filterRulesDiffer,
|
||||||
@ -34,6 +43,7 @@ import { StoragePathListViewService } from 'src/app/services/storage-path-list-v
|
|||||||
import { ToastService } from 'src/app/services/toast.service'
|
import { ToastService } from 'src/app/services/toast.service'
|
||||||
import { ComponentWithPermissions } from '../with-permissions/with-permissions.component'
|
import { ComponentWithPermissions } from '../with-permissions/with-permissions.component'
|
||||||
import { FilterEditorComponent } from './filter-editor/filter-editor.component'
|
import { FilterEditorComponent } from './filter-editor/filter-editor.component'
|
||||||
|
import { PaperlessStoragePath } from 'src/app/data/paperless-storage-path'
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-explorer',
|
selector: 'app-explorer',
|
||||||
@ -140,44 +150,11 @@ export class ExplorerComponent
|
|||||||
this.list.reload()
|
this.list.reload()
|
||||||
})
|
})
|
||||||
|
|
||||||
this.route.paramMap
|
|
||||||
.pipe(
|
|
||||||
filter((params) => params.has('id')), // only on saved view e.g. /view/id
|
|
||||||
switchMap((params) => {
|
|
||||||
return this.savedViewService
|
|
||||||
.getCached(+params.get('id'))
|
|
||||||
.pipe(map((view) => ({ view })))
|
|
||||||
})
|
|
||||||
)
|
|
||||||
.pipe(takeUntil(this.unsubscribeNotifier))
|
|
||||||
.subscribe(({ view }) => {
|
|
||||||
if (!view) {
|
|
||||||
this.router.navigate(['404'])
|
|
||||||
return
|
|
||||||
}
|
|
||||||
this.unmodifiedSavedView = view
|
|
||||||
this.list.activateSavedViewWithQueryParams(
|
|
||||||
view,
|
|
||||||
convertToParamMap(this.route.snapshot.queryParams)
|
|
||||||
)
|
|
||||||
// this.list.reload()
|
|
||||||
this.unmodifiedFilterRules = view.filter_rules
|
|
||||||
})
|
|
||||||
|
|
||||||
this.route.queryParamMap
|
this.route.queryParamMap
|
||||||
.pipe(
|
.pipe(takeUntil(this.unsubscribeNotifier))
|
||||||
filter(() => !this.route.snapshot.paramMap.has('id')), // only when not on /view/id
|
|
||||||
takeUntil(this.unsubscribeNotifier)
|
|
||||||
)
|
|
||||||
.subscribe((queryParams) => {
|
.subscribe((queryParams) => {
|
||||||
if (queryParams.has('view')) {
|
this.list.loadFromQueryParams(queryParams)
|
||||||
// loading a saved view on /documents
|
this.unmodifiedFilterRules = []
|
||||||
this.loadViewConfig(parseInt(queryParams.get('view')))
|
|
||||||
} else {
|
|
||||||
this.list.activateSavedView(null)
|
|
||||||
this.list.loadFromQueryParams(queryParams)
|
|
||||||
this.unmodifiedFilterRules = []
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -187,19 +164,10 @@ export class ExplorerComponent
|
|||||||
this.unsubscribeNotifier.complete()
|
this.unsubscribeNotifier.complete()
|
||||||
}
|
}
|
||||||
|
|
||||||
loadViewConfig(viewID: number) {
|
openDocumentDetail(storagePath: PaperlessStoragePath) {
|
||||||
this.savedViewService
|
this.router.navigate(['explorer'], {
|
||||||
.getCached(viewID)
|
queryParams: { spid: storagePath.id },
|
||||||
.pipe(first())
|
})
|
||||||
.subscribe((view) => {
|
|
||||||
this.unmodifiedSavedView = view
|
|
||||||
this.list.activateSavedView(view)
|
|
||||||
this.list.reload()
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
openDocumentDetail(document: PaperlessDocument) {
|
|
||||||
this.router.navigate(['documents', document.id])
|
|
||||||
}
|
}
|
||||||
|
|
||||||
toggleSelected(document: PaperlessDocument, event: MouseEvent): void {
|
toggleSelected(document: PaperlessDocument, event: MouseEvent): void {
|
||||||
|
@ -1,10 +1,7 @@
|
|||||||
import { HttpClient } from '@angular/common/http'
|
import { HttpClient } from '@angular/common/http'
|
||||||
import { Injectable } from '@angular/core'
|
import { Injectable } from '@angular/core'
|
||||||
import { Observable, map } from 'rxjs'
|
import { Observable, filter, map, switchMap, tap } from 'rxjs'
|
||||||
import { FilterRule } from 'src/app/data/filter-rule'
|
import { FilterRule } from 'src/app/data/filter-rule'
|
||||||
import { PaperlessDocument } from 'src/app/data/paperless-document'
|
|
||||||
import { PaperlessDocumentMetadata } from 'src/app/data/paperless-document-metadata'
|
|
||||||
import { PaperlessDocumentSuggestions } from 'src/app/data/paperless-document-suggestions'
|
|
||||||
import { PaperlessStoragePath } from 'src/app/data/paperless-storage-path'
|
import { PaperlessStoragePath } from 'src/app/data/paperless-storage-path'
|
||||||
import { Results } from 'src/app/data/results'
|
import { Results } from 'src/app/data/results'
|
||||||
import { queryParamsFromFilterRules } from 'src/app/utils/query-params'
|
import { queryParamsFromFilterRules } from 'src/app/utils/query-params'
|
||||||
@ -26,8 +23,6 @@ interface SelectionData {
|
|||||||
providedIn: 'root',
|
providedIn: 'root',
|
||||||
})
|
})
|
||||||
export class CustomStoragePathService extends AbstractPaperlessService<PaperlessStoragePath> {
|
export class CustomStoragePathService extends AbstractPaperlessService<PaperlessStoragePath> {
|
||||||
private _searchQuery: string
|
|
||||||
|
|
||||||
constructor(http: HttpClient) {
|
constructor(http: HttpClient) {
|
||||||
super(http, 'storage_paths')
|
super(http, 'storage_paths')
|
||||||
}
|
}
|
||||||
@ -38,16 +33,40 @@ export class CustomStoragePathService extends AbstractPaperlessService<Paperless
|
|||||||
sortField?: string,
|
sortField?: string,
|
||||||
sortReverse?: boolean,
|
sortReverse?: boolean,
|
||||||
filterRules?: FilterRule[],
|
filterRules?: FilterRule[],
|
||||||
extraParams = {}
|
extraParams = {},
|
||||||
|
parentStoragePathId?: number
|
||||||
): Observable<Results<PaperlessStoragePath>> {
|
): Observable<Results<PaperlessStoragePath>> {
|
||||||
return this.list(
|
const params = Object.assign(
|
||||||
page,
|
extraParams,
|
||||||
pageSize,
|
queryParamsFromFilterRules(filterRules)
|
||||||
sortField,
|
)
|
||||||
sortReverse,
|
if (parentStoragePathId !== null && parentStoragePathId !== undefined) {
|
||||||
Object.assign(extraParams, queryParamsFromFilterRules(filterRules))
|
return this.get(parentStoragePathId).pipe(
|
||||||
).pipe(
|
switchMap((storagePath) => {
|
||||||
|
params.path__istartswith = storagePath.path
|
||||||
|
return this.list(page, pageSize, sortField, sortReverse, params).pipe(
|
||||||
|
map((results) => {
|
||||||
|
results.results = results.results.filter((s) => {
|
||||||
|
const isNotParent = s.id !== parentStoragePathId
|
||||||
|
const isDirectChild =
|
||||||
|
s.path
|
||||||
|
.replace(storagePath.path, '')
|
||||||
|
.split('/')
|
||||||
|
.filter((s) => !!s).length === 1
|
||||||
|
return isNotParent && isDirectChild
|
||||||
|
})
|
||||||
|
return results
|
||||||
|
})
|
||||||
|
)
|
||||||
|
})
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.list(page, pageSize, sortField, sortReverse, params).pipe(
|
||||||
map((results) => {
|
map((results) => {
|
||||||
|
results.results = results.results.filter(
|
||||||
|
(s) => s.path.split('/').length === 1
|
||||||
|
)
|
||||||
return results
|
return results
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
@ -58,79 +77,4 @@ export class CustomStoragePathService extends AbstractPaperlessService<Paperless
|
|||||||
fields: 'id',
|
fields: 'id',
|
||||||
}).pipe(map((response) => response.results.map((doc) => doc.id)))
|
}).pipe(map((response) => response.results.map((doc) => doc.id)))
|
||||||
}
|
}
|
||||||
|
|
||||||
getPreviewUrl(id: number, original: boolean = false): string {
|
|
||||||
let url = this.getResourceUrl(id, 'preview')
|
|
||||||
if (this._searchQuery) url += `#search="${this._searchQuery}"`
|
|
||||||
if (original) {
|
|
||||||
url += '?original=true'
|
|
||||||
}
|
|
||||||
return url
|
|
||||||
}
|
|
||||||
|
|
||||||
getThumbUrl(id: number): string {
|
|
||||||
return this.getResourceUrl(id, 'thumb')
|
|
||||||
}
|
|
||||||
|
|
||||||
getDownloadUrl(id: number, original: boolean = false): string {
|
|
||||||
let url = this.getResourceUrl(id, 'download')
|
|
||||||
if (original) {
|
|
||||||
url += '?original=true'
|
|
||||||
}
|
|
||||||
return url
|
|
||||||
}
|
|
||||||
|
|
||||||
update(o: PaperlessDocument): Observable<PaperlessDocument> {
|
|
||||||
// we want to only set created_date
|
|
||||||
o.created = undefined
|
|
||||||
return super.update(o)
|
|
||||||
}
|
|
||||||
|
|
||||||
uploadDocument(formData) {
|
|
||||||
return this.http.post(
|
|
||||||
this.getResourceUrl(null, 'post_document'),
|
|
||||||
formData,
|
|
||||||
{ reportProgress: true, observe: 'events' }
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
getMetadata(id: number): Observable<PaperlessDocumentMetadata> {
|
|
||||||
return this.http.get<PaperlessDocumentMetadata>(
|
|
||||||
this.getResourceUrl(id, 'metadata')
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
bulkEdit(ids: number[], method: string, args: any) {
|
|
||||||
return this.http.post(this.getResourceUrl(null, 'bulk_edit'), {
|
|
||||||
documents: ids,
|
|
||||||
method: method,
|
|
||||||
parameters: args,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
getSuggestions(id: number): Observable<PaperlessDocumentSuggestions> {
|
|
||||||
return this.http.get<PaperlessDocumentSuggestions>(
|
|
||||||
this.getResourceUrl(id, 'suggestions')
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
bulkDownload(
|
|
||||||
ids: number[],
|
|
||||||
content = 'both',
|
|
||||||
useFilenameFormatting: boolean = false
|
|
||||||
) {
|
|
||||||
return this.http.post(
|
|
||||||
this.getResourceUrl(null, 'bulk_download'),
|
|
||||||
{
|
|
||||||
documents: ids,
|
|
||||||
content: content,
|
|
||||||
follow_formatting: useFilenameFormatting,
|
|
||||||
},
|
|
||||||
{ responseType: 'blob' }
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
public set searchQuery(query: string) {
|
|
||||||
this._searchQuery = query
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -57,6 +57,8 @@ export interface ListViewState {
|
|||||||
* Contains the IDs of all selected documents.
|
* Contains the IDs of all selected documents.
|
||||||
*/
|
*/
|
||||||
selected?: Set<number>
|
selected?: Set<number>
|
||||||
|
|
||||||
|
storagePathId?: number | null
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -108,6 +110,7 @@ export class StoragePathListViewService {
|
|||||||
sortReverse: true,
|
sortReverse: true,
|
||||||
filterRules: [],
|
filterRules: [],
|
||||||
selected: new Set<number>(),
|
selected: new Set<number>(),
|
||||||
|
storagePathId: null,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -121,56 +124,22 @@ export class StoragePathListViewService {
|
|||||||
return this.listViewStates.get(this._activeSavedViewId)
|
return this.listViewStates.get(this._activeSavedViewId)
|
||||||
}
|
}
|
||||||
|
|
||||||
activateSavedView(view: PaperlessSavedView) {
|
|
||||||
this.rangeSelectionAnchorIndex = this.lastRangeSelectionToIndex = null
|
|
||||||
if (view) {
|
|
||||||
this._activeSavedViewId = view.id
|
|
||||||
this.loadSavedView(view)
|
|
||||||
} else {
|
|
||||||
this._activeSavedViewId = null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
activateSavedViewWithQueryParams(
|
|
||||||
view: PaperlessSavedView,
|
|
||||||
queryParams: ParamMap
|
|
||||||
) {
|
|
||||||
const viewState = paramsToViewState(queryParams)
|
|
||||||
this.activateSavedView(view)
|
|
||||||
this.currentPage = viewState.currentPage
|
|
||||||
}
|
|
||||||
|
|
||||||
loadSavedView(view: PaperlessSavedView, closeCurrentView: boolean = false) {
|
|
||||||
if (closeCurrentView) {
|
|
||||||
this._activeSavedViewId = null
|
|
||||||
}
|
|
||||||
|
|
||||||
this.activeListViewState.filterRules = cloneFilterRules(view.filter_rules)
|
|
||||||
this.activeListViewState.sortField = view.sort_field
|
|
||||||
this.activeListViewState.sortReverse = view.sort_reverse
|
|
||||||
if (this._activeSavedViewId) {
|
|
||||||
this.activeListViewState.title = view.name
|
|
||||||
}
|
|
||||||
|
|
||||||
this.reduceSelectionToFilter()
|
|
||||||
|
|
||||||
if (!this.router.routerState.snapshot.url.includes('/view/')) {
|
|
||||||
this.router.navigate(['view', view.id])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
loadFromQueryParams(queryParams: ParamMap) {
|
loadFromQueryParams(queryParams: ParamMap) {
|
||||||
const paramsEmpty: boolean = queryParams.keys.length == 0
|
const isParamsEmpty: boolean = queryParams.keys.length == 0
|
||||||
let newState: ListViewState = this.listViewStates.get(
|
let newState: ListViewState & { storagePathId?: number } =
|
||||||
this._activeSavedViewId
|
this.listViewStates.get(this._activeSavedViewId)
|
||||||
)
|
if (!isParamsEmpty) {
|
||||||
if (!paramsEmpty) newState = paramsToViewState(queryParams)
|
newState = paramsToViewState(queryParams)
|
||||||
|
if (queryParams.has('spid')) {
|
||||||
|
newState.storagePathId = parseInt(queryParams.get('spid'))
|
||||||
|
}
|
||||||
|
}
|
||||||
if (newState == undefined) newState = this.defaultListViewState() // if nothing in local storage
|
if (newState == undefined) newState = this.defaultListViewState() // if nothing in local storage
|
||||||
|
|
||||||
// only reload if things have changed
|
// only reload if things have changed
|
||||||
if (
|
if (
|
||||||
!this.initialized ||
|
!this.initialized ||
|
||||||
paramsEmpty ||
|
isParamsEmpty ||
|
||||||
this.activeListViewState.sortField !== newState.sortField ||
|
this.activeListViewState.sortField !== newState.sortField ||
|
||||||
this.activeListViewState.sortReverse !== newState.sortReverse ||
|
this.activeListViewState.sortReverse !== newState.sortReverse ||
|
||||||
this.activeListViewState.currentPage !== newState.currentPage ||
|
this.activeListViewState.currentPage !== newState.currentPage ||
|
||||||
@ -183,7 +152,8 @@ export class StoragePathListViewService {
|
|||||||
this.activeListViewState.sortField = newState.sortField
|
this.activeListViewState.sortField = newState.sortField
|
||||||
this.activeListViewState.sortReverse = newState.sortReverse
|
this.activeListViewState.sortReverse = newState.sortReverse
|
||||||
this.activeListViewState.currentPage = newState.currentPage
|
this.activeListViewState.currentPage = newState.currentPage
|
||||||
this.reload(null, paramsEmpty) // update the params if there arent any
|
this.activeListViewState.storagePathId = newState.storagePathId
|
||||||
|
this.reload(null, isParamsEmpty) // update the params if there arent any
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -198,11 +168,12 @@ export class StoragePathListViewService {
|
|||||||
activeListViewState.sortField,
|
activeListViewState.sortField,
|
||||||
activeListViewState.sortReverse,
|
activeListViewState.sortReverse,
|
||||||
activeListViewState.filterRules,
|
activeListViewState.filterRules,
|
||||||
{ truncate_content: true }
|
{ truncate_content: true },
|
||||||
|
activeListViewState.storagePathId
|
||||||
)
|
)
|
||||||
.subscribe({
|
.subscribe({
|
||||||
next: (result) => {
|
next: (result) => {
|
||||||
console.log('list filtered result:', result)
|
console.log('result:', result)
|
||||||
this.initialized = true
|
this.initialized = true
|
||||||
this.isReloading = false
|
this.isReloading = false
|
||||||
activeListViewState.collectionSize = result.count
|
activeListViewState.collectionSize = result.count
|
||||||
|
@ -1,159 +1,159 @@
|
|||||||
from django.db.models import Q
|
from django.db.models import Q
|
||||||
from django_filters.rest_framework import BooleanFilter
|
from django_filters.rest_framework import BooleanFilter
|
||||||
from django_filters.rest_framework import Filter
|
from django_filters.rest_framework import Filter
|
||||||
from django_filters.rest_framework import FilterSet
|
from django_filters.rest_framework import FilterSet
|
||||||
from rest_framework_guardian.filters import ObjectPermissionsFilter
|
from rest_framework_guardian.filters import ObjectPermissionsFilter
|
||||||
|
|
||||||
from .models import Correspondent
|
from .models import Correspondent
|
||||||
from .models import Document
|
from .models import Document
|
||||||
from .models import DocumentType
|
from .models import DocumentType
|
||||||
from .models import Log
|
from .models import Log
|
||||||
from .models import StoragePath
|
from .models import StoragePath
|
||||||
from .models import Tag
|
from .models import Tag
|
||||||
|
|
||||||
|
|
||||||
CHAR_KWARGS = ["istartswith", "iendswith", "icontains", "iexact"]
|
CHAR_KWARGS = ["istartswith", "iendswith", "icontains", "iexact"]
|
||||||
ID_KWARGS = ["in", "exact"]
|
ID_KWARGS = ["in", "exact"]
|
||||||
INT_KWARGS = ["exact", "gt", "gte", "lt", "lte", "isnull"]
|
INT_KWARGS = ["exact", "gt", "gte", "lt", "lte", "isnull"]
|
||||||
DATE_KWARGS = ["year", "month", "day", "date__gt", "gt", "date__lt", "lt"]
|
DATE_KWARGS = ["year", "month", "day", "date__gt", "gt", "date__lt", "lt"]
|
||||||
|
|
||||||
|
|
||||||
class CorrespondentFilterSet(FilterSet):
|
class CorrespondentFilterSet(FilterSet):
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Correspondent
|
model = Correspondent
|
||||||
fields = {"name": CHAR_KWARGS}
|
fields = {"name": CHAR_KWARGS}
|
||||||
|
|
||||||
|
|
||||||
class TagFilterSet(FilterSet):
|
class TagFilterSet(FilterSet):
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Tag
|
model = Tag
|
||||||
fields = {"name": CHAR_KWARGS}
|
fields = {"name": CHAR_KWARGS}
|
||||||
|
|
||||||
|
|
||||||
class DocumentTypeFilterSet(FilterSet):
|
class DocumentTypeFilterSet(FilterSet):
|
||||||
class Meta:
|
class Meta:
|
||||||
model = DocumentType
|
model = DocumentType
|
||||||
fields = {"name": CHAR_KWARGS}
|
fields = {"name": CHAR_KWARGS}
|
||||||
|
|
||||||
|
|
||||||
class ObjectFilter(Filter):
|
class ObjectFilter(Filter):
|
||||||
def __init__(self, exclude=False, in_list=False, field_name=""):
|
def __init__(self, exclude=False, in_list=False, field_name=""):
|
||||||
super().__init__()
|
super().__init__()
|
||||||
self.exclude = exclude
|
self.exclude = exclude
|
||||||
self.in_list = in_list
|
self.in_list = in_list
|
||||||
self.field_name = field_name
|
self.field_name = field_name
|
||||||
|
|
||||||
def filter(self, qs, value):
|
def filter(self, qs, value):
|
||||||
if not value:
|
if not value:
|
||||||
return qs
|
return qs
|
||||||
|
|
||||||
try:
|
try:
|
||||||
object_ids = [int(x) for x in value.split(",")]
|
object_ids = [int(x) for x in value.split(",")]
|
||||||
except ValueError:
|
except ValueError:
|
||||||
return qs
|
return qs
|
||||||
|
|
||||||
if self.in_list:
|
if self.in_list:
|
||||||
qs = qs.filter(**{f"{self.field_name}__id__in": object_ids}).distinct()
|
qs = qs.filter(**{f"{self.field_name}__id__in": object_ids}).distinct()
|
||||||
else:
|
else:
|
||||||
for obj_id in object_ids:
|
for obj_id in object_ids:
|
||||||
if self.exclude:
|
if self.exclude:
|
||||||
qs = qs.exclude(**{f"{self.field_name}__id": obj_id})
|
qs = qs.exclude(**{f"{self.field_name}__id": obj_id})
|
||||||
else:
|
else:
|
||||||
qs = qs.filter(**{f"{self.field_name}__id": obj_id})
|
qs = qs.filter(**{f"{self.field_name}__id": obj_id})
|
||||||
|
|
||||||
return qs
|
return qs
|
||||||
|
|
||||||
|
|
||||||
class InboxFilter(Filter):
|
class InboxFilter(Filter):
|
||||||
def filter(self, qs, value):
|
def filter(self, qs, value):
|
||||||
if value == "true":
|
if value == "true":
|
||||||
return qs.filter(tags__is_inbox_tag=True)
|
return qs.filter(tags__is_inbox_tag=True)
|
||||||
elif value == "false":
|
elif value == "false":
|
||||||
return qs.exclude(tags__is_inbox_tag=True)
|
return qs.exclude(tags__is_inbox_tag=True)
|
||||||
else:
|
else:
|
||||||
return qs
|
return qs
|
||||||
|
|
||||||
|
|
||||||
class TitleContentFilter(Filter):
|
class TitleContentFilter(Filter):
|
||||||
def filter(self, qs, value):
|
def filter(self, qs, value):
|
||||||
if value:
|
if value:
|
||||||
return qs.filter(Q(title__icontains=value) | Q(content__icontains=value))
|
return qs.filter(Q(title__icontains=value) | Q(content__icontains=value))
|
||||||
else:
|
else:
|
||||||
return qs
|
return qs
|
||||||
|
|
||||||
|
|
||||||
class DocumentFilterSet(FilterSet):
|
class DocumentFilterSet(FilterSet):
|
||||||
|
|
||||||
is_tagged = BooleanFilter(
|
is_tagged = BooleanFilter(
|
||||||
label="Is tagged",
|
label="Is tagged",
|
||||||
field_name="tags",
|
field_name="tags",
|
||||||
lookup_expr="isnull",
|
lookup_expr="isnull",
|
||||||
exclude=True,
|
exclude=True,
|
||||||
)
|
)
|
||||||
|
|
||||||
tags__id__all = ObjectFilter(field_name="tags")
|
tags__id__all = ObjectFilter(field_name="tags")
|
||||||
|
|
||||||
tags__id__none = ObjectFilter(field_name="tags", exclude=True)
|
tags__id__none = ObjectFilter(field_name="tags", exclude=True)
|
||||||
|
|
||||||
tags__id__in = ObjectFilter(field_name="tags", in_list=True)
|
tags__id__in = ObjectFilter(field_name="tags", in_list=True)
|
||||||
|
|
||||||
correspondent__id__none = ObjectFilter(field_name="correspondent", exclude=True)
|
correspondent__id__none = ObjectFilter(field_name="correspondent", exclude=True)
|
||||||
|
|
||||||
document_type__id__none = ObjectFilter(field_name="document_type", exclude=True)
|
document_type__id__none = ObjectFilter(field_name="document_type", exclude=True)
|
||||||
|
|
||||||
storage_path__id__none = ObjectFilter(field_name="storage_path", exclude=True)
|
storage_path__id__none = ObjectFilter(field_name="storage_path", exclude=True)
|
||||||
|
|
||||||
is_in_inbox = InboxFilter()
|
is_in_inbox = InboxFilter()
|
||||||
|
|
||||||
title_content = TitleContentFilter()
|
title_content = TitleContentFilter()
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Document
|
model = Document
|
||||||
fields = {
|
fields = {
|
||||||
"title": CHAR_KWARGS,
|
"title": CHAR_KWARGS,
|
||||||
"content": CHAR_KWARGS,
|
"content": CHAR_KWARGS,
|
||||||
"archive_serial_number": INT_KWARGS,
|
"archive_serial_number": INT_KWARGS,
|
||||||
"created": DATE_KWARGS,
|
"created": DATE_KWARGS,
|
||||||
"added": DATE_KWARGS,
|
"added": DATE_KWARGS,
|
||||||
"modified": DATE_KWARGS,
|
"modified": DATE_KWARGS,
|
||||||
"correspondent": ["isnull"],
|
"correspondent": ["isnull"],
|
||||||
"correspondent__id": ID_KWARGS,
|
"correspondent__id": ID_KWARGS,
|
||||||
"correspondent__name": CHAR_KWARGS,
|
"correspondent__name": CHAR_KWARGS,
|
||||||
"tags__id": ID_KWARGS,
|
"tags__id": ID_KWARGS,
|
||||||
"tags__name": CHAR_KWARGS,
|
"tags__name": CHAR_KWARGS,
|
||||||
"document_type": ["isnull"],
|
"document_type": ["isnull"],
|
||||||
"document_type__id": ID_KWARGS,
|
"document_type__id": ID_KWARGS,
|
||||||
"document_type__name": CHAR_KWARGS,
|
"document_type__name": CHAR_KWARGS,
|
||||||
"storage_path": ["isnull"],
|
"storage_path": ["isnull"],
|
||||||
"storage_path__id": ID_KWARGS,
|
"storage_path__id": ID_KWARGS,
|
||||||
"storage_path__name": CHAR_KWARGS,
|
"storage_path__name": CHAR_KWARGS,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
class LogFilterSet(FilterSet):
|
class LogFilterSet(FilterSet):
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Log
|
model = Log
|
||||||
fields = {"level": INT_KWARGS, "created": DATE_KWARGS, "group": ID_KWARGS}
|
fields = {"level": INT_KWARGS, "created": DATE_KWARGS, "group": ID_KWARGS}
|
||||||
|
|
||||||
|
|
||||||
class StoragePathFilterSet(FilterSet):
|
class StoragePathFilterSet(FilterSet):
|
||||||
class Meta:
|
class Meta:
|
||||||
model = StoragePath
|
model = StoragePath
|
||||||
fields = {
|
fields = {
|
||||||
"name": CHAR_KWARGS,
|
"name": CHAR_KWARGS,
|
||||||
"path": CHAR_KWARGS,
|
"path": CHAR_KWARGS,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
class ObjectOwnedOrGrantedPermissionsFilter(ObjectPermissionsFilter):
|
class ObjectOwnedOrGrantedPermissionsFilter(ObjectPermissionsFilter):
|
||||||
"""
|
"""
|
||||||
A filter backend that limits results to those where the requesting user
|
A filter backend that limits results to those where the requesting user
|
||||||
has read object level permissions, owns the objects, or objects without
|
has read object level permissions, owns the objects, or objects without
|
||||||
an owner (for backwards compat)
|
an owner (for backwards compat)
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def filter_queryset(self, request, queryset, view):
|
def filter_queryset(self, request, queryset, view):
|
||||||
objects_with_perms = super().filter_queryset(request, queryset, view)
|
objects_with_perms = super().filter_queryset(request, queryset, view)
|
||||||
objects_owned = queryset.filter(owner=request.user)
|
objects_owned = queryset.filter(owner=request.user)
|
||||||
objects_unowned = queryset.filter(owner__isnull=True)
|
objects_unowned = queryset.filter(owner__isnull=True)
|
||||||
return objects_with_perms | objects_owned | objects_unowned
|
return objects_with_perms | objects_owned | objects_unowned
|
||||||
|
Loading…
x
Reference in New Issue
Block a user