Compare commits
6 commits
796b687719
...
016edae3eb
Author | SHA1 | Date | |
---|---|---|---|
016edae3eb | |||
eb9e9088ca | |||
b109e5995e | |||
a59423780e | |||
b6b29d9fed | |||
61c4beda47 |
10 changed files with 317 additions and 181 deletions
|
@ -1,6 +1,6 @@
|
||||||
from django.contrib import admin
|
from django.contrib import admin
|
||||||
|
|
||||||
from inventory.models import Item, Container, Event
|
from inventory.models import Item, Container, ItemPlacement, Comment, Event
|
||||||
|
|
||||||
|
|
||||||
class ItemAdmin(admin.ModelAdmin):
|
class ItemAdmin(admin.ModelAdmin):
|
||||||
|
@ -22,3 +22,17 @@ class EventAdmin(admin.ModelAdmin):
|
||||||
|
|
||||||
|
|
||||||
admin.site.register(Event, EventAdmin)
|
admin.site.register(Event, EventAdmin)
|
||||||
|
|
||||||
|
|
||||||
|
class ItemPlacementAdmin(admin.ModelAdmin):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
admin.site.register(ItemPlacement, ItemPlacementAdmin)
|
||||||
|
|
||||||
|
|
||||||
|
class CommentAdmin(admin.ModelAdmin):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
admin.site.register(Comment, CommentAdmin)
|
||||||
|
|
|
@ -1,12 +1,13 @@
|
||||||
from django.urls import re_path
|
from django.urls import re_path
|
||||||
from django.contrib.auth.decorators import permission_required
|
from django.contrib.auth.decorators import permission_required
|
||||||
from rest_framework import routers, viewsets
|
from rest_framework import routers, viewsets, status
|
||||||
from rest_framework.decorators import api_view, permission_classes
|
from rest_framework.decorators import api_view, permission_classes
|
||||||
from rest_framework.response import Response
|
from rest_framework.response import Response
|
||||||
from rest_framework.permissions import IsAuthenticated
|
from rest_framework.permissions import IsAuthenticated
|
||||||
|
|
||||||
from inventory.models import Event, Container, Item
|
from inventory.models import Event, Container, Item, Comment
|
||||||
from inventory.serializers import EventSerializer, ContainerSerializer, ItemSerializer, SearchResultSerializer
|
from inventory.serializers import EventSerializer, ContainerSerializer, CommentSerializer, ItemSerializer, \
|
||||||
|
SearchResultSerializer
|
||||||
|
|
||||||
from base64 import b64decode
|
from base64 import b64decode
|
||||||
|
|
||||||
|
@ -22,6 +23,20 @@ class ContainerViewSet(viewsets.ModelViewSet):
|
||||||
queryset = Container.objects.all()
|
queryset = Container.objects.all()
|
||||||
|
|
||||||
|
|
||||||
|
class ItemViewSet(viewsets.ModelViewSet):
|
||||||
|
serializer_class = ItemSerializer
|
||||||
|
|
||||||
|
def prefetch_queryset(self, queryset):
|
||||||
|
serializer = self.get_serializer_class()
|
||||||
|
if hasattr(serializer, 'Meta') and hasattr(serializer.Meta, 'prefetch_related_fields'):
|
||||||
|
queryset = queryset.prefetch_related(*serializer.Meta.prefetch_related_fields)
|
||||||
|
return queryset
|
||||||
|
|
||||||
|
def get_queryset(self):
|
||||||
|
queryset = Item.objects.all()
|
||||||
|
return self.prefetch_queryset(queryset)
|
||||||
|
|
||||||
|
|
||||||
def filter_items(items, query):
|
def filter_items(items, query):
|
||||||
query_tokens = query.split(' ')
|
query_tokens = query.split(' ')
|
||||||
for item in items:
|
for item in items:
|
||||||
|
@ -49,6 +64,7 @@ def search_items(request, event_slug, query):
|
||||||
@api_view(['GET', 'POST'])
|
@api_view(['GET', 'POST'])
|
||||||
@permission_classes([IsAuthenticated])
|
@permission_classes([IsAuthenticated])
|
||||||
def item(request, event_slug):
|
def item(request, event_slug):
|
||||||
|
vs = ItemViewSet()
|
||||||
try:
|
try:
|
||||||
event = None
|
event = None
|
||||||
if event_slug != 'none':
|
if event_slug != 'none':
|
||||||
|
@ -56,7 +72,7 @@ def item(request, event_slug):
|
||||||
if request.method == 'GET':
|
if request.method == 'GET':
|
||||||
if not request.user.has_event_perm(event, 'view_item'):
|
if not request.user.has_event_perm(event, 'view_item'):
|
||||||
return Response(status=403)
|
return Response(status=403)
|
||||||
return Response(ItemSerializer(Item.objects.filter(event=event), many=True).data)
|
return Response(ItemSerializer(vs.prefetch_queryset(Item.objects.filter(event=event)), many=True).data)
|
||||||
elif request.method == 'POST':
|
elif request.method == 'POST':
|
||||||
if not request.user.has_event_perm(event, 'add_item'):
|
if not request.user.has_event_perm(event, 'add_item'):
|
||||||
return Response(status=403)
|
return Response(status=403)
|
||||||
|
@ -71,6 +87,25 @@ def item(request, event_slug):
|
||||||
return Response(status=400)
|
return Response(status=400)
|
||||||
|
|
||||||
|
|
||||||
|
@api_view(['POST'])
|
||||||
|
@permission_classes([IsAuthenticated])
|
||||||
|
@permission_required('tickets.add_comment', raise_exception=True)
|
||||||
|
def add_comment(request, event_slug, id):
|
||||||
|
event = None
|
||||||
|
if event_slug != 'none':
|
||||||
|
event = Event.objects.get(slug=event_slug)
|
||||||
|
item = Item.objects.get(event=event, id=id)
|
||||||
|
if not request.user.has_event_perm(event, 'view_item'):
|
||||||
|
return Response(status=403)
|
||||||
|
if 'comment' not in request.data or request.data['comment'] == '':
|
||||||
|
return Response({'status': 'error', 'message': 'missing comment'}, status=status.HTTP_400_BAD_REQUEST)
|
||||||
|
comment = Comment.objects.create(
|
||||||
|
item=item,
|
||||||
|
comment=request.data['comment'],
|
||||||
|
)
|
||||||
|
return Response(CommentSerializer(comment).data, status=status.HTTP_201_CREATED)
|
||||||
|
|
||||||
|
|
||||||
@api_view(['GET', 'PUT', 'DELETE', 'PATCH'])
|
@api_view(['GET', 'PUT', 'DELETE', 'PATCH'])
|
||||||
@permission_classes([IsAuthenticated])
|
@permission_classes([IsAuthenticated])
|
||||||
def item_by_id(request, event_slug, id):
|
def item_by_id(request, event_slug, id):
|
||||||
|
@ -117,5 +152,6 @@ urlpatterns = router.urls + [
|
||||||
re_path(r'^(?P<event_slug>[\w-]+)/items/$', item, name='item'),
|
re_path(r'^(?P<event_slug>[\w-]+)/items/$', item, name='item'),
|
||||||
re_path(r'^(?P<event_slug>[\w-]+)/items/(?P<query>[-A-Za-z0-9+/]*={0,3})/$', search_items, name='search_items'),
|
re_path(r'^(?P<event_slug>[\w-]+)/items/(?P<query>[-A-Za-z0-9+/]*={0,3})/$', search_items, name='search_items'),
|
||||||
re_path(r'^(?P<event_slug>[\w-]+)/item/$', item, name='item'),
|
re_path(r'^(?P<event_slug>[\w-]+)/item/$', item, name='item'),
|
||||||
|
re_path(r'^(?P<event_slug>[\w-]+)/item/(?P<id>\d+)/comment/$', add_comment, name='add_comment'),
|
||||||
re_path(r'^(?P<event_slug>[\w-]+)/item/(?P<id>\d+)/$', item_by_id, name='item_by_id'),
|
re_path(r'^(?P<event_slug>[\w-]+)/item/(?P<id>\d+)/$', item_by_id, name='item_by_id'),
|
||||||
]
|
]
|
||||||
|
|
|
@ -1,36 +0,0 @@
|
||||||
# Generated by Django 4.2.7 on 2024-11-23 00:19
|
|
||||||
|
|
||||||
from django.db import migrations, models
|
|
||||||
import django.db.models.deletion
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
('inventory', '0006_alter_event_table'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.RemoveField(
|
|
||||||
model_name='item',
|
|
||||||
name='container',
|
|
||||||
),
|
|
||||||
migrations.CreateModel(
|
|
||||||
name='ItemPlacement',
|
|
||||||
fields=[
|
|
||||||
('id', models.AutoField(primary_key=True, serialize=False)),
|
|
||||||
('timestamp', models.DateTimeField(auto_now_add=True)),
|
|
||||||
('container', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='item_history', to='inventory.container')),
|
|
||||||
('item', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='container_history', to='inventory.item')),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
migrations.CreateModel(
|
|
||||||
name='Comment',
|
|
||||||
fields=[
|
|
||||||
('id', models.AutoField(primary_key=True, serialize=False)),
|
|
||||||
('comment', models.TextField()),
|
|
||||||
('timestamp', models.DateTimeField(auto_now_add=True)),
|
|
||||||
('item', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='comments', to='inventory.item')),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
]
|
|
|
@ -0,0 +1,52 @@
|
||||||
|
# Generated by Django 4.2.7 on 2024-11-23 15:27
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
import django.db.models.deletion
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
dependencies = [
|
||||||
|
('inventory', '0006_alter_event_table'),
|
||||||
|
]
|
||||||
|
|
||||||
|
def set_initial_container(apps, schema_editor):
|
||||||
|
Item = apps.get_model('inventory', 'Item')
|
||||||
|
for item in Item.objects.all():
|
||||||
|
item.container_history.get_or_create(container=item.container_old)
|
||||||
|
item.save()
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.RenameField(
|
||||||
|
model_name='item',
|
||||||
|
old_name='container',
|
||||||
|
new_name='container_old',
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='ItemPlacement',
|
||||||
|
fields=[
|
||||||
|
('id', models.AutoField(primary_key=True, serialize=False)),
|
||||||
|
('timestamp', models.DateTimeField(auto_now_add=True)),
|
||||||
|
('container',
|
||||||
|
models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='item_history',
|
||||||
|
to='inventory.container')),
|
||||||
|
('item',
|
||||||
|
models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='container_history',
|
||||||
|
to='inventory.item')),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='Comment',
|
||||||
|
fields=[
|
||||||
|
('id', models.AutoField(primary_key=True, serialize=False)),
|
||||||
|
('comment', models.TextField()),
|
||||||
|
('timestamp', models.DateTimeField(auto_now_add=True)),
|
||||||
|
('item', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='comments',
|
||||||
|
to='inventory.item')),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
migrations.RunPython(set_initial_container),
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='item',
|
||||||
|
name='container_old',
|
||||||
|
),
|
||||||
|
]
|
|
@ -32,7 +32,11 @@ class Item(SoftDeleteModel):
|
||||||
@property
|
@property
|
||||||
def container(self):
|
def container(self):
|
||||||
try:
|
try:
|
||||||
return self.container_history.order_by('-timestamp').first().container
|
history = sorted(self.container_history.all(), key=lambda x: x.timestamp, reverse=True)
|
||||||
|
if history:
|
||||||
|
return history[0].container
|
||||||
|
else:
|
||||||
|
return None
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
@ -92,7 +96,7 @@ class Comment(models.Model):
|
||||||
timestamp = models.DateTimeField(auto_now_add=True)
|
timestamp = models.DateTimeField(auto_now_add=True)
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return str(self.issue_thread) + ' comment #' + str(self.id)
|
return str(self.item) + ' comment #' + str(self.id)
|
||||||
|
|
||||||
|
|
||||||
class Event(models.Model):
|
class Event(models.Model):
|
||||||
|
|
|
@ -3,7 +3,7 @@ from rest_framework import serializers
|
||||||
from rest_framework.relations import SlugRelatedField
|
from rest_framework.relations import SlugRelatedField
|
||||||
|
|
||||||
from files.models import File
|
from files.models import File
|
||||||
from inventory.models import Event, Container, Item
|
from inventory.models import Event, Container, Item, Comment
|
||||||
from inventory.shared_serializers import BasicItemSerializer
|
from inventory.shared_serializers import BasicItemSerializer
|
||||||
from mail.models import EventAddress
|
from mail.models import EventAddress
|
||||||
from tickets.shared_serializers import BasicIssueSerializer
|
from tickets.shared_serializers import BasicIssueSerializer
|
||||||
|
@ -38,6 +38,18 @@ class ContainerSerializer(serializers.ModelSerializer):
|
||||||
return len(instance.items)
|
return len(instance.items)
|
||||||
|
|
||||||
|
|
||||||
|
class CommentSerializer(serializers.ModelSerializer):
|
||||||
|
|
||||||
|
def validate(self, attrs):
|
||||||
|
if 'comment' not in attrs or attrs['comment'] == '':
|
||||||
|
raise serializers.ValidationError('comment cannot be empty')
|
||||||
|
return attrs
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
model = Comment
|
||||||
|
fields = ('id', 'comment', 'timestamp', 'item')
|
||||||
|
|
||||||
|
|
||||||
class ItemSerializer(BasicItemSerializer):
|
class ItemSerializer(BasicItemSerializer):
|
||||||
timeline = serializers.SerializerMethodField()
|
timeline = serializers.SerializerMethodField()
|
||||||
dataImage = serializers.CharField(write_only=True, required=False)
|
dataImage = serializers.CharField(write_only=True, required=False)
|
||||||
|
@ -48,6 +60,12 @@ class ItemSerializer(BasicItemSerializer):
|
||||||
fields = ['cid', 'box', 'id', 'description', 'file', 'dataImage', 'returned', 'event', 'related_issues',
|
fields = ['cid', 'box', 'id', 'description', 'file', 'dataImage', 'returned', 'event', 'related_issues',
|
||||||
'timeline']
|
'timeline']
|
||||||
read_only_fields = ['id']
|
read_only_fields = ['id']
|
||||||
|
prefetch_related_fields = ['comments', 'issue_relation_changes', 'container_history',
|
||||||
|
'container_history__container', 'files', 'event',
|
||||||
|
'issue_relation_changes__issue_thread',
|
||||||
|
'issue_relation_changes__issue_thread__event',
|
||||||
|
'issue_relation_changes__issue_thread__state_changes',
|
||||||
|
'issue_relation_changes__issue_thread__assignments']
|
||||||
|
|
||||||
def to_internal_value(self, data):
|
def to_internal_value(self, data):
|
||||||
container = None
|
container = None
|
||||||
|
@ -106,6 +124,14 @@ class ItemSerializer(BasicItemSerializer):
|
||||||
'timestamp': relation.timestamp,
|
'timestamp': relation.timestamp,
|
||||||
'issue_thread': BasicIssueSerializer(relation.issue_thread).data,
|
'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'])
|
return sorted(timeline, key=lambda x: x['timestamp'])
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,7 @@ from knox.models import AuthToken
|
||||||
|
|
||||||
from authentication.models import ExtendedUser
|
from authentication.models import ExtendedUser
|
||||||
from files.models import File
|
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
|
from base64 import b64encode
|
||||||
|
|
||||||
|
@ -21,7 +21,8 @@ class ItemTestCase(TestCase):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
super().setUp()
|
super().setUp()
|
||||||
self.event = Event.objects.create(slug='EVENT', name='Event')
|
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 = ExtendedUser.objects.create_user('testuser', 'test', 'test')
|
||||||
self.user.user_permissions.add(*Permission.objects.all())
|
self.user.user_permissions.add(*Permission.objects.all())
|
||||||
self.token = AuthToken.objects.create(user=self.user)
|
self.token = AuthToken.objects.create(user=self.user)
|
||||||
|
@ -38,7 +39,7 @@ class ItemTestCase(TestCase):
|
||||||
|
|
||||||
def test_members_and_timeline(self):
|
def test_members_and_timeline(self):
|
||||||
now = datetime.now()
|
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(
|
comment = Comment.objects.create(
|
||||||
item=item,
|
item=item,
|
||||||
comment="test",
|
comment="test",
|
||||||
|
@ -47,6 +48,11 @@ class ItemTestCase(TestCase):
|
||||||
match = ItemRelation.objects.create(
|
match = ItemRelation.objects.create(
|
||||||
issue_thread=self.issue,
|
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),
|
timestamp=now + timedelta(seconds=5),
|
||||||
)
|
)
|
||||||
response = self.client.get(f'/api/2/{self.event.slug}/item/')
|
response = self.client.get(f'/api/2/{self.event.slug}/item/')
|
||||||
|
@ -54,25 +60,34 @@ class ItemTestCase(TestCase):
|
||||||
self.assertEqual(len(response.json()), 1)
|
self.assertEqual(len(response.json()), 1)
|
||||||
self.assertEqual(response.json()[0]['id'], item.id)
|
self.assertEqual(response.json()[0]['id'], item.id)
|
||||||
self.assertEqual(response.json()[0]['description'], '1')
|
self.assertEqual(response.json()[0]['description'], '1')
|
||||||
self.assertEqual(response.json()[0]['box'], 'BOX')
|
self.assertEqual(response.json()[0]['box'], 'BOX2')
|
||||||
self.assertEqual(response.json()[0]['cid'], self.box.id)
|
self.assertEqual(response.json()[0]['cid'], self.box2.id)
|
||||||
self.assertEqual(response.json()[0]['file'], None)
|
self.assertEqual(response.json()[0]['file'], None)
|
||||||
self.assertEqual(response.json()[0]['returned'], False)
|
self.assertEqual(response.json()[0]['returned'], False)
|
||||||
self.assertEqual(response.json()[0]['event'], self.event.slug)
|
self.assertEqual(response.json()[0]['event'], self.event.slug)
|
||||||
self.assertEqual(len(response.json()[0]['timeline']), 2)
|
self.assertEqual(len(response.json()[0]['timeline']), 4)
|
||||||
self.assertEqual(response.json()[0]['timeline'][0]['type'], 'comment')
|
self.assertEqual(response.json()[0]['timeline'][0]['type'], 'placement')
|
||||||
self.assertEqual(response.json()[0]['timeline'][1]['type'], 'issue_relation')
|
self.assertEqual(response.json()[0]['timeline'][1]['type'], 'comment')
|
||||||
self.assertEqual(response.json()[0]['timeline'][0]['id'], comment.id)
|
self.assertEqual(response.json()[0]['timeline'][2]['type'], 'issue_relation')
|
||||||
self.assertEqual(response.json()[0]['timeline'][1]['id'], match.id)
|
self.assertEqual(response.json()[0]['timeline'][3]['type'], 'placement')
|
||||||
self.assertEqual(response.json()[0]['timeline'][0]['comment'], 'test')
|
self.assertEqual(response.json()[0]['timeline'][1]['id'], comment.id)
|
||||||
self.assertEqual(response.json()[0]['timeline'][0]['timestamp'],
|
self.assertEqual(response.json()[0]['timeline'][2]['id'], match.id)
|
||||||
comment.timestamp.strftime('%Y-%m-%dT%H:%M:%S.%fZ'))
|
self.assertEqual(response.json()[0]['timeline'][3]['id'], placement.id)
|
||||||
self.assertEqual(response.json()[0]['timeline'][1]['status'], 'possible')
|
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'],
|
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'))
|
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'][2]['issue_thread']['name'], "test issue")
|
||||||
self.assertEqual(response.json()[0]['timeline'][1]['issue_thread']['event'], "EVENT")
|
self.assertEqual(response.json()[0]['timeline'][2]['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']['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(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]['name'], "test issue")
|
||||||
self.assertEqual(response.json()[0]['related_issues'][0]['event'], "EVENT")
|
self.assertEqual(response.json()[0]['related_issues'][0]['event'], "EVENT")
|
||||||
|
@ -80,15 +95,15 @@ class ItemTestCase(TestCase):
|
||||||
|
|
||||||
def test_members_with_file(self):
|
def test_members_with_file(self):
|
||||||
import base64
|
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'))
|
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/')
|
response = self.client.get(f'/api/2/{self.event.slug}/item/')
|
||||||
self.assertEqual(response.status_code, 200)
|
self.assertEqual(response.status_code, 200)
|
||||||
self.assertEqual(len(response.json()), 1)
|
self.assertEqual(len(response.json()), 1)
|
||||||
self.assertEqual(response.json()[0]['id'], item.id)
|
self.assertEqual(response.json()[0]['id'], item.id)
|
||||||
self.assertEqual(response.json()[0]['description'], '1')
|
self.assertEqual(response.json()[0]['description'], '1')
|
||||||
self.assertEqual(response.json()[0]['box'], 'BOX')
|
self.assertEqual(response.json()[0]['box'], 'BOX1')
|
||||||
self.assertEqual(response.json()[0]['cid'], self.box.id)
|
self.assertEqual(response.json()[0]['cid'], self.box1.id)
|
||||||
self.assertEqual(response.json()[0]['file'], file.hash)
|
self.assertEqual(response.json()[0]['file'], file.hash)
|
||||||
self.assertEqual(response.json()[0]['returned'], False)
|
self.assertEqual(response.json()[0]['returned'], False)
|
||||||
self.assertEqual(response.json()[0]['event'], self.event.slug)
|
self.assertEqual(response.json()[0]['event'], self.event.slug)
|
||||||
|
@ -96,36 +111,38 @@ class ItemTestCase(TestCase):
|
||||||
|
|
||||||
def test_members_with_two_file(self):
|
def test_members_with_two_file(self):
|
||||||
import base64
|
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')
|
||||||
file1 = File.objects.create(item=item, data="data:text/plain;base64," + base64.b64encode(b"foo").decode('utf-8'))
|
file1 = File.objects.create(item=item,
|
||||||
file2 = File.objects.create(item=item, data="data:text/plain;base64," + base64.b64encode(b"bar").decode('utf-8'))
|
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/')
|
response = self.client.get(f'/api/2/{self.event.slug}/item/')
|
||||||
self.assertEqual(response.status_code, 200)
|
self.assertEqual(response.status_code, 200)
|
||||||
self.assertEqual(len(response.json()), 1)
|
self.assertEqual(len(response.json()), 1)
|
||||||
self.assertEqual(response.json()[0]['id'], item.id)
|
self.assertEqual(response.json()[0]['id'], item.id)
|
||||||
self.assertEqual(response.json()[0]['description'], '1')
|
self.assertEqual(response.json()[0]['description'], '1')
|
||||||
self.assertEqual(response.json()[0]['box'], 'BOX')
|
self.assertEqual(response.json()[0]['box'], 'BOX1')
|
||||||
self.assertEqual(response.json()[0]['cid'], self.box.id)
|
self.assertEqual(response.json()[0]['cid'], self.box1.id)
|
||||||
self.assertEqual(response.json()[0]['file'], file2.hash)
|
self.assertEqual(response.json()[0]['file'], file2.hash)
|
||||||
self.assertEqual(response.json()[0]['returned'], False)
|
self.assertEqual(response.json()[0]['returned'], False)
|
||||||
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_multi_members(self):
|
def test_multi_members(self):
|
||||||
Item.objects.create(container=self.box, event=self.event, description='1')
|
Item.objects.create(container=self.box1, 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='2')
|
||||||
Item.objects.create(container=self.box, event=self.event, description='3')
|
Item.objects.create(container=self.box1, event=self.event, description='3')
|
||||||
response = self.client.get(f'/api/2/{self.event.slug}/item/')
|
response = self.client.get(f'/api/2/{self.event.slug}/item/')
|
||||||
self.assertEqual(response.status_code, 200)
|
self.assertEqual(response.status_code, 200)
|
||||||
self.assertEqual(len(response.json()), 3)
|
self.assertEqual(len(response.json()), 3)
|
||||||
|
|
||||||
def test_create_item(self):
|
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.status_code, 201)
|
||||||
self.assertEqual(response.json()['id'], 1)
|
self.assertEqual(response.json()['id'], 1)
|
||||||
self.assertEqual(response.json()['description'], '1')
|
self.assertEqual(response.json()['description'], '1')
|
||||||
self.assertEqual(response.json()['box'], 'BOX')
|
self.assertEqual(response.json()['box'], 'BOX1')
|
||||||
self.assertEqual(response.json()['cid'], self.box.id)
|
self.assertEqual(response.json()['cid'], self.box1.id)
|
||||||
self.assertEqual(response.json()['file'], None)
|
self.assertEqual(response.json()['file'], None)
|
||||||
self.assertEqual(response.json()['returned'], False)
|
self.assertEqual(response.json()['returned'], False)
|
||||||
self.assertEqual(response.json()['event'], self.event.slug)
|
self.assertEqual(response.json()['event'], self.event.slug)
|
||||||
|
@ -133,43 +150,43 @@ class ItemTestCase(TestCase):
|
||||||
self.assertEqual(len(Item.objects.all()), 1)
|
self.assertEqual(len(Item.objects.all()), 1)
|
||||||
self.assertEqual(Item.objects.all()[0].id, 1)
|
self.assertEqual(Item.objects.all()[0].id, 1)
|
||||||
self.assertEqual(Item.objects.all()[0].description, '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):
|
def test_create_item_without_container(self):
|
||||||
response = self.client.post(f'/api/2/{self.event.slug}/item/', {'description': '1'})
|
response = self.client.post(f'/api/2/{self.event.slug}/item/', {'description': '1'})
|
||||||
self.assertEqual(response.status_code, 400)
|
self.assertEqual(response.status_code, 400)
|
||||||
|
|
||||||
def test_create_item_without_description(self):
|
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)
|
self.assertEqual(response.status_code, 400)
|
||||||
|
|
||||||
def test_create_item_with_file(self):
|
def test_create_item_with_file(self):
|
||||||
import base64
|
import base64
|
||||||
response = self.client.post(f'/api/2/{self.event.slug}/item/',
|
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(
|
'dataImage': "data:text/plain;base64," + base64.b64encode(b"foo").decode(
|
||||||
'utf-8')}, content_type='application/json')
|
'utf-8')}, content_type='application/json')
|
||||||
self.assertEqual(response.status_code, 201)
|
self.assertEqual(response.status_code, 201)
|
||||||
self.assertEqual(response.json()['id'], 1)
|
self.assertEqual(response.json()['id'], 1)
|
||||||
self.assertEqual(response.json()['description'], '1')
|
self.assertEqual(response.json()['description'], '1')
|
||||||
self.assertEqual(response.json()['box'], 'BOX')
|
self.assertEqual(response.json()['box'], 'BOX1')
|
||||||
self.assertEqual(response.json()['id'], self.box.id)
|
self.assertEqual(response.json()['id'], self.box1.id)
|
||||||
self.assertEqual(len(response.json()['file']), 64)
|
self.assertEqual(len(response.json()['file']), 64)
|
||||||
self.assertEqual(len(Item.objects.all()), 1)
|
self.assertEqual(len(Item.objects.all()), 1)
|
||||||
self.assertEqual(Item.objects.all()[0].id, 1)
|
self.assertEqual(Item.objects.all()[0].id, 1)
|
||||||
self.assertEqual(Item.objects.all()[0].description, '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)
|
self.assertEqual(len(File.objects.all()), 1)
|
||||||
|
|
||||||
def test_update_item(self):
|
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'},
|
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.status_code, 200)
|
||||||
self.assertEqual(response.json()['id'], item.id)
|
self.assertEqual(response.json()['id'], item.id)
|
||||||
self.assertEqual(response.json()['description'], '2')
|
self.assertEqual(response.json()['description'], '2')
|
||||||
self.assertEqual(response.json()['box'], 'BOX')
|
self.assertEqual(response.json()['box'], 'BOX1')
|
||||||
self.assertEqual(response.json()['cid'], self.box.id)
|
self.assertEqual(response.json()['cid'], self.box1.id)
|
||||||
self.assertEqual(response.json()['file'], None)
|
self.assertEqual(response.json()['file'], None)
|
||||||
self.assertEqual(response.json()['returned'], False)
|
self.assertEqual(response.json()['returned'], False)
|
||||||
self.assertEqual(response.json()['event'], self.event.slug)
|
self.assertEqual(response.json()['event'], self.event.slug)
|
||||||
|
@ -177,60 +194,62 @@ class ItemTestCase(TestCase):
|
||||||
self.assertEqual(len(Item.objects.all()), 1)
|
self.assertEqual(len(Item.objects.all()), 1)
|
||||||
self.assertEqual(Item.objects.all()[0].id, 1)
|
self.assertEqual(Item.objects.all()[0].id, 1)
|
||||||
self.assertEqual(Item.objects.all()[0].description, '2')
|
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):
|
def test_update_item_with_file(self):
|
||||||
import base64
|
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}/',
|
response = self.client.patch(f'/api/2/{self.event.slug}/item/{item.id}/',
|
||||||
{'description': '2',
|
{'description': '2',
|
||||||
'dataImage': "data:text/plain;base64," + base64.b64encode(b"foo").decode('utf-8')},
|
'dataImage': "data:text/plain;base64," + base64.b64encode(b"foo").decode(
|
||||||
|
'utf-8')},
|
||||||
content_type='application/json')
|
content_type='application/json')
|
||||||
self.assertEqual(response.status_code, 200)
|
self.assertEqual(response.status_code, 200)
|
||||||
self.assertEqual(response.json()['id'], 1)
|
self.assertEqual(response.json()['id'], 1)
|
||||||
self.assertEqual(response.json()['description'], '2')
|
self.assertEqual(response.json()['description'], '2')
|
||||||
self.assertEqual(response.json()['box'], 'BOX')
|
self.assertEqual(response.json()['box'], 'BOX1')
|
||||||
self.assertEqual(response.json()['id'], self.box.id)
|
self.assertEqual(response.json()['id'], self.box1.id)
|
||||||
self.assertEqual(len(response.json()['file']), 64)
|
self.assertEqual(len(response.json()['file']), 64)
|
||||||
self.assertEqual(len(Item.objects.all()), 1)
|
self.assertEqual(len(Item.objects.all()), 1)
|
||||||
self.assertEqual(Item.objects.all()[0].id, 1)
|
self.assertEqual(Item.objects.all()[0].id, 1)
|
||||||
self.assertEqual(Item.objects.all()[0].description, '2')
|
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)
|
self.assertEqual(len(File.objects.all()), 1)
|
||||||
|
|
||||||
def test_delete_item(self):
|
def test_delete_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')
|
||||||
Item.objects.create(container=self.box, event=self.event, description='2')
|
Item.objects.create(container=self.box1, event=self.event, description='2')
|
||||||
self.assertEqual(len(Item.objects.all()), 2)
|
self.assertEqual(len(Item.objects.all()), 2)
|
||||||
response = self.client.delete(f'/api/2/{self.event.slug}/item/{item.id}/')
|
response = self.client.delete(f'/api/2/{self.event.slug}/item/{item.id}/')
|
||||||
self.assertEqual(response.status_code, 204)
|
self.assertEqual(response.status_code, 204)
|
||||||
self.assertEqual(len(Item.objects.all()), 1)
|
self.assertEqual(len(Item.objects.all()), 1)
|
||||||
|
|
||||||
def test_delete_item2(self):
|
def test_delete_item2(self):
|
||||||
Item.objects.create(container=self.box, event=self.event, description='1')
|
Item.objects.create(container=self.box1, event=self.event, description='1')
|
||||||
item2 = Item.objects.create(container=self.box, event=self.event, description='2')
|
item2 = Item.objects.create(container=self.box1, event=self.event, description='2')
|
||||||
self.assertEqual(len(Item.objects.all()), 2)
|
self.assertEqual(len(Item.objects.all()), 2)
|
||||||
response = self.client.delete(f'/api/2/{self.event.slug}/item/{item2.id}/')
|
response = self.client.delete(f'/api/2/{self.event.slug}/item/{item2.id}/')
|
||||||
self.assertEqual(response.status_code, 204)
|
self.assertEqual(response.status_code, 204)
|
||||||
self.assertEqual(len(Item.objects.all()), 1)
|
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(item3.id, 3)
|
||||||
self.assertEqual(len(Item.objects.all()), 2)
|
self.assertEqual(len(Item.objects.all()), 2)
|
||||||
|
|
||||||
def test_item_count(self):
|
def test_item_count(self):
|
||||||
Item.objects.create(container=self.box, event=self.event, description='1')
|
Item.objects.create(container=self.box1, 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='2')
|
||||||
response = self.client.get('/api/2/boxes/')
|
response = self.client.get('/api/2/boxes/')
|
||||||
self.assertEqual(response.status_code, 200)
|
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()[0]['itemCount'], 2)
|
||||||
|
self.assertEqual(response.json()[1]['itemCount'], 0)
|
||||||
|
|
||||||
def test_item_nonexistent(self):
|
def test_item_nonexistent(self):
|
||||||
response = self.client.get(f'/api/2/NOEVENT/item/')
|
response = self.client.get(f'/api/2/NOEVENT/item/')
|
||||||
self.assertEqual(response.status_code, 404)
|
self.assertEqual(response.status_code, 404)
|
||||||
|
|
||||||
def test_item_return(self):
|
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)
|
self.assertEqual(item.returned_at, None)
|
||||||
response = self.client.get(f'/api/2/{self.event.slug}/item/')
|
response = self.client.get(f'/api/2/{self.event.slug}/item/')
|
||||||
self.assertEqual(response.status_code, 200)
|
self.assertEqual(response.status_code, 200)
|
||||||
|
@ -245,8 +264,8 @@ class ItemTestCase(TestCase):
|
||||||
self.assertEqual(len(response.json()), 0)
|
self.assertEqual(len(response.json()), 0)
|
||||||
|
|
||||||
def test_item_show_not_returned(self):
|
def test_item_show_not_returned(self):
|
||||||
item1 = Item.objects.create(container=self.box, event=self.event, description='1')
|
item1 = Item.objects.create(container=self.box1, event=self.event, description='1')
|
||||||
item2 = Item.objects.create(container=self.box, event=self.event, description='2')
|
item2 = Item.objects.create(container=self.box1, event=self.event, description='2')
|
||||||
response = self.client.get(f'/api/2/{self.event.slug}/item/')
|
response = self.client.get(f'/api/2/{self.event.slug}/item/')
|
||||||
self.assertEqual(response.status_code, 200)
|
self.assertEqual(response.status_code, 200)
|
||||||
self.assertEqual(len(response.json()), 2)
|
self.assertEqual(len(response.json()), 2)
|
||||||
|
@ -258,6 +277,77 @@ class ItemTestCase(TestCase):
|
||||||
self.assertEqual(response.json()[0]['id'], item1.id)
|
self.assertEqual(response.json()[0]['id'], item1.id)
|
||||||
|
|
||||||
|
|
||||||
|
class ItemSearchTestCase(TestCase):
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
super().setUp()
|
||||||
|
self.event = Event.objects.create(slug='EVENT', name='Event')
|
||||||
|
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.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')
|
||||||
|
response = self.client.get(f'/api/2/{self.event.slug}/items/{search_query}/')
|
||||||
|
self.assertEqual(200, response.status_code)
|
||||||
|
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('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):
|
||||||
|
search_query = b64encode(b'def').decode('utf-8')
|
||||||
|
response = self.client.get(f'/api/2/{self.event.slug}/items/{search_query}/')
|
||||||
|
self.assertEqual(200, response.status_code)
|
||||||
|
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('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('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):
|
||||||
|
search_query = b64encode(b'jkl').decode('utf-8')
|
||||||
|
response = self.client.get(f'/api/2/{self.event.slug}/items/{search_query}/')
|
||||||
|
self.assertEqual(200, response.status_code)
|
||||||
|
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('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):
|
||||||
|
search_query = b64encode(b'abc def').decode('utf-8')
|
||||||
|
response = self.client.get(f'/api/2/{self.event.slug}/items/{search_query}/')
|
||||||
|
self.assertEqual(200, response.status_code)
|
||||||
|
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('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('BOX1', response.json()[1]['box'])
|
||||||
|
self.assertEqual(self.box1.id, response.json()[1]['cid'])
|
||||||
|
self.assertEqual(1, response.json()[1]['search_score'])
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class ItemSearchTestCase(TestCase):
|
class ItemSearchTestCase(TestCase):
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
|
@ -327,74 +417,3 @@ class ItemSearchTestCase(TestCase):
|
||||||
self.assertEqual(self.box.id, response.json()[1]['cid'])
|
self.assertEqual(self.box.id, response.json()[1]['cid'])
|
||||||
self.assertEqual(1, response.json()[1]['search_score'])
|
self.assertEqual(1, response.json()[1]['search_score'])
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
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.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')
|
|
||||||
|
|
||||||
def test_search(self):
|
|
||||||
search_query = b64encode(b'abc').decode('utf-8')
|
|
||||||
response = self.client.get(f'/api/2/{self.event.slug}/items/{search_query}/')
|
|
||||||
self.assertEqual(200, response.status_code)
|
|
||||||
self.assertEqual(1, len(response.json()))
|
|
||||||
self.assertEqual(self.item1.uid, response.json()[0]['uid'])
|
|
||||||
self.assertEqual('abc def', response.json()[0]['description'])
|
|
||||||
self.assertEqual('BOX', response.json()[0]['box'])
|
|
||||||
self.assertEqual(self.box.cid, response.json()[0]['cid'])
|
|
||||||
self.assertEqual(1, response.json()[0]['search_score'])
|
|
||||||
|
|
||||||
def test_search2(self):
|
|
||||||
search_query = b64encode(b'def').decode('utf-8')
|
|
||||||
response = self.client.get(f'/api/2/{self.event.slug}/items/{search_query}/')
|
|
||||||
self.assertEqual(200, response.status_code)
|
|
||||||
self.assertEqual(2, len(response.json()))
|
|
||||||
self.assertEqual(self.item1.uid, response.json()[0]['uid'])
|
|
||||||
self.assertEqual('abc def', response.json()[0]['description'])
|
|
||||||
self.assertEqual('BOX', response.json()[0]['box'])
|
|
||||||
self.assertEqual(self.box.cid, response.json()[0]['cid'])
|
|
||||||
self.assertEqual(1, response.json()[0]['search_score'])
|
|
||||||
self.assertEqual(self.item2.uid, response.json()[1]['uid'])
|
|
||||||
self.assertEqual('def ghi', response.json()[1]['description'])
|
|
||||||
self.assertEqual('BOX', response.json()[1]['box'])
|
|
||||||
self.assertEqual(self.box.cid, response.json()[1]['cid'])
|
|
||||||
self.assertEqual(1, response.json()[0]['search_score'])
|
|
||||||
|
|
||||||
def test_search3(self):
|
|
||||||
search_query = b64encode(b'jkl').decode('utf-8')
|
|
||||||
response = self.client.get(f'/api/2/{self.event.slug}/items/{search_query}/')
|
|
||||||
self.assertEqual(200, response.status_code)
|
|
||||||
self.assertEqual(1, len(response.json()))
|
|
||||||
self.assertEqual(self.item3.uid, response.json()[0]['uid'])
|
|
||||||
self.assertEqual('jkl mno pqr', response.json()[0]['description'])
|
|
||||||
self.assertEqual('BOX', response.json()[0]['box'])
|
|
||||||
self.assertEqual(self.box.cid, response.json()[0]['cid'])
|
|
||||||
self.assertEqual(1, response.json()[0]['search_score'])
|
|
||||||
|
|
||||||
def test_search4(self):
|
|
||||||
search_query = b64encode(b'abc def').decode('utf-8')
|
|
||||||
response = self.client.get(f'/api/2/{self.event.slug}/items/{search_query}/')
|
|
||||||
self.assertEqual(200, response.status_code)
|
|
||||||
self.assertEqual(2, len(response.json()))
|
|
||||||
self.assertEqual(self.item1.uid, response.json()[0]['uid'])
|
|
||||||
self.assertEqual('abc def', response.json()[0]['description'])
|
|
||||||
self.assertEqual('BOX', response.json()[0]['box'])
|
|
||||||
self.assertEqual(self.box.cid, response.json()[0]['cid'])
|
|
||||||
self.assertEqual(2, response.json()[0]['search_score'])
|
|
||||||
self.assertEqual(self.item2.uid, response.json()[1]['uid'])
|
|
||||||
self.assertEqual('def ghi', response.json()[1]['description'])
|
|
||||||
self.assertEqual('BOX', response.json()[1]['box'])
|
|
||||||
self.assertEqual(self.box.cid, response.json()[1]['cid'])
|
|
||||||
self.assertEqual(1, response.json()[1]['search_score'])
|
|
||||||
|
|
||||||
|
|
|
@ -21,7 +21,13 @@ 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')
|
|
||||||
|
def get_queryset(self):
|
||||||
|
queryset = IssueThread.objects.all()
|
||||||
|
serializer = self.get_serializer_class()
|
||||||
|
if hasattr(serializer, 'Meta') and hasattr(serializer.Meta, 'prefetch_related_fields'):
|
||||||
|
queryset = queryset.prefetch_related(*serializer.Meta.prefetch_related_fields)
|
||||||
|
return queryset
|
||||||
|
|
||||||
|
|
||||||
class RelationViewSet(viewsets.ModelViewSet):
|
class RelationViewSet(viewsets.ModelViewSet):
|
||||||
|
|
|
@ -47,6 +47,12 @@ class IssueSerializer(BasicIssueSerializer):
|
||||||
model = IssueThread
|
model = IssueThread
|
||||||
fields = ('id', 'timeline', 'name', 'state', 'assigned_to', 'last_activity', 'uuid', 'related_items', 'event')
|
fields = ('id', 'timeline', 'name', 'state', 'assigned_to', 'last_activity', 'uuid', 'related_items', 'event')
|
||||||
read_only_fields = ('id', 'timeline', 'last_activity', 'uuid', 'related_items')
|
read_only_fields = ('id', 'timeline', 'last_activity', 'uuid', 'related_items')
|
||||||
|
prefetch_related_fields = ['state_changes', 'comments', 'emails', 'emails__attachments', 'assignments',
|
||||||
|
'item_relation_changes', 'shipping_vouchers', 'item_relation_changes__item',
|
||||||
|
'item_relation_changes__item__container_history', 'event',
|
||||||
|
'item_relation_changes__item__container_history__container',
|
||||||
|
'item_relation_changes__item__files', 'item_relation_changes__item__event',
|
||||||
|
'item_relation_changes__item__event']
|
||||||
|
|
||||||
def to_internal_value(self, data):
|
def to_internal_value(self, data):
|
||||||
ret = super().to_internal_value(data)
|
ret = super().to_internal_value(data)
|
||||||
|
@ -63,12 +69,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 = max(
|
||||||
|
[t.timestamp for t in self.state_changes.all()]) if self.state_changes.exists() else None
|
||||||
last_comment = max([t.timestamp for t in self.comments.all()]) if self.comments.exists() else None
|
last_comment = max([t.timestamp for t in self.comments.all()]) if self.comments.exists() else None
|
||||||
last_mail = max([t.timestamp for t in self.emails.all()]) if self.emails.exists() else None
|
last_mail = max([t.timestamp for t in self.emails.all()]) if self.emails.exists() else None
|
||||||
last_assignment = max([t.timestamp for t in self.assignments.all()]) if self.assignments.exists() else None
|
last_assignment = max([t.timestamp for t in self.assignments.all()]) if self.assignments.exists() else None
|
||||||
|
|
||||||
last_relation = max([t.timestamp for t in self.item_relation_changes.all()]) if self.item_relation_changes.exists() else None
|
last_relation = max([t.timestamp for t in
|
||||||
|
self.item_relation_changes.all()]) if self.item_relation_changes.exists() 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)
|
||||||
|
@ -129,7 +137,6 @@ class IssueSerializer(BasicIssueSerializer):
|
||||||
return sorted(timeline, key=lambda x: x['timestamp'])
|
return sorted(timeline, key=lambda x: x['timestamp'])
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class SearchResultSerializer(serializers.Serializer):
|
class SearchResultSerializer(serializers.Serializer):
|
||||||
search_score = serializers.IntegerField()
|
search_score = serializers.IntegerField()
|
||||||
item = IssueSerializer()
|
item = IssueSerializer()
|
||||||
|
|
|
@ -75,6 +75,14 @@ server {
|
||||||
allow 127.0.0.1;
|
allow 127.0.0.1;
|
||||||
allow ::1;
|
allow ::1;
|
||||||
deny all;
|
deny all;
|
||||||
|
proxy_set_header Host $http_host;
|
||||||
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||||
|
proxy_set_header X-Forwarded-Proto $scheme;
|
||||||
|
proxy_set_header Upgrade $http_upgrade;
|
||||||
|
proxy_set_header Connection $connection_upgrade;
|
||||||
|
proxy_redirect off;
|
||||||
|
proxy_buffering off;
|
||||||
|
proxy_pass http://c3lf-sys3;
|
||||||
}
|
}
|
||||||
|
|
||||||
listen 443 ssl http2; # managed by Certbot
|
listen 443 ssl http2; # managed by Certbot
|
||||||
|
|
Loading…
Add table
Reference in a new issue