diff --git a/.env.dev b/.env.dev index fe69fd87..e7717e1f 100644 --- a/.env.dev +++ b/.env.dev @@ -18,5 +18,6 @@ GUNICORN_WORKERS=3 GUNICORN_LOGLEVEL=info # Nginx host ports for local development (override prod defaults) -NGINX_HTTP_PORT=8000 -NGINX_HTTPS_PORT=8443 \ No newline at end of file +NGINX_HTTP_PORT=8080 +# Pick a non-privileged HTTPS port to avoid conflicts with host installs +NGINX_HTTPS_PORT=8444 \ No newline at end of file diff --git a/.gitignore b/.gitignore index 117005a9..5d244eab 100644 --- a/.gitignore +++ b/.gitignore @@ -15,4 +15,6 @@ temp/ # Loki runtime data /docker/loki-data/ -/docker/loki-wal/ \ No newline at end of file +/docker/loki-wal/ +# Local runtime logs collected by Promtail +/logs/ \ No newline at end of file diff --git a/deploy/nginx/dev.conf b/deploy/nginx/dev.conf index 495c7e57..6eb39ef9 100644 --- a/deploy/nginx/dev.conf +++ b/deploy/nginx/dev.conf @@ -7,6 +7,10 @@ server { listen [::]:80; server_name _; + # Write logs to the host-mounted folder so Promtail can scrape them + access_log /var/log/rad/nginx.access.log combined; + error_log /var/log/rad/nginx.error.log warn; + client_max_body_size 100M; location /static/ { diff --git a/deploy/nginx/prod.conf b/deploy/nginx/prod.conf index d08ca5cc..a4c7fea8 100644 --- a/deploy/nginx/prod.conf +++ b/deploy/nginx/prod.conf @@ -8,6 +8,10 @@ server { listen [::]:80; server_name _; + # Write logs to the host-mounted folder so Promtail can scrape them + access_log /var/log/rad/nginx.access.log combined; + error_log /var/log/rad/nginx.error.log warn; + client_max_body_size 100M; # Serve static files from the static volume @@ -112,6 +116,10 @@ server { client_max_body_size 4G; + # Write logs to the host-mounted folder so Promtail can scrape them + access_log /var/log/rad/nginx.access.log combined; + error_log /var/log/rad/nginx.error.log warn; + # Same static/media handling as above location /static/ { alias /usr/src/app/static/; } location /media { alias /usr/src/app/media; } diff --git a/docker/docker-compose.dev.yml b/docker/docker-compose.dev.yml index 92b8ec23..598c2634 100644 --- a/docker/docker-compose.dev.yml +++ b/docker/docker-compose.dev.yml @@ -24,6 +24,7 @@ services: image: nginx:1.25-alpine volumes: - ../deploy/nginx/dev.conf:/etc/nginx/conf.d/default.conf:ro + - ../logs:/var/log/rad:rw loki: image: grafana/loki:2.8.2 diff --git a/docker/docker-compose.prod.yml b/docker/docker-compose.prod.yml index 1808f0c5..68f0e361 100644 --- a/docker/docker-compose.prod.yml +++ b/docker/docker-compose.prod.yml @@ -45,6 +45,7 @@ services: - web volumes: - ../deploy/nginx/prod.conf:/etc/nginx/conf.d/default.conf:ro + - ../logs:/var/log/rad:rw - static_volume:/usr/src/app/static:ro - media_volume:/usr/src/app/media:ro - ../deploy/nginx/certs:/etc/letsencrypt:ro diff --git a/generic/mixins.py b/generic/mixins.py index 99765d4f..75898e4e 100644 --- a/generic/mixins.py +++ b/generic/mixins.py @@ -65,6 +65,9 @@ class AuthorMixin(): def is_author(self, user: User) -> bool: """Returns True if the user is an author of the object""" + if user.is_superuser: + return True + return self.author.filter(id=user.id).exists() diff --git a/generic/views.py b/generic/views.py index a7b14ffe..223dae71 100644 --- a/generic/views.py +++ b/generic/views.py @@ -1774,7 +1774,7 @@ class ExamViews(View, LoginRequiredMixin): def exam_list_collection(self, request, collection_id): collection = get_object_or_404(ExamCollection, pk=collection_id) - if not request.user in collection.author.all(): + if not collection.is_author(request.user): raise PermissionDenied return self.exam_list(request, all=True, collection=collection)