Merge pull request #5 from apoclyps/black-formatting

[ISSUE-4] Applying black formatting
This commit is contained in:
2019-07-26 08:45:41 +01:00
committed by GitHub
37 changed files with 990 additions and 1150 deletions

View File

@@ -22,10 +22,10 @@ BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
# See https://docs.djangoproject.com/en/1.8/howto/deployment/checklist/
# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = '=3tf-@u1t7x4%$yr++59+8tspl4ao&r3&!bb6l(t&$#6@bfkwg'
SECRET_KEY = "=3tf-@u1t7x4%$yr++59+8tspl4ao&r3&!bb6l(t&$#6@bfkwg"
# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = os.environ.get('DJANGO_DEBUG', True)
DEBUG = os.environ.get("DJANGO_DEBUG", True)
ALLOWED_HOSTS = os.environ.get("DJANGO_ALLOWED_HOSTS", "localhost").split(",")
@@ -33,46 +33,46 @@ ALLOWED_HOSTS = os.environ.get("DJANGO_ALLOWED_HOSTS", "localhost").split(",")
# Application definition
INSTALLED_APPS = (
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'snowpenguin.django.recaptcha2',
'comic',
'comic_auth',
"django.contrib.admin",
"django.contrib.auth",
"django.contrib.contenttypes",
"django.contrib.sessions",
"django.contrib.messages",
"django.contrib.staticfiles",
"snowpenguin.django.recaptcha2",
"comic",
"comic_auth",
)
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
"django.middleware.security.SecurityMiddleware",
"django.contrib.sessions.middleware.SessionMiddleware",
"django.middleware.common.CommonMiddleware",
"django.middleware.csrf.CsrfViewMiddleware",
"django.contrib.auth.middleware.AuthenticationMiddleware",
"django.contrib.messages.middleware.MessageMiddleware",
"django.middleware.clickjacking.XFrameOptionsMiddleware",
]
ROOT_URLCONF = 'cbreader.urls'
ROOT_URLCONF = "cbreader.urls"
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': ['templates'],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
],
},
"BACKEND": "django.template.backends.django.DjangoTemplates",
"DIRS": ["templates"],
"APP_DIRS": True,
"OPTIONS": {
"context_processors": [
"django.template.context_processors.debug",
"django.template.context_processors.request",
"django.contrib.auth.context_processors.auth",
"django.contrib.messages.context_processors.messages",
]
},
}
]
WSGI_APPLICATION = 'cbreader.wsgi.application'
WSGI_APPLICATION = "cbreader.wsgi.application"
# Database
@@ -83,20 +83,15 @@ DATABASE_URL = os.getenv("DATABASE_URL")
if DATABASE_URL:
DATABASES = {"default": dj_database_url.config(conn_max_age=500)}
else:
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
}
}
DATABASES = {"default": {"ENGINE": "django.db.backends.sqlite3", "NAME": os.path.join(BASE_DIR, "db.sqlite3")}}
# Internationalization
# https://docs.djangoproject.com/en/1.8/topics/i18n/
LANGUAGE_CODE = 'en-ie'
LANGUAGE_CODE = "en-ie"
TIME_ZONE = 'UTC'
TIME_ZONE = "UTC"
USE_I18N = True
@@ -108,16 +103,16 @@ USE_TZ = True
# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/1.8/howto/static-files/
STATIC_URL = '/static/'
STATIC_URL = "/static/"
LOGIN_REDIRECT_URL = '/comic/'
LOGIN_REDIRECT_URL = "/comic/"
LOGIN_URL = '/login/'
LOGIN_URL = "/login/"
UNRAR_TOOL = os.getenv("UNRAR_TOOL", None)
CBREADER_USE_RECAPTCHA = False
RECAPTCHA_PRIVATE_KEY = ''
RECAPTCHA_PUBLIC_KEY = ''
RECAPTCHA_PRIVATE_KEY = ""
RECAPTCHA_PUBLIC_KEY = ""
COMIC_DIR = "/media/comics"

View File

@@ -1,123 +0,0 @@
"""
Django settings for cbreader project.
Generated by 'django-admin startproject' using Django 1.8.2.
For more information on this file, see
https://docs.djangoproject.com/en/1.8/topics/settings/
For the full list of settings and their values, see
https://docs.djangoproject.com/en/1.8/ref/settings/
"""
# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
import os
import dj_database_url
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/1.8/howto/deployment/checklist/
# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = '=3tf-@u1t7x4%$yr++59+8tspl4ao&r3&!bb6l(t&$#6@bfkwg'
# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = os.environ.get('DJANGO_DEBUG', True)
ALLOWED_HOSTS = os.environ.get("DJANGO_ALLOWED_HOSTS", "localhost").split(",")
# Application definition
INSTALLED_APPS = (
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'snowpenguin.django.recaptcha2',
'comic',
'comic_auth',
)
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
]
ROOT_URLCONF = 'cbreader.urls'
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': ['templates'],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
],
},
},
]
WSGI_APPLICATION = 'cbreader.wsgi.application'
# Database
# https://docs.djangoproject.com/en/1.8/ref/settings/#databases
DATABASE_URL = os.getenv("TEST_DATABASE_URL")
if DATABASE_URL:
DATABASES = {"default": dj_database_url.config(conn_max_age=500)}
else:
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
}
}
# Internationalization
# https://docs.djangoproject.com/en/1.8/topics/i18n/
LANGUAGE_CODE = 'en-ie'
TIME_ZONE = 'UTC'
USE_I18N = True
USE_L10N = True
USE_TZ = True
# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/1.8/howto/static-files/
STATIC_URL = '/static/'
LOGIN_REDIRECT_URL = '/comic/'
LOGIN_URL = '/login/'
UNRAR_TOOL = os.getenv("UNRAR_TOOL", None)
CBREADER_USE_RECAPTCHA = False
RECAPTCHA_PRIVATE_KEY = ''
RECAPTCHA_PUBLIC_KEY = ''
COMIC_DIR = "/media/comics"

View File

@@ -0,0 +1,118 @@
"""
Django settings for cbreader project.
Generated by 'django-admin startproject' using Django 1.8.2.
For more information on this file, see
https://docs.djangoproject.com/en/1.8/topics/settings/
For the full list of settings and their values, see
https://docs.djangoproject.com/en/1.8/ref/settings/
"""
# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
import os
import dj_database_url
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/1.8/howto/deployment/checklist/
# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = "=3tf-@u1t7x4%$yr++59+8tspl4ao&r3&!bb6l(t&$#6@bfkwg"
# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = os.environ.get("DJANGO_DEBUG", True)
ALLOWED_HOSTS = os.environ.get("DJANGO_ALLOWED_HOSTS", "localhost").split(",")
# Application definition
INSTALLED_APPS = (
"django.contrib.admin",
"django.contrib.auth",
"django.contrib.contenttypes",
"django.contrib.sessions",
"django.contrib.messages",
"django.contrib.staticfiles",
"snowpenguin.django.recaptcha2",
"comic",
"comic_auth",
)
MIDDLEWARE = [
"django.middleware.security.SecurityMiddleware",
"django.contrib.sessions.middleware.SessionMiddleware",
"django.middleware.common.CommonMiddleware",
"django.middleware.csrf.CsrfViewMiddleware",
"django.contrib.auth.middleware.AuthenticationMiddleware",
"django.contrib.messages.middleware.MessageMiddleware",
"django.middleware.clickjacking.XFrameOptionsMiddleware",
]
ROOT_URLCONF = "cbreader.urls"
TEMPLATES = [
{
"BACKEND": "django.template.backends.django.DjangoTemplates",
"DIRS": ["templates"],
"APP_DIRS": True,
"OPTIONS": {
"context_processors": [
"django.template.context_processors.debug",
"django.template.context_processors.request",
"django.contrib.auth.context_processors.auth",
"django.contrib.messages.context_processors.messages",
]
},
}
]
WSGI_APPLICATION = "cbreader.wsgi.application"
# Database
# https://docs.djangoproject.com/en/1.8/ref/settings/#databases
DATABASE_URL = os.getenv("TEST_DATABASE_URL")
if DATABASE_URL:
DATABASES = {"default": dj_database_url.config(conn_max_age=500)}
else:
DATABASES = {"default": {"ENGINE": "django.db.backends.sqlite3", "NAME": os.path.join(BASE_DIR, "db.sqlite3")}}
# Internationalization
# https://docs.djangoproject.com/en/1.8/topics/i18n/
LANGUAGE_CODE = "en-ie"
TIME_ZONE = "UTC"
USE_I18N = True
USE_L10N = True
USE_TZ = True
# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/1.8/howto/static-files/
STATIC_URL = "/static/"
LOGIN_REDIRECT_URL = "/comic/"
LOGIN_URL = "/login/"
UNRAR_TOOL = os.getenv("UNRAR_TOOL", None)
CBREADER_USE_RECAPTCHA = False
RECAPTCHA_PRIVATE_KEY = ""
RECAPTCHA_PUBLIC_KEY = ""
COMIC_DIR = "/media/comics"

View File

@@ -20,11 +20,11 @@ import comic.views
import comic_auth.views
urlpatterns = [
url(r'^$', comic.views.comic_redirect),
url(r'^login/', comic_auth.views.comic_login),
url(r'^logout/', comic_auth.views.comic_logout),
url(r'^setup/', comic.views.initial_setup),
url(r'^comic/', include('comic.urls')),
url(r'^admin/', admin.site.urls),
url(r"^$", comic.views.comic_redirect),
url(r"^login/", comic_auth.views.comic_login),
url(r"^logout/", comic_auth.views.comic_logout),
url(r"^setup/", comic.views.initial_setup),
url(r"^comic/", include("comic.urls")),
url(r"^admin/", admin.site.urls),
# url(r'^silk/', include('silk.urls', namespace='silk'))
]

