Swagger - add manual parameters? - django-rest-framework

Very new to swagger
class VerifyEmailAPI(generics.GenericAPIView):
"""
Verify Email of a registered user
"""
token_param_config = openapi.Schema(type=openapi.TYPE_OBJECT, properties={
'token': openapi.Schema(type=openapi.TYPE_STRING, description='Test')
})
#swagger_auto_schema(manual_parameters=[token_param_config])
def get(self, request):
token = request.GET.get('token')
# print(token)
try:
payload = jwt.decode(token, settings.SECRET_KEY, algorithms=['HS256'])
# print(payload)
user = User.objects.get(id=payload['user_id'])
# print(user)
if not user.is_verified:
user.is_verified = True
user.save()
return Response({'msg': 'We have verified your email.'})
except jwt.ExpiredSignatureError as identifier:
return Response({'msg': 'Link has expired.'})
except jwt.exceptions.DecodeError as identifier:
return Response({'msg': 'Please request a new link, this one is not working.'})
I am getting: > AttributeError: object of class Schema has no attribute in_
I tried:
1)
#swagger_auto_schema(request_body=openapi.Schema(type=openapi.TYPE_OBJECT, properties={
'token': openapi.Schema(type=openapi.TYPE_STRING, description='Test')
}))
#swagger_auto_schema(method='get', request_body=openapi.Schema(type=openapi.TYPE_OBJECT, properties={
'token': openapi.Schema(type=openapi.TYPE_STRING, description='Test')
}))
token_param_config = openapi.Parameter('token', in_=openapi.IN_QUERY,
description='A system generated token to verify the email', type=openapi.TYPE_STRING)
#swagger_auto_schema(manual_parameters=[token_param_config])
Not sure where I am going wrong with this.

Related

(Django Simple JWT) 401 Unauthorized when logging out

I'm having trouble with simple JWT when I try to log out. I'm informed that when logging out, the cookie must be deleted and the refresh token must be blacklisted!
All of the previous authentication steps (register, login) worked as expected, except for logout.
Register
Login
Logout
In the capture above I got 401 unauthorized. The cookie seemed to be removed as intended.
As suggested by the Q/As I found, I have tried the following:
Print Exception but nothing showed beside 401 error.
Add authorization header and interchange between 'Bearer ' and 'JWT '.
Modify settings.py and apply simple jwt authentication code templates. My code is as followed:
settings.py
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': (
'rest_framework_simplejwt.authentication.JWTAuthentication',
)
}
SIMPLE_JWT = {
'ACCESS_TOKEN_LIFETIME': timedelta(minutes=60),
'REFRESH_TOKEN_LIFETIME': timedelta(days=1),
'ROTATE_REFRESH_TOKENS': True,
'BLACKLIST_AFTER_ROTATION': True,
'ALGORITHM': 'HS256',
'SIGNING_KEY': SECRET_KEY,
'VERIFYING_KEY': None,
'AUTH_HEADER_TYPES': ('Bearer', 'JWT',),
'AUTH_HEADER_NAME': 'HTTP_AUTHORIZATION',
'USER_ID_FIELD': 'email',
'USER_ID_CLAIM': 'user_id',
'AUTH_TOKEN_CLASSES': ('rest_framework_simplejwt.tokens.AccessToken',),
'TOKEN_TYPE_CLAIM': 'token_type',
}
AUTH_USER_MODEL = 'users.CustomUser'
CORS_ALLOWED_ORIGINS = [
"http://127.0.0.1:3000",
"http://localhost:3000",
"http://127.0.0.1:8000",
"http://localhost:8000",
]
serializers.py
class LogoutSerializer(serializers.Serializer):
refresh = serializers.CharField()
default_error_messages = {
'bad_token': _('Token is invalid or expired')
}
def validate(self, attrs):
self.token = attrs['refresh']
return attrs
def save(self, **kwargs):
try:
RefreshToken(self.token).blacklist()
except TokenError:
self.fail('bad_token')
except Exception as e:
print('\nException in logging out:', e)
views.py
class RegisterView(APIView):
permission_classes = [AllowAny]
def post(self, request, format='json'):
serializer = UserSerializer(data=request.data)
if serializer.is_valid():
user = serializer.save()
if user:
json = serializer.data
return Response(json, status=status.HTTP_201_CREATED)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
class LoginView(APIView):
def post(self, request):
email = request.data['email']
password = request.data['password']
user = CustomUser.objects.filter(email=email).first()
if user is None:
raise AuthenticationFailed('User not found!')
if not user.check_password(password):
raise AuthenticationFailed('Incorrect password!')
payload = {
# 'id': user.id,
'email': user.email,
'exp': datetime.datetime.utcnow() + datetime.timedelta(minutes=60),
'iat': datetime.datetime.utcnow()
}
token = jwt.encode(payload, 'secret', algorithm='HS256')
response = Response({'message': 'success'})
response.set_cookie(key='jwt', value=token, httponly=True)
response.data = {
'jwt': token
}
return response
class LogoutView(generics.GenericAPIView):
serializer_class = LogoutSerializer
permission_classes = (permissions.IsAuthenticated,)
def post(self, request):
serializer = self.serializer_class(data=request.data)
serializer.is_valid(raise_exception=True)
serializer.save()
return Response(status=status.HTTP_204_NO_CONTENT)
users/urls.py
urlpatterns = [
path('', UserList.as_view()),
path('register', RegisterView.as_view()),
path('login', LoginView.as_view()),
path('user', UserView.as_view()),
path('logout', LogoutView.as_view()),
]
models.py
class CustomUserManager(BaseUserManager):
def create_superuser(self, email, password=None):
if password is None:
raise TypeError('Password should not be none')
user = self.create_user(email, password)
user.is_superuser = True
user.is_staff = True
if user.is_superuser is not True:
raise ValueError(
'Superuser must be assigned to is_staff=True.')
if user.is_staff is not True:
raise ValueError(
'Superuser must be assigned to is_superuser=True.')
user.save()
return user
def create_user(self, email, password=None):
if email is None:
raise TypeError('Users should have a Email')
email = self.normalize_email(email)
user = self.model(email=email)
user.set_password(password)
user.save()
return user
AUTH_PROVIDERS = {'facebook': 'facebook', 'google': 'google',
'twitter': 'twitter', 'email': 'email'}
class CustomUser(AbstractBaseUser, PermissionsMixin):
email = models.EmailField(max_length=255, unique=True, db_index=True)
is_active = models.BooleanField(default=True)
is_staff = models.BooleanField(default=False)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
about = models.TextField(_(
'about'), max_length=500, blank=True)
auth_provider = models.CharField(
max_length=255, blank=False,
null=False, default=AUTH_PROVIDERS.get('email'))
USERNAME_FIELD = 'email'
# REQUIRED_FIELDS = ['username']
objects = CustomUserManager()
def __str__(self):
return self.email
def tokens(self):
refresh = RefreshToken.for_user(self)
return {
'refresh': str(refresh),
'access': str(refresh.access_token)
}
The code above was derived from several tutorials but somehow did not work like they should!
Could you suggest me a way to solve this? Thank you!
This is because you have permission_classes = (permissions.IsAuthenticated,) in the LogoutView.
You can safely allow logout for any user.
permission_classes = (AllowAny,)

Passing pk in a get request function

I am new to Django so I figure this question could be a bit stupid.I have an api endpoint that returns a list of Doctors(and their details) and another that returns one doctor(and his details)-this is the call am trying to make.I think the issue I am having is with how to ref the pk in the request url.
As it is, when I test on postman I get the error {
"errors": "JSONDecodeError('Expecting value: line 1 column 1 (char 0)',)",
"status": "error"
}
I am almost certain the issue is in api_services.py.I really hope someone can just point it out to me.
views.py
`class FinanceDoctorsView(GenericAPIView):
authentication_classes = [TokenAuthentication]
permission_classes = [IsAuthenticated]
#classmethod
#encryption_check
def get(self, request, *args, **kwargs):
response = {}
pk = kwargs.get("pk")
try:
result = {}
auth = cc_authenticate()
res = getDoctorInfo(auth["key"], pk)
result = res
return Response(result, status=status.HTTP_200_OK)
except Exception as e:
error = getattr(e, "message", repr(e))
result["errors"] = error
result["status"] = "error"
return Response(result, status=status.HTTP_400_BAD_REQUEST)`
api_services.py
import requests
def getDoctorInfo(auth, params):
print("getting doctorInfo from Callcenter")
try:
headers = {
"Authorization": f'Token {auth}'
}
url = f'{CC_URL}/finance/doctor-info/<int:pk>'
res = requests.get(url, headers=headers)
print("returning doctorInfo response", res.status_code)
return res.json()
except ConnectionError as err:
print("connection exception occurred")
print(err)
return err
urls.py
path(
"doctor-info/<int:pk>", views.FinanceDoctorsView.as_view(), name="doctor_info"
),
I think in the api service file, you have made a typo
url = f'{CC_URL}/finance/doctor-info/<int:pk>'
Should had be
# as in the function you have defined params,
# and I think it could have been renamed as pk
url = f'{CC_URL}/finance/doctor-info/{params}'

