From 65b5a8b8b2bc77f66f2dd389e77e17494e4104b5 Mon Sep 17 00:00:00 2001 From: jedi Date: Sat, 23 Nov 2024 16:13:29 +0100 Subject: [PATCH 1/4] stash --- core/inventory/models.py | 2 +- core/inventory/tests/v2/test_items.py | 143 ++++++++++++++------------ 2 files changed, 77 insertions(+), 68 deletions(-) diff --git a/core/inventory/models.py b/core/inventory/models.py index fbbe0a9..10796e1 100644 --- a/core/inventory/models.py +++ b/core/inventory/models.py @@ -92,7 +92,7 @@ class Comment(models.Model): timestamp = models.DateTimeField(auto_now_add=True) def __str__(self): - return str(self.issue_thread) + ' comment #' + str(self.id) + return str(self.item) + ' comment #' + str(self.id) class Event(models.Model): diff --git a/core/inventory/tests/v2/test_items.py b/core/inventory/tests/v2/test_items.py index 8a38b86..375f257 100644 --- a/core/inventory/tests/v2/test_items.py +++ b/core/inventory/tests/v2/test_items.py @@ -7,7 +7,7 @@ from knox.models import AuthToken from authentication.models import ExtendedUser from files.models import File -from inventory.models import Event, Container, Item, Comment +from inventory.models import Event, Container, Item, Comment, ItemPlacement from base64 import b64encode @@ -19,7 +19,8 @@ class ItemTestCase(TestCase): def setUp(self): super().setUp() self.event = Event.objects.create(slug='EVENT', name='Event') - self.box = Container.objects.create(name='BOX') + self.box1 = Container.objects.create(name='BOX1') + self.box2 = Container.objects.create(name='BOX2') self.user = ExtendedUser.objects.create_user('testuser', 'test', 'test') self.user.user_permissions.add(*Permission.objects.all()) self.token = AuthToken.objects.create(user=self.user) @@ -36,7 +37,7 @@ class ItemTestCase(TestCase): def test_members_and_timeline(self): now = datetime.now() - item = Item.objects.create(container=self.box, event=self.event, description='1') + item = Item.objects.create(container=self.box1, event=self.event, description='1') comment = Comment.objects.create( item=item, comment="test", @@ -44,7 +45,12 @@ class ItemTestCase(TestCase): ) match = ItemRelation.objects.create( issue_thread=self.issue, - item = item, + item=item, + timestamp=now + timedelta(seconds=4), + ) + placement = ItemPlacement.objects.create( + container=self.box2, + item=item, timestamp=now + timedelta(seconds=5), ) response = self.client.get(f'/api/2/{self.event.slug}/item/') @@ -52,8 +58,8 @@ class ItemTestCase(TestCase): self.assertEqual(len(response.json()), 1) self.assertEqual(response.json()[0]['id'], item.id) self.assertEqual(response.json()[0]['description'], '1') - self.assertEqual(response.json()[0]['box'], 'BOX') - self.assertEqual(response.json()[0]['cid'], self.box.id) + self.assertEqual(response.json()[0]['box'], 'BOX2') + self.assertEqual(response.json()[0]['cid'], self.box2.id) self.assertEqual(response.json()[0]['file'], None) self.assertEqual(response.json()[0]['returned'], False) self.assertEqual(response.json()[0]['event'], self.event.slug) @@ -78,15 +84,15 @@ class ItemTestCase(TestCase): def test_members_with_file(self): import base64 - item = Item.objects.create(container=self.box, event=self.event, description='1') + item = Item.objects.create(container=self.box1, event=self.event, description='1') file = File.objects.create(item=item, data="data:text/plain;base64," + base64.b64encode(b"foo").decode('utf-8')) response = self.client.get(f'/api/2/{self.event.slug}/item/') self.assertEqual(response.status_code, 200) self.assertEqual(len(response.json()), 1) self.assertEqual(response.json()[0]['id'], item.id) self.assertEqual(response.json()[0]['description'], '1') - self.assertEqual(response.json()[0]['box'], 'BOX') - self.assertEqual(response.json()[0]['cid'], self.box.id) + self.assertEqual(response.json()[0]['box'], 'BOX1') + self.assertEqual(response.json()[0]['cid'], self.box1.id) self.assertEqual(response.json()[0]['file'], file.hash) self.assertEqual(response.json()[0]['returned'], False) self.assertEqual(response.json()[0]['event'], self.event.slug) @@ -94,36 +100,38 @@ class ItemTestCase(TestCase): def test_members_with_two_file(self): import base64 - item = Item.objects.create(container=self.box, event=self.event, description='1') - file1 = File.objects.create(item=item, data="data:text/plain;base64," + base64.b64encode(b"foo").decode('utf-8')) - file2 = File.objects.create(item=item, data="data:text/plain;base64," + base64.b64encode(b"bar").decode('utf-8')) + item = Item.objects.create(container=self.box1, event=self.event, description='1') + file1 = File.objects.create(item=item, + data="data:text/plain;base64," + base64.b64encode(b"foo").decode('utf-8')) + file2 = File.objects.create(item=item, + data="data:text/plain;base64," + base64.b64encode(b"bar").decode('utf-8')) response = self.client.get(f'/api/2/{self.event.slug}/item/') self.assertEqual(response.status_code, 200) self.assertEqual(len(response.json()), 1) self.assertEqual(response.json()[0]['id'], item.id) self.assertEqual(response.json()[0]['description'], '1') - self.assertEqual(response.json()[0]['box'], 'BOX') - self.assertEqual(response.json()[0]['cid'], self.box.id) + self.assertEqual(response.json()[0]['box'], 'BOX1') + self.assertEqual(response.json()[0]['cid'], self.box1.id) self.assertEqual(response.json()[0]['file'], file2.hash) self.assertEqual(response.json()[0]['returned'], False) self.assertEqual(response.json()[0]['event'], self.event.slug) self.assertEqual(len(response.json()[0]['related_issues']), 0) def test_multi_members(self): - Item.objects.create(container=self.box, event=self.event, description='1') - Item.objects.create(container=self.box, event=self.event, description='2') - Item.objects.create(container=self.box, event=self.event, description='3') + Item.objects.create(container=self.box1, event=self.event, description='1') + Item.objects.create(container=self.box1, event=self.event, description='2') + Item.objects.create(container=self.box1, event=self.event, description='3') response = self.client.get(f'/api/2/{self.event.slug}/item/') self.assertEqual(response.status_code, 200) self.assertEqual(len(response.json()), 3) def test_create_item(self): - response = self.client.post(f'/api/2/{self.event.slug}/item/', {'cid': self.box.id, 'description': '1'}) + response = self.client.post(f'/api/2/{self.event.slug}/item/', {'cid': self.box1.id, 'description': '1'}) self.assertEqual(response.status_code, 201) self.assertEqual(response.json()['id'], 1) self.assertEqual(response.json()['description'], '1') - self.assertEqual(response.json()['box'], 'BOX') - self.assertEqual(response.json()['cid'], self.box.id) + self.assertEqual(response.json()['box'], 'BOX1') + self.assertEqual(response.json()['cid'], self.box1.id) self.assertEqual(response.json()['file'], None) self.assertEqual(response.json()['returned'], False) self.assertEqual(response.json()['event'], self.event.slug) @@ -131,43 +139,43 @@ class ItemTestCase(TestCase): self.assertEqual(len(Item.objects.all()), 1) self.assertEqual(Item.objects.all()[0].id, 1) self.assertEqual(Item.objects.all()[0].description, '1') - self.assertEqual(Item.objects.all()[0].container.id, self.box.id) + self.assertEqual(Item.objects.all()[0].container.id, self.box1.id) def test_create_item_without_container(self): response = self.client.post(f'/api/2/{self.event.slug}/item/', {'description': '1'}) self.assertEqual(response.status_code, 400) def test_create_item_without_description(self): - response = self.client.post(f'/api/2/{self.event.slug}/item/', {'cid': self.box.id}) + response = self.client.post(f'/api/2/{self.event.slug}/item/', {'cid': self.box1.id}) self.assertEqual(response.status_code, 400) def test_create_item_with_file(self): import base64 response = self.client.post(f'/api/2/{self.event.slug}/item/', - {'cid': self.box.id, 'description': '1', + {'cid': self.box1.id, 'description': '1', 'dataImage': "data:text/plain;base64," + base64.b64encode(b"foo").decode( 'utf-8')}, content_type='application/json') self.assertEqual(response.status_code, 201) self.assertEqual(response.json()['id'], 1) self.assertEqual(response.json()['description'], '1') - self.assertEqual(response.json()['box'], 'BOX') - self.assertEqual(response.json()['id'], self.box.id) + self.assertEqual(response.json()['box'], 'BOX1') + self.assertEqual(response.json()['id'], self.box1.id) self.assertEqual(len(response.json()['file']), 64) self.assertEqual(len(Item.objects.all()), 1) self.assertEqual(Item.objects.all()[0].id, 1) self.assertEqual(Item.objects.all()[0].description, '1') - self.assertEqual(Item.objects.all()[0].container.id, self.box.id) + self.assertEqual(Item.objects.all()[0].container.id, self.box1.id) self.assertEqual(len(File.objects.all()), 1) def test_update_item(self): - item = Item.objects.create(container=self.box, event=self.event, description='1') + item = Item.objects.create(container=self.box1, event=self.event, description='1') response = self.client.patch(f'/api/2/{self.event.slug}/item/{item.id}/', {'description': '2'}, - content_type='application/json') + content_type='application/json') self.assertEqual(response.status_code, 200) self.assertEqual(response.json()['id'], item.id) self.assertEqual(response.json()['description'], '2') - self.assertEqual(response.json()['box'], 'BOX') - self.assertEqual(response.json()['cid'], self.box.id) + self.assertEqual(response.json()['box'], 'BOX1') + self.assertEqual(response.json()['cid'], self.box1.id) self.assertEqual(response.json()['file'], None) self.assertEqual(response.json()['returned'], False) self.assertEqual(response.json()['event'], self.event.slug) @@ -175,60 +183,62 @@ class ItemTestCase(TestCase): self.assertEqual(len(Item.objects.all()), 1) self.assertEqual(Item.objects.all()[0].id, 1) self.assertEqual(Item.objects.all()[0].description, '2') - self.assertEqual(Item.objects.all()[0].container.id, self.box.id) + self.assertEqual(Item.objects.all()[0].container.id, self.box1.id) def test_update_item_with_file(self): import base64 - item = Item.objects.create(container=self.box, event=self.event, description='1') + item = Item.objects.create(container=self.box1, event=self.event, description='1') response = self.client.patch(f'/api/2/{self.event.slug}/item/{item.id}/', - {'description': '2', - 'dataImage': "data:text/plain;base64," + base64.b64encode(b"foo").decode('utf-8')}, - content_type='application/json') + {'description': '2', + 'dataImage': "data:text/plain;base64," + base64.b64encode(b"foo").decode( + 'utf-8')}, + content_type='application/json') self.assertEqual(response.status_code, 200) self.assertEqual(response.json()['id'], 1) self.assertEqual(response.json()['description'], '2') - self.assertEqual(response.json()['box'], 'BOX') - self.assertEqual(response.json()['id'], self.box.id) + self.assertEqual(response.json()['box'], 'BOX1') + self.assertEqual(response.json()['id'], self.box1.id) self.assertEqual(len(response.json()['file']), 64) self.assertEqual(len(Item.objects.all()), 1) self.assertEqual(Item.objects.all()[0].id, 1) self.assertEqual(Item.objects.all()[0].description, '2') - self.assertEqual(Item.objects.all()[0].container.id, self.box.id) + self.assertEqual(Item.objects.all()[0].container.id, self.box1.id) self.assertEqual(len(File.objects.all()), 1) def test_delete_item(self): - item = Item.objects.create(container=self.box, event=self.event, description='1') - Item.objects.create(container=self.box, event=self.event, description='2') + item = Item.objects.create(container=self.box1, event=self.event, description='1') + Item.objects.create(container=self.box1, event=self.event, description='2') self.assertEqual(len(Item.objects.all()), 2) response = self.client.delete(f'/api/2/{self.event.slug}/item/{item.id}/') self.assertEqual(response.status_code, 204) self.assertEqual(len(Item.objects.all()), 1) def test_delete_item2(self): - Item.objects.create(container=self.box, event=self.event, description='1') - item2 = Item.objects.create(container=self.box, event=self.event, description='2') + Item.objects.create(container=self.box1, event=self.event, description='1') + item2 = Item.objects.create(container=self.box1, event=self.event, description='2') self.assertEqual(len(Item.objects.all()), 2) response = self.client.delete(f'/api/2/{self.event.slug}/item/{item2.id}/') self.assertEqual(response.status_code, 204) self.assertEqual(len(Item.objects.all()), 1) - item3 = Item.objects.create(container=self.box, event=self.event, description='3') + item3 = Item.objects.create(container=self.box1, event=self.event, description='3') self.assertEqual(item3.id, 3) self.assertEqual(len(Item.objects.all()), 2) def test_item_count(self): - Item.objects.create(container=self.box, event=self.event, description='1') - Item.objects.create(container=self.box, event=self.event, description='2') + Item.objects.create(container=self.box1, event=self.event, description='1') + Item.objects.create(container=self.box1, event=self.event, description='2') response = self.client.get('/api/2/boxes/') self.assertEqual(response.status_code, 200) - self.assertEqual(len(response.json()), 1) + self.assertEqual(len(response.json()), 2) self.assertEqual(response.json()[0]['itemCount'], 2) + self.assertEqual(response.json()[1]['itemCount'], 0) def test_item_nonexistent(self): response = self.client.get(f'/api/2/NOEVENT/item/') self.assertEqual(response.status_code, 404) def test_item_return(self): - item = Item.objects.create(container=self.box, event=self.event, description='1') + item = Item.objects.create(container=self.box1, event=self.event, description='1') self.assertEqual(item.returned_at, None) response = self.client.get(f'/api/2/{self.event.slug}/item/') self.assertEqual(response.status_code, 200) @@ -243,8 +253,8 @@ class ItemTestCase(TestCase): self.assertEqual(len(response.json()), 0) def test_item_show_not_returned(self): - item1 = Item.objects.create(container=self.box, event=self.event, description='1') - item2 = Item.objects.create(container=self.box, event=self.event, description='2') + item1 = Item.objects.create(container=self.box1, event=self.event, description='1') + item2 = Item.objects.create(container=self.box1, event=self.event, description='2') response = self.client.get(f'/api/2/{self.event.slug}/item/') self.assertEqual(response.status_code, 200) self.assertEqual(len(response.json()), 2) @@ -261,15 +271,15 @@ class ItemSearchTestCase(TestCase): def setUp(self): super().setUp() self.event = Event.objects.create(slug='EVENT', name='Event') - self.box = Container.objects.create(name='BOX') + self.box1 = Container.objects.create(name='BOX1') self.user = ExtendedUser.objects.create_user('testuser', 'test', 'test') self.user.user_permissions.add(*Permission.objects.all()) self.token = AuthToken.objects.create(user=self.user) self.client = Client(headers={'Authorization': 'Token ' + self.token[1]}) - self.item1 = Item.objects.create(container=self.box, event=self.event, description='abc def') - self.item2 = Item.objects.create(container=self.box, event=self.event, description='def ghi') - self.item3 = Item.objects.create(container=self.box, event=self.event, description='jkl mno pqr') - self.item4 = Item.objects.create(container=self.box, event=self.event, description='stu vwx') + self.item1 = Item.objects.create(container=self.box1, event=self.event, description='abc def') + self.item2 = Item.objects.create(container=self.box1, event=self.event, description='def ghi') + self.item3 = Item.objects.create(container=self.box1, event=self.event, description='jkl mno pqr') + self.item4 = Item.objects.create(container=self.box1, event=self.event, description='stu vwx') def test_search(self): search_query = b64encode(b'abc').decode('utf-8') @@ -278,8 +288,8 @@ class ItemSearchTestCase(TestCase): self.assertEqual(1, len(response.json())) self.assertEqual(self.item1.id, response.json()[0]['id']) self.assertEqual('abc def', response.json()[0]['description']) - self.assertEqual('BOX', response.json()[0]['box']) - self.assertEqual(self.box.id, response.json()[0]['cid']) + self.assertEqual('BOX1', response.json()[0]['box']) + self.assertEqual(self.box1.id, response.json()[0]['cid']) self.assertEqual(1, response.json()[0]['search_score']) def test_search2(self): @@ -289,13 +299,13 @@ class ItemSearchTestCase(TestCase): self.assertEqual(2, len(response.json())) self.assertEqual(self.item1.id, response.json()[0]['id']) self.assertEqual('abc def', response.json()[0]['description']) - self.assertEqual('BOX', response.json()[0]['box']) - self.assertEqual(self.box.id, response.json()[0]['cid']) + self.assertEqual('BOX1', response.json()[0]['box']) + self.assertEqual(self.box1.id, response.json()[0]['cid']) self.assertEqual(1, response.json()[0]['search_score']) self.assertEqual(self.item2.id, response.json()[1]['id']) self.assertEqual('def ghi', response.json()[1]['description']) - self.assertEqual('BOX', response.json()[1]['box']) - self.assertEqual(self.box.id, response.json()[1]['cid']) + self.assertEqual('BOX1', response.json()[1]['box']) + self.assertEqual(self.box1.id, response.json()[1]['cid']) self.assertEqual(1, response.json()[0]['search_score']) def test_search3(self): @@ -305,8 +315,8 @@ class ItemSearchTestCase(TestCase): self.assertEqual(1, len(response.json())) self.assertEqual(self.item3.id, response.json()[0]['id']) self.assertEqual('jkl mno pqr', response.json()[0]['description']) - self.assertEqual('BOX', response.json()[0]['box']) - self.assertEqual(self.box.id, response.json()[0]['cid']) + self.assertEqual('BOX1', response.json()[0]['box']) + self.assertEqual(self.box1.id, response.json()[0]['cid']) self.assertEqual(1, response.json()[0]['search_score']) def test_search4(self): @@ -316,12 +326,11 @@ class ItemSearchTestCase(TestCase): self.assertEqual(2, len(response.json())) self.assertEqual(self.item1.id, response.json()[0]['id']) self.assertEqual('abc def', response.json()[0]['description']) - self.assertEqual('BOX', response.json()[0]['box']) - self.assertEqual(self.box.id, response.json()[0]['cid']) + self.assertEqual('BOX1', response.json()[0]['box']) + self.assertEqual(self.box1.id, response.json()[0]['cid']) self.assertEqual(2, response.json()[0]['search_score']) self.assertEqual(self.item2.id, response.json()[1]['id']) self.assertEqual('def ghi', response.json()[1]['description']) - self.assertEqual('BOX', response.json()[1]['box']) - self.assertEqual(self.box.id, response.json()[1]['cid']) + self.assertEqual('BOX1', response.json()[1]['box']) + self.assertEqual(self.box1.id, response.json()[1]['cid']) self.assertEqual(1, response.json()[1]['search_score']) - From 8cedbb51800daef656f4f2abf08cb8263b8a2237 Mon Sep 17 00:00:00 2001 From: jedi Date: Sun, 24 Nov 2024 16:20:22 +0100 Subject: [PATCH 2/4] stash --- core/inventory/serializers.py | 8 +++++++ core/inventory/tests/v2/test_items.py | 33 +++++++++++++++++---------- 2 files changed, 29 insertions(+), 12 deletions(-) diff --git a/core/inventory/serializers.py b/core/inventory/serializers.py index 79caddd..f13235c 100644 --- a/core/inventory/serializers.py +++ b/core/inventory/serializers.py @@ -105,6 +105,14 @@ class ItemSerializer(BasicItemSerializer): 'timestamp': relation.timestamp, 'issue_thread': BasicIssueSerializer(relation.issue_thread).data, }) + for placement in (obj.container_history.all()): + timeline.append({ + 'type': 'placement', + 'id': placement.id, + 'timestamp': placement.timestamp, + 'cid': placement.container.id, + 'box': placement.container.name + }) return sorted(timeline, key=lambda x: x['timestamp']) diff --git a/core/inventory/tests/v2/test_items.py b/core/inventory/tests/v2/test_items.py index 375f257..0c85eb4 100644 --- a/core/inventory/tests/v2/test_items.py +++ b/core/inventory/tests/v2/test_items.py @@ -63,20 +63,29 @@ class ItemTestCase(TestCase): self.assertEqual(response.json()[0]['file'], None) self.assertEqual(response.json()[0]['returned'], False) self.assertEqual(response.json()[0]['event'], self.event.slug) - self.assertEqual(len(response.json()[0]['timeline']), 2) - self.assertEqual(response.json()[0]['timeline'][0]['type'], 'comment') - self.assertEqual(response.json()[0]['timeline'][1]['type'], 'issue_relation') - self.assertEqual(response.json()[0]['timeline'][0]['id'], comment.id) - self.assertEqual(response.json()[0]['timeline'][1]['id'], match.id) - self.assertEqual(response.json()[0]['timeline'][0]['comment'], 'test') - self.assertEqual(response.json()[0]['timeline'][0]['timestamp'], - comment.timestamp.strftime('%Y-%m-%dT%H:%M:%S.%fZ')) - self.assertEqual(response.json()[0]['timeline'][1]['status'], 'possible') + self.assertEqual(len(response.json()[0]['timeline']), 4) + self.assertEqual(response.json()[0]['timeline'][0]['type'], 'placement') + self.assertEqual(response.json()[0]['timeline'][1]['type'], 'comment') + self.assertEqual(response.json()[0]['timeline'][2]['type'], 'issue_relation') + self.assertEqual(response.json()[0]['timeline'][3]['type'], 'placement') + self.assertEqual(response.json()[0]['timeline'][1]['id'], comment.id) + self.assertEqual(response.json()[0]['timeline'][2]['id'], match.id) + self.assertEqual(response.json()[0]['timeline'][3]['id'], placement.id) + self.assertEqual(response.json()[0]['timeline'][0]['box'], 'BOX1') + self.assertEqual(response.json()[0]['timeline'][0]['cid'], self.box1.id) + self.assertEqual(response.json()[0]['timeline'][1]['comment'], 'test') self.assertEqual(response.json()[0]['timeline'][1]['timestamp'], + comment.timestamp.strftime('%Y-%m-%dT%H:%M:%S.%fZ')) + self.assertEqual(response.json()[0]['timeline'][2]['status'], 'possible') + self.assertEqual(response.json()[0]['timeline'][2]['timestamp'], match.timestamp.strftime('%Y-%m-%dT%H:%M:%S.%fZ')) - self.assertEqual(response.json()[0]['timeline'][1]['issue_thread']['name'], "test issue") - self.assertEqual(response.json()[0]['timeline'][1]['issue_thread']['event'], "EVENT") - self.assertEqual(response.json()[0]['timeline'][1]['issue_thread']['state'], "pending_new") + self.assertEqual(response.json()[0]['timeline'][2]['issue_thread']['name'], "test issue") + self.assertEqual(response.json()[0]['timeline'][2]['issue_thread']['event'], "EVENT") + self.assertEqual(response.json()[0]['timeline'][2]['issue_thread']['state'], "pending_new") + self.assertEqual(response.json()[0]['timeline'][3]['box'], 'BOX2') + self.assertEqual(response.json()[0]['timeline'][3]['cid'], self.box2.id) + self.assertEqual(response.json()[0]['timeline'][3]['timestamp'], + placement.timestamp.strftime('%Y-%m-%dT%H:%M:%S.%fZ')) self.assertEqual(len(response.json()[0]['related_issues']), 1) self.assertEqual(response.json()[0]['related_issues'][0]['name'], "test issue") self.assertEqual(response.json()[0]['related_issues'][0]['event'], "EVENT") From 401b71571ff7c349026818267c1f9c91bad0c1f8 Mon Sep 17 00:00:00 2001 From: jedi Date: Sun, 24 Nov 2024 21:58:26 +0100 Subject: [PATCH 3/4] stash --- web/src/components/AuthenticatedImage.vue | 28 ++- web/src/components/ItemTimeline.vue | 222 ------------------- web/src/components/Timeline.vue | 76 ++----- web/src/components/TimelinePlacement.vue | 85 +++++++ web/src/components/TimelineRelatedItem.vue | 14 +- web/src/components/TimelineRelatedTicket.vue | 98 ++++++++ web/src/main.js | 4 +- web/src/store.js | 13 +- web/src/views/Item.vue | 94 +++++--- web/src/views/Items.vue | 12 +- web/src/views/Ticket.vue | 127 ++++++++--- web/src/views/Tickets.vue | 12 +- web/src/views/admin/Events.vue | 4 +- 13 files changed, 417 insertions(+), 372 deletions(-) delete mode 100644 web/src/components/ItemTimeline.vue create mode 100644 web/src/components/TimelinePlacement.vue create mode 100644 web/src/components/TimelineRelatedTicket.vue diff --git a/web/src/components/AuthenticatedImage.vue b/web/src/components/AuthenticatedImage.vue index 9e1a963..8b463b0 100644 --- a/web/src/components/AuthenticatedImage.vue +++ b/web/src/components/AuthenticatedImage.vue @@ -42,19 +42,27 @@ export default { url: this.src, data: this.image_data }); + }, + deferImage() { + setTimeout(() => { + if (this.cached) { + const c = this.getThumbnail(this.src); + if (c) { + this.image_data = c; + return; + } + } + this.loadImage(); + }, 0); + } + }, + watch: { + src: function (newVal, oldVal) { + this.deferImage() } }, mounted() { - setTimeout(() => { - if (this.cached) { - const c = this.getThumbnail(this.src); - if (c) { - this.image_data = c; - return; - } - } - this.loadImage(); - }, 0); + this.deferImage(); } } \ No newline at end of file diff --git a/web/src/components/ItemTimeline.vue b/web/src/components/ItemTimeline.vue deleted file mode 100644 index fcf20ca..0000000 --- a/web/src/components/ItemTimeline.vue +++ /dev/null @@ -1,222 +0,0 @@ - - - - - \ No newline at end of file diff --git a/web/src/components/Timeline.vue b/web/src/components/Timeline.vue index 88bfa94..41e1274 100644 --- a/web/src/components/Timeline.vue +++ b/web/src/components/Timeline.vue @@ -21,6 +21,9 @@ + + + @@ -30,40 +33,15 @@ + +