View File

@@ -5,24 +5,24 @@ from comic.models import Setting, ComicBook, ComicPage, ComicStatus, Directory
@admin.register(Setting)
class SettingAdmin(admin.ModelAdmin):
list_display = ('name', 'value')
list_display = ("name", "value")
@admin.register(ComicBook)
class ComicBookAdmin(admin.ModelAdmin):
list_display = ['file_name', 'date_added']
search_fields = ['file_name']
list_display = ["file_name", "date_added"]
search_fields = ["file_name"]
@admin.register(ComicPage)
class ComicPageAdmin(admin.ModelAdmin):
list_display = ('Comic', 'index', 'page_file_name', 'content_type')
list_filter = ['Comic']
list_display = ("Comic", "index", "page_file_name", "content_type")
list_filter = ["Comic"]
@admin.register(ComicStatus)
class ComicStatusAdmin(admin.ModelAdmin):
list_display = ['user', 'comic', 'last_read_page', 'unread']
list_display = ["user", "comic", "last_read_page", "unread"]
@admin.register(Directory)

View File

@@ -19,14 +19,14 @@ class RecentComics(Feed):
@staticmethod
def items() -> ComicBook:
return ComicBook.objects.order_by('-date_added')[:10]
return ComicBook.objects.order_by("-date_added")[:10]
def item_title(self, item: ComicBook) -> str:
return item.file_name
def item_description(self, item: ComicBook) -> str:
return item.date_added.strftime('%a, %e %b %Y %H:%M')
return item.date_added.strftime("%a, %e %b %Y %H:%M")
# item_link is only needed if NewsItem has no get_absolute_url method.
def item_link(self, item: ComicBook) -> str:
return '/comic/read/{0}/0/'.format(urlsafe_base64_encode(item.selector.bytes))
return "/comic/read/{0}/0/".format(urlsafe_base64_encode(item.selector.bytes))

View File

@@ -7,214 +7,137 @@ from comic.models import Setting
class InitialSetupForm(forms.Form):
username = forms.CharField(help_text='Username',
widget=forms.TextInput(
attrs={
'class': 'form-control',
}
))
email = forms.CharField(help_text='Email Address',
widget=forms.TextInput(
attrs={
'class': 'form-control'
}
))
password = forms.CharField(help_text='New Password',
widget=forms.PasswordInput(
attrs={
'class': 'form-control',
}
))
password_confirm = forms.CharField(help_text='New Password Confirmation',
widget=forms.PasswordInput(
attrs={
'class': 'form-control',
}
))
base_dir = forms.CharField(help_text='Base Directory',
widget=forms.TextInput(
attrs={
'class': 'form-control'
}
))
username = forms.CharField(help_text="Username", widget=forms.TextInput(attrs={"class": "form-control"}))
email = forms.CharField(help_text="Email Address", widget=forms.TextInput(attrs={"class": "form-control"}))
password = forms.CharField(help_text="New Password", widget=forms.PasswordInput(attrs={"class": "form-control"}))
password_confirm = forms.CharField(
help_text="New Password Confirmation", widget=forms.PasswordInput(attrs={"class": "form-control"})
)
base_dir = forms.CharField(help_text="Base Directory", widget=forms.TextInput(attrs={"class": "form-control"}))
def clean_base_dir(self):
data = self.cleaned_data['base_dir']
data = self.cleaned_data["base_dir"]
if not path.isdir(data):
raise forms.ValidationError('This is not a valid Directory')
raise forms.ValidationError("This is not a valid Directory")
return data
def clean(self):
form_data = self.cleaned_data
if form_data['password'] != form_data['password_confirm']:
raise forms.ValidationError('Passwords do not match.')
if len(form_data['password']) < 8:
raise forms.ValidationError('Password is too short')
if form_data["password"] != form_data["password_confirm"]:
raise forms.ValidationError("Passwords do not match.")
if len(form_data["password"]) < 8:
raise forms.ValidationError("Password is too short")
return form_data
class AccountForm(forms.Form):
username = forms.CharField(help_text='Username',
username = forms.CharField(
help_text="Username",
required=False,
widget=forms.TextInput(
attrs={
'class': 'form-control disabled',
'readonly': True,
}
))
email = forms.CharField(help_text='Email Address',
widget=forms.TextInput(
attrs={
'class': 'form-control'
}
))
password = forms.CharField(help_text='New Password',
widget=forms.TextInput(attrs={"class": "form-control disabled", "readonly": True}),
)
email = forms.CharField(help_text="Email Address", widget=forms.TextInput(attrs={"class": "form-control"}))
password = forms.CharField(
help_text="New Password", required=False, widget=forms.PasswordInput(attrs={"class": "form-control"})
)
password_confirm = forms.CharField(
help_text="New Password Confirmation",
required=False,
widget=forms.PasswordInput(
attrs={
'class': 'form-control',
}
))
password_confirm = forms.CharField(help_text='New Password Confirmation',
required=False,
widget=forms.PasswordInput(
attrs={
'class': 'form-control',
}
))
widget=forms.PasswordInput(attrs={"class": "form-control"}),
)
def clean_email(self):
data = self.cleaned_data['email']
user = User.objects.get(username=self.cleaned_data['username'])
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')
raise forms.ValidationError("Email Address is in use")
return data
def clean(self):
form_data = self.cleaned_data
if form_data['password'] != form_data['password_confirm']:
raise forms.ValidationError('Passwords do not match.')
if len(form_data['password']) < 8 & len(form_data['password']) != 0:
raise forms.ValidationError('Password is too short')
if form_data["password"] != form_data["password_confirm"]:
raise forms.ValidationError("Passwords do not match.")
if len(form_data["password"]) < 8 & len(form_data["password"]) != 0:
raise forms.ValidationError("Password is too short")
return form_data
class AddUserForm(forms.Form):
username = forms.CharField(help_text='Username',
widget=forms.TextInput(
attrs={
'class': 'form-control',
}
))
email = forms.CharField(help_text='Email Address',
widget=forms.TextInput(
attrs={
'class': 'form-control'
}
))
password = forms.CharField(help_text='New Password',
widget=forms.PasswordInput(
attrs={
'class': 'form-control',
}
))
password_confirm = forms.CharField(help_text='New Password Confirmation',
widget=forms.PasswordInput(
attrs={
'class': 'form-control',
}
))
username = forms.CharField(help_text="Username", widget=forms.TextInput(attrs={"class": "form-control"}))
email = forms.CharField(help_text="Email Address", widget=forms.TextInput(attrs={"class": "form-control"}))
password = forms.CharField(help_text="New Password", widget=forms.PasswordInput(attrs={"class": "form-control"}))
password_confirm = forms.CharField(
help_text="New Password Confirmation", widget=forms.PasswordInput(attrs={"class": "form-control"})
)
def clean_username(self):
data = self.cleaned_data['username']
data = self.cleaned_data["username"]
if User.objects.filter(username=data).exists():
raise forms.ValidationError('This username Exists.')
raise forms.ValidationError("This username Exists.")
return data
def clean_email(self):
data = self.cleaned_data['email']
data = self.cleaned_data["email"]
if User.objects.filter(email=data).exists():
raise forms.ValidationError('Email Address is in use')
raise forms.ValidationError("Email Address is in use")
return data
def clean(self):
form_data = self.cleaned_data
if form_data['password'] != form_data['password_confirm']:
raise forms.ValidationError('Passwords do not match.')
if len(form_data['password']) < 8:
raise forms.ValidationError('Password is too short')
if form_data["password"] != form_data["password_confirm"]:
raise forms.ValidationError("Passwords do not match.")
if len(form_data["password"]) < 8:
raise forms.ValidationError("Password is too short")
return form_data
class EditUserForm(forms.Form):
username = forms.CharField(help_text='Username',
username = forms.CharField(
help_text="Username",
required=False,
widget=forms.TextInput(
attrs={
'class': 'form-control disabled',
'readonly': True,
}
))
email = forms.CharField(help_text='Email Address',
widget=forms.TextInput(
attrs={
'class': 'form-control'
}
))
password = forms.CharField(help_text='New Password',
required=False,
widget=forms.PasswordInput(
attrs={
'class': 'form-control',
}
))
widget=forms.TextInput(attrs={"class": "form-control disabled", "readonly": True}),
)
email = forms.CharField(help_text="Email Address", widget=forms.TextInput(attrs={"class": "form-control"}))
password = forms.CharField(
help_text="New Password", required=False, widget=forms.PasswordInput(attrs={"class": "form-control"})
)
# TODO: allow setting superuser on users
@staticmethod
def get_initial_values(user):
out = {
'username': user.username,
'email': user.email
}
out = {"username": user.username, "email": user.email}
return out
def clean_email(self):
data = self.cleaned_data['email']
user = User.objects.get(username=self.cleaned_data['username'])
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')
raise forms.ValidationError("Email Address is in use")
return data
def clean_password(self):
data = self.cleaned_data['password']
data = self.cleaned_data["password"]
if len(data) < 8 & len(data) != 0:
raise forms.ValidationError('Password is too short')
raise forms.ValidationError("Password is too short")
return data
class SettingsForm(forms.Form):
base_dir = forms.CharField(help_text='Base Directory',
widget=forms.TextInput(
attrs={
'class': 'form-control'
}
))
base_dir = forms.CharField(help_text="Base Directory", widget=forms.TextInput(attrs={"class": "form-control"}))
def clean_base_dir(self):
data = self.cleaned_data['base_dir']
data = self.cleaned_data["base_dir"]
if not path.isdir(data):
raise forms.ValidationError('This is not a valid Directory')
raise forms.ValidationError("This is not a valid Directory")
return data
@staticmethod
def get_initial_values():
base_dir, _ = Setting.objects.get_or_create(name='BASE_DIR')
base_dir, _ = Setting.objects.get_or_create(name="BASE_DIR")
initial = {
'base_dir': base_dir.value,
}
initial = {"base_dir": base_dir.value}
return initial

