Compare commits

..

1 commit

Author SHA1 Message Date
1506509b9a add frontend to edit event details
Some checks failed
/ test (push) Failing after 52s
2024-11-21 02:25:36 +01:00
9 changed files with 60 additions and 111 deletions

View file

@ -1,24 +0,0 @@
# Generated by Django 4.2.7 on 2024-11-21 22:40
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('files', '0002_alter_file_file'),
]
def set_creation_date(apps, schema_editor):
File = apps.get_model('files', 'File')
for file in File.objects.all():
if file.created_at is None:
if not file.item.created_at is None:
file.created_at = file.item.created_at
else:
file.created_at = max(File.objects.filter(
id__lt=file.id, created_at__isnull=False).values_list('created_at', flat=True))
file.save()
operations = [
migrations.RunPython(set_creation_date),
]

View file

@ -9,7 +9,25 @@ from mail.models import EventAddress
from tickets.shared_serializers import BasicIssueSerializer from tickets.shared_serializers import BasicIssueSerializer
#class EventAdressSerializer(serializers.ModelSerializer):
# class Meta:
# model = EventAddress
# fields = ['address']
# def to_internal_value(self, data):
# if not isinstance(data, str):
# raise serializers.ValidationError('This field must be a string.')
#
# def create(self, validated_data):
# return EventAddress.objects.create(**validated_data)
#
# def validate(self, data):
# return isinstance(data, str)
class EventSerializer(serializers.ModelSerializer): class EventSerializer(serializers.ModelSerializer):
#addresses = EventAdressSerializer(many=True, required=False)
addresses = SlugRelatedField(many=True, slug_field='address', queryset=EventAddress.objects.all()) addresses = SlugRelatedField(many=True, slug_field='address', queryset=EventAddress.objects.all())
class Meta: class Meta:
@ -17,13 +35,16 @@ class EventSerializer(serializers.ModelSerializer):
fields = ['id', 'slug', 'name', 'start', 'end', 'pre_start', 'post_end', 'addresses'] fields = ['id', 'slug', 'name', 'start', 'end', 'pre_start', 'post_end', 'addresses']
read_only_fields = ['id'] read_only_fields = ['id']
def to_internal_value(self, data): # def update(self, instance, validated_data):
data = data.copy() # addresses = validated_data.pop('addresses', None)
addresses = data.pop('addresses', None) # instance.save(validated_data)
dict = super().to_internal_value(data) # if addresses:
if addresses: # for address in addresses:
dict['addresses'] = [EventAddress.objects.get_or_create(address=x)[0] for x in addresses] # nested_instance, created = EventAddress.objects.get_or_create(address=address)
return dict # instance.addresses.add(nested_instance)
#
# return instance
class ContainerSerializer(serializers.ModelSerializer): class ContainerSerializer(serializers.ModelSerializer):

View file

@ -24,7 +24,7 @@ class BasicItemSerializer(serializers.ModelSerializer):
def get_file(self, instance): def get_file(self, instance):
if len(instance.files.all()) > 0: if len(instance.files.all()) > 0:
return sorted(instance.files.all(), key=lambda x: x.created_at, reverse=True)[0].hash return instance.files.all().order_by('-created_at')[0].hash
return None return None
def get_returned(self, instance): def get_returned(self, instance):

View file

