From 089f865e3da532f3f56549aa887a4bb0528f2857 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20H=C3=BCbsch?= Date: Tue, 9 Jun 2015 10:12:30 +0200 Subject: [PATCH 1/4] Add play-scalate, adjust some views. --- app/controllers/Application.scala | 4 +++- app/views/index.jade | 1 + app/views/index.scala.html | 7 ------- app/views/loginForm.jade | 1 + app/views/main.jade | 8 ++++++++ app/views/main.scala.html | 15 --------------- build.sbt | 10 +++++++++- 7 files changed, 22 insertions(+), 24 deletions(-) create mode 100644 app/views/index.jade delete mode 100644 app/views/index.scala.html create mode 100644 app/views/loginForm.jade create mode 100644 app/views/main.jade delete mode 100644 app/views/main.scala.html diff --git a/app/controllers/Application.scala b/app/controllers/Application.scala index 4ca8e00..359debc 100644 --- a/app/controllers/Application.scala +++ b/app/controllers/Application.scala @@ -2,6 +2,8 @@ package controllers import play.api._ import play.api.mvc._ +import com.github.tototoshi.play2.scalate._ + import repositories._ import models._ @@ -9,7 +11,7 @@ class Application extends Controller { def index = Action { UserRepository.insert(User("test")) - Ok(views.html.index("Your new application is ready.")) + Ok(Scalate.render("index.jade")) } } diff --git a/app/views/index.jade b/app/views/index.jade new file mode 100644 index 0000000..ad323ea --- /dev/null +++ b/app/views/index.jade @@ -0,0 +1 @@ +- render("main.jade", Map("title" -> "titel", "content" -> "loginForm.jade")) diff --git a/app/views/index.scala.html b/app/views/index.scala.html deleted file mode 100644 index d6a6b22..0000000 --- a/app/views/index.scala.html +++ /dev/null @@ -1,7 +0,0 @@ -@(message: String) - -@main("Welcome to Play") { - - @play20.welcome(message) - -} diff --git a/app/views/loginForm.jade b/app/views/loginForm.jade new file mode 100644 index 0000000..b9362ad --- /dev/null +++ b/app/views/loginForm.jade @@ -0,0 +1 @@ +p Test diff --git a/app/views/main.jade b/app/views/main.jade new file mode 100644 index 0000000..5f43ef9 --- /dev/null +++ b/app/views/main.jade @@ -0,0 +1,8 @@ +-@val title: String +-@val content: String + +html(lang="en") + head + title= title + body + - render(content) diff --git a/app/views/main.scala.html b/app/views/main.scala.html deleted file mode 100644 index aff0eff..0000000 --- a/app/views/main.scala.html +++ /dev/null @@ -1,15 +0,0 @@ -@(title: String)(content: Html) - - - - - - @title - - - - - - @content - - diff --git a/build.sbt b/build.sbt index 6746986..40f986a 100644 --- a/build.sbt +++ b/build.sbt @@ -11,11 +11,19 @@ libraryDependencies ++= Seq( cache, ws, specs2 % Test, - "org.mongodb" %% "casbah" % "2.8.1" + "org.mongodb" %% "casbah" % "2.8.1", + "com.github.tototoshi" %% "play-scalate" % "0.1.0-SNAPSHOT", + "org.scalatra.scalate" %% "scalate-core" % "1.7.0", + "org.scala-lang" % "scala-compiler" % scalaVersion.value ) resolvers += "scalaz-bintray" at "http://dl.bintray.com/scalaz/releases" +resolvers += "sonatype snapshots" at "https://oss.sonatype.org/content/repositories/snapshots/" + + // Play provides two styles of routers, one expects its actions to be injected, the // other, legacy style, accesses its actions statically. routesGenerator := InjectedRoutesGenerator + +unmanagedResourceDirectories in Compile += baseDirectory.value / "app" / "views" From deb69c4ad4cf9dbe9877e7ac99f1bad61e95a955 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20H=C3=BCbsch?= Date: Tue, 9 Jun 2015 11:46:33 +0200 Subject: [PATCH 2/4] Add user register and login form jade templates. --- app/controllers/Application.scala | 3 +-- app/controllers/Users.scala | 21 +++++++++++++++++++++ app/views/index.jade | 3 ++- app/views/loginForm.jade | 1 - app/views/user/loginForm.jade | 10 ++++++++++ app/views/user/register.jade | 9 +++++++++ app/views/user/successfulRegistered.jade | 6 ++++++ conf/routes | 3 +++ 8 files changed, 52 insertions(+), 4 deletions(-) create mode 100644 app/controllers/Users.scala delete mode 100644 app/views/loginForm.jade create mode 100644 app/views/user/loginForm.jade create mode 100644 app/views/user/register.jade create mode 100644 app/views/user/successfulRegistered.jade diff --git a/app/controllers/Application.scala b/app/controllers/Application.scala index 359debc..8eeda41 100644 --- a/app/controllers/Application.scala +++ b/app/controllers/Application.scala @@ -10,8 +10,7 @@ import models._ class Application extends Controller { def index = Action { - UserRepository.insert(User("test")) - Ok(Scalate.render("index.jade")) + Ok(Scalate.render("index.jade", Map("title" -> "Index"))) } } diff --git a/app/controllers/Users.scala b/app/controllers/Users.scala new file mode 100644 index 0000000..9baceb1 --- /dev/null +++ b/app/controllers/Users.scala @@ -0,0 +1,21 @@ +package controllers + +import play.api.mvc._ +import com.github.tototoshi.play2.scalate._ + +class Users extends Controller { + def newUser = Action(parse.urlFormEncoded) { implicit request => + val email = request.body.get("email").get.head + val password = request.body.get("password").get.head + + Ok(Scalate.render("user/successfulRegistered.jade", Map("email" -> email, "password" -> password))) + } + + def register = Action { + Ok(Scalate.render("user/register.jade")) + } + + def login = Action { + Ok("TODO") + } +} diff --git a/app/views/index.jade b/app/views/index.jade index ad323ea..45c9bab 100644 --- a/app/views/index.jade +++ b/app/views/index.jade @@ -1 +1,2 @@ -- render("main.jade", Map("title" -> "titel", "content" -> "loginForm.jade")) +-@val title: String +- render("main.jade", Map("title" -> title, "content" -> "user/loginForm.jade")) diff --git a/app/views/loginForm.jade b/app/views/loginForm.jade deleted file mode 100644 index b9362ad..0000000 --- a/app/views/loginForm.jade +++ /dev/null @@ -1 +0,0 @@ -p Test diff --git a/app/views/user/loginForm.jade b/app/views/user/loginForm.jade new file mode 100644 index 0000000..1bf0af6 --- /dev/null +++ b/app/views/user/loginForm.jade @@ -0,0 +1,10 @@ +form(action='/user/login' method='POST' enctype='application/x-www-form-urlencoded') + label Email + input(type='email' name='email' tabindex='1' required='required') + + label Password + input(type='password' name='password' tabindex='2' required='required') + + input(type='submit' value='Login') + +a(href='/user/register') Register diff --git a/app/views/user/register.jade b/app/views/user/register.jade new file mode 100644 index 0000000..ca10ebe --- /dev/null +++ b/app/views/user/register.jade @@ -0,0 +1,9 @@ +form(action='/user/new' method='POST' enctype='application/x-www-form-urlencoded') + label Email + input(type='email' name='email' tabindex='1' required='required') + + label Password + input(type='password' name='password' tabindex='2' required='required') + + input(type='submit' value='Register') + diff --git a/app/views/user/successfulRegistered.jade b/app/views/user/successfulRegistered.jade new file mode 100644 index 0000000..8ab9bd1 --- /dev/null +++ b/app/views/user/successfulRegistered.jade @@ -0,0 +1,6 @@ +-@val email: String +-@val password: String + +Registriert mit +p= email +p= password diff --git a/conf/routes b/conf/routes index e71a0bd..9ab6f5d 100644 --- a/conf/routes +++ b/conf/routes @@ -4,6 +4,9 @@ # Home page GET / controllers.Application.index +GET /user/register controllers.Users.register +POST /user/login controllers.Users.login +POST /user/new controllers.Users.newUser # Map static resources from the /public folder to the /assets URL path GET /assets/*file controllers.Assets.versioned(path="/public", file: Asset) From 236241dcda28c95cffa5d9fb572467844d88b467 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20H=C3=BCbsch?= Date: Tue, 9 Jun 2015 15:02:42 +0200 Subject: [PATCH 3/4] Add user authorization. --- app/controllers/Users.scala | 42 +++++++++++++++++++++++++-- app/models/User.scala | 6 ++-- app/repositories/UserRepository.scala | 14 +++++++++ app/views/user/afterLogin.jade | 2 ++ build.sbt | 4 ++- conf/routes | 2 ++ 6 files changed, 63 insertions(+), 7 deletions(-) create mode 100644 app/views/user/afterLogin.jade diff --git a/app/controllers/Users.scala b/app/controllers/Users.scala index 9baceb1..153262b 100644 --- a/app/controllers/Users.scala +++ b/app/controllers/Users.scala @@ -2,12 +2,17 @@ package controllers import play.api.mvc._ import com.github.tototoshi.play2.scalate._ +import org.mindrot.jbcrypt.BCrypt +import repositories.UserRepository +import models.User class Users extends Controller { def newUser = Action(parse.urlFormEncoded) { implicit request => + val salt = BCrypt.gensalt() val email = request.body.get("email").get.head - val password = request.body.get("password").get.head + val password = BCrypt.hashpw(request.body.get("password").get.head, salt) + UserRepository.insert(User(email, password, salt)) Ok(Scalate.render("user/successfulRegistered.jade", Map("email" -> email, "password" -> password))) } @@ -15,7 +20,38 @@ class Users extends Controller { Ok(Scalate.render("user/register.jade")) } - def login = Action { - Ok("TODO") + def login = Action(parse.urlFormEncoded) { implicit request => + val email = request.body.get("email").get.head + val password = request.body.get("password").get.head + + val user = UserRepository.findByEmail(email) + + if(user.isDefined) { + val salt = user.get.salt + val passwordCorrect = BCrypt.checkpw(BCrypt.hashpw(password, salt), BCrypt.hashpw(user.get.password, salt)) + + if(passwordCorrect) { + val sessionId = java.util.UUID.randomUUID.toString + Redirect("/user/secret").withSession("sessionId" -> sessionId) + } else { + Redirect("/") + } + } else { + Ok("User existiert nicht") + } + } + + def logout = Action { + Redirect("/").withNewSession + } + + def afterLogin = Action { request => + val sessionId = request.session.get("sessionId") + + if(sessionId.isDefined) { + Ok(Scalate.render("user/afterLogin.jade")) + } else { + Unauthorized("Not allowed") + } } } diff --git a/app/models/User.scala b/app/models/User.scala index 6279e97..65dba53 100644 --- a/app/models/User.scala +++ b/app/models/User.scala @@ -1,6 +1,6 @@ package models -case class User(name: String) +case class User(email: String, password: String, salt: String) object User { def serialize(user: User) : List[(String, Any)] = { @@ -10,7 +10,7 @@ object User { attributes.zip(values).toList } - def getValues(user: User) : Seq[Any] = { - User.unapply(user).productIterator.toSeq + def getValues(user: User) : List[Any] = { + user.productIterator.toList } } diff --git a/app/repositories/UserRepository.scala b/app/repositories/UserRepository.scala index 7398501..909ef88 100644 --- a/app/repositories/UserRepository.scala +++ b/app/repositories/UserRepository.scala @@ -13,4 +13,18 @@ object UserRepository { collection.insert(test) } + + def findByEmail(email: String) : Option[User] = { + val query = MongoDBObject("email" -> email) + val doc = collection.findOne(query) + + if(doc.isDefined) { + val password = doc.get("password").toString() + val salt = doc.get("salt").toString() + + Some(User(email, password, salt)) + } else { + None + } + } } diff --git a/app/views/user/afterLogin.jade b/app/views/user/afterLogin.jade new file mode 100644 index 0000000..d49d612 --- /dev/null +++ b/app/views/user/afterLogin.jade @@ -0,0 +1,2 @@ +p geheim und so +a(href='/user/logout') Logout diff --git a/build.sbt b/build.sbt index 40f986a..845b941 100644 --- a/build.sbt +++ b/build.sbt @@ -14,11 +14,13 @@ libraryDependencies ++= Seq( "org.mongodb" %% "casbah" % "2.8.1", "com.github.tototoshi" %% "play-scalate" % "0.1.0-SNAPSHOT", "org.scalatra.scalate" %% "scalate-core" % "1.7.0", - "org.scala-lang" % "scala-compiler" % scalaVersion.value + "org.scala-lang" % "scala-compiler" % scalaVersion.value, + "org.mindrot" % "jbcrypt" % "0.3m" ) resolvers += "scalaz-bintray" at "http://dl.bintray.com/scalaz/releases" resolvers += "sonatype snapshots" at "https://oss.sonatype.org/content/repositories/snapshots/" +resolvers += "jbcrypt repo" at "http://mvnrepository.com/" diff --git a/conf/routes b/conf/routes index 9ab6f5d..190b5a2 100644 --- a/conf/routes +++ b/conf/routes @@ -7,6 +7,8 @@ GET / controllers.Application.index GET /user/register controllers.Users.register POST /user/login controllers.Users.login POST /user/new controllers.Users.newUser +GET /user/secret controllers.Users.afterLogin +GET /user/logout controllers.Users.logout # Map static resources from the /public folder to the /assets URL path GET /assets/*file controllers.Assets.versioned(path="/public", file: Asset) From b9964465161e939030d51b374ad4ea1ad5d73eab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20H=C3=BCbsch?= Date: Tue, 9 Jun 2015 16:06:12 +0200 Subject: [PATCH 4/4] Add bootstrap styles. --- app/controllers/Users.scala | 8 ++++---- app/views/main.jade | 7 +++++++ app/views/user/afterLogin.jade | 5 +++-- app/views/user/loginForm.jade | 21 ++++++++++++--------- app/views/user/register.jade | 20 ++++++++++++-------- app/views/user/successfulRegistered.jade | 8 ++------ 6 files changed, 40 insertions(+), 29 deletions(-) diff --git a/app/controllers/Users.scala b/app/controllers/Users.scala index 153262b..be5c4bf 100644 --- a/app/controllers/Users.scala +++ b/app/controllers/Users.scala @@ -13,11 +13,11 @@ class Users extends Controller { val password = BCrypt.hashpw(request.body.get("password").get.head, salt) UserRepository.insert(User(email, password, salt)) - Ok(Scalate.render("user/successfulRegistered.jade", Map("email" -> email, "password" -> password))) + Ok(Scalate.render("main.jade", Map("title" -> "Register thanks", "content" -> "user/successfulRegistered.jade"))) } def register = Action { - Ok(Scalate.render("user/register.jade")) + Ok(Scalate.render("main.jade", Map("title" -> "Register", "content" -> "user/register.jade"))) } def login = Action(parse.urlFormEncoded) { implicit request => @@ -41,7 +41,7 @@ class Users extends Controller { } } - def logout = Action { + def logout = Action { Redirect("/").withNewSession } @@ -49,7 +49,7 @@ class Users extends Controller { val sessionId = request.session.get("sessionId") if(sessionId.isDefined) { - Ok(Scalate.render("user/afterLogin.jade")) + Ok(Scalate.render("main.jade", Map("title" -> "User Area", "content" -> "user/afterLogin.jade"))) } else { Unauthorized("Not allowed") } diff --git a/app/views/main.jade b/app/views/main.jade index 5f43ef9..434404b 100644 --- a/app/views/main.jade +++ b/app/views/main.jade @@ -4,5 +4,12 @@ html(lang="en") head title= title + link(rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.4/css/bootstrap.min.css") body + nav(class='navbar navbar-inverse') + ul(class='nav navbar-nav') + li + a(href='/') Home + // TODO show logout if user logged in + - render(content) diff --git a/app/views/user/afterLogin.jade b/app/views/user/afterLogin.jade index d49d612..804b865 100644 --- a/app/views/user/afterLogin.jade +++ b/app/views/user/afterLogin.jade @@ -1,2 +1,3 @@ -p geheim und so -a(href='/user/logout') Logout +.container(style='padding-top: 10px; width: 400px;') + | geheim und so + a(href='/user/logout') Logout diff --git a/app/views/user/loginForm.jade b/app/views/user/loginForm.jade index 1bf0af6..a81e7bf 100644 --- a/app/views/user/loginForm.jade +++ b/app/views/user/loginForm.jade @@ -1,10 +1,13 @@ -form(action='/user/login' method='POST' enctype='application/x-www-form-urlencoded') - label Email - input(type='email' name='email' tabindex='1' required='required') +.container(style='padding-top: 50px; width: 400px;') + form(action='/user/login' method='POST' enctype='application/x-www-form-urlencoded') + .form-group + label Email + input(type='email' name='email' tabindex='1' required='required' class='form-control') + + .form-group + label Password + input(type='password' name='password' tabindex='2' required='required' class='form-control') - label Password - input(type='password' name='password' tabindex='2' required='required') - - input(type='submit' value='Login') - -a(href='/user/register') Register + .form-group + input(type='submit' value='Login' class='btn btn-success btn-sm') + a(href='/user/register' class='btn btn-default btn-sm') Register diff --git a/app/views/user/register.jade b/app/views/user/register.jade index ca10ebe..4715dae 100644 --- a/app/views/user/register.jade +++ b/app/views/user/register.jade @@ -1,9 +1,13 @@ -form(action='/user/new' method='POST' enctype='application/x-www-form-urlencoded') - label Email - input(type='email' name='email' tabindex='1' required='required') +.container(style='padding-top: 50px; width: 400px;') + form(action='/user/new' method='POST' enctype='application/x-www-form-urlencoded') + .form-group + label Email + input(type='email' name='email' tabindex='1' required='required' class='form-control') + + .form-group + label Password + input(type='password' name='password' tabindex='2' required='required' class='form-control') - label Password - input(type='password' name='password' tabindex='2' required='required') - - input(type='submit' value='Register') - + .form-group + input(type='submit' value='Register' class='btn btn-default btn-sm') + diff --git a/app/views/user/successfulRegistered.jade b/app/views/user/successfulRegistered.jade index 8ab9bd1..ca67627 100644 --- a/app/views/user/successfulRegistered.jade +++ b/app/views/user/successfulRegistered.jade @@ -1,6 +1,2 @@ --@val email: String --@val password: String - -Registriert mit -p= email -p= password +.container(style='padding-top: 10px; width: 400px;') + | Vielen Dank für Ihre Registrierung.