Created
January 24, 2017 20:40
-
-
Save giltotherescue/eaab9394830dbf50a6ae56741bda6d31 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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