finalising the project configuration

This commit is contained in:
Faraphel 2024-01-16 21:32:07 +01:00
parent 9c4cb77d35
commit 96905d9f78
10 changed files with 235 additions and 53 deletions

View file

@ -3,6 +3,9 @@ FROM python:3.12
# Set environment variables for Django # Set environment variables for Django
ENV DJANGO_SETTINGS_MODULE=Palto.settings ENV DJANGO_SETTINGS_MODULE=Palto.settings
ENV DJANGO_SECRET_KEY=""
ENV DATABASE_ENGINE="sqlite"
ENV DEBUG=false
# Set the working directory in the container # Set the working directory in the container
WORKDIR /App WORKDIR /App
@ -10,8 +13,12 @@ WORKDIR /App
# Copy the current directory contents into the container # Copy the current directory contents into the container
COPY . /App COPY . /App
# Install any needed packages specified in requirements.txt # Install requirements
RUN pip install -r requirements.txt RUN python -m pip install -r requirements.txt
# Prepare the server
RUN python manage.py collectstatic --no-input
RUN python manage.py migrate
# Expose the port on which your Django application will run # Expose the port on which your Django application will run
EXPOSE 80 EXPOSE 80

View file

@ -0,0 +1,167 @@
# Generated by Django 5.0.1 on 2024-01-15 17:37
import Palto.Palto.models
import django.contrib.auth.models
import django.contrib.auth.validators
import django.db.models.deletion
import django.utils.timezone
import uuid
from django.conf import settings
from django.db import migrations, models
class Migration(migrations.Migration):
initial = True
dependencies = [
('auth', '0012_alter_user_first_name_max_length'),
]
operations = [
migrations.CreateModel(
name='Absence',
fields=[
('id', models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False)),
('message', models.TextField()),
('start', models.DateTimeField()),
('end', models.DateTimeField()),
],
bases=(models.Model, Palto.Palto.models.ModelPermissionHelper),
),
migrations.CreateModel(
name='Department',
fields=[
('id', models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False)),
('name', models.CharField(max_length=64, unique=True)),
('email', models.EmailField(max_length=254)),
],
bases=(models.Model, Palto.Palto.models.ModelPermissionHelper),
),
migrations.CreateModel(
name='AbsenceAttachment',
fields=[
('id', models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False)),
('content', models.FileField(upload_to='absence/attachment/')),
('absence', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='attachments', to='Palto.absence')),
],
bases=(models.Model, Palto.Palto.models.ModelPermissionHelper),
),
migrations.AddField(
model_name='absence',
name='department',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='absences', to='Palto.department'),
),
migrations.CreateModel(
name='StudentGroup',
fields=[
('id', models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False)),
('name', models.CharField(max_length=128)),
('department', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='student_groups', to='Palto.department')),
],
bases=(models.Model, Palto.Palto.models.ModelPermissionHelper),
),
migrations.CreateModel(
name='User',
fields=[
('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=150, 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')),
('id', models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False)),
('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,
},
bases=(models.Model, Palto.Palto.models.ModelPermissionHelper),
managers=[
('objects', django.contrib.auth.models.UserManager()),
],
),
migrations.CreateModel(
name='TeachingUnit',
fields=[
('id', models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False)),
('name', models.CharField(max_length=64)),
('email', models.EmailField(blank=True, max_length=254, null=True)),
('department', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='teaching_units', to='Palto.department')),
('student_groups', models.ManyToManyField(blank=True, related_name='studying_units', to='Palto.studentgroup')),
('managers', models.ManyToManyField(blank=True, related_name='managing_units', to=settings.AUTH_USER_MODEL)),
('teachers', models.ManyToManyField(blank=True, related_name='teaching_units', to=settings.AUTH_USER_MODEL)),
],
bases=(models.Model, Palto.Palto.models.ModelPermissionHelper),
),
migrations.CreateModel(
name='TeachingSession',
fields=[
('id', models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False)),
('start', models.DateTimeField()),
('duration', models.DurationField()),
('note', models.TextField(blank=True)),
('group', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='teaching_sessions', to='Palto.studentgroup')),
('unit', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='sessions', to='Palto.teachingunit')),
('teacher', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='teaching_sessions', to=settings.AUTH_USER_MODEL)),
],
bases=(models.Model, Palto.Palto.models.ModelPermissionHelper),
),
migrations.AddField(
model_name='studentgroup',
name='owner',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='owning_groups', to=settings.AUTH_USER_MODEL),
),
migrations.AddField(
model_name='studentgroup',
name='students',
field=models.ManyToManyField(blank=True, related_name='student_groups', to=settings.AUTH_USER_MODEL),
),
migrations.CreateModel(
name='StudentCard',
fields=[
('id', models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False)),
('uid', models.BinaryField(max_length=7)),
('department', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='student_cards', to='Palto.department')),
('owner', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='student_cards', to=settings.AUTH_USER_MODEL)),
],
bases=(models.Model, Palto.Palto.models.ModelPermissionHelper),
),
migrations.AddField(
model_name='department',
name='managers',
field=models.ManyToManyField(blank=True, related_name='managing_departments', to=settings.AUTH_USER_MODEL),
),
migrations.AddField(
model_name='department',
name='students',
field=models.ManyToManyField(blank=True, related_name='studying_departments', to=settings.AUTH_USER_MODEL),
),
migrations.AddField(
model_name='department',
name='teachers',
field=models.ManyToManyField(blank=True, related_name='teaching_departments', to=settings.AUTH_USER_MODEL),
),
migrations.CreateModel(
name='Attendance',
fields=[
('id', models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False)),
('date', models.DateTimeField()),
('session', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='attendances', to='Palto.teachingsession')),
('student', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='attended_sessions', to=settings.AUTH_USER_MODEL)),
],
bases=(models.Model, Palto.Palto.models.ModelPermissionHelper),
),
migrations.AddField(
model_name='absence',
name='student',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='absences', to=settings.AUTH_USER_MODEL),
),
]

