Compare commits

..

135 Commits

Author SHA1 Message Date
mpeltriaux f134948685 Merge branch 'master' into Docker 2026-03-01 14:31:45 +01:00
mpeltriaux 1e525b90a9 # Dockerfile upgrade
* upgrade baseimage to python 3.13
2026-03-01 14:04:58 +01:00
mpeltriaux 63a516e7d6 Merge branch 'master' into Docker
# Conflicts:
#	requirements.txt
2026-03-01 14:04:21 +01:00
mpeltriaux 2399ca9bf9 Merge pull request 'master' (#530) from master into Docker
Reviewed-on: #530
2026-01-30 08:44:00 +00:00
mpeltriaux c48ccd5334 Merge pull request 'master' (#528) from master into Docker
Reviewed-on: #528
2026-01-21 14:53:47 +00:00
mpeltriaux e2f8fc9c6d # Fix docker warnings
* fixes docker warnings about use of deprecated syntax
2026-01-21 15:52:07 +01:00
mpeltriaux fac658e52c Merge pull request 'master' (#524) from master into Docker
Reviewed-on: #524
2026-01-14 08:08:36 +00:00
mpeltriaux d6a65dd59a Merge pull request 'master' (#521) from master into Docker
Reviewed-on: #521
2026-01-13 09:37:16 +00:00
mpeltriaux cbc8acf6f6 Merge pull request 'master' (#519) from master into Docker
Reviewed-on: #519
2026-01-10 10:04:14 +00:00
mpeltriaux 31de477f26 Merge pull request 'master' (#516) from master into Docker
Reviewed-on: #516
2025-12-19 14:18:12 +01:00
mpeltriaux 19b6e633df Merge pull request 'master' (#514) from master into Docker
Reviewed-on: #514
2025-12-17 14:04:03 +01:00
mpeltriaux b98f821c98 Merge pull request 'master' (#511) from master into Docker
Reviewed-on: #511
2025-12-03 13:50:13 +01:00
mpeltriaux 5421de4e80 Merge pull request 'master' (#509) from master into Docker
Reviewed-on: #509
2025-11-30 12:33:58 +01:00
mpeltriaux a7a0044fc5 Merge pull request 'master' (#506) from master into Docker
Reviewed-on: #506
2025-11-28 11:45:48 +01:00
mpeltriaux 36552b3886 Merge pull request 'master' (#502) from master into Docker
Reviewed-on: #502
2025-11-19 13:16:48 +01:00
mpeltriaux a766c4dbe8 Merge pull request 'master' (#499) from master into Docker
Reviewed-on: #499
2025-11-07 14:12:18 +01:00
mpeltriaux 8126781b77 Merge pull request 'master' (#496) from master into Docker
Reviewed-on: #496
2025-10-23 16:13:04 +02:00
mpeltriaux a6a66d7499 Merge pull request 'master' (#493) from master into Docker
Reviewed-on: #493
2025-10-21 15:59:53 +02:00
mpeltriaux 1c0b67693d Merge pull request 'master' (#489) from master into Docker
Reviewed-on: #489
2025-10-15 09:51:46 +02:00
mpeltriaux ce6bb6b23b Merge pull request 'master' (#486) from master into Docker
Reviewed-on: #486
2025-10-12 11:32:27 +02:00
mpeltriaux 0b8176db2e Merge pull request 'master' (#484) from master into Docker
Reviewed-on: #484
2025-09-22 12:37:34 +02:00
mpeltriaux 3a299a040a Merge pull request 'master' (#482) from master into Docker
Reviewed-on: #482
2025-08-18 08:47:01 +02:00
mpeltriaux 3c5206139b Merge pull request 'master' (#477) from master into Docker
Reviewed-on: #477
2025-05-12 15:40:21 +02:00
mpeltriaux 6c53f39a28 Merge pull request 'master' (#474) from master into Docker
Reviewed-on: #474
2025-03-28 16:41:31 +01:00
mpeltriaux 64d8f47174 Merge pull request 'Docker_enhanced' (#472) from Docker_enhanced into Docker
Reviewed-on: #472
2025-03-28 16:11:18 +01:00
mpeltriaux f5f3246e89 # Docker enhancements
* optimizes nginx.conf
   * better logging of proxied requests
2025-03-24 14:17:08 +01:00
mpeltriaux ad8961ab82 # Docker enhancements
* optimizes nginx.conf
   * better proxy pipelining
* optimizes Dockerfile
   * smaller resulting image
   * faster rebuilding due to reusing of existing layers
* optimizes docker-entrypoint.sh
   * better startup performance
   * better compatibility with docker engine
2025-03-24 13:52:31 +01:00
mpeltriaux c2c8630c82 Merge pull request 'master' (#471) from master into Docker
Reviewed-on: #471
2025-02-14 15:33:19 +01:00
mpeltriaux dce9e1fc71 # Enhancements
* increases nginx max POST body size to 25MB (document upload)
* limits package requests on version 2.32 due to dependency of kombu to this version
2025-01-24 16:21:55 +01:00
mpeltriaux 2b84bab1d0 Merge pull request 'master' (#469) from master into Docker
Reviewed-on: #469
2025-01-24 16:12:33 +01:00
mpeltriaux 303583daa1 Merge pull request 'master' (#466) from master into Docker
Reviewed-on: #466
2025-01-21 13:44:14 +01:00
mpeltriaux d07b2ffbfb Merge pull request 'master' (#463) from master into Docker
Reviewed-on: #463
2025-01-08 16:05:15 +01:00
mpeltriaux 335800c44b Merge pull request 'master' (#459) from master into Docker
Reviewed-on: #459
2024-12-23 13:42:36 +01:00
mpeltriaux 5766cfde47 Merge pull request 'master' (#454) from master into Docker
Reviewed-on: #454
2024-12-23 12:09:47 +01:00
mpeltriaux 2ed3fcc0f9 Merge pull request 'master' (#449) from master into Docker
Reviewed-on: #449
2024-11-13 16:09:48 +01:00
mpeltriaux bf72295615 Merge pull request 'master' (#447) from master into Docker
Reviewed-on: #447
2024-10-26 10:25:06 +02:00
mpeltriaux 6b860f8ea5 Merge pull request 'master' (#445) from master into Docker
Reviewed-on: #445
2024-10-26 09:48:50 +02:00
mpeltriaux 2fa2fa547b Merge pull request 'master' (#443) from master into Docker
Reviewed-on: #443
2024-10-25 19:27:23 +02:00
mpeltriaux 3de956872c Merge pull request 'master' (#441) from master into Docker
Reviewed-on: #441
2024-10-25 14:24:55 +02:00
mpeltriaux 1c8e3992d6 Merge pull request 'master' (#438) from master into Docker
Reviewed-on: #438
2024-08-26 18:57:35 +02:00
mpeltriaux e6e9e141c8 Merge pull request 'master' (#436) from master into Docker
Reviewed-on: #436
2024-08-19 18:35:17 +02:00
mpeltriaux f8ece06ee8 Merge pull request 'master' (#431) from master into Docker
Reviewed-on: #431
2024-08-07 12:07:22 +02:00
mpeltriaux 149a351bfd Merge pull request 'master' (#429) from master into Docker
Reviewed-on: #429
2024-08-07 12:02:21 +02:00
mpeltriaux 0164717b8e Merge pull request 'master' (#426) from master into Docker
Reviewed-on: #426
2024-08-06 14:28:41 +02:00
mpeltriaux 104952bfc3 Merge pull request 'master' (#423) from master into Docker
Reviewed-on: #423
2024-07-10 09:30:30 +02:00
mpeltriaux f96241c8d1 Merge pull request 'master' (#421) from master into Docker
Reviewed-on: #421
2024-07-10 09:27:09 +02:00
mpeltriaux ac6b534f58 Merge pull request 'master' (#418) from master into Docker
Reviewed-on: #418
2024-07-08 18:44:22 +02:00
mpeltriaux 06910cd69a # Image tag
* increases image tag
2024-07-05 10:56:10 +02:00
mpeltriaux a48ba520fc Merge branch 'refs/heads/master' into Docker
# Conflicts:
#	konova/celery.py
2024-07-05 10:52:13 +02:00
mpeltriaux 9f18aa5890 Merge pull request 'master' (#414) from master into Docker
Reviewed-on: #414
2024-07-04 11:42:20 +02:00
mpeltriaux ab3bd84f3b # Docker enhancement
* adds logging for gunicorn by default
* adds image tagging
* drops docker-compose environment setting in favor of .env usage (needs to be copied from .env.sample)
2024-07-04 09:37:13 +02:00
mpeltriaux f829cd5a4c Merge branch 'refs/heads/master' into Docker
# Conflicts:
#	konova/sub_settings/django_settings.py
#	konova/sub_settings/sso_settings.py
#	requirements.txt
2024-07-04 09:30:41 +02:00
mpeltriaux 0f2bf95b71 Merge pull request 'master' (#409) from master into Docker
Reviewed-on: #409
2024-06-18 11:50:43 +02:00
mpeltriaux 6a307016ec Merge pull request 'master' (#403) from master into Docker
Reviewed-on: #403
2024-05-17 10:59:17 +02:00
mpeltriaux 51017ef8fa Merge pull request 'master' (#401) from master into Docker
Reviewed-on: #401
2024-05-17 07:54:16 +02:00
mpeltriaux 05560534bc Merge pull request 'master' (#399) from master into Docker
Reviewed-on: #399
2024-05-16 17:37:56 +02:00
mpeltriaux c882173e78 Merge branch 'refs/heads/master' into Docker
# Conflicts:
#	konova/sub_settings/sso_settings.py
#	requirements.txt
2024-05-16 15:22:57 +02:00
mpeltriaux 1d94211428 # Requirements update
* fixes requirements.txt due to django-simple-sso dependency
2024-04-12 08:51:18 +02:00
mpeltriaux 37357080d8 # Gunicorn update
* updates gunicorn package
2024-04-12 08:08:27 +02:00
mpeltriaux 5afa13ac92 Merge branch 'refs/heads/master' into Docker
# Conflicts:
#	requirements.txt
2024-04-12 08:07:05 +02:00
mpeltriaux 416cad1c8f Merge pull request 'master' (#392) from master into Docker
Reviewed-on: SGD-Nord/konova#392
2024-04-02 08:11:08 +02:00
mpeltriaux b5f83b7163 Merge pull request '# Requirements' (#390) from master into Docker
Reviewed-on: SGD-Nord/konova#390
2024-03-11 08:22:35 +01:00
mpeltriaux 20cfb5f345 Merge pull request 'master' (#389) from master into Docker
Reviewed-on: SGD-Nord/konova#389
2024-02-29 18:39:41 +01:00
mpeltriaux 88c96b95f2 Merge pull request '# HOTFIX' (#388) from master into Docker
Reviewed-on: SGD-Nord/konova#388
2024-02-21 18:32:16 +01:00
mpeltriaux f6c500b02a Merge pull request 'master' (#387) from master into Docker
Reviewed-on: SGD-Nord/konova#387
2024-02-16 10:16:43 +01:00
mpeltriaux d702cd8716 Merge pull request 'master' (#385) from master into Docker
Reviewed-on: SGD-Nord/konova#385
2024-02-16 08:45:32 +01:00
mpeltriaux 329cdd4838 Merge pull request 'Docker_django5' (#380) from Docker_django5 into Docker
Reviewed-on: SGD-Nord/konova#380
2024-01-05 17:39:48 +01:00
mpeltriaux 1b70024a29 # Python bullseye
* adds -bullseye to base docker package to ensure backwards compatibility
2024-01-05 17:38:58 +01:00
mpeltriaux 58206853ee Django5
* changes python dependency
2024-01-05 10:05:27 +01:00
mpeltriaux 6356398c40 Merge pull request 'master' (#379) from master into Docker_django5
Reviewed-on: SGD-Nord/konova#379
2024-01-05 09:47:53 +01:00
mpeltriaux 8519922d78 Merge pull request 'Netgis map client fix' (#376) from master into Docker
Reviewed-on: SGD-Nord/konova#376
2023-12-28 15:13:11 +01:00
mpeltriaux 5ac0654fd4 Merge pull request 'master' (#375) from master into Docker
Reviewed-on: SGD-Nord/konova#375
2023-12-13 13:38:00 +01:00
mpeltriaux 6c07a81b4f Merge pull request 'master' (#372) from master into Docker
Reviewed-on: SGD-Nord/konova#372
2023-12-12 07:35:17 +01:00
mpeltriaux ba45b4f961 Merge pull request 'HOTFIX netgis client' (#367) from master into Docker
Reviewed-on: SGD-Nord/konova#367
2023-12-07 06:44:47 +01:00
mpeltriaux 280de82a52 Merge pull request 'Hotfix map client edit errors' (#366) from master into Docker
Reviewed-on: SGD-Nord/konova#366
2023-12-05 07:29:41 +01:00
mpeltriaux 6022e2d879 Merge pull request '# Hotfix netgis client' (#365) from master into Docker
Reviewed-on: SGD-Nord/konova#365
2023-12-05 07:06:19 +01:00
mpeltriaux 1996efcc0d Docker-compose fix
* drops local volume usage in favor of copied code into container
2023-11-30 12:44:50 +01:00
mpeltriaux 80569119cb Merge branch 'master' into Docker
# Conflicts:
#	requirements.txt
2023-11-30 12:43:44 +01:00
mpeltriaux 98e71d4e8a Merge pull request 'HOTFIX' (#355) from master into Docker
Reviewed-on: SGD-Nord/konova#355
2023-11-07 16:27:11 +01:00
mpeltriaux fec7191ac2 Merge pull request 'HOTFIX' (#354) from master into Docker
Reviewed-on: SGD-Nord/konova#354
2023-10-26 07:27:19 +02:00
mpeltriaux 9b1085f206 Merge pull request 'HOTFIX' (#353) from master into Docker
Reviewed-on: SGD-Nord/konova#353
2023-10-26 07:23:21 +02:00
mpeltriaux b35d175a5c Merge pull request 'master' (#351) from master into Docker
Reviewed-on: SGD-Nord/konova#351
2023-10-25 10:10:14 +02:00
mpeltriaux 7f5fb022ac Merge pull request 'master' (#348) from master into Docker
Reviewed-on: SGD-Nord/konova#348
2023-09-15 13:21:38 +02:00
mpeltriaux 2d3314ab18 Merge pull request 'master' (#344) from master into Docker
Reviewed-on: SGD-Nord/konova#344
2023-08-25 15:06:32 +02:00
mpeltriaux 8b489f013d Merge pull request 'master' (#341) from master into Docker
Reviewed-on: SGD-Nord/konova#341
2023-08-09 07:30:18 +02:00
mpeltriaux 16ce5506d8 Merge pull request 'master' (#336) from master into Docker
Reviewed-on: SGD-Nord/konova#336
2023-05-17 14:40:17 +02:00
mpeltriaux e440bf8372 Merge pull request 'master' (#333) from master into Docker
Reviewed-on: SGD-Nord/konova#333
2023-05-16 14:11:20 +02:00
mpeltriaux 607db267e6 Merge pull request 'master' (#330) from master into Docker
Reviewed-on: SGD-Nord/konova#330
2023-04-26 11:30:22 +02:00
mpeltriaux 352ca64e09 Merge pull request 'master' (#327) from master into Docker
Reviewed-on: SGD-Nord/konova#327
2023-04-19 15:25:05 +02:00
mpeltriaux f2b735da6e Merge pull request 'master' (#324) from master into Docker
Reviewed-on: SGD-Nord/konova#324
2023-03-30 15:12:47 +02:00
mpeltriaux 6f7cfb713e Merge pull request 'master' (#321) from master into Docker
Reviewed-on: SGD-Nord/konova#321
2023-03-28 13:53:14 +02:00
mpeltriaux 103b703ee9 Merge pull request 'master' (#318) from master into Docker
Reviewed-on: SGD-Nord/konova#318
2023-03-24 07:14:34 +01:00
mpeltriaux daf8b1dce6 Merge pull request 'master' (#316) from master into Docker
Reviewed-on: SGD-Nord/konova#316
2023-03-22 09:00:33 +01:00
mpeltriaux c088affd74 Merge pull request 'master' (#313) from master into Docker
Reviewed-on: SGD-Nord/konova#313
2023-03-16 08:14:37 +01:00
mpeltriaux ecc727c991 Merge pull request 'master' (#311) from master into Docker
Reviewed-on: SGD-Nord/konova#311
2023-03-13 07:00:49 +01:00
mpeltriaux 632569fa5d Merge pull request 'master' (#307) from master into Docker
Reviewed-on: SGD-Nord/konova#307
2023-02-23 15:35:07 +01:00
mpeltriaux 6c6cbb7396 Merge pull request 'HOTFIX' (#305) from master into Docker
Reviewed-on: SGD-Nord/konova#305
2023-02-23 12:03:23 +01:00
mpeltriaux 5e6bfdf77e Merge pull request 'HOTFIX' (#304) from master into Docker
Reviewed-on: SGD-Nord/konova#304
2023-02-23 10:45:57 +01:00
mpeltriaux 35e5e18b79 Merge pull request 'master' (#303) from master into Docker
Reviewed-on: SGD-Nord/konova#303
2023-02-23 10:24:38 +01:00
mpeltriaux c0e8c6bd84 Merge pull request 'master' (#298) from master into Docker
Reviewed-on: SGD-Nord/konova#298
2023-02-21 08:07:47 +01:00
mpeltriaux 64541b76c5 Merge pull request 'master' (#295) from master into Docker
Reviewed-on: SGD-Nord/konova#295
2023-02-13 14:42:17 +01:00
mpeltriaux f65b9262cb Merge pull request 'master' (#292) from master into Docker
Reviewed-on: SGD-Nord/konova#292
2023-02-06 15:01:50 +01:00
mpeltriaux 2765d0548e Merge pull request 'Quality Check Command enhancement' (#288) from master into Docker
Reviewed-on: SGD-Nord/konova#288
2023-02-01 14:17:21 +01:00
mpeltriaux 951f810ce5 Merge pull request 'master' (#287) from master into Docker
Reviewed-on: SGD-Nord/konova#287
2023-02-01 14:10:04 +01:00
mpeltriaux d2c177d448 Merge pull request 'master' (#283) from master into Docker
Reviewed-on: SGD-Nord/konova#283
2022-12-22 07:56:02 +01:00
mpeltriaux 299727a7b4 Merge pull request 'master' (#279) from master into Docker
Reviewed-on: SGD-Nord/konova#279
2022-12-14 16:37:41 +01:00
mpeltriaux b97976b2c5 Merge pull request 'master' (#276) from master into Docker
Reviewed-on: SGD-Nord/konova#276
2022-12-13 06:50:43 +01:00
mpeltriaux 20241661ff Merge pull request 'master' (#273) from master into Docker
Reviewed-on: SGD-Nord/konova#273
2022-12-09 13:02:46 +01:00
mpeltriaux ad5c0bea67 Merge pull request 'master' (#270) from master into Docker
Reviewed-on: SGD-Nord/konova#270
2022-12-09 07:25:30 +01:00
mpeltriaux 80a44277bc Merge pull request 'Hotfix: Resubmission mail' (#265) from master into Docker
Reviewed-on: SGD-Nord/konova#265
2022-12-05 06:55:53 +01:00
mpeltriaux 5c2b5affc9 Merge pull request 'master' (#264) from master into Docker
Reviewed-on: SGD-Nord/konova#264
2022-12-05 06:10:26 +01:00
mpeltriaux cd99743d1e Merge pull request 'master' (#261) from master into Docker
Reviewed-on: SGD-Nord/konova#261
2022-12-02 06:43:28 +01:00
mpeltriaux b39432be1a Merge pull request 'master' (#259) from master into Docker
Reviewed-on: SGD-Nord/konova#259
2022-12-01 14:01:40 +01:00
mpeltriaux 03f9a33e54 Merge pull request 'Hotfix' (#256) from master into Docker
Reviewed-on: SGD-Nord/konova#256
2022-12-01 07:05:50 +01:00
mpeltriaux 699a9c1e76 Merge pull request 'Revert "File number public reports"' (#254) from master into Docker
Reviewed-on: SGD-Nord/konova#254
2022-11-28 13:52:34 +01:00
mpeltriaux 4dfd02291e Merge pull request 'master' (#253) from master into Docker
Reviewed-on: SGD-Nord/konova#253
2022-11-28 07:29:36 +01:00
mpeltriaux e7ca485a88 Merge pull request 'master' (#247) from master into Docker
Reviewed-on: SGD-Nord/konova#247
2022-11-23 16:07:21 +01:00
mpeltriaux 8319cbfe17 Merge pull request 'master' (#245) from master into Docker
Reviewed-on: SGD-Nord/konova#245
2022-11-23 07:14:15 +01:00
mpeltriaux 4a023e9f10 Merge pull request 'Hotfix' (#242) from master into Docker
Reviewed-on: SGD-Nord/konova#242
2022-11-18 16:22:50 +01:00
mpeltriaux 4100f96dc6 Merge pull request 'master' (#241) from master into Docker
Reviewed-on: SGD-Nord/konova#241
2022-11-18 16:17:39 +01:00
mpeltriaux ca24f098e4 Merge pull request 'master' (#236) from master into Docker
Reviewed-on: SGD-Nord/konova#236
2022-11-18 06:53:27 +01:00
mpeltriaux 80dcd62199 Merge pull request 'master' (#234) from master into Docker
Reviewed-on: SGD-Nord/konova#234
2022-11-17 06:55:28 +01:00
mpeltriaux 0cfd3da728 Merge pull request 'master' (#227) from master into Docker
Reviewed-on: SGD-Nord/konova#227
2022-11-14 07:23:43 +01:00
mpeltriaux e141851a87 Merge pull request 'master' (#224) from master into Docker
Reviewed-on: SGD-Nord/konova#224
2022-10-19 07:35:31 +02:00
mpeltriaux 89ec67999b Merge pull request 'master' (#221) from master into Docker
Reviewed-on: SGD-Nord/konova#221
2022-10-12 09:02:49 +02:00
mpeltriaux ec38daaedc Merge pull request 'master' (#219) from master into Docker
Reviewed-on: SGD-Nord/konova#219
2022-10-11 16:41:06 +02:00
mpeltriaux 45c0826a84 Merge pull request 'master' (#215) from master into Docker
Reviewed-on: SGD-Nord/konova#215
2022-10-05 11:03:03 +02:00
mpeltriaux 45a383cf85 Merge pull request 'master' (#213) from master into Docker
Reviewed-on: SGD-Nord/konova#213
2022-09-29 10:46:30 +02:00
mpeltriaux 90aff209f9 Merge pull request 'master' (#210) from master into Docker
Reviewed-on: SGD-Nord/konova#210
2022-09-28 12:28:49 +02:00
mpeltriaux 13528e91e9 Merge pull request 'master' (#207) from master into Docker
Reviewed-on: SGD-Nord/konova#207
2022-09-16 12:13:59 +02:00
mpeltriaux 04179d633c Merge pull request 'master' (#205) from master into Docker
Reviewed-on: SGD-Nord/konova#205
2022-09-16 07:24:21 +02:00
mpeltriaux 0a241305d3 Merge pull request 'Docker Update' (#199) from master into Docker
Reviewed-on: SGD-Nord/konova#199
2022-08-15 11:23:09 +02:00
mpeltriaux 31565a0bc4 Merge pull request 'Docker_tmp' (#188) from Docker_tmp into Docker
Reviewed-on: SGD-Nord/konova#188
2022-08-02 09:54:31 +02:00
mpeltriaux af747417d3 Revert "Revert "Merge branch 'Docker' into master""
This reverts commit 1c38acea25.
2022-08-02 09:44:25 +02:00
mpeltriaux c6606c4151 Merge pull request 'master' (#187) from master into Docker_tmp
Reviewed-on: SGD-Nord/konova#187
2022-08-02 09:43:04 +02:00
29 changed files with 234 additions and 346 deletions
+36
View File
@@ -0,0 +1,36 @@
# Nutze ein schlankes Python-Image
FROM python:3.13-slim-bullseye
ENV PYTHONUNBUFFERED 1
WORKDIR /konova
# Installiere System-Abhängigkeiten
RUN apt-get update && apt-get install -y --no-install-recommends \
gdal-bin redis-server nginx \
&& rm -rf /var/lib/apt/lists/* # Platz sparen
# Erstelle benötigte Verzeichnisse & setze Berechtigungen
RUN mkdir -p /var/log/nginx /var/log/gunicorn /var/lib/nginx /tmp/nginx_client_body \
&& touch /var/log/nginx/access.log /var/log/nginx/error.log \
&& chown -R root:root /var/log/nginx /var/lib/nginx /tmp/nginx_client_body
# Kopiere und installiere Python-Abhängigkeiten
COPY ./requirements.txt /konova/
RUN pip install --upgrade pip && pip install --no-cache-dir -r requirements.txt
# Entferne Standard-Nginx-Site und ersetze sie durch eigene Config
RUN rm -rf /etc/nginx/sites-enabled/default
COPY ./nginx.conf /etc/nginx/conf.d
# Kopiere restliche Projektdateien
COPY . /konova/
# Sammle statische Dateien
RUN python manage.py collectstatic --noinput
# Exponiere Ports
#EXPOSE 80 6379 8000
# Setze Entrypoint
ENTRYPOINT ["/konova/docker-entrypoint.sh"]
+56
View File
@@ -4,6 +4,7 @@ the database postgresql and the css library bootstrap as well as the icon packag
fontawesome for a modern look, following best practices from the industry.
## Background processes
### !!! For non-docker run
Konova uses celery for background processing. To start the worker you need to run
```shell
$ celery -A konova worker -l INFO
@@ -18,3 +19,58 @@ Technical documention is provided in the projects git wiki.
A user documentation is not available (and not needed, yet).
# Docker
To run the docker-compose as expected, you need to take the following steps:
1. Create a database containing docker, using an appropriate Dockerfile, e.g. the following
```
version: '3.3'
services:
postgis:
image: postgis/postgis
restart: always
container_name: postgis-docker
ports:
- 5433:5432
volumes:
- db-volume:/var/lib/postgresql/data
environment:
- POSTGRES_PASSWORD=postgres
- POSTGRES_USER=postgres
networks:
- db-network-bridge
networks:
db-network-bridge:
driver: "bridge"
volumes:
db-volume:
```
This Dockerfile creates a Docker container running postgresql and postgis, creates the default superuser postgres,
creates a named volume for persisting the database and creates a new network bridge, which **must be used by any other
container, which wants to write/read on this database**.
2. Make sure the name of the network bridge above matches the network in the konova docker-compose.yml
3. Get into the running postgis container (`docker exec -it postgis-docker bash`) and create new databases, users and so on. Make sure the database `konova` exists now!
4. Replace all `CHANGE_ME_xy` values inside of konova/docker-compose.yml for your installation. Make sure the `SSO_HOST` holds the proper SSO host, e.g. for the arnova project `arnova.example.org` (Arnova must be installed and the webserver configured as well, of course)
5. Take a look on konova/settings.py and konova/sub_settings/django_settings.py. Again: Replace all occurences of `CHANGE_ME` with proper values for your installation.
1. Make sure you have the proper host strings added to `ALLOWED_HOSTS` inside of django_settings.py.
6. Build and run the docker setup using `docker-compose build` and `docker-compose start` from the main directory of this project (where the docker-compose.yml lives)
7. Run migrations! To do so, get into the konova service container (`docker exec -it konova-docker bash`) and run the needed commands (`python manage.py makemigrations LIST_OF_ALL_MIGRATABLE_APPS`, then `python manage.py migrate`)
8. Run the setup command `python manage.py setup` and follow the instructions on the CLI
9. To enable **SMTP** mail support, make sure your host machine (the one where the docker container run) has the postfix service configured properly. Make sure the `mynetworks` variable is xtended using the docker network bridge ip, created in the postgis container and used by the konova services.
1. **Hint**: You can find out this easily by trying to perform a test mail in the running konova web application (which will fail, of course). Then take a look to the latest entries in `/var/log/mail.log` on your host machine. The failed IP will be displayed there.
2. **Please note**: This installation guide is based on SMTP using postfix!
3. Restart the postfix service on your host machine to reload the new configuration (`service postfix restart`)
10. Finally, make sure your host machine webserver passes incoming requests properly to the docker nginx webserver of konova. A proper nginx config for the host machine may look like this:
```
server {
server_name konova.domain.org;
location / {
proxy_pass http://localhost:KONOVA_NGINX_DOCKER_PORT/;
proxy_set_header Host $host;
}
}
```
-23
View File
@@ -1,23 +0,0 @@
# Generated by Django 6.0.5 on 2026-05-10 07:18
import django.db.models.deletion
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('api', '0003_oauthtoken'),
('user', '0010_user_sso_identifier'),
]
operations = [
migrations.CreateModel(
name='ExternalIdentifier',
fields=[
('external_id', models.CharField(db_comment='Identifier from a source system', max_length=255, primary_key=True, serialize=False)),
('internal_id', models.UUIDField(db_comment='Identifier in konova')),
('created', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to='user.useractionlogentry')),
],
),
]
-1
View File
@@ -6,4 +6,3 @@ Created on: 21.01.22
"""
from .token import *
from .external_identifier import *
-51
View File
@@ -1,51 +0,0 @@
"""
Author: Michel Peltriaux
Created on: 10.05.26
"""
from django.db import models
class ExternalIdentifier(models.Model):
""" Holds a lookup to match a given external identifier against the internal identifier in konova.
Relevant in cases of API transmitted entries, which are updates using external identifiers instead of
the internal ones directly.
"""
external_id = models.CharField(
max_length=255,
primary_key=True,
db_comment="Identifier from a source system"
)
internal_id = models.UUIDField(
db_comment="Identifier in konova"
)
created = models.ForeignKey(
"user.UserActionLogEntry",
on_delete=models.SET_NULL,
null=True,
blank=True,
related_name='+'
)
def __str__(self):
return f"{self.external_id} -> {self.internal_id}"
@staticmethod
def resolve_external_identifier(external_identifier: str):
""" Returns a ExternalIdentifier object, if the given parameter could be resolved as an external identifier.
Args:
external_identifier (str): An external identifier.
Returns:
ExternalIdentifier | None
"""
if external_identifier:
try:
obj = ExternalIdentifier.objects.get(external_id=external_identifier)
return obj
except ExternalIdentifier.DoesNotExist:
pass
return None
@@ -8,7 +8,6 @@
"is_coherence_keeping": false,
"is_pik": false,
"intervention": "MUST_BE_SET_IN_TEST",
"external_identifier": "LOREMIPSUM-123",
"before_states": [
],
"after_states": [
@@ -4,7 +4,6 @@
],
"properties": {
"title": "Test_ecoaccount",
"external_identifier": "LOREMIPSUM-1234",
"deductable_surface": 10000.0,
"is_pik": false,
"responsible": {
@@ -4,7 +4,6 @@
],
"properties": {
"title": "Test_ema",
"external_identifier": "LOREMIPSUM-1235",
"is_pik": false,
"responsible": {
"conservation_office": null,
@@ -4,7 +4,6 @@
],
"properties": {
"title": "Test_intervention",
"external_identifier": "LOREMIPSUM-1236",
"responsible": {
"registration_office": null,
"registration_file_number": null,
+5 -25
View File
@@ -9,7 +9,6 @@ import json
from django.urls import reverse
from api.models import ExternalIdentifier
from api.tests.v1.share.test_api_sharing import BaseAPIV1TestCase
@@ -43,22 +42,7 @@ class APIV1CreateTestCase(BaseAPIV1TestCase):
response = self._run_create_request(url, post_body)
self.assertEqual(response.status_code, 200, msg=response.content)
content = json.loads(response.content)
_id = content.get("id", None)
self.assertIsNotNone(_id, msg=response.content)
return _id
def _test_external_identifier_created(self, internal_id, external_id):
""" Tests whether an external identifier has been created
Args:
internal_id ():
external_id ():
Returns:
"""
external_identifier = ExternalIdentifier.objects.get(internal_id=internal_id)
self.assertEqual(external_identifier.external_id, external_id)
self.assertIsNotNone(content.get("id", None), msg=response.content)
def test_create_intervention(self):
""" Tests api creation
@@ -70,8 +54,7 @@ class APIV1CreateTestCase(BaseAPIV1TestCase):
json_file_path = "api/tests/v1/create/intervention_create_post_body.json"
with open(json_file_path) as json_file:
post_body = json.load(fp=json_file)
internal_id = self._test_create_object(url, post_body)
self._test_external_identifier_created(internal_id, post_body["properties"]["external_identifier"])
self._test_create_object(url, post_body)
def test_create_compensation(self):
""" Tests api creation
@@ -94,8 +77,7 @@ class APIV1CreateTestCase(BaseAPIV1TestCase):
# Add the user to the shared users of the intervention and try again! Now everything should work as expected.
self.intervention.users.add(self.superuser)
internal_id = self._test_create_object(url, post_body)
self._test_external_identifier_created(internal_id, post_body["properties"]["external_identifier"])
self._test_create_object(url, post_body)
def test_create_eco_account(self):
""" Tests api creation
@@ -107,8 +89,7 @@ class APIV1CreateTestCase(BaseAPIV1TestCase):
json_file_path = "api/tests/v1/create/ecoaccount_create_post_body.json"
with open(json_file_path) as json_file:
post_body = json.load(fp=json_file)
internal_id = self._test_create_object(url, post_body)
self._test_external_identifier_created(internal_id, post_body["properties"]["external_identifier"])
self._test_create_object(url, post_body)
def test_create_ema(self):
""" Tests api creation
@@ -120,8 +101,7 @@ class APIV1CreateTestCase(BaseAPIV1TestCase):
json_file_path = "api/tests/v1/create/ema_create_post_body.json"
with open(json_file_path) as json_file:
post_body = json.load(fp=json_file)
internal_id = self._test_create_object(url, post_body)
self._test_external_identifier_created(internal_id, post_body["properties"]["external_identifier"])
self._test_create_object(url, post_body)
def test_create_deduction(self):
""" Tests api creation
+9 -16
View File
@@ -31,10 +31,9 @@ class APIV1SharingTestCase(BaseAPIV1TestCase):
def setUpTestData(cls):
super().setUpTestData()
def _run_share_request(self, url, user_list: list, team_list: list):
def _run_share_request(self, url, user_list: list):
data = {
"users": user_list,
"teams": team_list
"users": user_list
}
data = json.dumps(data)
response = self.client.put(
@@ -59,22 +58,16 @@ class APIV1SharingTestCase(BaseAPIV1TestCase):
self.superuser.username,
self.user.username,
]
team_list = [
str(self.team.id),
]
response = self._run_share_request(url, user_list, team_list)
response = self._run_share_request(url, user_list)
# Must fail, since performing user has no access on requested object
self.assertEqual(response.status_code, 500)
self.assertTrue(len(json.loads(response.content.decode("utf-8")).get("errors", [])) > 0)
# Add performing user to shared access users, switch from team id to team name and rerun the request
# Add performing user to shared access users and rerun the request
obj.users.add(self.superuser)
team_list = [
self.team.name
]
response = self._run_share_request(url, user_list, team_list)
response = self._run_share_request(url, user_list)
shared_users = obj.shared_users
self.assertEqual(response.status_code, 200)
@@ -91,14 +84,14 @@ class APIV1SharingTestCase(BaseAPIV1TestCase):
share_url = reverse("api:v1:intervention-share", args=(self.intervention.id,))
# Expect the first request to work properly
self.intervention.users.add(self.superuser)
response = self._run_share_request(share_url, [self.superuser.username], [str(self.team.id)])
response = self._run_share_request(share_url, [self.superuser.username])
self.assertEqual(response.status_code, 200)
# Change the token
self.header_data["HTTP_ksptoken"] = f"{self.superuser.api_token.token}__X"
# Expect the request to fail now
response = self._run_share_request(share_url, [self.superuser.username], [])
response = self._run_share_request(share_url, [self.superuser.username])
self.assertEqual(response.status_code, 403)
def test_api_intervention_sharing(self):
@@ -151,11 +144,11 @@ class APIV1SharingTestCase(BaseAPIV1TestCase):
self.assertEqual(self.intervention.users.count(), 1)
# Try to add another user via API -> must work!
response = self._run_share_request(share_url, [self.superuser.username, self.user.username], [])
response = self._run_share_request(share_url, [self.superuser.username, self.user.username])
self.assertEqual(response.status_code, 200)
self.assertEqual(self.intervention.users.count(), 2)
# Now try to remove the user again -> expect no changes at all to the shared user list
response = self._run_share_request(share_url, [self.superuser.username], [])
response = self._run_share_request(share_url, [self.superuser.username])
self.assertEqual(response.status_code, 200)
self.assertEqual(self.intervention.users.count(), 2)
@@ -44,7 +44,6 @@
],
"properties": {
"title": "TEST_compensation_CHANGED",
"external_identifier": "LOREMIPSUM-123_CHANGED",
"is_cef": true,
"is_coherence_keeping": true,
"is_pik": true,
@@ -44,7 +44,6 @@
],
"properties": {
"title": "TEST_account_CHANGED",
"external_identifier": "LOREMIPSUM-1234_CHANGED",
"deductable_surface": "100000.0",
"is_pik": true,
"responsible": {
@@ -44,7 +44,6 @@
],
"properties": {
"title": "TEST_EMA_CHANGED",
"external_identifier": "LOREMIPSUM-1235_CHANGED",
"responsible": {
"conservation_office": null,
"conservation_file_number": "TEST_CHANGED",
@@ -44,7 +44,6 @@
],
"properties": {
"title": "Test_intervention_CHANGED",
"external_identifier": "LOREMIPSUM-1236_CHANGED",
"responsible": {
"registration_office": null,
"registration_file_number": "CHANGED",
-18
View File
@@ -10,11 +10,9 @@ from abc import abstractmethod
from django.contrib.gis import geos
from django.contrib.gis.geos import GEOSGeometry
from django.core.exceptions import ObjectDoesNotExist
from django.core.paginator import Paginator
from django.db.models import Q
from api.models import ExternalIdentifier
from konova.models import Geometry
from konova.utils.message_templates import DATA_UNSHARED
@@ -78,14 +76,6 @@ class AbstractModelAPISerializer:
del self.lookup["id"]
else:
# Return certain object
## But first check, whether this is an external identifier ...
try:
## If we can find this _id on our ExternalIdentifier model, we need to map it on the internal id
ext_id = ExternalIdentifier.objects.get(external_id=_id)
_id = ext_id.internal_id
except ObjectDoesNotExist:
# If we did not find it, we assume that this is already an internal id. (Or it does not exist at all)
pass
self.lookup["id"] = _id
self.shared_lookup = Q(
@@ -171,14 +161,6 @@ class AbstractModelAPISerializer:
Returns:
"""
# First if there is an external identifier linked to an internal one, so we can continue with the internal
try:
ext_id = ExternalIdentifier.objects.get(external_id=id)
id = ext_id.internal_id
except ObjectDoesNotExist:
# No external id found - let's hope the given id exists internally
pass
obj = self.model.objects.get(
id=id,
deleted__isnull=True,
-11
View File
@@ -88,11 +88,6 @@ class CompensationAPISerializerV1(AbstractModelAPISerializerV1, AbstractCompensa
# Nothing to do here
return obj
# Transform a potential external identifier into an internal one
intervention_ext_id = self._get_external_identifier(intervention_id)
if intervention_ext_id:
intervention_id = intervention_ext_id.internal_id
intervention = Intervention.objects.get(
id=intervention_id,
)
@@ -119,10 +114,6 @@ class CompensationAPISerializerV1(AbstractModelAPISerializerV1, AbstractCompensa
# Fill in data to objects
properties = json_model["properties"]
external_identifier = properties.get("external_identifier", None)
self._check_external_identifier_on_entry_creation(external_identifier)
obj.identifier = obj.generate_new_identifier()
obj.title = properties["title"]
obj.is_cef = properties["is_cef"]
@@ -138,7 +129,6 @@ class CompensationAPISerializerV1(AbstractModelAPISerializerV1, AbstractCompensa
obj = self._set_compensation_states(obj, properties["after_states"], obj.after_states)
obj = self._set_deadlines(obj, properties["deadlines"])
self._set_external_identifier(obj.id, properties.get("external_identifier", None), obj.created)
obj.log.add(obj.created)
celery_update_parcels.delay(obj.geometry.id)
@@ -180,7 +170,6 @@ class CompensationAPISerializerV1(AbstractModelAPISerializerV1, AbstractCompensa
obj = self._set_compensation_states(obj, properties["after_states"], obj.after_states)
obj = self._set_deadlines(obj, properties["deadlines"])
self._set_external_identifier(obj.id, properties.get("external_identifier", None), update_action)
obj.log.add(update_action)
celery_update_parcels.delay(obj.geometry.id)
-8
View File
@@ -62,14 +62,6 @@ class DeductionAPISerializerV1(AbstractModelAPISerializerV1,
if surface <= 0:
raise ValueError("Surface must be > 0 m²")
# Check if external identifiers need to be mapped onto internal ones
acc_ext_id = self._get_external_identifier(acc_id)
intervention_ext_id = self._get_external_identifier(intervention_id)
if acc_ext_id:
acc_id = acc_ext_id.internal_id
if intervention_ext_id:
intervention_id = intervention_ext_id.internal_id
acc = EcoAccount.objects.get(
id=acc_id,
deleted__isnull=True,
+1 -9
View File
@@ -121,9 +121,7 @@ class EcoAccountAPISerializerV1(AbstractModelAPISerializerV1,
obj = self._initialize_objects(json_model, user)
# Fill in data to objects
properties = json_model.get("properties", None)
if not properties:
raise AssertionError("No 'properties' found in payload!")
properties = json_model["properties"]
obj.identifier = obj.generate_new_identifier()
obj.title = properties["title"]
obj.is_pik = properties.get("is_pik", False)
@@ -149,7 +147,6 @@ class EcoAccountAPISerializerV1(AbstractModelAPISerializerV1,
obj = self._set_compensation_states(obj, properties["after_states"], obj.after_states)
obj = self._set_deadlines(obj, properties["deadlines"])
self._set_external_identifier(obj.id, properties.get("external_identifier", None), obj.created)
obj.log.add(obj.created)
obj.users.add(user)
@@ -175,10 +172,6 @@ class EcoAccountAPISerializerV1(AbstractModelAPISerializerV1,
# Fill in data to objects
properties = json_model["properties"]
external_identifier = properties.get("external_identifier", None)
self._check_external_identifier_on_entry_creation(external_identifier)
obj.title = properties["title"]
obj.is_pik = properties.get("is_pik", False)
obj.deductable_surface = float(properties["deductable_surface"])
@@ -199,7 +192,6 @@ class EcoAccountAPISerializerV1(AbstractModelAPISerializerV1,
obj = self._set_compensation_states(obj, properties["after_states"], obj.after_states)
obj = self._set_deadlines(obj, properties["deadlines"])
self._set_external_identifier(obj.id, external_identifier, update_action)
obj.log.add(update_action)
celery_update_parcels.delay(obj.geometry.id)
-6
View File
@@ -104,10 +104,6 @@ class EmaAPISerializerV1(AbstractModelAPISerializerV1, AbstractCompensationAPISe
# Fill in data to objects
properties = json_model["properties"]
external_identifier = properties.get("external_identifier", None)
self._check_external_identifier_on_entry_creation(external_identifier)
obj.identifier = obj.generate_new_identifier()
obj.title = properties["title"]
obj.is_pik = properties.get("is_pik", False)
@@ -123,7 +119,6 @@ class EmaAPISerializerV1(AbstractModelAPISerializerV1, AbstractCompensationAPISe
obj = self._set_compensation_states(obj, properties["after_states"], obj.after_states)
obj = self._set_deadlines(obj, properties["deadlines"])
self._set_external_identifier(obj.id, external_identifier, obj.created)
obj.log.add(obj.created)
obj.users.add(user)
@@ -166,7 +161,6 @@ class EmaAPISerializerV1(AbstractModelAPISerializerV1, AbstractCompensationAPISe
obj = self._set_compensation_states(obj, properties["after_states"], obj.after_states)
obj = self._set_deadlines(obj, properties["deadlines"])
self._set_external_identifier(obj.id, properties.get("external_identifier", None), update_action)
obj.log.add(update_action)
celery_update_parcels.delay(obj.geometry.id)
+4 -10
View File
@@ -150,14 +150,10 @@ class InterventionAPISerializerV1(AbstractModelAPISerializerV1,
# Fill in data to objects
properties = json_model["properties"]
external_identifier = properties.get("external_identifier", None)
self._check_external_identifier_on_entry_creation(external_identifier)
obj.identifier = obj.generate_new_identifier()
obj.title = properties.get("title", None)
self._set_responsibility(obj, properties.get("responsible", None))
self._set_legal(obj, properties.get("legal", None))
obj.title = properties["title"]
self._set_responsibility(obj, properties["responsible"])
self._set_legal(obj, properties["legal"])
obj.responsible.handler.save()
obj.responsible.save()
@@ -165,7 +161,6 @@ class InterventionAPISerializerV1(AbstractModelAPISerializerV1,
obj.legal.save()
obj.save()
self._set_external_identifier(obj.id, external_identifier, obj.created)
obj.users.add(user)
obj.log.add(obj.created)
@@ -191,7 +186,7 @@ class InterventionAPISerializerV1(AbstractModelAPISerializerV1,
# Fill in data to objects
properties = json_model["properties"]
obj.title = properties.get("title")
obj.title = properties["title"]
self._set_responsibility(obj, properties.get("responsible", None))
self._set_legal(obj, properties.get("legal", None))
self._set_payments(obj, properties.get("payments", None))
@@ -205,7 +200,6 @@ class InterventionAPISerializerV1(AbstractModelAPISerializerV1,
obj.save()
obj.mark_as_edited(user, edit_comment="API update")
self._set_external_identifier(obj.id, properties.get("external_identifier", None), update_action)
obj.send_data_to_egon()
celery_update_parcels.delay(obj.geometry.id)
-60
View File
@@ -12,7 +12,6 @@ from django.contrib.gis.geos import MultiPolygon
from django.core.exceptions import ObjectDoesNotExist
from django.db.models import QuerySet
from api.models import ExternalIdentifier
from api.utils.serializer.serializer import AbstractModelAPISerializer
from codelist.models import KonovaCode
from codelist.settings import CODELIST_COMPENSATION_ACTION_ID, CODELIST_BIOTOPES_ID, CODELIST_PROCESS_TYPE_ID, \
@@ -40,20 +39,12 @@ class AbstractModelAPISerializerV1(AbstractModelAPISerializer):
else:
geom = MultiPolygon().geojson
geo_json = json.loads(geom)
ext_ids = list(
ExternalIdentifier.objects.filter(
internal_id=entry.id
).values_list(
"external_id", flat=True
)
)
self.properties_data = {
"id": entry.id,
"identifier": entry.identifier,
"title": entry.title,
"created_on": self._created_on_to_json(entry),
"modified_on": self._modified_on_to_json(entry),
"external_identifiers": ext_ids,
}
self._extend_properties_data(entry)
geo_json["properties"] = self.properties_data
@@ -146,57 +137,6 @@ class AbstractModelAPISerializerV1(AbstractModelAPISerializer):
success = entry.deleted is not None
return success
def _set_external_identifier(self, internal_identifier, external_identifier, log_entry):
""" If an external identifier was provided in the payload, we set it
in the database
Args:
internal_identifier (BaseObject): The already processed konova object (EIV, KOM, ...)
external_identifier (any): The external identifier taken from the payload
Returns:
"""
if external_identifier is None:
return None
ext_id_obj = ExternalIdentifier.objects.get_or_create(
internal_id=internal_identifier,
external_id=external_identifier
)[0]
if not ext_id_obj.created:
ext_id_obj.created = log_entry
ext_id_obj.save()
return ext_id_obj
def _get_external_identifier(self, external_identifier):
""" Checks whether a linkage based on an external identifier already exists and returns it if so.
Args:
external_identifier (any): The external identifier according to payload
Returns:
ExternalIdentifier | None
"""
return ExternalIdentifier.resolve_external_identifier(external_identifier)
def _check_external_identifier_on_entry_creation(self, external_identifier):
""" Special check for POST processing:
Checks whether an external identifier already exists on the database. This hints that
the entry already has been created in the past. Instead of POST, the PUT method shall be used
to avoid creating duplicates.
Args:
external_identifier (any): The external identifier according to payload
Returns:
"""
persisted_external_identifier = self._get_external_identifier(external_identifier)
if persisted_external_identifier:
raise AssertionError(f"{external_identifier} has already been initially created! Use PUT for updates!")
class DeductableAPISerializerV1Mixin:
class Meta:
+19 -68
View File
@@ -6,14 +6,13 @@ Created on: 21.01.22
"""
import json
import uuid
from django.db.models import QuerySet, Q
from django.db.models import QuerySet
from django.http import JsonResponse, HttpRequest
from django.views import View
from django.views.decorators.csrf import csrf_exempt
from api.models import APIUserToken, ExternalIdentifier
from api.models import APIUserToken
from api.settings import KSP_TOKEN_HEADER_IDENTIFIER, KSP_USER_HEADER_IDENTIFIER
from compensation.models import EcoAccount
from ema.models import Ema
@@ -206,10 +205,6 @@ class AbstractModelShareAPIView(AbstractAPIView):
"""
try:
external_identifier = ExternalIdentifier.resolve_external_identifier(id)
if external_identifier:
id = external_identifier.internal_id
users = self._get_shared_users_of_object(id)
teams = self._get_shared_teams_of_object(id)
except Exception as e:
@@ -242,9 +237,6 @@ class AbstractModelShareAPIView(AbstractAPIView):
"""
try:
external_identifier = ExternalIdentifier.resolve_external_identifier(id)
if external_identifier:
id = external_identifier.internal_id
success = self._process_put_body(request.body, id)
except Exception as e:
return self._return_error_response(e)
@@ -317,36 +309,22 @@ class AbstractModelShareAPIView(AbstractAPIView):
raise ValueError("Shared user list must not be empty!")
new_teams = content.get("teams", [])
self.__process_user_sharing(new_users, obj)
self.__process_team_sharing(new_teams, obj)
return True
def __process_user_sharing(self, user_list: list, obj):
""" Processes API sharing for user payload
Args:
user_list (list): A list of users to share the obj with
obj (BaseObject): The shareable object
Returns:
"""
# Eliminate duplicates
new_users = list(dict.fromkeys(user_list))
new_users = list(dict.fromkeys(new_users))
new_teams = list(dict.fromkeys(new_teams))
# Make sure each of these names exist as a user
new_users_objs = []
for user in new_users:
try:
user_obj = User.objects.get(username=user)
except User.DoesNotExist:
raise AssertionError(f"User with username {user} does not exist")
new_users_objs.append(user_obj)
new_users_objs.append(User.objects.get(username=user))
# Make sure each of these names exist as a user
new_teams_objs = []
for team_name in new_teams:
new_teams_objs.append(Team.objects.get(name=team_name))
if self.user.is_default_group_only():
# Default only users are not allowed to remove other users from having access. They can only add new ones!
# So we need to keep the ones that already have access from being removed!
new_users_to_be_added = User.objects.filter(
username__in=new_users
).exclude(
@@ -354,44 +332,17 @@ class AbstractModelShareAPIView(AbstractAPIView):
)
new_users_objs = obj.shared_users.union(new_users_to_be_added)
new_teams_to_be_added = Team.objects.filter(
name__in=new_teams
).exclude(
id__in=obj.shared_teams
)
new_teams_objs = obj.shared_teams.union(new_teams_to_be_added)
obj.share_with_user_list(new_users_objs)
obj.share_with_team_list(new_teams_objs)
return True
def __process_team_sharing(self, team_list: list, obj):
""" Processes API sharing for team payload
Args:
team_list (list): A list of teams to share the obj with
obj (BaseObject): The shareable object
Returns:
"""
# Eliminate duplicates
new_teams = list(dict.fromkeys(team_list))
# Resolve team names or ids into objects
new_team_ids = []
for team in new_teams:
try:
uuid.UUID(team)
try:
new_team_ids.append(Team.objects.get(id=team).id)
except Team.DoesNotExist:
raise AssertionError(f"Team with id {team} does not exist!")
except ValueError:
# entry is a name and not a uuid -> try to resolve as name!
try:
new_team_ids.append(Team.objects.get(name=team).id)
except Team.DoesNotExist:
raise AssertionError(f"Team with name {team} does not exist!")
new_team_objs = Team.objects.filter(id__in=new_team_ids)
if self.user.is_default_group_only():
# Default only users are not allowed to remove other users from having access. They can only add new ones!
# So we need to keep the ones that already have access from being removed!
new_team_objs = obj.shared_teams.union(new_team_objs)
obj.share_with_team_list(new_team_objs)
class InterventionAPIShareView(AbstractModelShareAPIView):
model = Intervention
+21
View File
@@ -0,0 +1,21 @@
services:
konova:
external_links:
- postgis:db
- arnova-nginx-server:arnova
build: .
image: "ksp/konova:x.y"
container_name: "konova-docker"
command: ./docker-entrypoint.sh
restart: always
volumes:
- /data/apps/konova/uploaded_files:/konova_uploaded_files
ports:
- "1337:80"
# Instead of an own, new network, we need to connect to the existing one, which is provided by the postgis container
# NOTE: THIS NETWORK MUST EXIST
networks:
default:
name: postgis_nat_it_backend
external: true
+27
View File
@@ -0,0 +1,27 @@
#!/bin/bash
set -e # Beende Skript bei Fehlern
set -o pipefail # Fehler in Pipelines nicht ignorieren
# Starte Redis
redis-server --daemonize yes
# Starte Celery Worker im Hintergrund
celery -A konova worker --loglevel=info &
# Starte Nginx als Hintergrundprozess
nginx -g "daemon off;" &
# Setze Gunicorn Worker-Anzahl (Standard: (2*CPUs)+1)
WORKERS=${GUNICORN_WORKERS:-$((2 * $(nproc) + 1))}
# Stelle sicher, dass Logs existieren
mkdir -p /var/log/gunicorn
touch /var/log/gunicorn/access.log /var/log/gunicorn/error.log
# Starte Gunicorn als Hauptprozess
exec gunicorn --workers="$WORKERS" konova.wsgi:application \
--bind=0.0.0.0:8000 \
--access-logfile /var/log/gunicorn/access.log \
--error-logfile /var/log/gunicorn/error.log \
--access-logformat '%({x-real-ip}i)s via %(h)s %(l)s %(u)s %(t)s "%(r)s" %(s)s %(b)s "%(f)s" "%(a)s"'
+2 -3
View File
@@ -191,11 +191,10 @@ STATICFILES_DIRS = [
]
# EMAIL (see https://docs.djangoproject.com/en/dev/topics/email/)
# CHANGE_ME !!! ONLY FOR DEVELOPMENT !!!
if DEBUG:
# ONLY FOR DEVELOPMENT NEEDED
EMAIL_BACKEND = 'django.core.mail.backends.filebased.EmailBackend'
EMAIL_FILE_PATH = '/tmp/app-messages' # change this to a proper location
EMAIL_FILE_PATH = '/tmp/app-messages'
DEFAULT_FROM_EMAIL = env("DEFAULT_FROM_EMAIL") # The default email address for the 'from' element
SERVER_EMAIL = DEFAULT_FROM_EMAIL # The default email sender address, which is used by Django to send errors via mail
+25
View File
@@ -0,0 +1,25 @@
server {
listen 80;
client_max_body_size 25M;
location / {
proxy_pass http://127.0.0.1:8000;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Host $host;
proxy_redirect off;
proxy_cache_bypass $http_upgrade;
}
location /static/ {
alias /konova/static/;
access_log /var/log/nginx/access.log;
autoindex off;
types {
text/css css;
application/javascript js;
}
}
error_log /var/log/nginx/error.log;
}
+27 -27
View File
@@ -4,62 +4,62 @@ async-timeout==5.0.1
beautifulsoup4==4.14.3
billiard==4.2.4
cached-property==2.0.1
celery==5.6.3
certifi==2026.4.22
celery==5.6.2
certifi==2026.2.25
cffi==2.0.0
chardet==7.4.3
charset-normalizer==3.4.7
click==8.3.3
chardet==6.0.0.post1
charset-normalizer==3.4.4
click==8.3.1
click-didyoumean==0.3.1
click-plugins==1.1.1.2
click-repl==0.3.0
coverage==7.13.5
cryptography==48.0.0
coverage==7.13.4
cryptography==46.0.5
Deprecated==1.3.1
Django==6.0.5
django-autocomplete-light==4.0.0
Django==6.0.2
django-autocomplete-light==3.12.1
django-bootstrap-modal-forms==3.0.5
django-bootstrap4==26.1
django-environ==0.13.0
django-filter==25.2
django-fontawesome-5==1.0.18
django-oauth-toolkit==3.2.0
django-tables2==3.0.0
django-tables2==2.8.0
et_xmlfile==2.0.0
gunicorn==26.0.0
idna==3.13
importlib_metadata==9.0.0
gunicorn==25.1.0
idna==3.11
importlib_metadata==8.7.1
itsdangerous==2.2.0
jwcrypto==1.5.7
jwcrypto==1.5.6
kombu==5.6.2
oauthlib==3.3.1
openpyxl==3.2.0b1
packaging==26.2
pika==1.4.0
pillow==12.2.0
packaging==26.0
pika==1.3.2
pillow==12.1.1
prompt_toolkit==3.0.52
psycopg==3.3.4
psycopg-binary==3.3.4
psycopg==3.3.3
psycopg-binary==3.3.3
pycparser==3.0
pyparsing==3.3.2
pypng==0.20220715.0
pyproj==3.7.2
python-dateutil==2.9.0.post0
pytz==2026.2
pytz==2025.2
PyYAML==6.0.3
qrcode==8.2
redis==7.4.0
requests==2.33.1
redis==7.2.1
requests==2.32.5
six==1.17.0
soupsieve==2.8.3
sqlparse==0.5.5
typing_extensions==4.15.0
tzdata==2026.2
tzdata==2025.3
tzlocal==5.3.1
urllib3==2.7.0
urllib3==2.6.3
vine==5.1.0
wcwidth==0.7.0
wcwidth==0.6.0
webservices==0.7
wrapt==2.1.2
wrapt==2.1.1
xmltodict==1.0.4
zipp==3.23.1
zipp==3.23.0
+1 -1
View File
@@ -70,7 +70,7 @@
</div>
<div class="dropdown-menu dropdown-menu-right">
{% for rpp_option in table.results_per_page_choices %}
<a class="dropdown-item {% if table.results_per_page_chosen == rpp_option %}selected{% endif %}" href="{% querystring %}&{{ table.results_per_page_parameter}}={{rpp_option }}">
<a class="dropdown-item {% if table.results_per_page_chosen == rpp_option %}selected{% endif %}" href="{% querystring table.results_per_page_parameter=rpp_option %}">
{{ rpp_option }}
</a>
{% endfor %}