Android HTTP errors when using POST with Appcelerator - android

I'm using Appcelerator to build an app for both iOS and Android.
Part of the app requires HTTP POSTs to an API.
This works great on iOS, but fails on Android, giving me this error in the process...
[ERROR] : TiHttpClient: org.apache.http.client.HttpResponseException: Not Acceptable
I understand there may be a few differences in how Android handles these calls, but I'm not exactly sure what I need to change in order for them to work.
Here is one of the calls I'm making.
Any pointers on what i could be doing wrong?
function doRegister() {
// check to see if we already have a username saved
if (!Ti.App.Properties.getString('userEmail')) {
var userEmailfromBox = Ti.App.Properties.getString('userEmailfromBox');
var HashedEmail = Ti.Utils.sha256(userEmailfromBox);
var registerData = {
"account": {
"name": userEmailfromBox,
"mail": userEmailfromBox,
"pass": HashedEmail,
"field_user_type": {
"und": "xxxxx"
}
}
};
var registration = Ti.Network.createHTTPClient({
onload: function() {
// handle the response
Ti.API.info(this.responseText);
// need to save this email so we don't keep registering the user
Ti.App.Properties.setString('userEmail', userEmailfromBox);
// then we need to load the next step
doLogin();
},
onerror : function(e) {
Ti.API.info('Registering: ' + e.error);
//alert('error');
// then we need to load the next step
//doLogin();
}
});
registration.open('POST', 'https://www.myurlredacted.com');
// change the loading message
//loaderWheel.message = 'Creating User';
loaderWheel.message = 'Uploading Your Photos';
// show the indicator
loaderWheel.show();
// set the header for the correct JSON format
registration.setRequestHeader("Content-Type", "application/json; charset=utf-8");
// send the data to the server
registration.send(JSON.stringify(registerData));
} else {
// user is already registered, so skip them onto the next step
Ti.API.info('user already registered');
// then we need to load the next step
doLogin();
}
}

I just ran the following code based on yours:
var url = "http://requestb.in/1iuahxb1";
var registerData = {
"account": {
"name": 'userEmailfromBox',
"mail": 'userEmailfromBox',
"pass": 'HashedEmail',
"field_user_type": {
"und": "xxxxx"
}
}
};
var registration = Ti.Network.createHTTPClient({
onload: function () {
// handle the response
Ti.API.info(this.responseText);
},
onerror: function (e) {
Ti.API.info('Registering: ' + e.error);
}
});
registration.open('POST', url);
// set the header for the correct JSON format
registration.setRequestHeader("Content-Type", "application/json; charset=utf-8");
// send the data to the server
registration.send(JSON.stringify(registerData));
It runs without errors and the requestb.in recieves the post:
http://requestb.in/1iuahxb1?inspect

Related

How do I set up mail adapter on Bitnami parse server?

