diff --git a/portfolio/__pycache__/settings.cpython-36.pyc b/portfolio/__pycache__/settings.cpython-36.pyc index 9c26ff9..65be4c8 100644 Binary files a/portfolio/__pycache__/settings.cpython-36.pyc and b/portfolio/__pycache__/settings.cpython-36.pyc differ diff --git a/portfolio/__pycache__/urls.cpython-36.pyc b/portfolio/__pycache__/urls.cpython-36.pyc index f9a272a..f663d91 100644 Binary files a/portfolio/__pycache__/urls.cpython-36.pyc and b/portfolio/__pycache__/urls.cpython-36.pyc differ diff --git a/portfolio/account/__pycache__/models.cpython-36.pyc b/portfolio/account/__pycache__/models.cpython-36.pyc index 89e037e..51fa655 100644 Binary files a/portfolio/account/__pycache__/models.cpython-36.pyc and b/portfolio/account/__pycache__/models.cpython-36.pyc differ diff --git a/portfolio/account/__pycache__/serializers.cpython-36.pyc b/portfolio/account/__pycache__/serializers.cpython-36.pyc index 1213bb2..f28f03d 100644 Binary files a/portfolio/account/__pycache__/serializers.cpython-36.pyc and b/portfolio/account/__pycache__/serializers.cpython-36.pyc differ diff --git a/portfolio/account/__pycache__/views.cpython-36.pyc b/portfolio/account/__pycache__/views.cpython-36.pyc index 4383903..df9191c 100644 Binary files a/portfolio/account/__pycache__/views.cpython-36.pyc and b/portfolio/account/__pycache__/views.cpython-36.pyc differ diff --git a/portfolio/account/models.py b/portfolio/account/models.py index f00d2bf..1b23089 100644 --- a/portfolio/account/models.py +++ b/portfolio/account/models.py @@ -1,10 +1,8 @@ from django.db import models from django.http import HttpResponse from django.contrib.auth.models import User -from django.contrib.auth import authenticate from rest_framework.response import Response -from rest_framework.authtoken.models import Token from rest_framework import serializers @@ -12,18 +10,29 @@ class AbstractUser(models.Model): city = models.CharField(verbose_name='City', max_length=255) country = models.CharField(verbose_name='Country', max_length=255) ip = models.CharField(verbose_name='IP', max_length=15) - - def fromDict(self, dict): - self.__dict__.update(dict) class Meta: abstract = True class Account(User, AbstractUser): - + + def fromDict(self, dict): + self.__dict__.update(dict) + + def toDict(self) -> dict: + return { + 'id': self.id, + 'username': self.username, + 'password': None, + 'email': self.email, + 'ip': self.ip, + 'city': self.city, + 'country': self.country + } + @staticmethod - def register(userDict) -> object: + def register(userDict) -> dict: account = Account.objects.create_user( userDict['username'], userDict['email'], @@ -33,26 +42,15 @@ class Account(User, AbstractUser): account.city = userDict['city'], account.country = userDict['country'] account.save() - return account + return account.toDict() - def login(self, username, password) -> dict: - tryLogin = authenticate(username = username, password = password) - if tryLogin is not None: - user = Account.objects.get(username = username) - token = Token.objects.create(user = user) - return token.__dict__ - else: - return { 'error': 'login failed'} - - def logout(self): - pass - - def update(self, userDict): + def update(self, userDict) -> dict: if 'password' in userDict: password = userDict.pop('password') self.set_password(password) self.fromDict(userDict) - self.save() + self.save() + return self.toDict() def set_password(self, raw_password): return super().set_password(raw_password) diff --git a/portfolio/account/serializers.py b/portfolio/account/serializers.py index 58a09a6..45d39c7 100644 --- a/portfolio/account/serializers.py +++ b/portfolio/account/serializers.py @@ -1,6 +1,9 @@ from .models import Account, Guest -from rest_framework import serializers +from rest_framework import serializers +from rest_framework.authtoken.models import Token + +from django.contrib.auth import authenticate, logout from django.core.paginator import Paginator from django.http import JsonResponse @@ -25,12 +28,40 @@ class AccountSerializer(AccountGetSerializer): return Account.register(validated_data) def update(self, instance, validated_data): - return instance.update(instance, **validated_data) + return instance.update(validated_data) class Meta: model = Account fields = ['id', 'username', 'password', 'email', 'ip', 'city', 'country'] +class AccountAuthSerializer(serializers.ModelSerializer): + username = serializers.CharField(max_length = 100) + password = serializers.CharField(max_length = 100) + + @staticmethod + def login(username, password) -> dict: + tryLogin = authenticate(username = username, password = password) + if tryLogin is not None: + user = Account.objects.get(username = username) + try: + token = Token.objects.get(user = user) + except: + token = Token.objects.create(user = user) + return { 'token': token.key, 'user': user.toDict() } + else: + return { 'error': 'login failed'} + + @staticmethod + def logout(request, format=None): + tokenStr = request.headers['Authorization'].split(' ')[1] + token = Token.objects.get(key = tokenStr) + token.delete() + return { 'info': 'logout' } + + class Meta: + model = Account + fields = ['username', 'password'] + class GuestSerializer(serializers.HyperlinkedModelSerializer): id = serializers.IntegerField(read_only = True) diff --git a/portfolio/account/views.py b/portfolio/account/views.py index 03c55f6..cf2419f 100644 --- a/portfolio/account/views.py +++ b/portfolio/account/views.py @@ -1,4 +1,5 @@ -from rest_framework import viewsets +from rest_framework import viewsets, mixins, permissions +from rest_framework.authtoken.views import ObtainAuthToken from rest_framework.response import Response from drf_yasg.utils import swagger_auto_schema @@ -6,13 +7,14 @@ from django.core.paginator import Paginator from django.shortcuts import get_object_or_404 from .models import Account, Guest -from .serializers import AccountSerializer, GuestSerializer, AccountGetSerializer +from .serializers import * class AccountViewSet(viewsets.ModelViewSet): queryset = Account.objects.all() serializer_class = AccountSerializer + permission_classes = [permissions.IsAuthenticated] @swagger_auto_schema(responses={ 200: AccountGetSerializer }) def retrieve(self, request, pk=None): @@ -27,6 +29,27 @@ class AccountViewSet(viewsets.ModelViewSet): return Response(serializer.data) +class AccountAuth(ObtainAuthToken): + + queryset = Account.objects.all() + serializer_class = AccountAuthSerializer + + @swagger_auto_schema( + responses={ 200: '{ Token: Authorize }' }, + request_body=AccountAuthSerializer + ) + def post(self, request, *args, **kwargs): + serializer = self.serializer_class(data=request.data, context={'request': request}) + serializer.is_valid(raise_exception=True) + username = serializer.validated_data['username'] + password = serializer.validated_data['password'] + return Response(AccountAuthSerializer.login(username, password)) + + @swagger_auto_schema(responses={ 200: '{ info: logout }' }) + def delete(self, request, *args, **kwargs): + return Response(self.serializer_class.logout(request)) + + class GuestViewSet(viewsets.ModelViewSet): queryset = Guest.objects.all() serializer_class = GuestSerializer diff --git a/portfolio/settings.py b/portfolio/settings.py index baee004..cd5ea0d 100644 --- a/portfolio/settings.py +++ b/portfolio/settings.py @@ -57,11 +57,13 @@ REST_FRAMEWORK = { # Use Django's standard `django.contrib.auth` permissions, # or allow read-only access for unauthenticated users. 'DEFAULT_PERMISSION_CLASSES': [ - 'rest_framework.permissions.DjangoModelPermissionsOrAnonReadOnly' + # 'rest_framework.permissions.DjangoModelPermissionsOrAnonReadOnly', + 'rest_framework.permissions.IsAdminUser' ], 'DEFAULT_AUTHENTICATION_CLASSES': [ - 'rest_framework.authentication.BasicAuthentication', + # 'rest_framework.authentication.BasicAuthentication', 'rest_framework.authentication.SessionAuthentication', + 'rest_framework.authentication.TokenAuthentication', ] } diff --git a/portfolio/urls.py b/portfolio/urls.py index f24424a..5440999 100644 --- a/portfolio/urls.py +++ b/portfolio/urls.py @@ -14,13 +14,12 @@ Including another URLconf 2. Add a URL to urlpatterns: path('blog/', include('blog.urls')) """ from django.contrib import admin -from django.urls import path, re_path, include -from django.conf.urls.static import static +from django.urls import path, include, re_path from drf_yasg import openapi from drf_yasg.views import get_schema_view from rest_framework import routers, permissions -from rest_framework_swagger.views import get_swagger_view +from rest_framework.authtoken import views as authViews from portfolio import settings from .account import views @@ -40,18 +39,20 @@ schema_view = get_schema_view( router = routers.DefaultRouter() router.register(r'users', views.AccountViewSet, basename='user') +# router.register(r'users/auth', views.AccountAuth, basename='user auth') router.register(r'guests', views.GuestViewSet) urlpatterns = [ path('admin/', admin.site.urls), path('', include(router.urls)), - path('api-auth/', include('rest_framework.urls', namespace='rest_framework')) + # path('api-auth/', include('rest_framework.urls', namespace='rest_framework')) ] if settings.DEBUG: urlpatterns = [ path('admin/', admin.site.urls), path('', include(router.urls)), - path('api-auth/', include('rest_framework.urls', namespace='rest_framework')), + re_path(r'users/auth', views.AccountAuth.as_view()), + # path('api-auth/', include('rest_framework.urls', namespace='rest_framework')), path('swagger/', schema_view.with_ui('swagger', cache_timeout=0)) ] \ No newline at end of file