Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 0 additions & 12 deletions .coveragerc

This file was deleted.

32 changes: 32 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
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/
.venv
.vscode/*
.python-version

node_modules/

*.mo

.env

*.swp
13 changes: 13 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
DJANGO_SETTINGS_MODULE=settings.prod
ALLOWED_HOSTS=.fachschaft.informatik.tu-darmstadt.de,.d120.de
CSRF_TRUSTED_ORIGINS=
SECRET_KEY=
KEYCLOAK_CLIENT_ID=
KEYCLOAK_SECRET=
KEYCLOAK_SERVER_URL=
EMAIL_HOST=
EMAIL_PORT=
EMAIL_USE_TLS=True
EMAIL_HOST_USER=
EMAIL_HOST_PASSWORD=
GUNICORN_WORKERS=
2 changes: 1 addition & 1 deletion .github/workflows/django.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ jobs:
run: |
python -m pip install --upgrade pip
pip install coveralls
pip install -r requirements.txt
pip install -e ".[dev]"
echo "PASSWORD_HASHERS = ['django.contrib.auth.hashers.MD5PasswordHasher',]" >> src/settings.py

- name: Static tests
Expand Down
13 changes: 13 additions & 0 deletions .github/workflows/docker-build.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
name: Docker Build

on: [push, pull_request]

jobs:
docker-build:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v4

- name: Build Docker image
run: docker build -t pyfeedback:test .
7 changes: 7 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,14 @@ pyenv
settings_secret.py
static/*
venv/
.venv/
.vscode/*
.python-version

node_modules/

*.mo

.env

*.swp
76 changes: 76 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
# ==========================================
# Build Node.js Dependencies
# ==========================================

FROM node:22-slim AS node-builder

WORKDIR /app

COPY package*.json ./
RUN npm ci --only=production

# ==========================================
# Build Python Dependencies
# ==========================================

FROM python:3.13-slim AS python-builder

ENV PYTHONDONTWRITEBYTECODE=1 \
PYTHONUNBUFFERED=1

WORKDIR /app

COPY pyproject.toml ./

COPY src ./src

RUN pip install --root-user-action ignore --upgrade pip && \
pip install --root-user-action ignore --no-cache-dir .

# ==========================================
# Final Production Image
# ==========================================

FROM python:3.13-slim AS production

ARG DEBIAN_FRONTEND=noninteractive

ENV PYTHONDONTWRITEBYTECODE=1 \
PYTHONUNBUFFERED=1

RUN apt-get update && \
apt-get install -y --no-install-recommends \
gettext \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/*

# non-root user

RUN useradd -m -r appuser

WORKDIR /app

COPY --from=python-builder /usr/local/lib/python3.13/site-packages/ /usr/local/lib/python3.13/site-packages/
COPY --from=python-builder /usr/local/bin/ /usr/local/bin/

COPY --from=node-builder /app/node_modules /app/node_modules

COPY --chown=appuser:appuser . .

COPY --chown=appuser:appuser entrypoint.sh /usr/local/bin/entrypoint.sh
RUN chmod +x /usr/local/bin/entrypoint.sh

RUN mkdir -p /app/static && \
chown appuser:appuser /app/static

# Build static assets & translations as non-root user

USER appuser

RUN django-admin compilemessages && \
python src/manage.py collectstatic --no-input --clear

EXPOSE 8000
WORKDIR /app/src

ENTRYPOINT ["/usr/local/bin/entrypoint.sh"]
26 changes: 22 additions & 4 deletions Readme.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
# Feedback-Software
![Build Status](https://github.com/d120/pyfeedback/workflows/Test/badge.svg?branch=master)
[![Test](https://github.com/d120/pyfeedback/actions/workflows/django.yml/badge.svg?branch=master)](https://github.com/d120/pyfeedback/actions/workflows/django.yml)
[![Docker Build](https://github.com/d120/pyfeedback/actions/workflows/docker-build.yml/badge.svg?branch=master)](https://github.com/d120/pyfeedback/actions/workflows/docker-build.yml)
[![Coverage Status](https://coveralls.io/repos/github/d120/pyfeedback/badge.svg?branch=master)](https://coveralls.io/github/d120/pyfeedback?branch=master)


Expand All @@ -16,17 +17,34 @@ To use pyfeedback the following tools have to be installed:

## Preparing development environment

* Create a virtualenv with `python -m venv venv`
* Activate the virtualenv with `source venv/bin/activate`
* Install all requirements with `pip install -r requirements.txt`
* Create a virtualenv with `python -m venv .venv`
* Activate the virtualenv with `source .venv/bin/activate`
* Install all requirements with `pip install -e ".[dev]"`
* Create the test database with `python src/manage.py migrate`
* Compile translations with `(cd src && django-admin compilemessages)`
* Install frontend dependencies with `npm i`
* Start the development server with `python src/manage.py runserver`

## Production
- Use `pip install .` to install dependencies.
- Docker: make sure to set `DJANGO_SETTINGS_MODULE=settings.prod` in .env
- Without docker: `gunicorn wsgi:application`

## Tests
pyfeedback is using a test driven development and tries to get to 100% coverage. Tests can be run with
```
python src/manage.py test feedback
```
Do not implement new functionality without providing a test for it.

## Settings

`src/manage.py` uses settings.dev, `src/wsgi.py` uses settings.prod

Use `python src/manage.py runserver --settings=settings.prod` to run production settings during development.


## Docker

- DJANGO_SETTINGS_MODULE: `settings.prod` or `settings.dev`. `settings.prod` runs with wsgi.py and gunicorn, `settings.dev` with manage.py
- GUNICORN_WORKERS: *default* 3 workers
13 changes: 13 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
services:
pyfeedback:
build: .
container_name: pyfeedback-docker
ports:
- "8000:8000"
env_file:
- .env
volumes:
- pyfeedback-db:/app/db/

volumes:
pyfeedback-db:
30 changes: 30 additions & 0 deletions entrypoint.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
#!/bin/sh

# Exit on error
set -e

echo "Applying database migrations..."
python manage.py migrate --no-input

if [ $# -eq 0 ]; then

if [ "$DJANGO_SETTINGS_MODULE" = "settings.dev" ]; then
echo "Starting Django development server..."
exec python manage.py runserver 0.0.0.0:8000

elif [ "$DJANGO_SETTINGS_MODULE" = "settings.prod" ]; then
echo "Starting Gunicorn with ${GUNICORN_WORKERS:-3} workers..."
exec gunicorn \
--bind 0.0.0.0:8000 \
--workers "${GUNICORN_WORKERS:-3}" \
wsgi:application

else
echo "Unknown DJANGO_SETTINGS_MODULE: $DJANGO_SETTINGS_MODULE"
exit 1
fi

else
echo "Running custom command: $@"
exec "$@"
fi
50 changes: 50 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
[build-system]
requires = ["setuptools>=61.0"]
build-backend = "setuptools.build_meta"

[project]
name = "pyfeedback"
version = "3.0.0"
description = "Web application to assist feedback for modules at TU Darmstadt"
readme = "README.md"
requires-python = ">=3.13"
authors = [
{ name = "d120" }
]
dependencies = [
"Django==6.0.7",
"django-formtools==2.7",
"django-allauth[socialaccount]==65.18.0",
"gunicorn==26.0.0",
"whitenoise[brotli]==6.12.0",
]

[project.optional-dependencies]
dev = [
"django-debug-toolbar==7.0.0",
"coverage==7.15.1",
"freezegun==1.5.5",
"python-dotenv>=1.0.0",
]

[tool.setuptools.packages.find]
where = ["src"]

[tool.coverage.run]
source = ["src"]
omit = [
"*/migrations/*",
"*/tests/*",
"*/tests.py",
"*/tests_*.py",
"src/manage.py",
"src/wsgi.py",
"src/asgi.py",
"*/locale/*",
"*/settings/*",
]

[tool.coverage.report]
precision = 2
show_missing = true
fail_under = 85
6 changes: 0 additions & 6 deletions requirements.txt

This file was deleted.

26 changes: 0 additions & 26 deletions script/bootstrap

This file was deleted.

Loading
Loading