AngularJS get next $state - angularjs

Hey guys I wrote this code to do a front end check (I already checked in server side). To see if user is logged or not depending in the "State" it is or path in this case, because I was using the $location first, but I moved to ui.router. Any suggestions of how to make this code work with ui.router:
app.run(function($rootScope, $state, checkLogin, User) {
$rootScope.$on("$stateChangeStart", function(event, next, current) {
checkLogin.check(function(response) {
if (response) {
var nextUrl = next.$$route.orginalPath
if (nextUrl == 'login' || nextUrl == '/') {
$state.target('panel')
}
$rootScope.isLogged = true;
} else {
$rootScope.isLogged = false;
$state.target('login')
}
});
});
});

Related

Google Authentication with Protractor

I have only been able to track down this link to solve my problem. I am trying to use protractor to run e2e testing. This is my first go at it, and I like it. However my project requires Google Authentication, then once authenticated, I compare it to my database to make sure the user is in the project. I cannot figure out from the stackoverflow post how to call to the Google Auth page object demee is talking about in the last answer. Also the first person says to find element by.id('Email') and by.id('Passwd') which may be a problem, because my google auth is coming up in another window. So I am not sure how to call to that with Protractor. Here is some of my code after I initialize the $window once gapi is loaded:
.controller('ContainerController', ['$scope', '$rootScope', '$state','$window', '$location','employeeFactory', 'employeeTestFactory', function ($scope, $rootScope, $state, $window,$location, employeeFactory, employeeTestFactory) {
$rootScope.callRequests=function(){};
$rootScope.callInfo=function(){};
if(typeof $rootScope.gapi !== "undefined")gapi.load('client:auth2', initClient);
$rootScope.$on('$stateChangeStart', function(event, toState, toParams, fromState, fromParams){
if(typeof $rootScope.gapi === "undefined") return;
gapi.load('client:auth2', initClient);
})
$scope.$state = $state;
$window.initGapi = function() {
gapi.load('client:auth2', initClient);
$rootScope.gapi = gapi;
}
$rootScope.calculateUsed = function(val){
$rootScope.employee.timePending = $rootScope.employee.timePending = 0;
var newTimeUsed = 0;
angular.forEach(val, function(key, value){
var td = key.timeDuration;
if(key.timeState === "pending"){
$rootScope.employee.timePending += Number(td);
}else{
newTimeUsed += Number(td);
}
});
$rootScope.employee.totalTimeUsed = newTimeUsed;
}
$scope.employeeType = $rootScope.email = "";
function initClient() {
gapi.client.init({
apiKey: 'AIzaSyDaMf0eviuFygt1hzwQz03a2k2lrLDnpIc',
discoveryDocs: ["https://people.googleapis.com/$discovery/rest?version=v1"],
clientId: '977491754644-954b83j2evmq65v6kchq4dsd9j0ud4vg.apps.googleusercontent.com',
scope: 'profile'
}).then(function () { gapi.auth2.getAuthInstance().isSignedIn.listen(updateSigninStatus); updateSigninStatus(gapi.auth2.getAuthInstance().isSignedIn.get());
$scope.employee = [];
});
}
function updateSigninStatus(isSignedIn) {
if (isSignedIn) {
getEmailAddress();
}else{
$state.go('app');
}
}
$scope.handleSignInClick = function(event) {
if(!gapi.auth2.getAuthInstance().isSignedIn.get()){
gapi.auth2.getAuthInstance().signIn();
}
}
$scope.handleSignOutClick = function(event) {
if(gapi.auth2.getAuthInstance().isSignedIn.get()){
gapi.auth2.getAuthInstance().signOut();
}
}
function getEmailAddress() {
gapi.client.people.people.get({
resourceName: 'people/me'
}).then(function(response) {
$rootScope.email = response.result.emailAddresses[0].value;
$rootScope.callRequests();
$rootScope.callInfo();
//Here is where I compare google to my db and route users back to main if not in db employeeTestFactory.get($rootScope.email).then(function(message) {
if(typeof message.employeeid === "undefined"){
$state.go('app');
}else if($location.path() === "/"){
$state.go('app.employee');
$rootScope.employee = message;
}else{
$rootScope.employee = message;
}
});
}, function(reason) {
console.log('Error: ' + reason.result.error.message);
});
}
}])
.controller('LoginController', ['$scope', '$state', '$window', '$http','$rootScope', '$timeout', 'GooglePlus', 'gapiService', function ($scope, $state, $window, $http, $rootScope, $timeout, GooglePlus, gapiService) {
$scope.$state = $state;
$scope.callme = function(){
$scope.handleSignInClick();
}
// if it could not be loaded, try the rest of
// the options. if it was, return it.
var url;
var windowThatWasOpened;
$http.get("url").then(function(response) {
url = response.data;
});
$scope.login = function() {
windowThatWasOpened = $window.open(url, "Please sign in with Google", "width=500px,height=700px");
}
window.onmessage = function(e) {
if(windowThatWasOpened) windowThatWasOpened.close();
var urlWithCode = e.data;
var idx = urlWithCode.lastIndexOf("code=");
if(idx === -1) return;
var code = urlWithCode.substring(idx + 5).replace("#","");
$http.get("token?code=" + code).then(function(response) {
var userurl = 'https://www.googleapis.com/plus/v1/people/me?access_token='+response.data.access_token;
$http.get(userurl).then(function(response) {
console.log("user info: "+JSON.stringify(response.data));
})
});
}
}])
And here is the code I am trying to navigate to google with:
describe('Protractor Demo App', function() {
it('should have a title', function() {
browser.get('http://localhost:9000/');
element(by.id('gLogin')).click().then(function(){
Google.loginToGoogle();
});
expect(browser.getTitle()).toEqual('TrinityIT Time Off Tracking');
browser.sleep(5000);
});
});
And here is my conf file:
exports.config = {
framework: 'jasmine',
specs: ['googlePage.js','spec.js'],
onPrepare: function () {
global.isAngularSite = function (flag) {
console.log('Switching to ' + (flag ? 'Asynchronous' : 'Synchronous') + ' mode.')
browser.ignoreSynchronization = !flag;
},
global.BROWSER_WAIT = 5000;
}
}
Assuming that what you're looking to do is test your app, rather than test the OAuth dialogue, then there is an easier approach.
First an OAuth refresher, the whole point of doing all the OAuth stuff is that you end up with an Access Token that you can include as an "Authorization: Bearer xxxxx" HTTP Header with your Google API (eg. Drive, YouTube, Calendar, etc) requests. Sooooooo, if you had an Access Token, you could bypass all the OAuth stuff and your app will be active and able to be tested.
So, what you want is an automated way to get an Access Token. That's pretty simple. Somewhere, either in your app code or in your Protractor preamble scripts, you need to ingest a Refresh Token, and use that to generate an Access Token which is available to your app.
I do this with a file refreshtoken.js which I carefully do NOT check in to git for security reasons. refreshtoken.js is
var refreshtoken="1x97e978a7a0977...";
var client_id="423432423#gfgfd";
If you look at the answer to How do I authorise an app (web or installed) without user intervention? (canonical ?), you will see the steps to get a Refresh Token, and at the bottom, some JavaScript to show how to use the Refresh Token to fetch an Access Token. It might look like a lot of steps, but you only ever do them once, so it's not too onerous.
This approach bypasses OAuth, so isn't the answer if it's specifically OAuth that you want to test. However it does allow you to test your app in a much more robust manner. It also has the benefit that it can be used for Karma unit testing as well as Protractor e2e testing.