View File

@@ -7,11 +7,11 @@ from comic.models import Setting, Directory, ComicBook
class Command(BaseCommand):
help = 'Scan directories to Update Comic DB'
help = "Scan directories to Update Comic DB"
def __init__(self):
super().__init__()
self.base_dir = Setting.objects.get(name='BASE_DIR').value
self.base_dir = Setting.objects.get(name="BASE_DIR").value
def handle(self, *args, **options):
self.scan_directory()
@@ -36,25 +36,21 @@ class Command(BaseCommand):
for file in os.listdir(comic_dir):
if isdir(os.path.join(comic_dir, file)):
if directory:
next_directory, created = Directory.objects.get_or_create(name=file,
parent=directory)
next_directory, created = Directory.objects.get_or_create(name=file, parent=directory)
else:
next_directory, created = Directory.objects.get_or_create(name=file,
parent__isnull=True)
next_directory, created = Directory.objects.get_or_create(name=file, parent__isnull=True)
if created:
next_directory.save()
self.scan_directory(next_directory)
else:
try:
if directory:
book = ComicBook.objects.get(file_name=file,
directory=directory)
book = ComicBook.objects.get(file_name=file, directory=directory)
if book.version == 0:
book.version = 1
book.save()
else:
book = ComicBook.objects.get(file_name=file,
directory__isnull=True)
book = ComicBook.objects.get(file_name=file, directory__isnull=True)
if book.version == 0:
if directory:
book.directory = directory

View File

@@ -6,16 +6,15 @@ from django.db import models, migrations
class Migration(migrations.Migration):
dependencies = [
]
dependencies = []
operations = [
migrations.CreateModel(
name='Setting',
name="Setting",
fields=[
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
('name', models.CharField(max_length=50)),
('value', models.TextField()),
("id", models.AutoField(verbose_name="ID", serialize=False, auto_created=True, primary_key=True)),
("name", models.CharField(max_length=50)),
("value", models.TextField()),
],
),
)
]

View File

@@ -6,14 +6,8 @@ from django.db import models, migrations
class Migration(migrations.Migration):
dependencies = [
('comic', '0001_initial'),
]
dependencies = [("comic", "0001_initial")]
operations = [
migrations.AlterField(
model_name='setting',
name='name',
field=models.CharField(unique=True, max_length=50),
),
migrations.AlterField(model_name="setting", name="name", field=models.CharField(unique=True, max_length=50))
]

View File

@@ -6,27 +6,25 @@ from django.db import models, migrations
class Migration(migrations.Migration):
dependencies = [
('comic', '0002_auto_20150616_1613'),
]
dependencies = [("comic", "0002_auto_20150616_1613")]
operations = [
migrations.CreateModel(
name='ComicBook',
name="ComicBook",
fields=[
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
('file_name', models.CharField(unique=True, max_length=100)),
('last_read_page', models.IntegerField()),
("id", models.AutoField(verbose_name="ID", serialize=False, auto_created=True, primary_key=True)),
("file_name", models.CharField(unique=True, max_length=100)),
("last_read_page", models.IntegerField()),
],
),
migrations.CreateModel(
name='ComicPage',
name="ComicPage",
fields=[
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
('index', models.IntegerField()),
('page_file_name', models.CharField(max_length=100)),
('content_type', models.CharField(max_length=30)),
('Comic', models.ForeignKey(to='comic.ComicBook', on_delete=models.CASCADE)),
("id", models.AutoField(verbose_name="ID", serialize=False, auto_created=True, primary_key=True)),
("index", models.IntegerField()),
("page_file_name", models.CharField(max_length=100)),
("content_type", models.CharField(max_length=30)),
("Comic", models.ForeignKey(to="comic.ComicBook", on_delete=models.CASCADE)),
],
),
]

View File

@@ -6,15 +6,10 @@ from django.db import models, migrations
class Migration(migrations.Migration):
dependencies = [
('comic', '0003_comicbook_comicpage'),
]
dependencies = [("comic", "0003_comicbook_comicpage")]
operations = [
migrations.AddField(
model_name='comicbook',
name='unread',
field=models.BooleanField(default=True),
preserve_default=False,
),
model_name="comicbook", name="unread", field=models.BooleanField(default=True), preserve_default=False
)
]

View File

@@ -7,36 +7,27 @@ from django.db import models, migrations
class Migration(migrations.Migration):
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
('comic', '0004_comicbook_unread'),
]
dependencies = [migrations.swappable_dependency(settings.AUTH_USER_MODEL), ("comic", "0004_comicbook_unread")]
operations = [
migrations.CreateModel(
name='ComicStatus',
name="ComicStatus",
fields=[
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
('last_read_page', models.IntegerField()),
('unread', models.BooleanField()),
("id", models.AutoField(verbose_name="ID", serialize=False, auto_created=True, primary_key=True)),
("last_read_page", models.IntegerField()),
("unread", models.BooleanField()),
],
),
migrations.RemoveField(
model_name='comicbook',
name='last_read_page',
),
migrations.RemoveField(
model_name='comicbook',
name='unread',
migrations.RemoveField(model_name="comicbook", name="last_read_page"),
migrations.RemoveField(model_name="comicbook", name="unread"),
migrations.AddField(
model_name="comicstatus",
name="comic",
field=models.ForeignKey(to="comic.ComicBook", on_delete=models.CASCADE),
),
migrations.AddField(
model_name='comicstatus',
name='comic',
field=models.ForeignKey(to='comic.ComicBook', on_delete=models.CASCADE),
),
migrations.AddField(
model_name='comicstatus',
name='user',
model_name="comicstatus",
name="user",
field=models.ForeignKey(to=settings.AUTH_USER_MODEL, on_delete=models.CASCADE),
),
]

View File

@@ -6,19 +6,9 @@ from django.db import models, migrations
class Migration(migrations.Migration):
dependencies = [
('comic', '0005_auto_20150625_1400'),
]
dependencies = [("comic", "0005_auto_20150625_1400")]
operations = [
migrations.AlterField(
model_name='comicstatus',
name='last_read_page',
field=models.IntegerField(default=0),
),
migrations.AlterField(
model_name='comicstatus',
name='unread',
field=models.BooleanField(default=True),
),
migrations.AlterField(model_name="comicstatus", name="last_read_page", field=models.IntegerField(default=0)),
migrations.AlterField(model_name="comicstatus", name="unread", field=models.BooleanField(default=True)),
]

View File

@@ -6,14 +6,8 @@ from django.db import models, migrations
class Migration(migrations.Migration):
dependencies = [
('comic', '0006_auto_20150625_1411'),
]
dependencies = [("comic", "0006_auto_20150625_1411")]
operations = [
migrations.AlterField(
model_name='setting',
name='name',
field=models.CharField(unique=True, max_length=100),
),
migrations.AlterField(model_name="setting", name="name", field=models.CharField(unique=True, max_length=100))
]

View File

@@ -11,39 +11,40 @@ import uuid
class Migration(migrations.Migration):
dependencies = [
('comic', '0007_auto_20150626_1820'),
]
dependencies = [("comic", "0007_auto_20150626_1820")]
operations = [
migrations.CreateModel(
name='Directory',
name="Directory",
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('name', models.CharField(max_length=100)),
('selector', models.UUIDField(default=uuid.uuid4, null=True)),
('parent', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='comic.Directory')),
("id", models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")),
("name", models.CharField(max_length=100)),
("selector", models.UUIDField(default=uuid.uuid4, null=True)),
(
"parent",
models.ForeignKey(
blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to="comic.Directory"
),
),
],
),
migrations.AddField(
model_name='comicbook',
name='date_added',
field=models.DateTimeField(auto_now_add=True, default=datetime.datetime(2016, 3, 31, 10, 40, 30, 62170, tzinfo=utc)),
model_name="comicbook",
name="date_added",
field=models.DateTimeField(
auto_now_add=True, default=datetime.datetime(2016, 3, 31, 10, 40, 30, 62170, tzinfo=utc)
),
preserve_default=False,
),
migrations.AddField(
model_name='comicbook',
name='selector',
field=models.UUIDField(default=uuid.uuid4, null=True),
model_name="comicbook", name="selector", field=models.UUIDField(default=uuid.uuid4, null=True)
),
migrations.AddField(model_name="comicbook", name="version", field=models.IntegerField(default=0)),
migrations.AddField(
model_name='comicbook',
name='version',
field=models.IntegerField(default=0),
model_name="comicbook",
name="directory",
field=models.ForeignKey(
blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to="comic.Directory"
),
migrations.AddField(
model_name='comicbook',
name='directory',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='comic.Directory'),
),
]

View File

@@ -8,11 +8,11 @@ import uuid
def gen_uuid(apps, schema_editor):
comicbook = apps.get_model('comic', 'comicbook')
comicbook = apps.get_model("comic", "comicbook")
for row in comicbook.objects.all():
row.selector = uuid.uuid4()
row.save()
directory = apps.get_model('comic', 'directory')
directory = apps.get_model("comic", "directory")
for row in directory.objects.all():
row.selector = uuid.uuid4()
row.save()
@@ -20,10 +20,6 @@ def gen_uuid(apps, schema_editor):
class Migration(migrations.Migration):
dependencies = [
('comic', '0008_auto_20160331_1140'),
]
dependencies = [("comic", "0008_auto_20160331_1140")]
operations = [
migrations.RunPython(gen_uuid, reverse_code=migrations.RunPython.noop),
]
operations = [migrations.RunPython(gen_uuid, reverse_code=migrations.RunPython.noop)]