I'm new to bitnami so setting up the email adapter is proving quite difficult for my android app, any assistance would be appreciated. My goal is to send a password reset to a user after they enter their email address on my app.
What Have I done so far
Created a custom domain and setting up mailgun, acquiring the API key
Set up AWS and once Bitnami was up and running connected Parse to my app
I made sure parse-server-simple-mailgun-adapter was installed
Since app folder and server.js file does not exist anymore when searching through previous forums I placed the below code into this index.js file - /opt/bitnami/parse/node_modules/parse-server/lib/index.js
I taken this code from the following entry https://github.com/ParsePlatform/parse-server
The code currently looks like this in my index.js file:
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
Object.defineProperty(exports, "S3Adapter", {
enumerable: true,
get: function () {
return _s3FilesAdapter.default;
}
});
Object.defineProperty(exports, "FileSystemAdapter", {
enumerable: true,
get: function () {
return _fsFilesAdapter.default;
}
});
Object.defineProperty(exports, "InMemoryCacheAdapter", {
enumerable: true,
get: function () {
return _InMemoryCacheAdapter.default;
}
});
Object.defineProperty(exports, "NullCacheAdapter", {
enumerable: true,
get: function () {
return _NullCacheAdapter.default;
}
});
Object.defineProperty(exports, "RedisCacheAdapter", {
enumerable: true,
get: function () {
return _RedisCacheAdapter.default;
}
});
Object.defineProperty(exports, "LRUCacheAdapter", {
enumerable: true,
get: function () {
return _LRUCache.default;
}
});
Object.defineProperty(exports, "PushWorker", {
enumerable: true,
get: function () {
return _PushWorker.PushWorker;
}
});
Object.defineProperty(exports, "ParseGraphQLServer", {
enumerable: true,
get: function () {
return _ParseGraphQLServer.ParseGraphQLServer;
}
});
exports.TestUtils = exports.ParseServer = exports.GCSAdapter = exports.default = void
var _ParseServer2 = _interopRequireDefault(require("./ParseServer"));
var _s3FilesAdapter = _interopRequireDefault(require("#parse/s3-files-adapter"));
var _fsFilesAdapter = _interopRequireDefault(require("#parse/fs-files-adapter"));
var _InMemoryCacheAdapter = _interopRequireDefault(require("./Adapters/Cache/InMemoryC
var _NullCacheAdapter = _interopRequireDefault(require("./Adapters/Cache/NullCacheAdap
var _RedisCacheAdapter = _interopRequireDefault(require("./Adapters/Cache/RedisCacheAd
var _LRUCache = _interopRequireDefault(require("./Adapters/Cache/LRUCache.js"));
var TestUtils = _interopRequireWildcard(require("./TestUtils"));
exports.TestUtils = TestUtils;
var _deprecated = require("./deprecated");
var _logger = require("./logger");
var _PushWorker = require("./Push/PushWorker");
var _Options = require("./Options");
var _ParseGraphQLServer = require("./GraphQL/ParseGraphQLServer");
var server = ParseServer({
...otherOptions,
// Enable email verification
verifyUserEmails: true,
// if `verifyUserEmails` is `true` and
// // if `emailVerifyTokenValidityDuration` is `undefined` then
// // email verify token never expires
// // else
// // email verify token expires after `emailVerifyTokenValidityDuration`
// //
// // `emailVerifyTokenValidityDuration` defaults to `undefined`
// email verify token below expires in 2 hours (= 2 * 60 * 60 == 7200 seconds)
// emailVerifyTokenValidityDuration: 2 * 60 * 60, // in seconds (2 hours = 7200 seconds)
// set preventLoginWithUnverifiedEmail to false to allow user to login without verifying their email
// // set preventLoginWithUnverifiedEmail to true to prevent user from login if their email is not verified
preventLoginWithUnverifiedEmail: false, // defaults to false
// The public URL of your app.
// // This will appear in the link that is used to verify email addresses and reset passwords.
// // Set the mount path as it is in serverURL
publicServerURL: 'https://xxxxxxxx/xxxxx/',
// Your apps name. This will appear in the subject and body of the emails that are sent.
appName: 'parse-server',
// The email adapter
emailAdapter: {
module: '#parse/simple-mailgun-adapter',
options: {
// The address that your emails come from
fromAddress: 'xxxxxxxxxxxxxxxxxxxxxxxxx',
// Your domain from mailgun.com
domain: 'xxxxxxxxxxxxxxx',
// Your API key from mailgun.com
apiKey: 'xxxxxxxxxxxxxxxxxxxxxxxxxx',
}
},
// account lockout policy setting (OPTIONAL) - defaults to undefined
// // if the account lockout policy is set and there are more than `threshold` number of failed login attempts
r code `Parse.Error.OBJECT_NOT_FOUND` with error message `Your account is locked due to multiple failed login attempts.
ute(s)`. After `duration` minutes of no login attempts, the application will allow the user to try login again.
accountLockout: {
duration: 5, // duration policy setting determines the number of minutes that a locked-out account remains locked out before automatically becom
nlocked. Set it to a value greater than 0 and less than 100000.
threshold: 3, // threshold policy setting determines the number of failed sign-in attempts that will cause a user account to be locked. Set it
n integer value greater than 0 and less than 1000.
},
// optional settings to enforce password policies
passwordPolicy: {
// Two optional settings to enforce strong passwords. Either one or both can be specified.
// // If both are specified, both checks must pass to accept the password
// // 1. a RegExp object or a regex string representing the pattern to enforce
validatorPattern: /^(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])(?=.{8,})/, // enforce password with at least 8 char with at least 1 lower case, 1 upper case and 1
t
// 2. a callback function to be invoked to validate the password
validatorCallback: (password) => { return validatePassword(password) },
doNotAllowUsername: true, // optional setting to disallow username in passwords
maxPasswordAge: 90, // optional setting in days for password expiry. Login fails if user does not reset the password within this period after signup/l
eset.
maxPasswordHistory: 5, // optional setting to prevent reuse of previous n passwords. Maximum value that can be specified is 20. Not specifying it or spe
ng 0 will not enforce history.
//optional setting to set a validity duration for password reset links (in seconds)
resetTokenValidityDuration: 24*60*60, // expire after 24 hours
}
});
function _getRequireWildcardCache() { if (typeof WeakMap !== "function") return null; var cache = new WeakMap(); _getRequireWildcardCache = function () { ret
urn cache; }; return cache; }
function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function")
{ return { default: obj }; } var cache = _getRequireWildcardCache(); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasProperty
Descriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc
= hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); }
else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
// Factory function
const _ParseServer = function (options) {
const server = new _ParseServer2.default(options);
return server.app;
}; // Mount the create liveQueryServer
exports.ParseServer = _ParseServer;
_ParseServer.createLiveQueryServer = _ParseServer2.default.createLiveQueryServer;
_ParseServer.start = _ParseServer2.default.start;
const GCSAdapter = (0, _deprecated.useExternal)('GCSAdapter', '#parse/gcs-files-adapter');
exports.GCSAdapter = GCSAdapter;
Object.defineProperty(module.exports, 'logger', {
get: _logger.getLogger
});
var _default = _ParseServer2.default;
exports.default = _default;
My config.json file looks like this(Config file located /opt/bitnami/parse) :
{
"appId": "myapp",
"masterKey": "NTxxxxxxmm",
"appName": "parse-server",
"mountPath": "/parse",
"port": "1337",
"host": "0.0.0.0",
"serverURL": "http://3.1xxxxx5/parse/",
"databaseURI": "mongodb://bn_parse:TFyNVz7Y45#127.xxxxx:27xx7/bitnami_parse"
}
When I run my app with the following code:
ParseUser.requestPasswordResetInBackground("myemail#gmail.com",
new RequestPasswordResetCallback() {
public void done(ParseException e) {
if (e == null) {
// An email was successfully sent with reset instructions.
Toast.makeText(getApplicationContext(),
"Password Reset email has been sent to this email address",
Toast.LENGTH_LONG).show();
} else {
// Something went wrong. Look at the ParseException to see what's up.
Log.i("Error", "Password Reset Error", e);
Toast.makeText(getApplicationContext(), e.getMessage(), Toast.LENGTH_SHORT).show();
Toast.makeText(getApplicationContext(),
"Saving user failed.", Toast.LENGTH_SHORT).show();
}
}
});
I get the following Error message in the logs:
2020-06-13 23:13:05.704 15647-15647/com.example.Fitness I/Error: Password Reset Error
com.parse.ParseRequest$ParseRequestException: bad json response
at com.parse.ParseRequest.newTemporaryException(ParseRequest.java:290)
at com.parse.ParseRESTCommand.onResponseAsync(ParseRESTCommand.java:308)
at com.parse.ParseRESTUserCommand.onResponseAsync(ParseRESTUserCommand.java:126)
at com.parse.ParseRequest$3.then(ParseRequest.java:137)
at com.parse.ParseRequest$3.then(ParseRequest.java:133)
at bolts.Task$15.run(Task.java:917)
at bolts.BoltsExecutors$ImmediateExecutor.execute(BoltsExecutors.java:105)
at bolts.Task.completeAfterTask(Task.java:908)
at bolts.Task.continueWithTask(Task.java:715)
at bolts.Task.continueWithTask(Task.java:726)
at bolts.Task$13.then(Task.java:818)
at bolts.Task$13.then(Task.java:806)
at bolts.Task$15.run(Task.java:917)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1162)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:636)
at java.lang.Thread.run(Thread.java:764)
Caused by: org.json.JSONException: Value <!DOCTYPE of type java.lang.String cannot be converted to JSONObject
at org.json.JSON.typeMismatch(JSON.java:111)
at org.json.JSONObject.<init>(JSONObject.java:163)
at org.json.JSONObject.<init>(JSONObject.java:176)
at com.parse.ParseRESTCommand.onResponseAsync(ParseRESTCommand.java:298)
at com.parse.ParseRESTUserCommand.onResponseAsync(ParseRESTUserCommand.java:126) 
at com.parse.ParseRequest$3.then(ParseRequest.java:137) 
at com.parse.ParseRequest$3.then(ParseRequest.java:133) 
at bolts.Task$15.run(Task.java:917) 
at bolts.BoltsExecutors$ImmediateExecutor.execute(BoltsExecutors.java:105) 
at bolts.Task.completeAfterTask(Task.java:908) 
at bolts.Task.continueWithTask(Task.java:715) 
at bolts.Task.continueWithTask(Task.java:726) 
at bolts.Task$13.then(Task.java:818) 
at bolts.Task$13.then(Task.java:806) 
at bolts.Task$15.run(Task.java:917) 
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1162) 
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:636) 
at java.lang.Thread.run(Thread.java:764) 
2020-06-13 23:13:05.754 1441-1441/? D/gralloc_ranchu: gralloc_alloc: Creating ashmem region of size 360448
It looks like the email address which is a string cannot be converted to a JSON object, I've checked and made sure that my server URL has a "/" at the end of the URL. I also added 'com.parse:parse-android:1.12.0' into my gradle to see if that would fix it but the issue is still occurring.
If I've added these entries in the wrong index.js file or need to format the file can someone let me know what I'm doing wrong?
The code you copied and pasted is unfortunately rather difficult to follow, but the error
Caused by: org.json.JSONException: Value
indicates that the URL your Android app is reaching is not returning JSON data. Your Android code is either not hitting the proper URL to invoke the function, or your server is misconfigured and is returning HTML (probably an error page or a 404) to the Android app. Unless you've tested and verified that you can successfully invoke a basic function that returns JSON, I'd suggest removing all the email-related code and working on that first, before trying to put that back in.