@ -50,16 +50,14 @@ class EventTestCase(TestCase):
def test_update_event(self): def test_update_event(self):
from rest_framework.test import APIClient from rest_framework.test import APIClient
event = Event.objects.create(slug='EVENT1', name='Event 1') event = Event.objects.create(slug='EVENT1', name='Event 1')
response = APIClient().patch(f'/api/2/events/{event.id}/', {'addresses': ['foo@bar.baz', 'foo1@bar.baz']}) response = APIClient().patch(f'/api/2/events/{event.eid}/', {'addresses': ['foo@bar.baz', 'foo1@bar.baz']})
self.assertEqual(response.status_code, 200) self.assertEqual(response.status_code, 200)
self.assertEqual(response.json()['slug'], 'EVENT1') self.assertEqual(response.json()['slug'], 'EVENT1')
self.assertEqual(response.json()['name'], 'Event 1') self.assertEqual(response.json()['name'], 'Event 1')
self.assertEqual(2, len(response.json()['addresses']))
self.assertEqual('foo@bar.baz', response.json()['addresses'][0])
self.assertEqual('foo1@bar.baz', response.json()['addresses'][1])
self.assertEqual(len(Event.objects.all()), 1) self.assertEqual(len(Event.objects.all()), 1)
self.assertEqual(Event.objects.all()[0].slug, 'EVENT1') self.assertEqual(Event.objects.all()[0].slug, 'EVENT1')
self.assertEqual(Event.objects.all()[0].name, 'Event 1') self.assertEqual(Event.objects.all()[0].name, 'Event 1')
self.assertEqual(1, len(response.json()[0]['addresses']))
def test_remove_event(self): def test_remove_event(self):
event = Event.objects.create(slug='EVENT1', name='Event 1') event = Event.objects.create(slug='EVENT1', name='Event 1')
@ -69,26 +67,13 @@ class EventTestCase(TestCase):
self.assertEqual(response.status_code, 204) self.assertEqual(response.status_code, 204)
self.assertEqual(len(Event.objects.all()), 1) self.assertEqual(len(Event.objects.all()), 1)
def test_event_with_address(self): def test_items2(self):
from mail.models import EventAddress from mail.models import EventAddress
event1 = Event.objects.create(slug='TEST1', name='Event') event1 = Event.objects.create(slug='TEST1', name='Event')
EventAddress.objects.create(event=event1, address='foo@bar.baz') EventAddress.objects.create(event=Event.objects.get(slug='TEST1'), address='foo@bar.baz')
response = self.client.get('/api/2/events/') response = self.client.get('/api/2/events/')
self.assertEqual(response.status_code, 200) self.assertEqual(response.status_code, 200)
self.assertEqual(1, len(response.json())) self.assertEqual(1, len(response.json()))
self.assertEqual('TEST1', response.json()[0]['slug']) self.assertEqual('TEST1', response.json()[0]['slug'])
self.assertEqual('Event', response.json()[0]['name']) self.assertEqual('Event', response.json()[0]['name'])
self.assertEqual(1, len(response.json()[0]['addresses'])) self.assertEqual(1, len(response.json()[0]['addresses']))
def test_items_remove_addresss(self):
from mail.models import EventAddress
from rest_framework.test import APIClient
event1 = Event.objects.create(slug='TEST1', name='Event')
EventAddress.objects.create(event=event1, address='foo@bar.baz')
EventAddress.objects.create(event=event1, address='fo1o@bar.baz')
response = APIClient().patch(f'/api/2/events/{event1.id}/', {'addresses': ['foo1@bar.baz']})
self.assertEqual(response.status_code, 200)
self.assertEqual('TEST1', response.json()['slug'])
self.assertEqual('Event', response.json()['name'])
self.assertEqual(1, len(response.json()['addresses']))
self.assertEqual('foo1@bar.baz', response.json()['addresses'][0])

View file