View file

@ -218,7 +218,7 @@ def new_absence_view(request: WSGIRequest):
content=file content=file
) )
return redirect("Palto:homepage") # TODO(Faraphel): redirect to absence list return redirect("Palto:absence_list")
# render the page # render the page
return render( return render(

View file

@ -10,9 +10,12 @@ For the full list of settings and their values, see
https://docs.djangoproject.com/en/4.2/ref/settings/ https://docs.djangoproject.com/en/4.2/ref/settings/
""" """
import os import os
import warnings
from datetime import timedelta from datetime import timedelta
from pathlib import Path from pathlib import Path
from django.core.management.utils import get_random_secret_key
# Build paths inside the project like this: BASE_DIR / 'subdir'. # Build paths inside the project like this: BASE_DIR / 'subdir'.
BASE_DIR = Path(__file__).resolve().parent.parent BASE_DIR = Path(__file__).resolve().parent.parent
@ -21,22 +24,16 @@ BASE_DIR = Path(__file__).resolve().parent.parent
# See https://docs.djangoproject.com/en/4.2/howto/deployment/checklist/ # See https://docs.djangoproject.com/en/4.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 = os.environ["DJANGO_SECRET"] SECRET_KEY = os.getenv("DJANGO_SECRET_KEY")
if not SECRET_KEY:
SECRET_KEY = get_random_secret_key()
warnings.warn('The Django secret key should be defined in the "DJANGO_SECRET_KEY" variable environment.')
# SECURITY WARNING: don't run with debug turned on in production! # SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True DEBUG = os.getenv("DEBUG", "false").lower() in ["1", "true"]
ALLOWED_HOSTS = [ ALLOWED_HOSTS = os.getenv("", "localhost 0.0.0.0").split(" ")
"127.0.0.1", INTERNAL_IPS = ["localhost"]
"localhost",
"0.0.0.0",
]
INTERNAL_IPS = [
"127.0.0.1",
"localhost",
"0.0.0.0",
]
# Application definition # Application definition
@ -94,12 +91,30 @@ WSGI_APPLICATION = 'Palto.wsgi.application'
# https://docs.djangoproject.com/en/4.2/ref/settings/#databases # https://docs.djangoproject.com/en/4.2/ref/settings/#databases
DATABASES = { DATABASES = {
'default': { "sqlite": {
'ENGINE': 'django.db.backends.sqlite3', 'ENGINE': 'django.db.backends.sqlite3',
'NAME': BASE_DIR / 'db.sqlite3', 'NAME': BASE_DIR / os.getenv("DATABASE_SQLITE_FILENAME", "db.sqlite3"),
} },
"mysql": {
'ENGINE': 'django.db.backends.mysql',
"NAME": os.getenv("MYSQL_POSTGRES_NAME"),
"USER": os.getenv("MYSQL_POSTGRES_USER"),
"PASSWORD": os.getenv("MYSQL_POSTGRES_PASSWORD"),
"HOST": os.getenv("MYSQL_POSTGRES_HOST", "localhost"),
"PORT": os.getenv("MYSQL_POSTGRES_PORT", "5432"),
},
"postgres": {
"ENGINE": "django.db.backends.postgresql",
"NAME": os.getenv("DATABASE_POSTGRES_NAME"),
"USER": os.getenv("DATABASE_POSTGRES_USER"),
"PASSWORD": os.getenv("DATABASE_POSTGRES_PASSWORD"),
"HOST": os.getenv("DATABASE_POSTGRES_HOST", "localhost"),
"PORT": os.getenv("DATABASE_POSTGRES_PORT", "5432"),
},
} }
DATABASES["default"] = DATABASES[os.getenv("DATABASE_ENGINE", "sqlite")]
# Password validation # Password validation
# https://docs.djangoproject.com/en/4.2/ref/settings/#auth-password-validators # https://docs.djangoproject.com/en/4.2/ref/settings/#auth-password-validators

View file

@ -8,11 +8,7 @@ https://docs.djangoproject.com/en/4.2/howto/deployment/wsgi/
""" """
import dotenv
from django.core.wsgi import get_wsgi_application from django.core.wsgi import get_wsgi_application
from utils import env
dotenv.load_dotenv(env.create_dotenv())
application = get_wsgi_application() application = get_wsgi_application()

View file

@ -9,6 +9,8 @@ this session.
# Installation # Installation
## Classic
1. Install `python >= 3.11` 1. Install `python >= 3.11`
2. Create a virtual environment with `python -m venv ./.venv/`. The next steps will be inside it. 2. Create a virtual environment with `python -m venv ./.venv/`. The next steps will be inside it.
3. Install the dependencies with `python -m pip install -r ./requirements.txt`. 3. Install the dependencies with `python -m pip install -r ./requirements.txt`.
@ -16,3 +18,28 @@ this session.
5. Make the migrations with `python ./manage.py makemigrations`. 5. Make the migrations with `python ./manage.py makemigrations`.
6. Apply the migrations to the database with `python ./manage.py migrate`. 6. Apply the migrations to the database with `python ./manage.py migrate`.
7. Run the program by with `python ./manage.py runserver`. 7. Run the program by with `python ./manage.py runserver`.
## Docker
1. Start a terminal in the directory of the project.
2. Run `docker build`.
3. Change the environment variables to match your configuration.
# Advanced Settings
## Debug Mode
By default, the server is launch in production mode.
This disables the automatic static files serving since they are considered as being already served by nginx or apache.
You can start with the environment variable `DEBUG=true` to start it in development mode.
## Secret Key
You should set a django secret key manually in the `DJANGO_SECRET_KEY` environment variable. You can get one by
opening a python interpreter with django and calling the function `django.core.management.utils.get_random_secret_key()`.
## Database
The database used by default is `sqlite`. This is not recommended to keep it since it won't be saved by docker after
a restart if no volume are set, and it is considered a slow database engine. Using a `postgres` database is recommended.
You can find more details about the database in the configuration `settings.py`.

View file

@ -3,15 +3,9 @@
import sys import sys
import dotenv
from utils import env
def main(): def main():
"""Run administrative tasks.""" """Run administrative tasks."""
dotenv.load_dotenv(env.create_dotenv())
try: try:
from django.core.management import execute_from_command_line from django.core.management import execute_from_command_line
except ImportError as exc: except ImportError as exc:

View file

@ -13,4 +13,3 @@ factory_boy
# Other librairies # Other librairies
markdown markdown
python-dotenv

View file

View file

@ -1,23 +0,0 @@
from pathlib import Path
from django.core.management.utils import get_random_secret_key
path_dotenv = Path("./.env")
def create_dotenv(force: bool = False) -> Path:
# if not forced and the file already exist, ignore
if not force and path_dotenv.exists():
return path_dotenv
# otherwise create the file
path_dotenv.write_text(
(
f"DJANGO_SETTINGS_MODULE='Palto.settings'\n"
f"DJANGO_SECRET={get_random_secret_key()!r}\n"
),
encoding="utf-8"
)
return path_dotenv