Skip to content

Commit

Permalink
Classification (ajurna#32)
Browse files Browse the repository at this point in the history
* added some code cleanup for views.py

* added some code cleanup for views.py

* fixed comics not working in the base directory.
  • Loading branch information
ajurna authored May 11, 2021
1 parent 443e43e commit ce38340
Show file tree
Hide file tree
Showing 21 changed files with 355 additions and 105 deletions.
1 change: 1 addition & 0 deletions cbreader/settings/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
"comic_auth",
'django_extensions',
'imagekit',
'django_boost',
)

MIDDLEWARE = [
Expand Down
2 changes: 1 addition & 1 deletion comic/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,5 +47,5 @@ class ComicStatusAdmin(admin.ModelAdmin):

@admin.register(UserMisc)
class UserMiscAdmin(admin.ModelAdmin):
list_display = ('id', 'user', 'feed_id')
list_display = ('user', 'feed_id', 'allowed_to_read')
list_filter = ('user',)
23 changes: 10 additions & 13 deletions comic/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
from django import forms
from django.contrib.auth.models import User

from comic.models import Directory


class InitialSetupForm(forms.Form):
username = forms.CharField(widget=forms.TextInput(attrs={"class": "form-control"}))
Expand Down Expand Up @@ -87,28 +89,23 @@ class EditUserForm(forms.Form):
required=False,
widget=forms.TextInput(attrs={"class": "form-control disabled", "readonly": True}),
)
email = forms.CharField(widget=forms.TextInput(attrs={"class": "form-control"}))
email = forms.EmailField(widget=forms.TextInput(attrs={"class": "form-control"}))
password = forms.CharField(
required=False, widget=forms.PasswordInput(attrs={"class": "form-control"})
)
# TODO: allow setting superuser on users
allowed_to_read = forms.ChoiceField(choices=Directory.Classification.choices)

@staticmethod
def get_initial_values(user):
out = {"username": user.username, "email": user.email}
out = {"username": user.username, "email": user.email, "allowed_to_read": user.usermisc.allowed_to_read}
return out

def clean_email(self):
data = self.cleaned_data["email"]
user = User.objects.get(username=self.cleaned_data["username"])
if data == user.email:
return data
if User.objects.filter(email=data).exists():
raise forms.ValidationError("Email Address is in use")
return data

def clean_password(self):
data = self.cleaned_data["password"]
if len(data) < 8 & len(data) != 0:
raise forms.ValidationError("Password is too short")
return data
return data


class DirectoryEditForm(forms.Form):
classification = forms.ChoiceField(choices=Directory.Classification.choices)
23 changes: 23 additions & 0 deletions comic/migrations/0025_auto_20210506_1342.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# Generated by Django 3.2 on 2021-05-06 12:42

from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
('comic', '0024_auto_20210422_0855'),
]

operations = [
migrations.AddField(
model_name='directory',
name='classification',
field=models.PositiveSmallIntegerField(choices=[(0, 'G'), (1, 'PG'), (2, '12'), (3, '15'), (4, '18')], default=4),
),
migrations.AddField(
model_name='usermisc',
name='allowed_to_read',
field=models.PositiveSmallIntegerField(choices=[(0, 'G'), (1, 'PG'), (2, '12'), (3, '15'), (4, '18')], default=4),
),
]
22 changes: 22 additions & 0 deletions comic/migrations/0026_alter_usermisc_user.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# Generated by Django 3.2 on 2021-05-06 12:50

from django.conf import settings
from django.db import migrations
import django.db.models.deletion
import django_boost.models.fields


class Migration(migrations.Migration):

dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
('comic', '0025_auto_20210506_1342'),
]

operations = [
migrations.AlterField(
model_name='usermisc',
name='user',
field=django_boost.models.fields.AutoOneToOneField(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL),
),
]
26 changes: 26 additions & 0 deletions comic/migrations/0027_auto_20210506_1356.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# Generated by Django 3.2 on 2021-05-06 12:56

from django.conf import settings
from django.db import migrations
import django.db.models.deletion
import django_boost.models.fields


class Migration(migrations.Migration):

dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
('comic', '0026_alter_usermisc_user'),
]

operations = [
migrations.RemoveField(
model_name='usermisc',
name='id',
),
migrations.AlterField(
model_name='usermisc',
name='user',
field=django_boost.models.fields.AutoOneToOneField(on_delete=django.db.models.deletion.CASCADE, primary_key=True, serialize=False, to=settings.AUTH_USER_MODEL),
),
]
44 changes: 30 additions & 14 deletions comic/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,7 @@
import uuid
import zipfile
from functools import reduce
from itertools import zip_longest
from os import listdir
from itertools import zip_longest, chain
from pathlib import Path
from typing import Optional, List, Union, Tuple

Expand All @@ -18,6 +17,7 @@
from django.db.transaction import atomic
from django.templatetags.static import static
from django.utils.http import urlsafe_base64_encode
from django_boost.models.fields import AutoOneToOneField
from imagekit.models import ProcessedImageField
from imagekit.processors import ResizeToFill

Expand All @@ -28,6 +28,13 @@


