AEM/CQ6.2: How to integrate Google reCaptcha or built-in captcha on an Adaptive Form? - aem

Someone created a form that uses Adaptive Form.
I want to include some sort of captcha function on the form.
I tried using the built-in captcha (Form => Captcha). I made sure the captcha field is ticked as required but I have no problems submitting the form even if the captcha field is blank.
I was looking at incorporating Google's reCaptcha and the best guide I've seen is this: PracticalAEM article. But it doesn't really tell me how to include this new component into my existing setup.
Thanks very much for the help!

Captcha should be implemented on both sides of your application client and server.
Lets describe how reCaptcha work:
1) Browser render page with reCaptcha script with site ID(that is what you did based on article)
2) User answer reCaptcha and google return back some long string with captcha code(on that moment technically captcha still not validated)
3) Your frontend has to decide what to do with response(usually you placing it in mandatory field)
4) Submit reCaptcha captcha code to backEnd.(captcha still not validated)
This part is not described in the article that you read because it is basic for all captchas:
5) Backend should read captcha code and request google for verification of captcha code for current site ID
ReCaptchaImpl reCaptcha = new ReCaptchaImpl();
reCaptcha.setPrivateKey("your_private_key");
String challenge = request.getParameter("recaptcha_challenge_field");
String uresponse = request.getParameter("recaptcha_response_field");
ReCaptchaResponse reCaptchaResponse = reCaptcha.checkAnswer(remoteAddr, challenge, uresponse);
if (reCaptchaResponse.isValid()) {
....
} else {
//send response to browser with message "Captcha is invalid"
}
As you can see only response from google to backend is reCaptcha validation.
And for any captcha implementation there is two parts:
1) frontend where you can fulfil captcha check
2) backend where you can verify that check was done properly.

See if this helps. I have done this on a simple html form (not adaptive).
Folder structure..
recaptcha (main component folder name)
> _cq_editConfig.xml
> .content.xml
> dialog.xml
> recaptch.html
cq_editConfig.xml
<?xml version="1.0" encoding="UTF-8"?>
<jcr:root xmlns:cq="http://www.day.com/jcr/cq/1.0"
xmlns:jcr="http://www.jcp.org/jcr/1.0"
xmlns:nt="http://www.jcp.org/jcr/nt/1.0"
cq:disableTargeting="true"
jcr:primaryType="cq:EditConfig"/>
.content.xml
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<jcr:root xmlns:cq="http://www.day.com/jcr/cq/1.0"
xmlns:jcr="http://www.jcp.org/jcr/1.0"
xmlns:sling="http://sling.apache.org/jcr/sling/1.0"
allowedParents="[*/parsys]"
componentGroup="ABC Commons"
jcr:description="ABC reCaptcha"/>
dialog.xml
<?xml version="1.0" encoding="UTF-8"?>
<jcr:root xmlns:cq="http://www.day.com/jcr/cq/1.0" xmlns:jcr="http://www.jcp.org/jcr/1.0" xmlns:nt="http://www.jcp.org/jcr/nt/1.0"
jcr:primaryType="cq:Dialog"
title="ABC reCaptcha Component"
xtype="dialog">
<items jcr:primaryType="cq:WidgetCollection"></items>
</jcr:root>
recaptcha.html
<div class="col-md-12">
<div id="response-div" style="color:red; font-weight: bold;"></div>
<script src='https://www.google.com/recaptcha/api.js?onload=reCaptchaCallback&render=explicit' async defer></script>
<div id="rcaptcha" class="g-recaptcha" data-sitekey="SITE-KEY"></div>
<input type="hidden" value="true" id="recaptchaRequired" name="recaptchaRequired" />
<button id="addButton" class="btn plus btn-success">Submit</button>
</div>
</div>
<script>
var RC2KEY = 'SITE-KEY';
var doSubmit = false;
function reCaptchaVerify(response) {
if (response === document.querySelector('.g-recaptcha-response').value) {
doSubmit = true;
}
}
function reCaptchaExpired () {
/* do something when it expires */
}
function reCaptchaCallback () {
grecaptcha.render('rcaptcha', {
'sitekey': RC2KEY,
'callback': reCaptchaVerify,
'expired-callback': reCaptchaExpired
});
}
$("#addButton").click(function (e) {
e.preventDefault();
if (doSubmit) {
//alert('submit pressed');
$( "form:first" ).submit();
} else {
//alert('recaptcha not selected');
document.getElementById("response-div").innerHTML = "Recaptcha is required!";
}
});
</script>
Note: Replace the SITE-KEY