View File

@@ -9,19 +9,13 @@ import uuid
class Migration(migrations.Migration):
dependencies = [
('comic', '0009_auto_20160331_1140'),
]
dependencies = [("comic", "0009_auto_20160331_1140")]
operations = [
migrations.AlterField(
model_name='comicbook',
name='selector',
field=models.UUIDField(default=uuid.uuid4, unique=True),
model_name="comicbook", name="selector", field=models.UUIDField(default=uuid.uuid4, unique=True)
),
migrations.AlterField(
model_name='directory',
name='selector',
field=models.UUIDField(default=uuid.uuid4, unique=True),
model_name="directory", name="selector", field=models.UUIDField(default=uuid.uuid4, unique=True)
),
]

View File

@@ -7,14 +7,6 @@ from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('comic', '0010_auto_20160331_1140'),
]
dependencies = [("comic", "0010_auto_20160331_1140")]
operations = [
migrations.AlterField(
model_name='comicbook',
name='version',
field=models.IntegerField(default=1),
),
]
operations = [migrations.AlterField(model_name="comicbook", name="version", field=models.IntegerField(default=1))]

View File

@@ -8,19 +8,17 @@ import uuid
class Migration(migrations.Migration):
dependencies = [
('comic', '0011_auto_20160331_1141'),
]
dependencies = [("comic", "0011_auto_20160331_1141")]
operations = [
migrations.AlterField(
model_name='comicbook',
name='selector',
model_name="comicbook",
name="selector",
field=models.UUIDField(db_index=True, default=uuid.uuid4, unique=True),
),
migrations.AlterField(
model_name='directory',
name='selector',
model_name="directory",
name="selector",
field=models.UUIDField(db_index=True, default=uuid.uuid4, unique=True),
),
]

View File

@@ -7,14 +7,8 @@ from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('comic', '0012_auto_20160401_0949'),
]
dependencies = [("comic", "0012_auto_20160401_0949")]
operations = [
migrations.AddField(
model_name='comicstatus',
name='finished',
field=models.BooleanField(default=False),
),
migrations.AddField(model_name="comicstatus", name="finished", field=models.BooleanField(default=False))
]

View File

@@ -5,22 +5,19 @@ from __future__ import unicode_literals
from django.db import migrations
from django.db.models import Max
def set_finished(apps, schema_editor):
comicstatus = apps.get_model('comic', 'comicstatus')
comicpage = apps.get_model('comic', 'ComicPage')
comicstatus = apps.get_model("comic", "comicstatus")
comicpage = apps.get_model("comic", "ComicPage")
for row in comicstatus.objects.all():
last_page = comicpage.objects.filter(Comic=row.comic).aggregate(Max('index'))
if row.last_read_page == last_page['index__max']:
last_page = comicpage.objects.filter(Comic=row.comic).aggregate(Max("index"))
if row.last_read_page == last_page["index__max"]:
row.finished = True
row.save()
class Migration(migrations.Migration):
dependencies = [
('comic', '0013_comicstatus_finished'),
]
dependencies = [("comic", "0013_comicstatus_finished")]
operations = [
migrations.RunPython(set_finished, reverse_code=migrations.RunPython.noop),
]
operations = [migrations.RunPython(set_finished, reverse_code=migrations.RunPython.noop)]

View File

@@ -7,14 +7,8 @@ from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('comic', '0014_auto_20160404_1402'),
]
dependencies = [("comic", "0014_auto_20160404_1402")]
operations = [
migrations.AlterField(
model_name='comicbook',
name='file_name',
field=models.CharField(max_length=100),
),
migrations.AlterField(model_name="comicbook", name="file_name", field=models.CharField(max_length=100))
]

View File

@@ -6,14 +6,8 @@ from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('comic', '0015_auto_20160405_1126'),
]
dependencies = [("comic", "0015_auto_20160405_1126")]
operations = [
migrations.AlterField(
model_name='comicpage',
name='page_file_name',
field=models.CharField(max_length=200),
),
migrations.AlterField(model_name="comicpage", name="page_file_name", field=models.CharField(max_length=200))
]

View File

@@ -10,19 +10,18 @@ from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
('comic', '0016_auto_20160414_1335'),
]
dependencies = [migrations.swappable_dependency(settings.AUTH_USER_MODEL), ("comic", "0016_auto_20160414_1335")]
operations = [
migrations.CreateModel(
name='UserMisc',
name="UserMisc",
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('feed_id', models.UUIDField(db_index=True, default=uuid.uuid4, unique=True)),
("id", models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")),
("feed_id", models.UUIDField(db_index=True, default=uuid.uuid4, unique=True)),
(
'user', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
],
"user",
models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL),
),
],
)
]

View File

@@ -6,17 +6,13 @@ from django.db import migrations
def gen_feeds(apps, schema_editor):
user_misc = apps.get_model('comic', 'UserMisc')
User = apps.get_model('auth', 'user')
user_misc = apps.get_model("comic", "UserMisc")
User = apps.get_model("auth", "user")
for user in User.objects.all():
um = user_misc.objects.create(user=user)
class Migration(migrations.Migration):
dependencies = [
('comic', '0017_usermisc'),
]
dependencies = [("comic", "0017_usermisc")]
operations = [
migrations.RunPython(gen_feeds, reverse_code=migrations.RunPython.noop),
]
operations = [migrations.RunPython(gen_feeds, reverse_code=migrations.RunPython.noop)]

View File

