Validating Recaptcha with Python and DTML

Without using something like Collective.recaptcha, I am trying to write a simple Python script that will validate Recaptcha2 with Google and return a variable that I can test for with a statement.

I posted this question in detail on stackoverflow:

Being that I am not a great Python coder, I'm sure my script needs a bit of work, however it does return the True or False value when run from the command line. It's now just a matter of getting that result into a variable that Zope can see/use.

Thanks in advance!

Your script returns a value, so can you save that value in the DTML? I guess that's what you're asking? I don't know how your DTML is called or how it's supposed to interact with its caller.

That's why I posted the link to the stackoverflow post. It has a detailed explanation on everything as well as the code.

I am not sure, but I think you should try to create a dtml-method, instead of dtml-doc.

https://zope.readthedocs.io/en/latest/zope2book/DTML.html#formatting-and-displaying-sequences

You should also consider to use ZPT instead of DTML.

Take a look at the first note: https://zope.readthedocs.io/en/latest/zope2book/DTML.html#basic-dtml

I tried with a dtml-method and it's exactly the same. I have read the example regarding using a ZPT but this is workable, as far as I know, with both a dtml-doc and dtml-method. It's really about how it's done and that's where I'm getting hung up.

I have not followed your initial question because important information has been on "stackoverflow" rather than here. It is more difficult to reply to something external, e.g. to quote something. Thus, in the future, put all relevant material here (otherwise, it will ignore your question).

<dtml-if expr="'success' == True">

Your problem is the 'success': it designates the string "success" and this is always (independent from your script result) not equal to True. What you want to check is the variable "success" from the result. You would use <dtml-if "success == True"> (or simply <dtml-if success>) for this.

This will still not work as you are using <dtml-with recaptcha-validate>. The DTML namespace (extended via the "dtml-with") distinguishes "objects" and "mappings"; in the first case (the default), the attributes, in the second case (requested via the mapping attribute) the mapping keys are made available via the DTML namespace. As your recaptcha-validate returns a mapping, you should use <dtml-with recaptcha-validate mapping>.

However, I suggest to simplify the interface between your DTML and your script drastically. Let your script directly return a boolean value (rather than a mapping with success key). Then you can use <dtml-if recaptcha-validate> (without anything else).

dieter,

First of all, thank you for such a detailed response. With regards to posting everything here instead of on stackoverflow, it makes sense. I honestly just linked to it because I thought that would make it easier, rather than such a huge post here. However, I definitely see the wisdom.

That all being said, I tried your suggestion and when I try to submit the form, Zope is throwing an error of:
'bool' object has no attribute 'getitem'

To make things easier, per your suggestion. Here is the current version of the script.

import urllib
import urllib2
import json

REQUEST = container.REQUEST

URIReCaptcha = 'https://www.google.com/recaptcha/api/siteverify'
secret = 'XXXXXXXXXXXXXXXX'
recaptcha_response = context.REQUEST['g-recaptcha-response']
remoteip = REQUEST.HTTP_X_FORWARDED_FOR

params = urllib.urlencode({
'secret': secret,
'response': recaptcha_response,
'remoteip': remoteip,
})

#print params
from urllib2 import urlopen
req = urllib2.Request(URIReCaptcha, params)
response = urllib2.urlopen(req)
result = json.load(response)
success = result.get('success', None)
return success

Another tip for you (concerning this forum): when you include literal output (e.g. from an error message or a traceback), enclose it in backquotes (small output) or triple backquotes (multi line output). The backquote enclosure indicates literal output (without other markup). Without this indication, the output may not be faithfully represented. As an example, the __getitem__ from your error message was turned into getitem.

Now to your problem. Apparently, you have modified your script according to my final advice but not the dtml document. With the new script return value, you must no longer use a dtml-with; just use <dtml-if recaptcha-validate> without the enclosing dtml-with. The dtml-with pushes the scripts return value (now a bool) onto the DTML namespace and it indeed lacks a __getitem__ (and therefore cannot be pushed onto the DTML namespace).

Thank you again! That worked perfectly. I was so close, but without your help I'm not sure I would've gotten there anytime soon. I really appreciate it.