Complete the login feature

This commit is contained in:
Andrew Miner
2015-04-01 13:31:07 -07:00
parent 764f835698
commit ad897b80c0
10 changed files with 253 additions and 60 deletions
+15 -2
View File
@@ -14,14 +14,12 @@ module.exports = class BaseController extends Backbone.View
constructor: (options={})->
@tryRefresh = _.debounce @_tryRefresh, 100
Object.defineProperty this, 'model', get:@getModel, set:@setModel
@_model = null
@_rendered = false
@_parent = options.parent
@_children = []
Object.defineProperty this, 'rendered', get:-> return @_rendered
@_loadTemplate options.templateName
super options
@@ -122,6 +120,21 @@ module.exports = class BaseController extends Backbone.View
@_model = newModel
@tryRefresh()
isRendered: ->
return @_rendered
getUser: ->
return @_user
setUser: (user)->
@_user = user
@tryRefresh()
Object.defineProperties @prototype,
model: {get:@prototype.getModel, set:@prototype.setModel}
rendered: {get:@prototype.isRendered }
user: {get:@prototype.user, set:@prototype.setUser}
# Backbone.View Overrides ######################################################################
events: ->
@@ -7,17 +7,36 @@ All rights reserved.
BaseController = require './base_controller'
{Duration} = require '../constants'
{Event} = require '../constants'
{ProductionEnvs} = require '../constants'
{Url} = require '../constants'
########################################################################################################################
module.exports = class HeaderController extends BaseController
constructor: (options={})->
if not options.client? then throw new Error 'options.client is required'
super options
@client = options.client
@_user = options.user
# Event Methods ################################################################################
onLoginLinkClicked: (event)->
event.preventDefault()
if @user?
@client.logout()
.then ->
router.user = null
.catch (error)->
logger.error -> "Failed to log out: #{error}"
.done()
else
router.navigate Url.login(), trigger:true
onLogoClicked: ->
router.navigate '/', trigger:true
return false
@@ -28,6 +47,18 @@ module.exports = class HeaderController extends BaseController
router.navigate $(event.currentTarget).attr('href'), trigger:true
return false
# Property Methods #############################################################################
getUser: ->
return @_user
setUser: (user)->
@_user = user
@tryRefresh()
Object.defineProperties @prototype,
user: {get:@prototype.getUser, set:@prototype.setUser}
# BaseController Overrides #####################################################################
render: ->
@@ -36,6 +67,8 @@ module.exports = class HeaderController extends BaseController
@_rendered = true
@$navLinks = ($(el) for el in @$('.navBar a'))
@$loginName = @$('.login .name')
@$loginLink = @$('.login a')
zIndex = @$navLinks.length + 100
for $navLink in @$navLinks
@@ -46,6 +79,13 @@ module.exports = class HeaderController extends BaseController
$('body').append "<script async src=\"#{addThisUrl}\"></script>"
refresh: ->
if @user?
@$loginName.html "Hello #{router.user.login}!"
@$loginLink.html "Logout"
else
@$loginName.html ''
@$loginLink.html 'Login'
for $navLink in @$navLinks
linkPage = $navLink.data('page')
if @model is linkPage
@@ -64,4 +104,4 @@ module.exports = class HeaderController extends BaseController
return _.extend super,
'click a.logo': 'onLogoClicked'
'click .navBar a': 'onNavItemClicked'
'click .login a': 'routeLinkClick'
'click .login a': 'onLoginLinkClicked'
@@ -5,24 +5,37 @@ Copyright (c) 2015 by Redwood Labs
All rights reserved.
###
PageController = require './page_controller'
{Login} = require '../constants'
PageController = require './page_controller'
User = require '../models/user'
{CraftingGuideClient} = require 'crafting-guide-common'
{Event} = require '../constants'
{Login} = require '../constants'
{Url} = require '../constants'
########################################################################################################################
module.exports = class LoginPageController extends PageController
@ServerStatus:
Up: 'up'
Down: 'down'
@State: State =
ReadyToLogin: 'ready-to-login'
ServerDown: 'server-down'
InvalidCallback: 'invalid-callback'
FetchingToken: 'fetching-token'
LoggedIn: 'logged-in'
constructor: (options={})->
options.templateName = 'login_page'
super options
@client = options.client
@params = options.params
@storage = options.storage
@_accessTokenLookupFailed = false
@client.on Event.change + ':status', => @tryRefresh()
super options
# Event Methods ################################################################################
onExpandReadMore: (event)->
@@ -42,13 +55,6 @@ module.exports = class LoginPageController extends PageController
setLoginSecurityToken: (value)->
@storage.store 'loginSecurityToken', value
getServerStatus: ->
return @_serverStatus
setServerStatus: (serverStatus)->
@_serverStatus = serverStatus
@tryRefresh()
Object.defineProperties @prototype,
loginSecurityToken: {get:@prototype.getLoginSecurityToken, set:@prototype.setLoginSecurityToken}
serverStatus: {get:@prototype.getServerStatus, set:@prototype.setServerStatus}
@@ -60,24 +66,28 @@ module.exports = class LoginPageController extends PageController
# BaseController Methods #######################################################################
onWillRender: ->
@_validateServerStatus()
super
onDidRender: ->
@$readMoreLink = @$('a.read-more')
@$readMoreContent = @$('.read-more-content')
@$serviceUpContent = @$('.service-up')
@$serviceDownContent = @$('.service-down')
@$readMoreLink = @$('a.read-more')
@$readMoreContent = @$('.read-more-content')
if (not @user?) and (@params?.state is @loginSecurityToken)
@client.completeGitHubLogin code:@params.code
.then (response)->
attributes = response.json.data.user
if attributes?
router.user = new User attributes
router.navigate Url.root(), trigger:true
.catch (error)->
logger.error "Failed to get access token: #{error}"
@_accessTokenLookupFailed = true
@refresh()
.done()
super
refresh: ->
if @serverStatus is LoginPageController.ServerStatus.Down
@$serviceUpContent.addClass 'hidden'
@$serviceDownContent.removeClass 'hidden'
else
@$serviceUpContent.removeClass 'hidden'
@$serviceDownContent.addClass 'hidden'
state = @_computeState()
@$('.two-thirds-content').addClass 'hidden'
@$(".two-thirds-content.#{state}").removeClass 'hidden'
super
@@ -90,21 +100,31 @@ module.exports = class LoginPageController extends PageController
# Private Methods ##############################################################################
_computeState: ->
if @user? then return State.LoggedIn
if @client.status is CraftingGuideClient.Status.Down then return State.ServerDown
if @_accessTokenLookupFailed then return State.InvalidCallback
if @params?.state?
if @params.state is @loginSecurityToken
return State.FetchingToken
else
return State.InvalidCallback
return State.ReadyToLogin
_compeleteLogin: (code)->
@client.completeGitHubLogin code:code
.then (response)=>
router.user = new User response.json.user
.catch (error)->
@_accessTokenLookupFailed = true
@refresh
.done()
_redirectToGitHub: ->
@loginSecurityToken = _.uuid()
baseUrl = Login.authorizeUrl state:@loginSecurityToken
window.location.href = baseUrl
_validateServerStatus: ->
message = _.uuid()
logger.info "Checking Crafting Guide Server at #{@client.baseUrl}..."
@client.ping message:message
.then (response)=>
if response.json.message is message
@serverStatus = LoginPageController.ServerStatus.Up
logger.info "Crafting Guide Server is up"
else
throw new Error "Invalid server ping response: #{response.json.message} isnt #{message}"
.catch (error)=>
@serverStatus = LoginPageController.ServerStatus.Down
logger.error "Crafting Guide server is down: #{error}"
clientId = Login.clientIds[global.env]
window.location.href = Login.authorizeUrl clientId:clientId, state:@loginSecurityToken