Related

TVML: adding new lines to a description text

Experimenting with Apple TV's TVML: I'm using a Product Template, and in the description field I'd like to add carriage returns, to make it look somewhat like a list.
Here is a simple example:
var Template = function() { return `<?xml version="1.0" encoding="UTF-8" ?>
<document>
<productTemplate>
<banner>
<infoList>
</infoList>
<stack>
<title>Big Title</title>
<description>
Line one
Line two
</description>
</stack>
</banner>
</productTemplate>
</document>`
}
I've tried \n, &#xD, &#xA between the lines, and even something like this:
<![CDATA[
Line 1 <br />
Line 2 <br />
]]>
But none of these work. Is there a way to incorporate line breaks in TVML descriptions?
Having this code in a template.xml.js and loading it via the Presenter.js in the TVMLCatalog example from apple:
<stack>
<description>Insert your \n username (tipically your ID)</description>
</stack>
It renders
This also works:
var Template = function() {
const description = `
Line 1
Line 2
`.trim();
return `<?xml version="1.0" encoding="UTF-8" ?>
<document>
<productTemplate>
<banner>
<infoList>
</infoList>
<stack>
<title>Big Title</title>
<description>
${description}
</description>
</stack>
</banner>
</productTemplate>
</document>`
}

How do I pass an object to, or set a variable in a TVML template file I am using?

I'm working with the TVMLCatalog sample files from Apple, and am stuck trying to pass an object to a template file I am loading in the presenter (javascript file). This seems like it should be a totally rudimentary thing to accomplish, but it has me beat.
I have the following, which loads a template with the resource loader, and pushes it to the view.
resourceLoader.loadResource('http://localhost/mytemplate.xml.js',
function(resource) {
if (resource) {
var doc = self.makeDocument(resource);
doc.addEventListener("select", self.load.bind(self));
navigationDocument.pushDocument(doc);
}
}
);
Where do I define an object or set a variable that will be in the document when the template file is loaded in the view?
Yes! You can inject variables into your TVML templates.
First, you have to create a string that contain the same TVML template, and use ${variable} to inject values.
Then, use DOMParser object to convert this string into XML DOM element.
Finally, present the document with help of presentModal method (main object navigationDocument)
Your function will look like this:
function catalogTemplate(title, firstMovie, secMovie) {
var xmlStr = `<?xml version="1.0" encoding="UTF-8" ?>
<document>
<catalogTemplate>
<banner>
<title>${title}</title>
</banner>
<list>
<section>
<listItemLockup>
<title>All Movies</title>
<decorationLabel>2</decorationLabel>
<relatedContent>
<grid>
<section>
<lockup>
<img src="http://a.dilcdn.com/bl/wp-content/uploads/sites/2/2014/03/Maleficent-Poster.jpg" width="250" height="376" />
<title>${firstMovie}</title>
</lockup>
<lockup>
<img src="http://www.freedesign4.me/wp-content/gallery/posters/free-movie-film-poster-the_dark_knight_movie_poster.jpg" width="250" height="376" />
<title>${secMovie}</title>
</lockup>
</section>
</grid>
</relatedContent>
</listItemLockup>
</section>
</list>
</catalogTemplate>
</document>`
var parser = new DOMParser();
var catalogDOMElem = parser.parseFromString(xmlStr, "application/xml");
navigationDocument.presentModal(catalogDOMElem );
}
PS: I used Catalog template as an example. You can use any template
In the onLaunch function, you can call the catalogTemplate function by passing any variable.
App.onLaunch = function(options) {
catalogTemplate("title", "Maleficent.", "The Dark knight");
}
You can add a listener and pass an function to move to another page or trigger an action using addEventListener
function catalogTemplate(title, firstMovie, secMovie, cb) {
var xmlStr = `<?xml version="1.0" encoding="UTF-8" ?>
<document>
<catalogTemplate>
<banner>
<title>${title}</title>
</banner>
<list>
<section>
<listItemLockup>
<title>All Movies</title>
<decorationLabel>2</decorationLabel>
<relatedContent>
<grid>
<section>
<lockup>
<img src="http://a.dilcdn.com/bl/wp-content/uploads/sites/2/2014/03/Maleficent-Poster.jpg" width="250" height="376" />
<title>${firstMovie}</title>
</lockup>
<lockup>
<img src="http://www.freedesign4.me/wp-content/gallery/posters/free-movie-film-poster-the_dark_knight_movie_poster.jpg" width="250" height="376" />
<title>${secMovie}</title>
</lockup>
</section>
</grid>
</relatedContent>
</listItemLockup>
</section>
</list>
</catalogTemplate>
</document>
`
var parser = new DOMParser();
var catalogDOMElem = parser.parseFromString(xmlStr, "application/xml”);
catalogDOMElem.addEventListener("select", cb, false);
navigationDocument.presentModal(catalogDOMElem );
}
Let's create another template just to showcase how we jump to another page by selecting a specific item.
function ratingTemplate(title) {
var xmlStr = `<?xml version="1.0" encoding="UTF-8" ?>
<document>
<ratingTemplate>
<title>${title}</title>
<ratingBadge value="0.8"></ratingBadge>
</ratingTemplate>
</document>`
var parser = new DOMParser();
var ratingDOMElem = parser.parseFromString(xmlStr,"application/xml");
navigationDocument.presentModal(ratingDOMElement);
}
In our onLaunch function.
App.onLaunch = function(options) {
catalogTemplate("title", "Maleficent.", "The Dark knight", function() {
navigationDocument.dismissModal();
ratingTemplate(“rating template title")
});
}
Check this list for more tutorials.

Can't fetch mail body using gmail contextual gadget

Here is my manifest.xml file
<?xml version="1.0" encoding="UTF-8" ?>
<ApplicationManifest xmlns="http://schemas.google.com/ApplicationManifest/2009">
 
  <Name>My test gadget</Name>
  <Description>Test Gmail contextual gadgets for mail body</Description>
 
 
<Extension id="MailBodyReaderGadget" type="contextExtractor">
  <Name>Mail Body Reader Gadget</Name>
  <Url>google.com:EmailBodyExtractor</Url>
<Param name="body" value=".*" /> 
  <Triggers ref="mailBodyTextWidget" /> 
  <Scope ref="emailBody" />
  <Container name="mail" />
</Extension>
 
<!-- our GADGET -->
<Extension id="mailBodyTextWidget" type="gadget">
  <Name>Get mail body</Name>
  <Url>http://test.com/spec.xml</Url>
  <Container name="mail" />
</Extension>
 
<!-- gadget Scope -->
<Scope id="emailBody">
  <Url>tag:google.com,2010:auth/contextual/extractor/BODY</Url>
  <Reason>This app will show the mail body text when you click the button "Show Mail Body"</Reason>
</Scope>
</ApplicationManifest>
and spec.xml file
<?xml version="1.0" encoding="UTF-8"?>
<Module>
<ModulePrefs
height="200"
author=""
author_email=""
author_location="US">
        <Require feature="dynamic-height"/>
        <Require feature="google.contentmatch">
            <Param name="extractors">
                google.com:EmailBodyExtractor
            </Param>
        </Require>
    </ModulePrefs>
    <Content type="html" view="card">
<![CDATA[      
<script type="text/javascript">
document.write([
"\<script src='",
("https:" == document.location.protocol) ? "https://" : "http://",
"ajax.googleapis.com/ajax/libs/jquery/1.2.6/jquery.min.js' type='text/javascript'>\<\/script>"
].join(''));
</script>
<button id="btn">Show Mail Body</button>
<div id="widget" style="heigth:300px;width:500px;">
</div>
    <script>
        matches = google.contentmatch.getContentMatches();
        for (var match in matches) {
          for (var key in matches[match]) {                     
            $("#widget").html(matches[match][key]);           
          }
        }       
    </script>    
    ]]>
  </Content>
</Module>
This is my code, i have been tried to fetch mail subject and from and to email addresses it has been worked. But the main issue is i can't fetch mail body. Is there any solution to fix this?
The answer is to delete the node <Param name="body" value=".*" />
This one had me stuck, as I thought that the <param> node was required to define the name of the output parameter to use in our gadget.
But in fact the MailBodyReaderGadget outputs the parameter of "body" automatically.
So the <Param> node is only used if you wish to filter the output.
As you always want to output the body, you can delete this node entirely.
The reason it is not working at the moment is because the .* filter doesn't match return characters (which will be in the body)

Zend_Nav in zend framework issue getting menu to show up

I have the following problem, using zend framework, specifically zend_nav to create a reusable menu to be passed in via the layout/layout.phtml page. These are the code fragments in their respective files.
first of in application/configs/navigation.xml,
<configdata>
<nav>
<label>Home</label>
<controller>index</controller>
<action>index</action>
<pages>
<add>
<label>Add</label>
<controller>post</controller>
<action>add</action>
</add>
<login>
<label>Admin</label>
<controller>login</controller>
<action>login</action>
</login>
</pages>
</nav>
</configdata>
this is then passed into an object in the Bootstrap.php file(only showing that specific method)
protected function __initNavigation(){
$this->bootstrap('layout');
$layout = $this->getResource('layout');
$view = $layout->getView();
$config = new Zend_Config_Xml(APPLICATION .'/config/navigation.xml', 'nav');
$container = new Zend_Navigation($config);
$view->navigation($container);
}
and then finally in the view layout.phtml, the object should return the menu
<!-- application/layouts/scripts/layout.phtml -->
<?php echo $this->doctype() ?>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Zend Blog !</title>
<?php echo $this->headLink()->appendStylesheet('/css/global.css')?>
</head>
<body>
<div id="header">
<div id="header-logo">
<b>Blog Me !</b>
</div>
</div>
<div id="menu">
<?php echo $this->navigation()->menu() ?>
</div>
<div id="content">
<?php echo $this->layout()->content ?>
</div>
</body>
</html>
The menu does however not show up when i start up my app in the browser, any ideas as to might have gone wrong, is humbly received.
If you did not name the function __initNavigation with two _ underscores on purpose then you probably expected the code to run automatically. For it to run automatically you need to use a single underscore.
Another possible problem is that _initNavigation runs before _initView as Zend goes through these resources in alphabetical order. But then you need not access $view in this code. You can use the Zend_Registry to store the navigation container:
protected function _initNavigation() {
$config = new Zend_Config_Xml(APPLICATION .'/config/navigation.xml', 'nav');
$container = new Zend_Navigation($config);
Zend_Registry::set('Zend_Navigation', $container);
}
The Zend_Navigation registry entry will be used by default by any navigation helper when no container is specified.
Well i`m impressed, really quick answers, the problem had several aspects, first of you where both right about using a single underscore sign, thanks a lot the both of you !
And as i t turned out, i did misspell,
$config = new Zend_Config_Xml(APPLICATION .'/config/navigation.xml', 'nav');
should be,
$config = new Zend_Config_Xml(APPLICATION_PATH .'/configs/navigation.xml', 'nav');
my fault. And finally a miss in the navigation.xml file, inside the - node, there should be nodes surrounding each of the "page" nodes, that is for instance for the home. It should have
<configdata>
<nav>
<home>
<label>Home</label>
<controller>index</controller>
<action>index</action>
</home>
That was it !
Again, thanks a lot for your hints and tips i the right direction.
Sinc Kalle Johansson
I think your code is correct, just your protected function __initNavigation()
should use just one _ in your _initNavigation()
Then change __initNavigation() to _initNavigation()

Load page to Modal Window from form with jQuery

I´m working on a website with a purchase process. I have a form generated by some PHP that looks like this:
<form name="order_form" action="'.$thePayreadApi->get_server_url().'" method="post" id="payer-form">
'.$thePayreadApi->generate_form().'
<input type="submit" value="Klicka för betalning" />
</form>';
When the form is submitted it will go to a new page (located on another server) where the purchase is performed.
Basically what I want is the form to be submitted through AJAX and then load the new page in a Modal Window. I use jQuery throughout the website so I´d like a solution based on that lib.
I´ve found these sites that might be a hint:
http://pixeline.be/blog/2008/javascript-loading-external-urls-in-jqmodal-jquery-plugin/
http://dev.iceburg.net/jquery/jqModal/
Any help is really appreciated!
I haven't tried this exactly, but the theory is what I would go for:
$("form[name='order_form']").submit(function() {
//Validate in here
var validate = false;
if($("input[form='element1']").val()!="") {
validate = true;
}
if(validate) {
this.submit();
} else {
return false;
}
});
<form action="shopping.php" target="targetIframe" method="post">
<input type="submit" value="Click Me" />
</form>
<iframe name="targetIframe" src=""></iframe>