add backend support for saved views

This commit is contained in:
jonaswinkler 2020-12-12 15:46:56 +01:00
parent bf9051e44d
commit dfa1f29809
6 changed files with 152 additions and 5 deletions

View File

@ -4,7 +4,8 @@ from django.utils.safestring import mark_safe
from whoosh.writing import AsyncWriter from whoosh.writing import AsyncWriter
from . import index from . import index
from .models import Correspondent, Document, DocumentType, Log, Tag from .models import Correspondent, Document, DocumentType, Log, Tag, \
SavedView, SavedViewFilterRule
class CorrespondentAdmin(admin.ModelAdmin): class CorrespondentAdmin(admin.ModelAdmin):
@ -131,8 +132,22 @@ class LogAdmin(admin.ModelAdmin):
list_display_links = ("created", "message") list_display_links = ("created", "message")
class RuleInline(admin.TabularInline):
model = SavedViewFilterRule
class SavedViewAdmin(admin.ModelAdmin):
list_display = ("name", "user")
inlines = [
RuleInline
]
admin.site.register(Correspondent, CorrespondentAdmin) admin.site.register(Correspondent, CorrespondentAdmin)
admin.site.register(Tag, TagAdmin) admin.site.register(Tag, TagAdmin)
admin.site.register(DocumentType, DocumentTypeAdmin) admin.site.register(DocumentType, DocumentTypeAdmin)
admin.site.register(Document, DocumentAdmin) admin.site.register(Document, DocumentAdmin)
admin.site.register(Log, LogAdmin) admin.site.register(Log, LogAdmin)
admin.site.register(SavedView, SavedViewAdmin)

View File

@ -0,0 +1,37 @@
# Generated by Django 3.1.4 on 2020-12-12 14:41
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
('documents', '1006_auto_20201208_2209'),
]
operations = [
migrations.CreateModel(
name='SavedView',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('name', models.CharField(max_length=128)),
('show_on_dashboard', models.BooleanField()),
('show_in_sidebar', models.BooleanField()),
('sort_field', models.CharField(max_length=128)),
('sort_reverse', models.BooleanField(default=False)),
('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
],
),
migrations.CreateModel(
name='SavedViewFilterRule',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('rule_type', models.PositiveIntegerField(choices=[(0, 'Title contains'), (1, 'Content contains'), (2, 'ASN is'), (3, 'Correspondent is'), (4, 'Document type is'), (5, 'Is in inbox'), (6, 'Has tag'), (7, 'Has any tag'), (8, 'Created before'), (9, 'Created after'), (10, 'Created year is'), (11, 'Created month is'), (12, 'Created day is'), (13, 'Added before'), (14, 'Added after'), (15, 'Modified before'), (16, 'Modified after'), (17, 'Does not have tag')])),
('value', models.CharField(max_length=128)),
('saved_view', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='filter_rules', to='documents.savedview')),
],
),
]

View File

