Attribute Error when writing a captcha decorator - python

I wrote a captcha decorator...
def validate_captcha(view):
'''Decorator to validate a captcha based on settings'''
def failure():
return HttpResponse('There was an error, please refresh and try again')
def wrap(request, *args, **kwargs):
if request.method == 'POST':
url = "https://www.google.com/recaptcha/api/siteverify"
values = {
'secret': settings.GOOGLE_RECAPTCHA_SECRET_KEY,
'response': request.POST.get(u'g-recaptcha-response', None),
'remoteip': request.META.get("REMOTE_ADDR", None),
}
data = urllib.urlencode(values)
req = urllib2.Request(url, data)
response = urllib2.urlopen(req)
result = json.loads(response.read())
# result["success"] will be True on a success
if result["success"]:
return view
else:
return failure
return failure
return wrap
and then used it on a view...
#validate_captcha
def sendemail(request):
...
but then I get an attribute error...
Traceback:
File "/home/jeff/Django/langalang/venv/local/lib/python2.7/site-packages/django/core/handlers/base.py" in get_response
223. response = middleware_method(request, response)
File "/home/jeff/Django/langalang/venv/local/lib/python2.7/site-packages/django/middleware/common.py" in process_response
138. if response.status_code == 404 and not settings.DEBUG:
Exception Type: AttributeError at /ko/contact/sendemail
Exception Value: 'function' object has no attribute 'status_code'
I THINK...this is happening because it returned a function, but I cannot figure out why django is treating this as a response, because the response was already handled in my decorator and I verified that it made it through to the return point 'result["success"]'

I think you should call the failure() function so that you actually have an HttpResponse returned from the wrapping decorator. Replace:
return failure
with:
return failure()
And, the same goes for the view, call it:
return view(request, *args, **kwargs)

Related

How do I pass a variable to a route from a decoration in Flask

I am setting up a decoration that checks if the route has an authentication token and if so I want the decoration to return to the route the currently logged-in user.
Below is the code to the decoration:
def token_required(f):
#wraps(f)
def decorated(*args, **kwargs):
token = None
# jwt is passed in the request header
if 'x-access-token' in request.headers:
token = request.headers['x-access-token']
# return 401 if token is not passed
if not token:
return jsonify({'message' : 'Token is missing!'}), 401
try:
# decoding the payload to fetch the stored details
data = jwt.decode(token, current_app.config['SECRET_KEY'])
current_user = User.query\
.filter_by(public_id = data['public_id'])\
.first()
except:
return jsonify({
'message' : 'Token is invalid !!'
}), 401
return f(current_user, *args, **kwargs)
return decorated
The problem is that when I try this it throws this error:
TypeError: currentUser() takes 0 positional arguments but 1 was given
I also tried to return this:
return f(*args, **kwargs, current_user=current_user)
but this only works if I add current_user as an argument to the given route

pydantic.error_wrappers.ValidationError: 1 validation error for '' with FastAPI

I have these Schemas in my FastAPI application:
class Run(BaseModel):
id: int = Field(..., description="Run id")
type: str = Field(..., description="Type")
class RunsResponse(BaseModel):
data: list[Run] = Field(..., description="List of existing runs")
links: dict = Field(..., description="link to runs")
Then I have this decorator to use for all the endpoints:
def handle_request(func):
#wraps(func)
async def wrapper(*args, **kwargs):
try:
response = func(*args, **kwargs)
except (requests.exceptions.SSLError, requests.exceptions.RequestException) as ex:
raise HTTPException(status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=str(ex))
return response
return wrapper
And this route:
#router.get(
"/runs",
response_model=RunsResponse,
)
#handle_request
async def get_runs(request: Request) -> JSONResponse:
response = send_request(request, SOME_URL)
return JSONResponse(content=response)
So if I try the api without having those codes in a decorator, everything works fine. But when I put the codes in a decorator and use it on my router function, I get this error:
pydantic.error_wrappers.ValidationError: 1 validation error for RunsResponse
response
value is not a valid dict (type=type_error.dict)
I can't debug the code cause the error happens right after I press the Execute button in Swagger. I suspect it has something to do with #wraps from functools but I can't figure out how to fix it.
Can anyone help me with this please?
UPDATE:
I'm adding the send_request method, just in case:
def send_request(request: Request, url: str) -> dict:
headers = {
"Content-type": "application/json",
"Accept": "application/json",
}
response = requests.get(url, headers=headers)
data = response.json()
return data
I was able to fix the problem just by unpacking the function in decorator into a non-coroutine object using await before returning it:
def handle_request(func):
#wraps(func)
async def wrapper(*args, **kwargs):
try:
response = await func(*args, **kwargs) # <- Added await here
except (requests.exceptions.SSLError, requests.exceptions.RequestException) as ex:
raise HTTPException(status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=str(ex))
return response
return wrapper
Now everything is working fine.

How do i get the context to test my view page?

I'm trying to test my search results to check the response when there are no results.
this is the function in my view:
def get_context_data(self, *args, **kwargs):
result = super().get_context_data(**kwargs)
query = self.request.GET.get('q')
result['book'] = get_object_or_404(books,ISBN = query)
return result
this is my test class and function
class Test_Search_results_view(TestCase):
def test_no_results(self):
response1 = self.client.get('/TextSearch/results1/?books=new&q=9780815345244')
response2 = self.client.get('/TextSearch/results2/?books=new&author=Bruce+Alberts&Book+Name=Molecular+Biology+of+the+Cell&edition=6')
self.assertEqual(response1.status_code, 404)
self.assertEqual(response2.status_code, 404)
self.assertQuerysetEqual(response2.context['book'],[])
but i keep getting this error
self.assertQuerysetEqual(response2.context['book'],[])
File "C:----\context.py", line 83, in __getitem__
raise KeyError(key)
KeyError: 'book'
how do I check if my book query got empty results?
If this line: result['book'] = get_object_or_404(books,ISBN = query) causes 404 to be raised, then, you will have nothing in result['book']. Because the 404 is and exception which is raised. get_object_or_404 does not return an empty value which you could assert in your test.

View function did not return a response in flask

I have a code below which setups cookie and then adds this cookie to the response with set_cookies function. However, even though I return a response I received the following error:
ValueError: View function did not return a response
My code is simply this:
def login():
if request.method == "POST":
timestamp = str(int(time.time()))
cookie = timestamp+'user'
cookie = base64.b64encode(cookie.encode('utf-8')).decode('utf-8')
resp = make_response()
resp = resp.set_cookie("LoginCookie",cookie)
return resp
response.set_cookie is an in-place operation. This means that if you set something to it's return value, it will be None, which is the default return value (functions with no return return None).
What should be used instead is:
resp.set_cookie("LoginCookie",cookie)

I need the request in my decorator but I can't figure out how to get it in there

my deorator function...
def validate_captcha(view):
'''Decorator to validate a captcha based on settings'''
def failure():
return HttpResponse('You need to complete the captcha, please refresh and try again')
if request.method == 'POST':
url = "https://www.google.com/recaptcha/api/siteverify"
values = {
'secret': settings.GOOGLE_RECAPTCHA_SECRET_KEY,
'response': request.POST.get(u'g-recaptcha-response', None),
'remoteip': request.META.get("REMOTE_ADDR", None),
}
data = urllib.urlencode(values)
req = urllib2.Request(url, data)
response = urllib2.urlopen(req)
result = json.loads(response.read())
# result["success"] will be True on a success
if result["success"]:
return view
else:
return fail
return fail
and then my view...
#validate_captcha
def sendemail(request):
...
I could put the request in the decorator args, but then it is undefined when i put it in the view args. I tried calling it a few others ways without success, how would you put it in there?
You need to have a wrapper function:
def validate_captcha(view):
def wrap(request, *args, **kwargs):
if request.method == 'POST':
url = "https://www.google.com/recaptcha/api/siteverify"
values = {
'secret': settings.GOOGLE_RECAPTCHA_SECRET_KEY,
'response': request.POST.get(u'g-recaptcha-response', None),
'remoteip': request.META.get("REMOTE_ADDR", None),
}
data = urllib.urlencode(values)
req = urllib2.Request(url, data)
response = urllib2.urlopen(req)
result = json.loads(response.read())
# result["success"] will be True on a success
if result["success"]:
return view
else:
return fail
return fail
return wrap
Make sure study this awesome and quite detailed overview on decorators in Python (I personally think, it is one of the best SO answers ever):
https://stackoverflow.com/a/1594484/771848

Categories

Resources