1

I am trying to make an application using web framework Flask as Back-end and AngularJS as Front-end, in Flask there is an extension called flask_login that has a function current_user where user object get saved, by that i can access the user from anywhere in my templates.

The main problem that i am facing which i don't know how to solve it is that , i need to save the user object in a $scope so i can get any information about the user in my templates after user get logged in, so for example:

<div class="books">
    <div class="profile" id="{{ current_user.public_id }}">
        <img src="http://www.placehold.it/200x200" class="img-responsive img-circle">
        <h4>{{ current_user.username }}</h4>
        <p>{{ current_user.email }}</p>
    </div>
</div>

here i am using simple jinja2 code to fetch the user information, i need that to become something like:

<div class="books" ng-controller="myApp.user.controller">
    <div class="profile" id="<% $scope.current_user.public_id %>">
        <img src="http://www.placehold.it/200x200" class="img-responsive img-circle">
        <h4><% $scope.current_user.username %></h4>
        <p><% $scope.current_user.email %></p>
    </div>
</div>

Here is view.py where login process get handled:

@app.route('/api/login', methods=['POST'])
def login():
    json_data = request.json
    user = User.query.filter_by(email=json_data['email']).first()
    if user and bcrypt.check_password_hash(
            user.password, json_data['password']):
        session['logged_in'] = True
        session['logged_email'] = user.email
        status = True
        g.user = user.email
    else:
        status = False
    return jsonify({'result': status})


@app.route('/api/status')
def status():
    if session.get('logged_in'):
        if session['logged_in']:
            return jsonify({'status': True, 'user':g.user.email})
    else:
        return jsonify({'status': False})

here is my angular code:

myApp.run(function ($rootScope, $location, $route, AuthService) {
  $rootScope.$on('$routeChangeStart',
    function (event, next, current) {
      AuthService.getUserStatus()
      .then(function(){
        if (next.access.restricted && !AuthService.isLoggedIn()){
          $location.path('/login');
          $route.reload();
        }
        console.log(AuthService.getUserStatus());
      });
  });
});

angular.module('myApp').factory('AuthService',
  ['$q', '$timeout', '$http',
  function ($q, $timeout, $http) {

    // create user variable
    var user = null;
    var email = null;

    // return available functions for use in controllers
    return ({
      isLoggedIn: isLoggedIn,
      login: login,
      logout: logout,
      register: register,
      getUserStatus: getUserStatus
    });

    function isLoggedIn() {
      if(user) {
        return true;
      } else {
        return false;
      }
    }

    function login(email, password) {

      // create a new instance of deferred
      var deferred = $q.defer();

      // send a post request to the server
      $http.post('/api/login', {email: email, password: password})
        // handle success
        .success(function (data, status) {
          if(status === 200 && data.result){
            user = true;

            deferred.resolve();
          } else {
            user = false;
            deferred.reject();
          }
        })
        // handle error
        .error(function (data) {
          user = false;
          deferred.reject();
        });
      // return promise object
      return deferred.promise;

    }

    function getUserStatus() {
      return $http.get('/api/status')
      // handle success
      .success(function (data) {
        if(data.status){
          user = true;
          email = data.user;
        } else {
          user = false;
        }
      })
      // handle error
      .error(function (data) {
        user = false;
      });
    }

}]);

If you noticed here console.log(AuthService.getUserStatus()); inside console i can see the data contains the user email address.

Please any suggestions how can i make that work ??

swordfish
  • 959
  • 16
  • 39
  • 1
    Read about [Deferred Antipattern](https://stackoverflow.com/questions/30750207/is-this-a-deferred-antipattern) – Alon Eitan Feb 18 '18 at 15:30

1 Answers1

0

$q and angular promises solved my problem. I used the $q service to set up a promise, which i will access in my user controller:

function currentUser(){
  var deferred = $q.defer();
  $http.get('/api/current_user')
  .success(function(data){
    if (data.status){
      user = true;
      deferred.resolve(data);
      // console.log(data.user);
    } else {
      user = false;
      deferred.reject();
    }
  })
  .error(function(data){
    user = false;
    deferred.reject(data);
  });
  return deferred.promise;
}

I also utilized the $http to send an AJAX request to my route /api/current_user endpoint that i already set up in my application back-end.

Based on the returned response, i either accept or reject the object and set the value of user to true or false.

Now that i have a promise, i need to update the service interaction inside my controller, because i can't access the data from Object.$$state.value , so :

angular.module('myApp').controller('userController',
['$scope', '$location', 'AuthService',
function ($scope, $location, AuthService) {
    AuthService.currentUser().then(function(data) {
    $scope.user = data.user;
    });
}]);

Now i can get the data from inside my templates:

<div class="books" ng-controller="userController">
    <div class="profile" id="<% user.public_id %>">
        <img src="<% user.avatar %>" class="img-responsive img-circle">
        <h4><% user.email %></h4>
        <p><% user.joined  | amUtc | amLocal | amTimezone:'Europe/Moscow' | amDateFormat:'YYYY.MM.DD HH:mm:ss' %></p>
    </div>
</div>

I would like to thank @Alon Eitan for helping solve this issue , appreciated :).

swordfish
  • 959
  • 16
  • 39
  • pretty sure that this is the pattern that @alonEitan was trying to discourage by pointing to that article. Also, the use of `.success` was deprecated, which seems to indicate that you are running an older AngularJs release. This may work, but it's probably not the most efficient way to solve the problem.... – Claies Feb 18 '18 at 18:16
  • @Claies, you are right, in latest version of AngularJS the success method doesn't work, i need to use the `successCallback` and `errorCallback` !! – swordfish Feb 18 '18 at 19:58
  • @swordfish, you can mark this answer as correct if it solved your problem, even if it was provided by yourself. – lealceldeiro Feb 19 '18 at 14:32