add new URLS, add swaggger doc, add tests
pull/272/head
Markos Gogoulos 2021-08-05 13:25:25 +03:00 zatwierdzone przez GitHub
rodzic 86cc0442d8
commit ba94989e6a
Nie znaleziono w bazie danych klucza dla tego podpisu
ID klucza GPG: 4AEE18F83AFDEB23
17 zmienionych plików z 370 dodań i 82 usunięć

Wyświetl plik

@ -29,7 +29,7 @@ jobs:
shell: bash shell: bash
- name: Run Django Tests - name: Run Django Tests
run: docker-compose -f docker-compose-dev.yaml exec -T web pytest run: docker-compose -f docker-compose-dev.yaml exec --env TESTING=True -T web pytest
- name: Tear down the Stack - name: Tear down the Stack
run: docker-compose -f docker-compose-dev.yaml down run: docker-compose -f docker-compose-dev.yaml down

Wyświetl plik

@ -441,6 +441,13 @@ LOCAL_INSTALL = False
# it is placed here so it can be overrided on local_settings.py # it is placed here so it can be overrided on local_settings.py
GLOBAL_LOGIN_REQUIRED = False GLOBAL_LOGIN_REQUIRED = False
# TODO: separate settings on production/development more properly, for now
# this should be ok
CELERY_TASK_ALWAYS_EAGER = False
if os.environ.get("TESTING"):
CELERY_TASK_ALWAYS_EAGER = True
try: try:
# keep a local_settings.py file for local overrides # keep a local_settings.py file for local overrides
from .local_settings import * # noqa from .local_settings import * # noqa

Wyświetl plik

