Flask-jwt and Flask-resftul error handling - flask

I'm using flask-jwt and flask-restful
This is how flask-jwt handling errors(taken from its github repo) but none of them let me take the parameters of JWTError.
if auth is None:
raise JWTError('Authorization Required', 'Authorization header was missing', 401, {
'WWW-Authenticate': 'JWT realm="%s"' % realm
})
parts = auth.split()
if parts[0].lower() != auth_header_prefix.lower():
raise JWTError('Invalid JWT header', 'Unsupported authorization type')
elif len(parts) == 1:
raise JWTError('Invalid JWT header', 'Token missing')
elif len(parts) > 2:
raise JWTError('Invalid JWT header', 'Token contains spaces')
try:
handler = _jwt.decode_callback
payload = handler(parts[1])
except SignatureExpired:
raise JWTError('Expired JWT', 'Token is expired', 401, {
"WWW-Authenticate": 'JWT realm="{0}"'.format(realm)
})
except BadSignature:
raise JWTError('Invalid JWT', 'Token is undecipherable')
_request_ctx_stack.top.current_user = user = _jwt.user_callback(payload)
if user is None:
raise JWTError('Invalid JWT', 'User does not exist')
And the following are the different ways how I try to handle JWTError
In flask:
def handle_user_exception_again(e):
if isinstance(e, JWTError):
data = {'status_code': 1132, 'message': "JWTError already exists."}
return jsonify(data), e.status_code, e.headers
return e
app.handle_user_exception = handle_user_exception_again
In flask-restful (handle_error)
class FlaskRestfulJwtAPI(Api):
def handle_error(self, e):
if isinstance(e, JWTError):
code = 400
data = {'status_code': code, 'message': "JWTError already exists."}
elif isinstance(e, KeyError):
code = 400
data = {'status_code': code, 'message': "KeyError already exists."}
else:
# Did not match a custom exception, continue normally
return super(FlaskRestfulJwtAPI, self).handle_error(e)
return self.make_response(data, code)
In flask-restful (error_router)
class FlaskRestfulJwtAPI(Api):
def error_router(self, original_handler, e):
print(type(e))
if e is JWTError:#KeyError:
data = {
"code":400,
"message":"JWTError"
}
return jsonify(data), 400
elif isinstance(e,KeyError):
data = {
"code":400,
"message":"KeyError"
}
return jsonify(data), 400
else:
return super(FlaskRestfulJwtAPI, self).error_router(original_handler, e)

I see that you are trying to raise an HTTPException from these errors, which helps with returning them to users. To raise an HTTP exception, you can catch all errors and if they are an instance of a JWTError, you can convert them to an instance of an HTTPException using a function like the following:
def convert_to_http_exception(e):
if isinstance(e, JWTError):
jwtdescription = e.error + ": " + e.description
http_exception = HTTPException(description=jwtdescription)
http_exception.code = e.status_code
return http_exception
else:
return e

Related

Strange TyperError put() missing 1 required positional argument: 'path'

I've been trying to test my PUT method in the following APITestcase:
def test_story_delete(self):
c = APIRequestFactory
user = User.objects.get(username='test1')
payload = {'storyName': 'changetest'}
request = c.put(reverse('storyFunctions',args=[self.room.pk,self.story.pk]), format='json')
force_authenticate(request,user=user)
My URL:
path('room/<int:pk>/story/<int:idStory>/adm', APIHstory.as_view(),name='storyFunctions'),
And I'm keep receiving this error:
TypeError: put() missing 1 required positional argument: 'path'
I don't understand what is going on because i declared the path inside request. Can someone help me?
Edit: sharing the view that I'm testing
class APIstory(APIView):
permission_classes = [IsAuthenticated]
def put(self,request, pk, idStory):
data = self.request.data
pk = self.kwargs['pk']
id = self.kwargs['idStory']
name = data['storyName'].strip()
if name == "" or str.isspace(name) or len(name) < 4:
return Response({"error": "minimum of 4 words"}, status=400)
if PokerRoom.objects.filter(id=pk).exists():
session = PokerRoom.objects.filter(id=pk)
if session[0].status == 'Finished':
return Response({'error': 'Session already ended'}, status=400)
else:
session = PokerRoom(id=pk)
if Story.objects.filter(id=id, idRoom=session).exists():
if not Story.objects.filter(idRoom=session, storyName=name).exists():
for hist in Story.objects.filter(id=id, idRoom=session):
if hist.status == 'Pending':
if hist.storyName == name:
return Response({'error':'story with the same name'}, status=400)
hist.storyName = name
hist.save()
status = hist.status
body = {"id":id,"storyName":name,"status":status}
message_socket("STORY_UPDATE", pk, body)
return Response({'success': 'story {} edited, status is {}.'.format(hist.id,hist.status)})
else:
return Response({'error': 'story already ended'}, status= 400)
else:
return Response({'error': 'story with the same name'}, status= 400)
return Response({'error': 'session doesnt exists.'}, status=400)
else:
return Response({'error': 'session doesnt exists.'}, status=400)
Edit2: I was forgetting to put the body in my request, but now I'm getting the following error: TypeError: super(type, obj): obj must be an instance or subtype of type
Shouldn't you add the request body also in a put request?
Something like this?
request = c.put(reverse('storyFunctions', kwargs={'pk': self.room.pk, 'idStory': self.story.pk}), payload, format='json')
As per the docs

