from rest_framework import routers, viewsets, serializers, permissions from rest_framework.decorators import api_view, permission_classes, authentication_classes from rest_framework.authtoken.serializers import AuthTokenSerializer from rest_framework.permissions import IsAuthenticated from rest_framework.response import Response from django.contrib.auth import login from django.urls import path from django.dispatch import receiver from django.db.models.signals import post_save from django.contrib.auth.models import Group from knox.models import AuthToken from knox.views import LoginView as KnoxLoginView from authentication.models import ExtendedUser class UserSerializer(serializers.ModelSerializer): permissions = serializers.SerializerMethodField() groups = serializers.SlugRelatedField(many=True, read_only=True, slug_field='name') class Meta: model = ExtendedUser fields = ('id', 'username', 'email', 'first_name', 'last_name', 'permissions', 'groups') read_only_fields = ('id', 'username', 'email', 'first_name', 'last_name', 'permissions', 'groups') def get_permissions(self, obj): return list(set(obj.get_permissions())) @receiver(post_save, sender=ExtendedUser) def create_auth_token(sender, instance=None, created=False, **kwargs): if created: AuthToken.objects.create(user=instance) class UserViewSet(viewsets.ModelViewSet): queryset = ExtendedUser.objects.all() serializer_class = UserSerializer class GroupSerializer(serializers.ModelSerializer): permissions = serializers.SerializerMethodField() members = serializers.SerializerMethodField() class Meta: model = Group fields = ('id', 'name', 'permissions', 'members') def get_permissions(self, obj): return ["*:" + p.codename for p in obj.permissions.all()] def get_members(self, obj): return [u.username for u in obj.user_set.all()] class GroupViewSet(viewsets.ModelViewSet): queryset = Group.objects.all() serializer_class = GroupSerializer @api_view(['GET']) @permission_classes([IsAuthenticated]) def selfUser(request): serializer = UserSerializer(request.user) return Response(serializer.data, status=200) @api_view(['POST']) @permission_classes([]) @authentication_classes([]) def registerUser(request): try: username = request.data.get('username') 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) 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.register(r'users', UserViewSet, basename='users') router.register(r'groups', GroupViewSet, basename='groups') urlpatterns = router.urls + [ path('self/', selfUser), path('login/', LoginView.as_view()), path('register/', registerUser), ]