From 3a5b7046f78122c77861a2cfce46fa3b5e248f8f Mon Sep 17 00:00:00 2001 From: Radek Czajka Date: Mon, 17 Jun 2024 13:43:10 +0200 Subject: [PATCH] Allow config without localsettings. Basic docker conf. Remove stale files. --- Dockerfile | 15 +++++ docker-compose.yml | 10 ++++ manage | 12 ++++ requirements.txt | 4 ++ src/cas/localsettings.sample | 6 -- src/cas/logging.cfg | 34 ----------- src/cas/settings.py | 110 ++++++++++++++++++++++++----------- src/services/views.py | 5 +- 8 files changed, 121 insertions(+), 75 deletions(-) create mode 100644 Dockerfile create mode 100644 docker-compose.yml create mode 100755 manage delete mode 100644 src/cas/localsettings.sample delete mode 100644 src/cas/logging.cfg diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..2b7586c --- /dev/null +++ b/Dockerfile @@ -0,0 +1,15 @@ +FROM python:3.10-alpine AS base + +COPY requirements.txt requirements.txt +RUN pip install --no-cache-dir -r requirements.txt + +WORKDIR /app + + +FROM base AS prod + +COPY src src + +RUN pip install --no-cache-dir gunicorn psycopg2-binary + +RUN src/manage.py collectstatic --no-input diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..b1d9818 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,10 @@ +version: '3' + +services: + dev: + build: + context: . + target: base + volumes: + - ./src:/app/src + - ./media:/app/media diff --git a/manage b/manage new file mode 100755 index 0000000..62e0c46 --- /dev/null +++ b/manage @@ -0,0 +1,12 @@ +#!/bin/sh + +if [ "$1" = "runserver" ] +then + PORT="$2" + [ -z "$PORT" ] && PORT=8000 + EXPOSED=127.0.0.1:"$PORT" + echo "expose as: $EXPOSED" + exec docker-compose run -p "$EXPOSED":"$PORT" dev python src/manage.py runserver 0.0.0.0:"$PORT" +else + exec docker-compose run dev python src/manage.py "$@" +fi diff --git a/requirements.txt b/requirements.txt index 52ea8e6..56f0c6a 100644 --- a/requirements.txt +++ b/requirements.txt @@ -4,3 +4,7 @@ Django==4.1.13 django-gravatar2==1.4.4 django-oidc-provider2==0.9.1 django-cas-provider==24.6 + +bcrypt==4.1.3 + +ipython diff --git a/src/cas/localsettings.sample b/src/cas/localsettings.sample deleted file mode 100644 index b5eab8f..0000000 --- a/src/cas/localsettings.sample +++ /dev/null @@ -1,6 +0,0 @@ -# Copy this to localsettings.py and set any settings you need to change. - -DEBUG = True -SECRET_KEY = '' -ALLOWED_HOSTS = [] - diff --git a/src/cas/logging.cfg b/src/cas/logging.cfg deleted file mode 100644 index ce758bc..0000000 --- a/src/cas/logging.cfg +++ /dev/null @@ -1,34 +0,0 @@ -[loggers] -keys=root,fnp - -[handlers] -keys=console,lf - -[formatters] -keys=default - -[logger_root] -level=DEBUG -handlers=console - -[logger_fnp] -level=DEBUG -handlers=lf,console -qualname=fnp -propagate=0 - -[formatter_default] -format=%(asctime)s %(name)s/%(levelname)s :: %(module)s:%(lineno)d :: %(message)s -datefmt= - -[handler_console] -class=StreamHandler -level=DEBUG -formatter=default -args=(sys.stderr, ) - -[handler_lf] -class=FileHandler -level=DEBUG -formatter=default -args=("/var/services/logs/cas.log",) \ No newline at end of file diff --git a/src/cas/settings.py b/src/cas/settings.py index c54bc14..36e8ba3 100644 --- a/src/cas/settings.py +++ b/src/cas/settings.py @@ -1,37 +1,65 @@ -from os import path +import os -PROJECT_ROOT = path.realpath(path.dirname(__file__)) - -DEBUG = True +PROJECT_ROOT = os.path.realpath(os.path.dirname(__file__)) ADMINS = [ + tuple(adm.split(':')) + for adm in + os.environ.get('ADMINS', '').split('\n') + if adm ] -MANAGERS = ADMINS +MANAGERS = [ + tuple(adm.split(':')) + for adm in + os.environ.get('MANAGERS', os.environ.get('ADMINS', '')).split('\n') + if adm +] -DATABASES = { - 'default': { - 'ENGINE': 'django.db.backends.sqlite3', # Add 'postgresql_psycopg2', 'postgresql', 'mysql', 'sqlite3' or 'oracle'. - 'NAME': path.join(PROJECT_ROOT, 'dev.sqlite'), # Or path to database file if using sqlite3. - 'USER': '', # Not used with sqlite3. - 'PASSWORD': '', # Not used with sqlite3. - 'HOST': '', # Set to empty string for localhost. Not used with sqlite3. - 'PORT': '', # Set to empty string for default. Not used with sqlite3. +DEBUG = False + +if 'DB_NAME' in os.environ: + DATABASES = { + 'default': { + 'ENGINE': 'django.db.backends.postgresql_psycopg2', + 'NAME': os.environ['DB_NAME'], + 'USER': os.environ.get('DB_USER', ''), + 'PASSWORD': os.environ.get('DB_PASSWORD', ''), + 'HOST': os.environ.get('DB_HOST', ''), + 'PORT': os.environ.get('DB_PORT', ''), + } + } +else: + DEBUG = True + + DATABASES = { + 'default': { + 'ENGINE': 'django.db.backends.sqlite3', + 'NAME': '/app/src/cas/dev.sqlite', + } } -} -DEFAULT_AUTO_FIELD = 'django.db.models.AutoField' + +DEBUG = os.environ.get('DEBUG', str(DEBUG)).lower() == 'True' + + +DEFAULT_FROM_EMAIL = os.environ.get('DEFAULT_FROM_EMAIL', '') +EMAIL_SUBJECT_PREFIX = os.environ.get('EMAIL_SUBJECT_PREFIX', '') +SECRET_KEY = os.environ.get('SECRET_KEY', '') +ALLOWED_HOSTS = os.environ.get('ALLOWED_HOSTS', '').split() +EMAILS_BASE_DOMAINS = os.environ.get('EMAILS_BASE_DOMAINS', '').split() +SECURE_PROXY_SSL_HEADER = os.environ.get('SECURE_PROXY_SSL_HEADER', '').split() # Local time zone for this installation. Choices can be found here: # http://en.wikipedia.org/wiki/List_of_tz_zones_by_name # although not all choices may be available on all operating systems. # If running in a Windows environment this must be set to the same as your # system time zone. -TIME_ZONE = 'Europe/Warsaw' +TIME_ZONE = os.environ.get('TIME_ZONE', 'Europe/Warsaw') # Language code for this installation. All choices can be found here: # http://www.i18nguy.com/unicode/language-identifiers.html -LANGUAGE_CODE = 'pl' +LANGUAGE_CODE = os.environ.get('LANGUAGE_CODE', 'pl') SITE_ID = 1 @@ -43,18 +71,38 @@ USE_TZ = True # Absolute path to the directory that holds media. # Example: "/home/media/media.lawrence.com/" -MEDIA_ROOT = path.join(PROJECT_ROOT, '../../media/') +MEDIA_ROOT = '/app/media/' # URL that handles the media served from MEDIA_ROOT. Make sure to use a # trailing slash if there is a path component (optional in other cases). # Examples: "http://media.lawrence.com", "http://example.com/media/" MEDIA_URL = '/media/' -STATIC_ROOT = path.join(PROJECT_ROOT, '../../static/') +STATIC_ROOT = '/app/static/' STATIC_URL = '/static/' + + +SESSION_COOKIE_NAME = 'fnpcas' + +GRAVATAR_DEFAULT_IMAGE = 'mm' +GRAVATAR_URL_PREFIX = 'https://www.gravatar.com/' + +SITE_TITLE = 'Fundacja Wolne Lektury' + + +# Import localsettings file, which may override settings defined here +try: + from .localsettings import * +except ImportError: + pass + + + +DEFAULT_AUTO_FIELD = 'django.db.models.AutoField' + STATICFILES_DIRS = [ - path.join(PROJECT_ROOT, 'static'), + os.path.join(PROJECT_ROOT, 'static'), ] ROOT_URLCONF = 'cas.urls' @@ -117,23 +165,19 @@ MIDDLEWARE = ( ) # django-cas-provider settings -LOGIN_URL = '/cas/login/' -LOGOUT_URL = '/cas/logout/' +LOGIN_URL = '/cas/login' +LOGOUT_URL = '/cas/logout' LOGIN_REDIRECT_URL = '/accounts/' CAS_CUSTOM_ATTRIBUTES_CALLBACK = 'cas.utils.custom_attributes_callback' -SESSION_COOKIE_NAME = 'fnpcas' - -GRAVATAR_DEFAULT_IMAGE = 'mm' -GRAVATAR_URL_PREFIX = 'https://www.gravatar.com/' - -SITE_TITLE = 'Fundacja Wolne Lektury' OIDC_USERINFO = 'emails.oidc.userinfo' +PASSWORD_HASHERS = ( + 'cas.hashers.FNPBCryptPasswordHasher', +) -# Import localsettings file, which may override settings defined here -try: - from .localsettings import * -except ImportError: - pass +if DEBUG: + EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend' + ALLOWED_HOSTS = ALLOWED_HOSTS or ['*'] + SECRET_KEY = SECRET_KEY or 'dev-secret-key' diff --git a/src/services/views.py b/src/services/views.py index f96dd0b..c2c4a06 100644 --- a/src/services/views.py +++ b/src/services/views.py @@ -1,3 +1,4 @@ +from django.contrib.auth.mixins import LoginRequiredMixin from django.views.generic import DetailView, ListView from .models import Service @@ -14,11 +15,11 @@ class SshAuthorizedKeysView(DetailView): return obj -class ServicesView(ListView): +class ServicesView(LoginRequiredMixin, ListView): def get_queryset(self): return Service.for_user(self.request.user) -class ServiceDetail(DetailView): +class ServiceDetail(LoginRequiredMixin, DetailView): def get_queryset(self): return Service.for_user(self.request.user) -- 2.20.1