Skip to content

Instantly share code, notes, and snippets.

@giltotherescue
Created January 24, 2017 20:40
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save giltotherescue/eaab9394830dbf50a6ae56741bda6d31 to your computer and use it in GitHub Desktop.
Save giltotherescue/eaab9394830dbf50a6ae56741bda6d31 to your computer and use it in GitHub Desktop.
angular.module('airfoil.services-auth', [])
.factory('Auth', function ($ionicPlatform, $q, $state, $injector, $timeout, AutoComplete, $rootScope, es,
$cordovaFacebook, $cordovaDevice, $cordovaDialogs, $cordovaPush, $cordovaBackgroundGeolocation,
$analytics) {
var self = this;
self.initialized = false;
self.AuthData = {};
self.ProfileData = {};
self.PushData = null;
self.lastAirportCallback = null;
/**
* Init the global variable AuthData
*/
self.init = function() {
onAuth().then(
function (AuthData) {
self.initialized = true;
self.AuthData = AuthData;
if (window.intercom) {
window.intercom.registerIdentifiedUser({userId: self.AuthData.uid});
}
}, function(error) {
self.initialized = true;
self.unAuth();
$state.go('start');
}
);
};
/**
* unAuthenticate the user
* independent of method (password, twitter, etc.)
*/
self.unAuth = function () {
self.AuthData = {};
return firebase.auth().signOut();
};
/**
* Monitor the current authentication state
* returns on success: AuthData
* returns on fail: AUTH_LOGGED_OUT
*/
function onAuth() {
var defer = $q.defer();
function AuthDataCallback(user) {
if (user) {
self.AuthData = user;
defer.resolve(user);
} else {
defer.reject("AUTH_LOGGED_OUT");
}
}
firebase.auth().onAuthStateChanged(AuthDataCallback);
return defer.promise;
}
self.getAuthState = function () {
var defer = $q.defer();
if (!self.initialized) {
// Delay all resolves until Firebase is initialized
$timeout(function() {
// uncomment this to see how long we're blocking while waiting for a response
// console.log('pausing');
defer.resolve(self.getAuthState());
}, 200);
} else {
if (self.AuthData.hasOwnProperty('uid')) {
defer.resolve();
} else {
defer.reject('Logged out');
}
}
return defer.promise;
};
self.signInPassword = function (email, password) {
var defer = $q.defer();
firebase.auth().signInWithEmailAndPassword(email, password).then(
function (user) {
self.AuthData = user;
defer.resolve(user);
}, function (error) {
defer.reject(error);
}
);
return defer.promise;
};
self.signUpPassword = function (email, password) {
var defer = $q.defer();
firebase.auth().createUserWithEmailAndPassword(email, password).then(
function (user) {
self.AuthData = user;
defer.resolve(user);
}, function (error) {
defer.reject(error);
}
);
return defer.promise;
};
/**
* Change Password or Email / Reset Password
*/
self.changePassword = function (email, password, newPassword) {
var defer = $q.defer();
var retry = true;
var updateIt = function () {
firebase.auth().currentUser.updatePassword(newPassword).then(
function () {
defer.resolve();
}, function (error) {
// login if necessary
if (error.code == 'auth/requires-recent-login' && retry) {
retry = false; // only retry once
var credential = firebase.auth.EmailAuthProvider.credential(email, password);
firebase.auth().currentUser.reauthenticate(credential).then(
function () {
updateIt();
}, function (error) {
defer.reject(error);
}
);
} else {
defer.reject(error);
}
}
);
};
updateIt();
return defer.promise;
};
self.changeEmail = function (email, newEmail, password) {
var defer = $q.defer();
var retry = true;
var updateIt = function () {
firebase.auth().currentUser.updateEmail(newEmail).then(
function () {
defer.resolve();
}, function (error) {
// login if necessary
if (error.code == 'auth/requires-recent-login' && retry) {
retry = false; // only retry once
var credential = firebase.auth.EmailAuthProvider.credential(email, password);
firebase.auth().currentUser.reauthenticate(credential).then(
function () {
updateIt();
}, function (error) {
defer.reject(error);
}
);
} else {
defer.reject(error);
}
}
);
};
updateIt();
return defer.promise;
};
self.resetPassword = function (email) {
return firebase.auth().sendPasswordResetEmail(email);
};
/**
* ---------------------------------------------------------------------------
* Social Authentication
* Setup your providers as follows: https://www.firebase.com/docs/web/guide/user-auth.html#section-providers
*/
self.signInFacebook = function () {
var defer = $q.defer();
// authenticate Facebook
$cordovaFacebook.login(["public_profile", "email", "user_friends"], function (status) {
// authenticate Firebase
var credential = firebase.auth.FacebookAuthProvider.credential(status.authResponse.accessToken);
firebase.auth().signInWithCredential(credential).then(
function (user) {
self.AuthData = user;
defer.resolve(user);
}, function (error) {
defer.reject(error);
}
);
}, function (error) {
defer.reject(error);
});
return defer.promise;
};
self.loadProfile = function (refresh) {
var defer = $q.defer();
if (refresh || !self.ProfileData.hasOwnProperty('name')) {
var profileService = $injector.get('Profile');
profileService.get(self.AuthData.uid).then(
function (data) {
if (data != null &&
data.hasOwnProperty('business') &&
data.hasOwnProperty('type') &&
data.hasOwnProperty('name') &&
data.hasOwnProperty('email')) {
// logged in
self.ProfileData = data;
// update Sentry
Raven.setUserContext({
'email': data.email,
'id': self.AuthData.uid
});
var properties = {
Airport: data.airport,
Created: new Date(data.created).toISOString(),
Type: data.type,
Facebook: data.facebook || null,
// mixpanel
$email: data.email,
$name: data.name,
// intercom
email: data.email,
name: data.name,
signed_up_at: new Date(data.created).toISOString()
};
$analytics.setUsername(self.AuthData.uid);
$analytics.setUserProperties(properties);
if (window.FirebasePlugin) {
window.FirebasePlugin.onTokenRefresh(function (token) {
self.PushData = token;
self.saveSetting('fcm_token', token);
}, function (error) {
console.error(error);
});
}
defer.resolve('success');
} else {
// logged in but no profile yet
if (window.mixpanel) {
mixpanel.alias(self.AuthData.uid);
}
if (window.intercom) {
intercom.registerIdentifiedUser({userId: self.AuthData.uid});
}
defer.resolve();
}
}, function (error) {
defer.reject(error);
}
);
} else {
defer.resolve('success');
}
return defer.promise;
};
self.getSetting = function (setting) {
if (self.ProfileData.hasOwnProperty('settings') && self.ProfileData.settings.hasOwnProperty(setting)) {
return self.ProfileData.settings[setting];
}
return null;
};
self.saveSetting = function (key, val) {
var defer = $q.defer();
db.child('profiles/' + self.AuthData.uid + '/settings/' + key).set(val).then(
function () {
if (!self.ProfileData.hasOwnProperty('settings')) {
self.ProfileData.settings = {};
}
self.ProfileData.settings[key] = val;
defer.resolve();
}, function (error) {
defer.reject(error);
}
);
return defer.promise;
};
self.initPush = function () {
console.log('PUSH: INIT', self.getSetting('push'));
if (window.cordova && self.getSetting('push') === 1) {
if (window.intercom) {
window.intercom.registerForPush();
}
console.log('PUSH: CHECK FIREBASE');
//console.error(error);
if (!window.FirebasePlugin) {
console.log('PUSH: FIREBASE PLUGIN DOES NOT EXIST');
return false;
}
if ($cordovaDevice.device.platform == 'iOS') {
window.FirebasePlugin.grantPermission(function(success) {
console.log('PUSH: GRANTED PERMISSION', success);
// now grant
window.FirebasePlugin.getToken(function(token) {
console.log('PUSH: GOT FIREBASE IOS', token);
self.PushData = token;
self.saveSetting('fcm_token', token);
window.FirebasePlugin.onNotificationOpen(function(notification) {
console.log('PUSH: GOT NOTICE IOS', notification);
// clear all badges once app opens
// this is temporary until we build something smarter
window.FirebasePlugin.setBadgeNumber(0);
if (notification.hasOwnProperty('url')) {
console.log('PUSH: HAS URL', notification.url);
doOpenURL(notification.url);
}
}, function(error) {
console.error(error);
});
});
});
} else {
window.FirebasePlugin.getToken(function(token) {
console.log('PUSH: GOT FIREBASE ANDROID', token);
self.PushData = token;
self.saveSetting('fcm_token', token);
window.FirebasePlugin.onNotificationOpen(function(notification) {
console.log('PUSH: GOT NOTICE ANDROID');
console.log(notification);
}, function(error) {
console.error(error);
});
});
}
}
};
// isManual when the user expresses intent
self.initLocation = function (isManual) {
var defer = $q.defer();
// log when someone explicitly geolocates
if (isManual) {
$analytics.eventTrack('Geolocate');
}
if (window.cordova) {
var geo = $cordovaBackgroundGeolocation;
// set new location
var callbackFunc = function (location) {
$rootScope.currentLocation = location;
geo.finish();
self.checkIfAtAirport();
};
// location error
var failFunc = function (error) {
console.log(error);
};
var options = {
desiredAccuracy: 100, // meters
distanceFilter: 500, // meters
stationaryRadius: 100, // meters
interval: 1000 * 120, // check location every 2 mins
fastestInterval: 1000 * 20, // don't check more often than every 20 secs
maxLocations: 1, // store only the most recent location in the local db
debug: false,
stopOnTerminate: true // stop location tracking if the app is manually closed
};
geo.configure(callbackFunc, failFunc, options);
var startUp = function() {
geo.start(
function(success) {
defer.resolve(success);
},
function (error) {
if (error.code === 2) {
geo.stop();
if (isManual) {
$cordovaDialogs.confirm(
'Would you like to enable location access in app settings?',
'Permission Denied',
['Not now', 'Open Settings']
).then(
function (index) {
if (index === 2) {
geo.showAppSettings();
}
}
);
}
} else {
console.error('LOCATION: start failed', error);
}
defer.reject(error);
}
);
};
if (self.getSetting('location') === 1) {
geo.isLocationEnabled(
function (enabled) {
isLocationEnabled = enabled;
if (enabled) {
// start is complete
startUp();
} else {
if (isManual) {
$cordovaDialogs.confirm(
'Would you like to open location settings?',
'Location Services are disabled',
['Not now', 'Open Settings']
).then(
function (index) {
if (index === 2) {
geo.showLocationSettings();
}
}
);
}
defer.reject();
}
},
function (error) {
console.error('LOCATION: Error detecting status of location settings', error);
defer.reject(error);
}
);
} else {
startUp();
}
} else {
defer.resolve();
}
return defer.promise;
};
self.checkIfAtAirport = function() {
// rate limit: only one check per 5 seconds
var curDate = Date.now();
var diff = curDate - self.lastAirportCallback;
if (self.lastAirportCallback && diff < (5000)) {
self.lastAirportCallback = curDate;
return;
}
self.lastAirportCallback = curDate;
var body = {
"size": 1,
"filter": {
"geo_distance": {
"distance": "800m", // less than half a mile away
"location": {
"lat": $rootScope.currentLocation.latitude,
"lon": $rootScope.currentLocation.longitude
}
}
},
"sort": [
{
"_geo_distance": {
"location": {
"lat": $rootScope.currentLocation.latitude,
"lon": $rootScope.currentLocation.longitude
},
"order": "asc",
"unit": "m"
}
}
]
};
es.search({
index: 'airports',
type: 'airports',
body: body
}).then(function(success) {
if (success && success.hits.hits && success.hits.hits.length) {
var nearest = success.hits.hits[0];
// only airports, no helipads or other types
if (nearest && (nearest._source.type == 'large_airport' || nearest._source.type == 'medium_airport' || nearest._source.type == 'small_airport')) {
$rootScope.currentAirport = nearest._source;
$rootScope.$broadcast('Arrived at Airport');
$analytics.eventTrack('Geolocate / Arrived at Airport');
}
} else if ($rootScope.currentAirport) {
$rootScope.currentAirport = null;
$rootScope.$broadcast('Left Airport');
$analytics.eventTrack('Geolocate / Left Airport');
}
});
};
return self;
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment