mirror of
https://github.com/th3r00t/pyShelf.git
synced 2026-04-28 01:59:35 -04:00
Phased out nginx in favor of running django under daphne with asgi.
Adjusted the docker image in favor of this, & fixed urls.py which was missing the static request responder.
This commit is contained in:
8
configure
vendored
8
configure
vendored
@@ -29,10 +29,10 @@ def set_secret(config=load_config()):
|
|||||||
|
|
||||||
def init_django_database():
|
def init_django_database():
|
||||||
cmds = [
|
cmds = [
|
||||||
'python manage.py makemigrations',
|
'python3 manage.py makemigrations',
|
||||||
'python manage.py makemigrations interface',
|
'python3 manage.py makemigrations interface',
|
||||||
'python manage.py migrate',
|
'python3 manage.py migrate',
|
||||||
'python manage.py migrate interface',
|
'python3 manage.py migrate interface',
|
||||||
]
|
]
|
||||||
os.chdir("src")
|
os.chdir("src")
|
||||||
for cmd in cmds:
|
for cmd in cmds:
|
||||||
|
|||||||
17
docker/Dockerfile
vendored
17
docker/Dockerfile
vendored
@@ -12,25 +12,16 @@
|
|||||||
FROM ubuntu
|
FROM ubuntu
|
||||||
|
|
||||||
EXPOSE 8000
|
EXPOSE 8000
|
||||||
|
EXPOSE 1337
|
||||||
|
|
||||||
RUN apt-get update -y
|
RUN apt-get update -y
|
||||||
RUN DEBIAN_FRONTEND=noninteractive apt-get install -y build-essential python3 python3-dev python3-pip python3-venv nginx-full
|
RUN DEBIAN_FRONTEND=noninteractive apt-get install -y build-essential python3 python3-dev python3-pip python3-venv
|
||||||
|
|
||||||
RUN DEBIAN_FRONTEND=noninteractive apt-get install -y cron
|
|
||||||
RUN echo "* * * * * cd /pyshelf/ && python3 importBooks >> /var/log/cron.log 2>&1" > import_books_scheduler.cron && crontab import_books_scheduler.cron
|
|
||||||
|
|
||||||
COPY ./docker/pyshelf_nginx.conf /etc/nginx/sites-available/pyshelf_nginx.conf
|
|
||||||
RUN ln -s /etc/nginx/sites-available/pyshelf_nginx.conf /etc/nginx/sites-enabled/
|
|
||||||
|
|
||||||
COPY . /pyshelf
|
COPY . /pyshelf
|
||||||
COPY ./docker/config.json /pyshelf/config.json
|
COPY ./docker/config.json /pyshelf/config.json
|
||||||
|
|
||||||
WORKDIR /pyshelf/
|
WORKDIR /pyshelf/
|
||||||
RUN python3 -m pip install -r requirements.txt
|
RUN python3 -m pip install -r requirements.txt
|
||||||
|
RUN python3 configure
|
||||||
|
|
||||||
WORKDIR /pyshelf/
|
ENTRYPOINT daphne --root-path=/pyshelf/src/interface frontend.asgi:application
|
||||||
ENTRYPOINT cron start \
|
|
||||||
&& python3 configure \
|
|
||||||
# && python3 importBooks \
|
|
||||||
&& nginx -g "daemon on;" \
|
|
||||||
&& uwsgi --ini uwsgi.ini
|
|
||||||
|
|||||||
15
docker/config.json
vendored
15
docker/config.json
vendored
@@ -1 +1,14 @@
|
|||||||
{"TITLE": "pyShelf E-Book Server", "VERSION": "Docker", "BOOKPATH": "/books", "DB_HOST": "db", "DB_PORT": "5432", "DATABASE": "pyshelf", "USER": "pyshelf", "PASSWORD": "pyshelf", "BOOKSHELF": "data/shelf.json", "ALLOWED_HOSTS": "*", "SECRET": ""}
|
{
|
||||||
|
"TITLE": "pyShelf E-Book Server",
|
||||||
|
"VERSION": "Docker",
|
||||||
|
"BOOKPATH": "/books",
|
||||||
|
"DB_HOST": "db",
|
||||||
|
"DB_PORT": "5432",
|
||||||
|
"DATABASE": "pyshelf",
|
||||||
|
"USER": "pyshelf",
|
||||||
|
"PASSWORD": "pyshelf",
|
||||||
|
"BOOKSHELF": "data/shelf.json",
|
||||||
|
"ALLOWED_HOSTS": "*",
|
||||||
|
"SECRET": "",
|
||||||
|
"BUILD_MODE": "production"
|
||||||
|
}
|
||||||
|
|||||||
@@ -23,4 +23,5 @@ jsonpickle
|
|||||||
django-widget-tweaks
|
django-widget-tweaks
|
||||||
loguru
|
loguru
|
||||||
ptvsd
|
ptvsd
|
||||||
pudb
|
pudb
|
||||||
|
daphne
|
||||||
|
|||||||
@@ -9,8 +9,6 @@ class Config:
|
|||||||
"""
|
"""
|
||||||
Main System Configuration
|
Main System Configuration
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
def __init__(self, root):
|
def __init__(self, root):
|
||||||
"""
|
"""
|
||||||
Initialize main configuration options
|
Initialize main configuration options
|
||||||
@@ -19,8 +17,10 @@ class Config:
|
|||||||
self._fp = "config.json"
|
self._fp = "config.json"
|
||||||
self._cp = pathlib.Path.joinpath(root, self._fp)
|
self._cp = pathlib.Path.joinpath(root, self._fp)
|
||||||
self._data = self.open_file()
|
self._data = self.open_file()
|
||||||
try: self.logger
|
try:
|
||||||
except AttributeError: self.logger = self.get_logger()
|
self.logger
|
||||||
|
except AttributeError:
|
||||||
|
self.logger = self.get_logger()
|
||||||
self.book_path = self._data["BOOKPATH"]
|
self.book_path = self._data["BOOKPATH"]
|
||||||
self.TITLE = self._data["TITLE"]
|
self.TITLE = self._data["TITLE"]
|
||||||
self.VERSION = self._data["VERSION"]
|
self.VERSION = self._data["VERSION"]
|
||||||
@@ -37,12 +37,14 @@ class Config:
|
|||||||
self.db_user = self._data["USER"]
|
self.db_user = self._data["USER"]
|
||||||
self.db_pass = self._data["PASSWORD"]
|
self.db_pass = self._data["PASSWORD"]
|
||||||
self.SECRET = self._data["SECRET"]
|
self.SECRET = self._data["SECRET"]
|
||||||
self.debug_build_mode = (self._data["BUILD_MODE"].casefold() == "debug")
|
self.build_mode = self._data["BUILD_MODE"]
|
||||||
|
|
||||||
def get_logger(self):
|
def get_logger(self):
|
||||||
_logger = logger
|
_logger = logger
|
||||||
_logger.add(pathlib.PurePath(self.root, 'data','pyshelf.log'),
|
_logger.add(pathlib.PurePath(self.root, 'data', 'pyshelf.log'),
|
||||||
rotation="2 MB", enqueue=True, colorize=True)
|
rotation="2 MB",
|
||||||
|
enqueue=True,
|
||||||
|
colorize=True)
|
||||||
return _logger
|
return _logger
|
||||||
|
|
||||||
def open_file(self):
|
def open_file(self):
|
||||||
|
|||||||
16
src/frontend/asgi.py
Normal file
16
src/frontend/asgi.py
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
"""
|
||||||
|
ASGI config for asgi project.
|
||||||
|
|
||||||
|
It exposes the ASGI callable as a module-level variable named ``application``.
|
||||||
|
|
||||||
|
For more information on this file, see
|
||||||
|
https://docs.djangoproject.com/en/3.1/howto/deployment/asgi/
|
||||||
|
"""
|
||||||
|
|
||||||
|
import os
|
||||||
|
|
||||||
|
from django.core.asgi import get_asgi_application
|
||||||
|
|
||||||
|
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'frontend.settings')
|
||||||
|
|
||||||
|
application = get_asgi_application()
|
||||||
@@ -21,38 +21,36 @@ CUR_DIR = Path.cwd()
|
|||||||
PRG_DIR = CUR_DIR.parts[0:-1]
|
PRG_DIR = CUR_DIR.parts[0:-1]
|
||||||
PRG_DIR = Path(*PRG_DIR)
|
PRG_DIR = Path(*PRG_DIR)
|
||||||
|
|
||||||
|
|
||||||
CONFIG = Config(PRG_DIR)
|
CONFIG = Config(PRG_DIR)
|
||||||
# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
|
# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
|
||||||
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
||||||
|
|
||||||
|
|
||||||
# Quick-start development settings - unsuitable for production
|
# Quick-start development settings - unsuitable for production
|
||||||
# See https://docs.djangoproject.com/en/2.2/howto/deployment/checklist/
|
# See https://docs.djangoproject.com/en/2.2/howto/deployment/checklist/
|
||||||
|
|
||||||
# SECURITY WARNING: keep the secret key used in production secret!
|
# SECURITY WARNING: keep the secret key used in production secret!
|
||||||
SECRET_KEY = CONFIG.SECRET
|
SECRET_KEY = CONFIG.SECRET
|
||||||
# SECURITY WARNING: don't run with debug turned on in production!
|
# SECURITY WARNING: don't run with debug turned on in production!
|
||||||
DEBUG = TEMPLATE_DEBUG = CONFIG.debug_build_mode
|
|
||||||
|
BUILD_MODE = CONFIG.build_mode
|
||||||
|
if BUILD_MODE == 'debug':
|
||||||
|
DEBUG = TEMPLATE_DEBUG = True
|
||||||
|
else:
|
||||||
|
DEBUG = TEMPLATE_DEBUG = False
|
||||||
if DEBUG is True:
|
if DEBUG is True:
|
||||||
print("DEBUG build mode is ON")
|
print("DEBUG build mode is ON")
|
||||||
from pudb.remote import set_trace
|
from pudb.remote import set_trace
|
||||||
|
else:
|
||||||
|
print("Production Mode Set")
|
||||||
ALLOWED_HOSTS = CONFIG.allowed_hosts
|
ALLOWED_HOSTS = CONFIG.allowed_hosts
|
||||||
|
|
||||||
|
|
||||||
# Application definition
|
# Application definition
|
||||||
|
|
||||||
INSTALLED_APPS = [
|
INSTALLED_APPS = [
|
||||||
"django.contrib.admin",
|
"django.contrib.admin", "django.contrib.auth",
|
||||||
"django.contrib.auth",
|
"django.contrib.contenttypes", "django.contrib.sessions",
|
||||||
"django.contrib.contenttypes",
|
"django.contrib.messages", "django.contrib.staticfiles", "interface",
|
||||||
"django.contrib.sessions",
|
"interface.templatetags", "debug_toolbar", "widget_tweaks"
|
||||||
"django.contrib.messages",
|
|
||||||
"django.contrib.staticfiles",
|
|
||||||
"interface",
|
|
||||||
"interface.templatetags",
|
|
||||||
"debug_toolbar",
|
|
||||||
"widget_tweaks"
|
|
||||||
]
|
]
|
||||||
AUTH_USER_MODEL = "interface.User"
|
AUTH_USER_MODEL = "interface.User"
|
||||||
MIDDLEWARE = [
|
MIDDLEWARE = [
|
||||||
@@ -90,9 +88,9 @@ TEMPLATES = [
|
|||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
|
||||||
WSGI_APPLICATION = "frontend.wsgi.application"
|
# WSGI_APPLICATION = "frontend.wsgi.application"
|
||||||
|
|
||||||
|
|
||||||
|
WSGI_APPLICATION = 'asgi.wsgi.application'
|
||||||
# Database
|
# Database
|
||||||
# https://docs.djangoproject.com/en/2.2/ref/settings/#databases
|
# https://docs.djangoproject.com/en/2.2/ref/settings/#databases
|
||||||
DATABASES = {
|
DATABASES = {
|
||||||
@@ -115,14 +113,23 @@ DATABASES = {
|
|||||||
|
|
||||||
AUTH_PASSWORD_VALIDATORS = [
|
AUTH_PASSWORD_VALIDATORS = [
|
||||||
{
|
{
|
||||||
"NAME": "django.contrib.auth.password_validation.UserAttributeSimilarityValidator",
|
"NAME":
|
||||||
|
"django.contrib.auth.password_validation.UserAttributeSimilarityValidator",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"NAME":
|
||||||
|
"django.contrib.auth.password_validation.MinimumLengthValidator",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"NAME":
|
||||||
|
"django.contrib.auth.password_validation.CommonPasswordValidator",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"NAME":
|
||||||
|
"django.contrib.auth.password_validation.NumericPasswordValidator",
|
||||||
},
|
},
|
||||||
{"NAME": "django.contrib.auth.password_validation.MinimumLengthValidator",},
|
|
||||||
{"NAME": "django.contrib.auth.password_validation.CommonPasswordValidator",},
|
|
||||||
{"NAME": "django.contrib.auth.password_validation.NumericPasswordValidator",},
|
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
# Internationalization
|
# Internationalization
|
||||||
# https://docs.djangoproject.com/en/2.2/topics/i18n/
|
# https://docs.djangoproject.com/en/2.2/topics/i18n/
|
||||||
|
|
||||||
@@ -136,7 +143,6 @@ USE_L10N = True
|
|||||||
|
|
||||||
USE_TZ = True
|
USE_TZ = True
|
||||||
|
|
||||||
|
|
||||||
# Static files (CSS, JavaScript, Images)
|
# Static files (CSS, JavaScript, Images)
|
||||||
# https://docs.djangoproject.com/en/2.2/howto/static-files/
|
# https://docs.djangoproject.com/en/2.2/howto/static-files/
|
||||||
LOGIN_REDIRECT_URL = 'home'
|
LOGIN_REDIRECT_URL = 'home'
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ from django.contrib.auth import views as auth_views
|
|||||||
from django.contrib.auth.models import User
|
from django.contrib.auth.models import User
|
||||||
from django.shortcuts import HttpResponse
|
from django.shortcuts import HttpResponse
|
||||||
from django.urls import include, path, re_path
|
from django.urls import include, path, re_path
|
||||||
|
from django.conf.urls.static import static
|
||||||
from interface import views
|
from interface import views
|
||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
@@ -67,7 +68,7 @@ urlpatterns = [
|
|||||||
auth_views.PasswordResetCompleteView.as_view(),
|
auth_views.PasswordResetCompleteView.as_view(),
|
||||||
name='password_reset_complete',
|
name='password_reset_complete',
|
||||||
),
|
),
|
||||||
]
|
] + static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)
|
||||||
if settings.DEBUG:
|
if settings.DEBUG:
|
||||||
import debug_toolbar
|
import debug_toolbar
|
||||||
|
|
||||||
|
|||||||
@@ -1,111 +0,0 @@
|
|||||||
# Generated by Django 3.0.7 on 2020-07-23 16:01
|
|
||||||
|
|
||||||
from django.conf import settings
|
|
||||||
import django.contrib.auth.models
|
|
||||||
import django.contrib.auth.validators
|
|
||||||
from django.db import migrations, models
|
|
||||||
import django.db.models.deletion
|
|
||||||
import django.utils.timezone
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
initial = True
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
('auth', '0011_update_proxy_permissions'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.CreateModel(
|
|
||||||
name='User',
|
|
||||||
fields=[
|
|
||||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
|
||||||
('password', models.CharField(max_length=128, verbose_name='password')),
|
|
||||||
('last_login', models.DateTimeField(blank=True, null=True, verbose_name='last login')),
|
|
||||||
('is_superuser', models.BooleanField(default=False, help_text='Designates that this user has all permissions without explicitly assigning them.', verbose_name='superuser status')),
|
|
||||||
('username', models.CharField(error_messages={'unique': 'A user with that username already exists.'}, help_text='Required. 150 characters or fewer. Letters, digits and @/./+/-/_ only.', max_length=150, unique=True, validators=[django.contrib.auth.validators.UnicodeUsernameValidator()], verbose_name='username')),
|
|
||||||
('first_name', models.CharField(blank=True, max_length=30, verbose_name='first name')),
|
|
||||||
('last_name', models.CharField(blank=True, max_length=150, verbose_name='last name')),
|
|
||||||
('email', models.EmailField(blank=True, max_length=254, verbose_name='email address')),
|
|
||||||
('is_staff', models.BooleanField(default=False, help_text='Designates whether the user can log into this admin site.', verbose_name='staff status')),
|
|
||||||
('is_active', models.BooleanField(default=True, help_text='Designates whether this user should be treated as active. Unselect this instead of deleting accounts.', verbose_name='active')),
|
|
||||||
('date_joined', models.DateTimeField(default=django.utils.timezone.now, verbose_name='date joined')),
|
|
||||||
('facebook', models.CharField(max_length=255, null=True)),
|
|
||||||
('twitter', models.CharField(max_length=255, null=True)),
|
|
||||||
('ulvl', models.IntegerField(default=1)),
|
|
||||||
('sponsorid', models.IntegerField(null=True)),
|
|
||||||
('matrixid', models.CharField(max_length=255, null=True)),
|
|
||||||
('groups', models.ManyToManyField(blank=True, help_text='The groups this user belongs to. A user will get all permissions granted to each of their groups.', related_name='user_set', related_query_name='user', to='auth.Group', verbose_name='groups')),
|
|
||||||
('user_permissions', models.ManyToManyField(blank=True, help_text='Specific permissions for this user.', related_name='user_set', related_query_name='user', to='auth.Permission', verbose_name='user permissions')),
|
|
||||||
],
|
|
||||||
options={
|
|
||||||
'verbose_name': 'user',
|
|
||||||
'verbose_name_plural': 'users',
|
|
||||||
'abstract': False,
|
|
||||||
},
|
|
||||||
managers=[
|
|
||||||
('objects', django.contrib.auth.models.UserManager()),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
migrations.CreateModel(
|
|
||||||
name='Books',
|
|
||||||
fields=[
|
|
||||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
|
||||||
('title', models.TextField()),
|
|
||||||
('author', models.CharField(max_length=255, null=True)),
|
|
||||||
('categories', models.TextField(null=True)),
|
|
||||||
('cover', models.BinaryField(editable=True, null=True)),
|
|
||||||
('pages', models.IntegerField(null=True)),
|
|
||||||
('progress', models.IntegerField(null=True)),
|
|
||||||
('file_name', models.TextField()),
|
|
||||||
('description', models.TextField(null=True)),
|
|
||||||
('identifier', models.CharField(max_length=255, null=True)),
|
|
||||||
('publisher', models.TextField(null=True)),
|
|
||||||
('date', models.DateField(null=True)),
|
|
||||||
('rights', models.CharField(max_length=255, null=True)),
|
|
||||||
('tags', models.TextField(null=True)),
|
|
||||||
],
|
|
||||||
options={
|
|
||||||
'db_table': 'books',
|
|
||||||
},
|
|
||||||
),
|
|
||||||
migrations.CreateModel(
|
|
||||||
name='Navigation',
|
|
||||||
fields=[
|
|
||||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
|
||||||
('title', models.CharField(max_length=255)),
|
|
||||||
('link', models.CharField(max_length=255, null=True)),
|
|
||||||
('category', models.CharField(max_length=255, null=True)),
|
|
||||||
('parent_id', models.IntegerField(null=True)),
|
|
||||||
('alt', models.CharField(max_length=255, null=True)),
|
|
||||||
('type', models.IntegerField(null=True)),
|
|
||||||
('socket', models.CharField(max_length=255)),
|
|
||||||
],
|
|
||||||
options={
|
|
||||||
'db_table': 'navigation',
|
|
||||||
},
|
|
||||||
),
|
|
||||||
migrations.CreateModel(
|
|
||||||
name='Favorites',
|
|
||||||
fields=[
|
|
||||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
|
||||||
('book', models.ForeignKey(default=None, on_delete=django.db.models.deletion.CASCADE, to='interface.Books')),
|
|
||||||
('user', models.ForeignKey(default=None, on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
|
|
||||||
],
|
|
||||||
options={
|
|
||||||
'db_table': 'favorites',
|
|
||||||
},
|
|
||||||
),
|
|
||||||
migrations.CreateModel(
|
|
||||||
name='Collections',
|
|
||||||
fields=[
|
|
||||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
|
||||||
('collection', models.CharField(max_length=255)),
|
|
||||||
('book_id', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='interface.Books')),
|
|
||||||
],
|
|
||||||
options={
|
|
||||||
'db_table': 'collections',
|
|
||||||
},
|
|
||||||
),
|
|
||||||
]
|
|
||||||
Reference in New Issue
Block a user