Redirect to dashboard if user is logged in with Ionic

I am trying to make my app direct to the dashboard on initial load if the user has authenticated with Firebase already.
Basically, if the user has logged in. I want them to see the dashboard instead of the login page when they open the app on their phone.
I've tried to place this in my app.run(). It works and does what I want but it results in an ugly error
Error: [$rootScope:infdig] 10 $digest() iterations reached. Aborting! Watchers fired in the last 5 iterations: []
This runs about 20 times before stopping.
My code in the app.run() function:
$rootScope.$on("$stateChangeStart", function(event, next, current) {
if($rootScope.user)
{
if(next.name === 'login')
{
$state.go('tab.dash');
event.preventDefault();
}
else
{
console.log('Do Nothing, User Is Not Logged In');
}
}
});
How do I do this without getting any errors?
Try placing your code within $ionicPlatform.ready (without $stateChangeStart).
I'm using Parse for my app but here is my code.
.run(function($state, $ionicPlatform, $rootScope) {
$ionicPlatform.ready(function() {
var currentUser = Parse.User.current();
$rootScope.isLoggedIn = false;
if (currentUser) {
$state.go('tab.home');
$rootScope.isLoggedIn = true;
} else {
$state.go('login');
}
});
})
Found this on https://devdactic.com/user-auth-angularjs-ionic/
$urlRouterProvider.otherwise(function ($injector, $location) {
var $state = $injector.get("$state");
var $rootScope = $injector.get("$rootScope");
if ($rootScope.user) {
$state.go("app.dashboard");
} else {
$state.go("app.login");
}
});
That should solve your problem

