Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found
Select Git revision
  • 299-delete-planed-assemblies
  • 302-habitat-info
  • 607-schedule-versions
  • 720-schedule_source
  • add-django-ninja
  • andi/develop
  • andi/schedule-api
  • andi/speaker_import
  • assembly-import
  • camp23-prod
  • chore/backoffice-list
  • chore/conference-singleton
  • chore/event-views
  • chore/update-rooms
  • cyroxx/add_edit_links
  • cyroxx/bulletin_description
  • develop
  • editMail
  • feat/dynamic-link-forms
  • feat/unit-integration-tests
  • feature/RegisterSpeaker
  • feature/audit_log
  • feature/bg-eyecandy
  • feature/conference-query-set
  • feature/event_import_slugs_of_serial_event
  • feature/mqtt
  • feature/parallax-css-testpage
  • feature/pypy
  • feature/scheduleimport_skippedrooms
  • feature/show_vods
  • production
  • room-docu
  • stable-38c3
  • camp23-prod
  • camp23-prod-archive
  • prod-2024-10-14_22-49
  • prod-2024-10-20_23-27
  • prod-2024-10-29_09-45
  • prod-2024-10-31_13-17
  • prod-2024-11-01_11-14
  • prod-2024-11-02_21-16
  • prod-2024-11-03_01-42
  • prod-2024-11-03_12-10
  • prod-2024-11-16_03-41
  • prod-2024-12-04_00-57
  • prod-2024-12-05_00-48
  • prod-2024-12-05_10-09
  • prod-2024-12-10_00-17
  • prod-2024-12-10_07-23
  • prod-2024-12-10_23-04
  • prod-2024-12-14_03-24
  • prod-2024-12-16_02-27
  • prod-2024-12-17_15-05
  • prod-2024-12-19_02-32
  • prod-2024-12-20_12-25
  • prod-2024-12-21_10-44
  • prod-2024-12-21_13-42
  • prod-2024-12-22_00-55
  • prod-2024-12-22_01-34
  • prod-2024-12-22_17-25
  • prod-2024-12-22_21-12
  • prod-2024-12-23_23-39
  • prod-2024-12-24_14-48
  • prod-2024-12-25_01-29
  • prod-2024-12-25_15-54
  • prod-2024-12-25_21-04
  • prod-2024-12-26_00-21
  • prod-2024-12-26_13-12
  • prod-2024-12-26_21-45
  • prod-2024-12-27_00-34
  • prod-2024-12-27_13-29
  • prod-2024-12-27_16-01
  • prod-2024-12-27_16-37
  • prod-2024-12-27_20-15
  • prod-2024-12-27_21-15
  • prod-2024-12-28_02-32
  • prod-2024-12-28_12-24
  • prod-2024-12-28_18-32
  • prod-2024-12-29_02-25
  • prod-2024-12-29_02-55
  • prod-2024-12-29_03-20
  • prod-2024-12-29_03-32
  • prod-2024-12-29_20-35
  • prod-2024-12-30_03-16
  • prod-2024-12-30_12-40
  • prod-2024-12-31_09-54
  • prod-2025-01-07_13-15
  • prod-2025-01-20_00-20
  • prod-2025-01-21_22-00
  • prod-2025-01-21_22-46
  • prod-2025-04-18_22-42
91 results

Target

Select target project
  • hub/hub
  • cyroxx/hub
  • myigel/hub
  • thomasdotwtf/hub
4 results
Select Git revision
  • 299-delete-planed-assemblies
  • 302-habitat-info
  • 445-schedule-redirects
  • 511-schedule-foo-fixed
  • 607-schedule-versions
  • 623-wiki-im-baustellenmodus-sollte-mal-als-wiki-admin-trotzdem-seiten-anlegen-bearbeiten-konnen
  • 720-schedule_source
  • andi/develop
  • andi/schedule-api
  • andi/speaker_import
  • badge-redeem-404
  • camp23-prod
  • chore/event-views
  • cyroxx/add_edit_links
  • cyroxx/bulletin_description
  • deploy/curl-verbose
  • develop
  • editMail
  • feat/dynamic-link-forms
  • feat/unit-integration-tests
  • feature/568-habitatmanagement
  • feature/RegisterSpeaker
  • feature/audit_log
  • feature/bg-eyecandy
  • feature/conference-query-set
  • feature/mqtt
  • feature/parallax-css-testpage
  • feature/pypy
  • feature/scheduleimport_skippedrooms
  • fix/index
  • fix/public-badge-access-rights
  • fix/registration_mail_subject
  • ical-export
  • production
  • room-docu
  • camp23-prod
  • camp23-prod-archive
  • prod-2024-10-14_22-49
  • prod-2024-10-20_23-27
  • prod-2024-10-29_09-45
  • prod-2024-10-31_13-17
  • prod-2024-11-01_11-14
  • prod-2024-11-02_21-16
  • prod-2024-11-03_01-42
  • prod-2024-11-03_12-10
  • prod-2024-11-16_03-41
  • prod-2024-12-04_00-57
  • prod-2024-12-05_00-48
  • prod-2024-12-05_10-09
  • prod-2024-12-10_00-17
  • prod-2024-12-10_07-23
  • prod-2024-12-10_23-04
  • prod-2024-12-14_03-24
  • prod-2024-12-16_02-27
  • prod-2024-12-17_15-05
  • prod-2024-12-19_02-32
  • prod-2024-12-20_12-25
  • prod-2024-12-21_10-44
  • prod-2024-12-21_13-42
  • prod-2024-12-22_00-55
  • prod-2024-12-22_01-34
  • prod-2024-12-22_17-25
  • prod-2024-12-22_21-12
  • prod-2024-12-23_23-39
  • prod-2024-12-24_14-48
  • prod-2024-12-25_01-29
  • prod-2024-12-25_15-54
  • prod-2024-12-25_21-04
  • prod-2024-12-26_00-21
  • prod-2024-12-26_13-12
  • prod-2024-12-26_21-45
  • prod-2024-12-27_00-34
  • prod-2024-12-27_13-29
  • prod-2024-12-27_16-01
  • prod-2024-12-27_16-37
  • prod-2024-12-27_20-15
76 results
Show changes

Commits on Source 840