@@ -27,11 +27,11 @@ class Setting(models.Model):
class Directory(models.Model):
name = models.CharField(max_length=100)
parent = models.ForeignKey('Directory', null=True, blank=True, on_delete=models.CASCADE)
parent = models.ForeignKey("Directory", null=True, blank=True, on_delete=models.CASCADE)
selector = models.UUIDField(unique=True, default=uuid.uuid4, db_index=True)
def __str__(self):
return 'Directory: {0}; {1}'.format(self.name, self.parent)
return "Directory: {0}; {1}".format(self.name, self.parent)
@property
def path(self):
@@ -83,7 +83,7 @@ class ComicBook(models.Model):
return urlsafe_base64_encode(self.selector.bytes)
def get_image(self, page):
base_dir = Setting.objects.get(name='BASE_DIR').value
base_dir = Setting.objects.get(name="BASE_DIR").value
if self.directory:
archive_path = path.join(base_dir, self.directory.path, self.file_name)
else:
@@ -109,11 +109,11 @@ class ComicBook(models.Model):
class Navigation:
next_index = 0
next_path = ''
next_path = ""
prev_index = 0
prev_path = ''
prev_path = ""
cur_index = 0
cur_path = ''
cur_path = ""
q_prev_to_directory = False
q_next_to_directory = False
@@ -122,10 +122,7 @@ class ComicBook(models.Model):
setattr(self, arg, kwargs[arg])
def nav(self, page, user):
out = self.Navigation(
cur_index=page,
cur_path=urlsafe_base64_encode(self.selector.bytes)
)
out = self.Navigation(cur_index=page, cur_path=urlsafe_base64_encode(self.selector.bytes))
if page == 0:
out.prev_path, out.prev_index = self.nav_get_prev_comic(user)
if out.prev_index == -1:
@@ -144,7 +141,7 @@ class ComicBook(models.Model):
return out
def nav_get_prev_comic(self, user):
base_dir = Setting.objects.get(name='BASE_DIR').value
base_dir = Setting.objects.get(name="BASE_DIR").value
if self.directory:
folder = path.join(base_dir, self.directory.path)
else:
@@ -155,7 +152,7 @@ class ComicBook(models.Model):
if self.directory:
comic_path = urlsafe_base64_encode(self.directory.selector.bytes)
else:
comic_path = ''
comic_path = ""
index = -1
else:
prev_comic = dir_list[comic_index - 1]
@@ -163,11 +160,9 @@ class ComicBook(models.Model):
if not path.isdir(path.join(folder, prev_comic)):
try:
if self.directory:
book = ComicBook.objects.get(file_name=prev_comic,
directory=self.directory)
book = ComicBook.objects.get(file_name=prev_comic, directory=self.directory)
else:
book = ComicBook.objects.get(file_name=prev_comic,
directory__isnull=True)
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)
@@ -180,12 +175,12 @@ class ComicBook(models.Model):
if self.directory:
comic_path = urlsafe_base64_encode(self.directory.selector.bytes)
else:
comic_path = ''
comic_path = ""
index = -1
return comic_path, index
def nav_get_next_comic(self, user):
base_dir = Setting.objects.get(name='BASE_DIR').value
base_dir = Setting.objects.get(name="BASE_DIR").value
if self.directory:
folder = path.join(base_dir, self.directory.path)
else:
@@ -196,11 +191,9 @@ class ComicBook(models.Model):
next_comic = dir_list[comic_index + 1]
try:
if self.directory:
book = ComicBook.objects.get(file_name=next_comic,
directory=self.directory)
book = ComicBook.objects.get(file_name=next_comic, directory=self.directory)
else:
book = ComicBook.objects.get(file_name=next_comic,
directory__isnull=True)
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)
@@ -215,18 +208,18 @@ class ComicBook(models.Model):
if self.directory:
comic_path = urlsafe_base64_encode(self.directory.selector.bytes)
else:
comic_path = ''
comic_path = ""
index = -1
return comic_path, index
class DirFile:
def __init__(self):
self.name = ''
self.name = ""
self.isdir = False
self.icon = ''
self.icon = ""
self.iscb = False
self.location = ''
self.label = ''
self.location = ""
self.label = ""
self.cur_page = 0
def __str__(self):
@@ -234,7 +227,7 @@ class ComicBook(models.Model):
@property
def pages(self):
return [cp for cp in ComicPage.objects.filter(Comic=self).order_by('index')]
return [cp for cp in ComicPage.objects.filter(Comic=self).order_by("index")]
def page_name(self, index):
return ComicPage.objects.get(Comic=self, index=index).page_file_name
@@ -247,15 +240,14 @@ class ComicBook(models.Model):
:type directory: Directory
"""
try:
book = ComicBook.objects.get(file_name=comic_file_name,
version=0)
book = ComicBook.objects.get(file_name=comic_file_name, version=0)
book.directory = directory
book.version = 1
book.save()
return book
except ComicBook.DoesNotExist:
pass
base_dir = Setting.objects.get(name='BASE_DIR').value
base_dir = Setting.objects.get(name="BASE_DIR").value
if directory:
comic_full_path = path.join(base_dir, directory.get_path(), comic_file_name)
else:
@@ -272,32 +264,30 @@ class ComicBook(models.Model):
return comic_file_name
with atomic():
if directory:
book = ComicBook(file_name=comic_file_name,
directory=directory)
book = ComicBook(file_name=comic_file_name, directory=directory)
else:
book = ComicBook(file_name=comic_file_name)
book.save()
page_index = 0
for page_file_name in sorted([str(x) for x in cbx.namelist()], key=str.lower):
try:
dot_index = page_file_name.rindex('.') + 1
dot_index = page_file_name.rindex(".") + 1
except ValueError:
continue
ext = page_file_name.lower()[dot_index:]
if ext in ['jpg', 'jpeg']:
content_type = 'image/jpeg'
elif ext == 'png':
content_type = 'image/png'
elif ext == 'bmp':
content_type = 'image/bmp'
elif ext == 'gif':
content_type = 'image/gif'
if ext in ["jpg", "jpeg"]:
content_type = "image/jpeg"
elif ext == "png":
content_type = "image/png"
elif ext == "bmp":
content_type = "image/bmp"
elif ext == "gif":
content_type = "image/gif"
else:
content_type = 'text/plain'
page = ComicPage(Comic=book,
index=page_index,
page_file_name=page_file_name,
content_type=content_type)
content_type = "text/plain"
page = ComicPage(
Comic=book, index=page_index, page_file_name=page_file_name, content_type=content_type
)
page.save()
page_index += 1
return book
@@ -336,8 +326,12 @@ class ComicStatus(models.Model):
return self.__repr__()
def __repr__(self):
return f'<ComicStatus:{self.user.username}:{self.comic.file_name}:{self.last_read_page}:' \
f'{self.unread}:{self.finished}'
return (
f"<ComicStatus:{self.user.username}:{self.comic.file_name}:{self.last_read_page}:"
f"{self.unread}:{self.finished}"
)
# TODO: add support to reference items last being read

File diff suppressed because it is too large Load Diff

View File

@@ -12,9 +12,7 @@ from comic.util import generate_directory
class ComicBookTests(TestCase):
def setUp(self):
Setting.objects.create(
name="BASE_DIR", value=path.join(os.getcwd(), "comic", "test")
)
Setting.objects.create(name="BASE_DIR", value=path.join(os.getcwd(), "comic", "test"))
User.objects.create_user("test", "test@test.com", "test")
user = User.objects.first()
ComicBook.process_comic_book("test1.rar")
@@ -133,51 +131,34 @@ class ComicBookTests(TestCase):
d = Directory.objects.get(name="test_folder", parent__isnull=True)
location = "/comic/{0}/".format(urlsafe_base64_encode(d.selector.bytes))
self.assertEqual(dir1.location, location)
self.assertEqual(
dir1.label,
'<center><span class="label label-default">Empty</span></center>',
)
self.assertEqual(dir1.label, '<center><span class="label label-default">Empty</span></center>')
dir2 = folders[1]
self.assertEqual(dir2.name, "test1.rar")
self.assertEqual(dir2.type, "book")
self.assertEqual(dir2.icon, "glyphicon-book")
c = ComicBook.objects.get(file_name="test1.rar", directory__isnull=True)
location = "/comic/read/{0}/{1}/".format(
urlsafe_base64_encode(c.selector.bytes), "0"
)
location = "/comic/read/{0}/{1}/".format(urlsafe_base64_encode(c.selector.bytes), "0")
self.assertEqual(dir2.location, location)
self.assertEqual(
dir2.label,
'<center><span class="label label-default">Unread</span></center>',
)
self.assertEqual(dir2.label, '<center><span class="label label-default">Unread</span></center>')
dir3 = folders[2]
self.assertEqual(dir3.name, "test2.rar")
self.assertEqual(dir3.type, "book")
self.assertEqual(dir3.icon, "glyphicon-book")
c = ComicBook.objects.get(file_name="test2.rar", directory__isnull=True)
location = "/comic/read/{0}/{1}/".format(
urlsafe_base64_encode(c.selector.bytes), "2"
)
location = "/comic/read/{0}/{1}/".format(urlsafe_base64_encode(c.selector.bytes), "2")
self.assertEqual(dir3.location, location)
self.assertEqual(
dir3.label, '<center><span class="label label-primary">3/4</span></center>'
)
self.assertEqual(dir3.label, '<center><span class="label label-primary">3/4</span></center>')
dir4 = folders[3]
self.assertEqual(dir4.name, "test3.rar")
self.assertEqual(dir4.type, "book")
self.assertEqual(dir3.icon, "glyphicon-book")
c = ComicBook.objects.get(file_name="test3.rar", directory__isnull=True)
location = "/comic/read/{0}/{1}/".format(
urlsafe_base64_encode(c.selector.bytes), "0"
)
location = "/comic/read/{0}/{1}/".format(urlsafe_base64_encode(c.selector.bytes), "0")
self.assertEqual(dir4.location, location)
self.assertEqual(
dir4.label,
'<center><span class="label label-default">Unread</span></center>',
)
self.assertEqual(dir4.label, '<center><span class="label label-default">Unread</span></center>')
def test_pages(self):
book = ComicBook.objects.get(file_name="test1.rar")
@@ -217,9 +198,7 @@ class ComicBookTests(TestCase):
response = c.post("/comic/list_json/")
self.assertEqual(response.status_code, 200)
directory = Directory.objects.first()
response = c.post(
f"/comic/list_json/{urlsafe_base64_encode(directory.selector.bytes)}/"
)
response = c.post(f"/comic/list_json/{urlsafe_base64_encode(directory.selector.bytes)}/")
self.assertEqual(response.status_code, 200)
def test_recent_comics(self):
@@ -241,12 +220,7 @@ class ComicBookTests(TestCase):
generate_directory(User.objects.first())
ComicStatus.objects.all().delete()
req_data = {
"start": "0",
"length": "10",
"search[value]": "",
"order[0][dir]": "desc",
}
req_data = {"start": "0", "length": "10", "search[value]": "", "order[0][dir]": "desc"}
response = c.post("/comic/recent/json/", req_data)
self.assertEqual(response.status_code, 200)
req_data["search[value]"] = "test1.rar"
@@ -261,13 +235,11 @@ class ComicBookTests(TestCase):
{
"date": book.date_added.strftime("%d/%m/%y-%H:%M"),
"icon": '<span class="glyphicon glyphicon-book"></span>',
"label": '<center><span class="label '
'label-default">Unread</span></center>',
"label": '<center><span class="label ' 'label-default">Unread</span></center>',
"name": "test1.rar",
"selector": urlsafe_base64_encode(book.selector.bytes),
"type": "book",
"url": f"/comic/read/"
f"{urlsafe_base64_encode(book.selector.bytes)}/0/",
"url": f"/comic/read/" f"{urlsafe_base64_encode(book.selector.bytes)}/0/",
}
],
"recordsFiltered": 1,
@@ -302,11 +274,7 @@ class ComicBookTests(TestCase):
response = c.get("/comic/edit/")
self.assertEqual(response.status_code, 405)
req_data = {
"comic_list_length": 10,
"func": "unread",
"selected": book.selector_string,
}
req_data = {"comic_list_length": 10, "func": "unread", "selected": book.selector_string}
response = c.post("/comic/edit/", req_data)
self.assertEqual(response.status_code, 200)

View File

@@ -2,20 +2,21 @@ from django.conf.urls import url
from . import feeds
from . import views
urlpatterns = [
url(r'^$', views.comic_list, name='index'),
url(r'^settings/$', views.settings_page, name='settings'),
url(r'^settings/users/$', views.users_page, name='users'),
url(r'^settings/users/(?P<user_id>[0-9]+)/$', views.user_config_page, name='users'),
url(r'^settings/users/add/$', views.user_add_page, name='users'),
url(r'^account/$', views.account_page, name='account'),
url(r'^read/(?P<comic_selector>[\w-]+)/(?P<page>[0-9]+)/$', views.read_comic, name='read_comic'),
url(r'^read/(?P<comic_selector>[\w-]+)/(?P<page>[0-9]+)/img$', views.get_image, name='get_image'),
url(r'^list_json/$', views.comic_list_json, name='comic_list_json1'),
url(r'^list_json/(?P<directory_selector>[\w-]+)/$', views.comic_list_json, name='comic_list_json2'),
url(r'^recent/$', views.recent_comics, name='recent_comics'),
url(r'^recent/json/$', views.recent_comics_json, name='recent_comics_json'),
url(r'^edit/$', views.comic_edit, name='comic_edit'),
url(r'^feed/(?P<user_selector>[\w-]+)/$', feeds.RecentComics()),
url(r'^(?P<directory_selector>[\w-]+)/$', views.comic_list, name='comic_list'),
url(r"^$", views.comic_list, name="index"),
url(r"^settings/$", views.settings_page, name="settings"),
url(r"^settings/users/$", views.users_page, name="users"),
url(r"^settings/users/(?P<user_id>[0-9]+)/$", views.user_config_page, name="users"),
url(r"^settings/users/add/$", views.user_add_page, name="users"),
url(r"^account/$", views.account_page, name="account"),
url(r"^read/(?P<comic_selector>[\w-]+)/(?P<page>[0-9]+)/$", views.read_comic, name="read_comic"),
url(r"^read/(?P<comic_selector>[\w-]+)/(?P<page>[0-9]+)/img$", views.get_image, name="get_image"),
url(r"^list_json/$", views.comic_list_json, name="comic_list_json1"),
url(r"^list_json/(?P<directory_selector>[\w-]+)/$", views.comic_list_json, name="comic_list_json2"),
url(r"^recent/$", views.recent_comics, name="recent_comics"),
url(r"^recent/json/$", views.recent_comics_json, name="recent_comics_json"),
url(r"^edit/$", views.comic_edit, name="comic_edit"),
url(r"^feed/(?P<user_selector>[\w-]+)/$", feeds.RecentComics()),
url(r"^(?P<directory_selector>[\w-]+)/$", views.comic_list, name="comic_list"),
]

View File

@@ -8,32 +8,32 @@ from .models import ComicBook, Setting, ComicStatus, Directory
def generate_title_from_path(file_path):
if file_path == '':
return 'CBWebReader'
return 'CBWebReader - ' + ' - '.join(file_path.split(path.sep))
if file_path == "":
return "CBWebReader"
return "CBWebReader - " + " - ".join(file_path.split(path.sep))
class Menu:
def __init__(self, user, page=''):
def __init__(self, user, page=""):
"""
:type page: str
"""
self.menu_items = OrderedDict()
self.menu_items['Browse'] = '/comic/'
self.menu_items['Recent'] = '/comic/recent/'
self.menu_items['Account'] = '/comic/account/'
self.menu_items["Browse"] = "/comic/"
self.menu_items["Recent"] = "/comic/recent/"
self.menu_items["Account"] = "/comic/account/"
if user.is_superuser:
self.menu_items['Settings'] = '/comic/settings/'
self.menu_items['Users'] = '/comic/settings/users/'
self.menu_items['Logout'] = '/logout/'
self.menu_items["Settings"] = "/comic/settings/"
self.menu_items["Users"] = "/comic/settings/users/"
self.menu_items["Logout"] = "/logout/"
self.current_page = page
class Breadcrumb:
def __init__(self):
self.name = 'Home'
self.url = '/comic/'
self.name = "Home"
self.url = "/comic/"
def __str__(self):
return self.name
@@ -56,12 +56,12 @@ def generate_breadcrumbs_from_path(directory=False, book=False):
for item in folders[::-1]:
bc = Breadcrumb()
bc.name = item.name
bc.url = '/comic/' + urlsafe_base64_encode(item.selector.bytes)
bc.url = "/comic/" + urlsafe_base64_encode(item.selector.bytes)
output.append(bc)
if book:
bc = Breadcrumb()
bc.name = book.file_name
bc.url = '/read/' + urlsafe_base64_encode(book.selector.bytes)
bc.url = "/read/" + urlsafe_base64_encode(book.selector.bytes)
output.append(bc)
return output
@@ -79,46 +79,45 @@ def generate_breadcrumbs_from_menu(paths):
class DirFile:
def __init__(self):
self.name = ''
self.icon = ''
self.location = ''
self.label = ''
self.type = ''
self.selector = ''
self.name = ""
self.icon = ""
self.location = ""
self.label = ""
self.type = ""
self.selector = ""
def __str__(self):
return self.name
def populate_directory(self, directory, user):
self.name = directory.name
self.icon = 'glyphicon-folder-open'
self.icon = "glyphicon-folder-open"
self.selector = urlsafe_base64_encode(directory.selector.bytes)
self.location = '/comic/{0}/'.format(self.selector)
self.location = "/comic/{0}/".format(self.selector)
self.label = generate_dir_status(user, directory)
self.type = 'directory'
self.type = "directory"
def populate_comic(self, comic, user):
if type(comic) == str:
self.icon = 'glyphicon-remove'
self.icon = "glyphicon-remove"
self.name = comic
self.selector = '0'
self.location = '/'
self.selector = "0"
self.location = "/"
self.label = '<center><span class="label label-danger">Error</span></center>'
self.type = 'book'
self.type = "book"
else:
self.icon = 'glyphicon-book'
self.icon = "glyphicon-book"
self.name = comic.file_name
status, created = ComicStatus.objects.get_or_create(comic=comic, user=user)
if created:
status.save()
self.selector = urlsafe_base64_encode(comic.selector.bytes)
self.location = '/comic/read/{0}/{1}/'.format(self.selector,
status.last_read_page)
self.location = "/comic/read/{0}/{1}/".format(self.selector, status.last_read_page)
self.label = generate_label(comic, status)
self.type = 'book'
self.type = "book"
def __repr__(self):
return f'<DirFile: {self.name}: {self.type}>'
return f"<DirFile: {self.name}: {self.type}>"
def generate_directory(user, directory=False):
@@ -126,7 +125,7 @@ def generate_directory(user, directory=False):
:type user: User
:type directory: Directory
"""
base_dir = Setting.objects.get(name='BASE_DIR').value
base_dir = Setting.objects.get(name="BASE_DIR").value
files = []
if directory:
ordered_dir_list = listdir(path.join(base_dir, directory.path))
@@ -136,15 +135,11 @@ def generate_directory(user, directory=False):
dir_list = [x for x in ordered_dir_list if path.isdir(path.join(base_dir, x))]
file_list = [x for x in ordered_dir_list if x not in dir_list]
if directory:
dir_list_obj = Directory.objects.filter(name__in=dir_list,
parent=directory)
file_list_obj = ComicBook.objects.filter(file_name__in=file_list,
directory=directory)
dir_list_obj = Directory.objects.filter(name__in=dir_list, parent=directory)
file_list_obj = ComicBook.objects.filter(file_name__in=file_list, directory=directory)
else:
dir_list_obj = Directory.objects.filter(name__in=dir_list,
parent__isnull=True)
file_list_obj = ComicBook.objects.filter(file_name__in=file_list,
directory__isnull=True)
dir_list_obj = Directory.objects.filter(name__in=dir_list, parent__isnull=True)
file_list_obj = ComicBook.objects.filter(file_name__in=file_list, directory__isnull=True)
for directory_obj in dir_list_obj:
df = DirFile()
df.populate_directory(directory_obj, user)
@@ -159,8 +154,7 @@ def generate_directory(user, directory=False):
file_list.remove(file_obj.file_name)
for directory_name in dir_list:
if directory:
directory_obj = Directory(name=directory_name,
parent=directory)
directory_obj = Directory(name=directory_name, parent=directory)
else:
directory_obj = Directory(name=directory_name)
directory_obj.save()
@@ -168,7 +162,7 @@ def generate_directory(user, directory=False):
df.populate_directory(directory_obj, user)
files.append(df)
for file_name in file_list:
if file_name.lower()[-4:] in ['.rar', '.zip', '.cbr', '.cbz']:
if file_name.lower()[-4:] in [".rar", ".zip", ".cbr", ".cbz"]:
book = ComicBook.process_comic_book(file_name, directory)
df = DirFile()
df.populate_comic(book, user)
@@ -184,17 +178,17 @@ def generate_label(book, status):
elif (status.last_read_page + 1) == book.page_count:
label_text = '<center><span class="label label-success">Read</span></center>'
else:
label_text = '<center><span class="label label-primary">%s/%s</span></center>' % \
(status.last_read_page + 1, book.page_count)
label_text = '<center><span class="label label-primary">%s/%s</span></center>' % (
status.last_read_page + 1,
book.page_count,
)
return label_text
def generate_dir_status(user, directory):
cb_list = ComicBook.objects.filter(directory=directory)
total = cb_list.count()
total_read = ComicStatus.objects.filter(user=user,
comic__in=cb_list,
finished=True).count()
total_read = ComicStatus.objects.filter(user=user, comic__in=cb_list, finished=True).count()
if total == 0:
return '<center><span class="label label-default">Empty</span></center>'
elif total == total_read:

