           queue.next()
 
       ->
-        loginHelper.fetchSession {
+        fetchSession {
           clientId, username
         }, queue, callback, (session_) ->
           session = session_

        # # user is member, check validity
        # # user is not member, and trying to access with invitationToken
        # both should succeed
        loginHelper.fetchInvitationByCode invitationToken, queue, callback, (invitation_) ->
          invitation = invitation_

      ->
        loginHelper.fetchInvitationByData {
          user, groupName, invitationToken
        }, queue, callback, (invitation_) -> invitation = invitation_


      callback null, response


  fetchSession = (options, queue, callback, fetchData) ->

    { clientId, username } = options

    # fetch session of the current requester
    JSession.fetchSession clientId, (err, { session: fetchedSession }) ->
      return callback err  if err

      session = fetchedSession
      unless session
        console.error "login: session not found #{username}"
        return callback new KodingError 'Couldn\'t restore your session!'

      fetchData session

      queue.next()


  validateLoginCredentials = (options, queue, callback, fetchData) ->

    { username, password, tfcode } = options

    # check credential validity
    JUser.one { username }, (err, user) ->
      return logAndReturnLoginError username, err.message, callback if err
      fetchData user

      # if user not found it means we dont know about given username
      unless user?
        return logAndReturnLoginError username, 'Unknown user name', callback

      # if password is autogenerated return error
      if user.getAt('passwordStatus') is 'needs reset'
        return logAndReturnLoginError username, \
          'You should reset your password in order to continue!', callback

      # check if provided password is correct
      unless user.checkPassword password
        return logAndReturnLoginError username, 'Access denied!', callback

      # check if user is using 2factor auth and provided key is ok
      if !!(user.getAt 'twofactorkey')

        unless tfcode
          return callback new KodingError \
            'TwoFactor auth Enabled', 'VERIFICATION_CODE_NEEDED'

        unless user.check2FactorAuth tfcode
          return logAndReturnLoginError username, 'Access denied!', callback

      # if everything is fine, just continue
      queue.next()


  fetchInvitationByCode = (invitationToken, queue, callback, fetchData) ->

    # if we dont have an invitation code, do not continue
    return queue.next()  unless invitationToken

    JInvitation = require '../invitation'
    JInvitation.byCode invitationToken, (err, invitation) ->
      return callback err  if err
      return callback new KodingError 'invitation is not valid'  unless invitation
      fetchData invitation
      queue.next()


  fetchInvitationByData = (options, queue, callback, fetchData) ->

    { user, groupName, invitationToken } = options
    # check if user has pending invitation
    return queue.next()  if invitationToken

    selector = { email: user.email, groupName }
    JInvitation = require '../invitation'
    JInvitation.one selector, {}, (err, invitation) ->
      fetchData invitation  if invitation
      queue.next()


  @login = (clientId, credentials, callback) ->
