add hidden documents, fix untagged
This commit is contained in:
parent
954cdd8d97
commit
9f61506839
6 changed files with 106 additions and 17 deletions
18
sdbs_pile/pile/migrations/0004_document_hidden.py
Normal file
18
sdbs_pile/pile/migrations/0004_document_hidden.py
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
# Generated by Django 3.0.4 on 2020-03-19 19:48
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('pile', '0003_auto_20200318_2201'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='document',
|
||||||
|
name='hidden',
|
||||||
|
field=models.BooleanField(default=False),
|
||||||
|
),
|
||||||
|
]
|
17
sdbs_pile/pile/migrations/0005_auto_20200320_1329.py
Normal file
17
sdbs_pile/pile/migrations/0005_auto_20200320_1329.py
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
# Generated by Django 3.0.4 on 2020-03-20 12:29
|
||||||
|
|
||||||
|
from django.db import migrations
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('pile', '0004_document_hidden'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterModelOptions(
|
||||||
|
name='document',
|
||||||
|
options={'ordering': ['-id'], 'permissions': [('see_hidden', 'Can see hidden documents')]},
|
||||||
|
),
|
||||||
|
]
|
|
@ -1,6 +1,7 @@
|
||||||
from django.core.exceptions import ValidationError
|
from django.core.exceptions import ValidationError
|
||||||
from django.core.files.storage import FileSystemStorage
|
from django.core.files.storage import FileSystemStorage
|
||||||
from django.db import models
|
from django.db import models
|
||||||
|
from django.db.models import Count
|
||||||
from model_utils.models import SoftDeletableModel
|
from model_utils.models import SoftDeletableModel
|
||||||
|
|
||||||
|
|
||||||
|
@ -8,10 +9,29 @@ class Tag(SoftDeletableModel):
|
||||||
name = models.CharField(max_length=128, null=False, blank=False)
|
name = models.CharField(max_length=128, null=False, blank=False)
|
||||||
description = models.TextField(null=False, blank=True)
|
description = models.TextField(null=False, blank=True)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def documents_exclude_hidden(self):
|
||||||
|
return Document.exclude_hidden.filter(tags__in=[self])
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return self.name
|
return self.name
|
||||||
|
|
||||||
|
|
||||||
|
class DocumentManager(models.Manager):
|
||||||
|
def __init__(self, include_hidden=True):
|
||||||
|
super(DocumentManager, self).__init__()
|
||||||
|
self._include_hidden = include_hidden
|
||||||
|
|
||||||
|
def get_queryset(self):
|
||||||
|
if self._include_hidden:
|
||||||
|
return super().get_queryset()
|
||||||
|
else:
|
||||||
|
return super().get_queryset().filter(hidden=False)
|
||||||
|
|
||||||
|
def untagged(self):
|
||||||
|
return self.get_queryset().annotate(tag_count=Count('tags')).filter(tag_count=0)
|
||||||
|
|
||||||
|
|
||||||
class Document(SoftDeletableModel):
|
class Document(SoftDeletableModel):
|
||||||
title = models.CharField(max_length=512, null=False, blank=False)
|
title = models.CharField(max_length=512, null=False, blank=False)
|
||||||
description = models.TextField(null=False, blank=True)
|
description = models.TextField(null=False, blank=True)
|
||||||
|
@ -19,9 +39,13 @@ class Document(SoftDeletableModel):
|
||||||
published = models.CharField(max_length=128, null=False, blank=True)
|
published = models.CharField(max_length=128, null=False, blank=True)
|
||||||
external_url = models.URLField(null=True, blank=True)
|
external_url = models.URLField(null=True, blank=True)
|
||||||
file = models.FileField(null=True, blank=True, storage=FileSystemStorage(location='docs'))
|
file = models.FileField(null=True, blank=True, storage=FileSystemStorage(location='docs'))
|
||||||
tags = models.ManyToManyField(Tag, related_name="documents")
|
hidden = models.BooleanField(default=False, null=False, blank=False)
|
||||||
|
tags = models.ManyToManyField(Tag, related_name="documents", blank=True)
|
||||||
uploaded = models.DateTimeField(auto_now_add=True, null=True)
|
uploaded = models.DateTimeField(auto_now_add=True, null=True)
|
||||||
|
|
||||||
|
objects = DocumentManager()
|
||||||
|
exclude_hidden = DocumentManager(include_hidden=False)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def url(self):
|
def url(self):
|
||||||
if self.file:
|
if self.file:
|
||||||
|
@ -30,6 +54,9 @@ class Document(SoftDeletableModel):
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
ordering = ['-id']
|
ordering = ['-id']
|
||||||
|
permissions = [
|
||||||
|
("see_hidden", "Can see hidden documents")
|
||||||
|
]
|
||||||
|
|
||||||
def get_absolute_url(self):
|
def get_absolute_url(self):
|
||||||
from django.urls import reverse
|
from django.urls import reverse
|
||||||
|
|
|
@ -28,12 +28,12 @@
|
||||||
<div id="sidebar-taglist">
|
<div id="sidebar-taglist">
|
||||||
<ul>
|
<ul>
|
||||||
<li id="sidebar-taglist-top"><a href="{% url "pile:tag" "*" %}">ALL ({{ document_count }})</a></li>
|
<li id="sidebar-taglist-top"><a href="{% url "pile:tag" "*" %}">ALL ({{ document_count }})</a></li>
|
||||||
{% if untagged.count %}
|
{% if untagged_count %}
|
||||||
<li id="sidebar-taglist-top"><a href="?tag=_">UNTAGGED ({{ untagged_count }})</a></li>
|
<li id="sidebar-taglist-top"><a href="/tag/_">UNTAGGED ({{ untagged_count }})</a></li>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% for tag in tags %}
|
{% for tag, tag_count in tags %}
|
||||||
{% if tag.documents.count > 0 %}
|
{% if tag_count > 0 %}
|
||||||
<li><a href="{% url 'pile:tag' tag.id %}">{{ tag.name }} ({{ tag.documents.count }})</a></li>
|
<li><a href="{% url 'pile:tag' tag.id %}">{{ tag.name }} ({{ tag_count }})</a></li>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</ul>
|
</ul>
|
||||||
|
|
|
@ -1,6 +1,15 @@
|
||||||
{% extends "front_base.html" %}
|
{% extends "front_base.html" %}
|
||||||
|
|
||||||
{% block title %}{% if tag %}: Filed under "{{ tag.name }}"{% else %}: All documents{% endif %}{% endblock %}
|
{% block title %}{% spaceless %}
|
||||||
|
|
||||||
|
{% if tag %}
|
||||||
|
: Filed under "{{ tag.name }}"
|
||||||
|
{% elif untagged %}
|
||||||
|
: Untagged
|
||||||
|
{% else %}
|
||||||
|
: All documents
|
||||||
|
{% endif %}
|
||||||
|
{% endspaceless %}{% endblock %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
{% if tag %}
|
{% if tag %}
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
# Create your views here.
|
# Create your views here.
|
||||||
|
from operator import itemgetter
|
||||||
|
|
||||||
from django.contrib.syndication.views import Feed
|
from django.contrib.syndication.views import Feed
|
||||||
from django.core.exceptions import ObjectDoesNotExist
|
from django.core.exceptions import ObjectDoesNotExist
|
||||||
from django.db.models import Count
|
|
||||||
from django.http import Http404
|
from django.http import Http404
|
||||||
from django.views.generic import TemplateView
|
from django.views.generic import TemplateView
|
||||||
|
|
||||||
|
@ -9,12 +10,25 @@ from sdbs_pile.pile.models import Tag, Document
|
||||||
|
|
||||||
|
|
||||||
class BasePileView(TemplateView):
|
class BasePileView(TemplateView):
|
||||||
|
|
||||||
|
@property
|
||||||
|
def include_hidden(self):
|
||||||
|
return self.request.user.has_perm('document.see_hidden')
|
||||||
|
|
||||||
|
@property
|
||||||
|
def documents(self):
|
||||||
|
return Document.objects if self.include_hidden else Document.exclude_hidden
|
||||||
|
|
||||||
def get_context_data(self, **kwargs):
|
def get_context_data(self, **kwargs):
|
||||||
|
tags = list(Tag.objects.all())
|
||||||
|
tags.sort(key=lambda tag: tag.name)
|
||||||
|
tags = [(tag, (tag.documents if self.include_hidden else tag.documents_exclude_hidden).count()) for tag in tags]
|
||||||
|
tags.sort(key=itemgetter(1), reverse=True)
|
||||||
|
|
||||||
return {
|
return {
|
||||||
'tags': sorted(sorted(Tag.objects.all(), key=lambda tag: tag.name),
|
'tags': tags,
|
||||||
key=lambda tag: tag.documents.count(), reverse=True),
|
'document_count': self.documents.count(),
|
||||||
'document_count': Document.objects.count(),
|
'untagged_count': self.documents.untagged().count()
|
||||||
'untagged_count': Document.objects.annotate(tag_count=Count('tags')).filter(tag_count__gt=0).count()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -25,7 +39,7 @@ class IndexView(BasePileView):
|
||||||
base_context_data = super(IndexView, self).get_context_data(**kwargs)
|
base_context_data = super(IndexView, self).get_context_data(**kwargs)
|
||||||
|
|
||||||
return {
|
return {
|
||||||
'recent_documents': Document.objects.order_by('-uploaded')[:5],
|
'recent_documents': self.documents.order_by('-uploaded')[:5],
|
||||||
**base_context_data
|
**base_context_data
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -38,19 +52,23 @@ class TagView(BasePileView):
|
||||||
|
|
||||||
if name_or_id == "*":
|
if name_or_id == "*":
|
||||||
tag = None
|
tag = None
|
||||||
documents = Document.objects.all()
|
documents = self.documents.all()
|
||||||
|
elif name_or_id == "_":
|
||||||
|
tag = "UNTAGGED"
|
||||||
|
documents = self.documents.untagged()
|
||||||
else:
|
else:
|
||||||
try:
|
try:
|
||||||
try:
|
try:
|
||||||
tag = Tag.objects.get(id=int(name_or_id))
|
tag = Tag.objects.get(id=int(name_or_id))
|
||||||
except ValueError:
|
except ValueError:
|
||||||
tag = Tag.objects.get(name=name_or_id)
|
tag = Tag.objects.get(name=name_or_id)
|
||||||
documents = tag.documents.all()
|
documents = tag.documents.all() if self.include_hidden else tag.documents_exclude_hidden
|
||||||
except ObjectDoesNotExist:
|
except ObjectDoesNotExist:
|
||||||
raise Http404
|
raise Http404
|
||||||
|
|
||||||
return {
|
return {
|
||||||
'tag': tag,
|
'tag': tag if tag != "UNTAGGED" else None,
|
||||||
|
'untagged': tag == "UNTAGGED",
|
||||||
'documents': documents,
|
'documents': documents,
|
||||||
**base_context_data
|
**base_context_data
|
||||||
}
|
}
|
||||||
|
@ -63,7 +81,7 @@ class DocumentView(BasePileView):
|
||||||
base_context_data = super(DocumentView, self).get_context_data()
|
base_context_data = super(DocumentView, self).get_context_data()
|
||||||
|
|
||||||
try:
|
try:
|
||||||
document = Document.objects.get(pk=document_id)
|
document = self.documents.get(pk=document_id)
|
||||||
except ObjectDoesNotExist:
|
except ObjectDoesNotExist:
|
||||||
raise Http404
|
raise Http404
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue