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.
Related
I have a button on the client side that is helping me test a simplified version of a backend function. For some reason, the client side (Logcat in Android Studio) is returning test button isUsernameAvailable: Success. result.data = 2000. When I look at the Firebase console, I see that the code reached _isUsernameAvailable REACHED THEN. However, I don't understand why the client received a 2000 instead of a 5. If it reached the aforementioned section, the line after that reads return 5. Why didn't my client receive a 5?
Client code:
testbutton.setOnClickListener() {
functions = Firebase.functions
var data = hashMapOf<String, Any>()
data["username"] = "ThisUsernameDoesntExist"
functions.getHttpsCallable("isUsernameAvailable")
.call(data)
.addOnSuccessListener {result ->
Log.e(tag, "test button isUsernameAvailable: Success. result.data = " + result.data.toString())
}
.addOnFailureListener {exception ->
Log.e(tag, "test button failure exception: $exception")
}
}
Cloud Function code:
//Check if username is available (callable from client)
exports.isUsernameAvailable = functions.https.onCall(async(data, context) => {
const username = data.username
await admin.firestore().collection('users').where('username', '==', username).limit(1).get()
.then(result => {
console.log('_isUsernameAvailable REACHED THEN ')
return 5
})
.catch(error => {
console.log('_isUsernameAvailable REACHED CATCH ')
return 6
})
return 2000
});
This answer partly explained what's happening on your code. To apply on your case, return 5 is just returning from the Firestore callback function and it does not cause your main function process to end.
A solution is to create a variable to assign the value whenever an event is met instead of returning it:
exports.isUsernameAvailable = functions.https.onCall(async(data, context) => {
const username = data.username
var returnCode = 0
await admin.firestore().collection('users').where('username', '==', username).limit(1).get()
.then(result => {
console.log('_isUsernameAvailable REACHED THEN ')
returnCode = 5
})
.catch(error => {
console.log('_isUsernameAvailable REACHED CATCH ')
returnCode = 6
})
if (returnCode != 2000){
return returnCode
}
return 2000
});
I am trying to set a new track and upload APK for publishing using nodejs... But no APK is uploaded nor is there a track set.
But the results from the validation and all the other steps are exactly as I expect(according to API). The script succeeds, yet nothing changes in the developer console... So is there a magic guru out there that may see my issue?
NOTE 1: I did publish my app manually because the android-publisher is only for updating apps that have been published before
NOTE 2: This worked before(a long time ago), and has stopped working for a while, I finally got around to updating everything
My code:
var google = require('googleapis').google;
var Promise = require('bluebird');
var _ = require('lodash');
var settings = require('./config/settings.json');
// Enable API access into the Developer Console: https://play.google.com/apps/publish/?account=7639196906174529268#ApiAccessPlace
// Create a service account
// Download the JSON and save it here
// Make sure the email of the JSON is added to the apps for release manager role:
// https://play.google.com/apps/publish/?account=7639196906174529268#AdminPlace
var key = require('./config/google-play-user.json');
// editing "scope" allowed for OAuth2
var scopes = [
'https://www.googleapis.com/auth/androidpublisher'
];
var OAuth2 = google.auth.OAuth2;
var oauth2Client = new OAuth2();
var jwtClient = new google.auth.JWT(key.client_email, null, key.private_key, scopes, null);
var play = google.androidpublisher({
version: 'v3',
auth: oauth2Client,
params: {
// default options
// this is the package name for your initial app you've already set up on the Play Store
packageName: settings.app.id
}
});
google.options({auth: oauth2Client});
// Start with a new edit.
startEdit().then(function(data) {
// Load our APK(in this case a Cordova APK).
var standardAPK = require('fs').readFileSync('./platforms/android/build/outputs/apk/android-release.apk');
// Stage the upload (doesn't actually upload anything).
return upload({
edit: data.edit,
apk: standardAPK,
key: 'standardApk'
});
}).then(function(data) {
// Set our track.
return setTrack(data);
}).then(function(data) {
// Validate our changes.
return validateToPlayStore(data);
}).then(function(data) {
console.log('Successful uploaded APK files:', data);
}).catch(function(err) {
console.log(err);
process.exit(1);
});
/**
* Sets our authorization token and begins an edit transaction.
*/
function startEdit() {
return new Promise(function(resolve, reject) {
jwtClient.authorize(function(err, tokens) {
if (err) {
console.log(err);
process.exit(1);
return;
}
// Set the credentials before we doing anything.
oauth2Client.setCredentials(tokens);
play.edits.insert({
packageName: settings.app.id
}, function(err, edit) {
if (err || !edit) { reject(err); }
resolve({
edit: edit.data
});
});
});
});
}
/**
* Stages an upload of the APK (but doesn't actually upload anything)
*/
function upload(data) {
var edit = data.edit;
var apk = data.apk;
var key = data.key;
return new Promise(function(resolve, reject) {
play.edits.apks.upload({
editId: edit.id,
packageName: settings.app.id,
media: {
mimeType: 'application/vnd.android.package-archive',
body: apk
}
}, function(err, res) {
if (err || !res) { reject(err); }
// Pass any data we care about to the next function call.
var obj = {};
obj[key] = res.data;
resolve(_.omit(_.extend(data, obj), 'apk'));
});
});
}
/**
* Sets our track (beta, production, etc.)
*/
function setTrack(data) {
var edit = data.edit;
var track = 'production';
return new Promise(function(resolve, reject) {
play.edits.tracks.update({
editId: edit.id,
track: track,
packageName: settings.app.id
}, function(err, res) {
if (err || !res) { reject(err); }
resolve(_.extend(data, {setTrackResults: res.data}));
});
});
}
/**
* Validates our edit transaction and makes our changes live.
*/
function validateToPlayStore(data) {
return new Promise(function(resolve, reject) {
// play.edits.commit({ // Commit will set the change LIVE
play.edits.validate({ // Validate will only validate it, not set it LIVE.
editId: data.edit.id,
packageName: settings.app.id
}, function(err, res) {
if (err || !res) { reject(err); }
resolve(_.extend(data, {validateToPlayStoreResults: res.data}));
});
});
}
Originally from http://frontendcollisionblog.com/javascript/2015/12/26/using-nodejs-to-upload-app-to-google-play.html when it still worked
You can use apkup to upload APKs to Google Play. apkup is basically a friendly wrapper/CLI for the googleapis package.
CLI example:
npx apkup \
--key ./config/google-play-user.json \
--release-notes "en-US=lorem ipsum dolor" \
--apk ./platforms/android/build/outputs/apk/android-release.apk
Node.js example:
const { Apkup } = require('apkup')
const key = require('./config/google-play-user.json')
const apkup = new Apkup(key)
apkup
.upload('./platforms/android/build/outputs/apk/android-release.apk', {
releaseNotes: [
{
language: 'en-US',
text: 'Minor bug fixes...'
}
]
})
.then(data => {
console.log(` > ${data.packageName} version ${data.versionCode} is up!`)
})
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!
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
I am using login with facebook utility of parse in my android application. Login with facebook utility works fine. it inserts only "userName" and "authData" column of "User" table.
I am getting name and email of facebook user using graph API of facebook.
Question -
How do we store "fullName" and "email" of facebook user into parse?
Thanks in advance!
I was able to write user Facebook details in CloudCode by doing the following:
Parse.Cloud.beforeSave(Parse.User, function (request, response) {
// Use Master Key
Parse.Cloud.useMasterKey();
// Pull User Object
var User = request.object;
// User Check
if (!User) {
// Not allowed
response.error();
return;
}
// For some reason, pulling authData fails. A try catch helps the TypeError that may happen
try {
var authData = User.get('authData');
var access_token = authData.facebook.access_token;
} catch(e) {
var access_token = null;
}
Parse.Cloud.httpRequest({
url:'https://graph.facebook.com/v2.1/me?fields=picture.height(50).width(50),email,first_name,last_name,friends.limit(5000),name,gender&access_token='+access_token,
success:function (httpResponse) {
// Success
var facebookIds = [];
try {
var facebookFriends = httpResponse.data.friends.data;
} catch (e) {
var facebookFriends = [];
}
var promise = _.each(facebookFriends, function(facebookFriend) {
facebookIds.push(facebookFriend.id);
});
Parse.Promise.when([promise]).then(function () {
if (request.object.existed() == false) {
User.set("displayName", httpResponse.data.name);
}
// Updating user object
User.set("facebookFriends", facebookIds);
User.set("fbEmail", httpResponse.data.email);
User.set("profileThumb", httpResponse.data.picture.data.url);
User.set("facebookId", httpResponse.data.id);
User.set("gender", httpResponse.data.gender);
response.success();
});
},
error:function (error){
// Error
response.error('Server error.')
}
});
});