ionic3 error on android when calling GET HTTP

In Ionic3 I installed import { HttpClientModule } from '#angular/common/http'; and in my code I'm trying to call below url :
testHTTP(){
this.httpClient.get("https://api.upcitemdb.com/prod/trial/lookup?upc=5425016921463").subscribe(
data => {
console.log('Data : ', data);
this.lookup = data["items"][0].title;
}, err => {
console.log('Error : ', err);
this.lookup = JSON.stringify(err);
});
}
but every time it fails with :
{"headers":{"normalizedNames":{},"lazyUpdate":null,"headers":{}},"status":0,"statusText":"Unknown Error","url":null,"ok":false,"name":"HttpErrorResponse","message":"Http failure response for (unknown url): 0 Unknown Error","error":{"isTrusted":true}}
When I click on the button calling testHTTP on Chrome, I get a CORS error with this object (but I can deactivate CORS and get the real response).
How do you setup ionic http for the get to work please ?
You should use a XMLHttpRequest. And dont forget the Headers.
var xhr = new XMLHttpRequest();
xhr.open("GET", "https://api.upcitemdb.com/prod/trial/lookup?upc=5425016921463", true);
//Really important to set this header
xhr.setRequestHeader("Access-Control-Allow-Origin","http://localhost:8100");
xhr.onreadystatechange = function() {
if(xhr.readyState == xhr.DONE) {
let ResponseFromRequest = xhr.response //Response from your request
}
}
xhr.send(null);

