Rendering reCaptcha V2.0 widget within Marionette Itemview - javascript

This will be a post where I ask the question and propose a solution
Since having had several trouble and having looked around a lot I decided to post my final solution for anyone else to take profit from it.
Question:
How to render google's reCaptcha v2.0 widget and verifying it in a Marionettejs app with a java back end.

After the common steps and following google guides to render the re captcha my captcha still didn't render, so here comes my solution:
Rendering the captcha and the inclusion of the script are both made inside the itemview onRender function:
'text!login/templates/form.html',
'app'
], function (app, Marionette, Backbone, _, $, Handlebars, FormTemplate) {
return Marionette.ItemView.extend({
template: Handlebars.compile(FormTemplate),
ui: {
form: '
},
events: {
'submit #ui.form': 'onSubmit'
},
onRender: function() {
this.loadCaptcha();
},
loadCaptcha: function() {
var self = this;
var getRecaptchaResponse = function(response) {
self.captchaResponse = response;
};
window.renderCaptcha = function () {
self.captchaWidgetId = grecaptcha.render('yourCaptchaDiv', {
sitekey: 'YourSiteKey',
callback: getRecaptchaResponse
});
};
$.getScript('https://www.google.com/recaptcha/api.js?onload=renderCaptcha&render=explicit', function() {});
},
...
}
I tried other ways of loading the script with several errors, like the script loaded before the div for it, or the browser says de Dom has completely loaded but the onRender gets called after
I had to include a div for the captcha widget to load in, this is in
form.html
<div id="reCaptcha" class="btn"></div>
That will have your widget rendered, now you need to both verify it has been filled and it is a valid user response with google, for this I use the same module and use the next function:
onSubmit: function (e) {
//only act if the captcha has been filled - This could be easily erased from a browser, but a back end verification takes place too
if (grecaptcha.getResponse() !== "") {
e.preventDefault();
var _view = this;
this.blockForm();
$.ajax({
url: 'yourLoginService',
type: 'POST',
data: {
userLogin: this.ui.user.val(),
userPassword: this.ui.password.val(),
//get the captcha response
captchaResponse: grecaptcha.getResponse()
}
}).done(function (data) {
app.router.navigate('', {trigger: true});
_view.destroy();
}).fail(function (jqXHR, textStatus, errorThrown) {
// your fail handling
});
}
},
Then comes the time to verify your captcha server side using the secret key provided by google (note this is a Java6 app, therefore the clumbersome exception Handling):
//some other imports ignored
import org.apache.commons.io.IOUtils;
import org.json.JSONException;
import org.json.JSONObject;
class Captcha {
private static final String CAPTCHA_SECRET_KEY = "YourSecretKey";
private static final Logger LOGGER = Logger.getLogger(Captcha.class);
static boolean isCaptchaValid(String response) {
try {
String url = "https://www.google.com/recaptcha/api/siteverify?"
+ "secret=" + CAPTCHA_SECRET_KEY
+ "&response=" + response;
InputStream res = new URL(url).openStream();
JSONObject json = new JSONObject(getJsonResponse(res));
res.close();
return json.getBoolean("success");
} catch (JSONException e) {
LOGGER.error("Can not parse captcha response Json: " + e);
return false;
} catch (MalformedURLException e) {
LOGGER.error("Malformed URL: " + e);
return false;
} catch (IOException e) {
LOGGER.error("Error reading response from captcha verification response: " + e);
return false;
}
}
private static String getJsonResponse(InputStream res) throws IOException {
BufferedReader rd = new BufferedReader(new InputStreamReader(res, Charset.forName("UTF-8")));
/*TODO in java 8+ use this and avoid using the external library
return rd.lines().collect(Collectors.joining());
*/
return IOUtils.toString(rd);
}
}

Related

Handling the tags that are available in the dropdown list options

I am trying to pull the data from the SQL server DB through API for the dropdown lists options like below, the API GetGInfo makes the call to DB and retrieves the data.
self.getGTypes = function (data, event) {
$.ajax({
url: '/REQ/GetGInfo',
type: 'POST',
data: {
sNumber: self.sNumber()
},
success: function (response) {
self.gTypes(response);
},
error: function (errorThrown) {
console.log("Error retrieving the record");
}
})
};
The UI
<select id="GType" name="GType" class="form-control" data-bind="
options: gTypes,
value: gType,
optionsCaption: 'Select'"></select>
This works perfectly fine, but the data in the DB sometimes contains the html tags like or Lepob.I am trying to understand if it is possible to show in UI like below
because in the dropdown I am just seeing like this Lepob.
How can I handle this
EDIT API that returns the data
[HttpPost]
public JsonResult GetGInfo(string sNumber)
{
try
{
DSRepository dsr = new DSRepository();
List<String> gTypeList = dsr.GetDDInfo(sNumber);
if (gTypeList != null)
{
return Json(gTypeList);
}
else
return Json("Not Applicable");
}
catch (Exception e)
{
return null;
}
}
GetDDInfo method
public List<string> GetDDInfo(string sNumber)
{
using (JMPContainer jsContext = new JMPContainer())
{
try
{
return jsContext.vw_Plist.Where(x => x.sNumber== sNumber).Select(y => y.Gtype).Distinct().ToList();
}
catch (Exception e)
{
Console.WriteLine(e.Message);
throw e;
}
}
}
Not going to work. An option element cannot contain any other tags.
If you really must have the superscript characters, I suppose you could convert the characters between the <sup> tags to their Unicode superscript versions.

ng-grid not binding with latest data after async XMLHttpRequest's response

I have a AngularJS web application, I'm trying to upload a file to a server and while the upload is complete, I have to update ng-grid with the last uploaded file's entry. The following is my grid html,
<div class="gridholder" data-ng-grid="viewmodel.gridOptions">
</div>
The following is my controller logic.
vm.gridOptions = {
data: 'gridData',
enableColumnResize: true,
enablePaging: true,
columnDefs: [
{ field: 'FileName', displayName: 'File Name', width: 250 }
{ field: 'UploadedDate', displayName: 'Uploaded Date'}
],
multiSelect: false,
enableSorting: true,
showFooter: true,
};
The requirement is that I show the progress of file upload and the entire application to be responsive when upload is in progress, I have achieved this but my ng-grid not is updating in a particular scenario.
If I remain in the same page until the file is uploaded and the response comes, the grid is refreshing but when I move to another page of my application and come back to the file upload page, and the response comes after, my grid is not getting refreshed.
This is my file upload js code,
var data = new FormData();
data.append('file', file);
var xhrRequest = Factory.uploadFileRequest('UploadFile');
xhrRequest.upload.addEventListener("progress", progressHandler, false);
xhrRequest.onreadystatechange = function (e) {
};
xhrRequest.onload = function (e) {
if (JSON.parse(e.currentTarget.responseText).Success == true) {
$timeout(function () {
$scope.LoadGrid();
//showing success message here
}, 2000);
}
else
{
//showing error message here
}
};
xhrRequest.onerror = function (e) {
//showing error message here
};
xhrRequest.send(data);
$scope.LoadGrid = function () {
Factory.callGet("Files").then(function (d) {
$scope.gridData = d.data;
}
$scope.totalItems = $scope.gridData.length;
}, function error(err) {
//Error Message
});
}
gridData is my data-ng-grid value. I'm calling my LoadGrid method inside a $timeout already but still the grid is not refreshing with latest data. Any help would be much appreciated.
Possible Problem
You implemented upload logic inside the controller. When you switch to another view, angularjs destroys your controller and therefore no one listens on file upload response.
Possible solution:
1) Use a service (or Factory) kind of singleton to manage upload process there.
For example MyService.upload(data).then(function (response) {/**/});
2) By default MyService.upload(data) returns a promise on a regular basis but also stores the result inside the Service, for example, upload_results:
app.service('MyService',['$q',function ($q) {
var self = this;
var upload_results = [];
self.upload = function (_data) {
return // <YOUR_PROMISE>
.then(function (response) {
upload_results.push({
id: new Date().getTime(),
data: response.data
})
}
, function (error) {
console.error(error);
return $q.reject(error);
});
};
self.getResults() = function(){
return upload_results;
}
self.resetResults() = function(){
upload_results = [];
}
}
When you initialize the controller on start or go back to the previous controller, you ask the service if it has something for you:
var results = MyService.getResults();
if(results.length > 0){
$scope.gridData = results[0].data; // or use timestamp to manage it
MyService.resetResults();
}
Hope it will give you some insight,

Response in file upload with Jersey and ExtJS

I have a method which save an image file in the database as a BLOB file. The method works fine, but when I get the callback in ExtJS filefield component, it always goes through failure function and I don't know what I have to respond to go through success function, this is my code:
Server method:
#POST
#Path("/upload")
#Consumes(MediaType.MULTIPART_FORM_DATA)
#Produces({ MediaType.APPLICATION_JSON })
public ServiceResponse uploadFile(#QueryParam("id") Long iconId, FormDataMultiPart form) {
CatIcon icon;
if (iconId != null) {
icon = catIconBean.getOne(iconId);
} else {
icon = new CatIcon();
}
byte[] image = form.getField("iconBmp").getValueAs(byte[].class);
if (image.length != 0) {
MultivaluedMap<String, String> headers = form.getField("iconBmp").getHeaders();
String type = headers.getFirst("Content-type");
List<String> list = Arrays.asList("image/gif", "image/png", "image/jpg", "image/jpeg",
"image/x-icon", "image/bmp");
if (list.contains(type)) {
icon.setIconBmp(image);
icon.setType(type);
}
}
icon.setDescription(form.getField("description").getValue());
icon.setFileName(form.getField("fileName").getValue());
icon = catIconBean.saveIcon(icon);
ServiceResponse sr = new ServiceResponse();
sr.httpResponse = true;
return sr;
}
What I have to return in the code above?
Client:
uploadIcon : function(item, e, eOpts) {
var me = this;
var form = this.getDetail().getForm();
var valid = form.isValid();
if (!valid) {
return false;
}
var values = form.getValues();
if(values) {
form.submit({
url : myApplication.defaultHost() + 'icon/upload?id=' + values.id,
waitMsg : 'Uploading...',
success : function(form, action) {
me.onCompleteSaveOrDelete();
},
failure : function(form, action) {
me.onCompleteSaveOrDelete();
}
});
}
},
I write the same function, me.onCompleteSaveOrDelete(), in both callback functions to make it be called, that's the method which I want to be called in success.
Greetings.
UPDATE:
I did almost the same Alexander.Berg answered. The only difference was that I write #Produces({ MediaType.APPLICATION_JSON }) instead of #Produces({ MediaType.TEXT_HTML }), because I need Json Response. But when I debug in chrome and check the response, I get this:
In failure:
failure : function(form, action) {
me.onCompleteSaveOrDelete();
}
In action param, within responseText:
"{"data":"{\"success\":true}","httpResponse":true,"totalCount":0}"
But It's still going through failure...I think I'm very close, any help??
Greetings.
The fileupload in Extjs is more tricky, because it is using iframe and submit, not a real ajax request for uploading files.
Try this on Server method:
#POST
#Path("/upload")
#Consumes(MediaType.MULTIPART_FORM_DATA)
#Produces(MediaType.TEXT_HTML)
public String uploadFile(#QueryParam("id") Long iconId, FormDataMultiPart form) {
(...)
JSONObject json = new JSONObject();
json.put("success", true);
json.put("msg", "Success");
return json.toString();
}
this is because the upload accepts Content-Type text/html,
see Example at http://docs.sencha.com/extjs/4.2.2/#!/api/Ext.form.field.File -> Example Usage -> Live Preview
Use Firefox browser with Firebug plugin and on Net tab the following URL -> http://docs.sencha.com/extjs/4.2.2/photo-upload.php
Response Headersview source
(...)
Content-Type text/html
(...)
Request Headersview source
Accept text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
(...)

AngularJS redirection after ng-click

I have a REST API that read/save data from a MongoDB database.
The application I use retrieves a form and create an object (a job) from it, then save it to the DB. After the form, I have a button which click event triggers the saving function of my controller, then redirects to another url.
Once I click on the button, I am said that the job has well been added to the DB but the application is jammed and the redirection is never called. However, if I reload my application, I can see that the new "job" has well been added to the DB. What's wrong with this ??? Thanks !
Here is my code:
Sample html(jade) code:
button.btn.btn-large.btn-primary(type='submit', ng:click="save()") Create
Controller of the angular module:
function myJobOfferListCtrl($scope, $location, myJobs) {
$scope.save = function() {
var newJob = new myJobs($scope.job);
newJob.$save(function(err) {
if(err)
console.log('Impossible to create new job');
else {
console.log('Ready to redirect');
$location.path('/offers');
}
});
};
}
Configuration of the angular module:
var myApp = angular.module('appProfile', ['ngResource']);
myApp.factory('myJobs',['$resource', function($resource) {
return $resource('/api/allMyPostedJobs',
{},
{
save: {
method: 'POST'
}
});
}]);
The routing in my nodejs application :
app.post('/job', pass.ensureAuthenticated, jobOffers_routes.create);
And finally the controller of my REST API:
exports.create = function(req, res) {
var user = req.user;
var job = new Job({ user: user,
title: req.body.title,
description: req.body.description,
salary: req.body.salary,
dueDate: new Date(req.body.dueDate),
category: req.body.category});
job.save(function(err) {
if(err) {
console.log(err);
res.redirect('/home');
}
else {
console.log('New job for user: ' + user.username + " has been posted."); //<--- Message displayed in the log
//res.redirect('/offers'); //<---- triggered but never render
res.send(JSON.stringify(job));
}
});
};
I finally found the solution ! The issue was somewhere 18inches behind the screen....
I modified the angular application controller like this :
$scope.save = function() {
var newJob = new myJobs($scope.job);
newJob.$save(function(job) {
if(!job) {
$log.log('Impossible to create new job');
}
else {
$window.location.href = '/offers';
}
});
};
The trick is that my REST api returned the created job as a json object, and I was dealing with it like it were an error ! So, each time I created a job object, I was returned a json object, and as it was non null, the log message was triggered and I was never redirected.
Furthermore, I now use the $window.location.href property to fully reload the page.

Play2 and Scala - Static files and I18 messages in my JS files

When posting a form in my web app I perform a couple of checks in javascript before validating the form in the backend. The js validation is dependent upon I18 messages and images.
If this was a scala template I would of course use #Messages and #routes.Assets.at but I don't want to mix the two(scala template and .js file).
E.g I have this check in my js file where currently the image routes is hardcoded:
$("form input[type=submit]").click(function (e) {
e.preventDefault();
var email = $("#username");
var emailPattern = /^([0-9a-zA-Z]([-\.\w]*[0-9a-zA-Z])*#([0-9a-zA-Z][-\w]*[0-9a-zA-Z]\.)+[a-zA-Z]{2,9})$/;
if (email.val() == "") {
email.css("background-image", "url('/assets/images/general/input-row-red.jpg')");
return e.preventDefault();
} else {
email.css("background-image", "url(/images/general/inputTextBg.png)");
}
});
I have tried to prepare the js files with the messages they need like this:
.js file:
/* Prepare messages*/
var messages = "";
$.getJSON("/messages/source", {
"keys": "sms.form.login.hide,sms.form.login"},
function (data) {
messages = data.messages;
});
MessageSource controller:
object MessageSource extends Controller {
def getMessages(keys : String) = Action { request =>
if(keys.isEmpty) {
BadRequest(Json.obj("status" -> "KO", "message" -> "key plix!"))
}
else {
var js = Map.empty[String, String]
for (k <- keys.split(",")) {
js = js + (k -> Messages(k))
}
Ok(Json.obj("status" -> "OK", "messages" -> js))
}
}
}
But I don't feel that this is the best solution. I have looked at http://www.playframework.com/documentation/2.1.0/ScalaRouting but I can't figure it out.
Maybe you have some nice solution for me?
Maybe this way?
jsfile:
#scripts = {
<script type="text/javascript" src="#routes.Application.javascriptRoutes"></script>
<script type="text/javascript">
jsRoutes.controllers.Application.messages("admin.venue.1,admin.venue.2,admin.venue.3" ).ajax({
type: 'GET',
success: function (data) {
console.log(data.messages);
},
error: function () {
console.log("error");
}
});
</script>
}
Controller:
object Application extends Controller {
def javascriptRoutes = Action {
implicit request =>
import routes.javascript._
Ok(
Routes.javascriptRouter("jsRoutes")
(
routes.javascript.Application.messages
)
).as("text/javascript")
}
def messages(keys : String) = Action {
implicit request => {
val messages = keys.split(",").map { key =>
key -> Messages(key)
}.toMap
Ok(Json.obj("status" -> "OK", "messages" -> messages))
}
}
}
routes:
# Javascript routes
GET /javascriptRoutes controllers.Application.javascriptRoutes
GET /messages controllers.Application.messages(keys: String)

Categories

Resources