class Directory(models.Model):
class Classification(models.IntegerChoices):
C_G = 0, 'G'
C_PG = 1, 'PG'
C_12 = 2, '12'
C_15 = 3, '15'
C_18 = 4, '18'

name = models.CharField(max_length=100)
parent = models.ForeignKey("Directory", null=True, blank=True, on_delete=models.CASCADE)
selector = models.UUIDField(unique=True, default=uuid.uuid4, db_index=True)
Expand All @@ -40,6 +47,7 @@ class Directory(models.Model):
on_delete=models.SET_NULL,
related_name='directory_thumbnail_issue')
thumbnail_index = models.PositiveIntegerField(default=0)
classification = models.PositiveSmallIntegerField(choices=Classification.choices, default=Classification.C_18)

class Meta:
ordering = ['name']
Expand Down Expand Up @@ -108,6 +116,10 @@ def get_path_objects(self, p=None):
def url_safe_selector(self):
return urlsafe_base64_encode(self.selector.bytes)

def set_classification(self, form_data):
self.classification = form_data['classification']
self.save()


class ComicBook(models.Model):
file_name = models.TextField()
Expand Down Expand Up @@ -144,7 +156,7 @@ def mark_previous(self, user):
def url_safe_selector(self):
return urlsafe_base64_encode(self.selector.bytes)

def get_pdf(self):
def get_pdf(self) -> Path:
base_dir = settings.COMIC_BOOK_VOLUME
return Path(base_dir, self.directory.get_path(), self.file_name)

Expand Down Expand Up @@ -209,6 +221,7 @@ def generate_thumbnail(self, page_index: int = None):
self.save()

def _get_pdf_image(self, page_index: int):
# noinspection PyTypeChecker
doc = fitz.open(self.get_pdf())
page = doc[page_index]
pix = page.get_pixmap()
Expand All @@ -219,7 +232,6 @@ def _get_pdf_image(self, page_index: int):
img.seek(0)
return img, pil_data


def is_last_page(self, page):
if (self.page_count - 1) == page:
return True
Expand Down Expand Up @@ -265,9 +277,9 @@ def nav_get_prev_comic(self, user) -> str:
book = ComicBook.objects.get(file_name=prev_comic, directory__isnull=True)
except ComicBook.DoesNotExist:
if self.directory:
book = ComicBook.process_comic_book(prev_comic, self.directory)
book = ComicBook.process_comic_book(Path(prev_comic), self.directory)
else:
book = ComicBook.process_comic_book(prev_comic)
book = ComicBook.process_comic_book(Path(prev_comic))
cs, _ = ComicStatus.objects.get_or_create(comic=book, user=user)
comic_path = urlsafe_base64_encode(book.selector.bytes)

Expand All @@ -290,9 +302,9 @@ def nav_get_next_comic(self, user):
book = ComicBook.objects.get(file_name=next_comic, directory__isnull=True)
except ComicBook.DoesNotExist:
if self.directory:
book = ComicBook.process_comic_book(next_comic, self.directory)
book = ComicBook.process_comic_book(Path(next_comic), self.directory)
else:
book = ComicBook.process_comic_book(next_comic)
book = ComicBook.process_comic_book(Path(next_comic))
except ComicBook.MultipleObjectsReturned:
if self.directory:
books = ComicBook.objects.filter(file_name=next_comic, directory=self.directory).order_by('id')
Expand Down Expand Up @@ -353,21 +365,21 @@ def process_comic_book(comic_file_path: Path, directory: "Directory" = False) ->
with atomic():
for page_index in range(archive.page_count):
page = ComicPage(
Comic=book, index=page_index, page_file_name=page_index+1, content_type='application/pdf'
Comic=book, index=page_index, page_file_name=page_index + 1, content_type='application/pdf'
)
page.save()
return book

@staticmethod
def get_ordered_dir_list(folder):
def get_ordered_dir_list(folder: Path) -> List[str]:
directories = []
files = []
for item in listdir(folder):
if Path(folder, item).is_dir():
for item in folder.glob('*'):
if item.is_dir():
directories.append(item)
else:
files.append(item)
return sorted(directories) + sorted(files)
return [x.name for x in chain(sorted(directories), sorted(files))]