{{ item }}

  • - - - -
    -
    - - - - Save Comment - -
    -
    +
  • - - - -
    -
    - {{ newestMailSubject }} -
    -
    - - - - Send Mail - -
    -
    +
  • @@ -78,12 +56,20 @@ import TimelineAssignment from "@/components/TimelineAssignment.vue"; import TimelineRelatedItem from "@/components/TimelineRelatedItem.vue"; import TimelineShippingVoucher from "@/components/TimelineShippingVoucher.vue"; import AsyncButton from "@/components/inputs/AsyncButton.vue"; +import TimelinePlacement from "@/components/TimelinePlacement.vue"; +import TimelineRelatedTicket from "@/components/TimelineRelatedTicket.vue"; export default { name: 'Timeline', components: { - TimelineShippingVoucher, AsyncButton, - TimelineRelatedItem, TimelineAssignment, TimelineStateChange, TimelineComment, TimelineMail + TimelineRelatedTicket, + TimelinePlacement, + TimelineShippingVoucher, + TimelineRelatedItem, + TimelineAssignment, + TimelineStateChange, + TimelineComment, + TimelineMail }, props: { timeline: { @@ -91,33 +77,13 @@ export default { default: () => [] } }, - emits: ['sendMail', 'addComment'], - data: () => ({ - newMail: "", - newComment: "" - }), computed: { - ...mapGetters(['stateInfo']), - newestMailSubject() { - const mail = this.timeline.filter(item => item.type === 'mail').pop(); - return mail ? mail.subject : ""; - }, + ...mapGetters(['stateInfo']) }, - methods: { - ...mapActions(['sendMail', 'postComment']), - sendMailAndClear: async function () { - await this.sendMail(this.newMail); - this.newMail = ""; - }, - addCommentAndClear: async function () { - await this.postComment(this.newComment); - this.newComment = ""; - } - } }; - \ No newline at end of file diff --git a/web/src/components/TimelineRelatedItem.vue b/web/src/components/TimelineRelatedItem.vue index c17a3a8..b795853 100644 --- a/web/src/components/TimelineRelatedItem.vue +++ b/web/src/components/TimelineRelatedItem.vue @@ -5,8 +5,12 @@ - linked item #{{ item.item.uid }} on as {{ item.status }} + linked item #{{ + item.item.id + }} on as {{ + item.status + }}
    @@ -20,8 +24,10 @@
    -
    uid: {{ item.item.uid }} box: {{ item.item.box }}
    -
    {{ item.item.description }}
    +
    id: {{ item.item.id }} box: {{ item.item.box }}
    + +
    {{ item.item.description }}
    +
    @@ -33,7 +71,7 @@
    @@ -58,6 +96,30 @@
    +
    +
    +
    +
    Related
    +
    + +
    + +
    id: {{ item.id }} box: {{ + item.box + }}
    + +
    {{ item.description }}
    +
    +
    +
    +
    +
    +
    @@ -68,15 +130,19 @@ import {mapActions, mapGetters, mapState} from 'vuex'; import Timeline from "@/components/Timeline.vue"; import ClipboardButton from "@/components/inputs/ClipboardButton.vue"; import AsyncLoader from "@/components/AsyncLoader.vue"; +import AuthenticatedImage from "@/components/AuthenticatedImage.vue"; +import AsyncButton from "@/components/inputs/AsyncButton.vue"; export default { name: 'Ticket', - components: {AsyncLoader, ClipboardButton, Timeline}, + components: {AsyncButton, AuthenticatedImage, AsyncLoader, ClipboardButton, Timeline}, data() { return { selected_state: null, selected_assignee: null, shipping_voucher_type: null, + newMail: "", + newComment: "" } }, computed: { @@ -90,46 +156,51 @@ export default { shippingEmail() { const domain = document.location.hostname; return `ticket+${this.ticket.uuid}@${domain}`; - } + }, + newestMailSubject() { + const mail = this.ticket.timeline ? this.ticket.timeline.filter(item => item.type === 'mail').pop() : null; + return mail ? mail.subject : ""; + }, }, methods: { ...mapActions(['deleteItem', 'markItemReturned', 'sendMail', 'updateTicketPartial', 'postComment']), ...mapActions(['loadTickets', 'fetchTicketStates', 'loadUsers', 'scheduleAfterInit']), ...mapActions(['claimShippingVoucher', 'fetchShippingVouchers']), - handleMail(mail) { - this.sendMail({ - id: this.ticket.id, - message: mail - }) - }, - handleComment(comment) { - this.postComment({ - id: this.ticket.id, - message: comment - }) - }, - changeTicketStatus(ticket) { - ticket.state = this.selected_state; + changeTicketStatus() { + this.ticket.state = this.selected_state; this.updateTicketPartial({ - id: ticket.id, + id: this.ticket.id, state: this.selected_state, }) }, - assignTicket(ticket) { - ticket.assigned_to = this.selected_assignee; + assignTicket() { + this.ticket.assigned_to = this.selected_assignee; this.updateTicketPartial({ - id: ticket.id, + id: this.ticket.id, assigned_to: this.selected_assignee }) }, + sendMailAndClear: async function () { + await this.sendMail({ + id: this.ticket.id, + message: this.newMail, + }) + this.newMail = ""; + }, + addCommentAndClear: async function () { + await this.postComment({ + id: this.ticket.id, + message: this.newComment + }) + this.newComment = ""; + } }, mounted() { this.scheduleAfterInit(() => [Promise.all([this.fetchTicketStates(), this.loadTickets(), this.loadUsers(), this.fetchShippingVouchers()]).then(() => { - if (this.ticket.state == "pending_new") { + if (this.ticket.state === "pending_new") { this.selected_state = "pending_open"; - this.changeTicketStatus(this.ticket) + this.changeTicketStatus() } - ; this.selected_state = this.ticket.state; this.selected_assignee = this.ticket.assigned_to })]); diff --git a/web/src/views/Tickets.vue b/web/src/views/Tickets.vue index 4c60aed..c85ad0a 100644 --- a/web/src/views/Tickets.vue +++ b/web/src/views/Tickets.vue @@ -12,11 +12,11 @@ > @@ -39,11 +39,11 @@ {{ item.event }} diff --git a/web/src/views/admin/Events.vue b/web/src/views/admin/Events.vue index e2ff952..62fedbb 100644 --- a/web/src/views/admin/Events.vue +++ b/web/src/views/admin/Events.vue @@ -88,11 +88,11 @@ export default { if (!this.events[id].addresses.includes(a)) this.events[id].addresses.push(a) this.new_address[id] = "" - this.updateEvent({id: this.events[id].eid, partial_event: {addresses: this.events[id].addresses}}); + this.updateEvent({id: this.events[id].id, partial_event: {addresses: this.events[id].addresses}}); }, deleteAddress(id, a_id) { this.events[id].addresses = this.events[id].addresses.filter((e, i) => i !== a_id); - this.updateEvent({id: this.events[id].eid, partial_event: {addresses: this.events[id].addresses}}); + this.updateEvent({id: this.events[id].id, partial_event: {addresses: this.events[id].addresses}}); } }, }; From 1a3aab4d418b2e4e7fd314e69cf04f768b36bae6 Mon Sep 17 00:00:00 2001 From: jedi Date: Thu, 28 Nov 2024 18:55:18 +0100 Subject: [PATCH 4/4] stash --- .forgejo/workflows/deploy_staging.yml | 8 +- core/.coveragerc | 7 +- web/src/App.vue | 13 ++-- web/src/components/inputs/InputCombo.vue | 6 +- web/src/store.js | 7 +- web/src/views/Item.vue | 95 ++++++++++++++---------- web/src/views/Items.vue | 40 ++-------- web/src/views/Ticket.vue | 5 +- web/src/views/Tickets.vue | 7 +- 9 files changed, 90 insertions(+), 98 deletions(-) diff --git a/.forgejo/workflows/deploy_staging.yml b/.forgejo/workflows/deploy_staging.yml index 0dccd66..881f31e 100644 --- a/.forgejo/workflows/deploy_staging.yml +++ b/.forgejo/workflows/deploy_staging.yml @@ -17,12 +17,12 @@ jobs: - name: Install dependencies working-directory: core run: pip3 install -r requirements.dev.txt - - name: Run django tests + - name: Run django tests with coverage working-directory: core - run: python3 manage.py test - - name: Run django coverage + run: coverage run manage.py test + - name: Evaluate coverage working-directory: core - run: coverage manage.py test + run: coverage report deploy: needs: [ test ] diff --git a/core/.coveragerc b/core/.coveragerc index 14c1fba..3091244 100644 --- a/core/.coveragerc +++ b/core/.coveragerc @@ -9,6 +9,9 @@ omit = */tests/* */migrations/* core/asgi.py - core/wsgi.py + core/globals.py core/settings.py - manage.py \ No newline at end of file + mail/socket.py + manage.py + server.py + helper.py \ No newline at end of file diff --git a/web/src/App.vue b/web/src/App.vue index bd4956f..d2c9f7d 100644 --- a/web/src/App.vue +++ b/web/src/App.vue @@ -1,5 +1,6 @@