Skip to content

Commit

Permalink
Basic sign-up, sign-in, sing-out functionality is working
Browse files Browse the repository at this point in the history
  • Loading branch information
wbillingsley committed Sep 4, 2013
1 parent 16e702a commit 59a97ce
Show file tree
Hide file tree
Showing 16 changed files with 351 additions and 13 deletions.
21 changes: 19 additions & 2 deletions app/assets/javascripts/components/SiteHeader.coffee
@@ -1,10 +1,27 @@
define(["modules/base"], (l) ->

Assessory.angularApp.directive("siteHeader", () ->

Assessory.controllers.SiteHeader = ['$scope', 'UserService', '$location', "$route", ($scope, UserService, $location, $route) ->

$scope.user = UserService.self()

$scope.logOut = () ->
UserService.logOut().then(
(res) ->
$location.path("/")
$route.reload()
(res) ->
$location.path("/")
$route.reload()
)
]

Assessory.angularApp.directive("siteHeader", ["UserService", (UserService) ->
{
controller: Assessory.controllers.SiteHeader
restrict: 'E'
templateUrl: "directive_siteHeader.html"
}
)
)]

)
19 changes: 19 additions & 0 deletions app/assets/javascripts/controllers/login/LogIn.coffee
@@ -0,0 +1,19 @@
#
# Controller for log-in form.
#
define(["./base"], (l) ->

Assessory.controllers.login.LogIn = ["$scope", "UserService", "$location", ($scope, UserService, $location) ->
$scope.user = { }

$scope.errors = []

$scope.submit = (user) ->
$scope.errors = [ ]
UserService.logIn(user).then(
(data) -> $location.path("/")
(fail) -> $scope.errors = [ fail.data?.error || "Unexpected error" ]
)
]

)
19 changes: 19 additions & 0 deletions app/assets/javascripts/controllers/login/SignUp.coffee
@@ -0,0 +1,19 @@
#
# Controller for sign-up form.
#
define(["./base"], (l) ->

Assessory.controllers.login.SignUp = ["$scope", "UserService", "$location", ($scope, UserService, $location) ->
$scope.user = { }

$scope.errors = []

$scope.submit = (user) ->
$scope.errors = [ ]
UserService.signUp(user).then(
(data) -> $location.path("/")
(fail) -> $scope.errors = [ fail.data?.error || "Unexpected error" ]
)
]

)
5 changes: 5 additions & 0 deletions app/assets/javascripts/controllers/login/base.coffee
@@ -0,0 +1,5 @@
define(["modules/base"], (l) ->

Assessory.controllers.login = {}

)
7 changes: 6 additions & 1 deletion app/assets/javascripts/main.js
Expand Up @@ -3,10 +3,15 @@
* (At the moment we're just including everything!)
*/
require([
"modules/base",
"modules/base",

"services/UserService",

"components/SiteHeader",

"controllers/login/LogIn",
"controllers/login/SignUp",

"modules/app"

], function(l) {
Expand Down
40 changes: 40 additions & 0 deletions app/assets/javascripts/services/UserService.coffee
@@ -0,0 +1,40 @@
define(["modules/base"], () ->

Assessory.services.UserService = Assessory.angularApp.service('UserService', ['$http', '$cacheFactory', ($http, $cacheFactory) ->

cache = $cacheFactory("userCache")

{

# Fetches a JSON representation of the user themselves
self: () ->
cache.get("self") || (
prom = $http.get("/self").then(
(successRes) -> successRes.data
)
cache.put("self", prom)
prom
)

signUp: (json) -> $http.post("/signUp", json).then((res) ->
user = res.data
cache.put("self", user)
user
)

logIn: (json) -> $http.post("/logIn", json).then((res) ->
user = res.data
cache.put("self", user)
user
)

logOut: () ->
cache.remove("self")
$http.post("/logOut").then(
(res) -> null
(res) -> null
)
}
])

)
9 changes: 3 additions & 6 deletions app/com/assessory/play/controllers/Application.scala
Expand Up @@ -6,12 +6,6 @@ import com.assessory.reactivemongo.UserDAO

object Application extends Controller {

/**
* DataAction should retrieve user information using the UserDAO
* from our database classes. (It includes methods for bySessionKey, etc)
*/
implicit val userProvider = UserDAO

/**
* The HTML and Javascript for the client side of the app.
* This also ensures the user's Play session cookie includes
Expand Down Expand Up @@ -42,6 +36,9 @@ object Application extends Controller {
*/
def partial(templ:String) = Action {
templ match {
case "main.html" => Ok(views.html.partials.main())
case "signUp.html" => Ok(views.html.partials.signUp())
case "logIn.html" => Ok(views.html.partials.logIn())

case _ => NotFound(s"No such partial template: $templ")
}
Expand Down
71 changes: 71 additions & 0 deletions app/com/assessory/play/controllers/UserController.scala
@@ -0,0 +1,71 @@
package com.assessory.play.controllers

import play.api.mvc.{Action, Controller}
import com.assessory.reactivemongo.UserDAO
import com.assessory.play.json.UserToJson
import play.api.mvc.AnyContent

import com.assessory.api._
import com.wbillingsley.handy._
import com.wbillingsley.handy.Ref._
import com.wbillingsley.handy.appbase.DataAction

object UserController extends Controller {

implicit val userToJson = UserToJson

// TODO: Fix this. It's an ugly hack around making the implicits work
val dataAction = new DataAction

def self = dataAction.one { implicit request =>
request.approval.who
}

/**
* Creates a user and logs them in
*/
def signUp = dataAction.one(parse.json) { implicit request =>
for (
email <- Ref((request.body \ "email").asOpt[String]) orIfNone UserError("Email must not be blank");
password <- Ref((request.body \ "password").asOpt[String]) orIfNone UserError("Password must not be blank");
user <- {
val u = UserDAO.unsaved
val set = u.copy(
pwlogin=u.pwlogin.copy(email=Some(email), pwhash=u.pwlogin.hash(password)),
activeSessions=Seq(ActiveSession(request.sessionKey))
)
UserDAO.saveNew(set)
}
) yield user
}

/**
* Logging a user in involves finding the user (if the password hash matches), and pushing the
* current session key as an active session
*/
def logIn = dataAction.one(parse.json) { implicit request =>
for (
email <- Ref((request.body \ "email").asOpt[String]) orIfNone UserError("Email must not be blank");
password <- Ref((request.body \ "password").asOpt[String]) orIfNone UserError("Password must not be blank");
user <- UserDAO.byEmailAndPassword(email, password);
updated <- UserDAO.pushSession(user.itself, ActiveSession(request.sessionKey))
) yield user
}

/**
* To log a user out, we just have to remove the current session from their active sessions
*/
def logOut = dataAction.one { implicit request =>
for (
u <- request.user;
user <- UserDAO.deleteSession(u.itself, ActiveSession(request.sessionKey))
) yield {
println("user was " + u.id)
println("as was " + request.sessionKey)
user
}
}



}
13 changes: 13 additions & 0 deletions app/com/assessory/play/controllers/package.scala
@@ -0,0 +1,13 @@
package com.assessory.play

import com.assessory.reactivemongo.UserDAO

package object controllers {

/**
* DataAction should retrieve user information using the UserDAO
* from our database classes. (It includes methods for bySessionKey, etc)
*/
implicit val userProvider = UserDAO

}
39 changes: 39 additions & 0 deletions app/com/assessory/play/json/UserToJson.scala
@@ -0,0 +1,39 @@
package com.assessory.play.json

import com.wbillingsley.handy.appbase.JsonConverter
import com.assessory.api.User
import com.wbillingsley.handy.{Approval, RefNone}
import com.wbillingsley.handy.Ref._
import play.api.libs.json.Json
import play.api.libs.json.JsValue

object UserToJson extends JsonConverter[User, User] {

def toJsonFor(u:User, a:Approval[User]) = {
if (u.itself.getId == a.who.getId) {
Json.obj(
"id" -> u.id,
"nickname" -> u.nickname,
"avatar" -> u.avatar
).itself
} else {
// We don't hand out user details to other users at the moment
Json.obj("id" -> u.id).itself
}
}

def toJson(u:User) = toJsonFor(u, Approval(RefNone))


def update(u:User, json:JsValue) = {
u.copy(
name = (json \ "name").asOpt[String],
nickname = (json \ "nickname").asOpt[String],
avatar = (json \ "avatar").asOpt[String]
)
}




}
13 changes: 10 additions & 3 deletions app/views/partials/components/directive_siteHeader.scala.html
Expand Up @@ -6,10 +6,17 @@
<ul class="nav navbar-nav">
</ul>

<ul class="nav navbar-nav pull-right">
<li><a href="">Sign in</a></li>
<li><a href="">Sign up</a></li>
<ul class="nav navbar-nav pull-right" ng-hide="user">
<li><a href="/logIn">Log in</a></li>
<li><a href="/signUp">Sign up</a></li>
</ul>

<ul class="nav navbar-nav pull-right" ng-show="user">
<li><a href="#" ng-click="logOut()">Log out</a></li>
<li><a href="/self">{{ user.nickname || 'Anonymous' }}</a></li>
<li>{{ user.error }}</li>
</ul>

</div>
</div>
</div>
38 changes: 38 additions & 0 deletions app/views/partials/logIn.scala.html
@@ -0,0 +1,38 @@
<site-header></site-header>

<div class="container">
<div class="row">

<div class="col-sm-6">
<h1>Log In</h1>
<div class="well" ng-controller="Assessory.controllers.login.LogIn">
<form name="signup" role="form" class="form">
<div class="form-group">
<label>Email address</label>
<input type="text" class="form-control" ng-model="user.email" />
</div>
<div class="form-group">
<label>Password</label>
<input type="password" class="form-control" ng-model="user.password" />
</div>
<div ng-repeat="error in errors">
<div class="alert alert-danger">{{ error }}</div>
</div>
<div class="form-group">
<button class="btn btn-primary" ng-click="submit(user)">Log In</button>
</div>
</form>
</div>
</div>

<div class="col-sm-6">
<h1>or</h1>

<div>
<p><a class="btn btn-default" href="/oauth/twiiter" target="_self"><i class="icon-twitter"></i> Sign in with <b>Twitter</b></a></p>
<p><a class="btn btn-default" href="/oauth/github" target="_self"><i class="icon-github"></i> Sign in with <b>GitHub</b></a></p>
</div>
</div>

</div>
</div>
22 changes: 22 additions & 0 deletions app/views/partials/main.scala.html
@@ -0,0 +1,22 @@
<site-header></site-header>

<div class="container" ng-show="user">

<h2>My courses</h2>


</div>


<div class="container" ng-hide="user">

<h2>Welcome</h2>

<p>
You'll need to log in.
</p>

</div>



0 comments on commit 59a97ce

Please sign in to comment.