Box edit taken out into it's own page; Editing of all fields added
All checks were successful
Build containers when image tags change / build-if-image-changed (., web, containers, main container, git.baumann.gr/adebaumann/labhelper) (push) Successful in 18s
Build containers when image tags change / build-if-image-changed (data-loader, loader, initContainers, init-container, git.baumann.gr/adebaumann/labhelper-data-loader) (push) Successful in 4s

This commit is contained in:
2026-01-05 13:28:10 +01:00
parent ca50832b54
commit da506221f7
7 changed files with 446 additions and 263 deletions

View File

@@ -441,9 +441,16 @@ class ThingDetailViewTests(AuthTestCase):
self.assertContains(response, 'Arduino Uno')
def test_thing_detail_shows_tags_section(self):
"""Thing detail page should show tags section."""
"""Thing detail page should show tags section when tags exist."""
facet = Facet.objects.create(
name='Electronics',
color='#FF5733',
cardinality=Facet.Cardinality.MULTIPLE
)
tag = Tag.objects.create(facet=facet, name='Arduino')
self.thing.tags.add(tag)
response = self.client.get(f'/thing/{self.thing.id}/')
self.assertContains(response, 'Tags')
self.assertContains(response, 'Electronics')
def test_thing_detail_shows_description(self):
"""Thing detail page should show thing description."""
@@ -472,25 +479,11 @@ class ThingDetailViewTests(AuthTestCase):
response = self.client.get(f'/thing/{self.thing.id}/')
self.assertRedirects(response, f'/login/?next=/thing/{self.thing.id}/')
def test_thing_detail_move_to_box(self):
"""Thing can be moved to another box via POST."""
new_box = Box.objects.create(id='BOX002', box_type=self.box_type)
response = self.client.post(
f'/thing/{self.thing.id}/',
{'action': 'move', 'new_box': 'BOX002'}
)
self.assertRedirects(response, f'/thing/{self.thing.id}/')
self.thing.refresh_from_db()
self.assertEqual(self.thing.box, new_box)
def test_thing_detail_move_shows_all_boxes(self):
"""Thing detail page should show all available boxes in dropdown."""
Box.objects.create(id='BOX002', box_type=self.box_type)
Box.objects.create(id='BOX003', box_type=self.box_type)
def test_thing_detail_has_edit_button(self):
"""Thing detail page should have an edit button."""
response = self.client.get(f'/thing/{self.thing.id}/')
self.assertContains(response, 'BOX001')
self.assertContains(response, 'BOX002')
self.assertContains(response, 'BOX003')
self.assertContains(response, 'Edit')
self.assertContains(response, f'/thing/{self.thing.id}/edit/')
class SearchViewTests(AuthTestCase):
@@ -1024,14 +1017,14 @@ class ThingPictureUploadTests(AuthTestCase):
b'\x05\x18\xd8N\x00\x00\x00\x00IEND\xaeB`\x82'
)
def test_thing_detail_shows_add_picture_button(self):
"""Thing detail page should show 'Add picture' button when thing has no picture."""
response = self.client.get(f'/thing/{self.thing.id}/')
def test_edit_thing_shows_add_picture_button(self):
"""Edit thing page should show 'Add picture' button when thing has no picture."""
response = self.client.get(f'/thing/{self.thing.id}/edit/')
self.assertEqual(response.status_code, 200)
self.assertContains(response, 'Add picture')
def test_thing_detail_shows_change_picture_button(self):
"""Thing detail page should show 'Change picture' button when thing has a picture."""
def test_edit_thing_shows_change_picture_button(self):
"""Edit thing page should show 'Change picture' button when thing has a picture."""
image = SimpleUploadedFile(
name='test.png',
content=self.image_data,
@@ -1039,14 +1032,14 @@ class ThingPictureUploadTests(AuthTestCase):
)
self.thing.picture = image
self.thing.save()
response = self.client.get(f'/thing/{self.thing.id}/')
response = self.client.get(f'/thing/{self.thing.id}/edit/')
self.assertEqual(response.status_code, 200)
self.assertContains(response, 'Change picture')
# Clean up
self.thing.picture.delete(save=False)
def test_thing_detail_shows_remove_button(self):
"""Thing detail page should show 'Remove' button when thing has a picture."""
def test_edit_thing_shows_remove_button(self):
"""Edit thing page should show 'Remove' button when thing has a picture."""
image = SimpleUploadedFile(
name='test.png',
content=self.image_data,
@@ -1054,14 +1047,14 @@ class ThingPictureUploadTests(AuthTestCase):
)
self.thing.picture = image
self.thing.save()
response = self.client.get(f'/thing/{self.thing.id}/')
response = self.client.get(f'/thing/{self.thing.id}/edit/')
self.assertEqual(response.status_code, 200)
self.assertContains(response, 'Remove')
# Clean up
self.thing.picture.delete(save=False)
def test_delete_picture_removes_picture(self):
"""Deleting a picture should remove it from the thing."""
"""Deleting a picture should remove it from thing."""
image = SimpleUploadedFile(
name='test.png',
content=self.image_data,
@@ -1070,19 +1063,28 @@ class ThingPictureUploadTests(AuthTestCase):
self.thing.picture = image
self.thing.save()
response = self.client.post(f'/thing/{self.thing.id}/', {
response = self.client.post(f'/thing/{self.thing.id}/edit/', {
'action': 'delete_picture'
})
self.assertRedirects(response, f'/thing/{self.thing.id}/')
self.assertRedirects(response, f'/thing/{self.thing.id}/edit/')
self.thing.refresh_from_db()
self.assertFalse(self.thing.picture.name)
def test_delete_picture_on_thing_without_picture(self):
"""Deleting a picture from a thing without a picture should succeed."""
response = self.client.post(f'/thing/{self.thing.id}/', {
response = self.client.post(f'/thing/{self.thing.id}/edit/', {
'action': 'delete_picture'
})
self.assertRedirects(response, f'/thing/{self.thing.id}/')
self.assertRedirects(response, f'/thing/{self.thing.id}/edit/')
self.thing.refresh_from_db()
self.assertFalse(self.thing.picture.name)
def test_delete_picture_on_thing_without_picture(self):
"""Deleting a picture from a thing without a picture should succeed."""
response = self.client.post(f'/thing/{self.thing.id}/edit/', {
'action': 'delete_picture'
})
self.assertRedirects(response, f'/thing/{self.thing.id}/edit/')
self.thing.refresh_from_db()
self.assertFalse(self.thing.picture.name)
@@ -1257,24 +1259,24 @@ class ThingFileAndLinkCRUDTests(AuthTestCase):
content_type='application/pdf'
)
response = self.client.post(
f'/thing/{self.thing.id}/',
f'/thing/{self.thing.id}/edit/',
{'action': 'add_file', 'title': 'Datasheet', 'file': uploaded_file}
)
self.assertRedirects(response, f'/thing/{self.thing.id}/')
self.assertRedirects(response, f'/thing/{self.thing.id}/edit/')
self.assertEqual(self.thing.files.count(), 1)
self.assertEqual(self.thing.files.first().title, 'Datasheet')
def test_add_link_to_thing(self):
"""Adding a link should create ThingLink."""
response = self.client.post(
f'/thing/{self.thing.id}/',
f'/thing/{self.thing.id}/edit/',
{
'action': 'add_link',
'title': 'Manufacturer',
'url': 'https://www.arduino.cc'
}
)
self.assertRedirects(response, f'/thing/{self.thing.id}/')
self.assertRedirects(response, f'/thing/{self.thing.id}/edit/')
self.assertEqual(self.thing.links.count(), 1)
self.assertEqual(self.thing.links.first().title, 'Manufacturer')
self.assertEqual(self.thing.links.first().url, 'https://www.arduino.cc')
@@ -1288,10 +1290,10 @@ class ThingFileAndLinkCRUDTests(AuthTestCase):
)
file_id = thing_file.id
response = self.client.post(
f'/thing/{self.thing.id}/',
f'/thing/{self.thing.id}/edit/',
{'action': 'delete_file', 'file_id': str(file_id)}
)
self.assertRedirects(response, f'/thing/{self.thing.id}/')
self.assertRedirects(response, f'/thing/{self.thing.id}/edit/')
self.assertFalse(ThingFile.objects.filter(id=file_id).exists())
def test_delete_link_from_thing(self):
@@ -1303,10 +1305,10 @@ class ThingFileAndLinkCRUDTests(AuthTestCase):
)
link_id = thing_link.id
response = self.client.post(
f'/thing/{self.thing.id}/',
f'/thing/{self.thing.id}/edit/',
{'action': 'delete_link', 'link_id': str(link_id)}
)
self.assertRedirects(response, f'/thing/{self.thing.id}/')
self.assertRedirects(response, f'/thing/{self.thing.id}/edit/')
self.assertFalse(ThingLink.objects.filter(id=link_id).exists())
def test_cannot_delete_file_from_other_thing(self):
@@ -1322,10 +1324,10 @@ class ThingFileAndLinkCRUDTests(AuthTestCase):
)
file_id = thing_file.id
response = self.client.post(
f'/thing/{self.thing.id}/',
f'/thing/{self.thing.id}/edit/',
{'action': 'delete_file', 'file_id': str(file_id)}
)
self.assertRedirects(response, f'/thing/{self.thing.id}/')
self.assertRedirects(response, f'/thing/{self.thing.id}/edit/')
self.assertTrue(ThingFile.objects.filter(id=file_id).exists())
def test_cannot_delete_link_from_other_thing(self):
@@ -1341,10 +1343,10 @@ class ThingFileAndLinkCRUDTests(AuthTestCase):
)
link_id = thing_link.id
response = self.client.post(
f'/thing/{self.thing.id}/',
f'/thing/{self.thing.id}/edit/',
{'action': 'delete_link', 'link_id': str(link_id)}
)
self.assertRedirects(response, f'/thing/{self.thing.id}/')
self.assertRedirects(response, f'/thing/{self.thing.id}/edit/')
self.assertTrue(ThingLink.objects.filter(id=link_id).exists())
def test_thing_detail_shows_files_section(self):
@@ -1371,9 +1373,9 @@ class ThingFileAndLinkCRUDTests(AuthTestCase):
self.assertContains(response, 'Links')
self.assertContains(response, 'Documentation')
def test_thing_detail_shows_upload_forms(self):
"""Thing detail page should show upload forms."""
response = self.client.get(f'/thing/{self.thing.id}/')
def test_edit_thing_shows_upload_forms(self):
"""Edit thing page should show upload forms."""
response = self.client.get(f'/thing/{self.thing.id}/edit/')
self.assertEqual(response.status_code, 200)
self.assertContains(response, 'Upload File')
self.assertContains(response, 'Add Link')
@@ -1630,29 +1632,29 @@ class ThingTagTests(AuthTestCase):
self.assertNotIn(self.tag, self.thing.tags.all())
def test_thing_detail_add_tag(self):
"""Thing detail page can add a tag via POST."""
"""Edit thing page can add a tag via POST."""
response = self.client.post(
f'/thing/{self.thing.id}/',
f'/thing/{self.thing.id}/edit/',
{'action': 'add_tag', 'tag_id': str(self.tag.id)}
)
self.assertRedirects(response, f'/thing/{self.thing.id}/')
self.assertRedirects(response, f'/thing/{self.thing.id}/edit/')
self.thing.refresh_from_db()
self.assertIn(self.tag, self.thing.tags.all())
def test_thing_detail_remove_tag(self):
"""Thing detail page can remove a tag via POST."""
"""Edit thing page can remove a tag via POST."""
self.thing.tags.add(self.tag)
response = self.client.post(
f'/thing/{self.thing.id}/',
f'/thing/{self.thing.id}/edit/',
{'action': 'remove_tag', 'tag_id': str(self.tag.id)}
)
self.assertRedirects(response, f'/thing/{self.thing.id}/')
self.assertRedirects(response, f'/thing/{self.thing.id}/edit/')
self.thing.refresh_from_db()
self.assertNotIn(self.tag, self.thing.tags.all())
def test_thing_detail_shows_available_tags(self):
"""Thing detail page should show available tags to add."""
response = self.client.get(f'/thing/{self.thing.id}/')
"""Edit thing page should show available tags to add."""
response = self.client.get(f'/thing/{self.thing.id}/edit/')
self.assertEqual(response.status_code, 200)
self.assertContains(response, 'Electronics')
@@ -1674,10 +1676,10 @@ class ThingTagTests(AuthTestCase):
self.thing.tags.add(tag_low)
response = self.client.post(
f'/thing/{self.thing.id}/',
f'/thing/{self.thing.id}/edit/',
{'action': 'add_tag', 'tag_id': str(tag_high.id)}
)
self.assertRedirects(response, f'/thing/{self.thing.id}/')
self.assertRedirects(response, f'/thing/{self.thing.id}/edit/')
self.thing.refresh_from_db()
self.assertNotIn(tag_low, self.thing.tags.all())
self.assertIn(tag_high, self.thing.tags.all())