740 additional commits have been omitted to prevent performance issues.
// For format details, see https://aka.ms/devcontainer.json. For config options, see the
// README at: https://github.com/devcontainers/templates/tree/main/src/postgres
{
"name": "Python 3 & PostgreSQL",
"dockerComposeFile": [
"../docker-compose.yml",
"docker-compose.yml"
],
"service": "hub",
"workspaceFolder": "/workspaces/app",
"shutdownAction": "stopCompose",
// Features to add to the dev container. More info: https://containers.dev/features.
// "features": {},
// Use 'forwardPorts' to make a list of ports inside the container available locally.
// This can be used to network with other containers or the host.
"forwardPorts": [
80,
"db:5432"
],
"portsAttributes": {
"5432": {
"label": "postgres database"
},
"80": {
"label": "webserver serve"
}
},
"containerEnv": {
"HUB_DB_HOST": "localhost",
"DISABLE_RATELIMIT": "True",
"DJANGO_CREATE_ADMIN_PASSWORD": "hubhubhub"
},
"customizations": {
"vscode": {
"extensions": [
"ms-python.python"
]
}
}
// Use 'postCreateCommand' to run commands after the container is created.
// "postCreateCommand": "pip install --user -r requirements.txt",
// Configure tool-specific properties.
// "customizations": {},
// Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root.
// "remoteUser": "root"
}
version: '3.8'
services:
hub:
volumes:
- ./:/workspaces/app
# Overrides default command so things don't shut down after the process ends.
command: sleep infinity
entrypoint: []
# Runs app on the same network as the database container, allows "forwardPorts" in devcontainer.json function.
# network_mode: service:db # Already set in outer compose file
# Use "forwardPorts" in **devcontainer.json** to forward an app port locally.
# (Adding the "ports" property to this file will not forward from a Codespace.)
......@@ -10,3 +10,9 @@ src/hub/.settings.secret
# local media files
src/media/
.tools/
.vscode/
.venv*/
**/*_cache
......@@ -2,18 +2,16 @@
root = true
[*]
indent_style = space
indent_size = 4
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true
end_of_line = lf
indent_size = 2
indent_style = space
max_line_length = 120
trim_trailing_whitespace = true
[*.md]
trim_trailing_whitespace = false
[*.{css,html,js,scss,j2}]
indent_size = 2
[*.yml]
indent_size = 2
[*.py, *.toml]
indent_size = 4
......@@ -8,8 +8,6 @@ CLIENT_IP_HEADER=HTTP_X_REAL_IP
DJANGO_MIGRATE=yes
DJANGO_HOST=hub.localhost
ADMINS=admin@localhost
# mail configuration
MAIL_FROM=noreply@localhost
MAIL_CONFIG=smtp+tls://smtpuser:pass@mx:587
......
# Reformat with ruff
cad2f7373a716750d234842d93849af3014b72ad
# Reformat commits
dc0e95b225cf4db7aa4ff67a4bcd3572625eba56
14b7cb96e61e576ea62f5ee1b98d8bf4337895a8
## ruff
cad2f7373a716750d234842d93849af3014b72ad
## prettier
0bb342a92c644a25ca11b549c7a94c996c591279
## djLint
31839261af33014cbc7d5af93fcd1189d91d4755
# Split PlainUI views
caeff36b26f18a0732ddfcc752752529787a0632
/.yarn/** linguist-vendored
/.yarn/releases/* binary
/.yarn/plugins/**/* binary
/.pnp.* binary linguist-generated
# OS-specifc cache files
.DS_Store
Thumbs.db
# Django secret key
src/hub/settings/.settings.secret
# Python cache files
*.pyc
__pycache__/
# direnv
**/.envrc
# Dev environment settings
docker-compose.local.yml
dev.env
# editor config
/.idea/
/.vscode/
# OS-specifc cache files
.DS_Store
Thumbs.db
# generic temporary or backup files
*.bak
*.tmp
~*
bak/
tmp/
# venv stuff
venv/
bin/
include/
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class
# C extensions
*.so
# Distribution / packaging
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64
pyvenv.cfg
lib64/
parts/
sdist/
var/
wheels/
share/python-wheels/
*.egg-info/
.installed.cfg
*.egg
MANIFEST
# Installer logs
pip-log.txt
pip-delete-this-directory.txt
# Unit test / coverage reports
htmlcov/
.tox/
.nox/
.coverage
.coverage.*
.cache
src/hub/settings/.settings.secret
coverage.xml
*.cover
*.py,cover
.hypothesis/
.pytest_cache/
cover/
.tools/
# direnv
.envrc
# Translations
*.mo
*.pot
# Dev environment settings
docker-compose.local.yml
dev.env
# Django stuff:
*.log
local_settings.py
db.sqlite3
db.sqlite3-journal
coverage.xml
# IPython
profile_default/
ipython_config.py
# Environments
.env
.venv
env/
venv/
ENV/
env.bak/
venv.bak/
# mypy
.mypy_cache/
.dmypy.json
dmypy.json
# Cython debug symbols
cython_debug/
# yarn
.pnp.*
.yarn/*
!.yarn/patches
!.yarn/plugins
!.yarn/releases
# SDKS are excluded as we do not want them in the repository
# !.yarn/sdks
!.yarn/versions
......@@ -5,6 +5,7 @@ stages:
- container-test
- publish
- deploy
- cleanup
workflow:
rules:
......@@ -28,177 +29,232 @@ workflow:
# Use build cache to speed up CI
default:
cache:
- key: "kaniko-default"
- key:
files:
- uv.lock
paths:
- .cache/kaniko
- $UV_CACHE_DIR
- key: "python-default"
paths:
- .cache/pip
- .cache/pdm
- key:
files:
- src/plainui/yarn.lock
- yarn.lock
paths:
- .yarn-cache/
- .yarn/cache/
.django_runner_settings:
before_script:
- echo "{\"tag\":\"$CI_COMMIT_TAG\",\"commit\":\"$CI_COMMIT_SHA\",\"branch\":\"$CI_COMMIT_BRANCH\",\"ci\":true}" > src/version.json
- |
cat > src/version.json <<EOF
{
"tag": "$CI_COMMIT_TAG",
"commit": "$CI_COMMIT_SHA",
"branch": "$CI_COMMIT_BRANCH",
"ci": true,
"pipeline": {
"id": "$CI_PIPELINE_ID",
"url": "$CI_PIPELINE_URL",
"date": "$CI_PIPELINE_CREATED_AT"
}
}
EOF
services:
- name: postgis/postgis:15-3.3
alias: db_server
variables:
ALLOWED_HOSTS: "127.0.0.1,hubapp"
ALLOWED_HOSTS: "127.0.0.1,hubapp,hubapp-${CI_JOB_ID}"
DJANGO_DEBUG: "I_KNOW_WHAT_I_AM_DOING"
POSTGRES_HOST_AUTH_METHOD: trust
POSTGRES_PASSWORD: runner
POSTGRES_USER: ci
SSO_SECRET_GENERATE: "True"
STORAGE_TYPE: local
# Warm up the local image cache
# Will throw a warning for local stages, but that's fine
warmup:
stage: prepare
image:
name: gcr.io/kaniko-project/executor:debug
entrypoint: [""]
cache:
paths:
- "$CI_PROJECT_DIR/.cache/kaniko"
script:
- /kaniko/warmer --cache-dir=$CI_PROJECT_DIR/.cache/kaniko -d Dockerfile
rules:
- when: always
UV_CACHE_DIR: .uv-cache
# Kaniko build setup
.build:
extends:
- .default-rules
image:
name: gcr.io/kaniko-project/executor:debug
entrypoint: [""]
variables:
KANIKO_CACHE_ARGS: "--cache=true --cache-copy-layers=true --cache-run-layers=true --cache-ttl=24h --cache-repo=$CI_REGISTRY_IMAGE/cache"
KANIKO_ARGS: "--skip-unused-stages=true"
KANIKO_CACHE_ARGS: --cache=true
--cache-copy-layers=true
--cache-run-layers=true
--cache-ttl=24h
--cache-dir=$CI_PROJECT_DIR/.cache/kaniko
--cache-repo=$CI_REGISTRY_IMAGE/cache
KANIKO_ARGS: --skip-unused-stages=true
--context $CI_PROJECT_DIR
--build-arg REGISTRY=git.cccv.de/crews/hub/dependency_proxy/containers/
before_script:
- echo "{\"auths\":{\"$CI_REGISTRY\":{\"username\":\"$CI_REGISTRY_USER\",\"password\":\"$CI_REGISTRY_PASSWORD\"},\"https://index.docker.io/v1/\":{\"username\":\"$DOCKER_HUB_USER\",\"password\":\"$DOCKER_HUB_PASSWORD\"}}}" > /kaniko/.docker/config.json
- echo "{\"tag\":\"$CI_COMMIT_TAG\",\"commit\":\"$CI_COMMIT_SHA\",\"branch\":\"$CI_COMMIT_BRANCH\",\"ci\":true}" > src/version.json
.container-build:
extends:
- .build
- .default-rules
stage: build
- |
cat > /kaniko/.docker/config.json <<EOF
{
"auths": {
"$CI_REGISTRY": {
"username": "$CI_REGISTRY_USER",
"password": "$CI_REGISTRY_PASSWORD"
},
"$(echo -n $CI_DEPENDENCY_PROXY_SERVER | awk -F[:] '{print $1}')": {
"username": "$CI_DEPENDENCY_PROXY_USER",
"password": "$CI_DEPENDENCY_PROXY_PASSWORD"
}
}
}
EOF
- |
cat > src/version.json <<EOF
{
"tag": "$CI_COMMIT_TAG",
"commit": "$CI_COMMIT_SHA",
"branch": "$CI_COMMIT_BRANCH",
"ci": true
}
EOF
after_script:
- uv cache prune --ci
generate_css:
extends:
- .default-rules
image: node:20-bookworm
stage: prepare
needs: []
script:
- cd src/plainui/
- echo 'yarn-offline-mirror ".yarn-cache/"' >> .yarnrc
- echo 'yarn-offline-mirror-pruning true' >> .yarnrc
- yarn install --non-interactive --no-progress --frozen-lockfile
- yarn run build
artifacts:
paths:
- src/plainui/static/plainui/rc3*.css*
# Crane setup
.crane:
image:
name: gcr.io/go-containerregistry/crane:debug
entrypoint: [""]
variables:
GIT_STRATEGY: none
before_script:
- '[ -n "$DOCKER_CONFIG" ] || export DOCKER_CONFIG=$HOME/.docker'
- crane auth login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
meta_build:
stage: prepare
extends: .build
needs:
- warmup
variables:
PIP_CACHE_DIR: "$CI_PROJECT_DIR/.cache/pip"
UV_CACHE_DIR: .uv-cache
script:
- /kaniko/executor --context $CI_PROJECT_DIR --dockerfile $CI_PROJECT_DIR/.meta/Dockerfile --destination $CI_REGISTRY_IMAGE/build_image:$CI_PIPELINE_ID $KANIKO_ARGS $KANIKO_CACHE_ARGS
- /kaniko/executor
$KANIKO_ARGS
$KANIKO_CACHE_ARGS
--dockerfile $CI_PROJECT_DIR/Dockerfile
--target meta
--destination $CI_REGISTRY_IMAGE/meta_image:mi-$CI_PIPELINE_ID
rules:
- when: always
app_version:
.test:
extends:
- .default-rules
- .django_runner_settings
image: $CI_REGISTRY_IMAGE/build_image:$CI_PIPELINE_ID
stage: test
image: $CI_REGISTRY_IMAGE/meta_image:mi-$CI_PIPELINE_ID
variables:
UV_CACHE_DIR: .uv-cache
needs:
- meta_build
after_script:
- uv cache prune --ci
app_version:
stage: test
extends: .test
variables:
FF_NETWORK_PER_BUILD: 1
POSTGRES_DB: migrations
DATABASE_URL: "postgis://ci:runner@db_server/migrations"
HUB_DB_SCHEMA: migrations
script:
- python3 -V
- cd src
- tox run -e app_version
- uv sync
- uv run task app_version
allow_failure: true
rules:
- when: always
code_style:
image: $CI_REGISTRY_IMAGE/build_image:$CI_PIPELINE_ID
lint:
stage: test
needs:
- meta_build
extends: .test
script:
- python3 -V
- tox run
- tox -e py-lint,html-lint
allow_failure: true
rules:
- when: always
ruff:
image: $CI_REGISTRY_IMAGE/build_image:$CI_PIPELINE_ID
format:
stage: test
needs:
- meta_build
extends: .test
script:
- python3 -V
- tox run -e ruff
- tox -e py-format,html-format
- git diff --exit-code -- . ':!src/version.json'
allow_failure: true
rules:
- when: always
ruff_format:
image: $CI_REGISTRY_IMAGE/build_image:$CI_PIPELINE_ID
format_prettier:
image: node:22-alpine
stage: test
needs:
- meta_build
needs: []
before_script:
- apk add --no-cache git
- corepack enable
- 'echo "cacheFolder: \".yarn/cache/\"" >> .yarnrc.yml'
- yarn install --immutable
script:
- python3 -V
- tox run -e ruff_format
- yarn format
- git diff --exit-code -- . ':!src/version.json' ':!.yarnrc.yml'
allow_failure: true
rules:
- when: always
migration_check:
extends:
- .default-rules
- .django_runner_settings
image: $CI_REGISTRY_IMAGE/build_image:$CI_PIPELINE_ID
stage: test
needs:
- meta_build
extends: .test
variables:
FF_NETWORK_PER_BUILD: 1
POSTGRES_DB: migrations
DATABASE_URL: "postgis://ci:runner@db_server/migrations"
HUB_DB_SCHEMA: migrations
script:
- python3 -V
- cd src
- tox run -e migrations
- uv run task manage makemigrations --check
- uv run task manage makemigrations --dry-run
sanity_check:
translations_check:
stage: test
extends: .test
variables:
FF_NETWORK_PER_BUILD: 1
POSTGRES_DB: transaltions
DATABASE_URL: "postgis://ci:runner@db_server/transaltions"
allow_failure: true
script:
- python3 -V
- uv sync
- uv run task manage makemessages
- git diff --exit-code -- . ':!src/version.json'
requirements_export:
stage: test
extends: .test
script:
- python3 -V
- uv lock --check
- uv export --frozen -o=requirements.dev.txt --no-hashes --all-groups
- uv export --frozen -o=requirements.txt --no-hashes --no-dev
- git diff --exit-code -- . ':!src/version.json'
rules:
- changes:
- requirements.txt
- requirements.dev.txt
- project.toml
- uv.lock
django-tests:
stage: test
extends:
- .test
- .default-rules
- .django_runner_settings
image: $CI_REGISTRY_IMAGE/build_image:$CI_PIPELINE_ID
stage: test
needs:
- meta_build
- migration_check
......@@ -206,71 +262,69 @@ sanity_check:
FF_NETWORK_PER_BUILD: 1
POSTGRES_DB: self_test
DATABASE_URL: "postgis://ci:runner@db_server/self_test"
HUB_DB_SCHEMA: self_test
script:
- echo "{\"tag\":\"$CI_COMMIT_TAG\",\"commit\":\"$CI_COMMIT_SHA\",\"branch\":\"$CI_COMMIT_BRANCH\",\"ci\":false}" > src/version.json
- python3 -V
- cd src
- tox run -e django-full
- cd $CI_PROJECT_DIR
- coverage xml -i
- tox -e django-test
- tox -e coverage-report
coverage: '/(?i)total(?:\s+\d+){4}\s+(\d+)%/'
artifacts:
reports:
coverage_report:
coverage_format: cobertura
path: coverage.xml
build_test:
extends: .container-build
needs:
- generate_css
- sanity_check
script:
- /kaniko/executor --context $CI_PROJECT_DIR --dockerfile $CI_PROJECT_DIR/Dockerfile --destination $CI_REGISTRY_IMAGE/ci/hub:ci-$CI_PIPELINE_ID-test $KANIKO_ARGS $KANIKO_CACHE_ARGS
path: .tools/coverage/report.xml
paths:
- .tools/coverage/html_report/
expire_in: 1 week
expose_as: "HTML Coverage Report"
build_nginx:
extends: .container-build
stage: build
extends:
- .build
needs:
- generate_css
- build_test
- migration_check
- django-tests
script:
- /kaniko/executor --context $CI_PROJECT_DIR --dockerfile $CI_PROJECT_DIR/Dockerfile --target nginx --destination $CI_REGISTRY_IMAGE/ci/nginx:ci-$CI_PIPELINE_ID $KANIKO_ARGS $KANIKO_CACHE_ARGS
- /kaniko/executor
$KANIKO_ARGS
$KANIKO_CACHE_ARGS
--dockerfile $CI_PROJECT_DIR/Dockerfile
--target nginx
--destination $CI_REGISTRY_IMAGE/ci/nginx:ci-$CI_PIPELINE_ID
build_release:
extends: .container-build
stage: build
extends:
- .build
needs:
- generate_css
- build_test
- migration_check
- django-tests
script:
- /kaniko/executor --context $CI_PROJECT_DIR --dockerfile $CI_PROJECT_DIR/Dockerfile --target webworker --destination $CI_REGISTRY_IMAGE/ci/hub:ci-$CI_PIPELINE_ID $KANIKO_ARGS $KANIKO_CACHE_ARGS
- /kaniko/executor
$KANIKO_ARGS
$KANIKO_CACHE_ARGS
--dockerfile $CI_PROJECT_DIR/Dockerfile
--target webworker
--destination $CI_REGISTRY_IMAGE/ci/hub:ci-$CI_PIPELINE_ID
test_internals:
build_test:
stage: build
extends:
- .default-rules
- .django_runner_settings
stage: container-test
- .build
needs:
- build_test
image:
name: "$CI_REGISTRY_IMAGE/ci/hub:ci-$CI_PIPELINE_ID-test"
entrypoint: [""]
variables:
FF_NETWORK_PER_BUILD: 1
POSTGRES_DB: internals
DATABASE_URL: "postgis://ci:runner@db_server/internals"
SERVE_API: "yes"
SERVE_BACKOFFICE: "yes"
SERVE_FRONTEND: "yes"
USE_PLAIN_STATICFILES: "yes"
BADGE_RATE_LIMIT: "1/h"
DJANGO_SETTINGS_MODULE: "hub.settings.test"
before_script:
- python3 -V
- ls -l /app
- build_release
script:
- /usr/local/bin/app version
- /usr/local/bin/app test
- |
cat > Dockerfile_Test <<EOF
FROM $CI_REGISTRY_IMAGE/ci/hub:ci-$CI_PIPELINE_ID
ENV BIND_HTTP=1
EXPOSE 8000
EOF
- /kaniko/executor
--destination $CI_REGISTRY_IMAGE/ci/hub:ci-$CI_PIPELINE_ID-test
$KANIKO_ARGS
$KANIKO_CACHE_ARGS
--dockerfile Dockerfile_Test
.test_image:
extends:
......@@ -288,12 +342,12 @@ test_internals:
SERVE_API: "no"
SERVE_BACKOFFICE: "no"
SERVE_FRONTEND: "no"
BASE_URL: http://hubapp:8000
BASE_URL: http://hubapp-${CI_JOB_ID}:8000
services:
- name: postgis/postgis:15-3.3
alias: db_server
- name: "$CI_REGISTRY_IMAGE/ci/hub:ci-$CI_PIPELINE_ID-test"
alias: hubapp
alias: hubapp-${CI_JOB_ID}
variables:
DJANGO_CREATE_ADMIN_PASSWORD: "Test1234"
DJANGO_DEBUG: "no"
......@@ -303,6 +357,8 @@ test_internals:
SELECTED_CONFERENCE_ID: "017c0749-a2ea-4f86-92cd-e60b4508dd98"
before_script:
- pip3 install requests
# TODO: remove this sleep once we have debugged the case for the 0 ms failure
- sleep 30
- echo "testing on $BASE_URL"
- curl --max-time 8 --retry 3 --fail ${BASE_URL}/.well-known/version
- curl --max-time 3 --retry 3 --fail ${BASE_URL}/.well-known/health
......@@ -354,48 +410,19 @@ test_nginx_static:
.publish-image:
stage: publish
extends: .crane
needs:
- build_release
- test_image_frontend
- test_internals
- test_image_api
- test_nginx_static
image:
name: gcr.io/go-containerregistry/crane:debug
entrypoint: [""]
variables:
GIT_STRATEGY: none
before_script:
- '[ -n "$DOCKER_CONFIG" ] || export DOCKER_CONFIG=$HOME/.docker'
- crane auth login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
.publish-clean:
extends:
- .publish-image
after_script:
- crane delete $CI_REGISTRY_IMAGE/ci/hub:ci-${CI_PIPELINE_ID}-test
- crane delete $CI_REGISTRY_IMAGE/ci/hub:ci-${CI_PIPELINE_ID}
- crane delete $CI_REGISTRY_IMAGE/ci/nginx:ci-${CI_PIPELINE_ID}
publish-commit:
extends:
- .publish-clean
script:
- crane tag $CI_REGISTRY_IMAGE/ci/hub:ci-${CI_PIPELINE_ID} ${CI_COMMIT_SHORT_SHA}
- crane tag $CI_REGISTRY_IMAGE/ci/nginx:ci-${CI_PIPELINE_ID} ${CI_COMMIT_SHORT_SHA}
rules:
- if: '$CI_COMMIT_BRANCH == "develop" || $CI_PIPELINE_SOURCE == "merge_request_event" || $CI_COMMIT_TAG'
- when: never
publish-mr:
extends:
- .publish-image
needs:
- publish-commit
script:
- crane tag $CI_REGISTRY_IMAGE/ci/hub:${CI_COMMIT_SHORT_SHA} mr-${CI_MERGE_REQUEST_ID}
- crane tag $CI_REGISTRY_IMAGE/ci/nginx:${CI_COMMIT_SHORT_SHA} mr-${CI_MERGE_REQUEST_ID}
- crane tag $CI_REGISTRY_IMAGE/ci/hub:ci-$CI_PIPELINE_ID mr-${CI_MERGE_REQUEST_ID}
- crane tag $CI_REGISTRY_IMAGE/ci/nginx:ci-$CI_PIPELINE_ID mr-${CI_MERGE_REQUEST_ID}
rules:
- if: '$CI_PIPELINE_SOURCE == "merge_request_event"'
- when: never
......@@ -403,11 +430,9 @@ publish-mr:
publish-develop:
extends:
- .publish-image
needs:
- publish-commit
script:
- crane copy $CI_REGISTRY_IMAGE/ci/hub:${CI_COMMIT_SHORT_SHA} $CI_REGISTRY_IMAGE:development
- crane copy $CI_REGISTRY_IMAGE/ci/nginx:${CI_COMMIT_SHORT_SHA} $CI_REGISTRY_IMAGE/nginx:development
- crane copy $CI_REGISTRY_IMAGE/ci/hub:ci-$CI_PIPELINE_ID $CI_REGISTRY_IMAGE:development
- crane copy $CI_REGISTRY_IMAGE/ci/nginx:ci-$CI_PIPELINE_ID $CI_REGISTRY_IMAGE/nginx:development
rules:
- if: $CI_COMMIT_BRANCH == 'develop'
- when: never
......@@ -416,17 +441,33 @@ publish-develop:
publish-production:
extends:
- .publish-image
needs:
- publish-commit
script:
- crane copy $CI_REGISTRY_IMAGE/ci/hub:$CI_COMMIT_SHORT_SHA $CI_REGISTRY_IMAGE:production
- crane copy $CI_REGISTRY_IMAGE/ci/hub:ci-$CI_PIPELINE_ID $CI_REGISTRY_IMAGE:production
- crane tag $CI_REGISTRY_IMAGE:production latest
- crane copy $CI_REGISTRY_IMAGE/ci/nginx:$CI_COMMIT_SHORT_SHA $CI_REGISTRY_IMAGE/nginx:production
- crane copy $CI_REGISTRY_IMAGE/ci/nginx:ci-$CI_PIPELINE_ID $CI_REGISTRY_IMAGE/nginx:production
- crane tag $CI_REGISTRY_IMAGE/nginx:production latest
rules:
- if: '$CI_COMMIT_TAG =~ /^prod-\d{4}-\d{2}-\d{2}_\d{2}-\d{2}$/'
- when: never
publish-sentry-release:
stage: publish
image: python:3.11-bookworm
needs:
- publish-production
before_script:
- pip3 install sentry-cli
script:
- sentry-cli releases new $CI_COMMIT_TAG
- sentry-cli releases set-commits $CI_COMMIT_TAG --commit "hub / hub@$CI_COMMIT_SHA"
- sentry-cli releases finalize $CI_COMMIT_TAG
rules:
# skip if SENTRY URL is not set
- if: $SENTRY_URL == null
when: never
- if: '$CI_COMMIT_TAG =~ /^prod-\d{4}-\d{2}-\d{2}_\d{2}-\d{2}$/'
- when: never
deploy_develop:
stage: deploy
allow_failure: true
......@@ -456,6 +497,7 @@ deploy_production:
allow_failure: true
needs:
- publish-production
- publish-sentry-release
image: python:3.11-bookworm
script:
- 'curl -X POST "$DEPLOYMENT_SERVICEWEBHOOK_URL_PRODUCTION"'
......@@ -474,3 +516,28 @@ deploy_production:
# otherwise, skip this
- when: never
cleanup-ci-images:
stage: cleanup
extends:
- .crane
script:
- crane delete $CI_REGISTRY_IMAGE/ci/hub:ci-${CI_PIPELINE_ID}
- crane delete $CI_REGISTRY_IMAGE/ci/nginx:ci-${CI_PIPELINE_ID}
- crane delete $CI_REGISTRY_IMAGE/ci/hub:ci-${CI_PIPELINE_ID}-test
- crane delete $CI_REGISTRY_IMAGE/meta_image:mi-$CI_PIPELINE_ID
needs:
- job: publish-production
optional: true
- job: publish-develop
optional: true
- job: publish-mr
optional: true
rules:
- if: $CI_COMMIT_BRANCH == "develop"
- if: $CI_COMMIT_TAG
- if: $CI_PIPELINE_SOURCE == 'merge_request_event'
- if: $FORCE_PIPELINE_RUN == 'true'
when: on_success
- when: never
allow_failure: true
FROM python:3.11-bookworm
RUN apt update && apt install -y gettext gdal-bin iputils-ping
COPY src/requirements.txt src/requirements-dev.txt /
RUN pip3 install -r /requirements.txt -r /requirements-dev.txt "psycopg[binary]"
......@@ -2,18 +2,14 @@ exclude: ^.*.min.*|migrations|yarn.lock|venv$
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v2.3.0
rev: v5.0.0
hooks:
- id: check-yaml
- id: check-toml
- id: check-merge-conflict
- id: check-ast
- repo: https://github.com/PyCQA/flake8
rev: 6.1.0
hooks:
- id: flake8
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.1.5
rev: v0.9.7
hooks:
- id: ruff
args: [--fix]
......@@ -22,3 +18,47 @@ repos:
rev: v1.0.0
hooks:
- id: check-json5
- repo: https://github.com/djlint/djLint
rev: v1.36.4
hooks:
- id: djlint-reformat-django
- id: djlint-reformat-jinja
- id: djlint-django
- id: djlint-jinja
- repo: https://github.com/astral-sh/uv-pre-commit
rev: 0.6.2
hooks:
- id: uv-lock
- repo: https://github.com/astral-sh/uv-pre-commit
rev: 0.6.2
hooks:
- name: uv-export-prod
id: uv-export
args:
- --frozen
- -o=requirements.txt
- --no-hashes
- --no-dev
- name: uv-export-dev
id: uv-export
args:
- --frozen
- -o=requirements.dev.txt
- --no-hashes
- --all-groups
- repo: local
hooks:
- name: Check for uncreated migrations.
id: migrations-check
language: system
entry: sh -c "uv run task manage makemigrations --check --dry-run"
files: "models/.*.py$"
types:
- python
stages:
- pre-commit
- name: prettier
id: prettier
entry: yarn prettier --write --ignore-unknown
language: node
"types": [text]
**/*.html
**/*.j2
.yarn
.yarnrc.yml
.venv*
static.dist/
**/vendor/**/*
**/list_script.js
src/core/fixtures/local/**/*
src/plainui/static/plainui/hub.*
src/**/templates/**/*.js
{}
activitypub
Andi
ASGI
backoffice
blocktranslate
clonbares
CLUBFRIENDS
Conferencemember
csrf
csrfmiddlewaretoken
datatables
dect
derefer
dereferrer
Dereferrer
Disclaimern
Einlöseseite
emph
endblocktranslate
endfor
endspaceless
engelsystem
exneuland
favorited
forloop
gettz
Habitatsbeitritt
Habitatseinladung
Habitatszuordnung
Historieneintrag
htmlhead
jitsi
JITSI
keepalive
markdownify
merch
Merch
metanav
mgmt
msgid
msgstr
naturaltime
nplurals
orga
Orga
pentabarf
plainui
pois
pretix
Registrierungs
Registrierungsinformationen
Registrierungsstart
renderable
Roang
Screensharing
Shadowbanned
Shibboleet
unhide
Vorlesungsraum
Vorlesungssaal
yesno
[tool.pylint.main]
# Specify a score threshold under which the program will exit with error.
fail-under = 8.0
# Files or directories to be skipped. They should be base names, not paths.
ignore = ["CVS", ".git", "__pycache__", ".tools", "node_modules", "migrations"]
# Add files or directories matching the regular expressions patterns to the
# ignore-list. The regex matches against paths and can be in Posix or Windows
# format. Because '\\' represents the directory delimiter on Windows systems, it
# can't be used as an escape character.
# ignore-paths =
# Files or directories matching the regular expression patterns are skipped. The
# regex matches against base names, not paths. The default value ignores Emacs
# file locks
ignore-patterns = ["^\\.#"]
# Use multiple processes to speed up Pylint. Specifying 0 will auto-detect the
# number of processors available to use, and will cap the count on Windows to
# avoid hangs.
#jobs = 0
# List of plugins (as comma separated values of python module names) to load,
# usually to register additional checkers.
load-plugins = ["pylint_django"]
# Pickle collected data for later comparisons.
persistent = true
# Resolve imports to .pyi stubs if available. May reduce no-member messages and
# increase not-an-iterable messages.
prefer-stubs = true
# Minimum Python version to use for version dependent checks. Will default to the
# version used to run pylint.
py-version = "3.13"
[tool.pylint.basic]
# Good variable names which should always be accepted, separated by a comma.
good-names = ["i", "j", "k", "ex", "Run", "_"]
[tool.pylint.classes]
# Warn about protected attribute access inside special methods
# check-protected-access-in-special-methods =
# List of method names used to declare (i.e. assign) instance attributes.
defining-attr-methods = [
"__init__",
"__new__",
"setUp",
"asyncSetUp",
"__post_init__",
]
[tool.pylint.design]
# List of regular expressions of class ancestor names to ignore when counting
# public methods (see R0903)
# exclude-too-few-public-methods =
# List of qualified class names to ignore when counting class parents (see R0901)
# ignored-parents =
# Maximum number of arguments for function / method.
max-args = 5
# Maximum number of attributes for a class (see R0902).
max-attributes = 7
# Maximum number of boolean expressions in an if statement (see R0916).
max-bool-expr = 5
# Maximum number of branch for function / method body.
max-branches = 12
# Maximum number of locals for function / method body.
max-locals = 15
# Maximum number of parents for a class (see R0901).
max-parents = 7
# Maximum number of positional arguments for function / method.
max-positional-arguments = 5
# Maximum number of public methods for a class (see R0904).
max-public-methods = 20
# Maximum number of return / yield for function / method body.
max-returns = 6
# Maximum number of statements in function / method body.
max-statements = 50
# Minimum number of public methods for a class (see R0903).
# min-public-methods =
[tool.pylint.format]
# Maximum number of characters on a single line.
max-line-length = 160
# Maximum number of lines in a module.
max-module-lines = 1000
[tool.pylint.imports]
# List of modules that can be imported at any level, not just the top level one.
allow-any-import-level = ["core.templatetags.hub_absolute"]
[tool.pylint.logging]
# The type of string formatting that logging methods do. `old` means using %
# formatting, `new` is for `{}` formatting.
logging-format-style = "new"
[tool.pylint."messages control"]
# Disable the message, report, category or checker with the given id(s). You can
# either give multiple identifiers separated by comma (,) or put this option
# multiple times (only on the command line, not in the configuration file where
# it should appear only once). You can also use "--disable=all" to disable
# everything first and then re-enable specific checks. For example, if you want
# to run only the similarities checker, you can use "--disable=all
# --enable=similarities". If you want to run only the classes checker, but have
# no Warning level messages displayed, use "--disable=all --enable=classes
# --disable=W".
disable = [
"raw-checker-failed",
"bad-inline-option",
"locally-disabled",
"file-ignored",
"suppressed-message",
"useless-suppression",
"deprecated-pragma",
"use-implicit-booleaness-not-comparison-to-string",
"use-implicit-booleaness-not-comparison-to-zero",
"use-symbolic-message-instead",
"missing-module-docstring", # we did not write docstrings for all modules - Can be enabled with time
"missing-class-docstring", # we did not write docstrings for all classes - Can be enabled with time
"missing-function-docstring", # we did not write docstrings for all functions - Can be enabled with time
"too-many-ancestors", # we do not want to limit the number of ancestors to have full use of django features
"wrong-import-position", # import position is enforced by isort/ruff
"wrong-import-order", # import order is enforced by isort/ruff
"logging-too-many-args", # The way most of our logging is done, would trigger this. Enable with logging statement updates
# Let's ignore design issues for now
"too-few-public-methods",
"too-many-ancestors",
"too-many-arguments",
"too-many-boolean-expressions",
"too-many-branches",
"too-many-function-args",
"too-many-instance-attributes",
"too-many-locals",
"too-many-nested-blocks",
"too-many-positional-arguments",
"too-many-public-methods",
"too-many-return-statements",
"too-many-statements",
"unused-argument",
"protected-access",
]
[tool.pylint.miscellaneous]
# List of note tags to take in consideration, separated by a comma.
notes = ["FIXME", "XXX", "TODO"]
[tool.pylint.refactoring]
# Maximum number of nested blocks for function / method body
max-nested-blocks = 5
[tool.pylint.reports]
# Set the output format. Available formats are: text, parseable, colorized, json2
# (improved json format), json (old json format) and msvs (visual studio). You
# can also give a reporter class, e.g. mypackage.mymodule.MyReporterClass.
output-format = "colorized"
# Tells whether to display a full report or only the messages.
reports = true
# Activate the evaluation score.
score = true
[tool.pylint.typecheck]
# List of decorators that produce context managers, such as
# contextlib.contextmanager. Add to this list to register other decorators that
# produce valid context managers.
contextmanager-decorators = ["contextlib.contextmanager"]
# List of members which are set dynamically and missed by pylint inference
# system, and so shouldn't trigger E1101 when accessed. Python regular
# expressions are accepted.
# generated-members =
# Tells whether missing members accessed in mixin class should be ignored. A
# class is considered mixin if its name matches the mixin-class-rgx option.
# Tells whether to warn about missing members when the owner of the attribute is
# inferred to be None.
ignore-none = true
# This flag controls whether pylint should warn about no-member and similar
# checks whenever an opaque object is returned when inferring. The inference can
# return multiple potential results while evaluating a Python object, but some
# branches might not be evaluated, which results in partial inference. In that
# case, it might be useful to still emit no-member and other checks for the rest
# of the inferred objects.
ignore-on-opaque-inference = true
# List of symbolic message names to ignore for Mixin members.
ignored-checks-for-mixins = [
"no-member",
"not-async-context-manager",
"not-context-manager",
"attribute-defined-outside-init",
]
# List of class names for which member attributes should not be checked (useful
# for classes with dynamically set attributes). This supports the use of
# qualified names.
ignored-classes = [
"optparse.Values",
"thread._local",
"_thread._local",
"argparse.Namespace",
]
[tool.pylint.variables]
# Tells whether unused global variables should be treated as a violation.
allow-global-unused-variables = true
File suppressed by a .gitattributes entry, the file's encoding is unsupported, or the file size exceeds the limit.
yarnPath: .yarn/releases/yarn-4.6.0.cjs
# Lokale Entwicklung
Dieses Projekt basiert auf Python 3.13+ und Django 5.1+.
## Initiale Einrichtung
### Lokales Docker development image
Das Docker development image vereinfacht die initiale Einrichtung und sperrt alle Abhängigkeiten und Prozesse in einen Entwicklungscontainer. Alternativ ist auch eine [manuelle Einrichtung](#lokale-einrichtung) möglich.
1. [Docker](https://docs.docker.com/get-docker/) und [Docker Compose](https://docs.docker.com/compose/install/) installieren.
Unter Windows getestet mit WSL 2.
2. Klonen dieses Repositories an beliebigen Ort.
3. Image erzeugen: `docker compose build`
- Für schnellere Builds kann [buildkit](https://docs.docker.com/build/buildkit/) verwendet werden:
```bash
export DOCKER_BUILDKIT=1
```
- Die Standardpasswöter für PostgreSQL und Hub Benutzer sind in der `docker-compose.yml` Datei festgelegt und können per Umgebungsvariable angepasst werden.
4. Container erzeugen: `docker compose up -d hub`
- Beim Start mittels `docker compose` wird kein HUB Admin Benutzer angelegt um ein ungewolltes anlegen von diesen Benutzern in der Produktivumgebung vorzubeugen.
Falls der `admin` Benutzer angelegt werden soll muss die Umgebungsvariable `DJANGO_CREATE_ADMIN_PASSWORD` für den Container gesetzt werden.
5. Optional: Import von Demo-Daten: `docker compose exec -it hub python manage.py loaddata ./core/fixtures/anhalter.json`
#### Debug Zugriff
Um auf einen Docker Container mit dem root bentuzer zuzugreifen kann das folgende Kommando verwendet werden: `docker compose exec -u root hub /bin/bash`
#### Docker Einstellungen in der Entwicklungsumgebung
Um die Einstellungen der Instanz anzupassen kann eine `dev.env` Datei im Root-Verzeichnis angelegt werden.
Diese kann duch das anlegen einer localen compose Datei mit dem folgenden Inhalt geladen werden:
```yaml
version: "3.8"
services:
hub:
env_file:
- dev.env
```
Diese kann durch das setzen der Umgebungsvariable `COMPOSE_FILE=docker-compose.yml:docker-compose.local.yml` automatisch beim allen `docker compose` Kommandos berücksichtigt werden.
Um eine andere Demo Datei zu laden kann die Umgebungsvariable `DJANGO_LOAD_FIXTURE` gesetzt werden (Aufgrund von Compose Prioritäten ist es nicht möglich das über die dev.env Datei zu setzen).
### Lokale Einrichtung
1. Installiere, falls noch nicht geschehen, Python in Version 3.13 (oder höher) und habe eine PostgreSQL-Datenbank zur Hand (z.B. aus dem docker mit exposed port). Außerdem wird unter Umständen [GNU gettext](https://www.gnu.org/software/gettext/) benötigt, wenn man Übersetzungen kompilieren will. Alternativ kann auch das [docker dev image](#docker-dev-image) verwendet werden.
- Linux: Pakete `python3`, `postgresql` und `gettext`
- Mac: `brew install python3 postgresql gettext` bzw. https://postgresapp.com/
- Windows: [latest stable Python 3 release](https://www.python.org/downloads/windows/) und [PostgreSQL Installer](https://www.postgresql.org/download/windows/) und [gettext binaries](https://mlocati.github.io/articles/gettext-iconv-windows.html)
- Python Paketmanager: `uv`:
Kann mit OS Installationsmitteln, mit `pip install uv` oder `pipx install uv` installiert werden. (Siehe die [Offizielle Dokumentation](https://docs.astral.sh/uv/getting-started/installation/))
1. Klone dieses Repository an beliebigen Ort.
1. Installiere die python dependencies mit `uv sync`
1. (falls nicht bereits vorhanden) lege einen PostgreSQL-User an (`createuser -P hub_app`) sowie eine Datenbank (`createdb -O hub_app hub`) - unter Linux ggf. via `sudo -u postgres`
1. Konfiguriere deine Instanz mittels:
- Umgebungsvariablen (z.B. direnv, oder env Datei)
- oder mittels einer `local_settings.py` in `src/hub/` an (Dokumentation zur Datenbankkonfiguration in der [Django-Dokumentation](https://docs.djangoproject.com/en/3.1/ref/settings/#databases)):
```python
DEBUG = True
ALLOWED_HOSTS = ['127.0.0.1', 'localhost']
SESSION_COOKIE_SECURE = False
SESSION_COOKIE_DOMAIN = None
IS_API = True
IS_FRONTEND = True
STORAGE_TYPE = 'local'
EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend' # "send" emails as console output
SELECTED_CONFERENCE_ID = '40ba6cda-1970-409f-81ef-efb87ef09d95' # change this to the id of your conference you want to display in frontend (matches the one from rc3_2021.json)
METRICS_SERVER_IPS = ['127.0.0.1'] # Change this if you want to test the Prometheus / Grafana metrics endpoint (http://127.0.0.1:8000/metrics/)
DATABASES = {
'default': {
'ENGINE': 'django.contrib.gis.db.backends.postgis',
'NAME': 'hub',
'USER': 'hub_app',
'PASSWORD': '<kennwort-aus-dem-createuser-aufruf>',
'HOST': 'localhost',
'PORT': '5432',
}
}
```
8. Lege die Datenbanktabellen an: `uv run task manage migrate`
9. Richte einen Admin-Nutzer (für die Anwendung) ein: `uv run task manage createsuperuser`
10. optional: Import von Demo-Daten: `uv run task.py loaddata .src/core/fixtures/rc3_2021.json`
11. optional: Für deinen Adminuser via [Admin-Seite](http://localhost:8000/c3admin/) einen `ConferenceMember` anlegen um den User für das Frontend freizuschalten
## Nutzung
2. Wende ggf. vorhandene DB-Migrations an (wenn du gerade aus dem Git geupdatet hast): `uv run task manage migrate`
3. Stelle sicher dass alle Translations aktuell sind: `uv run task manage compilemessages`
4. Lasse alle staticfiles einsammeln: `uv run task manage collectstatic --noinput`
5. Starte den Dev-Server: `uv run task manage runserver`
6. Besuche die lokale Instanz: [Admin-Seite](http://localhost:8000/c3admin/), [API](http://localhost:8000/api/) und [plainui-Frontend](http://localhost:8000/)
## PlainUI Development Tipps
### Ein Theme erstellen
Sämtliche Hub-Komponenten müssen eigene Variablen definieren. Alle Variablen sind in [`_variables-hub.scss`](./src/plainui/styles/_variables-hub.scss) enthalten.
Gegebenenfalls müssen neue Variablen hinzugefügt werden. Ein neues Theme kann dann Variablen aus Bootstrap oder dem Hub überschreiben.
Als Beispiel kann das [`hub-high-contrast.scss`](./src/plainui/styles/themes/hub-high-contrast.scss) genommen werden.
### CSS Kompilieren (PlainUi)
1. Gehe in das Verzeichnis `src/plainui/`
2. Führe `yarn` aus, um die node_modules zu generieren
3. Führe `yarn build` aus um das CSS zu kompilieren
4. Um das CSS beim Entwickeln automatisch neu zu kompilieren gibt es `yarn watch`
#### Kompiliertes CSS mit lokalem docker-compose Setup ausliefern
Um das kompilierte CSS über eine lokale Instanz auszuliefern die z.B. mit `docker compose up` ausgeliefert wurde muss dem `nginx` Container in der `docker-compose.yml` ein zusätzlicher Ordner gemounted werden:
```
volumes:
- ./src/plainui/static:/www/static
...
```
#### CSS Watch im Container
1. Um die Styles zu kompilieren und eine watch zu starten benutze `docker compose --profile build up -d local-static`
### Components
Wiederverwendbare Elemente können als Komponenten integriert werden. Dafür gibt es jeweils 2 "components"-Ordner. Die HTML-Komponenten befinden sich in `plainui/jinja2/plainui/components`. Sollten zusätzliche Styles benötigt werden, können diese in `plainui/styles/components` hinzugefügt werden, welche anschließend in `rc3.scss` integriert werden. Wichtig ist, ein **eigenes File pro Komponente** anzulegen. Für Jinja eignen sich dazu [Macros](https://jinja.palletsprojects.com/en/2.10.x/templates/#import) oder [Includes](https://jinja.palletsprojects.com/en/2.10.x/templates/#include). Zusätzlich ist die Komponente in der Übersicht hinzuzufügen - lokal erreichbar unter <http://localhost:8000/component_gallery>.
## Python Development Tipps
### Abhängigkeitsverwaltung
Zur Verwaltung der verwendeten python Abhängigkeiten wir der [Paketmanager UV](https://docs.astral.sh/uv/) verwendet.
Mittels diesem werden die `requirements.txt` und die `requirements.dev.txt` erzeugt.
#### Installation der aktuellen Abhängigkeiten
Um die aktuellen python Abhängigkeiten zu installieren kann das Kommando `uv sync` verwendet werden.
Mit dem Kommando `ur sync --frozen` kann sichergestellt werden, dass genau die Versionen aus dem uv lock file installiert werden.
_Achtung_: **Nicht in der Lock Datei enthaltene python Pakete werden deinstalliert!**
#### Hinzufügen von neuen Abhängigkeiten
Um neue Abhängigkeiten hinzuzufügen kann das Kommando `uv add` verwendet werden. Mit dem Parameter `--dev` kann eine Abhängigkeit als Entwicklungs-Abhängigkeit deklariert werden. Diese wird dann in den Produktivinstanzen nicht installiert.
Anschließend müssen die `requirements.txt` und `requirements.dev.txt` angepasst werden.
Wenn `pre-commit` verwendet wird, passiert dies automatisch beim commit.
Alternativ können die folgenden Kommandos verwendet werden
```bash
uv export --format requirements-txt --no-hashes -o requirements.txt --no-dev
uv export --format requirements-txt --no-hashes -o requirements.dev.txt --all-groups
```
### Debugging DJANGO
Context im HTML-File ausgeben:
```html
<pre>{% debug %}</pre>
```
oder:
```html
<pre>
{{ show_vars(myContextElement) }}
</pre
>
```
### Übersetzungen extrahieren & compilieren
- `uv run task manage makemessages`
- Die Übersetzungsdateien in `<app>/locale/<sprache>/LC_MESSAGES/django.po` wurden um alle neuen Übersetzungsstrings erweitert. Bearbeiten und jeweils bei `msgstr` die Übersetzungen einfügen!
- `uv run task manage compilemessages`
- Zum Ausprobieren müsst ihr django neu starten um die neuen Übersetzungsdateien zu laden
### Übersetzungen definineren
- in Python: `gettext` wie üblich in Django, siehe [Doku](https://docs.djangoproject.com/en/3.1/topics/i18n/translation/#internationalization-in-python-code)
- in jinja2-Templates via `_`, bspw. `{{ _("Settings") }}` oder mit Platzhalter `{{ _("Hello, %(username)s", username=user.display_name) }}`
### Static Files einsammeln lassen
- `uv run task manage collectstatic`
- ohne dies brechen u.a. Unittests mit Fehlern wie "Missing staticfiles manifest entry" ab
### Tests
Es gibt Django (Unit-)Tests für die einzelnen Apps. Diese finden sich jeweils im `tests` Ordner der App.
Außerdem gibt es im repository root unter [tests](tests) auch noch einfache Integrationstests.
#### Test mit Übersetzten Inhalten
Um sicherzustellen, dass Tests mit Übersetzungen in allen Umgebungen funktionieren,
müssen die Übersetzungsfunktionen gemocked werden.
Dazu gibt es in `core.tests.utils` eine `mocktrans` Funktion die alle Text einfach mich `_trans` ergänzt (z.B. wird aus "Login" dann "Login_trans").
Die Funktion kann dann wie folgt verwendet werden:
```python
with patch('core.models.ticket._', side_effect=mocktrans):
translation = funktions_aufruf()
self.assertEqual(translation, "NoTIcket_trans")
```
#### Django Tests ausführen
Um die Tests ausführen zu können muss der Datenbanknutzer das Recht haben neue Datenbaken anzulegen.
Dafür mit `psql postgres` die Datenbankkonsole starten. Dort `ALTER USER hub_app CREATEDB;` ausführen (ggf. `hub_app` durch den gewählten Nutzernamen ersetzen). Am Ende mit `Strg-D` Konsole wieder schließen.
Um die Django Tests auszuführen kann das Kommando `uv run tox -e django-test` verwendet werden. \
Um nur die Tests einer App auszuführen stattdessen `uv run tox -e django-test -- <app>.tests` ausführen. \
Hilfreiche Argumente sind `-v 2` um die ausgeführten Tests anzuzeigen, `--failfast` um nach dem ersten Fehler abzubrechen, und `--keepdb` um nicht jedes mal die Migrationen durchführen zu müssen. \
Für weitere Infos zu dem Befehl ist https://docs.djangoproject.com/en/3.1/ref/django-admin/#django-admin-test hilfreich.
Um eine Ausführungsgebung zu verwenden die ähnlicher zu der der CI ist, kann `DJANGO_SETTINGS_MODULE=hub.settings.ci ./manage.py test` verwendet werden.
#### Django Tests in Docker ausführen
Um alle Tests auszuführen kann das `test` profil verwendet werden.
Hierzu einfach `docker compose --profile test run hubtest` ausführen.
Die oben beschriebenen Funktionen können einfach hinten angehängt werden (z.B. `docker compose --profile test run hubtest -v 2 --failtest`).
## Linting and Formatting
### Pre-commit hooks
Um zu verhindern, dass falscher Code eingecheckt wird können pre-commit hooks mittels "pre-commit install" hinzugefügt werden.
Ab dann wird vor jedem commit ein Teil der checks (vor allem Format Tests) durchgeführt.
### ruff for python
Um das Format und die Korrektheit der python Dateien im Hub sicherzustellen setzen wir das tool `ruff` ein.
Dieses hat die folgenden Kommandos:
- `ruff check`: Diess Kommando checkt auf häufige Fehler in python code und hat auch teilweise Möglichkeiten diese zu beheben
- `ruff format`: Dieses Kommando re-formatiert alle python dateien nach einem voregebenen Code-Style
### djLint
**Leider ist es nicht möglich djLint so zu konfigurieren, dass es automatisch die richtigen Profile verwendet.**
**Wenn eine Integration in einen Editor gewünscht ist, muss dies berücksichtigt werden!**
Manuell kann es folgendermaßen ausgeführt werden:
- `djlint --profile django --extension html --reformat .` um alle .html Dateien zu formatieren
- `djlint --profile jinja --extension j2 --reformat .` um alle .j2 Dateien zu formatieren
- `djlint --lint .` um alle ein potenzielle Fehler per Linting zu finden
## Häufige Fehler
**Datenbank-Migration schlägt fehl mit "'DatabaseOperations' object has no attribute 'geo_db_type'"**
```
$ ./manage.py migrate
<snip>
AttributeError: 'DatabaseOperations' object has no attribute 'geo_db_type'
```
Dieser Fehler tritt auf, wenn man [PostGIS](https://postgis.net/)-Felder mit dem normalen Django-Postgres-Backend anlegen möchte. Statt dessen als Engine `django.contrib.gis.db.backends.postgis` verwenden.
**Docker-Build schlägt fehl mit "error creating zfs mount"**
Hierbei handelt es sich um ein Problem von Docker multi-stage Builds und dem ZFS-Storage Treiber.
Da das Problem nur auftritt wenn einzelne Image-Layer nicht im Cache sind lässt sich das Problem umgehen indem man den Build solange ausführt bis er erfolgreich ist.
Ab Version 22 von `docker-ce` sollte das Problem nicht mehr auftreten.
Siehe auch den [zughörigen Issue auf GitHub](https://github.com/moby/buildkit/issues/1758).
## Docker Image Abhängigkeiten
Das Bild zeigt die aktuellen Docker Image Abhängigkeiten aus dem Multistage Dockerfile
![Semantic description of image](/docs/Dockerfile.png "Docker dependencies")
### Recreate image
```bash
docker run \
--rm \
--user "$(id -u):$(id -g)" \
--workdir /workspace \
--volume "$(pwd)":/workspace \
ghcr.io/patrickhoefler/dockerfilegraph:alpine -o png
```
## Ignore Format Commits
Um den Reformat in lokalen `git blame` Kommandos zu ignorieren kann man die `.git-blame-ignore-revs` Datei verwenden.
Für dauerhafte Konfiguration bitte das folgende Kommando verwenden:
```bash
git config blame.ignoreRevsFile .git-blame-ignore-revs
```
FROM python:3.11-bookworm as base
ARG DEVELOPMENT=False
######################################### [build] #############################
FROM base as build
ENV LC_ALL=C.UTF-8
RUN apt-get update && \
apt-get install -y --no-install-recommends \
build-essential \
gdal-bin libproj-dev \
ARG REGISTRY=""
FROM ${REGISTRY}python:3.13-bookworm AS base
COPY --from=ghcr.io/astral-sh/uv:0.5.21 /uv /uvx /bin/
ENV DEBIAN_FRONTEND=noninteractive
# Set up uv environment
ENV UV_LINK_MODE=copy UV_COMPILE_BYTECODE=1 UV_TOOL_BIN_DIR=/opt/uv-bin/
RUN echo 'APT::Install-Recommends "false";' > /etc/apt/apt.conf.d/99-unattended-minimal && \
echo 'APT::Install-Suggests "false";' >> /etc/apt/apt.conf.d/99-unattended-minimal && \
echo 'APT::Get::Assume-Yes "true";' >> /etc/apt/apt.conf.d/99-unattended-minimal
RUN --mount=target=/var/lib/apt/lists/,type=cache,sharing=locked \
--mount=target=/var/cache/apt/archives/,type=cache,sharing=locked \
# Prevent apt cache cleaning
rm -f /etc/apt/apt.conf.d/docker-clean && \
apt-get update && \
apt-get install \
gdal-bin \
gettext \
locales \
yarnpkg && \
apt-get clean && \
rm -rf /var/lib/apt/lists/* && \
locales && \
dpkg-reconfigure locales && \
locale-gen C.UTF-8 && \
/usr/sbin/update-locale LANG=C.UTF-8 && \
mkdir /install
# Fix caching issue with kaniko see: https://github.com/GoogleContainerTools/kaniko/issues/3246
mkdir -p /app/plainui
# install packages (prepare everything into /install but copy it to use it in the build image anyway)
COPY src/requirements.txt /
ENV PATH=/install/usr/local/bin:$PATH
RUN pip3 install --root=/install -r /requirements.txt gunicorn httpie httpie-unixsocket "psycopg[binary]"
# Add path for future uv location
ENV PATH="/install/.venv/bin:/opt/uv-bin:$PATH"
######################################### [meta] #############################
FROM base AS meta
######################################### [build-dev] #########################
FROM build as build-dev
RUN uv tool install tox --with tox-uv
COPY src/requirements-dev.txt /
RUN pip3 install --root=/install -r /requirements-dev.txt
######################################### [build-static] ######################
######################################### [build] #############################
FROM build as build-static
FROM base AS build
# Only copy over the requirements files, use cache if they have not changed.
RUN mkdir -p /app/plainui/
COPY src/plainui/package.json src/plainui/yarn.lock /app/plainui/
ENV LC_ALL=C.UTF-8
WORKDIR /app/plainui
RUN /usr/bin/yarnpkg
RUN --mount=target=/var/lib/apt/lists/,type=cache,sharing=locked \
--mount=target=/var/cache/apt/archives/,type=cache,sharing=locked \
apt-get update && \
apt-get install \
build-essential && \
mkdir /install
COPY src/ /app/
WORKDIR /install
COPY pyproject.toml uv.lock README.md /install/
RUN --mount=type=cache,target=/root/.cache/uv \
uv sync --frozen --no-install-project --no-editable
RUN /usr/bin/yarnpkg build
WORKDIR /app
RUN cp -r /install/* / && \
export DJANGO_SETTINGS_MODULE='hub.settings.build' && \
python3 /app/manage.py collectstatic --noinput && \
python3 /app/manage.py compilemessages && \
unset DJANGO_SETTINGS_MODULE
######################################### [build-dev] #########################
FROM build AS build-dev
######################################### [nginx] #############################
WORKDIR /install
RUN --mount=type=cache,target=/root/.cache/uv \
uv sync --frozen --no-install-project --no-editable
FROM nginx:1.25-alpine-slim as nginx
ENV APP_SOCKET "/run/hub/app.sock"
ENV SCRIPT_NAME ""
######################################### [node-build] ########################
VOLUME /www/media
FROM ${REGISTRY}node:20-alpine AS node-base
COPY --from=build-static /app/static.dist /www/static
COPY deployment/docker/index.html deployment/docker/error_*.html /www/default/
COPY deployment/docker/nginx.conf /etc/nginx/templates/default.conf.template
RUN mkdir -p /app/plainui/
COPY src/plainui/package.json src/plainui/yarn.lock src/plainui/.yarnrc.yml /app/plainui/
COPY src/plainui/.yarn/releases/yarn-4.5.1.cjs /app/plainui/.yarn/releases/
WORKDIR /app/plainui
RUN corepack enable && \
/usr/local/bin/yarnpkg set version stable && \
/usr/local/bin/yarnpkg install
######################################### [webworker-base] ####################
FROM base as webworker-base
ARG DEVELOPMENT
FROM base AS webworker-base
ENV APP_HOME=${APP_HOME:-/app_home}
VOLUME /data /app/media
ENV PYTHONDONTWRITEBYTECODE 1
ENV PYTHONUNBUFFERED 1
ENV PYTHONDONTWRITEBYTECODE=1
ENV PYTHONUNBUFFERED=1
ENV LC_ALL=C.UTF-8
ENV DJANGO_SETTINGS_MODULE=hub.settings.default
ENV DOCKER_UID=1000
RUN apt-get update && \
apt-get install -y --no-install-recommends \
gdal-bin libproj-dev \
rsync && \
if [ "$DEVELOPMENT" = "True" ]; then\
apt-get install -y --no-install-recommends \
gettext \
yarnpkg; \
fi && \
apt-get clean && \
rm -rf /var/lib/apt/lists/* && \
useradd -u $DOCKER_UID -ms /bin/bash -d /app_home appuser
RUN useradd -u $DOCKER_UID -ms /bin/bash -d /app_home appuser
COPY deployment/docker/app.sh /usr/local/bin/app
COPY deployment/docker/check_django.sh /usr/local/bin/hub_healthcheck
COPY deployment/docker/check_psql.py /usr/local/bin/postgres_healthcheck
COPY --from=build /install /
ENV PATH="/install/.venv/bin:$PATH"
RUN install -d -m 0755 -o appuser -g appuser /app/hub /data /app/media /run/hub && \
install -d -m 0700 -o appuser -g appuser ${APP_HOME}/.ssh && \
......@@ -111,22 +99,57 @@ RUN install -d -m 0755 -o appuser -g appuser /app/hub /data /app/media /run/hub
ENTRYPOINT ["/usr/local/bin/app"]
CMD ["webworker"]
######################################### [node-build] ######################
FROM node-base AS node-build
WORKDIR /app/plainui
COPY src/plainui/styles/ /app/plainui/styles
RUN /usr/local/bin/yarnpkg build
ENTRYPOINT ["/usr/local/bin/yarnpkg"]
CMD ["watch"]
######################################### [build-static] ######################
FROM build AS build-static
COPY --from=node-build /app/plainui/static/plainui/*.css* /app/plainui/static/plainui/
COPY /src/ /app
WORKDIR /app
RUN export DJANGO_SETTINGS_MODULE='hub.settings.build' && \
python3 /app/manage.py collectstatic --noinput && \
python3 /app/manage.py compilemessages && \
unset DJANGO_SETTINGS_MODULE
######################################### [nginx] #############################
FROM ${REGISTRY}nginx:1-alpine-slim AS nginx
ENV APP_SOCKET="/run/hub/app.sock"
ENV SCRIPT_NAME=""
COPY deployment/docker/index.html deployment/docker/error_*.html /www/default/
COPY deployment/docker/nginx.conf /etc/nginx/templates/default.conf.template
COPY --from=build-static /app/static.dist /www/static
######################################### [webworker] #########################
FROM webworker-base as webworker
FROM webworker-base AS webworker
COPY --from=build /install/.venv /install/.venv
COPY --from=build-static --chown=appuser /app /app
USER appuser
######################################### [dev] ###############################
FROM webworker-base as dev
FROM webworker-base AS dev
ENV DJANGO_SETTINGS_MODULE=hub.settings.dev
ENV SERVE_API=yes
ENV SERVE_FRONTEND=yes
ENV SELECTED_CONFERENCE_ID=017c0749-a2ea-4f86-92cd-e60b4508dd98
ENV ALLOWED_HOSTS="localhost,127.0.0.1"
ENV DEV=1
......@@ -134,19 +157,15 @@ USER root
RUN install -o appuser -g appuser -m 774 /dev/null /data/django.log
# Copy additional dev dependencies
COPY --from=build-dev /install /
COPY --from=build-dev /install/.venv /install/.venv
# Copy plainui styles
COPY --from=node-build /app/plainui/static/*.css* /app/plainui/static/
ENV PATH="/install/.venv/bin:$PATH"
USER appuser
COPY --from=build-static --chown=appuser /app /app
WORKDIR /app
RUN export DJANGO_SETTINGS_MODULE='hub.settings.build' && \
app build && \
python3 /app/manage.py collectstatic --noinput && \
python3 /app/manage.py compilemessages && \
unset DJANGO_SETTINGS_MODULE
######################################### [webworker] #########################
# default docker build target
FROM webworker
ENV BIND_HTTP=1
EXPOSE 8000
# Hub/Gateway (und Plain UI Frontend)
## Plain UI
Der Hub besteht aus mehreren Komponenten welche für unterschiedliche Funktionen gedacht sind
Es handelt sich um eine Darstellung der Konferenz-Inhalte als simples Frontend ohne viel Schnick-Schnack.
* Prodinstanz: <https://events.ccc.de/congress/2023/hub/>
* Testinstanz: <https://staging.hub.c3events.de/>
- Backoffice: Erfassung und Verwaltung von Informationen inkl. Bearbeitung von Reports
- PlainUI: Es handelt sich um eine Darstellung der Konferenz-Inhalte als simples Frontend ohne viel Schnick-Schnack.
- Produktiv-Instanz: <https://events.ccc.de/congress/2024/hub/>
- Test-Instanz: <https://plainui.staging.hub.c3events.de/>
- Core: Beinhaltet die Datenmodelle und Funktionen, die sowohl im Backoffice als auch in der PlainUI verwendet werden.
- Metanav/Navbar (not published yet): Bietet eine von allen Seiten gemeinsam einbindbare Navigationsleiste im jeweiligen Congress-Design.
## Datenmodell
......@@ -12,19 +15,42 @@ Es handelt sich um eine Darstellung der Konferenz-Inhalte als simples Frontend o
als PDF: [Grobes Datenmodell](docs/Grobes Datenmodell.pdf) und [automatisch exportiertes ER-Diagramm](docs/Datenmodell_autoexport.pdf) (kann Spuren von Unübersichtlichkeit enthalten)
### PlainUi Structure
- jinja2/plainui
- components
- tbd.
- styles
- components: components styles, die in `hub.scss` eingebunden werden
- utils: settings, die selbst keinen output generieren (z.B. Variablen, Mixins), damit sie in unterschiedlichen files verwendet werden können
- `hub.scss`: Hauptdatei, welche anschließend in CSS konvertiert wird
- static/plainui
- img: statische Bilder
- fonts: importierte Schriften
- das generierte CSS
## REST API
Am Beispiel der Konferenz-Slug "camp23", grundsätzlich sind alle hier aufgeführten Endpoints per GET abrufbar (Restriktionen bei nicht-öffentlichen Events, etc. sind möglich).
Grundsätzlich sind alle hier aufgeführten Endpoints per GET abrufbar (Restriktionen bei nicht-öffentlichen Events, etc. sind möglich).
Manche Endpunkte sind zusätzlich "schreibbar" und können zur Anlage bzw. Bearbeitung der jeweiligen Daten genutzt werden.
Testinstanz: <https://hub.test.c3voc.de/api/> / <https://staging.hub.c3events.de/api/> \
Prodinstanz: <https://api.events.ccc.de/congress/2023/>
Prodinstanz: <https://api.events.ccc.de/congress/2024/>
| Kategorie | Endpunkt | GET | POST | PUT | DEL | Beschreibung |
| ---------- | ---------------------------------------- | --- | ---- | --- | --- | ------------------------------------------- |
| ---------- | ---------------------------------------- | --- | ---- | --- | --- | ----------------------------------------------------- |
| Auth | `/auth/get-token` | | x | | | Ausstellen eines API-Tokens |
| Persönlich | `/me` | x | | x | | eigenes Profil / Settings |
| Persönlich | `/me/friends` | x | | x | x | Liste der Buddies |
| Persönlich | `/me/badges` | x | | | | Liste aller Badges/Achievements |
| Persönlich | `/me/events` | x | | | | Favorisierte Events |
| Persönlich | `/me/events/<uuid>/` | | | x | x | Events (ent-)favorisieren |
| Persönlich | `/me/friends` | x | | x | x | Liste der Buddies |
| Persönlich | `/me/received-messages/` | x | | | | Übersicht empfangener PN |
| Persönlich | `/me/received-messages/<uuid>` | x | | | | Details einer empfangenen PN |
| Persönlich | `/me/send-message` | | x | | | Send a new PN |
| Persönlich | `/me/sent-messages/` | x | | | | Übersicht gesendeter PN |
| Persönlich | `/me/sent-messages/<uuid>` | x | | | | Details einer gesendeten PN |
| Persönlich | `/me/delete-message/<uuid>` | x | | | | PN löschen |
| Konferenz | `/` | x | | | | Metadaten des Konferenz |
| Konferenz | `/tags` | x | | | | Liste aller Tags auf der Konferenz |
| Konferenz | `/tracks` | x | x | | | Liste der Tracks |
......@@ -47,228 +73,20 @@ Prodinstanz: <https://api.events.ccc.de/congress/2023/>
Per POST werden neue Einträge angelegt, per PUT bestehende verändert.
Details zu den einzelnen Endpunkten folgen in Kürze™.
### API-Beispiel mit cURL
## Navbar
Bietet eine von allen Seiten gemeinsam einbindbare Navigationsleiste im jeweiligen Congress-Design.
(not implemented yet)
# Lokale Entwicklung
Zuerst einen Token generieren:
Dieses Projekt basiert auf Python 3.11+ und Django 4.2+.
## Initiale Einrichtung
### Lokales Docker development image
Das Docker development image vereinfacht die initiale Einrichtung und sperrt alle Abhängigkeiten und Prozesse in einen Entwicklungscontainer. Alternativ ist auch eine [manuelle Einrichtung](#lokale-einrichtung) möglich.
1. [Docker](https://docs.docker.com/get-docker/) und [Docker Compose](https://docs.docker.com/compose/install/) installieren. Optional kann auch die [devcontainer cli](https://containers.dev/supporting#devcontainer-cli) verwendet werden.
Unter Windows getestet mit WSL 2.
2. Klonen dieses Repositories an beliebigen Ort.
3. Image erzeugen: `docker compose build` oder `devcontainer build`.
- Für schnellere Builds kann [buildkit](https://docs.docker.com/build/buildkit/) verwendet werden:
```bash
docker buildx bake
```
- Die Standardpasswöter für PostgreSQL und Hub Benutzer sind in der `docker-compose.yml` Datei festgelegt und können per Umgebungsvariable angepasst werden.
4. Container erzeugen: `docker compose up -d hub` oder `devcontainer up`.
- Beim Start mittels `docker compose` wird kein HUB Admin Benutzer angelegt um ein ungewolltes anlegen von diesen Benutzern in der Produktivumgebung vorzubeugen.
Falls der `admin` Benutzer angelegt werden soll muss die Umgebungsvariable `DJANGO_CREATE_ADMIN_PASSWORD` für den Container gesetzt werden.
- Bei Verwendung von devcontainers wird der `admin` Benutzer automatisch mit dem Password `hubhubhub` angelegt.
5. Optional: Import von Demo-Daten: `docker compose exec -it hub python manage.py loaddata ./core/fixtures/rc3_2021.json`
#### Docker Einstellungen in der Entwicklungsumgebung
Um die Einstellungen der Instanz anzupassen kann eine `dev.env` Datei im Root-Verzeichnis angelegt werden.
Diese kann duch das anlegen einer localen compose Datei mit dem folgenden Inhalt geladen werden:
```yaml
version: "3.8"
services:
hub:
env_file:
- dev.env
```
Diese kann durch das setzen der Umgebungsvariable `COMPOSE_FILE=docker-compose.yml:docker-compose.local.yml` automatisch beim allen `docker compose` Kommandos berücksichtigt werden.
Um eine andere Demo Datei zu laden kann die Umgebungsvariable `DJANGO_LOAD_FIXTURE` gesetzt werden (Aufgrund von Compose Prioritäten ist es nicht möglich das über die dev.env Datei zu setzen).
### Lokale Einrichtung
1. Installiere, falls noch nicht geschehen, Python in Version 3.11 (oder höher) und habe eine PostgreSQL-Datenbank zur Hand (geht potenziell auch mit sqlite aber das ist nicht getestet). Außerdem wird unter Umständen [GNU gettext](https://www.gnu.org/software/gettext/) benötigt, wenn man Übersetzungen kompilieren will. Alternativ kann auch das [docker dev image](#docker-dev-image) verwendet werden.
- Linux: Pakete `python3`, `postgresql` und `gettext`
- Mac: `brew install python3 postgresql gettext` bzw. https://postgresapp.com/
- Windows: [latest stable Python 3 release](https://www.python.org/downloads/windows/) und [PostgreSQL Installer](https://www.postgresql.org/download/windows/) und [gettext binaries](https://mlocati.github.io/articles/gettext-iconv-windows.html)
2. Klone dieses Repository an beliebigen Ort.
3. Gehe via Terminal/Konsole in das Unterverzeichnis `src`.
4. Falls du kein [direnv](https://direnv.net/) benutzt:
1. Richte ein venv ein: `python3 -m venv venv`
1. Aktiviere das venv: `. venv/bin/activate`
5. Installiere die benötigten Pakete: `python3 -m pip install -r requirements.txt "psycopg[binary]"`
6. (falls nicht bereits vorhanden) lege einen PostgreSQL-User an (`createuser -P hub_app`) sowie eine Datenbank (`createdb -O hub_app hub`) - unter Linux ggf. via `sudo -u postgres`
7. Lege eine Datei `local_settings.py` in `src/hub/` an (Dokumentation zur Datenbankkonfiguration in der [Django-Dokumentation](https://docs.djangoproject.com/en/3.1/ref/settings/#databases)):
```python
DEBUG = True
ALLOWED_HOSTS = ['127.0.0.1', 'localhost']
SESSION_COOKIE_SECURE = False
SESSION_COOKIE_DOMAIN = None
IS_API = True
IS_FRONTEND = True
EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend' # "send" emails as console output
SELECTED_CONFERENCE_ID = '40ba6cda-1970-409f-81ef-efb87ef09d95' # change this to the id of your conference you want to display in frontend (matches the one from rc3_2020.json)
METRICS_SERVER_IPS = ['127.0.0.1'] # Change this if you want to test the Prometheus / Grafana metrics endpoint (http://127.0.0.1:8000/metrics/)
DATABASES = {
'default': {
'ENGINE': 'django.contrib.gis.db.backends.postgis',
'NAME': 'hub',
'USER': 'hub_app',
'PASSWORD': '<kennwort-aus-dem-createuser-aufruf>',
'HOST': 'localhost',
'PORT': '5432',
}
}
```
8. Lege die Datenbanktabellen an: `./manage.py migrate`
9. Richte einen Admin-Nutzer (für die Anwendung) ein: `./manage.py createsuperuser`
10. optional: Import von Demo-Daten: `./manage.py loaddata ./core/fixtures/rc3_2021.json`
11. optional: Für deinen Adminuser via [Admin-Seite](http://localhost:8000/c3admin/) einen `ConferenceMember` anlegen um den User für das Frontend freizuschalten
## Nutzung
1. Gehe in das `src` Verzeichnis, nicht-direnv-Nutzer müssen das venv manuell aktivieren (siehe oben)
2. Wende ggf. vorhandene DB-Migrations an (wenn du gerade aus dem Git geupdatet hast): `./manage.py migrate`
3. Stelle sicher dass alle Translations aktuell sind: `./manage.py compilemessages`
4. Lasse alle staticfiles einsammeln: `./manage.py collectstatic`
5. Starte den Dev-Server: `./manage.py runserver`
6. Besuche die lokale Instanz: [Admin-Seite](http://localhost:8000/c3admin/), [API](http://localhost:8000/api/) und [plainui-Frontend](http://localhost:8000/)
## PlainUi Structure
- jinja2/plainui
- components
- tbd.
- styles
- components: components styles, die in `hub.scss` eingebunden werden
- utils: settings, die selbst keinen output generieren (z.B. Variablen, Mixins), damit sie in unterschiedlichen files verwendet werden können
- `hub.scss`: Hauptdatei, welche anschließend in CSS konvertiert wird
- static/plainui
- img: statische Bilder
- fonts: importierte Schriften
- das generierte CSS
## CSS Kompilieren (PlainUi)
1. Gehe in das Verzeichnis `src/plainui/`
2. Führe `yarn` aus, um die node_modules zu generieren
3. Führe `yarn build` aus um das CSS zu kompilieren
4. Um das CSS beim Entwickeln automatisch neu zu kompilieren gibt es `yarn watch`
## Components
Wiederverwendbare Elemente können als Komponenten integriert werden. Dafür gibt es jeweils 2 "components"-Ordner. Die HTML-Komponenten befinden sich in `plainui/jinja2/plainui/components`. Sollten zusätzliche Styles benötigt werden, können diese in `plainui/styles/components` hinzugefügt werden, welche anschließend in `rc3.scss` integriert werden. Wichtig ist, ein **eigenes File pro Komponente** anzulegen. Für Jinja eignen sich dazu [Macros](https://jinja.palletsprojects.com/en/2.10.x/templates/#import) oder [Includes](https://jinja.palletsprojects.com/en/2.10.x/templates/#include). Zusätzlich ist die Komponente in der Übersicht hinzuzufügen - lokal erreichbar unter <http://localhost:8000/component_gallery>.
## Debugging DJANGO
Context im HTML-File ausgeben:
```html
<pre>{% debug %}</pre>
```
oder:
```html
<pre>
{{ show_vars(myContextElement) }}
</pre
>
```
## Übersetzungen extrahieren & compilieren
- `./manage.py makemessages`
- Die Übersetzungsdateien in `<app>/locale/<sprache>/LC_MESSAGES/django.po` wurden um alle neuen Übersetzungsstrings erweitert. Bearbeiten und jeweils bei `msgstr` die Übersetzungen einfügen!
- `./manage.py compilemessages`
- Zum Ausprobieren müsst ihr django neu starten um die neuen Übersetzungsdateien zu laden
## Übersetzungen definineren
- in Python: `gettext` wie üblich in Django, siehe [Doku](https://docs.djangoproject.com/en/3.1/topics/i18n/translation/#internationalization-in-python-code)
- in jinja2-Templates via `_`, bspw. `{{ _("Settings") }}` oder mit Platzhalter `{{ _("Hello, %(username)s", username=user.display_name) }}`
## Static Files einsammeln lassen
- `./manage.py collectstatic`
- ohne dies brechen u.a. Unittests mit Fehlern wie "Missing staticfiles manifest entry" ab
## Tests
Es gibt Django (Unit-)Tests für die einzelnen Apps. Diese finden sich jeweils im `tests` Ordner der App.
Außerdem gibt es im repository root unter [tests](tests) auch noch einfache Integrationstests.
### Django Tests ausführen
Um die Tests ausführen zu können muss der Datenbanknutzer das Recht haben neue Datenbaken anzulegen.
Dafür mit `psql postgres` die Datenbankkonsole starten. Dort `ALTER USER hub_app CREATEDB;` ausführen (ggf. `hub_app` durch den gewählten Nutzernamen ersetzen). Am Ende mit `Strg-D` Konsole wieder schließen.
Manche Tests benötigen, die kompilierten Übersetzungen. Deshalb ist es sinvoll vor der Testausführung `./manage.py compilemessages` auszuführen.
Um alle Tests auszuführen in das `src` Verzeichnis wechseln und `./manage.py test` ausführen. \
Um nur die Tests einer App auszführen stattdessen `./manage.py test <app>.tests` ausführen. \
Hilfreiche Argumente sind `-v 2` um die ausgeführten Tests anzuzeigen und `--failfast` um nach dem ersten Fehler abzubrechen. \
Für weitere Infos zu dem Befehl ist https://docs.djangoproject.com/en/3.1/ref/django-admin/#django-admin-test hilfreich.
Um eine Ausführungsgebung zu verwenden die ähnlicher zu der der CI ist, kann `DJANGO_SETTINGS_MODULE=hub.settings.ci ./manage.py test` verwendet werden.
### Django Tests in Docker ausführen
Um alle Tests auszuführen kann das `test` profil verwendet werden.
Hierzu einfach `docker compose --profile test run hubtest` ausführen.
Die oben beschriebenen Funktionen können einfach hinten angehängt werden (z.B. `docker compose --profile test run hubtest -v 2 --failtest`).
### Pre-commit hooks
Um zu verhindern, dass Code eingecheckt wird können pre-commit hooks mittels "pre-commit install" hinzugefügt werden.
Ab dann wird vor jedem commit ein Teil der checks (vor allem Format Tests) durchgeführt.
## Debug Zugriff
Um auf einen Docker Container mit dem root bentuzer zuzugreifen kann das folgende Kommando verwendet werden: `docker compose exec -u root hub /bin/bash`
## Häufige Fehler
curl https://{API_URL}/api/auth/get-token -H "Content-Type: application/json" -X POST --data '{"username": "{USERNAME}", "password": "{PASSWORD}"}'
```
$ ./manage.py migrate
<snip>
AttributeError: 'DatabaseOperations' object has no attribute 'geo_db_type'
```
Dieser Fehler tritt auf, wenn man [PostGIS](https://postgis.net/)-Felder mit dem normalen Django-Postgres-Backend anlegen möchte. Statt dessen als Engine `django.contrib.gis.db.backends.postgis` verwenden.
## Docker Image Abhängigkeiten
Das Bild zeigt die aktuellen Docker Image Abhängigkeiten aus dem Multistage Dockerfile
![Semantic description of image](/docs/Dockerfile.png "Docker dependencies")
### Recreate image
Mit diesem Token können dann Endpunkte aufgerufen werden die eine Authentifizierung erfordern:
```bash
docker run \
--rm \
--user "$(id -u):$(id -g)" \
--workdir /workspace \
--volume "$(pwd)":/workspace \
ghcr.io/patrickhoefler/dockerfilegraph:alpine -o png
curl https://{API_URL}/api/me -H "Content-Type: application/json" -H "Authorization: Token {API_TOKEN}"
```
## Ignore Format Commits
Um den Reformat in lokalen `git blame` Kommandos zu ignorieren kann man die `.git-blame-ignore-revs` Datei verwenden.
Für dauerhafte Konfiguration bitte das folgende Kommando verwenden:
```bash
git config blame.ignoreRevsFile .git-blame-ignore-revs
```
## Development
see [Development.md](./Development.md)