From 68d453edc8e24cb14ccf19faaf87a778daea266e Mon Sep 17 00:00:00 2001 From: th3r00t Date: Fri, 11 Sep 2020 16:50:17 -0400 Subject: [PATCH] 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. --- configure | 8 +- docker/Dockerfile | 17 +--- docker/config.json | 15 ++- requirements.txt | 3 +- src/backend/lib/config.py | 18 ++-- src/frontend/asgi.py | 16 ++++ src/frontend/settings.py | 50 +++++----- src/frontend/urls.py | 3 +- src/interface/migrations/0001_initial.py | 111 ----------------------- src/interface/migrations/__init__.py | 0 10 files changed, 80 insertions(+), 161 deletions(-) create mode 100644 src/frontend/asgi.py delete mode 100644 src/interface/migrations/0001_initial.py delete mode 100644 src/interface/migrations/__init__.py diff --git a/configure b/configure index e0ab28c..7a61e2d 100755 --- a/configure +++ b/configure @@ -29,10 +29,10 @@ def set_secret(config=load_config()): def init_django_database(): cmds = [ - 'python manage.py makemigrations', - 'python manage.py makemigrations interface', - 'python manage.py migrate', - 'python manage.py migrate interface', + 'python3 manage.py makemigrations', + 'python3 manage.py makemigrations interface', + 'python3 manage.py migrate', + 'python3 manage.py migrate interface', ] os.chdir("src") for cmd in cmds: diff --git a/docker/Dockerfile b/docker/Dockerfile index daad156..d838917 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -12,25 +12,16 @@ FROM ubuntu EXPOSE 8000 +EXPOSE 1337 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 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/ +RUN DEBIAN_FRONTEND=noninteractive apt-get install -y build-essential python3 python3-dev python3-pip python3-venv COPY . /pyshelf COPY ./docker/config.json /pyshelf/config.json WORKDIR /pyshelf/ RUN python3 -m pip install -r requirements.txt +RUN python3 configure -WORKDIR /pyshelf/ -ENTRYPOINT cron start \ - && python3 configure \ - # && python3 importBooks \ - && nginx -g "daemon on;" \ - && uwsgi --ini uwsgi.ini +ENTRYPOINT daphne --root-path=/pyshelf/src/interface frontend.asgi:application diff --git a/docker/config.json b/docker/config.json index a2a9a84..62687f8 100644 --- a/docker/config.json +++ b/docker/config.json @@ -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" +} diff --git a/requirements.txt b/requirements.txt index 987a1bb..7b2383b 100755 --- a/requirements.txt +++ b/requirements.txt @@ -23,4 +23,5 @@ jsonpickle django-widget-tweaks loguru ptvsd -pudb \ No newline at end of file +pudb +daphne diff --git a/src/backend/lib/config.py b/src/backend/lib/config.py index 1292bc7..43722d4 100755 --- a/src/backend/lib/config.py +++ b/src/backend/lib/config.py @@ -9,8 +9,6 @@ class Config: """ Main System Configuration """ - - def __init__(self, root): """ Initialize main configuration options @@ -19,8 +17,10 @@ class Config: self._fp = "config.json" self._cp = pathlib.Path.joinpath(root, self._fp) self._data = self.open_file() - try: self.logger - except AttributeError: self.logger = self.get_logger() + try: + self.logger + except AttributeError: + self.logger = self.get_logger() self.book_path = self._data["BOOKPATH"] self.TITLE = self._data["TITLE"] self.VERSION = self._data["VERSION"] @@ -37,12 +37,14 @@ class Config: self.db_user = self._data["USER"] self.db_pass = self._data["PASSWORD"] 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): _logger = logger - _logger.add(pathlib.PurePath(self.root, 'data','pyshelf.log'), - rotation="2 MB", enqueue=True, colorize=True) + _logger.add(pathlib.PurePath(self.root, 'data', 'pyshelf.log'), + rotation="2 MB", + enqueue=True, + colorize=True) return _logger def open_file(self): diff --git a/src/frontend/asgi.py b/src/frontend/asgi.py new file mode 100644 index 0000000..91953a5 --- /dev/null +++ b/src/frontend/asgi.py @@ -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() diff --git a/src/frontend/settings.py b/src/frontend/settings.py index 7e2bce7..ea79189 100755 --- a/src/frontend/settings.py +++ b/src/frontend/settings.py @@ -21,38 +21,36 @@ CUR_DIR = Path.cwd() PRG_DIR = CUR_DIR.parts[0:-1] PRG_DIR = Path(*PRG_DIR) - CONFIG = Config(PRG_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__))) - # Quick-start development settings - unsuitable for production # See https://docs.djangoproject.com/en/2.2/howto/deployment/checklist/ # SECURITY WARNING: keep the secret key used in production secret! SECRET_KEY = CONFIG.SECRET # 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: print("DEBUG build mode is ON") from pudb.remote import set_trace +else: + print("Production Mode Set") ALLOWED_HOSTS = CONFIG.allowed_hosts - # Application definition INSTALLED_APPS = [ - "django.contrib.admin", - "django.contrib.auth", - "django.contrib.contenttypes", - "django.contrib.sessions", - "django.contrib.messages", - "django.contrib.staticfiles", - "interface", - "interface.templatetags", - "debug_toolbar", - "widget_tweaks" + "django.contrib.admin", "django.contrib.auth", + "django.contrib.contenttypes", "django.contrib.sessions", + "django.contrib.messages", "django.contrib.staticfiles", "interface", + "interface.templatetags", "debug_toolbar", "widget_tweaks" ] AUTH_USER_MODEL = "interface.User" MIDDLEWARE = [ @@ -90,9 +88,9 @@ TEMPLATES = [ }, ] -WSGI_APPLICATION = "frontend.wsgi.application" - +# WSGI_APPLICATION = "frontend.wsgi.application" +WSGI_APPLICATION = 'asgi.wsgi.application' # Database # https://docs.djangoproject.com/en/2.2/ref/settings/#databases DATABASES = { @@ -115,14 +113,23 @@ DATABASES = { 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 # https://docs.djangoproject.com/en/2.2/topics/i18n/ @@ -136,7 +143,6 @@ USE_L10N = True USE_TZ = True - # Static files (CSS, JavaScript, Images) # https://docs.djangoproject.com/en/2.2/howto/static-files/ LOGIN_REDIRECT_URL = 'home' diff --git a/src/frontend/urls.py b/src/frontend/urls.py index 532dc8e..e7e8024 100755 --- a/src/frontend/urls.py +++ b/src/frontend/urls.py @@ -19,6 +19,7 @@ from django.contrib.auth import views as auth_views from django.contrib.auth.models import User from django.shortcuts import HttpResponse from django.urls import include, path, re_path +from django.conf.urls.static import static from interface import views urlpatterns = [ @@ -67,7 +68,7 @@ urlpatterns = [ auth_views.PasswordResetCompleteView.as_view(), name='password_reset_complete', ), -] +] + static(settings.STATIC_URL, document_root=settings.STATIC_ROOT) if settings.DEBUG: import debug_toolbar diff --git a/src/interface/migrations/0001_initial.py b/src/interface/migrations/0001_initial.py deleted file mode 100644 index 61d40c8..0000000 --- a/src/interface/migrations/0001_initial.py +++ /dev/null @@ -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', - }, - ), - ] diff --git a/src/interface/migrations/__init__.py b/src/interface/migrations/__init__.py deleted file mode 100644 index e69de29..0000000