@ -1,7 +1,7 @@
import debug_toolbar import debug_toolbar
from django.conf.urls import include, url from django.conf.urls import include, re_path
from django.contrib import admin from django.contrib import admin
from django.urls import path, re_path from django.urls import path
from django.views.generic.base import TemplateView from django.views.generic.base import TemplateView
from drf_yasg import openapi from drf_yasg import openapi
from drf_yasg.views import get_schema_view from drf_yasg.views import get_schema_view
@ -15,15 +15,15 @@ schema_view = get_schema_view(
urlpatterns = [ urlpatterns = [
url(r"^__debug__/", include(debug_toolbar.urls)), re_path(r"^__debug__/", include(debug_toolbar.urls)),
path( path(
"robots.txt", "robots.txt",
TemplateView.as_view(template_name="robots.txt", content_type="text/plain"), TemplateView.as_view(template_name="robots.txt", content_type="text/plain"),
), ),
url(r"^", include("files.urls")), re_path(r"^", include("files.urls")),
url(r"^", include("users.urls")), re_path(r"^", include("users.urls")),
url(r"^accounts/", include("allauth.urls")), re_path(r"^accounts/", include("allauth.urls")),
url(r"^api-auth/", include("rest_framework.urls")), re_path(r"^api-auth/", include("rest_framework.urls")),
path("admin/", admin.site.urls), path("admin/", admin.site.urls),
re_path(r'^swagger(?P<format>\.json|\.yaml)$', schema_view.without_ui(cache_timeout=0), name='schema-json'), re_path(r'^swagger(?P<format>\.json|\.yaml)$', schema_view.without_ui(cache_timeout=0), name='schema-json'),
re_path(r'^swagger/$', schema_view.with_ui('swagger', cache_timeout=0), name='schema-swagger-ui'), re_path(r'^swagger/$', schema_view.with_ui('swagger', cache_timeout=0), name='schema-swagger-ui'),

Wyświetl plik

Wyświetl plik

@ -0,0 +1 @@
from .user_utils import create_account # noqa

Wyświetl plik

@ -0,0 +1,24 @@
from faker import Factory
from users.models import User
faker = Factory.create()
def create_account(username=None, email=None, password=None, name=None, **kwargs):
"Allow to create accounts by passing None or specific arguements"
email = email or faker.email()
username = username or email.split('a')[0]
password = password or faker.password()
name = name or faker.name()
description = kwargs.get('description') or faker.text()
is_superuser = kwargs.get('is_superuser') or False
is_manager = kwargs.get('is_manager') or False
is_editor = kwargs.get('is_editor') or False
user = User.objects.create(username=username, email=email, name=name, description=description, is_superuser=is_superuser, is_staff=is_superuser, is_editor=is_editor, is_manager=is_manager)
user.set_password(password)
user.save()
return user

Wyświetl plik

@ -1,5 +1,5 @@
from django.conf import settings from django.conf import settings
from django.conf.urls import include, url from django.conf.urls import include, re_path
from django.conf.urls.static import static from django.conf.urls.static import static
from django.urls import path from django.urls import path
@ -7,85 +7,85 @@ from . import management_views, views
from .feeds import IndexRSSFeed, SearchRSSFeed from .feeds import IndexRSSFeed, SearchRSSFeed
urlpatterns = [ urlpatterns = [
url(r"^$", views.index), re_path(r"^$", views.index),
url(r"^about", views.about, name="about"), re_path(r"^about", views.about, name="about"),
url(r"^add_subtitle", views.add_subtitle, name="add_subtitle"), re_path(r"^add_subtitle", views.add_subtitle, name="add_subtitle"),
url(r"^categories$", views.categories, name="categories"), re_path(r"^categories$", views.categories, name="categories"),
url(r"^contact$", views.contact, name="contact"), re_path(r"^contact$", views.contact, name="contact"),
url(r"^edit", views.edit_media, name="edit_media"), re_path(r"^edit", views.edit_media, name="edit_media"),
url(r"^embed", views.embed_media, name="get_embed"), re_path(r"^embed", views.embed_media, name="get_embed"),
url(r"^featured$", views.featured_media), re_path(r"^featured$", views.featured_media),
url(r"^fu/", include(("uploader.urls", "uploader"), namespace="uploader")), re_path(r"^fu/", include(("uploader.urls", "uploader"), namespace="uploader")),
url(r"^history$", views.history, name="history"), re_path(r"^history$", views.history, name="history"),
url(r"^liked$", views.liked_media, name="liked_media"), re_path(r"^liked$", views.liked_media, name="liked_media"),
url(r"^latest$", views.latest_media), re_path(r"^latest$", views.latest_media),
url(r"^members", views.members, name="members"), re_path(r"^members", views.members, name="members"),
url( re_path(
r"^playlist/(?P<friendly_token>[\w]*)$", r"^playlist/(?P<friendly_token>[\w]*)$",
views.view_playlist, views.view_playlist,
name="get_playlist", name="get_playlist",
), ),
url( re_path(
r"^playlists/(?P<friendly_token>[\w]*)$", r"^playlists/(?P<friendly_token>[\w]*)$",
views.view_playlist, views.view_playlist,
name="get_playlist", name="get_playlist",
), ),
url(r"^popular$", views.recommended_media), re_path(r"^popular$", views.recommended_media),
url(r"^recommended$", views.recommended_media), re_path(r"^recommended$", views.recommended_media),
path("rss/", IndexRSSFeed()), path("rss/", IndexRSSFeed()),
url("^rss/search", SearchRSSFeed()), re_path("^rss/search", SearchRSSFeed()),
url(r"^search", views.search, name="search"), re_path(r"^search", views.search, name="search"),
url(r"^scpublisher", views.upload_media, name="upload_media"), re_path(r"^scpublisher", views.upload_media, name="upload_media"),
url(r"^tags", views.tags, name="tags"), re_path(r"^tags", views.tags, name="tags"),
url(r"^tos$", views.tos, name="terms_of_service"), re_path(r"^tos$", views.tos, name="terms_of_service"),
url(r"^view", views.view_media, name="get_media"), re_path(r"^view", views.view_media, name="get_media"),
url(r"^upload", views.upload_media, name="upload_media"), re_path(r"^upload", views.upload_media, name="upload_media"),
# API VIEWS # API VIEWS
url(r"^api/v1/media$", views.MediaList.as_view()), re_path(r"^api/v1/media$", views.MediaList.as_view()),
url(r"^api/v1/media/$", views.MediaList.as_view()), re_path(r"^api/v1/media/$", views.MediaList.as_view()),
url( re_path(
r"^api/v1/media/(?P<friendly_token>[\w]*)$", r"^api/v1/media/(?P<friendly_token>[\w]*)$",
views.MediaDetail.as_view(), views.MediaDetail.as_view(),
name="api_get_media", name="api_get_media",
), ),
url( re_path(
r"^api/v1/media/encoding/(?P<encoding_id>[\w]*)$", r"^api/v1/media/encoding/(?P<encoding_id>[\w]*)$",
views.EncodingDetail.as_view(), views.EncodingDetail.as_view(),
name="api_get_encoding", name="api_get_encoding",
), ),
url(r"^api/v1/search$", views.MediaSearch.as_view()), re_path(r"^api/v1/search$", views.MediaSearch.as_view()),
url( re_path(
r"^api/v1/media/(?P<friendly_token>[\w]*)/actions$", r"^api/v1/media/(?P<friendly_token>[\w]*)/actions$",
views.MediaActions.as_view(), views.MediaActions.as_view(),
), ),
url(r"^api/v1/categories$", views.CategoryList.as_view()), re_path(r"^api/v1/categories$", views.CategoryList.as_view()),
url(r"^api/v1/tags$", views.TagList.as_view()), re_path(r"^api/v1/tags$", views.TagList.as_view()),
url(r"^api/v1/comments$", views.CommentList.as_view()), re_path(r"^api/v1/comments$", views.CommentList.as_view()),
url( re_path(
r"^api/v1/media/(?P<friendly_token>[\w]*)/comments$", r"^api/v1/media/(?P<friendly_token>[\w]*)/comments$",
views.CommentDetail.as_view(), views.CommentDetail.as_view(),
), ),
url( re_path(
r"^api/v1/media/(?P<friendly_token>[\w]*)/comments/(?P<uid>[\w-]*)$", r"^api/v1/media/(?P<friendly_token>[\w]*)/comments/(?P<uid>[\w-]*)$",
views.CommentDetail.as_view(), views.CommentDetail.as_view(),
), ),
url(r"^api/v1/playlists$", views.PlaylistList.as_view()), re_path(r"^api/v1/playlists$", views.PlaylistList.as_view()),
url(r"^api/v1/playlists/$", views.PlaylistList.as_view()), re_path(r"^api/v1/playlists/$", views.PlaylistList.as_view()),
url( re_path(
r"^api/v1/playlists/(?P<friendly_token>[\w]*)$", r"^api/v1/playlists/(?P<friendly_token>[\w]*)$",
views.PlaylistDetail.as_view(), views.PlaylistDetail.as_view(),
name="api_get_playlist", name="api_get_playlist",
), ),
url(r"^api/v1/user/action/(?P<action>[\w]*)$", views.UserActions.as_view()), re_path(r"^api/v1/user/action/(?P<action>[\w]*)$", views.UserActions.as_view()),
# ADMIN VIEWS # ADMIN VIEWS
url(r"^api/v1/encode_profiles/$", views.EncodeProfileList.as_view()), re_path(r"^api/v1/encode_profiles/$", views.EncodeProfileList.as_view()),
url(r"^api/v1/manage_media$", management_views.MediaList.as_view()), re_path(r"^api/v1/manage_media$", management_views.MediaList.as_view()),
url(r"^api/v1/manage_comments$", management_views.CommentList.as_view()), re_path(r"^api/v1/manage_comments$", management_views.CommentList.as_view()),
url(r"^api/v1/manage_users$", management_views.UserList.as_view()), re_path(r"^api/v1/manage_users$", management_views.UserList.as_view()),
url(r"^api/v1/tasks$", views.TasksList.as_view()), re_path(r"^api/v1/tasks$", views.TasksList.as_view()),
url(r"^api/v1/tasks/$", views.TasksList.as_view()), re_path(r"^api/v1/tasks/$", views.TasksList.as_view()),
url(r"^api/v1/tasks/(?P<friendly_token>[\w|\W]*)$", views.TaskDetail.as_view()), re_path(r"^api/v1/tasks/(?P<friendly_token>[\w|\W]*)$", views.TaskDetail.as_view()),
url(r"^manage/comments$", views.manage_comments, name="manage_comments"), re_path(r"^manage/comments$", views.manage_comments, name="manage_comments"),
url(r"^manage/media$", views.manage_media, name="manage_media"), re_path(r"^manage/media$", views.manage_media, name="manage_media"),
url(r"^manage/users$", views.manage_users, name="manage_users"), re_path(r"^manage/users$", views.manage_users, name="manage_users"),
] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT) ] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)

Wyświetl plik

@ -4,6 +4,8 @@ import sys
if __name__ == "__main__": if __name__ == "__main__":
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "cms.settings") os.environ.setdefault("DJANGO_SETTINGS_MODULE", "cms.settings")
os.environ.setdefault("TESTING", "True")
try: try:
from django.core.management import execute_from_command_line from django.core.management import execute_from_command_line
except ImportError as exc: except ImportError as exc:

