Get storage path explorer somewhat working
This commit is contained in:
parent
5ae5777467
commit
10ab272df7
@ -370,7 +370,7 @@
|
||||
</td>
|
||||
<td>
|
||||
<a
|
||||
routerLink="/explorer/{{ d.id }}"
|
||||
routerLink="/explorer?spid={{ d.id }}"
|
||||
title="Edit document"
|
||||
i18n-title
|
||||
style="overflow-wrap: anywhere"
|
||||
@ -386,20 +386,6 @@
|
||||
(click)="clickTag(t.id); $event.stopPropagation()"
|
||||
></app-tag>
|
||||
</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">
|
||||
<ng-container *ngIf="d.document_type">
|
||||
<a
|
||||
|
@ -8,7 +8,16 @@ import {
|
||||
} from '@angular/core'
|
||||
import { ActivatedRoute, Router, convertToParamMap } from '@angular/router'
|
||||
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 {
|
||||
FilterRule,
|
||||
filterRulesDiffer,
|
||||
@ -34,6 +43,7 @@ import { StoragePathListViewService } from 'src/app/services/storage-path-list-v
|
||||
import { ToastService } from 'src/app/services/toast.service'
|
||||
import { ComponentWithPermissions } from '../with-permissions/with-permissions.component'
|
||||
import { FilterEditorComponent } from './filter-editor/filter-editor.component'
|
||||
import { PaperlessStoragePath } from 'src/app/data/paperless-storage-path'
|
||||
|
||||
@Component({
|
||||
selector: 'app-explorer',
|
||||
@ -140,44 +150,11 @@ export class ExplorerComponent
|
||||
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
|
||||
.pipe(
|
||||
filter(() => !this.route.snapshot.paramMap.has('id')), // only when not on /view/id
|
||||
takeUntil(this.unsubscribeNotifier)
|
||||
)
|
||||
.pipe(takeUntil(this.unsubscribeNotifier))
|
||||
.subscribe((queryParams) => {
|
||||
if (queryParams.has('view')) {
|
||||
// loading a saved view on /documents
|
||||
this.loadViewConfig(parseInt(queryParams.get('view')))
|
||||
} else {
|
||||
this.list.activateSavedView(null)
|
||||
this.list.loadFromQueryParams(queryParams)
|
||||
this.unmodifiedFilterRules = []
|
||||
}
|
||||
this.list.loadFromQueryParams(queryParams)
|
||||
this.unmodifiedFilterRules = []
|
||||
})
|
||||
}
|
||||
|
||||
@ -187,19 +164,10 @@ export class ExplorerComponent
|
||||
this.unsubscribeNotifier.complete()
|
||||
}
|
||||
|
||||
loadViewConfig(viewID: number) {
|
||||
this.savedViewService
|
||||
.getCached(viewID)
|
||||
.pipe(first())
|
||||
.subscribe((view) => {
|
||||
this.unmodifiedSavedView = view
|
||||
this.list.activateSavedView(view)
|
||||
this.list.reload()
|
||||
})
|
||||
}
|
||||
|
||||
openDocumentDetail(document: PaperlessDocument) {
|
||||
this.router.navigate(['documents', document.id])
|
||||
openDocumentDetail(storagePath: PaperlessStoragePath) {
|
||||
this.router.navigate(['explorer'], {
|
||||
queryParams: { spid: storagePath.id },
|
||||
})
|
||||
}
|
||||
|
||||
toggleSelected(document: PaperlessDocument, event: MouseEvent): void {
|
||||
|
@ -1,10 +1,7 @@
|
||||
import { HttpClient } from '@angular/common/http'
|
||||
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 { 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 { Results } from 'src/app/data/results'
|
||||
import { queryParamsFromFilterRules } from 'src/app/utils/query-params'
|
||||
@ -26,8 +23,6 @@ interface SelectionData {
|
||||
providedIn: 'root',
|
||||
})
|
||||
export class CustomStoragePathService extends AbstractPaperlessService<PaperlessStoragePath> {
|
||||
private _searchQuery: string
|
||||
|
||||
constructor(http: HttpClient) {
|
||||
super(http, 'storage_paths')
|
||||
}
|
||||
@ -38,16 +33,40 @@ export class CustomStoragePathService extends AbstractPaperlessService<Paperless
|
||||
sortField?: string,
|
||||
sortReverse?: boolean,
|
||||
filterRules?: FilterRule[],
|
||||
extraParams = {}
|
||||
extraParams = {},
|
||||
parentStoragePathId?: number
|
||||
): Observable<Results<PaperlessStoragePath>> {
|
||||
return this.list(
|
||||
page,
|
||||
pageSize,
|
||||
sortField,
|
||||
sortReverse,
|
||||
Object.assign(extraParams, queryParamsFromFilterRules(filterRules))
|
||||
).pipe(
|
||||
const params = Object.assign(
|
||||
extraParams,
|
||||
queryParamsFromFilterRules(filterRules)
|
||||
)
|
||||
if (parentStoragePathId !== null && parentStoragePathId !== undefined) {
|
||||
return this.get(parentStoragePathId).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) => {
|
||||
results.results = results.results.filter(
|
||||
(s) => s.path.split('/').length === 1
|
||||
)
|
||||
return results
|
||||
})
|
||||
)
|
||||
@ -58,79 +77,4 @@ export class CustomStoragePathService extends AbstractPaperlessService<Paperless
|
||||
fields: '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.
|
||||
*/
|
||||
selected?: Set<number>
|
||||
|
||||
storagePathId?: number | null
|
||||
}
|
||||
|
||||
/**
|
||||
@ -108,6 +110,7 @@ export class StoragePathListViewService {
|
||||
sortReverse: true,
|
||||
filterRules: [],
|
||||
selected: new Set<number>(),
|
||||
storagePathId: null,
|
||||
}
|
||||
}
|
||||
|
||||
@ -121,56 +124,22 @@ export class StoragePathListViewService {
|
||||
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) {
|
||||
const paramsEmpty: boolean = queryParams.keys.length == 0
|
||||
let newState: ListViewState = this.listViewStates.get(
|
||||
this._activeSavedViewId
|
||||
)
|
||||
if (!paramsEmpty) newState = paramsToViewState(queryParams)
|
||||
const isParamsEmpty: boolean = queryParams.keys.length == 0
|
||||
let newState: ListViewState & { storagePathId?: number } =
|
||||
this.listViewStates.get(this._activeSavedViewId)
|
||||
if (!isParamsEmpty) {
|
||||
newState = paramsToViewState(queryParams)
|
||||
if (queryParams.has('spid')) {
|
||||
newState.storagePathId = parseInt(queryParams.get('spid'))
|
||||
}
|
||||
}
|
||||
if (newState == undefined) newState = this.defaultListViewState() // if nothing in local storage
|
||||
|
||||
// only reload if things have changed
|
||||
if (
|
||||
!this.initialized ||
|
||||
paramsEmpty ||
|
||||
isParamsEmpty ||
|
||||
this.activeListViewState.sortField !== newState.sortField ||
|
||||
this.activeListViewState.sortReverse !== newState.sortReverse ||
|
||||
this.activeListViewState.currentPage !== newState.currentPage ||
|
||||
@ -183,7 +152,8 @@ export class StoragePathListViewService {
|
||||
this.activeListViewState.sortField = newState.sortField
|
||||
this.activeListViewState.sortReverse = newState.sortReverse
|
||||
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.sortReverse,
|
||||
activeListViewState.filterRules,
|
||||
{ truncate_content: true }
|
||||
{ truncate_content: true },
|
||||
activeListViewState.storagePathId
|
||||
)
|
||||
.subscribe({
|
||||
next: (result) => {
|
||||
console.log('list filtered result:', result)
|
||||
console.log('result:', result)
|
||||
this.initialized = true
|
||||
this.isReloading = false
|
||||
activeListViewState.collectionSize = result.count
|
||||
|
@ -1,159 +1,159 @@
|
||||
from django.db.models import Q
|
||||
from django_filters.rest_framework import BooleanFilter
|
||||
from django_filters.rest_framework import Filter
|
||||
from django_filters.rest_framework import FilterSet
|
||||
from rest_framework_guardian.filters import ObjectPermissionsFilter
|
||||
|
||||
from .models import Correspondent
|
||||
from .models import Document
|
||||
from .models import DocumentType
|
||||
from .models import Log
|
||||
from .models import StoragePath
|
||||
from .models import Tag
|
||||
|
||||
|
||||
CHAR_KWARGS = ["istartswith", "iendswith", "icontains", "iexact"]
|
||||
ID_KWARGS = ["in", "exact"]
|
||||
INT_KWARGS = ["exact", "gt", "gte", "lt", "lte", "isnull"]
|
||||
DATE_KWARGS = ["year", "month", "day", "date__gt", "gt", "date__lt", "lt"]
|
||||
|
||||
|
||||
class CorrespondentFilterSet(FilterSet):
|
||||
class Meta:
|
||||
model = Correspondent
|
||||
fields = {"name": CHAR_KWARGS}
|
||||
|
||||
|
||||
class TagFilterSet(FilterSet):
|
||||
class Meta:
|
||||
model = Tag
|
||||
fields = {"name": CHAR_KWARGS}
|
||||
|
||||
|
||||
class DocumentTypeFilterSet(FilterSet):
|
||||
class Meta:
|
||||
model = DocumentType
|
||||
fields = {"name": CHAR_KWARGS}
|
||||
|
||||
|
||||
class ObjectFilter(Filter):
|
||||
def __init__(self, exclude=False, in_list=False, field_name=""):
|
||||
super().__init__()
|
||||
self.exclude = exclude
|
||||
self.in_list = in_list
|
||||
self.field_name = field_name
|
||||
|
||||
def filter(self, qs, value):
|
||||
if not value:
|
||||
return qs
|
||||
|
||||
try:
|
||||
object_ids = [int(x) for x in value.split(",")]
|
||||
except ValueError:
|
||||
return qs
|
||||
|
||||
if self.in_list:
|
||||
qs = qs.filter(**{f"{self.field_name}__id__in": object_ids}).distinct()
|
||||
else:
|
||||
for obj_id in object_ids:
|
||||
if self.exclude:
|
||||
qs = qs.exclude(**{f"{self.field_name}__id": obj_id})
|
||||
else:
|
||||
qs = qs.filter(**{f"{self.field_name}__id": obj_id})
|
||||
|
||||
return qs
|
||||
|
||||
|
||||
class InboxFilter(Filter):
|
||||
def filter(self, qs, value):
|
||||
if value == "true":
|
||||
return qs.filter(tags__is_inbox_tag=True)
|
||||
elif value == "false":
|
||||
return qs.exclude(tags__is_inbox_tag=True)
|
||||
else:
|
||||
return qs
|
||||
|
||||
|
||||
class TitleContentFilter(Filter):
|
||||
def filter(self, qs, value):
|
||||
if value:
|
||||
return qs.filter(Q(title__icontains=value) | Q(content__icontains=value))
|
||||
else:
|
||||
return qs
|
||||
|
||||
|
||||
class DocumentFilterSet(FilterSet):
|
||||
|
||||
is_tagged = BooleanFilter(
|
||||
label="Is tagged",
|
||||
field_name="tags",
|
||||
lookup_expr="isnull",
|
||||
exclude=True,
|
||||
)
|
||||
|
||||
tags__id__all = ObjectFilter(field_name="tags")
|
||||
|
||||
tags__id__none = ObjectFilter(field_name="tags", exclude=True)
|
||||
|
||||
tags__id__in = ObjectFilter(field_name="tags", in_list=True)
|
||||
|
||||
correspondent__id__none = ObjectFilter(field_name="correspondent", exclude=True)
|
||||
|
||||
document_type__id__none = ObjectFilter(field_name="document_type", exclude=True)
|
||||
|
||||
storage_path__id__none = ObjectFilter(field_name="storage_path", exclude=True)
|
||||
|
||||
is_in_inbox = InboxFilter()
|
||||
|
||||
title_content = TitleContentFilter()
|
||||
|
||||
class Meta:
|
||||
model = Document
|
||||
fields = {
|
||||
"title": CHAR_KWARGS,
|
||||
"content": CHAR_KWARGS,
|
||||
"archive_serial_number": INT_KWARGS,
|
||||
"created": DATE_KWARGS,
|
||||
"added": DATE_KWARGS,
|
||||
"modified": DATE_KWARGS,
|
||||
"correspondent": ["isnull"],
|
||||
"correspondent__id": ID_KWARGS,
|
||||
"correspondent__name": CHAR_KWARGS,
|
||||
"tags__id": ID_KWARGS,
|
||||
"tags__name": CHAR_KWARGS,
|
||||
"document_type": ["isnull"],
|
||||
"document_type__id": ID_KWARGS,
|
||||
"document_type__name": CHAR_KWARGS,
|
||||
"storage_path": ["isnull"],
|
||||
"storage_path__id": ID_KWARGS,
|
||||
"storage_path__name": CHAR_KWARGS,
|
||||
}
|
||||
|
||||
|
||||
class LogFilterSet(FilterSet):
|
||||
class Meta:
|
||||
model = Log
|
||||
fields = {"level": INT_KWARGS, "created": DATE_KWARGS, "group": ID_KWARGS}
|
||||
|
||||
|
||||
class StoragePathFilterSet(FilterSet):
|
||||
class Meta:
|
||||
model = StoragePath
|
||||
fields = {
|
||||
"name": CHAR_KWARGS,
|
||||
"path": CHAR_KWARGS,
|
||||
}
|
||||
|
||||
|
||||
class ObjectOwnedOrGrantedPermissionsFilter(ObjectPermissionsFilter):
|
||||
"""
|
||||
A filter backend that limits results to those where the requesting user
|
||||
has read object level permissions, owns the objects, or objects without
|
||||
an owner (for backwards compat)
|
||||
"""
|
||||
|
||||
def filter_queryset(self, request, queryset, view):
|
||||
objects_with_perms = super().filter_queryset(request, queryset, view)
|
||||
objects_owned = queryset.filter(owner=request.user)
|
||||
objects_unowned = queryset.filter(owner__isnull=True)
|
||||
return objects_with_perms | objects_owned | objects_unowned
|
||||
from django.db.models import Q
|
||||
from django_filters.rest_framework import BooleanFilter
|
||||
from django_filters.rest_framework import Filter
|
||||
from django_filters.rest_framework import FilterSet
|
||||
from rest_framework_guardian.filters import ObjectPermissionsFilter
|
||||
|
||||
from .models import Correspondent
|
||||
from .models import Document
|
||||
from .models import DocumentType
|
||||
from .models import Log
|
||||
from .models import StoragePath
|
||||
from .models import Tag
|
||||
|
||||
|
||||
CHAR_KWARGS = ["istartswith", "iendswith", "icontains", "iexact"]
|
||||
ID_KWARGS = ["in", "exact"]
|
||||
INT_KWARGS = ["exact", "gt", "gte", "lt", "lte", "isnull"]
|
||||
DATE_KWARGS = ["year", "month", "day", "date__gt", "gt", "date__lt", "lt"]
|
||||
|
||||
|
||||
class CorrespondentFilterSet(FilterSet):
|
||||
class Meta:
|
||||
model = Correspondent
|
||||
fields = {"name": CHAR_KWARGS}
|
||||
|
||||
|
||||
class TagFilterSet(FilterSet):
|
||||
class Meta:
|
||||
model = Tag
|
||||
fields = {"name": CHAR_KWARGS}
|
||||
|
||||
|
||||
class DocumentTypeFilterSet(FilterSet):
|
||||
class Meta:
|
||||
model = DocumentType
|
||||
fields = {"name": CHAR_KWARGS}
|
||||
|
||||
|
||||
class ObjectFilter(Filter):
|
||||
def __init__(self, exclude=False, in_list=False, field_name=""):
|
||||
super().__init__()
|
||||
self.exclude = exclude
|
||||
self.in_list = in_list
|
||||
self.field_name = field_name
|
||||
|
||||
def filter(self, qs, value):
|
||||
if not value:
|
||||
return qs
|
||||
|
||||
try:
|
||||
object_ids = [int(x) for x in value.split(",")]
|
||||
except ValueError:
|
||||
return qs
|
||||
|
||||
if self.in_list:
|
||||
qs = qs.filter(**{f"{self.field_name}__id__in": object_ids}).distinct()
|
||||
else:
|
||||
for obj_id in object_ids:
|
||||
if self.exclude:
|
||||
qs = qs.exclude(**{f"{self.field_name}__id": obj_id})
|
||||
else:
|
||||
qs = qs.filter(**{f"{self.field_name}__id": obj_id})
|
||||
|
||||
return qs
|
||||
|
||||
|
||||
class InboxFilter(Filter):
|
||||
def filter(self, qs, value):
|
||||
if value == "true":
|
||||
return qs.filter(tags__is_inbox_tag=True)
|
||||
elif value == "false":
|
||||
return qs.exclude(tags__is_inbox_tag=True)
|
||||
else:
|
||||
return qs
|
||||
|
||||
|
||||
class TitleContentFilter(Filter):
|
||||
def filter(self, qs, value):
|
||||
if value:
|
||||
return qs.filter(Q(title__icontains=value) | Q(content__icontains=value))
|
||||
else:
|
||||
return qs
|
||||
|
||||
|
||||
class DocumentFilterSet(FilterSet):
|
||||
|
||||
is_tagged = BooleanFilter(
|
||||
label="Is tagged",
|
||||
field_name="tags",
|
||||
lookup_expr="isnull",
|
||||
exclude=True,
|
||||
)
|
||||
|
||||
tags__id__all = ObjectFilter(field_name="tags")
|
||||
|
||||
tags__id__none = ObjectFilter(field_name="tags", exclude=True)
|
||||
|
||||
tags__id__in = ObjectFilter(field_name="tags", in_list=True)
|
||||
|
||||
correspondent__id__none = ObjectFilter(field_name="correspondent", exclude=True)
|
||||
|
||||
document_type__id__none = ObjectFilter(field_name="document_type", exclude=True)
|
||||
|
||||
storage_path__id__none = ObjectFilter(field_name="storage_path", exclude=True)
|
||||
|
||||
is_in_inbox = InboxFilter()
|
||||
|
||||
title_content = TitleContentFilter()
|
||||
|
||||
class Meta:
|
||||
model = Document
|
||||
fields = {
|
||||
"title": CHAR_KWARGS,
|
||||
"content": CHAR_KWARGS,
|
||||
"archive_serial_number": INT_KWARGS,
|
||||
"created": DATE_KWARGS,
|
||||
"added": DATE_KWARGS,
|
||||
"modified": DATE_KWARGS,
|
||||
"correspondent": ["isnull"],
|
||||
"correspondent__id": ID_KWARGS,
|
||||
"correspondent__name": CHAR_KWARGS,
|
||||
"tags__id": ID_KWARGS,
|
||||
"tags__name": CHAR_KWARGS,
|
||||
"document_type": ["isnull"],
|
||||
"document_type__id": ID_KWARGS,
|
||||
"document_type__name": CHAR_KWARGS,
|
||||
"storage_path": ["isnull"],
|
||||
"storage_path__id": ID_KWARGS,
|
||||
"storage_path__name": CHAR_KWARGS,
|
||||
}
|
||||
|
||||
|
||||
class LogFilterSet(FilterSet):
|
||||
class Meta:
|
||||
model = Log
|
||||
fields = {"level": INT_KWARGS, "created": DATE_KWARGS, "group": ID_KWARGS}
|
||||
|
||||
|
||||
class StoragePathFilterSet(FilterSet):
|
||||
class Meta:
|
||||
model = StoragePath
|
||||
fields = {
|
||||
"name": CHAR_KWARGS,
|
||||
"path": CHAR_KWARGS,
|
||||
}
|
||||
|
||||
|
||||
class ObjectOwnedOrGrantedPermissionsFilter(ObjectPermissionsFilter):
|
||||
"""
|
||||
A filter backend that limits results to those where the requesting user
|
||||
has read object level permissions, owns the objects, or objects without
|
||||
an owner (for backwards compat)
|
||||
"""
|
||||
|
||||
def filter_queryset(self, request, queryset, view):
|
||||
objects_with_perms = super().filter_queryset(request, queryset, view)
|
||||
objects_owned = queryset.filter(owner=request.user)
|
||||
objects_unowned = queryset.filter(owner__isnull=True)
|
||||
return objects_with_perms | objects_owned | objects_unowned
|
||||
|
Loading…
x
Reference in New Issue
Block a user