stash
This commit is contained in:
parent
6aaa522a6b
commit
ba427c7a84
25 changed files with 274 additions and 236 deletions
|
@ -1,57 +1,85 @@
|
||||||
from rest_framework import routers, viewsets, serializers
|
from rest_framework import routers, viewsets, serializers, permissions
|
||||||
from rest_framework.decorators import api_view, permission_classes, authentication_classes
|
from rest_framework.decorators import api_view, permission_classes, authentication_classes
|
||||||
from rest_framework.response import Response
|
from rest_framework.response import Response
|
||||||
from rest_framework.authentication import BasicAuthentication
|
from django.contrib.auth import login
|
||||||
from django.contrib.auth.models import User
|
|
||||||
from django.urls import path
|
from django.urls import path
|
||||||
|
from django.dispatch import receiver
|
||||||
|
from django.db.models.signals import post_save
|
||||||
|
from knox.models import AuthToken
|
||||||
|
from knox.views import LoginView as KnoxLoginView
|
||||||
|
from rest_framework.authtoken.serializers import AuthTokenSerializer
|
||||||
|
|
||||||
|
from authentication.models import ExtendedUser
|
||||||
|
|
||||||
|
|
||||||
class UserSerializer(serializers.ModelSerializer):
|
class UserSerializer(serializers.ModelSerializer):
|
||||||
class Meta:
|
class Meta:
|
||||||
model = User
|
model = ExtendedUser
|
||||||
fields = ('id', 'username', 'email', 'first_name', 'last_name')
|
fields = ('id', 'username', 'email', 'first_name', 'last_name')
|
||||||
|
|
||||||
|
|
||||||
class RegisterUserSerializer(serializers.ModelSerializer):
|
@receiver(post_save, sender=ExtendedUser)
|
||||||
class Meta:
|
def create_auth_token(sender, instance=None, created=False, **kwargs):
|
||||||
model = User
|
if created:
|
||||||
fields = ('username', 'password', 'email')
|
AuthToken.objects.create(user=instance)
|
||||||
extra_kwargs = {
|
|
||||||
'password': {'write_only': True},
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
class UserViewSet(viewsets.ModelViewSet):
|
class UserViewSet(viewsets.ModelViewSet):
|
||||||
queryset = User.objects.all()
|
queryset = ExtendedUser.objects.all()
|
||||||
serializer_class = UserSerializer
|
serializer_class = UserSerializer
|
||||||
authentication_classes = [BasicAuthentication]
|
|
||||||
permission_classes = []
|
|
||||||
|
|
||||||
|
|
||||||
@api_view(['GET'])
|
@api_view(['POST'])
|
||||||
@permission_classes([])
|
def selfUser(request):
|
||||||
@authentication_classes([BasicAuthentication])
|
serializer = UserSerializer(request.user)
|
||||||
def token(request):
|
return Response(serializer.data, status=200)
|
||||||
return Response({
|
|
||||||
'token': request.user.auth_token.key
|
|
||||||
})
|
|
||||||
|
|
||||||
|
|
||||||
@api_view(['POST'])
|
@api_view(['POST'])
|
||||||
@permission_classes([])
|
@permission_classes([])
|
||||||
@authentication_classes([])
|
@authentication_classes([])
|
||||||
def registerUser(request):
|
def registerUser(request):
|
||||||
serializer = RegisterUserSerializer(data=request.data)
|
try:
|
||||||
if serializer.is_valid():
|
username = request.data.get('username')
|
||||||
user = serializer.save()
|
password = request.data.get('password')
|
||||||
|
email = request.data.get('email')
|
||||||
|
|
||||||
|
errors = {}
|
||||||
|
if not username:
|
||||||
|
errors['username'] = 'Username is required'
|
||||||
|
if not password:
|
||||||
|
errors['password'] = 'Password is required'
|
||||||
|
if not email:
|
||||||
|
errors['email'] = 'Email is required'
|
||||||
|
if ExtendedUser.objects.filter(email=email).exists():
|
||||||
|
errors['email'] = 'Email already exists'
|
||||||
|
if ExtendedUser.objects.filter(username=username).exists():
|
||||||
|
errors['username'] = 'Username already exists'
|
||||||
|
if errors:
|
||||||
|
return Response({'errors': errors}, status=400)
|
||||||
|
user = ExtendedUser.objects.create_user(username, email, password)
|
||||||
return Response({'username': user.username, 'email': user.email}, status=201)
|
return Response({'username': user.username, 'email': user.email}, status=201)
|
||||||
return Response(serializer.errors, status=400)
|
except Exception as e:
|
||||||
|
return Response({'errors': str(e)}, status=400)
|
||||||
|
|
||||||
|
|
||||||
|
class LoginView(KnoxLoginView):
|
||||||
|
permission_classes = (permissions.AllowAny,)
|
||||||
|
authentication_classes = ()
|
||||||
|
|
||||||
|
def post(self, request, format=None):
|
||||||
|
serializer = AuthTokenSerializer(data=request.data)
|
||||||
|
serializer.is_valid(raise_exception=True)
|
||||||
|
user = serializer.validated_data['user']
|
||||||
|
login(request, user)
|
||||||
|
return super(LoginView, self).post(request, format=None)
|
||||||
|
|
||||||
|
|
||||||
router = routers.SimpleRouter()
|
router = routers.SimpleRouter()
|
||||||
router.register(r'users', UserViewSet, basename='users')
|
router.register(r'users', UserViewSet, basename='users')
|
||||||
|
|
||||||
urlpatterns = router.urls + [
|
urlpatterns = router.urls + [
|
||||||
path('token/', token),
|
path('self/', selfUser),
|
||||||
|
path('login/', LoginView.as_view()),
|
||||||
path('register/', registerUser),
|
path('register/', registerUser),
|
||||||
]
|
]
|
||||||
|
|
|
@ -1,35 +0,0 @@
|
||||||
# Generated by Django 4.2.7 on 2023-11-26 00:16
|
|
||||||
|
|
||||||
from django.conf import settings
|
|
||||||
from django.db import migrations
|
|
||||||
from django.contrib.auth.models import Permission, Group
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
initial = True
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
|
||||||
('authentication', '0001_initial'),
|
|
||||||
('inventory', '0003_alter_item_options'),
|
|
||||||
('tickets', '0003_alter_issuethread_options'),
|
|
||||||
]
|
|
||||||
|
|
||||||
def create_groups(apps, schema_editor):
|
|
||||||
admins = Group.objects.create(name='Admin')
|
|
||||||
orga = Group.objects.create(name='Orga')
|
|
||||||
team = Group.objects.create(name='Team')
|
|
||||||
users = Group.objects.create(name='User')
|
|
||||||
admins.permissions.add(*Permission.objects.all())
|
|
||||||
users.permissions.add(*Permission.objects.filter(codename__in=
|
|
||||||
['view_item', 'add_item', 'change_item', 'match_item']))
|
|
||||||
team.permissions.add(*Permission.objects.filter(codename__in=
|
|
||||||
['delete_item', 'view_issuethread', 'add_issuethread',
|
|
||||||
'change_issuethread', 'delete_issuethread', 'send_mail']),
|
|
||||||
*users.permissions.all())
|
|
||||||
orga.permissions.add(*Permission.objects.filter(codename__in=['add_event']),
|
|
||||||
*team.permissions.all())
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.RunPython(create_groups),
|
|
||||||
]
|
|
34
core/authentication/tests/v2/test_permissions.py
Normal file
34
core/authentication/tests/v2/test_permissions.py
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
from django.test import TestCase
|
||||||
|
from django.contrib.auth.models import Permission
|
||||||
|
|
||||||
|
from authentication.models import EventPermission, ExtendedUser
|
||||||
|
from inventory.models import Event
|
||||||
|
|
||||||
|
|
||||||
|
class PermissionsTestCase(TestCase):
|
||||||
|
def setUp(self):
|
||||||
|
super().setUp()
|
||||||
|
self.user = ExtendedUser.objects.create_user('testuser', 'test', 'test')
|
||||||
|
event1 = Event.objects.create(slug='testevent1', name='testevent1')
|
||||||
|
event2 = Event.objects.create(slug='testevent2', name='testevent2')
|
||||||
|
permission1 = Permission.objects.get(codename='view_event')
|
||||||
|
EventPermission.objects.create(user=self.user, permission=permission1, event=event1)
|
||||||
|
EventPermission.objects.create(user=self.user, permission=permission1, event=event2)
|
||||||
|
|
||||||
|
def test_user_permissions(self):
|
||||||
|
"""
|
||||||
|
Test that a user can only access their own data.
|
||||||
|
"""
|
||||||
|
self.client.force_login(self.user)
|
||||||
|
response = self.client.get('/api/2/users/')
|
||||||
|
self.assertEqual(response.status_code, 200)
|
||||||
|
self.assertEqual(len(response.json()), 2)
|
||||||
|
self.assertEqual(response.json()[0]['username'], 'testuser')
|
||||||
|
self.assertEqual(response.json()[0]['email'], 'test')
|
||||||
|
self.assertEqual(response.json()[0]['first_name'], '')
|
||||||
|
self.assertEqual(response.json()[0]['last_name'], '')
|
||||||
|
self.assertEqual(response.json()[0]['id'], 1)
|
||||||
|
self.assertEqual(response.json()[1]['username'], 'testuser')
|
||||||
|
self.assertEqual(response.json()[1]['email'], 'test')
|
||||||
|
self.assertEqual(response.json()[1]['first_name'], '')
|
||||||
|
self.assertEqual(response.json()[1]['last_name'], '')
|
|
@ -1,18 +1,93 @@
|
||||||
from django.test import TestCase, Client
|
from django.test import TestCase, Client
|
||||||
|
|
||||||
|
from knox.models import AuthToken
|
||||||
|
|
||||||
|
from authentication.models import ExtendedUser
|
||||||
from core import settings
|
from core import settings
|
||||||
|
|
||||||
client = Client()
|
|
||||||
|
|
||||||
|
class UserApiTest(TestCase):
|
||||||
|
|
||||||
class IssueApiTest(TestCase):
|
def setUp(self):
|
||||||
|
self.user = ExtendedUser.objects.create_user('testuser', 'test', 'test')
|
||||||
|
self.user.save()
|
||||||
|
self.token = AuthToken.objects.create(user=self.user)
|
||||||
|
self.client = Client(headers={'Authorization': 'Token ' + self.token[1]})
|
||||||
|
|
||||||
def test_issues(self):
|
def test_users(self):
|
||||||
response = client.get('/api/2/users/')
|
response = self.client.get('/api/2/users/')
|
||||||
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]['username'], settings.LEGACY_USER_NAME)
|
self.assertEqual(response.json()[0]['username'], settings.LEGACY_USER_NAME)
|
||||||
self.assertEqual(response.json()[0]['email'], 'mail@' + settings.MAIL_DOMAIN)
|
self.assertEqual(response.json()[0]['email'], 'mail@' + settings.MAIL_DOMAIN)
|
||||||
self.assertEqual(response.json()[0]['first_name'], '')
|
self.assertEqual(response.json()[0]['first_name'], '')
|
||||||
self.assertEqual(response.json()[0]['last_name'], '')
|
self.assertEqual(response.json()[0]['last_name'], '')
|
||||||
self.assertEqual(response.json()[0]['id'], 1)
|
self.assertEqual(response.json()[0]['id'], 1)
|
||||||
|
self.assertEqual(response.json()[1]['username'], 'testuser')
|
||||||
|
self.assertEqual(response.json()[1]['email'], 'test')
|
||||||
|
self.assertEqual(response.json()[1]['first_name'], '')
|
||||||
|
self.assertEqual(response.json()[1]['last_name'], '')
|
||||||
|
|
||||||
|
def test_self_user(self):
|
||||||
|
response = self.client.post('/api/2/self/')
|
||||||
|
self.assertEqual(response.status_code, 200)
|
||||||
|
self.assertEqual(response.json()['username'], 'testuser')
|
||||||
|
self.assertEqual(response.json()['email'], 'test')
|
||||||
|
self.assertEqual(response.json()['first_name'], '')
|
||||||
|
self.assertEqual(response.json()['last_name'], '')
|
||||||
|
|
||||||
|
def test_register_user(self):
|
||||||
|
anonymous = Client()
|
||||||
|
response = anonymous.post('/api/2/register/', {'username': 'testuser2', 'password': 'test', 'email': 'test2'},
|
||||||
|
content_type='application/json')
|
||||||
|
self.assertEqual(response.status_code, 201)
|
||||||
|
self.assertEqual(response.json()['username'], 'testuser2')
|
||||||
|
self.assertEqual(response.json()['email'], 'test2')
|
||||||
|
self.assertEqual(len(ExtendedUser.objects.all()), 3)
|
||||||
|
self.assertEqual(ExtendedUser.objects.get(username='testuser2').email, 'test2')
|
||||||
|
self.assertTrue(ExtendedUser.objects.get(username='testuser2').check_password('test'))
|
||||||
|
|
||||||
|
def test_register_user_duplicate(self):
|
||||||
|
anonymous = Client()
|
||||||
|
response = anonymous.post('/api/2/register/', {'username': 'testuser', 'password': 'test', 'email': 'test2'},
|
||||||
|
content_type='application/json')
|
||||||
|
self.assertEqual(response.status_code, 400)
|
||||||
|
self.assertEqual(response.json()['errors']['username'], 'Username already exists')
|
||||||
|
self.assertEqual(len(ExtendedUser.objects.all()), 2)
|
||||||
|
|
||||||
|
def test_register_user_no_username(self):
|
||||||
|
anonymous = Client()
|
||||||
|
response = anonymous.post('/api/2/register/', {'password': 'test', 'email': 'test2'},
|
||||||
|
content_type='application/json')
|
||||||
|
self.assertEqual(response.status_code, 400)
|
||||||
|
self.assertEqual(response.json()['errors']['username'], 'Username is required')
|
||||||
|
self.assertEqual(len(ExtendedUser.objects.all()), 2)
|
||||||
|
|
||||||
|
def test_register_user_no_password(self):
|
||||||
|
anonymous = Client()
|
||||||
|
response = anonymous.post('/api/2/register/', {'username': 'testuser2', 'email': 'test2'},
|
||||||
|
content_type='application/json')
|
||||||
|
self.assertEqual(response.status_code, 400)
|
||||||
|
self.assertEqual(response.json()['errors']['password'], 'Password is required')
|
||||||
|
self.assertEqual(len(ExtendedUser.objects.all()), 2)
|
||||||
|
|
||||||
|
def test_register_user_no_email(self):
|
||||||
|
anonymous = Client()
|
||||||
|
response = anonymous.post('/api/2/register/', {'username': 'testuser2', 'password': 'test'},
|
||||||
|
content_type='application/json')
|
||||||
|
self.assertEqual(response.status_code, 400)
|
||||||
|
self.assertEqual(response.json()['errors']['email'], 'Email is required')
|
||||||
|
self.assertEqual(len(ExtendedUser.objects.all()), 2)
|
||||||
|
|
||||||
|
def test_register_user_duplicate_email(self):
|
||||||
|
anonymous = Client()
|
||||||
|
response = anonymous.post('/api/2/register/', {'username': 'testuser2', 'password': 'test', 'email': 'test'},
|
||||||
|
content_type='application/json')
|
||||||
|
self.assertEqual(response.status_code, 400)
|
||||||
|
self.assertEqual(response.json()['errors']['email'], 'Email already exists')
|
||||||
|
self.assertEqual(len(ExtendedUser.objects.all()), 2)
|
||||||
|
|
||||||
|
def test_get_token(self):
|
||||||
|
anonymous = Client()
|
||||||
|
response = anonymous.post('/api/2/login/', {'username': 'testuser', 'password': 'test'},
|
||||||
|
content_type='application/json')
|
||||||
|
|
|
@ -51,7 +51,7 @@ INSTALLED_APPS = [
|
||||||
'django.contrib.staticfiles',
|
'django.contrib.staticfiles',
|
||||||
'django_extensions',
|
'django_extensions',
|
||||||
'rest_framework',
|
'rest_framework',
|
||||||
'rest_framework.authtoken',
|
'knox',
|
||||||
'drf_yasg',
|
'drf_yasg',
|
||||||
'channels',
|
'channels',
|
||||||
'authentication',
|
'authentication',
|
||||||
|
@ -63,9 +63,13 @@ INSTALLED_APPS = [
|
||||||
]
|
]
|
||||||
|
|
||||||
REST_FRAMEWORK = {
|
REST_FRAMEWORK = {
|
||||||
'TEST_REQUEST_DEFAULT_FORMAT': 'json'
|
'TEST_REQUEST_DEFAULT_FORMAT': 'json',
|
||||||
|
'DEFAULT_AUTHENTICATION_CLASSES': ('knox.auth.TokenAuthentication',),
|
||||||
|
'DEFAULT_PERMISSION_CLASSES': ('rest_framework.permissions.IsAuthenticated',),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
AUTH_USER_MODEL = 'authentication.ExtendedUser'
|
||||||
|
|
||||||
SWAGGER_SETTINGS = {
|
SWAGGER_SETTINGS = {
|
||||||
'SECURITY_DEFINITIONS': {
|
'SECURITY_DEFINITIONS': {
|
||||||
'api_key': {
|
'api_key': {
|
||||||
|
|
|
@ -16,6 +16,8 @@ class FileViewSet(viewsets.ModelViewSet):
|
||||||
serializer_class = FileSerializer
|
serializer_class = FileSerializer
|
||||||
queryset = File.objects.all()
|
queryset = File.objects.all()
|
||||||
lookup_field = 'hash'
|
lookup_field = 'hash'
|
||||||
|
permission_classes = []
|
||||||
|
authentication_classes = []
|
||||||
|
|
||||||
|
|
||||||
router = routers.SimpleRouter(trailing_slash=False)
|
router = routers.SimpleRouter(trailing_slash=False)
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
# Generated by Django 4.2.7 on 2023-11-18 11:28
|
# Generated by Django 4.2.7 on 2023-12-09 02:13
|
||||||
|
|
||||||
from django.db import migrations, models
|
from django.db import migrations, models
|
||||||
import django.db.models.deletion
|
import django.db.models.deletion
|
||||||
|
|
|
@ -1,22 +1,26 @@
|
||||||
from django.test import TestCase, Client
|
from django.test import TestCase, Client
|
||||||
|
|
||||||
|
from authentication.models import ExtendedUser
|
||||||
from files.models import File
|
from files.models import File
|
||||||
from inventory.models import Event, Container, Item
|
from inventory.models import Event, Container, Item
|
||||||
|
from knox.models import AuthToken
|
||||||
client = Client()
|
|
||||||
|
|
||||||
|
|
||||||
class FileTestCase(TestCase):
|
class FileTestCase(TestCase):
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
super().setUp()
|
super().setUp()
|
||||||
|
self.user = ExtendedUser.objects.create_user('testuser', 'test', 'test')
|
||||||
|
self.user.save()
|
||||||
|
self.token = AuthToken.objects.create(user=self.user)
|
||||||
|
self.client = Client(headers={'Authorization': 'Token ' + self.token[1]})
|
||||||
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.box = Container.objects.create(name='BOX')
|
||||||
|
|
||||||
def test_list_files(self):
|
def test_list_files(self):
|
||||||
import base64
|
import base64
|
||||||
item = File.objects.create(data="data:text/plain;base64," + base64.b64encode(b"foo").decode('utf-8'))
|
item = File.objects.create(data="data:text/plain;base64," + base64.b64encode(b"foo").decode('utf-8'))
|
||||||
response = client.get('/api/2/files/')
|
response = self.client.get('/api/2/files/')
|
||||||
self.assertEqual(response.status_code, 200)
|
self.assertEqual(response.status_code, 200)
|
||||||
self.assertEqual(response.json()[0]['hash'], item.hash)
|
self.assertEqual(response.json()[0]['hash'], item.hash)
|
||||||
self.assertEqual(len(response.json()[0]['hash']), 64)
|
self.assertEqual(len(response.json()[0]['hash']), 64)
|
||||||
|
@ -24,7 +28,7 @@ class FileTestCase(TestCase):
|
||||||
def test_one_file(self):
|
def test_one_file(self):
|
||||||
import base64
|
import base64
|
||||||
item = File.objects.create(data="data:text/plain;base64," + base64.b64encode(b"foo").decode('utf-8'))
|
item = File.objects.create(data="data:text/plain;base64," + base64.b64encode(b"foo").decode('utf-8'))
|
||||||
response = client.get(f'/api/2/files/{item.hash}/')
|
response = self.client.get(f'/api/2/files/{item.hash}/')
|
||||||
self.assertEqual(response.status_code, 200)
|
self.assertEqual(response.status_code, 200)
|
||||||
self.assertEqual(response.json()['hash'], item.hash)
|
self.assertEqual(response.json()['hash'], item.hash)
|
||||||
self.assertEqual(len(response.json()['hash']), 64)
|
self.assertEqual(len(response.json()['hash']), 64)
|
||||||
|
@ -33,7 +37,7 @@ class FileTestCase(TestCase):
|
||||||
import base64
|
import base64
|
||||||
Item.objects.create(container=self.box, event=self.event, description='1')
|
Item.objects.create(container=self.box, event=self.event, description='1')
|
||||||
item = Item.objects.create(container=self.box, event=self.event, description='2')
|
item = Item.objects.create(container=self.box, event=self.event, description='2')
|
||||||
response = client.post('/api/2/files/',
|
response = self.client.post('/api/2/files/',
|
||||||
{'data': "data:text/plain;base64," + base64.b64encode(b"foo").decode('utf-8')},
|
{'data': "data:text/plain;base64," + base64.b64encode(b"foo").decode('utf-8')},
|
||||||
content_type='application/json')
|
content_type='application/json')
|
||||||
self.assertEqual(response.status_code, 201)
|
self.assertEqual(response.status_code, 201)
|
||||||
|
@ -45,5 +49,5 @@ class FileTestCase(TestCase):
|
||||||
File.objects.create(item=item, data="data:text/plain;base64," + base64.b64encode(b"foo").decode('utf-8'))
|
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"bar").decode('utf-8'))
|
file = File.objects.create(item=item, data="data:text/plain;base64," + base64.b64encode(b"bar").decode('utf-8'))
|
||||||
self.assertEqual(len(File.objects.all()), 2)
|
self.assertEqual(len(File.objects.all()), 2)
|
||||||
response = client.delete(f'/api/2/files/{file.hash}/')
|
response = self.client.delete(f'/api/2/files/{file.hash}/')
|
||||||
self.assertEqual(response.status_code, 204)
|
self.assertEqual(response.status_code, 204)
|
||||||
|
|
|
@ -20,7 +20,6 @@ class EventViewSet(viewsets.ModelViewSet):
|
||||||
serializer_class = EventSerializer
|
serializer_class = EventSerializer
|
||||||
queryset = Event.objects.all()
|
queryset = Event.objects.all()
|
||||||
permission_classes = []
|
permission_classes = []
|
||||||
authentication_classes = []
|
|
||||||
|
|
||||||
|
|
||||||
class ContainerSerializer(serializers.ModelSerializer):
|
class ContainerSerializer(serializers.ModelSerializer):
|
||||||
|
@ -39,7 +38,6 @@ class ContainerViewSet(viewsets.ModelViewSet):
|
||||||
serializer_class = ContainerSerializer
|
serializer_class = ContainerSerializer
|
||||||
queryset = Container.objects.all()
|
queryset = Container.objects.all()
|
||||||
permission_classes = []
|
permission_classes = []
|
||||||
authentication_classes = []
|
|
||||||
|
|
||||||
|
|
||||||
class ItemSerializer(serializers.ModelSerializer):
|
class ItemSerializer(serializers.ModelSerializer):
|
||||||
|
@ -93,8 +91,6 @@ class ItemSerializer(serializers.ModelSerializer):
|
||||||
|
|
||||||
|
|
||||||
@api_view(['GET'])
|
@api_view(['GET'])
|
||||||
@permission_classes([])
|
|
||||||
@authentication_classes([])
|
|
||||||
def search_items(request, event_slug, query):
|
def search_items(request, event_slug, query):
|
||||||
try:
|
try:
|
||||||
event = Event.objects.get(slug=event_slug)
|
event = Event.objects.get(slug=event_slug)
|
||||||
|
@ -109,8 +105,6 @@ def search_items(request, event_slug, query):
|
||||||
|
|
||||||
|
|
||||||
@api_view(['GET', 'POST'])
|
@api_view(['GET', 'POST'])
|
||||||
@permission_classes([])
|
|
||||||
@authentication_classes([])
|
|
||||||
def item(request, event_slug):
|
def item(request, event_slug):
|
||||||
try:
|
try:
|
||||||
event = Event.objects.get(slug=event_slug)
|
event = Event.objects.get(slug=event_slug)
|
||||||
|
@ -126,8 +120,6 @@ def item(request, event_slug):
|
||||||
|
|
||||||
|
|
||||||
@api_view(['GET', 'PUT', 'DELETE'])
|
@api_view(['GET', 'PUT', 'DELETE'])
|
||||||
@permission_classes([])
|
|
||||||
@authentication_classes([])
|
|
||||||
def item_by_id(request, event_slug, id):
|
def item_by_id(request, event_slug, id):
|
||||||
try:
|
try:
|
||||||
event = Event.objects.get(slug=event_slug)
|
event = Event.objects.get(slug=event_slug)
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
# Generated by Django 4.2.7 on 2023-11-18 11:28
|
# Generated by Django 4.2.7 on 2023-12-09 02:13
|
||||||
|
|
||||||
from django.db import migrations, models
|
from django.db import migrations, models
|
||||||
import django.db.models.deletion
|
import django.db.models.deletion
|
||||||
|
@ -15,11 +15,16 @@ class Migration(migrations.Migration):
|
||||||
migrations.CreateModel(
|
migrations.CreateModel(
|
||||||
name='Container',
|
name='Container',
|
||||||
fields=[
|
fields=[
|
||||||
|
('is_deleted', models.BooleanField(default=False)),
|
||||||
|
('deleted_at', models.DateTimeField(blank=True, null=True)),
|
||||||
('cid', models.AutoField(primary_key=True, serialize=False)),
|
('cid', models.AutoField(primary_key=True, serialize=False)),
|
||||||
('name', models.CharField(max_length=255)),
|
('name', models.CharField(max_length=255)),
|
||||||
('created_at', models.DateTimeField(blank=True, null=True)),
|
('created_at', models.DateTimeField(blank=True, null=True)),
|
||||||
('updated_at', models.DateTimeField(blank=True, null=True)),
|
('updated_at', models.DateTimeField(blank=True, null=True)),
|
||||||
],
|
],
|
||||||
|
options={
|
||||||
|
'abstract': False,
|
||||||
|
},
|
||||||
),
|
),
|
||||||
migrations.CreateModel(
|
migrations.CreateModel(
|
||||||
name='Event',
|
name='Event',
|
||||||
|
@ -38,6 +43,8 @@ class Migration(migrations.Migration):
|
||||||
migrations.CreateModel(
|
migrations.CreateModel(
|
||||||
name='Item',
|
name='Item',
|
||||||
fields=[
|
fields=[
|
||||||
|
('is_deleted', models.BooleanField(default=False)),
|
||||||
|
('deleted_at', models.DateTimeField(blank=True, null=True)),
|
||||||
('iid', models.AutoField(primary_key=True, serialize=False)),
|
('iid', models.AutoField(primary_key=True, serialize=False)),
|
||||||
('uid', models.IntegerField()),
|
('uid', models.IntegerField()),
|
||||||
('description', models.TextField()),
|
('description', models.TextField()),
|
||||||
|
@ -48,6 +55,7 @@ class Migration(migrations.Migration):
|
||||||
('event', models.ForeignKey(db_column='eid', on_delete=django.db.models.deletion.CASCADE, to='inventory.event')),
|
('event', models.ForeignKey(db_column='eid', on_delete=django.db.models.deletion.CASCADE, to='inventory.event')),
|
||||||
],
|
],
|
||||||
options={
|
options={
|
||||||
|
'permissions': [('match_item', 'Can match item')],
|
||||||
'unique_together': {('uid', 'event')},
|
'unique_together': {('uid', 'event')},
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
|
|
@ -1,33 +0,0 @@
|
||||||
# Generated by Django 4.2.7 on 2023-11-20 11:23
|
|
||||||
|
|
||||||
from django.db import migrations, models
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
('inventory', '0001_initial'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.AddField(
|
|
||||||
model_name='container',
|
|
||||||
name='deleted_at',
|
|
||||||
field=models.DateTimeField(blank=True, null=True),
|
|
||||||
),
|
|
||||||
migrations.AddField(
|
|
||||||
model_name='container',
|
|
||||||
name='is_deleted',
|
|
||||||
field=models.BooleanField(default=False),
|
|
||||||
),
|
|
||||||
migrations.AddField(
|
|
||||||
model_name='item',
|
|
||||||
name='deleted_at',
|
|
||||||
field=models.DateTimeField(blank=True, null=True),
|
|
||||||
),
|
|
||||||
migrations.AddField(
|
|
||||||
model_name='item',
|
|
||||||
name='is_deleted',
|
|
||||||
field=models.BooleanField(default=False),
|
|
||||||
),
|
|
||||||
]
|
|
|
@ -1,17 +0,0 @@
|
||||||
# Generated by Django 4.2.7 on 2023-12-06 13:45
|
|
||||||
|
|
||||||
from django.db import migrations
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
('inventory', '0002_container_deleted_at_container_is_deleted_and_more'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.AlterModelOptions(
|
|
||||||
name='item',
|
|
||||||
options={'permissions': [('match_item', 'Can match item')]},
|
|
||||||
),
|
|
||||||
]
|
|
|
@ -12,8 +12,6 @@ class EmailSerializer(serializers.ModelSerializer):
|
||||||
class EmailViewSet(viewsets.ModelViewSet):
|
class EmailViewSet(viewsets.ModelViewSet):
|
||||||
serializer_class = EmailSerializer
|
serializer_class = EmailSerializer
|
||||||
queryset = Email.objects.all()
|
queryset = Email.objects.all()
|
||||||
permission_classes = []
|
|
||||||
authentication_classes = []
|
|
||||||
|
|
||||||
|
|
||||||
router = routers.SimpleRouter()
|
router = routers.SimpleRouter()
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
# Generated by Django 4.2.7 on 2023-12-06 02:52
|
# Generated by Django 4.2.7 on 2023-12-09 02:13
|
||||||
|
|
||||||
from django.db import migrations, models
|
from django.db import migrations, models
|
||||||
import django.db.models.deletion
|
import django.db.models.deletion
|
||||||
|
@ -9,8 +9,8 @@ class Migration(migrations.Migration):
|
||||||
initial = True
|
initial = True
|
||||||
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
('inventory', '0001_initial'),
|
||||||
('tickets', '0001_initial'),
|
('tickets', '0001_initial'),
|
||||||
('inventory', '0002_container_deleted_at_container_is_deleted_and_more'),
|
|
||||||
]
|
]
|
||||||
|
|
||||||
operations = [
|
operations = [
|
||||||
|
|
|
@ -1,16 +1,16 @@
|
||||||
import inspect
|
import inspect
|
||||||
from unittest import mock
|
from unittest import mock
|
||||||
|
from knox.models import AuthToken
|
||||||
|
|
||||||
from django.test import TestCase, Client
|
from django.test import TestCase, Client
|
||||||
|
|
||||||
|
from authentication.models import ExtendedUser
|
||||||
from core.settings import MAIL_DOMAIN
|
from core.settings import MAIL_DOMAIN
|
||||||
from inventory.models import Event
|
from inventory.models import Event
|
||||||
from mail.models import Email
|
from mail.models import Email
|
||||||
from mail.protocol import LMTPHandler
|
from mail.protocol import LMTPHandler
|
||||||
from tickets.models import IssueThread
|
from tickets.models import IssueThread
|
||||||
|
|
||||||
client = Client()
|
|
||||||
|
|
||||||
|
|
||||||
def make_mocked_coro(return_value=mock.sentinel, raise_exception=mock.sentinel):
|
def make_mocked_coro(return_value=mock.sentinel, raise_exception=mock.sentinel):
|
||||||
async def mock_coro(*args, **kwargs):
|
async def mock_coro(*args, **kwargs):
|
||||||
|
@ -25,6 +25,13 @@ def make_mocked_coro(return_value=mock.sentinel, raise_exception=mock.sentinel):
|
||||||
|
|
||||||
class EmailsApiTest(TestCase):
|
class EmailsApiTest(TestCase):
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
super().setUp()
|
||||||
|
self.user = ExtendedUser.objects.create_user('testuser', 'test', 'test')
|
||||||
|
self.user.save()
|
||||||
|
self.token = AuthToken.objects.create(user=self.user)
|
||||||
|
self.client = Client(headers={'Authorization': 'Token ' + self.token[1]})
|
||||||
|
|
||||||
def test_mails(self):
|
def test_mails(self):
|
||||||
Event.objects.get_or_create(
|
Event.objects.get_or_create(
|
||||||
name="Test event",
|
name="Test event",
|
||||||
|
@ -36,7 +43,7 @@ class EmailsApiTest(TestCase):
|
||||||
sender='test',
|
sender='test',
|
||||||
recipient='test',
|
recipient='test',
|
||||||
)
|
)
|
||||||
response = client.get('/api/2/mails/')
|
response = self.client.get('/api/2/mails/')
|
||||||
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]['subject'], 'test')
|
self.assertEqual(response.json()[0]['subject'], 'test')
|
||||||
|
@ -45,13 +52,20 @@ class EmailsApiTest(TestCase):
|
||||||
self.assertEqual(response.json()[0]['recipient'], 'test')
|
self.assertEqual(response.json()[0]['recipient'], 'test')
|
||||||
|
|
||||||
def test_mails_empty(self):
|
def test_mails_empty(self):
|
||||||
response = client.get('/api/2/mails/')
|
response = self.client.get('/api/2/mails/')
|
||||||
self.assertEqual(response.status_code, 200)
|
self.assertEqual(response.status_code, 200)
|
||||||
self.assertEqual(response.json(), [])
|
self.assertEqual(response.json(), [])
|
||||||
|
|
||||||
|
|
||||||
class LMTPHandlerTestCase(TestCase): # TODO replace with less hacky test
|
class LMTPHandlerTestCase(TestCase): # TODO replace with less hacky test
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
super().setUp()
|
||||||
|
self.user = ExtendedUser.objects.create_user('testuser', 'test', 'test')
|
||||||
|
self.user.save()
|
||||||
|
self.token = AuthToken.objects.create(user=self.user)
|
||||||
|
self.client = Client(headers={'Authorization': 'Token ' + self.token[1]})
|
||||||
|
|
||||||
def test_handle_client(self):
|
def test_handle_client(self):
|
||||||
from aiosmtpd.smtp import Envelope
|
from aiosmtpd.smtp import Envelope
|
||||||
from asgiref.sync import async_to_sync
|
from asgiref.sync import async_to_sync
|
||||||
|
@ -156,8 +170,7 @@ class LMTPHandlerTestCase(TestCase): # TODO replace with less hacky test
|
||||||
)
|
)
|
||||||
import aiosmtplib
|
import aiosmtplib
|
||||||
aiosmtplib.send = make_mocked_coro()
|
aiosmtplib.send = make_mocked_coro()
|
||||||
client = Client()
|
response = self.client.post(f'/api/2/tickets/{issue_thread.id}/reply/', {
|
||||||
response = client.post(f'/api/2/tickets/{issue_thread.id}/reply/', {
|
|
||||||
'message': 'test'
|
'message': 'test'
|
||||||
})
|
})
|
||||||
self.assertEqual(response.status_code, 201)
|
self.assertEqual(response.status_code, 201)
|
||||||
|
|
|
@ -13,8 +13,6 @@ class SystemEventSerializer(serializers.ModelSerializer):
|
||||||
class SystemEventViewSet(viewsets.ModelViewSet):
|
class SystemEventViewSet(viewsets.ModelViewSet):
|
||||||
serializer_class = SystemEventSerializer
|
serializer_class = SystemEventSerializer
|
||||||
queryset = SystemEvent.objects.all()
|
queryset = SystemEvent.objects.all()
|
||||||
permission_classes = []
|
|
||||||
authentication_classes = []
|
|
||||||
|
|
||||||
|
|
||||||
router = routers.SimpleRouter()
|
router = routers.SimpleRouter()
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
# Generated by Django 4.2.7 on 2023-12-01 18:19
|
# Generated by Django 4.2.7 on 2023-12-09 02:13
|
||||||
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.db import migrations, models
|
from django.db import migrations, models
|
||||||
|
|
|
@ -1,10 +1,11 @@
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from django.contrib.auth.models import User
|
|
||||||
from asgiref.sync import sync_to_async
|
from asgiref.sync import sync_to_async
|
||||||
from channels.layers import get_channel_layer
|
from channels.layers import get_channel_layer
|
||||||
|
|
||||||
|
from authentication.models import ExtendedUser
|
||||||
|
|
||||||
|
|
||||||
class SystemEvent(models.Model):
|
class SystemEvent(models.Model):
|
||||||
TYPE_CHOICES = [('ticket_created', 'ticket_created'),
|
TYPE_CHOICES = [('ticket_created', 'ticket_created'),
|
||||||
|
@ -19,7 +20,7 @@ class SystemEvent(models.Model):
|
||||||
('event_deleted', 'event_deleted'), ]
|
('event_deleted', 'event_deleted'), ]
|
||||||
id = models.AutoField(primary_key=True)
|
id = models.AutoField(primary_key=True)
|
||||||
timestamp = models.DateTimeField(auto_now_add=True)
|
timestamp = models.DateTimeField(auto_now_add=True)
|
||||||
user = models.ForeignKey(User, models.SET_NULL, null=True)
|
user = models.ForeignKey(ExtendedUser, models.SET_NULL, null=True)
|
||||||
type = models.CharField(max_length=255, choices=TYPE_CHOICES)
|
type = models.CharField(max_length=255, choices=TYPE_CHOICES)
|
||||||
reference = models.IntegerField(blank=True, null=True)
|
reference = models.IntegerField(blank=True, null=True)
|
||||||
|
|
||||||
|
|
|
@ -53,13 +53,9 @@ class IssueSerializer(serializers.ModelSerializer):
|
||||||
class IssueViewSet(viewsets.ModelViewSet):
|
class IssueViewSet(viewsets.ModelViewSet):
|
||||||
serializer_class = IssueSerializer
|
serializer_class = IssueSerializer
|
||||||
queryset = IssueThread.objects.all()
|
queryset = IssueThread.objects.all()
|
||||||
permission_classes = []
|
|
||||||
authentication_classes = []
|
|
||||||
|
|
||||||
|
|
||||||
@api_view(['POST'])
|
@api_view(['POST'])
|
||||||
@permission_classes([])
|
|
||||||
@authentication_classes([])
|
|
||||||
def reply(request, pk):
|
def reply(request, pk):
|
||||||
issue = IssueThread.objects.get(pk=pk)
|
issue = IssueThread.objects.get(pk=pk)
|
||||||
# email = issue.reply(request.data['body']) # TODO evaluate if this is a useful abstraction
|
# email = issue.reply(request.data['body']) # TODO evaluate if this is a useful abstraction
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
# Generated by Django 4.2.7 on 2023-12-06 02:34
|
# Generated by Django 4.2.7 on 2023-12-09 02:13
|
||||||
|
|
||||||
from django.db import migrations, models
|
from django.db import migrations, models
|
||||||
import django.db.models.deletion
|
import django.db.models.deletion
|
||||||
|
@ -18,9 +18,13 @@ class Migration(migrations.Migration):
|
||||||
('is_deleted', models.BooleanField(default=False)),
|
('is_deleted', models.BooleanField(default=False)),
|
||||||
('deleted_at', models.DateTimeField(blank=True, null=True)),
|
('deleted_at', models.DateTimeField(blank=True, null=True)),
|
||||||
('id', models.AutoField(primary_key=True, serialize=False)),
|
('id', models.AutoField(primary_key=True, serialize=False)),
|
||||||
|
('name', models.CharField(max_length=255)),
|
||||||
|
('state', models.CharField(default='new', max_length=255)),
|
||||||
|
('assigned_to', models.CharField(max_length=255, null=True)),
|
||||||
|
('last_activity', models.DateTimeField(auto_now=True)),
|
||||||
],
|
],
|
||||||
options={
|
options={
|
||||||
'abstract': False,
|
'permissions': [('send_mail', 'Can send mail')],
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
migrations.CreateModel(
|
migrations.CreateModel(
|
||||||
|
@ -29,7 +33,7 @@ class Migration(migrations.Migration):
|
||||||
('id', models.AutoField(primary_key=True, serialize=False)),
|
('id', models.AutoField(primary_key=True, serialize=False)),
|
||||||
('state', models.CharField(max_length=255)),
|
('state', models.CharField(max_length=255)),
|
||||||
('timestamp', models.DateTimeField(auto_now_add=True)),
|
('timestamp', models.DateTimeField(auto_now_add=True)),
|
||||||
('issue_thread', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='tickets.issuethread')),
|
('issue_thread', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='state_changes', to='tickets.issuethread')),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
migrations.CreateModel(
|
migrations.CreateModel(
|
||||||
|
@ -38,7 +42,7 @@ class Migration(migrations.Migration):
|
||||||
('id', models.AutoField(primary_key=True, serialize=False)),
|
('id', models.AutoField(primary_key=True, serialize=False)),
|
||||||
('comment', models.TextField()),
|
('comment', models.TextField()),
|
||||||
('timestamp', models.DateTimeField(auto_now_add=True)),
|
('timestamp', models.DateTimeField(auto_now_add=True)),
|
||||||
('issue_thread', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='tickets.issuethread')),
|
('issue_thread', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='comments', to='tickets.issuethread')),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
|
|
@ -1,45 +0,0 @@
|
||||||
# Generated by Django 4.2.7 on 2023-12-06 03:53
|
|
||||||
|
|
||||||
from django.db import migrations, models
|
|
||||||
import django.db.models.deletion
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
('tickets', '0001_initial'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.AddField(
|
|
||||||
model_name='issuethread',
|
|
||||||
name='assigned_to',
|
|
||||||
field=models.CharField(max_length=255, null=True),
|
|
||||||
),
|
|
||||||
migrations.AddField(
|
|
||||||
model_name='issuethread',
|
|
||||||
name='last_activity',
|
|
||||||
field=models.DateTimeField(auto_now=True),
|
|
||||||
),
|
|
||||||
migrations.AddField(
|
|
||||||
model_name='issuethread',
|
|
||||||
name='name',
|
|
||||||
field=models.CharField(default='unnamed issue', max_length=255),
|
|
||||||
preserve_default=False,
|
|
||||||
),
|
|
||||||
migrations.AddField(
|
|
||||||
model_name='issuethread',
|
|
||||||
name='state',
|
|
||||||
field=models.CharField(default='new', max_length=255),
|
|
||||||
),
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name='comment',
|
|
||||||
name='issue_thread',
|
|
||||||
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='comments', to='tickets.issuethread'),
|
|
||||||
),
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name='statechange',
|
|
||||||
name='issue_thread',
|
|
||||||
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='state_changes', to='tickets.issuethread'),
|
|
||||||
),
|
|
||||||
]
|
|
|
@ -1,17 +0,0 @@
|
||||||
# Generated by Django 4.2.7 on 2023-12-06 13:47
|
|
||||||
|
|
||||||
from django.db import migrations
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
('tickets', '0002_issuethread_assigned_to_issuethread_last_activity_and_more'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.AlterModelOptions(
|
|
||||||
name='issuethread',
|
|
||||||
options={'permissions': [('send_mail', 'Can send mail')]},
|
|
||||||
),
|
|
||||||
]
|
|
|
@ -2,16 +2,24 @@ from datetime import datetime, timedelta
|
||||||
|
|
||||||
from django.test import TestCase, Client
|
from django.test import TestCase, Client
|
||||||
|
|
||||||
|
from authentication.models import ExtendedUser
|
||||||
from mail.models import Email
|
from mail.models import Email
|
||||||
from tickets.models import IssueThread, StateChange, Comment
|
from tickets.models import IssueThread, StateChange, Comment
|
||||||
|
from django.contrib.auth.models import User
|
||||||
client = Client()
|
from knox.models import AuthToken
|
||||||
|
|
||||||
|
|
||||||
class IssueApiTest(TestCase):
|
class IssueApiTest(TestCase):
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
super().setUp()
|
||||||
|
self.user = ExtendedUser.objects.create_user('testuser', 'test', 'test')
|
||||||
|
self.user.save()
|
||||||
|
self.token = AuthToken.objects.create(user=self.user)
|
||||||
|
self.client = Client(headers={'Authorization': 'Token ' + self.token[1]})
|
||||||
|
|
||||||
def test_issues_empty(self):
|
def test_issues_empty(self):
|
||||||
response = client.get('/api/2/tickets/')
|
response = self.client.get('/api/2/tickets/')
|
||||||
self.assertEqual(response.status_code, 200)
|
self.assertEqual(response.status_code, 200)
|
||||||
self.assertEqual(response.json(), [])
|
self.assertEqual(response.json(), [])
|
||||||
|
|
||||||
|
@ -48,7 +56,7 @@ class IssueApiTest(TestCase):
|
||||||
timestamp=now + timedelta(seconds=3),
|
timestamp=now + timedelta(seconds=3),
|
||||||
)
|
)
|
||||||
|
|
||||||
response = client.get('/api/2/tickets/')
|
response = self.client.get('/api/2/tickets/')
|
||||||
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'], issue.id)
|
self.assertEqual(response.json()[0]['id'], issue.id)
|
||||||
|
|
|
@ -138,7 +138,8 @@ const store = new Vuex.Store({
|
||||||
actions: {
|
actions: {
|
||||||
async login({commit, dispatch, state}, {username, password, remember}) {
|
async login({commit, dispatch, state}, {username, password, remember}) {
|
||||||
commit('setRemember', remember);
|
commit('setRemember', remember);
|
||||||
const data = await fetch('/api/2/auth/token/', {
|
try{
|
||||||
|
const data = await fetch('/api/2/token/', {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: {'Content-Type': 'application/json'},
|
headers: {'Content-Type': 'application/json'},
|
||||||
body: JSON.stringify({username: username, password: password}),
|
body: JSON.stringify({username: username, password: password}),
|
||||||
|
@ -151,6 +152,10 @@ const store = new Vuex.Store({
|
||||||
} else {
|
} else {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.error(e);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
},
|
},
|
||||||
async loadEvents({commit}) {
|
async loadEvents({commit}) {
|
||||||
const {data} = await axios.get('/1/events/');
|
const {data} = await axios.get('/1/events/');
|
||||||
|
|
|
@ -31,6 +31,19 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div :class="errors.email?['mb-3','is-invalid']:['mb-3']">
|
||||||
|
<label class="form-label">E-Mail</label>
|
||||||
|
<div class="input-group">
|
||||||
|
<input class="form-control"
|
||||||
|
type="email" v-model="form.email" id="validationCustomEmail"
|
||||||
|
placeholder="Enter your email" required/>
|
||||||
|
</div>
|
||||||
|
<div class="invalid-feedback">
|
||||||
|
{{ errors.email }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
<div :class="errors.password?['mb-3','is-invalid']:['mb-3']">
|
<div :class="errors.password?['mb-3','is-invalid']:['mb-3']">
|
||||||
<label class="form-label">Password</label>
|
<label class="form-label">Password</label>
|
||||||
<input class="form-control" type="password"
|
<input class="form-control" type="password"
|
||||||
|
@ -79,11 +92,13 @@ export default {
|
||||||
form: {
|
form: {
|
||||||
username: '',
|
username: '',
|
||||||
password: '',
|
password: '',
|
||||||
|
email: '',
|
||||||
},
|
},
|
||||||
errors: {
|
errors: {
|
||||||
username: null,
|
username: null,
|
||||||
password: null,
|
password: null,
|
||||||
password2: null,
|
password2: null,
|
||||||
|
email: null,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -97,7 +112,7 @@ export default {
|
||||||
} else {
|
} else {
|
||||||
this.errors.password2 = null;
|
this.errors.password2 = null;
|
||||||
}
|
}
|
||||||
fetch('/api/2/auth/register/', {
|
fetch('/api/2/register/', {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/json',
|
'Content-Type': 'application/json',
|
||||||
|
|
Loading…
Reference in a new issue