Angular: Restore scope from sessionStorage

I am trying to retrieve my search and filter data from sessionStorage when the page refreshes.
sessionStorage.restorestate returns undefined, does anyone know why?
app.run(function($rootScope) {
$rootScope.$on("$routeChangeStart", function(event, next, current) {
if (sessionStorage.restorestate == "true") {
$rootScope.$broadcast('restorestate'); //let everything know we need to restore state
sessionStorage.restorestate = false;
}
});
//let everthing know that we need to save state now.
window.onbeforeunload = function(event) {
$rootScope.$broadcast('savestate');
};
});
Plunkr: http://plnkr.co/edit/oX4zygwB0bDpIcmGFgYr?p=preview
When you refresh the page in an Angular app, it is like completely rebooting the application. So to restore from the session storage, just do it when the service factory executes.
app.factory('CustomerSearchService', ['$rootScope',
function($rootScope) {
...
function restoreState() {
service.state = angular.fromJson(sessionStorage.CustomerSearchService);
}
if (sessionStorage.CustomerSearchService) restoreState();
...
}
]);
The saving part was already correct.
app.factory('CustomerSearchService', ['$rootScope',
function($rootScope) {
...
function saveState() {
sessionStorage.CustomerSearchService = angular.toJson(service.state);
}
$rootScope.$on("savestate", saveState);
...
}
]);
app.run(function($rootScope) {
window.onbeforeunload = function(event) {
$rootScope.$broadcast('savestate');
};
});
DEMO

Why I can't access $rootScope value from controller?

I have a variable set to true in the $rootScope. This variable is named loggedIn.
I created a NavController to control the display of my main menu links, and as you can see I injected the $rootScope properly.
appControllers.controller("NavController", function($rootScope, $scope) {
console.log($rootScope); //We can see that loggedIn is true
console.log($rootScope.loggedIn); //Outputs false
//Not working as expected
if($rootScope.loggedIn === true){
$scope.showHomeMenu = false;
$scope.showGameMenu = true;
$scope.currentHome = '/lobby';
}
else {
$scope.showHomeMenu = true;
$scope.showGameMenu = false;
$scope.currentHome = '/login';
}
});
Oddly, this doesn't work because $rootScope.loggedIn is evaluated to false, even though it's value was set to true. This is the output I get from the console.
As you can see from the $rootScope output, loggedIn should be true. But it's evaluated to false in the controller.
I guess I'm doing something really dumb here, but I can't figure out why!!
Edit 2
#rvignacio pointed out something interesting. The object $rootScope I see is the state of the object at the time of the expansion, not the state at the moment when I call log().
(which was predictable...)
I guess the issue is deeper than I thought! I'll have to dig to find the bug!
Edit
I set loggedIn in run().
app.config(function($routeProvider, $httpProvider) {
$routeProvider.
when('/', {
...
}).
...
});
var interceptor = ['$rootScope', '$q',
function(scope, $q) {
function success(response) {
return response;
}
function error(response) {
var status = response.status;
if (status == 401) {
var deferred = $q.defer();
var req = {
config: response.config,
deferred: deferred
};
scope.$broadcast('event:loginRequired');
return deferred.promise;
}
// otherwise
return $q.reject(response);
}
return function(promise) {
return promise.then(success, error);
};
}
];
$httpProvider.responseInterceptors.push(interceptor);
}).run(['$rootScope', '$http', '$location',
function(scope, $http, $location) {
/**
* Holds page you were on when 401 occured.
* This is good because, for example:
* User goes to protected content page, for example in a bookmark.
* 401 triggers relog, this will send them back where they wanted to go in the first place.
*/
scope.pageWhen401 = "";
scope.loggedIn = false;
scope.logout = function() {
$http.get('backend/logout.php').success(function(data) {
scope.loggedIn = false;
scope.$broadcast('event:doCheckLogin');
}).error(function(data) {
scope.$broadcast('event:doCheckLogin');
});
};
scope.$on('event:loginRequired', function() {
//Only redirect if we aren't on restricted pages
if ($location.path() == "/signup" ||
$location.path() == "/login" ||
$location.path() == "/contact" ||
$location.path() == "/about")
return;
//go to the login page
$location.path('/login').replace();
});
/**
* On 'event:loginConfirmed', return to the page.
*/
scope.$on('event:loginConfirmed', function() {
//*********************
//THIS IS WHERE I SET loggedIN
//*********************
scope.loggedIn = true;
console.log("Login confirmed!");
$location.path('/lobby').replace();
});
/**
* On 'logoutRequest' invoke logout on the server and broadcast 'event:loginRequired'.
*/
scope.$on('event:logoutRequest', function() {
scope.logout();
});
scope.$on("$locationChangeSuccess", function(event) {
//event.preventDefault();
ping();
});
scope.$on('event:doCheckLogin', function() {
ping();
});
/**
* Ping server to figure out if user is already logged in.
*/
function ping() {
$http.get('backend/checksession.php').success(function() {
scope.$broadcast('event:loginConfirmed');
}); //If it fails the interceptor will automatically redirect you.
}
//Finally check the logged in state on every load
ping();
}
]);
You guys were right. I'm using async calls to set loggedIn to true, so it was all a question of timing.
Welcome to the world of aynschronism dear me.
$watch-ing loggedIn solved the issue.
appControllers.controller("NavController", function($rootScope, $scope) {
$scope.showHomeMenu = true;
$scope.showGameMenu = false;
$scope.currentHome = '/login';
//ADDED
$rootScope.$watch('loggedIn', function(){
console.log($rootScope.loggedIn);
if($rootScope.loggedIn === true){
$scope.showHomeMenu = false;
$scope.showGameMenu = true;
$scope.currentHome = '/lobby';
}
else {
$scope.showHomeMenu = true;
$scope.showGameMenu = false;
$scope.currentHome = '/login';
}});
});
Also I changed where I set loggedIn to false in my code to increase performance and remove visible latency when logging out. Now everything runs fast.

