From 6f8f2733442872a59a12bbe52e5b072029960ba1 Mon Sep 17 00:00:00 2001
From: "Adrian A. Baumann"
Date: Thu, 4 Dec 2025 13:26:12 +0100
Subject: [PATCH] XSS prevention added (with tests)
---
argocd/deployment.yaml | 2 +-
dokumente/tests.py | 219 ++++++++++++++++++++++++++++++++++++++
pages/templates/base.html | 2 +-
3 files changed, 221 insertions(+), 2 deletions(-)
diff --git a/argocd/deployment.yaml b/argocd/deployment.yaml
index aeed948..4dfe9d0 100644
--- a/argocd/deployment.yaml
+++ b/argocd/deployment.yaml
@@ -25,7 +25,7 @@ spec:
mountPath: /data
containers:
- name: web
- image: git.baumann.gr/adebaumann/vui:0.966
+ image: git.baumann.gr/adebaumann/vui:0.967
imagePullPolicy: Always
ports:
- containerPort: 8000
diff --git a/dokumente/tests.py b/dokumente/tests.py
index 7d23026..18d9c1f 100644
--- a/dokumente/tests.py
+++ b/dokumente/tests.py
@@ -2343,3 +2343,222 @@ class UserCommentsViewTest(TestCase):
self.assertEqual(response.status_code, 200)
self.assertTemplateUsed(response, 'standards/user_comments.html')
+
+
+class AllCommentsViewTest(TestCase):
+ """Test the all comments view that displays all comments from all users (staff only)"""
+
+ def setUp(self):
+ """Set up test data"""
+ # Create users
+ self.user1 = User.objects.create_user(username='user1', password='pass123', first_name='Max', last_name='Mustermann')
+ self.user2 = User.objects.create_user(username='user2', password='pass123', first_name='Anna', last_name='Mueller')
+ self.staff_user = User.objects.create_user(username='staff', password='pass123', is_staff=True, first_name='Admin', last_name='User')
+
+ # Create documents
+ self.doc_type = Dokumententyp.objects.create(name='Test Type', verantwortliche_ve='test')
+ self.doc1 = Dokument.objects.create(nummer='DOC-001', name='Document 1', dokumententyp=self.doc_type, aktiv=True)
+ self.doc2 = Dokument.objects.create(nummer='DOC-002', name='Document 2', dokumententyp=self.doc_type, aktiv=True)
+
+ # Create themes
+ self.theme1 = Thema.objects.create(name='Theme 1')
+ self.theme2 = Thema.objects.create(name='Theme 2')
+
+ # Create vorgaben
+ self.vorgabe1 = Vorgabe.objects.create(
+ nummer=1,
+ order=1,
+ dokument=self.doc1,
+ thema=self.theme1,
+ titel='Vorgabe 1',
+ gueltigkeit_von=date.today()
+ )
+ self.vorgabe2 = Vorgabe.objects.create(
+ nummer=2,
+ order=2,
+ dokument=self.doc1,
+ thema=self.theme1,
+ titel='Vorgabe 2',
+ gueltigkeit_von=date.today()
+ )
+ self.vorgabe3 = Vorgabe.objects.create(
+ nummer=1,
+ order=1,
+ dokument=self.doc2,
+ thema=self.theme2,
+ titel='Vorgabe 3',
+ gueltigkeit_von=date.today()
+ )
+
+ # Create comments from different users
+ self.comment1 = VorgabeComment.objects.create(
+ vorgabe=self.vorgabe1,
+ user=self.user1,
+ text='User1 comment on vorgabe1'
+ )
+ self.comment2 = VorgabeComment.objects.create(
+ vorgabe=self.vorgabe2,
+ user=self.user1,
+ text='User1 comment on vorgabe2'
+ )
+ self.comment3 = VorgabeComment.objects.create(
+ vorgabe=self.vorgabe3,
+ user=self.user2,
+ text='User2 comment on vorgabe3'
+ )
+ self.comment4 = VorgabeComment.objects.create(
+ vorgabe=self.vorgabe1,
+ user=self.user2,
+ text='User2 comment on vorgabe1'
+ )
+
+ def test_all_comments_requires_login(self):
+ """Test that all comments view requires authentication"""
+ response = self.client.get(reverse('all_comments'))
+ self.assertEqual(response.status_code, 302)
+ self.assertIn('/login/', response.url)
+
+ def test_all_comments_staff_only(self):
+ """Test that non-staff users cannot access all comments view"""
+ self.client.login(username='user1', password='pass123')
+ response = self.client.get(reverse('all_comments'))
+ self.assertEqual(response.status_code, 302)
+ self.assertIn('/login/', response.url)
+
+ def test_all_comments_staff_can_access(self):
+ """Test that staff users can access all comments view"""
+ self.client.login(username='staff', password='pass123')
+ response = self.client.get(reverse('all_comments'))
+ self.assertEqual(response.status_code, 200)
+
+ def test_all_comments_shows_all_comments(self):
+ """Test that staff sees all comments from all users"""
+ self.client.login(username='staff', password='pass123')
+ response = self.client.get(reverse('all_comments'))
+
+ self.assertEqual(response.status_code, 200)
+ self.assertContains(response, 'User1 comment on vorgabe1')
+ self.assertContains(response, 'User1 comment on vorgabe2')
+ self.assertContains(response, 'User2 comment on vorgabe3')
+ self.assertContains(response, 'User2 comment on vorgabe1')
+
+ def test_all_comments_shows_usernames(self):
+ """Test that all comments display the username of the author"""
+ self.client.login(username='staff', password='pass123')
+ response = self.client.get(reverse('all_comments'))
+
+ self.assertEqual(response.status_code, 200)
+ # Check that user names appear in the response
+ self.assertContains(response, 'Max Mustermann')
+ self.assertContains(response, 'Anna Mueller')
+
+ def test_all_comments_grouped_by_document(self):
+ """Test that comments are properly grouped by document"""
+ self.client.login(username='staff', password='pass123')
+ response = self.client.get(reverse('all_comments'))
+
+ self.assertEqual(response.status_code, 200)
+ # Check that document titles appear
+ self.assertContains(response, 'DOC-001 – Document 1')
+ self.assertContains(response, 'DOC-002 – Document 2')
+
+ # Check context
+ self.assertIn('comments_by_document', response.context)
+ self.assertEqual(len(response.context['comments_by_document']), 2)
+
+ def test_all_comments_count_display(self):
+ """Test that total comment count is displayed"""
+ self.client.login(username='staff', password='pass123')
+ response = self.client.get(reverse('all_comments'))
+
+ self.assertEqual(response.status_code, 200)
+ self.assertEqual(response.context['total_comments'], 4)
+ self.assertContains(response, '4 Kommentare')
+
+ def test_all_comments_empty_view(self):
+ """Test the view when there are no comments"""
+ # Delete all comments
+ VorgabeComment.objects.all().delete()
+
+ self.client.login(username='staff', password='pass123')
+ response = self.client.get(reverse('all_comments'))
+
+ self.assertEqual(response.status_code, 200)
+ self.assertEqual(response.context['total_comments'], 0)
+ self.assertContains(response, 'Es gibt noch keine Kommentare')
+
+ def test_all_comments_template_used(self):
+ """Test that correct template is used"""
+ self.client.login(username='staff', password='pass123')
+ response = self.client.get(reverse('all_comments'))
+
+ self.assertEqual(response.status_code, 200)
+ self.assertTemplateUsed(response, 'standards/all_comments.html')
+
+ def test_all_comments_has_delete_buttons(self):
+ """Test that delete buttons are present for each comment"""
+ self.client.login(username='staff', password='pass123')
+ response = self.client.get(reverse('all_comments'))
+
+ self.assertEqual(response.status_code, 200)
+ # Check for delete button form elements - look for the delete form action URLs
+ self.assertContains(response, '/dokumente/comments/delete/', count=4)
+ # Also check for the delete button text
+ self.assertContains(response, 'Löschen', count=4)
+
+ def test_all_comments_vorgabe_number_link(self):
+ """Test that vorgabe numbers are linked correctly"""
+ self.client.login(username='staff', password='pass123')
+ response = self.client.get(reverse('all_comments'))
+
+ self.assertEqual(response.status_code, 200)
+ # Check that vorgabe numbers appear
+ self.assertContains(response, 'DOC-001.T.1')
+ self.assertContains(response, 'DOC-001.T.2')
+ self.assertContains(response, 'DOC-002.T.1')
+
+ def test_all_comments_ordered_by_document_and_date(self):
+ """Test that comments are ordered by document then by creation date"""
+ self.client.login(username='staff', password='pass123')
+ response = self.client.get(reverse('all_comments'))
+
+ self.assertEqual(response.status_code, 200)
+ # Check context has properly grouped comments
+ comments_by_doc = response.context['comments_by_document']
+
+ # Verify all documents are present
+ doc_numbers = [doc.nummer for doc in comments_by_doc.keys()]
+ self.assertIn('DOC-001', doc_numbers)
+ self.assertIn('DOC-002', doc_numbers)
+
+ def test_all_comments_displays_timestamps(self):
+ """Test that comment timestamps are displayed"""
+ self.client.login(username='staff', password='pass123')
+ response = self.client.get(reverse('all_comments'))
+
+ self.assertEqual(response.status_code, 200)
+ # Check that timestamp patterns appear (date formatting)
+ self.assertContains(response, 'Erstellt:')
+
+ def test_all_comments_regular_user_redirect(self):
+ """Test that regular users are redirected to login"""
+ # Create and login as regular user
+ regular_user = User.objects.create_user(username='regular', password='pass123')
+ self.client.login(username='regular', password='pass123')
+
+ response = self.client.get(reverse('all_comments'))
+ # Should redirect to login since user is not staff
+ self.assertEqual(response.status_code, 302)
+ self.assertIn('/login/', response.url)
+
+ def test_all_comments_no_own_comments_filter(self):
+ """Test that staff sees comments from ALL users, not just their own"""
+ self.client.login(username='staff', password='pass123')
+ response = self.client.get(reverse('all_comments'))
+
+ # Verify all comments are visible, not filtered by user
+ self.assertContains(response, 'User1 comment on vorgabe1')
+ self.assertContains(response, 'User2 comment on vorgabe1')
+ # Both users' comments on the same vorgabe should be visible
+ self.assertEqual(response.context['total_comments'], 4)
+
diff --git a/pages/templates/base.html b/pages/templates/base.html
index 424c607..90243d1 100644
--- a/pages/templates/base.html
+++ b/pages/templates/base.html
@@ -219,7 +219,7 @@
-
Version {{ version|default:"0.966" }}
+
Version {{ version|default:"0.967" }}