View File

@@ -18,8 +18,14 @@ from django.views.decorators.http import require_POST
from .forms import SettingsForm, AccountForm, EditUserForm, AddUserForm, InitialSetupForm
from .models import Setting, ComicBook, ComicStatus, Directory, ComicPage, UserMisc
from .util import generate_breadcrumbs_from_path, generate_breadcrumbs_from_menu, \
generate_title_from_path, Menu, generate_directory, generate_label
from .util import (
generate_breadcrumbs_from_path,
generate_breadcrumbs_from_menu,
generate_title_from_path,
Menu,
generate_directory,
generate_label,
)
# noinspection PyTypeChecker
@@ -27,11 +33,11 @@ from .util import generate_breadcrumbs_from_path, generate_breadcrumbs_from_menu
@login_required
def comic_list(request, directory_selector=False):
try:
base_dir = Setting.objects.get(name='BASE_DIR').value
base_dir = Setting.objects.get(name="BASE_DIR").value
except Setting.DoesNotExist:
return redirect('/comic/settings/')
return redirect("/comic/settings/")
if not path.isdir(base_dir):
return redirect('/comic/settings/')
return redirect("/comic/settings/")
if directory_selector:
selector = uuid.UUID(bytes=urlsafe_base64_decode(directory_selector))
@@ -42,18 +48,17 @@ def comic_list(request, directory_selector=False):
if directory:
title = generate_title_from_path(directory.path)
breadcrumbs = generate_breadcrumbs_from_path(directory)
json_url = '/comic/list_json/{0}/'.format(directory_selector)
json_url = "/comic/list_json/{0}/".format(directory_selector)
else:
title = generate_title_from_path('Home')
title = generate_title_from_path("Home")
breadcrumbs = generate_breadcrumbs_from_path()
json_url = '/comic/list_json/'
json_url = "/comic/list_json/"
return render(request, 'comic/comic_list.html', {
'breadcrumbs': breadcrumbs,
'menu': Menu(request.user, 'Browse'),
'title': title,
'json_url': json_url
})
return render(
request,
"comic/comic_list.html",
{"breadcrumbs": breadcrumbs, "menu": Menu(request.user, "Browse"), "title": title, "json_url": json_url},
)
@login_required
@@ -67,100 +72,99 @@ def comic_list_json(request, directory_selector=False):
directory = False
files = generate_directory(request.user, directory)
response_data = dict()
response_data['data'] = []
response_data["data"] = []
for file in files:
response_data['data'].append({
'blank': '',
'selector': file.selector,
'type': file.type,
'icon': icon_str.format(file.icon),
'name': file.name,
'label': file.label,
'url': file.location,
})
return HttpResponse(
json.dumps(response_data),
content_type="application/json"
response_data["data"].append(
{
"blank": "",
"selector": file.selector,
"type": file.type,
"icon": icon_str.format(file.icon),
"name": file.name,
"label": file.label,
"url": file.location,
}
)
return HttpResponse(json.dumps(response_data), content_type="application/json")
@login_required
def recent_comics(request):
feed_id, _ = UserMisc.objects.get_or_create(user=request.user)
return render(request,
'comic/recent_comics.html',
return render(
request,
"comic/recent_comics.html",
{
'breadcrumbs': generate_breadcrumbs_from_menu([('Recent', '/comic/recent/')]),
'menu': Menu(request.user, 'Recent'),
'title': 'Recent Comics',
'feed_id': urlsafe_base64_encode(feed_id.feed_id.bytes),
})
@login_required
@require_POST
def recent_comics_json(request):
start = int(request.POST['start'])
end = start + int(request.POST['length'])
icon = '<span class="glyphicon glyphicon-book"></span>'
comics = ComicBook.objects.all()
response_data = dict()
response_data['recordsTotal'] = comics.count()
if request.POST['search[value]']:
comics = comics.filter(file_name__contains=request.POST['search[value]'])
order_string = ''
# Ordering
if request.POST['order[0][dir]'] == 'desc':
order_string += '-'
if request.POST['order[0][dir]'] == '3':
order_string += 'date_added'
elif request.POST['order[0][dir]'] == '2':
order_string += 'date_added'
else:
order_string += 'date_added'
comics = comics.order_by(order_string)
response_data['recordsFiltered'] = comics.count()
response_data['data'] = list()
for book in comics[start:end]:
status, created = ComicStatus.objects.get_or_create(comic=book,
user=request.user)
if created:
status.save()
response_data['data'].append({
'selector': urlsafe_base64_encode(book.selector.bytes),
'icon': icon,
'type': 'book',
'name': book.file_name,
'date': book.date_added.strftime('%d/%m/%y-%H:%M'),
'label': generate_label(book, status),
'url': '/comic/read/{0}/{1}/'.format(urlsafe_base64_encode(book.selector.bytes),
status.last_read_page)
})
return HttpResponse(
json.dumps(response_data),
content_type="application/json"
"breadcrumbs": generate_breadcrumbs_from_menu([("Recent", "/comic/recent/")]),
"menu": Menu(request.user, "Recent"),
"title": "Recent Comics",
"feed_id": urlsafe_base64_encode(feed_id.feed_id.bytes),
},
)
@login_required
@require_POST
def recent_comics_json(request):
start = int(request.POST["start"])
end = start + int(request.POST["length"])
icon = '<span class="glyphicon glyphicon-book"></span>'
comics = ComicBook.objects.all()
response_data = dict()
response_data["recordsTotal"] = comics.count()
if request.POST["search[value]"]:
comics = comics.filter(file_name__contains=request.POST["search[value]"])
order_string = ""
# Ordering
if request.POST["order[0][dir]"] == "desc":
order_string += "-"
if request.POST["order[0][dir]"] == "3":
order_string += "date_added"
elif request.POST["order[0][dir]"] == "2":
order_string += "date_added"
else:
order_string += "date_added"
comics = comics.order_by(order_string)
response_data["recordsFiltered"] = comics.count()
response_data["data"] = list()
for book in comics[start:end]:
status, created = ComicStatus.objects.get_or_create(comic=book, user=request.user)
if created:
status.save()
response_data["data"].append(
{
"selector": urlsafe_base64_encode(book.selector.bytes),
"icon": icon,
"type": "book",
"name": book.file_name,
"date": book.date_added.strftime("%d/%m/%y-%H:%M"),
"label": generate_label(book, status),
"url": "/comic/read/{0}/{1}/".format(
urlsafe_base64_encode(book.selector.bytes), status.last_read_page
),
}
)
return HttpResponse(json.dumps(response_data), content_type="application/json")
@login_required
@require_POST
def comic_edit(request):
if 'selected' not in request.POST:
if "selected" not in request.POST:
return HttpResponse(status=200)
if request.POST['func'] == 'choose':
if request.POST["func"] == "choose":
return HttpResponse(status=200)
selected = [uuid.UUID(bytes=urlsafe_base64_decode(item)) for item in request.POST.getlist('selected')]
selected = [uuid.UUID(bytes=urlsafe_base64_decode(item)) for item in request.POST.getlist("selected")]
comics = ComicBook.objects.filter(selector__in=selected)
with atomic():
for comic in comics:
status, _ = ComicStatus.objects.get_or_create(comic=comic,
user=request.user)
if request.POST['func'] == 'read':
status, _ = ComicStatus.objects.get_or_create(comic=comic, user=request.user)
if request.POST["func"] == "read":
status.unread = False
status.finished = True
status.last_read_page = comic.page_count - 1
elif request.POST['func'] == 'unread':
elif request.POST["func"] == "unread":
status.unread = True
status.finished = False
status.last_read_page = 0
@@ -174,44 +178,37 @@ def account_page(request):
if request.POST:
form = AccountForm(request.POST)
if form.is_valid():
if form.cleaned_data['email'] != request.user.email:
request.user.email = form.cleaned_data['email']
success_message.append('Email Updated.')
if len(form.cleaned_data['password']) != 0:
request.user.set_password(form.cleaned_data['password'])
success_message.append('Password Updated.')
if form.cleaned_data["email"] != request.user.email:
request.user.email = form.cleaned_data["email"]
success_message.append("Email Updated.")
if len(form.cleaned_data["password"]) != 0:
request.user.set_password(form.cleaned_data["password"])
success_message.append("Password Updated.")
request.user.save()
else:
form = AccountForm(initial={
'username': request.user.username,
'email': request.user.email,
})
crumbs = [
('Account', '/comic/account/'),
]
form = AccountForm(initial={"username": request.user.username, "email": request.user.email})
crumbs = [("Account", "/comic/account/")]
context = {
'form': form,
'menu': Menu(request.user, 'Account'),
'error_message': form.errors,
'success_message': '</br>'.join(success_message),
'breadcrumbs': generate_breadcrumbs_from_menu(crumbs),
'title': 'CBWebReader - Account',
"form": form,
"menu": Menu(request.user, "Account"),
"error_message": form.errors,
"success_message": "</br>".join(success_message),
"breadcrumbs": generate_breadcrumbs_from_menu(crumbs),
"title": "CBWebReader - Account",
}
return render(request, 'comic/settings_page.html', context)
return render(request, "comic/settings_page.html", context)
@user_passes_test(lambda u: u.is_superuser)
def users_page(request):
users = User.objects.all()
crumbs = [
('Users', '/comic/settings/users/'),
]
crumbs = [("Users", "/comic/settings/users/")]
context = {
'users': users,
'menu': Menu(request.user, 'Users'),
'breadcrumbs': generate_breadcrumbs_from_menu(crumbs),
"users": users,
"menu": Menu(request.user, "Users"),
"breadcrumbs": generate_breadcrumbs_from_menu(crumbs),
}
return render(request, 'comic/users_page.html', context)
return render(request, "comic/users_page.html", context)
@user_passes_test(lambda u: u.is_superuser)
@@ -221,89 +218,78 @@ def user_config_page(request, user_id):
if request.POST:
form = EditUserForm(request.POST)
if form.is_valid():
if 'password' in form.cleaned_data:
if len(form.cleaned_data['password']) != 0:
user.set_password(form.cleaned_data['password'])
success_message.append('Password Updated.')
if form.cleaned_data['email'] != user.email:
user.email = form.cleaned_data['email']
success_message.append('Email Updated.</br>')
if "password" in form.cleaned_data:
if len(form.cleaned_data["password"]) != 0:
user.set_password(form.cleaned_data["password"])
success_message.append("Password Updated.")
if form.cleaned_data["email"] != user.email:
user.email = form.cleaned_data["email"]
success_message.append("Email Updated.</br>")
user.save()
else:
form = EditUserForm(initial=EditUserForm.get_initial_values(user))
users = User.objects.all()
crumbs = [
('Users', '/comic/settings/users/'),
(user.username, '/comic/settings/users/' + str(user.id)),
]
crumbs = [("Users", "/comic/settings/users/"), (user.username, "/comic/settings/users/" + str(user.id))]
context = {
'form': form,
'users': users,
'menu': Menu(request.user, 'Users'),
'error_message': form.errors,
'breadcrumbs': generate_breadcrumbs_from_menu(crumbs),
'success_message': '</br>'.join(success_message),
'title': 'CBWebReader - Edit User - ' + user.username,
"form": form,
"users": users,
"menu": Menu(request.user, "Users"),
"error_message": form.errors,
"breadcrumbs": generate_breadcrumbs_from_menu(crumbs),
"success_message": "</br>".join(success_message),
"title": "CBWebReader - Edit User - " + user.username,
}
return render(request, 'comic/settings_page.html', context)
return render(request, "comic/settings_page.html", context)
@user_passes_test(lambda u: u.is_superuser)
def user_add_page(request):
success_message = ''
success_message = ""
if request.POST:
form = AddUserForm(request.POST)
if form.is_valid():
user = User(
username=form.cleaned_data['username'],
email=form.cleaned_data['email'],
)
user.set_password(form.cleaned_data['password'])
user = User(username=form.cleaned_data["username"], email=form.cleaned_data["email"])
user.set_password(form.cleaned_data["password"])
user.save()
UserMisc.objects.create(user=user)
success_message = 'User {} created.'.format(user.username)
success_message = "User {} created.".format(user.username)
else:
form = AddUserForm()
crumbs = [
('Users', '/comic/settings/users/'),
('Add', '/comic/settings/users/add/'),
]
crumbs = [("Users", "/comic/settings/users/"), ("Add", "/comic/settings/users/add/")]
context = {
'form': form,
'menu': Menu(request.user, 'Users'),
'breadcrumbs': generate_breadcrumbs_from_menu(crumbs),
'error_message': form.errors,
'success_message': success_message,
'title': 'CBWebReader - Add User',
"form": form,
"menu": Menu(request.user, "Users"),
"breadcrumbs": generate_breadcrumbs_from_menu(crumbs),
"error_message": form.errors,
"success_message": success_message,
"title": "CBWebReader - Add User",
}
return render(request, 'comic/settings_page.html', context)
return render(request, "comic/settings_page.html", context)
@user_passes_test(lambda u: u.is_superuser)
def settings_page(request):
success_message = []
crumbs = [
('Settings', '/comic/settings/'),
]
crumbs = [("Settings", "/comic/settings/")]
if request.POST:
form = SettingsForm(request.POST)
if form.is_valid():
base_dir = Setting.objects.get(name='BASE_DIR')
base_dir.value = form.cleaned_data['base_dir']
base_dir = Setting.objects.get(name="BASE_DIR")
base_dir.value = form.cleaned_data["base_dir"]
base_dir.save()
success_message.append('Settings updated.')
success_message.append("Settings updated.")
form = SettingsForm(initial=SettingsForm.get_initial_values())
context = {
'error_message': form.errors,
'success_message': '</br>'.join(success_message),
'form': form,
'menu': Menu(request.user, 'Settings'),
'title': 'CBWebReader - Settings',
'breadcrumbs': generate_breadcrumbs_from_menu(crumbs),
"error_message": form.errors,
"success_message": "</br>".join(success_message),
"form": form,
"menu": Menu(request.user, "Settings"),
"title": "CBWebReader - Settings",
"breadcrumbs": generate_breadcrumbs_from_menu(crumbs),
}
return render(request, 'comic/settings_page.html', context)
return render(request, "comic/settings_page.html", context)
@login_required
@@ -317,21 +303,21 @@ def read_comic(request, comic_selector, page):
status, _ = ComicStatus.objects.get_or_create(comic=book, user=request.user)
status.unread = False
status.last_read_page = page
if ComicPage.objects.filter(Comic=book).aggregate(Max('index'))['index__max'] == status.last_read_page:
if ComicPage.objects.filter(Comic=book).aggregate(Max("index"))["index__max"] == status.last_read_page:
status.finished = True
else:
status.finished = False
status.save()
title = 'CBWebReader - ' + book.file_name + ' - Page: ' + str(page)
title = "CBWebReader - " + book.file_name + " - Page: " + str(page)
context = {
'book': book,
'orig_file_name': book.page_name(page),
'nav': book.nav(page, request.user),
'breadcrumbs': breadcrumbs,
'menu': Menu(request.user),
'title': title,
"book": book,
"orig_file_name": book.page_name(page),
"nav": book.nav(page, request.user),
"breadcrumbs": breadcrumbs,
"menu": Menu(request.user),
"title": title,
}
return render(request, 'comic/read_comic.html', context)
return render(request, "comic/read_comic.html", context)
@login_required
@@ -344,34 +330,29 @@ def get_image(_, comic_selector, page):
def initial_setup(request):
if User.objects.all().exists():
return redirect('/comic/')
return redirect("/comic/")
if request.POST:
form = InitialSetupForm(request.POST)
if form.is_valid():
user = User(
username=form.cleaned_data['username'],
email=form.cleaned_data['email'],
username=form.cleaned_data["username"],
email=form.cleaned_data["email"],
is_staff=True,
is_superuser=True,
)
user.set_password(form.cleaned_data['password'])
user.set_password(form.cleaned_data["password"])
user.save()
base_dir, _ = Setting.objects.get_or_create(name='BASE_DIR')
base_dir.value = form.cleaned_data['base_dir']
base_dir, _ = Setting.objects.get_or_create(name="BASE_DIR")
base_dir.value = form.cleaned_data["base_dir"]
base_dir.save()
user = authenticate(username=form.cleaned_data['username'],
password=form.cleaned_data['password'])
user = authenticate(username=form.cleaned_data["username"], password=form.cleaned_data["password"])
login(request, user)
return redirect('/comic/')
return redirect("/comic/")
else:
form = InitialSetupForm()
context = {
'form': form,
'title': 'CBWebReader - Setup',
'error_message': form.errors,
}
return render(request, 'comic/settings_page.html', context)
context = {"form": form, "title": "CBWebReader - Setup", "error_message": form.errors}
return render(request, "comic/settings_page.html", context)
def comic_redirect(_):
return redirect('/comic/')
return redirect("/comic/")

View File

@@ -6,26 +6,19 @@ from snowpenguin.django.recaptcha2.widgets import ReCaptchaWidget
class LoginForm(forms.Form):
username = forms.CharField(max_length=50,
label='',
username = forms.CharField(
max_length=50,
label="",
widget=forms.TextInput(
attrs={
'class': 'form-control',
'placeholder': 'Username',
'autofocus': True,
'required': True,
}
))
password = forms.CharField(label='Password',
widget=forms.PasswordInput(
attrs={
'class': 'form-control',
'placeholder': 'Username',
'required': True,
}
))
attrs={"class": "form-control", "placeholder": "Username", "autofocus": True, "required": True}
),
)
password = forms.CharField(
label="Password",
widget=forms.PasswordInput(attrs={"class": "form-control", "placeholder": "Username", "required": True}),
)
def __init__(self, *args, **kwargs):
super(LoginForm, self).__init__(*args, **kwargs)
if settings.CBREADER_USE_RECAPTCHA if hasattr(settings, 'CBREADER_USE_RECAPTCHA') else False:
self.fields['captcha'] = ReCaptchaField(widget=ReCaptchaWidget())
if settings.CBREADER_USE_RECAPTCHA if hasattr(settings, "CBREADER_USE_RECAPTCHA") else False:
self.fields["captcha"] = ReCaptchaField(widget=ReCaptchaWidget())

