diff --git a/CHANGELOG.md b/CHANGELOG.md index 101228528ebce23436702c5fc329a4c39408b669..1f345d81c5f6312582d8972518e7a85b7276ee99 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,7 +14,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Changed -- ... +- The `program/rrule.json` fixture contains all the supported recurrence rules. ### Deprecated diff --git a/Makefile b/Makefile index 679ef847d9c02dd820db9ddf4b85d36fa09e27d4..0e82f89d46a67467dc22d624955dcbc251747080 100644 --- a/Makefile +++ b/Makefile @@ -4,8 +4,13 @@ POETRY_RUN_MANAGE = $(POETRY_RUN) ./manage.py .DEFAULT_GOAL := run.prod -TANK_CALLBACK_BASE_URL ?= "${AURA_PROTO}://${AURA_HOST}/tank" -DASHBOARD_CALLBACK_BASE_URL ?= "${AURA_PROTO}://${AURA_HOST}" +ifndef TANK_CALLBACK_BASE_URL +override TANK_CALLBACK_BASE_URL = "${AURA_PROTO}://${AURA_HOST}/tank" +endif + +ifndef DASHBOARD_CALLBACK_BASE_URL +override DASHBOARD_CALLBACK_BASE_URL = "${AURA_PROTO}://${AURA_HOST}" +endif initialize: migrate loadfixtures $(POETRY_RUN_MANAGE) collectstatic --clear --no-input @@ -27,11 +32,17 @@ loadfixtures: loaddata: $(POETRY_RUN_MANAGE) loaddata ${DATA} -run.dev: migrate +removestaleimages: + $(POETRY_RUN_MANAGE) removestaleimages + +run.dev: dev.install migrate $(POETRY_RUN_MANAGE) runserver 0.0.0.0:8000 +dev.install: + $(POETRY) install --no-root + run.prod: migrate - $(POETRY_RUN) gunicorn --bind 0.0.0.0:8000 --workers `(nproc)` steering.wsgi + $(POETRY_RUN) gunicorn --bind 0.0.0.0:8000 --workers `nproc` steering.wsgi run.debug: migrate DEBUG=1 $(POETRY_RUN_MANAGE) runserver_plus 0.0.0.0:8000 diff --git a/fixtures/auth/group.json b/fixtures/auth/group.json deleted file mode 100644 index 06dbacd7e25d17fe967c3abda8d2d0c46df9132a..0000000000000000000000000000000000000000 --- a/fixtures/auth/group.json +++ /dev/null @@ -1,10 +0,0 @@ -[ - { - "model": "auth.group", - "pk": 1, - "fields": { - "name": "ProgrammmacherInnen", - "permissions": [] - } - } -] diff --git a/fixtures/auth/group_permissions.json b/fixtures/auth/group_permissions.json deleted file mode 100644 index c2b8e7c683df387460ce633b4a523b45f1c27a56..0000000000000000000000000000000000000000 --- a/fixtures/auth/group_permissions.json +++ /dev/null @@ -1,50 +0,0 @@ -[ - { - "model": "auth.group_permissions", - "pk": 1, - "fields": { - "group": 1, - "permission": 35 - } - }, - { - "model": "auth.group_permissions", - "pk": 2, - "fields": { - "group": 1, - "permission": 28 - } - }, - { - "model": "auth.group_permissions", - "pk": 3, - "fields": { - "group": 1, - "permission": 29 - } - }, - { - "model": "auth.group_permissions", - "pk": 4, - "fields": { - "group": 1, - "permission": 30 - } - }, - { - "model": "auth.group_permissions", - "pk": 5, - "fields": { - "group": 1, - "permission": 8 - } - }, - { - "model": "auth.group_permissions", - "pk": 6, - "fields": { - "group": 1, - "permission": 23 - } - } -] diff --git a/fixtures/auth/user.json b/fixtures/auth/user.json deleted file mode 100644 index 59c9850cb3a9158320ee38a2d7b79256db34ce8b..0000000000000000000000000000000000000000 --- a/fixtures/auth/user.json +++ /dev/null @@ -1,38 +0,0 @@ -[ - { - "model": "auth.user", - "pk": 1, - "fields": { - "password": "pbkdf2_sha256$36000$uMBrNYea7vcc$6599RKSDzRkpoO8lcOjOQI/O1ufPXphIYh10VNqZcYU=", - "last_login": null, - "is_superuser": true, - "username": "admin", - "first_name": "", - "last_name": "", - "email": "", - "is_staff": true, - "is_active": true, - "date_joined": "2017-12-31T22:00:00Z", - "groups": [], - "user_permissions": [] - } - }, - { - "model": "auth.user", - "pk": 2, - "fields": { - "password": "pbkdf2_sha256$36000$VVSM5LeZfBZM$w0XSHCrucEb7Oj1Qpjdy1SKq5KelpXSPiUXbxh3rWpM=", - "last_login": null, - "is_superuser": false, - "username": "pm1", - "first_name": "", - "last_name": "", - "email": "", - "is_staff": true, - "is_active": true, - "date_joined": "2017-12-31T22:00:00Z", - "groups": [], - "user_permissions": [] - } - } -] diff --git a/fixtures/auth/user_groups.json b/fixtures/auth/user_groups.json deleted file mode 100644 index ca3a1e2715920725a31c694012f76d093ae48bea..0000000000000000000000000000000000000000 --- a/fixtures/auth/user_groups.json +++ /dev/null @@ -1,10 +0,0 @@ -[ - { - "model": "auth.user_groups", - "pk": 1, - "fields": { - "user": 2, - "group": 1 - } - } -] diff --git a/program/management/commands/removestaleimages.py b/program/management/commands/removestaleimages.py new file mode 100644 index 0000000000000000000000000000000000000000..8e1d5f6512fa544a395b7677d9ddcd9d6109859d --- /dev/null +++ b/program/management/commands/removestaleimages.py @@ -0,0 +1,49 @@ +import os + +from versatileimagefield.fields import VersatileImageField + +from django.apps import apps +from django.conf import settings +from django.core.management.base import BaseCommand +from django.db.models import ImageField, Q + + +class Command(BaseCommand): + help = "removes images from the MEDIA_ROOT that are not referenced in the database." + + def handle(self, *args, **options): + def remove_file(path: str) -> None: + print(f"REMOVED {path}") + os.remove(path) + + image_names = [] # names (without extensions) of the images in the database + + for model in apps.get_models(): + for field in model._meta.get_fields(): + if isinstance(field, VersatileImageField) or isinstance(field, ImageField): + is_empty = Q(**{f"{field.name}": ""}) + images = model.objects.exclude(is_empty).values_list(field.name, flat=True) + + for image in images: + basename = os.path.basename(image) + filename, ext = os.path.splitext(basename) + image_names.append(filename) + + media_root = getattr(settings, "MEDIA_ROOT") + + for relative_root, dirs, files in os.walk(media_root): + for file_ in files: + relative_path = os.path.join(os.path.relpath(relative_root, media_root), file_) + head, tail = os.path.split(relative_path) + filename, ext = os.path.splitext(tail) + + fullpath = os.path.join(media_root, relative_path) + + if not head.startswith("__sized__"): + if filename not in image_names: + remove_file(fullpath) + else: + # cropped images + name, _ = filename.split("-crop-") + if name not in image_names: + remove_file(fullpath) diff --git a/run.sh b/run.sh deleted file mode 100755 index d97be642c6af7b2fb67e87445d9587bbce312b1d..0000000000000000000000000000000000000000 --- a/run.sh +++ /dev/null @@ -1,117 +0,0 @@ -#!/bin/bash -# Default mode -mode="dev" -docker="false" - -# -# Run Script for AURA Steering -# -# Call with one of these parameters: -# -# - init -# - dev -# - prod -# - test - -# - docker:build -# - docker:push -# - docker:dev -# - -if [[ $* =~ ^(init|init-db|dev|prod|test|build|push|serve)$ ]]; then - mode=$1 -fi - -if [[ "$1" == *"docker:"* ]]; then - docker="true" - mode=${1#*:} -fi - - -echo "[ Run mode=$mode ]" -echo "[ Docker=$docker ]" - - - -# +++ DEFAULT COMMANDS +++ # - -if [[ $docker == "false" ]]; then - - if [[ $mode == "init-db" ]]; then - echo "apply database migrations" - poetry run ./manage.py migrate - echo "collect static resources" - poetry run ./manage.py collectstatic --clear --noinput - echo "create django superuser" - poetry run ./manage.py createsuperuser --noinput - echo "create rsa key" - poetry run ./manage.py creatersakey - if [[ -z ${TANK_CALLBACK_BASE_URL} ]]; then - TANK_CALLBACK_BASE_URL="${AURA_PROTO}://${AURA_HOST}/tank" - fi - if [[ -z ${DASHBOARD_CALLBACK_BASE_URL} ]]; then - DASHBOARD_CALLBACK_BASE_URL="${AURA_PROTO}://${AURA_HOST}" - fi - echo "create dashboard client with client id $DASHBOARD_OIDC_CLIENT_ID" - poetry run ./manage.py create_oidc_client dashboard public --client-id $DASHBOARD_OIDC_CLIENT_ID --client-secret $DASHBOARD_OIDC_CLIENT_SECRET -r "id_token token" -u ${DASHBOARD_CALLBACK_BASE_URL}/oidc_callback.html -u ${DASHBOARD_CALLBACK_BASE_URL}/oidc_callback_silentRenew.html -p ${DASHBOARD_CALLBACK_BASE_URL} -p ${DASHBOARD_CALLBACK_BASE_URL}/ - echo "create tank client with client id $TANK_OIDC_CLIENT_ID" - poetry run ./manage.py create_oidc_client tank confidential --client-id $TANK_OIDC_CLIENT_ID --client-secret $TANK_OIDC_CLIENT_SECRET -r "code" -u ${TANK_CALLBACK_BASE_URL}/auth/oidc/callback - fi - - ### Initializes the project (Development) ### - - if [[ $mode == "init" ]]; then - echo "Installing dependencies with Poetry" - poetry install --no-root - fi - - ### Runs Steering in development mode (Virtualenv) ### - - if [[ $mode == "dev" ]]; then - echo "Activating Python Environment" - poetry run python manage.py runserver - fi - - ### Runs Steering in production mode (WSGI) ### - - if [[ $mode == "prod" ]]; then - echo "!!! Not yet implemented !!!" - #gunicorn -c config/gunicorn.conf.py src.app:app - fi - - ### Runs the test-cases ### - - if [[ $mode == "test" ]]; then - echo "!!! Not yet implemented !!!" - fi - -fi - - -# +++ DOCKER COMMANDS +++ # - -if [[ $docker == "true" ]]; then - BASE_D=$(realpath "${BASH_SOURCE%/*}/") - - ### Runs Steering from Docker ### - - if [[ $mode == "dev" ]]; then - exec sudo docker run --rm -it \ - -u $UID:$GID \ - -p 127.0.0.1:8000:8000 \ - -v "$BASE_D":/srv autoradio/steering /srv/manage.py \ - runserver 0.0.0.0:8000 - fi - - ### Create Docker Image from local project ### - - if [[ $mode == "build" ]]; then - exec sudo docker build -t autoradio/steering . - fi - - ### Pushes the latest Docker Image to Docker Hub ### - - if [[ $mode == "push" ]]; then - exec sudo docker push autoradio/steering - fi -fi