Testing POST with authentication in Django Rest Framework issue 401 returing

I'm trying to test POSTing data to a view in django-rest-framework that requires authentication. But I can't. I've read many threads of supposed solutions, but can't find any that solves to me.
Test:
class TodoListCreateAPIViewTestCase(APITestCase):
url = reverse("todolist:add")
def setUp(self):
self.username = "john"
self.email = "john#snow.com"
self.password = "you_know_nothing"
self.user = User.objects.create_user(self.username, self.email, self.password)
self.token = Token.objects.create(user=self.user)
#checking token here
def test_create_todo(self):
self.client.login(email=self.email, password='you_know_nothing')
client = APIClient()
client.credentials(HTTP_AUTHORIZATION='Token ' + self.token.key)
response = self.client.post(self.url, {"list_name": "Clean the room!"}, format='json')
self.assertEqual(201, response.status_code)
View
class Addtodolist(APIView):
authentication_classes = (JSONWebTokenAuthentication,TokenAuthentication)
permission_classes = [IsAuthenticated, ]
def post(self, request):
data = request.data
todolist_instance = Todolist.objects.filter(for_user=self.request.user).first()
if not todolist_instance:
list_serilaizer = AddtodolistSerializers(data=data, context={'user': request.user})
if list_serilaizer.is_valid():
list_serilaizer.save()
return Response(data=success_response(data=list_serilaizer.data, msg='Successfully Created list!'),
status=status.HTTP_200_OK)
else:
return Response(
failure_response(data={'detail': list_serilaizer.errors()}, msg='Following errors occured'),
status=status.HTTP_400_BAD_REQUEST)
else:
return Response(
failure_response(data={'detail': 'User can have only 1 List'}, msg='User can have only 1 List'),
status=status.HTTP_409_CONFLICT)
Change your code like this:
from django.shortcuts import reverse
from django.contrib.auth import get_user_model
from rest_framework.test import APIClient, APITestCase
from rest_framework.authtoken.models import Token
class TodoListCreateAPIViewTestCase(APITestCase):
url = reverse("todolist:add")
def setUp(self):
self.username = "john"
self.email = "john#snow.com"
self.password = "you_know_nothing"
self.user = get_user_model().objects.create_user(self.username,
self.email,
self.password)
self.token = Token.objects.create(user=self.user)
def test_create_todo(self):
client = APIClient()
client.login(username=self.username,
email=self.email,
password=self.password)
client.credentials(HTTP_AUTHORIZATION='Token ' + self.token.key)
response = client.post(self.url,
{"list_name": "Clean the room!"},
format='json')
self.assertEqual(response.status_code, 201)

How to get and delete access token django api