Cloud Function Not Working

I want to add notifications to an online android chatting app I have made. I am new to cloud functions, so I tried using the code given here https://firebase.googleblog.com/2016/08/sending-notifications-between-android.html
My index.js file
var firebase = require('firebase-admin');
var request = require('request');
var API_KEY = "xyz"; // Your Firebase
Cloud Messaging Server API key
// Fetch the service account key JSON file contents
var serviceAccount = require("firebase.json");
// Initialize the app with a service account, granting admin privileges
firebase.initializeApp({
credential: firebase.credential.cert(serviceAccount),
databaseURL: "https://firebaseio.com/"
});
ref = firebase.database().ref();
function listenForNotificationRequests() {
var requests = ref.child('notificationRequests');
requests.on('child_added', function(requestSnapshot) {
var request = requestSnapshot.val();
sendNotificationToUser(
request.username,
request.message,
function() {
console.log('notificationrecived, sent and removed- ' +
request.username + ' '+ request.message,);
requestSnapshot.ref.remove();
}
);
}, function(error) {
console.error(error);
});
};
function sendNotificationToUser(username, message, onSuccess) {
request({
url: 'https://fcm.googleapis.com/fcm/send',
method: 'POST',
headers: {
'Content-Type' :' application/json',
'Authorization': 'key='+API_KEY
},
body: JSON.stringify({
notification: {
title: message
},
to : '/topics/'+username
})
}, function(error, response, body) {
if (error) { console.error(error); }
else if (response.statusCode >= 400) {
console.error('HTTP Error: '+response.statusCode+' - '
+response.statusMessage);
}
else {n
onSuccess();
}
});
}
// start listening
listenForNotificationRequests();
I have successfully deployed this code to the server using node.js command line.
But this does not show up on the console and nor the logs that I added to debug
and the code doesn't seem to work. I have done everything given in the link i mentioned. I could use some help on how to fix my code
I don't know how big of a difference this makes, but in the Firebase admin set up page https://firebase.google.com/docs/admin/setup, it is mentioned that for Cloud Functions, the following line is sufficient for initialisation:-
var firebase = require('firebase-admin');
firebase.initializeApp(functions.config().firebase);
So, if you're going by the book, you may replace the initialisation line in your code with the one above and try running it again.
I didn't export my function listenForNotificationRequests() but called it only once at the end of the script.
Which is why it didn't show up on the Firebase Console.
I fixed this by simply exporting the function like this
exports.sendFollowerNotification = listenForNotificationRequests;