Wyświetl plik

@ -0,0 +1,54 @@
from django.test import Client, TestCase
from rest_framework.authtoken.models import Token
from files.tests import create_account
API_V1_LOGIN_URL = '/api/v1/login'
class TestUserLogin(TestCase):
fixtures = ["fixtures/categories.json", "fixtures/encoding_profiles.json"]
def setUp(self):
self.password = 'this_is_a_fake_password'
self.user = create_account(password=self.password)
def test_login_endpoint(self):
client = Client()
response = client.get(API_V1_LOGIN_URL)
self.assertEqual(
response.status_code,
405,
"GET not allowed here",
)
response = client.post(API_V1_LOGIN_URL, {'username': 'fake', 'password': 'fake'})
self.assertTrue('User not found' in str(response.content), 'Expected user not to be there')
user = self.user
response = client.post(API_V1_LOGIN_URL, {'username': user.username, 'password': self.password})
self.assertEqual(
response.status_code,
200,
"Expected 200",
)
data = response.data
self.assertEqual(
data.get('email'),
user.email,
"Expected user email",
)
self.assertEqual(
data.get('username'),
user.username,
"Expected username",
)
token = Token.objects.filter(user=user).first()
self.assertEqual(
data.get('token'),
token.key,
"Expected valid token",
)

