mirror of
https://github.com/ajurna/cbwebreader.git
synced 2025-12-06 06:17:17 +00:00
Merge pull request #5 from apoclyps/black-formatting
[ISSUE-4] Applying black formatting
This commit is contained in:
@@ -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"
|
||||
|
||||
@@ -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"
|
||||
118
cbreader/tests/test_settings.py
Normal file
118
cbreader/tests/test_settings.py
Normal 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"
|
||||
@@ -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'))
|
||||
]
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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))
|
||||
|
||||
207
comic/forms.py
207
comic/forms.py
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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()),
|
||||
],
|
||||
),
|
||||
)
|
||||
]
|
||||
|
||||
@@ -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))
|
||||
]
|
||||
|
||||
@@ -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)),
|
||||
],
|
||||
),
|
||||
]
|
||||
|
||||
@@ -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
|
||||
)
|
||||
]
|
||||
|
||||
@@ -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),
|
||||
),
|
||||
]
|
||||
|
||||
@@ -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)),
|
||||
]
|
||||
|
||||
@@ -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))
|
||||
]
|
||||
|
||||
@@ -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'),
|
||||
),
|
||||
]
|
||||
|
||||
@@ -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)]
|
||||
|
||||
@@ -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)
|
||||
),
|
||||
]
|
||||
|
||||
@@ -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))]
|
||||
|
||||
@@ -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),
|
||||
),
|
||||
]
|
||||
|
||||
@@ -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))
|
||||
]
|
||||
|
||||
@@ -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)]
|
||||
|
||||
@@ -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))
|
||||
]
|
||||
|
||||
@@ -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))
|
||||
]
|
||||
|
||||
@@ -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),
|
||||
),
|
||||
],
|
||||
)
|
||||
]
|
||||
|
||||
@@ -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)]
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
|
||||
436
comic/rarfile.py
436
comic/rarfile.py
File diff suppressed because it is too large
Load Diff
@@ -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)
|
||||
|
||||
|
||||
@@ -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"),
|
||||
]
|
||||
|
||||
@@ -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:
|
||||
|
||||
355
comic/views.py
355
comic/views.py
@@ -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/")
|
||||
|
||||
@@ -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())
|
||||
|
||||
@@ -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/")
|
||||
|
||||
@@ -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
2
pyproject.toml
Normal file
@@ -0,0 +1,2 @@
|
||||
[tool.black]
|
||||
line_length = 119
|
||||
17
setup.py
17
setup.py
@@ -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"],
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user