I want to get access token and delete it in logout api.But i am unable to get access token for the current log in user.
models.py
class MyUserManager(BaseUserManager):
def create_user(self, email, password=None, **extra_fields):
if not email:
raise ValueError('Users must have an email address')
account = self.model(
email=self.normalize_email(email),
)
account.account_type = extra_fields.get('account_type')
account.set_password(password)
account.save(using=self._db)
return account
def create_superuser(self, email, password, **extra_fields):
account = self.create_user(
email,
password=password,
)
account.account_type = 'A'
account.is_admin = True
account.save(using=self._db)
return account
class Account(AbstractBaseUser):
type_choice = (
('A', 'Admin'),
('S','Student'),
('T','Teacher'),
)
email = models.EmailField(
verbose_name='email address',
max_length=255,
unique=True,
)
account_type = models.CharField(choices=type_choice, max_length=1, null=True)
is_active = models.BooleanField(default=True)
is_admin = models.BooleanField(default=False)
objects = MyUserManager()
USERNAME_FIELD = 'email'
def __str__(self):
return self.email
def has_perm(self, perm, obj=None):
return True
def has_module_perms(self, app_label):
return True
#property
def is_staff(self):
return self.is_admin
#views.py
class AccountViewSet(viewsets.ViewSet):
def create(self,request):
# permission_classes = [TokenHasReadWriteScope]
try:
email=request.data.get('email')
password=request.data.get('password')
print(request.data)
# account_type=request.data.get('account_type')
if not all([email,password]):
raise Exception('All Fields are mandatory')
obj=Account()
obj.email=email
obj.set_password(password)
obj.save()
Application.objects.get_or_create(user=obj, client_type=Application.CLIENT_CONFIDENTIAL,
authorization_grant_type=Application.GRANT_PASSWORD)
token = get_access_token(obj)
return Response({"response":token, "success": True}, status=status.HTTP_200_OK)
except Exception as error:
traceback.print_exc()
return Response({"message": str(error), "success": False}, status=status.HTTP_200_OK)
def list(self,request):
try:
user=Account.objects.all()
users=[]
for i in user:
users.append({
"name":i.name,
"Address":i.Address,
"account_type":i.account_type,
})
return Response({"success":True, "users":users})
except Exception as error:
traceback.print_exc()
return Response({"message": str(error), "success": False}, status=status.HTTP_200_OK)
def retrieve(self, request, pk=None):
user = Account.objects.get(id=pk)
data = {
"name":user.name,
"email":user.Address,
#"password" : user.password,
#"date_of_birth":user.date_of_birth,
"account_type":user.account_type
}
return Response({"data":data,"success":True})
def destroy(self, request, pk=None):
employee = Account.objects.get(id=pk).delete()
print('>>>>>>>>>>',employee)
#employee.delete()
return Response({"success":'done',"message":"delete called"})
class LoginViewSet(viewsets.ViewSet):
def create(self,request):
try:
email = request.data.get('email')
password = request.data.get('password')
print(email,password)
if not all([email,password]):
raise Exception('all fields are mandatory')
acc = Account.objects.get(email = email)
print(acc.check_password(password))
account = authenticate(username=email,password=password)
print(account)
if account is not None:
token = get_access_token(account)
obj = Account.objects.get(email=account)
data = {
"email":account.email,
}
else:
raise Exception('Credential not matched')
return Response({"message": "Login Successfully", "user_info": data, "token": token, "Success": True}, status = status.HTTP_200_OK)
except Exception as error:
traceback.print_exc()
return Response({"message":str(error),"success":False},status = status.HTTP_200_OK)
class LogoutViewSet(viewsets.ViewSet):
def list(self, request, format=None):
accesstoken=AccessToken.objects.get(token=request.META.get('HTTP_AUTHORIZATION'))
return Response('response',status=status.HTTP_200_OK)

Tocken authentication fails in django rest

I can create user models. But authentication always fails even if there exists such a user with the given credentials
models.py have user creation method as
#receiver(post_save, sender=settings.AUTH_USER_MODEL)
def create_auth_token(sender, instance=None, created=False, **kwargs):
if created:
Token.objects.create(user=instance)
views.py have login/authentication method as
class ObtainAuthToken(APIView):
#csrf_exempt
def post(self, request):
user = authenticate(
username=request.data['username'],
password=request.data['password'])
if user:
token, created = Token.objects.get_or_create(user=user)
return Response({'token': token.key, 'user': UserSerializer(user).data})
return Response('Invalid username or passwordee', status=status.HTTP_400_BAD_REQUEST)
in settings.py
AUTH_USER_MODEL = 'account.User'
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
}
}
settings.py is here
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': (
'rest_framework.authentication.TokenAuthentication',
),
}
What is the problem with this code?

Resources