Unit Testing in Python Djnago

I am using
Django==3.0.3
djangorestframework==3.11.0
python ==3.6.8
I want to write unit testing for API and no need to use any database(no need of mock database)
that mean I want to mock the database call and write unit test cases
how can i write which property is used for this
Showing my api
#api_view(['POST'])
#permission_classes([IsAuthenticated])
def employee_entry(request):
try:
login = User.objects.get(pk=request.user.id)
validationmsg = ''
emp_data = request.data
if not emp_data:
validationmsg = validation["FDP15"]
elif emp_data["EmployeeName"] is None or emp_data["EmployeeName"] == '':
validationmsg = validation["FDP1"]
elif emp_data["EmployeeCode"] is None or emp_data["EmployeeCode"] == '':
validationmsg = validation["FDP2"]
elif Employee.objects.filter(EmployeeCode=emp_data["EmployeeCode"]).count() > 0:
validationmsg = validation["FDP3"]
if validationmsg != '':
return Response({msg: validationmsg}, status=status.HTTP_400_BAD_REQUEST)
employee = Employee(
EmployeeName=emp_data["EmployeeName"],
EmployeeCode=emp_data["EmployeeCode"],
Security=emp_data["Security"],
CreatedDate=date.today(),
CreatedUser=login,
)
employee.save()
if emp_data["Security"] == 1:
device = Device.objects.filter(~Q(DeviceStatus=static_values["const0"]))
employee.Device.set(device)
elif emp_data["Security"] == 0:
device = Device.objects.filter(~Q(DeviceStatus=static_values["const0"]), DefaultAccess=True)
employee.Device.set(device)
return Response({"EmployeeId": employee.EmployeeId}, status=status.HTTP_200_OK)
except(KeyError, TypeError, ValueError) as ex:
logging.getLogger("error_logger").exception(repr(ex))
return Response({msg: validation["FDP21"]}, status=status.HTTP_400_BAD_REQUEST)
except Exception as ex:
logging.getLogger("error_logger").exception(repr(ex))
return Response({msg: validation["FDP23"]}, status=status.HTTP_400_BAD_REQUEST)

Amazon Lex with Lambda function - error 424 Failed Dependency (Python)

