Change HTTP URL in Worklight adapter - ibm-mobilefirst

I need to create an HTTP adapter for worklight but the url must be programmatically provided via a parameter.
1) I was able to pass the user/password but not the url. Is there a way to do that?
I also try to create my own java adapter to call the REST API, It works when I test the adapter but it seems my response is not in the expected format for worklight. I got this error:
2) BAD_PARAMETER_EXPECTED_DOCUMENT_OR_ARRAY_OF_DOCUMENT.
my Java adapter returns a JSONArtifact (JSONObject) but it seems that worklight want this to be embedded in another JSONObject such as { "array":{...}}.
Is there a way to convert a JSONObject to the format expected by worklight.
import org.apache.wink.json4j.JSON;
import org.apache.wink.json4j.JSONArtifact;
import org.apache.wink.json4j.JSONException;
private Header headerUserAgent = new Header("User-Agent", "Mozilla");
private Header headerAccept = new Header("Accept", "application/json");
private String hostName;
private String baseURL;
protected MyHttpClient(String userName, String userPassword, String hostName, String baseURL ) {
super();
Credentials defaultcreds = new UsernamePasswordCredentials(userName,
userPassword);
this.getState().setCredentials(AuthScope.ANY, defaultcreds);
this.hostName = hostName;
this.baseURL = baseURL;
}
private GetMethod getGetMethod(String url) throws URIException {
GetMethod httpMethod = new GetMethod(new HttpsURL("https://"+hostName+baseURL+url).getEscapedURI());
addCommonHeaders(httpMethod);
return httpMethod;
}
private JSONArtifact getResponseAsJSONObject(InputStream inputStream) throws IOException {
InputStreamReader reader = new InputStreamReader(inputStream);
try {
JSONArtifact json = JSON.parse(reader);
return json;
} catch (NullPointerException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (JSONException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
Adapter:
function getResponse(user,password) {
var client = new com.itdove.mypackage.MyHttpClient(user,password,"myurl","mybaseurl");
return {
array : client.executeGet("mypath")
};
}
it works with this but this solution doesn't provide the service url as parameter:
function getResponseAdapters(path, username, password) {
var input = {
method : 'get',
returnedContentType : 'json',
headers: {
'User-Agent':'Mozilla',
'Authorization': 'Basic '+Base64.encode(username+':'+password),
} ,
path : '/resources/' + path
};
return WL.Server.invokeHttp(input);
}
function getResponse(username, password) {
return getMySCAWSAdapters(path, username, password);
}
Collection
vAPPArrayAdapterOptions = {
name: 'myResponseAdapter',
replace: '',
remove: '',
add: '',
load: {
procedure: 'getResponse',
params: ["user","password"],
key: 'array'
},
accept: function (data) {
return (data.status === 200);
}
},
...
vAPPArray = wlJsonStore.initCollection(
"vAPPArray",
vAPPArraySearchFields,
{adapter: vAPPArrayAdapterOptions,
onSuccess: initCollectionSuccessCallback,
onFailure: initCollectionFailureCallback,
load:true});
Many Thanks
Dominique

Found the solution:
First, I was using apache wink JSONArtifact instead of the com.ibm.json.java.JSONArtifact!
Secondly I modified my collector implement method as follow to add the status (not sure if it is needed or not)
function getResponse(user,password,hostname) {
var client = new com.itdove.mypackage.IWDHttpClient(user,password,hostname,"mypath");
return {
array :client.executeGet("mymethod"),
statusCode: client.getStatusCode(),
statusReason: client.getStatusReason()
};
}
in myCollector.js I set the user, password, hostname as follow before calling my initCollection.
params = [ settings.json.user, settings.json.password, settings.json.hostname ];
myAdapterOptions.load["params"] = params;

Related

Expected a value of type 'List<dynamic>', but got one of type '_JsonMap'

When I try to json decode I get the error Expected a value of type 'List', but got one of type '_JsonMap'
My code:
static Future<Response<Localizacao>> getLocalizacao(String cep) async {
await Future.delayed(Duration(milliseconds: 200));
try {
Map<String, String> headers = {
'Authorization': 'Token token=9e034db1f315356f30'};
String protocol = 'https://cors-anywhere.herokuapp.com/';
String uri =
'https://www.cepaberto.com/api/v3/cep?cep=' + cep;
final endpoint = "&format=json";
String url = protocol + uri + endpoint;
final response = await http.get(url, headers: headers);
if (response.statusCode == 200) {
final json = response.body;
List list = (jsonDecode(json) as List<dynamic>) ;
final local = list.map<Localizacao>((map) => Localizacao.fromJson(map)).toList();
return Response(true, msg: "OK", result: local[0]);
} else {
return Response(false, msg: "Erro ao conectar no web service");
}
} catch (e) {
return Response(false, msg: "Erro ao conectar no web service");
}
}
I tried other ways like:
List list = convert.json.decode(response.body);
List list = convert.json.decode(json);
Found out what the problem was.
I just had to add :
final json = "[" + response.body + "]";
Try this
if (response.statusCode == 200) {
print("IF responde==200");
final json = response.body;
print("IF rjson");
Map<String, dynamic> map= jsonDecode(json) ;
print("IF converting json");
final local = Localizacao.fromJson(map);
print("IF mapping list");
return Response(true, msg: "OK", result: local);
} else {
return Response(false, msg: "Erro ao conectar no web service");
}
} catch (e) {
print("error in getLocalizacao: $e");
return Response(false, msg: "Erro ao conectar no web service");
}

How to pass pdf file to Controller that requires IFormFile

I've been working on this the whole day and did my research already, I can't seem to find a solution anywhere. I have this function that calls a List in my controller, the List needs a IFormFile parameter,
here's my javascript method
function fileUploader_uploaded(e) {
const file = e.file;
const fileReader = new FileReader();
fileReader.onload = function () {
toggleDropZoneActive($("#dropzone-external")[0], false);
$("#dropzone-item")[0].data = fileReader.result;
}
fileReader.readAsDataURL(file);
const _fileReader = new FileReader();
var r = _fileReader.readAsBinaryString(file);
$("#dropzone-text")[0].style.display = "none";
$.ajax({
url: '#Url.Action("_Index", "FileUploader")',
data: { CFile: r}, // I'm trying to pass the pdf file here
cache: false,
success: function (data) {
console.log(data);
}
});
}
and this is my List in controller
public object _Index(IFormFile CFile)
{
if (CFile != null)
{
try
{
string documentText = "";
using PdfDocumentProcessor documentProcessor = new PdfDocumentProcessor();
documentProcessor.LoadDocument(CFile.OpenReadStream());
documentText = documentProcessor.Text;
string word = #"([0-9]+.[0-9]+-[0-9]+)";
Regex regex = new Regex(word);
foreach (Match match in regex.Matches(documentText))
{
sectionsList.Add(match.Value.ToString());
}
}
catch
{
Response.StatusCode = 400;
}
}
else
{
_logger.LogInformation("empty");
}
return sectionsList;
}
the CFile is always empty i tried different ways already like passing
data: { CFile: e.file}
Does anyone else have idea?
From this code data: { CFile: e.file}, you post it as the string, so it can not be recognized as a file. You need to use FormData and change the contentType.
function fileUploader_uploaded(e) {
const file = e.file;
const fileReader = new FileReader();
fileReader.onload = function () {
toggleDropZoneActive($("#dropzone-external")[0], false);
$("#dropzone-item")[0].data = fileReader.result;
}
fileReader.readAsDataURL(file);
const _fileReader = new FileReader();
var r = _fileReader.readAsBinaryString(file);
$("#dropzone-text")[0].style.display = "none";
//----------edit here---------
var form = new FormData()
form.append('CFile', file)
$.ajax({
url: '#Url.Action("_Index", "FileUploader")',
method:'post',
data: form,
cache: false,
contentType: false,
processData: false,
success: function (data) {
}
});
}
The bakend should add [FromForm].
[HttpPost]
public object _Index([FromForm]IFormFile CFile)

error: A value of type 'LocationModel' can't be returned from method 'getLocation' because it has a return type of 'List<dynamic>'

Future<List> getLocation(String city,DateTime date) async {
try {
http.Response hasil = await http.get(
Uri.encodeFull(
"https://api.pray.zone/v2/times/day.json?city=${city}&date=${date}"),
headers: {"Accept": "Application/json"});
if (hasil.statusCode == 200) {
print("Location Successfully Gathered");
final data = locationModelFromJson(hasil.body);
return data;
} else {
print("Error Status ${hasil.statusCode.toString()}");
}
} catch (e) {
print("error catch $e");
return null;
}
}
why cant i return the data variable? it says that because the model has a return type List<dynamic>
edit:
my Model is https://textuploader.com/1pmb6
As you can see, the data you are fetching and parsing is LocationModel.fromJson and you are returning it. But the return type of your method is Future<List> so clearly you are not returning the type that you mentioned the method would.
The correct implementation would be this,
Future<LocationModel> getLocation(String city,DateTime date) async {
...
}
if your API is returning a List of LocationModel which is why I assume you mentioned list,
then you will have to do this,
Future<List<LocationModel> getLocation(String city,DateTime date) async {
try {
http.Response hasil = await http.get(
Uri.encodeFull(
"https://api.pray.zone/v2/times/day.json?city=${city}&date=${date}"),
headers: {"Accept": "Application/json"});
if (hasil.statusCode == 200) {
print("Location Successfully Gathered");
List<LocationModel> locs =[];
hasil.forEach((d){
final l = locationModelFromJson(d.body);
locs.add(l);
});
return locs;
} else {
print("Error Status ${hasil.statusCode.toString()}");
}
} catch (e) {
print("error catch $e");
return null;
}
}
Dart is a very strictly typed language, so if you do not mention a type, Dart assumes that it is dynamic by default and hence you get that error.

Google Reaptcha v3 still letting spam through

I just added Google Recaptcha V3 to a site and a lot of spam is still getting through. I know that Google needs to build up some traffic on the site to determine if something is spam. How long should that take? Like if this is still happening after X days there is a problem? What is X?
Here is how I implemented this. On the client side I get the token:
function validateCaptcha(form, callback) {
$("#captcha-error").addClass('hidden');
$("#captcha-error").hide();
$("#captcha-error").html('');
var formName = $('#formName').val();
if (!formName) formName = 'AmeriGasGenericForm';
var siteKey = $('#siteKey').val();
if (grecaptcha) {
try {
grecaptcha.ready(function() {
grecaptcha.execute(siteKey, { action: formName }).then(function(token) {
$.ajax({
url: "/recaptcha-validate?recaptchaResponse=" + token + "&actionName=" + formName,
async: false,
success: function (response) {
console.log("score:" + response.score);
if (response.Success == false) {
$("#captcha-error").html('Unable to verify reCAPTCHA. Please try again.');
$("#captcha-error").removeClass('hidden');
$("#captcha-error").show();
} else {
callback(form);
}
},
error: function(e) {
console.log(e);
}
});
});
});
} catch (err) {
console.log(err);
}
}
}
That calls a server side check to validate:
public JsonNetResult ValidateRecaptcha(string recaptchaResponse, string actionName)
{
var result = new RecaptchaResult();
if (string.IsNullOrEmpty(recaptchaResponse))
{
result.Success = false;
return new JsonNetResult(result);
}
var secretKey = Settings.GetSetting("reCAPTCHA.Secret");
var url = "https://www.google.com/recaptcha/api/siteverify?secret=" + secretKey + "&response=" + recaptchaResponse;
var recaptchaThresholdString = ConfigurationManager.AppSettings["reCaptchaThreshold"];
if (!float.TryParse(recaptchaThresholdString, out var threshold))
{
threshold = 0.5f;
}
using (var reCaptchaHttpClient = new HttpClient())
{
try
{
var reCaptchaResponseString = reCaptchaHttpClient.GetStringAsync(url).Result;
var response = JsonConvert.DeserializeObject<RecaptchaResponseModel>(reCaptchaResponseString);
result.Score = response.score;
if (response.Success && response.score >= threshold && string.Equals(response.action, actionName,
StringComparison.CurrentCultureIgnoreCase))
result.Success = true;
else
result.Success = false;
}
catch (Exception ex)
{
result.Success = false;
}
}
return new JsonNetResult(result);
}
I have the threshold set to allow anything higher than .5 through. But, when I look at the reCaptcha admin console in Google, like 99% of the requests are scored at .9. So Im not sure what to do here to prevent spam. It seems recaptcha thinks everything is a human but when I look at actual submissions I am receiving, they are clearly spam.

MobileFirst - Invoking Java SQL Adapter adapter procedure

I am following the Java SQL Adapter tutorial for MobileFirst Platform 7.
I'm trying to Get User with userId = "bjones", but I don't know how to set the params {userId} into the procedure /adapters/UserAdapter/{userId}.
function loadUsers(){
busyIndicator.show();
var resourceRequest = new WLResourceRequest("/adapters/UserAdapter/", WLResourceRequest.GET);
resourceRequest.setQueryParameter("userId", "bjones");
resourceRequest.send().then(
loadUsersSuccess,
loadUsersFailure
);}
function loadUsersSuccess(result){
WL.Logger.debug("Feed retrieve success");
busyIndicator.hide();
WL.Logger.debug(JSON.stringify(result));
if (result.responseJSON.length>0)
displayFeeds(result.responseJSON);
else
loadUsersFailure();}
function loadUsersFailure(result){
WL.Logger.error("Feed retrieve failure");
busyIndicator.hide();
WL.SimpleDialog.show("Banking Application", "Service not available. Try again later.",
[{
text : 'Reload',
handler : WL.Client.reloadApp
},
{
text: 'Close',
handler : function() {}
}]
);}
My request is
localhost:10080/JavaAdapters/adapters/UserAdapter/?userId=bjones
but the JSON response contains all user stored in my database
Image for response
In addition, how about the REST call type #PUT, with Path param "userId" and body params: "firstName", "lastName", "password", in order to update an user
From the tutorial the adapter endpoint is /{userId} which means the userId is not a query param but it is part of the url. You need to update your loadUsers function so that it appends the userId at the end of the url, so in your example the fullpath will be /adapters/UserAdapter/bjones
function loadUsers(){
busyIndicator.show();
var usedId = "bjones";
var resourceRequest = new WLResourceRequest("/adapters/UserAdapter/"+userId, WLResourceRequest.GET);
resourceRequest.send().then(loadUsersSuccess,loadUsersFailure);
}
UPDATE:
function loadUsersSuccess(result) {
WL.Logger.debug("Feed retrieve success");
busyIndicator.hide();
WL.Logger.debug(JSON.stringify(result));
// if responseJSON is not null user data was returned
if (result.responseJSON != null) {
displayFeeds(result.responseJSON);
} else{
loadUsersFailure();
}
}
there are basically two type of URL with Parameters:
1. Path parameter:
/adapters/UserAdapter/users/{userId}
2. Query Parameter:
/adapters/UserAdapter/users?userId={userId}
java adapter with query parameter:
#GET
#Produces("application/json")
#OAuthSecurity(enabled = false)
#Path("/users")
public String getuserById(#QueryParam("userID") String userId)
{
System.out.println(userId);
}
java adapter with path parameter:
#GET
#Produces("application/json")
#OAuthSecurity(enabled = false)
#Path("/users/{userId}")
public String getuserById(#PathParam("userId") String userId)
{
System.out.println(userId);
}
I hope, second example answers your question in java adapter.