@ -9,6 +9,7 @@ import pathvalidate
import dateutil.parser import dateutil.parser
from django.conf import settings from django.conf import settings
from django.contrib.auth.models import User
from django.db import models from django.db import models
from django.utils import timezone from django.utils import timezone
from django.utils.text import slugify from django.utils.text import slugify
@ -305,6 +306,47 @@ class Log(models.Model):
return self.message return self.message
class SavedView(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
name = models.CharField(max_length=128)
show_on_dashboard = models.BooleanField()
show_in_sidebar = models.BooleanField()
sort_field = models.CharField(max_length=128)
sort_reverse = models.BooleanField(default=False)
class SavedViewFilterRule(models.Model):
RULE_TYPES = [
(0, "Title contains"),
(1, "Content contains"),
(2, "ASN is"),
(3, "Correspondent is"),
(4, "Document type is"),
(5, "Is in inbox"),
(6, "Has tag"),
(7, "Has any tag"),
(8, "Created before"),
(9, "Created after"),
(10, "Created year is"),
(11, "Created month is"),
(12, "Created day is"),
(13, "Added before"),
(14, "Added after"),
(15, "Modified before"),
(16, "Modified after"),
(17, "Does not have tag"),
]
saved_view = models.ForeignKey(SavedView, on_delete=models.CASCADE, related_name="filter_rules")
rule_type = models.PositiveIntegerField(choices=RULE_TYPES)
value = models.CharField(max_length=128)
# TODO: why is this in the models file? # TODO: why is this in the models file?
class FileInfo: class FileInfo:

View File

@ -3,7 +3,8 @@ from django.utils.text import slugify
from rest_framework import serializers from rest_framework import serializers
from rest_framework.fields import SerializerMethodField from rest_framework.fields import SerializerMethodField
from .models import Correspondent, Tag, Document, Log, DocumentType from .models import Correspondent, Tag, Document, Log, DocumentType, \
SavedView, SavedViewFilterRule
from .parsers import is_mime_type_supported from .parsers import is_mime_type_supported
@ -140,6 +141,39 @@ class LogSerializer(serializers.ModelSerializer):
) )
class SavedViewFilterRuleSerializer(serializers.ModelSerializer):
class Meta:
model = SavedViewFilterRule
fields = ["rule_type", "value"]
class SavedViewSerializer(serializers.ModelSerializer):
filter_rules = SavedViewFilterRuleSerializer(many=True)
class Meta:
model = SavedView
depth = 1
fields = ["id", "name", "show_on_dashboard", "show_in_sidebar",
"sort_field", "sort_reverse", "filter_rules"]
def update(self, instance, validated_data):
rules_data = validated_data.pop('filter_rules')
super(SavedViewSerializer, self).update(instance, validated_data)
SavedViewFilterRule.objects.filter(saved_view=instance).delete()
for rule_data in rules_data:
SavedViewFilterRule.objects.create(saved_view=instance, **rule_data)
return instance
def create(self, validated_data):
rules_data = validated_data.pop('filter_rules')
saved_view = SavedView.objects.create(**validated_data)
for rule_data in rules_data:
SavedViewFilterRule.objects.create(saved_view=saved_view, **rule_data)
return saved_view
class PostDocumentSerializer(serializers.Serializer): class PostDocumentSerializer(serializers.Serializer):
document = serializers.FileField( document = serializers.FileField(

View File

@ -38,7 +38,7 @@ from .filters import (
DocumentTypeFilterSet, DocumentTypeFilterSet,
LogFilterSet LogFilterSet
) )
from .models import Correspondent, Document, Log, Tag, DocumentType from .models import Correspondent, Document, Log, Tag, DocumentType, SavedView
from .parsers import get_parser_class_for_mime_type from .parsers import get_parser_class_for_mime_type
from .serialisers import ( from .serialisers import (
CorrespondentSerializer, CorrespondentSerializer,
@ -46,7 +46,8 @@ from .serialisers import (
LogSerializer, LogSerializer,
TagSerializer, TagSerializer,
DocumentTypeSerializer, DocumentTypeSerializer,
PostDocumentSerializer PostDocumentSerializer,
SavedViewSerializer
) )
@ -240,6 +241,22 @@ class LogViewSet(ReadOnlyModelViewSet):
ordering_fields = ("created",) ordering_fields = ("created",)
class SavedViewViewSet(ModelViewSet):
model = SavedView
queryset = SavedView.objects.all()
serializer_class = SavedViewSerializer
pagination_class = StandardPagination
permission_classes = (IsAuthenticated,)
def get_queryset(self):
user = self.request.user
return SavedView.objects.filter(user=user)
def perform_create(self, serializer):
serializer.save(user=self.request.user)
class PostDocumentView(APIView): class PostDocumentView(APIView):
permission_classes = (IsAuthenticated,) permission_classes = (IsAuthenticated,)

View File

@ -17,7 +17,8 @@ from documents.views import (
IndexView, IndexView,
SearchAutoCompleteView, SearchAutoCompleteView,
StatisticsView, StatisticsView,
PostDocumentView PostDocumentView,
SavedViewViewSet
) )
from paperless.views import FaviconView from paperless.views import FaviconView
@ -27,6 +28,7 @@ api_router.register(r"document_types", DocumentTypeViewSet)
api_router.register(r"documents", DocumentViewSet) api_router.register(r"documents", DocumentViewSet)
api_router.register(r"logs", LogViewSet) api_router.register(r"logs", LogViewSet)
api_router.register(r"tags", TagViewSet) api_router.register(r"tags", TagViewSet)
api_router.register(r"saved_views", SavedViewViewSet)
urlpatterns = [ urlpatterns = [