Wyświetl plik

@ -0,0 +1,49 @@
from django.test import Client, TestCase
from rest_framework.authtoken.models import Token
from files.tests import create_account
API_V1_USER_TOKEN_URL = '/api/v1/user/token'
class TestUserToken(TestCase):
fixtures = ["fixtures/categories.json", "fixtures/encoding_profiles.json"]
def setUp(self):
self.password = 'this_is_a_fake_password'
self.user = create_account(password=self.password)
def test_user_token_endpoint(self):
client = Client()
response = client.get(API_V1_USER_TOKEN_URL)
self.assertEqual(
response.status_code,
403,
"FORBIDDEN",
)
user = self.user
client.force_login(user=user)
response = client.post(API_V1_USER_TOKEN_URL)
self.assertEqual(
response.status_code,
405,
"method not allowed here",
)
response = client.get(API_V1_USER_TOKEN_URL)
data = response.data
self.assertEqual(
response.status_code,
200,
"expected 200",
)
token = Token.objects.filter(user=user).first()
self.assertEqual(
data.get('token'),
token.key,
"Expected valid token",
)

Wyświetl plik

@ -0,0 +1,41 @@
from django.test import Client, TestCase
from files.tests import create_account
API_V1_LOGIN_URL = '/api/v1/whoami'
class TestUserWhoami(TestCase):
fixtures = ["fixtures/categories.json", "fixtures/encoding_profiles.json"]
def setUp(self):
self.user = create_account()
def test_whoami_endpoint(self):
client = Client()
response = client.get(API_V1_LOGIN_URL)
self.assertEqual(
response.status_code,
403,
"Expected 403",
)
user = self.user
client.force_login(user=user)
response = client.get(API_V1_LOGIN_URL)
self.assertEqual(
response.status_code,
200,
"Expected 200",
)
data = response.data
self.assertEqual(
data.get('description'),
user.description,
"Expected user description",
)
self.assertEqual(
data.get('username'),
user.username,
"Expected username",
)

Wyświetl plik

@ -1,4 +0,0 @@
def test_new_user(user_factory):
print(user_factory.name)
print(user_factory.description)
assert True

Wyświetl plik

@ -1,10 +1,10 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from django.conf.urls import url from django.conf.urls import re_path
from . import views from . import views
app_name = "uploader" app_name = "uploader"
urlpatterns = [ urlpatterns = [
url(r"^upload/$", views.FineUploaderView.as_view(), name="upload"), re_path(r"^upload/$", views.FineUploaderView.as_view(), name="upload"),
] ]

Wyświetl plik