@ -56,23 +56,6 @@ class ItemTestCase(TestCase):
self.assertEqual(response.json()[0]['event'], self.event.slug) self.assertEqual(response.json()[0]['event'], self.event.slug)
self.assertEqual(len(response.json()[0]['related_issues']), 0) self.assertEqual(len(response.json()[0]['related_issues']), 0)
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'))
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]['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): 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='1')
Item.objects.create(container=self.box, event=self.event, description='2') Item.objects.create(container=self.box, event=self.event, description='2')

View file

@ -21,7 +21,7 @@ from tickets.shared_serializers import RelationSerializer
class IssueViewSet(viewsets.ModelViewSet): class IssueViewSet(viewsets.ModelViewSet):
serializer_class = IssueSerializer serializer_class = IssueSerializer
queryset = IssueThread.objects.all().prefetch_related('state_changes', 'comments', 'emails', 'emails__attachments', 'assignments', 'item_relation_changes', 'shipping_vouchers') queryset = IssueThread.objects.all()
class RelationViewSet(viewsets.ModelViewSet): class RelationViewSet(viewsets.ModelViewSet):
@ -148,12 +148,12 @@ def filter_issues(issues, query):
@api_view(['GET']) @api_view(['GET'])
@permission_classes([IsAuthenticated]) @permission_classes([])
# @permission_classes([IsAuthenticated])
# @permission_required('view_item', raise_exception=True)
def search_issues(request, event_slug, query): def search_issues(request, event_slug, query):
try: try:
event = Event.objects.get(slug=event_slug) event = Event.objects.get(slug=event_slug)
if not request.user.has_event_perm(event, 'view_issuethread'):
return Response(status=403)
items = filter_issues(IssueThread.objects.filter(event=event), b64decode(query).decode('utf-8')) items = filter_issues(IssueThread.objects.filter(event=event), b64decode(query).decode('utf-8'))
return Response(SearchResultSerializer(items, many=True).data) return Response(SearchResultSerializer(items, many=True).data)
except Event.DoesNotExist: except Event.DoesNotExist:

View file

@ -52,11 +52,7 @@ class IssueThread(SoftDeleteModel):
@property @property
def state(self): def state(self):
try: try:
state_changes = sorted(self.state_changes.all(), key=lambda x: x.timestamp, reverse=True) return self.state_changes.order_by('-timestamp').first().state
if state_changes:
return state_changes[0].state
else:
return None
except AttributeError: except AttributeError:
return 'none' return 'none'
@ -71,11 +67,7 @@ class IssueThread(SoftDeleteModel):
@property @property
def assigned_to(self): def assigned_to(self):
try: try:
assignments = sorted(self.assignments.all(), key=lambda x: x.timestamp, reverse=True) return self.assignments.order_by('-timestamp').first().assigned_to
if assignments:
return assignments[0].assigned_to
else:
return None
except AttributeError: except AttributeError:
return None return None

View file

@ -63,12 +63,14 @@ class IssueSerializer(BasicIssueSerializer):
@staticmethod @staticmethod
def get_last_activity(self): def get_last_activity(self):
try: try:
last_state_change = max([t.timestamp for t in self.state_changes.all()]) if self.state_changes.exists() else None last_state_change = self.state_changes.order_by('-timestamp').first().timestamp \
last_comment = max([t.timestamp for t in self.comments.all()]) if self.comments.exists() else None if self.state_changes.count() > 0 else None
last_mail = max([t.timestamp for t in self.emails.all()]) if self.emails.exists() else None last_comment = self.comments.order_by('-timestamp').first().timestamp if self.comments.count() > 0 else None
last_assignment = max([t.timestamp for t in self.assignments.all()]) if self.assignments.exists() else None last_mail = self.emails.order_by('-timestamp').first().timestamp if self.emails.count() > 0 else None
last_assignment = self.assignments.order_by('-timestamp').first().timestamp if \
last_relation = max([t.timestamp for t in self.item_relation_changes.all()]) if self.item_relation_changes.exists() else None self.assignments.count() > 0 else None
last_relation = self.item_relation_changes.order_by('-timestamp').first().timestamp if \
self.item_relation_changes.count() > 0 else None
args = [x for x in [last_state_change, last_comment, last_mail, last_assignment, last_relation] if args = [x for x in [last_state_change, last_comment, last_mail, last_assignment, last_relation] if
x is not None] x is not None]
return max(args) return max(args)

View file

@ -5,7 +5,7 @@ from django.test import TestCase, Client
from authentication.models import ExtendedUser from authentication.models import ExtendedUser
from inventory.models import Event, Container, Item from inventory.models import Event, Container, Item
from mail.models import Email, EmailAttachment from mail.models import Email, EmailAttachment
from tickets.models import IssueThread, StateChange, Comment, ItemRelation, Assignment from tickets.models import IssueThread, StateChange, Comment, ItemRelation
from django.contrib.auth.models import Permission from django.contrib.auth.models import Permission
from knox.models import AuthToken from knox.models import AuthToken
@ -53,24 +53,19 @@ class IssueApiTest(TestCase):
in_reply_to=mail1.reference, in_reply_to=mail1.reference,
timestamp=now + timedelta(seconds=2), timestamp=now + timedelta(seconds=2),
) )
assignment = Assignment.objects.create(
issue_thread=issue,
assigned_to=self.user,
timestamp=now + timedelta(seconds=3),
)
comment = Comment.objects.create( comment = Comment.objects.create(
issue_thread=issue, issue_thread=issue,
comment="test", comment="test",
timestamp=now + timedelta(seconds=4), timestamp=now + timedelta(seconds=3),
) )
match = ItemRelation.objects.create( match = ItemRelation.objects.create(
issue_thread=issue, issue_thread=issue,
item=self.item, item = self.item,
timestamp=now + timedelta(seconds=5), timestamp=now + timedelta(seconds=5),
) )
self.assertEqual('pending_new', issue.state) self.assertEqual('pending_new', issue.state)
self.assertEqual('test issue', issue.name) self.assertEqual('test issue', issue.name)
self.assertEqual(self.user, issue.assigned_to) self.assertEqual(None, issue.assigned_to)
self.assertEqual(36, len(issue.uuid)) self.assertEqual(36, len(issue.uuid))
response = self.client.get('/api/2/tickets/') response = self.client.get('/api/2/tickets/')
self.assertEqual(response.status_code, 200) self.assertEqual(response.status_code, 200)
@ -79,16 +74,14 @@ class IssueApiTest(TestCase):
self.assertEqual(response.json()[0]['name'], "test issue") self.assertEqual(response.json()[0]['name'], "test issue")
self.assertEqual(response.json()[0]['state'], "pending_new") self.assertEqual(response.json()[0]['state'], "pending_new")
self.assertEqual(response.json()[0]['event'], "evt") self.assertEqual(response.json()[0]['event'], "evt")
self.assertEqual(response.json()[0]['assigned_to'], self.user.username) self.assertEqual(response.json()[0]['assigned_to'], None)
self.assertEqual(response.json()[0]['uuid'], issue.uuid) self.assertEqual(response.json()[0]['uuid'], issue.uuid)
self.assertEqual(response.json()[0]['last_activity'], match.timestamp.strftime('%Y-%m-%dT%H:%M:%S.%fZ')) self.assertEqual(response.json()[0]['last_activity'], match.timestamp.strftime('%Y-%m-%dT%H:%M:%S.%fZ'))
self.assertEqual(len(response.json()[0]['timeline']), 6) self.assertEqual(len(response.json()[0]['timeline']), 5)
self.assertEqual(response.json()[0]['timeline'][0]['type'], 'state') self.assertEqual(response.json()[0]['timeline'][0]['type'], 'state')
self.assertEqual(response.json()[0]['timeline'][1]['type'], 'mail') self.assertEqual(response.json()[0]['timeline'][1]['type'], 'mail')
self.assertEqual(response.json()[0]['timeline'][2]['type'], 'mail') self.assertEqual(response.json()[0]['timeline'][2]['type'], 'mail')
self.assertEqual(response.json()[0]['timeline'][3]['type'], 'assignment') self.assertEqual(response.json()[0]['timeline'][3]['type'], 'comment')
self.assertEqual(response.json()[0]['timeline'][4]['type'], 'comment')
self.assertEqual(response.json()[0]['timeline'][5]['type'], 'item_relation')
self.assertEqual(response.json()[0]['timeline'][1]['id'], mail1.id) self.assertEqual(response.json()[0]['timeline'][1]['id'], mail1.id)
self.assertEqual(response.json()[0]['timeline'][2]['id'], mail2.id) self.assertEqual(response.json()[0]['timeline'][2]['id'], mail2.id)
self.assertEqual(response.json()[0]['timeline'][3]['id'], comment.id) self.assertEqual(response.json()[0]['timeline'][3]['id'], comment.id)
@ -105,18 +98,15 @@ class IssueApiTest(TestCase):
self.assertEqual(response.json()[0]['timeline'][2]['body'], 'test') self.assertEqual(response.json()[0]['timeline'][2]['body'], 'test')
self.assertEqual(response.json()[0]['timeline'][2]['timestamp'], self.assertEqual(response.json()[0]['timeline'][2]['timestamp'],
mail2.timestamp.strftime('%Y-%m-%dT%H:%M:%S.%fZ')) mail2.timestamp.strftime('%Y-%m-%dT%H:%M:%S.%fZ'))
self.assertEqual(response.json()[0]['timeline'][3]['assigned_to'], self.user.username) self.assertEqual(response.json()[0]['timeline'][3]['comment'], 'test')
self.assertEqual(response.json()[0]['timeline'][3]['timestamp'], self.assertEqual(response.json()[0]['timeline'][3]['timestamp'],
assignment.timestamp.strftime('%Y-%m-%dT%H:%M:%S.%fZ'))
self.assertEqual(response.json()[0]['timeline'][4]['comment'], 'test')
self.assertEqual(response.json()[0]['timeline'][4]['timestamp'],
comment.timestamp.strftime('%Y-%m-%dT%H:%M:%S.%fZ')) comment.timestamp.strftime('%Y-%m-%dT%H:%M:%S.%fZ'))
self.assertEqual(response.json()[0]['timeline'][5]['status'], 'possible') self.assertEqual(response.json()[0]['timeline'][4]['status'], 'possible')
self.assertEqual(response.json()[0]['timeline'][5]['timestamp'], self.assertEqual(response.json()[0]['timeline'][4]['timestamp'],
match.timestamp.strftime('%Y-%m-%dT%H:%M:%S.%fZ')) match.timestamp.strftime('%Y-%m-%dT%H:%M:%S.%fZ'))
self.assertEqual(response.json()[0]['timeline'][5]['item']['description'], "foo") self.assertEqual(response.json()[0]['timeline'][4]['item']['description'], "foo")
self.assertEqual(response.json()[0]['timeline'][5]['item']['event'], "evt") self.assertEqual(response.json()[0]['timeline'][4]['item']['event'], "evt")
self.assertEqual(response.json()[0]['timeline'][5]['item']['box'], "box1") self.assertEqual(response.json()[0]['timeline'][4]['item']['box'], "box1")
self.assertEqual(response.json()[0]['related_items'][0]['description'], "foo") self.assertEqual(response.json()[0]['related_items'][0]['description'], "foo")
self.assertEqual(response.json()[0]['related_items'][0]['event'], "evt") self.assertEqual(response.json()[0]['related_items'][0]['event'], "evt")
self.assertEqual(response.json()[0]['related_items'][0]['box'], "box1") self.assertEqual(response.json()[0]['related_items'][0]['box'], "box1")