Authentication with Passport Session on Android

I have a web app currently running with NodeJS and Express, where I authenticate the users using Passport sessions, and it works perfectly. Here is the overview of what I do:
app.use(session({
secret : 'hidden of course :)',
resave: false,
saveUninitialized: true
}));
app.use(passport.initialize());
app.use(passport.session());
/****** Passport functions ******/
passport.serializeUser(function (user, done) {
done(null, user.idUser);
});
passport.deserializeUser(function (id, done) {
db.user.findOne( { where : { idUser : id } }).then(function (user, err) {
done(null, user);
});
});
//Facebook
passport.use(new FacebookStrategy({
//Information stored on config/auth.js
clientID: *******,
clientSecret: ******,
callbackURL: *******,
profileFields: ['id', 'emails', 'displayName', 'name', 'gender', 'picture.type(large)']
}, function (accessToken, refreshToken, profile, done) {
//Using next tick to take advantage of async properties
process.nextTick(function () {
db.user.findOne( { where : { idUser : profile.id } }).then(function (user, err) {
if(err) {
return done(err);
}
if(user) {
return done(null, user);
} else {
// Check whether the email is undefined or valid
var emailTemp = '';
if(profile.emails && profile.emails[0] && profile.emails[0].value) {
emailTemp = profile.emails[0].value;
} else {
emailTemp = '';
}
var picture = '';
if(profile.photos && profile.photos[0] && profile.photos[0].value) {
picture = profile.photos[0].value;
} else {
picture = '/img/profile.png';
}
var sexFb = '';
if(profile.gender) {
sexFb = profile.gender;
} else {
sexFb = '';
}
// Create the user
db.user.create({
idUser : profile.id,
token : accessToken,
picture : picture,
nameUser : profile.displayName,
email : emailTemp,
sex : sexFb
}).then(function () {
db.user.findOne( { where : { idUser : profile.id } }).then(function (user, err) {
if(user) {
return done(null, user);
} else {
return done(err);
}
});
});
}
});
});
}));
app.use(express.static(__dirname + '/public/'));
/* FACEBOOK STRATEGY */
// Redirect the user to Facebook for authentication. When complete,
// Facebook will redirect the user back to the application at
// /auth/facebook/callback//
app.get('/auth/facebook', passport.authenticate('facebook', { scope : ['email']}));
/* FACEBOOK STRATEGY */
// Facebook will redirect the user to this URL after approval. Finish the
// authentication process by attempting to obtain an access token. If
// access was granted, the user will be logged in. Otherwise,
// authentication has failed.
app.get('/auth/facebook/callback',
passport.authenticate('facebook', { failureRedirect: '/' }),
function (req, res) {
// Successful authentication, redirect home.
res.redirect('../../app.html');
});
Now, I'm building our Android App and I need to authenticate our users, preferably using the backend I already built for the web version. I was checking some questions on SO like this one and I understood a lot of what I would have to do.
Currently my clients stay logged in through the cookie that Express-session handles, saving the user's id on the req.user, so that I can run queries like on this example:
app.put('/profile', function (req, res) {
//Updates the profile information of the user
db.user.update({
nameUser : req.body.nameUser
}, {
where : {
idUser : req.user.idUser
}
}).then(function (user) {
res.json({ yes : "yes" });
});
});
So my questions:
Can I authenticate my users using the same strategy as the one I currently have? If not, what would I have to change to be able to authenticate my users on Android?
Once they are authenticated, how can I set the req.user from Android (through HTTP request or whatever mean) to correctly perform the tasks on the backend (since all my requests are based on req.user)? I assume Android doesn't keep cookies like browsers do, so how would Passport Sessions know which user is calling the API?
I currently use Retrofit2 on my Android app to interact with the API, is it able to perform the actions necessary for this task?
Sorry for the long post, added a good chunk of code just to be on the safe side, if you guys have any questions or need any explanation please let me know!

Ti.Network.createHTTPClient async

I have the need to download data from a web server at startup of the app . The data is to be retrieved from a 50 http addresses . The problem that I load the page of the app before it has completed the recovery operation via http request of titanium . Do you have any suggestions?
function doRequest(url, callback) {
var client = Ti.Network.createHTTPClient({
onerror: function (err) {
callback(err, null);
},
onload: function () {
try {
callback(null, JSON.parse(this.responseText));
}
catch (err) {
callback(err, null);
}
}
});
client.open('GET', url);
client.send();
}
use promises.
https://github.com/kriskowal/q
Look at documentation on all or sequences
return Q.all([
download(url1),
download(url2)
...
]);

Categories

Resources