View File

@@ -9,45 +9,28 @@ def comic_login(request):
if request.POST:
form = LoginForm(request.POST)
if form.is_valid():
user = authenticate(username=form.cleaned_data['username'],
password=form.cleaned_data['password'])
user = authenticate(username=form.cleaned_data["username"], password=form.cleaned_data["password"])
if user is not None:
if user.is_active:
login(request, user)
if 'next' in request.GET:
return redirect(request.GET['next'])
if "next" in request.GET:
return redirect(request.GET["next"])
else:
return redirect('/comic/')
return redirect("/comic/")
else:
return render(request,
'comic_auth/login.html',
{
'error': True,
})
return render(request, "comic_auth/login.html", {"error": True})
else:
return render(request,
'comic_auth/login.html',
{
'error': True,
'form': form
})
return render(request, "comic_auth/login.html", {"error": True, "form": form})
else:
return render(request,
'comic_auth/login.html',
{
'error': True,
'form': form
})
return render(request, "comic_auth/login.html", {"error": True, "form": form})
else:
if not User.objects.all().exists():
return redirect('/setup/')
return redirect("/setup/")
form = LoginForm()
context = {
'form': form
}
return render(request, 'comic_auth/login.html', context)
context = {"form": form}
return render(request, "comic_auth/login.html", context)
def comic_logout(request):
logout(request)
return redirect('/login/')
return redirect("/login/")