I have copied and editied the OrderFlowers Amazon Lex blueprint to ask for a person's first and last name. When testing the Lambda function, I get the correct response but when trying to invoke my intent in Lex I get a 424 error Failed Dependency in my broswer console, and my test bot reports "An error has occurred: Invalid Lambda Response: Received error response from Lambda: Unhandled". I have looked over the code a number of times and I cannot work out if it is a permission issue or, there is something wrong with the fulfillment. My code is below and thanks in advance.
import math
import dateutil.parser
import datetime
import time
import os
import logging
logger = logging.getLogger()
logger.setLevel(logging.DEBUG)
def get_slots(intent_request):
return intent_request['currentIntent']['slots']
def elicit_slot(session_attributes, intent_name, slots, slot_to_elicit, message):
return {
'sessionAttributes': session_attributes,
'dialogAction': {
'type': 'ElicitSlot',
'intentName': intent_name,
'slots': slots,
'slotToElicit': slot_to_elicit,
'message': message
}
}
def close(session_attributes, fulfillment_state, message):
response = {
'sessionAttributes': session_attributes,
'dialogAction': {
'type': 'Close',
'fulfillmentState': fulfillment_state,
'message': message
}
}
return response
def delegate(session_attributes, slots):
return {
'sessionAttributes': session_attributes,
'dialogAction': {
'type': 'Delegate',
'slots': slots
}
}
def parse_int(n):
try:
return int(n)
except ValueError:
return float('nan')
def build_validation_result(is_valid, violated_slot, message_content):
if message_content is None:
return {
"isValid": is_valid,
"violatedSlot": violated_slot,
}
return {
'isValid': is_valid,
'violatedSlot': violated_slot,
'message': {'contentType': 'PlainText', 'content': message_content}
}
def validate_get_name(first_name, last_name):
first_name = ['john', 'ben']
if first_name is None and first_name not in first_name:
return build_validation_result(False,
'FirstName',
'Sorry please state your first name. ')
last_name = ['smith', 'doran']
if last_name is None and last_name not in last_name:
return build_validation_result (False,
'LastName',
'Sorry please state your last name. ')
return build_validation_result(True, None, None)
def get_name(intent_request):
first_name = get_slots(intent_request)["FirstName"]
last_name = get_slots(intent_request)["LastName"]
source = intent_request['invocationSource']
if source == 'DialogCodeHook':
slots = get_slots(intent_request)
validation_result = validate_get_name(first_name, last_name)
if not validation_result['isValid']:
slots[validation_result['violatedSlot']] = None
return elicit_slot(intent_request['sessionAttributes'],
intent_request['currentIntent']['name'],
slots,
validation_result['violatedSlot'],
validation_result['message'])
output_session_attributes = intent_request['sessionAttributes'] if intent_request['sessionAttributes'] is not None else {}
if get_name is not None:
return delegate(output_session_attributes, get_slots(intent_request))
return close(intent_request['sessionAttributes'],
'Fulfilled',
{'contentType': 'PlainText',
'content': 'Thanks, we have now preformed your intent'})
def dispatch(intent_request):
logger.debug('dispatch userId={}, intentName={}'.format(intent_request['userId'], intent_request['currentIntent']['name']))
intent_name = intent_request['currentIntent']['name']
if intent_name == 'GetName':
return get_name(intent_request)
raise Exception('Intent with name ' + intent_name + ' not supported')
def lambda_handler(event, context):
os.environ['TZ'] = 'America/New_York'
time.tzset()
logger.debug('event.bot.name={}'.format(event['bot']['name']))
return dispatch(event)
I tried to reproduce your error and the only situations when the error occured in my case were when I had some syntax errors like improper indentation. Go to function logs (either: go to https://console.aws.amazon.com/cloudwatch, click Logs on the left pane, choose the logs group corresponding to your lambda function, choose log stream having the time when you saw the error and look for some messages or open your lambda function code, go to Monitoring tab and click View logs in CloudWatch)
I saw that the code you shared here has wrong indentation (functions body should have one more tab). Does your code in lambda function editor look the same or the indentaions disappeared while pasting the code here?

TypeError: 'str' object is not callable python3

def SaveRoles(request):
if 'user_name' in request.session:
if request.method == "POST":
user_roles = request.POST['user_roles']
user_permission_level = request.POST['user_permission_level']
user_role_code = request.POST['user_role_code']
code = user_roles(user_roles=user_roles, user_permission_level=user_permission_level, user_role_code=user_role_code)
print("qqqqqq", code)
try:
model_status = code.save()
except Exception as e:
print("exception occured", e)
return render(request, 'administrator/add_role.html', {'message': 'Oops some error occured'})
if model_status == None:
role = user_roles.objects.all()
return HttpResponseRedirect('http://'+request.get_host()+'/admin/role-list/',{'message': 'Role added successfully','code': code})
else:
return HttpResponseRedirect('http://'+request.get_host()+'/admin/role-list/')
else:
return HttpResponseRedirect('/admin/')
When I am running this function I got the
TypeError: 'str' object is not callable
I searched all my code and I don't even use the word str anywhere in my project
But I cant figure out the error
user_roles is a string because you are assigning the value of request.POST['user_roles']. You probably need to change.
user_roles = request.POST['user_roles']
to
user_roles_val = request.POST['user_roles']
Ex:
def SaveRoles(request):
if 'user_name' in request.session:
if request.method == "POST":
user_roles_val = request.POST['user_roles'] #Update
user_permission_level = request.POST['user_permission_level']
user_role_code = request.POST['user_role_code']
code = user_roles(user_roles=user_roles_val, user_permission_level=user_permission_level, user_role_code=user_role_code) #Update
print("qqqqqq", code)
try:
model_status = code.save()
except Exception as e:
print("exception occured", e)
return render(request, 'administrator/add_role.html', {'message': 'Oops some error occured'})
if model_status == None:
role = user_roles.objects.all()
return HttpResponseRedirect('http://'+request.get_host()+'/admin/role-list/',{'message': 'Role added successfully','code': code})
else:
return HttpResponseRedirect('http://'+request.get_host()+'/admin/role-list/')
else:
return HttpResponseRedirect('/admin/')

django twilio for number phone confirmation returns exception in send function

I got an exception when i create a sms to send
here is my functions
def send_sms(to_number, body):
account_sid = settings.TWILIO_ACCOUNT_SID
auth_token = settings.TWILIO_AUTH_TOKEN
twilio_number = '+15005550006'
client = TwilioRestClient(account_sid, auth_token)
try :
client.messages.create(to=to_number,
from_=twilio_number,
body=body)
except Exception as e:
print e.message
def generate_code():
return str(random.randrange(100000, 999999))
def send_confirmation_code(request,to_number):
verification_code = generate_code()
send_sms(to_number, verification_code)
request.session['verification_code'] = verification_code
return verification_code