How to handle Firebase auth in single page app

I am using firebase simple login auth with angularjs and I want to create a single page app.
Before this, I have tried using service, main controller to handle it but I don't think it is good enough because I have to call FirebaseAuthClient() every time there is a route.
I also try to put FirebaseAuthClient() in angularjs .run() which initialize when app is start.
But it won't work when there is a route, I think it is because not a full page load.
Ok,
And here is what I want,
except login page, every route (pages) are required login.
A global FirebaseAuthClient() checking on every route so I don't need to call it again.
A global user which return from FirebaseAuthClient()
I'm not sure I understand. You only need to initialize FirebaseAuthClient and all login() once in your entire app. It's a singleton, and your auth credentials apply to any Firebase operations you perform.
What makes you think that this is not the case? What sorts of errors are you seeing?
Here is what I was using before moving auth over to Singly. Maybe it helps?
p4pApp.factory('firebaseAuth', function($rootScope) {
var auth = {},
FBref = new Firebase(p4pApp.FIREBASEPATH);
auth.broadcastAuthEvent = function() {
$rootScope.$broadcast('authEvent');
};
auth.client = new FirebaseAuthClient(FBref, function(error, user) {
if (error) {
} else if (user) {
auth.user = user;
auth.broadcastAuthEvent();
} else {
auth.user = null;
auth.broadcastAuthEvent();
}
});
auth.login = function() {
this.client.login('facebook');
};
auth.logout = function() {
this.client.logout();
};
return auth;
});
The AuthCtrl is common to all/most of my pages.
var AuthCtrl = function($scope, firebaseAuth) {
$scope.login = function() {
firebaseAuth.login();
};
$scope.logout = function() {
firebaseAuth.logout();
};
$scope.isLoggedIn = function() {
return !!$scope.user;
};
// src: Alex Vanston (https://coderwall.com/p/ngisma)
$scope.safeApply = function(fn) {
var phase = this.$root.$$phase;
if (phase == '$apply' || phase == '$digest') {
if(fn && (typeof(fn) === 'function')) {
fn();
}
} else {
this.$apply(fn);
}
};
$scope.$on('authEvent', function() {
$scope.safeApply(function() {
$scope.user = firebaseAuth.user;
});
});
};
From within the AuthCtrl you can just call isLoggedIn() to see if the user is logged in or not.

Resources