@ -1,5 +1,7 @@
from django import forms from django import forms
from files.methods import is_mediacms_manager
from .models import Channel, User from .models import Channel, User
@ -17,7 +19,6 @@ class UserForm(forms.ModelForm):
fields = ( fields = (
"name", "name",
"description", "description",
"email",
"logo", "logo",
"notification_on_comments", "notification_on_comments",
"is_featured", "is_featured",
@ -39,7 +40,7 @@ class UserForm(forms.ModelForm):
def __init__(self, user, *args, **kwargs): def __init__(self, user, *args, **kwargs):
super(UserForm, self).__init__(*args, **kwargs) super(UserForm, self).__init__(*args, **kwargs)
self.fields.pop("is_featured") self.fields.pop("is_featured")
if not user.is_superuser: if not is_mediacms_manager(user):
self.fields.pop("advancedUser") self.fields.pop("advancedUser")
self.fields.pop("is_manager") self.fields.pop("is_manager")
self.fields.pop("is_editor") self.fields.pop("is_editor")

Wyświetl plik

@ -1,4 +1,7 @@
from django.conf import settings
from django.contrib.auth import authenticate
from rest_framework import serializers from rest_framework import serializers
from rest_framework.authtoken.models import Token
from .models import User from .models import User
@ -77,3 +80,46 @@ class UserDetailSerializer(serializers.ModelSerializer):
"default_channel_edit_url", "default_channel_edit_url",
) )
extra_kwargs = {"name": {"required": False}} extra_kwargs = {"name": {"required": False}}
class LoginSerializer(serializers.Serializer):
email = serializers.CharField(max_length=255, required=False)
username = serializers.CharField(max_length=255, required=False)
password = serializers.CharField(max_length=128, write_only=True)
token = serializers.CharField(max_length=255, required=False)
def validate(self, data):
email = data.get('email', None)
username = data.get('username', None)
password = data.get('password', None)
if settings.ACCOUNT_AUTHENTICATION_METHOD == 'username' and not username:
raise serializers.ValidationError('username is required to log in.')
else:
username_or_email = username
if settings.ACCOUNT_AUTHENTICATION_METHOD == 'email' and not email:
raise serializers.ValidationError('email is required to log in.')
else:
username_or_email = email
if settings.ACCOUNT_AUTHENTICATION_METHOD == 'username_email' and not (username or email):
raise serializers.ValidationError('username or email is required to log in.')
else:
username_or_email = username or email
if password is None:
raise serializers.ValidationError('password is required to log in.')
user = authenticate(username=username_or_email, password=password)
if user is None:
raise serializers.ValidationError('User not found.')
if not user.is_active:
raise serializers.ValidationError('User has been deactivated.')
token = Token.objects.filter(user=user).first()
if not token:
token = Token.objects.create(user=user)
return {'email': user.email, 'username': user.username, 'token': token.key}

Wyświetl plik

@ -1,41 +1,45 @@
from django.conf.urls import url from django.conf.urls import re_path
from django.urls import path
from . import views from . import views
urlpatterns = [ urlpatterns = [
url(r"^user/(?P<username>[\w@._-]*)$", views.view_user, name="get_user"), re_path(r"^user/(?P<username>[\w@._-]*)$", views.view_user, name="get_user"),
url(r"^user/(?P<username>[\w@._-]*)/$", views.view_user, name="get_user"), re_path(r"^user/(?P<username>[\w@._-]*)/$", views.view_user, name="get_user"),
url( re_path(
r"^user/(?P<username>[\w@.]*)/media$", r"^user/(?P<username>[\w@.]*)/media$",
views.view_user_media, views.view_user_media,
name="get_user_media", name="get_user_media",
), ),
url( re_path(
r"^user/(?P<username>[\w@.]*)/playlists$", r"^user/(?P<username>[\w@.]*)/playlists$",
views.view_user_playlists, views.view_user_playlists,
name="get_user_playlists", name="get_user_playlists",
), ),
url( re_path(
r"^user/(?P<username>[\w@.]*)/about$", r"^user/(?P<username>[\w@.]*)/about$",
views.view_user_about, views.view_user_about,
name="get_user_about", name="get_user_about",
), ),
url(r"^user/(?P<username>[\w@.]*)/edit$", views.edit_user, name="edit_user"), re_path(r"^user/(?P<username>[\w@.]*)/edit$", views.edit_user, name="edit_user"),
url(r"^channel/(?P<friendly_token>[\w]*)$", views.view_channel, name="view_channel"), re_path(r"^channel/(?P<friendly_token>[\w]*)$", views.view_channel, name="view_channel"),
url( re_path(
r"^channel/(?P<friendly_token>[\w]*)/edit$", r"^channel/(?P<friendly_token>[\w]*)/edit$",
views.edit_channel, views.edit_channel,
name="edit_channel", name="edit_channel",
), ),
# API VIEWS # API VIEWS
url(r"^api/v1/users$", views.UserList.as_view(), name="api_users"), path('api/v1/whoami', views.UserWhoami.as_view(), name='user-whoami'),
url(r"^api/v1/users/$", views.UserList.as_view()), path('api/v1/user/token', views.UserToken.as_view(), name='user-token'),
url( path('api/v1/login', views.LoginView.as_view(), name='user-login'),
re_path(r"^api/v1/users$", views.UserList.as_view(), name="api_users"),
re_path(r"^api/v1/users/$", views.UserList.as_view()),
re_path(
r"^api/v1/users/(?P<username>[\w@._-]*)$", r"^api/v1/users/(?P<username>[\w@._-]*)$",
views.UserDetail.as_view(), views.UserDetail.as_view(),
name="api_get_user", name="api_get_user",
), ),
url( re_path(
r"^api/v1/users/(?P<username>[\w@._-]*)/contact", r"^api/v1/users/(?P<username>[\w@._-]*)/contact",
views.contact_user, views.contact_user,
name="api_contact_user", name="api_contact_user",

Wyświetl plik

@ -5,7 +5,8 @@ from django.http import HttpResponseRedirect
from django.shortcuts import render from django.shortcuts import render
from drf_yasg import openapi as openapi from drf_yasg import openapi as openapi
from drf_yasg.utils import swagger_auto_schema from drf_yasg.utils import swagger_auto_schema
from rest_framework import permissions, status from rest_framework import generics, permissions, status
from rest_framework.authtoken.models import Token
from rest_framework.decorators import api_view from rest_framework.decorators import api_view
from rest_framework.exceptions import PermissionDenied from rest_framework.exceptions import PermissionDenied
from rest_framework.parsers import ( from rest_framework.parsers import (
@ -23,7 +24,7 @@ from files.methods import is_mediacms_editor, is_mediacms_manager
from .forms import ChannelForm, UserForm from .forms import ChannelForm, UserForm
from .models import Channel, User from .models import Channel, User
from .serializers import UserDetailSerializer, UserSerializer from .serializers import LoginSerializer, UserDetailSerializer, UserSerializer
def get_user(username): def get_user(username):
@ -305,3 +306,65 @@ class UserDetail(APIView):
user.delete() user.delete()
return Response(status=status.HTTP_204_NO_CONTENT) return Response(status=status.HTTP_204_NO_CONTENT)
class UserWhoami(generics.RetrieveAPIView):
parser_classes = (JSONParser, FormParser, MultiPartParser)
queryset = User.objects.all()
permission_classes = (permissions.IsAuthenticated,)
serializer_class = UserDetailSerializer
def get_object(self):
return User.objects.get(id=self.request.user.id)
@swagger_auto_schema(
tags=['Users'],
operation_summary='Whoami user information',
operation_description='Whoami user information',
responses={200: openapi.Response('response description', UserDetailSerializer), 403: 'Forbidden'},
)
def get(self, request, *args, **kwargs):
return super(UserWhoami, self).get(request, *args, **kwargs)
class UserToken(APIView):
parser_classes = (JSONParser,)
permission_classes = (permissions.IsAuthenticated,)
@swagger_auto_schema(
tags=['Users'],
operation_summary='Get a user token',
operation_description="Returns an authenticated user's token",
responses={200: 'token', 403: 'Forbidden'},
)
def get(self, request, *args, **kwargs):
token = Token.objects.filter(user=request.user).first()
if not token:
token = Token.objects.create(user=request.user)
return Response({'token': str(token)}, status=200)
class LoginView(APIView):
permission_classes = (permissions.AllowAny,)
serializer_class = LoginSerializer
parser_classes = (MultiPartParser, FormParser, FileUploadParser)
@swagger_auto_schema(
tags=['Users'],
operation_summary='Login url',
operation_description="Login url endpoint. According to what the portal provides, you may provide username and/or email, plus the password",
manual_parameters=[
openapi.Parameter(name="username", in_=openapi.IN_FORM, type=openapi.TYPE_STRING, required=False, description="username"),
openapi.Parameter(name="email", in_=openapi.IN_FORM, type=openapi.TYPE_STRING, required=False, description="email"),
openapi.Parameter(name="password", in_=openapi.IN_FORM, type=openapi.TYPE_STRING, required=True, description="password"),
],
responses={200: openapi.Response('user details', LoginSerializer), 404: 'Bad request'},
)
def post(self, request):
data = request.data
serializer = self.serializer_class(data=data)
serializer.is_valid(raise_exception=True)
return Response(serializer.data, status=status.HTTP_200_OK)