View File

@@ -14,11 +14,11 @@ services:
- database
ports:
- "8000:8000"
volumes:
- ./cbreader:/src/cbreader
- ./comic:/src/comic
- ./comic_auth:/src/comic_auth
- ${COMIC_BOOK_VOLUME}:/data
# volumes:
# - ./cbreader:/src/cbreader
# - ./comic:/src/comic
# - ./comic_auth:/src/comic_auth
# - ${COMIC_BOOK_VOLUME}:/data
command: python manage.py runserver 0.0.0.0:8000
database:

2
pyproject.toml Normal file
View File

@@ -0,0 +1,2 @@
[tool.black]
line_length = 119

View File

@@ -1,12 +1,13 @@
from distutils.core import setup
setup(
name='cbwebreader',
version='',
packages=['comic', 'comic.migrations', 'cbreader', 'comic_auth', 'comic_auth.migrations'],
url='https://github.com/ajurna/cbwebreader',
license='http://creativecommons.org/licenses/by-sa/4.0/',
author='Ajurna',
author_email='ajurna@gmail.com',
description='Comic Book Web Reader', requires=['django-recaptcha', 'django', 'ujson']
name="cbwebreader",
version="",
packages=["comic", "comic.migrations", "cbreader", "comic_auth", "comic_auth.migrations"],
url="https://github.com/ajurna/cbwebreader",
license="http://creativecommons.org/licenses/by-sa/4.0/",
author="Ajurna",
author_email="ajurna@gmail.com",
description="Comic Book Web Reader",
requires=["django-recaptcha", "django", "ujson"],
)