@property
def get_archive_path(self):
Expand All @@ -388,6 +400,7 @@ def get_archive(self) -> Tuple[Union[rarfile.RarFile, zipfile.ZipFile, fitz.Docu
pass

try:
# noinspection PyUnresolvedReferences
return fitz.open(str(archive_path)), 'pdf'
except RuntimeError:
pass
Expand Down Expand Up @@ -475,5 +488,8 @@ def __repr__(self):


class UserMisc(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)

user = AutoOneToOneField(User, on_delete=models.CASCADE, primary_key=True)
feed_id = models.UUIDField(unique=True, default=uuid.uuid4, db_index=True)
allowed_to_read = models.PositiveSmallIntegerField(default=Directory.Classification.C_18,
choices=Directory.Classification.choices)
38 changes: 31 additions & 7 deletions comic/templates/comic/comic_list.html
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
{% extends "base.html" %}
{% load bootstrap4 %}
{% load static %}
{% block title %}{{ title }}{% endblock %}

Expand Down Expand Up @@ -48,7 +49,7 @@
{% endif %}
</a>
<div class="card-body">
<h5 class="card-title">
<h5 class="card-title {{ file.selector }}">
{% if file.item_type == 'Directory' %}
<a href="{% url "comic_list" file.selector %}" class="search-name">
{% elif file.item_type == 'ComicBook' %}
Expand All @@ -63,7 +64,7 @@ <h5 class="card-title">
<div class="progress-bar" role="progressbar" aria-valuenow="{{ file.percent }}" aria-valuemin="0" aria-valuemax="100"></div>
</div>
</p>
<div class="btn-group" role="group" aria-label="Comic Actions">
<div class="btn-group w-100" role="group" aria-label="Comic Actions">
<button type="button" class="btn btn-primary comic_action" title="Mark Un-Read" selector="{{ file.selector }}" itemtype="{{ file.item_type }}" comic_action="mark_unread"><i class="fas fa-book"></i></button>
<button type="button" class="btn btn-primary comic_action" title="Mark Read" selector="{{ file.selector }}" itemtype="{{ file.item_type }}" comic_action="mark_read"><i class="fas fa-book-open"></i></button>
<div class="btn-group" role="group">
Expand All @@ -75,25 +76,48 @@ <h5 class="card-title">
<button type="button" class="btn btn-primary dropdown-item comic_action" title="Mark Read" selector="{{ file.selector }}" itemtype="{{ file.item_type }}" comic_action="mark_read"><i class="fas fa-book-open">Mark Read</i></button>
{% if file.item_type != 'Directory' %}
<button type="button" class="btn btn-primary dropdown-item comic_action" title="Mark Previous Read" selector="{{ file.selector }}" itemtype="{{ file.item_type }}" comic_action="mark_previous"><i class="fas fa-book"><i class="fas fa-arrow-up">Mark Previous Read</i></i></button>
{% else %}
<button type="button" class="btn btn-primary dropdown-item modal-button" title="Edit Comic" data-toggle="modal" data-target="#editModal" selector="{{ file.selector }}" itemtype="{{ file.item_type }}"><i class="fas fa-edit">Edit Comic</i></button>
{% endif %}
{# <button type="button" class="btn btn-primary dropdown-item" title="Edit Comic"><i class="fas fa-edit">Edit Comic</i></button>#}

</div>
</div>

</div>
</div>
{% if file.total_unread and file.item_type == 'Directory' %}
<span class="badge rounded-pill bg-primary card-badge">{{ file.total_unread }}</span>
<span class="badge rounded-pill bg-primary unread-badge">{{ file.total_unread }}</span>
{% endif %}
<span class="badge rounded-pill bg-warning {{ file.selector }} classification-badge" classification="{{ file.obj.classification }}">{{ file.obj.get_classification_display }}</span>

</div>
</div>
</div>
{% endfor %}
</div>
</div>

<div class="modal fade" id="editModal" tabindex="-1" aria-labelledby="editModalLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="editModalLabel">Modal title</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
{% csrf_token %}
{% bootstrap_form form %}
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
<button type="button" class="btn btn-primary" id="save_button">Save changes</button>
</div>
</div>
</div>
</div>
{% endblock %}

{% block script %}
<script type="text/javascript" src="{% static "js/comic_list.min.js" %}"></script>
{{ js_urls|json_script:'js_urls' }}
<script type="text/javascript" src="{% static "js/comic_list.min.js" %}"></script>
{% endblock %}
2 changes: 2 additions & 0 deletions comic/templates/comic/users_page.html
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
<th>Username</th>
<th>Email</th>
<th>Superuser</th>
<th>Classification</th>
</tr>
</thead>
<tbody data-link="row" class="rowlink">
Expand All @@ -20,6 +21,7 @@
<td><a href="{% url 'user_details' user.id %}">{{user.username}}</a></td>
<td>{{user.email}}</td>
<td>{{user.is_superuser}}</td>
<td>{{ user.usermisc.get_allowed_to_read_display }}</td>
</tr>
{% endfor %}
</tbody>
Expand Down
Empty file added comic/templatetags/__init__.py
Empty file.
4 changes: 4 additions & 0 deletions comic/templatetags/comic_tags.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
from django import template

register = template.Library()

2 changes: 1 addition & 1 deletion comic/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
path("recent/", views.recent_comics, name="recent_comics"),
path("recent/json/", views.recent_comics_json, name="recent_comics_json"),
path("edit/", views.comic_edit, name="comic_edit"),
path("feed/<int:user_selector>/", feeds.RecentComics()),
path("feed/<user_selector>/", feeds.RecentComics()),
path("<directory_selector>/", views.comic_list, name="comic_list"),
path("<directory_selector>/thumb", views.directory_thumbnail, name="directory_thumbnail"),
path("action/<operation>/<item_type>/<selector>/", views.perform_action, name="perform_action")
Expand Down
Loading

0 comments on commit ce38340

Please sign in to comment.