Adam Zerner
Adam Zerner

Reputation: 19248

How should you getCurrentUser after a page reload?

Here is how I'm doing it so far:

angular
  .module('mean-starter')
  .factory('Auth', function($http, $state, $window, $cookies) {
    var currentUser = {};

    return {
      signup: function(user) {
        return $http
          .post('/users', user)
          .then(function(data, status, headers, config) {
            angular.copy(data, currentUser);
            $cookies.put('userId', data._id);
            $window.location.href = '/';
          })
        ;
      },
      login: function(user) {
        return $http
          .post('/login', user)
          .then(function(data) {
            angular.copy(data, currentUser);
            $cookies.put('userId', data._id);
            $window.location.href = '/';
          })
        ;
      },
      logout: function() {
        $http
          .get('/logout')
          .then(function() {
            angular.copy({}, currentUser);
            $cookies.remove('userId');
            $window.location.href = '/';
          })
          .catch(function() {
            console.log('Problem logging out.');
          })
        ;
      },
      getCurrentUser: function() {
        // user is logged in
        if (currentUser._id) {
          return currentUser;
        }
        // user is logged in, but page has been refreshed and currentUser is lost
        if ($cookies.get('userId')) {
          return $http.get('/current-user')
            .then(function(data) {
              angular.copy(data, currentUser);
            })
          ;
        }
        // user isn't logged in
        else {
          return currentUser;
        }
      },
      isLoggedIn: function() {
        return !!currentUser._id;
      }
    };
  })
;

After a page reload, the Auth factory gets re-run and currentUser is reassigned to {}. So if the user was logged in, currentUser won't reflect it. So I have to check for the case where !currentUser._id && $cookies.get('userId') and if so, query the database for the currently logged in user.

Now I want to access currentUser:

angular
  .module('mean-starter')
  .run(run)
;

function run($rootScope, Auth, $state) {
  $rootScope.$on('$stateChangeStart', function(event, toState, toParams) {
    if (typeof toState.authenticate !== 'undefined') {
      var currentUser = Auth.getCurrentUser();
      var admin = currentUser.role === 'admin';
      var authorized = currentUser._id.toString() === toParams.id;
      if (!Auth.isLoggedIn()) {
        event.preventDefault();
        alert('Must be logged in to access this route.');
        $state.go('login');
      }
      else if (toState.authenticate.authorized) {
        if (!admin && !authorized) {
          event.preventDefault();
          alert('You are not authorized to access that route.');
        }
      }
      else if (toState.authenticate.isAdmin) {
        if (!admin) {
          event.preventDefault();
          alert('You must be an admin to access this route.');
        }
      }
    }
  });
}

The problem is that I don't know whether or not Auth.getCurrentUser() will return the user or a promise. How can I check for this? How should this be architected?

Upvotes: 1

Views: 242

Answers (2)

logee
logee

Reputation: 5077

Why not just always return a promise in your getCurrentUser with the help of $q?

So something like this

getCurrentUser: function() {
        if (currentUser._id || !$cookies.get('userId')) {
          // $q.when will wrap your currentUser into a promise
          return $q.when(currentUser);
        }

        return $http.get('/current-user')
            .then(function(data) {
              angular.copy(data, currentUser);
              return currentUser;
            });
        }
      }

and in your controller:

Auth.getCurrentUser().then(function(currentUser) {
    // Your code

})

Upvotes: 2

maschwenk
maschwenk

Reputation: 599

You can adapt your function to return a promise in both cases using $q. In this case, all three logical paths should result in the same outcome, albeit by different sets of operations in between, therefore a promise would work perfectly here. Especially because you can have very specific control over the error handling flow (if needed)

http://markdalgleish.com/2013/06/using-promises-in-angularjs-views/

Upvotes: 0

Related Questions