diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 00000000..573b7551 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,27 @@ +latex/anschreiben/veranstalter.adr +# Ignore all files in db folder +db/* +# But keep the folder +!db/.gitkeep + +*.pyc +htmlcov +pyenv +*.aux +*.log +.idea +*.pdf +*.adr +.project +.pydevproject +.settings/* +.coverage +settings_secret.py +static/* +venv/ +.vscode/* +.python-version + +node_modules/ + +*.mo \ No newline at end of file diff --git a/.env b/.env new file mode 100644 index 00000000..31fa3b69 --- /dev/null +++ b/.env @@ -0,0 +1,11 @@ +SETTINGS_FILE=settings +DEBUG=False +ALLOWED_HOSTS=.fachschaft.informatik.tu-darmstadt.de,.d120.de +SECRET_KEY= +KEYCLOAK_CLIENT_ID= +KEYCLOAK_SECRET= +KEYCLOAK_SERVER_URL= +EMAIL_HOST=mail.d120.de +EMAIL_PORT=587 +EMAIL_HOST_USER=pyfeedback +EMAIL_HOST_PASSWORD= \ No newline at end of file diff --git a/.gitignore b/.gitignore index 8e614510..573b7551 100644 --- a/.gitignore +++ b/.gitignore @@ -23,3 +23,5 @@ venv/ .python-version node_modules/ + +*.mo \ No newline at end of file diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 00000000..e9a86cd0 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,72 @@ +## Stage 1: build stage +FROM python:3.13-slim AS builder + +RUN mkdir /app + +WORKDIR /app + +ENV PYTHONDONTWRITEBYTECODE=1 +ENV PYTHONUNBUFFERED=1 + +# install packages and node +RUN pip install --upgrade pip + +RUN apt-get update && apt-get install -y \ + curl \ + gnupg \ + ca-certificates \ + && curl -fsSL https://deb.nodesource.com/setup_22.x | bash - \ + && apt-get install -y nodejs \ + && apt-get clean \ + && rm -rf /var/lib/apt/lists/* + +# install pip requirements +COPY requirements.txt /app/ + +RUN pip install --no-cache-dir -r requirements.txt + +# install node_modules +COPY package*.json ./ + +RUN npm i + +## Stage 2: production stage +FROM python:3.13-slim + +RUN useradd -m -r appuser && \ + mkdir /app && \ + chown -R appuser /app + +# Copy the python dependencies and node_modules from the builder stage +COPY --from=builder /usr/local/lib/python3.13/site-packages/ /usr/local/lib/python3.13/site-packages/ +COPY --from=builder /usr/local/bin/ /usr/local/bin/ +COPY --from=builder /app/node_modules/ /app/node_modules/ + +# install gettext for translations (compiling) +RUN apt-get update && apt-get install -y gettext \ + && apt-get clean \ + && rm -rf /var/lib/apt/lists/* + +WORKDIR /app + +# copy the code +COPY --chown=appuser:appuser . . + +ENV PYTHONDONTWRITEBYTECODE=1 +ENV PYTHONUNBUFFERED=1 + +WORKDIR /app/src + +# switch to non-root user +USER appuser + +# compile translations +RUN django-admin compilemessages + +# migrate db changes +RUN python manage.py migrate --no-input + +EXPOSE 8000 + +# start applicaiton with gunicorn +CMD ["gunicorn", "--bind", "0.0.0.0:8000", "--workers", "3", "wsgi:application"] \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 00000000..b85d87b1 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,25 @@ +services: + django-web: + build: . + container_name: pyfeedback-docker + ports: + - "8000:8000" + environment: + - SETTINGS_FILE=${SETTINGS_FILE} + - DEBUG=${DEBUG} + - ALLOWED_HOSTS=${ALLOWED_HOSTS} + - SECRET_KEY=${SECRET_KEY} + - KEYCLOAK_CLIENT_ID=${KEYCLOAK_CLIENT_ID} + - KEYCLOAK_SECRET=${KEYCLOAK_SECRET} + - KEYCLOAK_SERVER_URL=${KEYCLOAK_SERVER_URL} + - EMAIL_HOST=${EMAIL_HOST} + - EMAIL_PORT=${EMAIL_PORT} + - EMAIL_HOST_USER=${EMAIL_HOST_USER} + - EMAIL_HOST_PASSWORD=${EMAIL_HOST_PASSWORD} + env_file: + - .env + volumes: + - db_data:/app/db/ + +volumes: + db_data: \ No newline at end of file diff --git a/requirements.txt b/requirements.txt index 9f6e7fb5..957e52e4 100644 --- a/requirements.txt +++ b/requirements.txt @@ -4,4 +4,5 @@ django-debug-toolbar==5.1.0 docutils==0.21.2 freezegun==1.5.1 django-formtools==2.5.1 -django-allauth[socialaccount,keycloak]==65.7.0 \ No newline at end of file +django-allauth[socialaccount,keycloak]==65.7.0 +gunicorn==23.0.0 \ No newline at end of file diff --git a/src/django.wsgi b/src/django.wsgi deleted file mode 100644 index ac4b0cc0..00000000 --- a/src/django.wsgi +++ /dev/null @@ -1,8 +0,0 @@ -import os - -from django.core.wsgi import get_wsgi_application - - -os.environ.setdefault("DJANGO_SETTINGS_MODULE", "settings") - -application = get_wsgi_application() diff --git a/src/locale/de/LC_MESSAGES/django.mo b/src/locale/de/LC_MESSAGES/django.mo deleted file mode 100644 index 21fa752f..00000000 Binary files a/src/locale/de/LC_MESSAGES/django.mo and /dev/null differ diff --git a/src/locale/en/LC_MESSAGES/django.mo b/src/locale/en/LC_MESSAGES/django.mo deleted file mode 100644 index aff8f190..00000000 Binary files a/src/locale/en/LC_MESSAGES/django.mo and /dev/null differ diff --git a/src/settings_production.py b/src/settings_production.py index ba6f04ea..939eb06e 100644 --- a/src/settings_production.py +++ b/src/settings_production.py @@ -1,11 +1,11 @@ from settings import * -import settings_secret as secrets +import os -DEBUG = False +DEBUG = (os.getenv("DEBUG", "False") == "True") # os.getenv only returns a string -ALLOWED_HOSTS = ['.fachschaft.informatik.tu-darmstadt.de', '.d120.de'] +ALLOWED_HOSTS = os.getenv("ALLOWED_HOSTS").split(",") -SECRET_KEY = secrets.SECRET_KEY +SECRET_KEY = os.getenv("SECRET_KEY") URL_PREFIX = 'feedback/' @@ -20,10 +20,10 @@ { "provider_id": "keycloak", "name": "Keycloak", - "client_id": secrets.KEYCLOAK_CLIENT_ID, - "secret": secrets.KEYCLOAK_SECRET, + "client_id": os.getenv("KEYCLOAK_CLIENT_ID"), + "secret": os.getenv("KEYCLOAK_SECRET"), "settings": { - "server_url": secrets.KEYCLOAK_SERVER_URL, + "server_url": os.getenv("KEYCLOAK_SERVER_URL"), }, } ] @@ -33,11 +33,11 @@ # @see https://docs.djangoproject.com/es/1.9/topics/email/ EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend' -EMAIL_HOST = 'mail.d120.de' -EMAIL_PORT = 587 +EMAIL_HOST = os.getenv("EMAIL_HOST") +EMAIL_PORT = int(os.getenv("EMAIL_PORT")) EMAIL_USE_TLS = True -EMAIL_HOST_USER = 'pyfeedback' -EMAIL_HOST_PASSWORD = secrets.EMAIL_HOST_PASSWORD +EMAIL_HOST_USER = os.getenv("EMAIL_HOST_USER") +EMAIL_HOST_PASSWORD = os.getenv("EMAIL_HOST_PASSWORD") SESSION_COOKIE_PATH = '/feedback' SESSION_COOKIE_SECURE = True diff --git a/src/wsgi.py b/src/wsgi.py new file mode 100644 index 00000000..872c4101 --- /dev/null +++ b/src/wsgi.py @@ -0,0 +1,10 @@ +import os + +from django.core.wsgi import get_wsgi_application + +# select in .env which settings to use +settings_file = os.getenv("SETTINGS_FILE", "settings") + +os.environ.setdefault("DJANGO_SETTINGS_MODULE", settings_file) + +application = get_wsgi_application()