Permalink
Browse files

Initial commit

  • Loading branch information...
0 parents commit 0c4e179ec760f20a4073c79621362f56eb15ac36 @sgodbillon sgodbillon committed Jul 30, 2012
@@ -0,0 +1,7 @@
+logs
+project/project
+project/target
+target
+tmp
+.history
+dist
@@ -0,0 +1,91 @@
+package controllers
+
+import play.api._
+import play.api.libs.iteratee._
+import play.api.mvc._
+import play.api.Play.current
+import play.api.data.Form
+import play.modules.mongodb.MongoAsyncPlugin
+import org.asyncmongo.bson._
+import org.asyncmongo.api._
+import org.asyncmongo.handlers.DefaultBSONHandlers._
+import models._
+import play.api.libs.concurrent.Promise
+
+object Application extends Controller with MongoController {
+ implicit val connection = MongoAsyncPlugin.connection
+ val db = MongoAsyncPlugin.db
+
+ def index = Action { request =>
+ val sort = request.queryString.get("sort").flatMap { sort =>
+ if(!sort.isEmpty) {
+ Some(Bson(sort.head -> BSONInteger(1)))
+ } else None
+ }
+ MongoPromiseResult {
+ implicit val userReader = User.UserBSONReader
+ val query = sort.map(sort => Bson("$orderby" -> sort.toDocument, "$query" -> Bson().toDocument)).getOrElse(Bson())
+ println(query)
+ val cursor = db("users").find(query)
+ val list = collect[List, User](cursor)
+ list.map { users =>
+ Ok(views.html.index(users))
+ }
+ }
+ }
+
+
+ def createForm = userForm(None)
+
+ def editForm(id: String) = userForm(Some(id))
+
+ def userForm(maybeId: Option[String]) = Action {
+ implicit val userReader = User.UserBSONReader
+ maybeId.map { id =>
+ MongoPromiseResult {
+ val objectId = new BSONObjectID(id)
+ val futureCursor = db("users").find(Bson("_id" -> objectId))
+ val futureMaybeUser = collect[Set, User](futureCursor).map(_.headOption)
+ futureMaybeUser.map { maybeUser =>
+ maybeUser.map { user =>
+ Ok(views.html.editUser(false, User.form.fill(user)))
+ }.getOrElse(NotFound)
+ }
+ }
+ }.getOrElse(Ok(views.html.editUser(true, User.form)))
+ }
+
+ def createUser = Action { implicit request =>
+ User.form.bindFromRequest.fold(
+ errors => Ok(views.html.editUser(false, errors)),
+ user => MongoFutureResult {
+ db("users").insert(user)(User.UserBSONWriter).map { _ =>
+ Redirect(routes.Application.index())
+ }
+ }
+ )
+ }
+
+ def editUser(id: String) = Action { implicit request =>
+ implicit val userWriter = User.UserBSONWriter
+ User.form.bindFromRequest.fold(
+ errors => Ok(views.html.editUser(true, errors)),
+ user => MongoFutureResult {
+ val objectId = new BSONObjectID(id)
+ db("users").update(Bson("_id" -> objectId), user.copy(id = Some(objectId))).map { _ =>
+ Redirect(routes.Application.index())
+ }
+ }
+ )
+ }
+
+ import play.api.data._
+ import play.api.data.Forms._
+ import play.api.data.validation.Constraints._
+
+ val searchForm = Form(
+ mapping(
+ "name" -> text
+ )(s => s)(s => Some(s))
+ )
+}
@@ -0,0 +1,46 @@
+package controllers
+
+import akka.dispatch.Future
+import akka.util.Timeout
+import akka.util.duration._
+import org.asyncmongo.api._
+import org.asyncmongo.gridfs._
+import play.api.libs.concurrent._
+import play.api.libs.iteratee._
+import play.api.mvc._
+import scala.collection.generic.CanBuildFrom
+
+trait MongoController {
+ self :Controller =>
+
+ def MongoPromiseResult(whenReady: => Promise[Result])(implicit connection: MongoConnection) = {
+ Async {
+ implicit val timeout = Timeout(1 seconds)
+ new AkkaPromise(connection.waitForPrimary(timeout)).flatMap(e => {println(e); whenReady})
+ }
+ }
+
+ def MongoFutureResult(whenReady: => Future[Result])(implicit connection: MongoConnection) = {
+ Async {
+ implicit val timeout = Timeout(1 seconds)
+ new AkkaPromise(connection.waitForPrimary(timeout).flatMap(e => {println(e); whenReady}))
+ }
+ }
+
+ def collect[M[_], T](futureCursor: Future[Cursor[T]])(implicit cbf: CanBuildFrom[M[_], T, M[T]]) = {
+ Cursor.enumerate(futureCursor) |>>> Iteratee.fold(cbf.apply) { (builder, t :T) => builder += t }.map(_.result)
+ }
+
+ def gridFSBodyParser(gfs: GridFS) :BodyParser[Seq[Promise[PutResult]]] = BodyParsers.parse.Multipart.multipartParser { headers =>
+ val filename = headers.get("content-disposition").flatMap(_.split(';').map(_.trim).find(_.startsWith("filename=")).map(_.drop("filename=\"".length).dropRight(1)))
+ val contentType = headers.get("content-type").map(_.trim)
+
+ filename.map { name =>
+ val mongoReadyPromise = new AkkaPromise(gfs.db.connection.waitForPrimary(Timeout(1 seconds)))
+ val promiseOfIteratee = mongoReadyPromise.map { _ =>
+ gfs.save(name, None, contentType)
+ }
+ Iteratee.flatten(promiseOfIteratee)
+ }.getOrElse(Done.apply(null, Input.Empty)) // if no filename, we drop the upload
+ }
+}
@@ -0,0 +1,78 @@
+package models
+
+import org.asyncmongo.bson._
+import org.asyncmongo.handlers._
+
+import org.jboss.netty.buffer._
+
+import play.api.data._
+import play.api.data.Forms._
+import play.api.data.format.Formats._
+import play.api.data.validation.Constraints._
+
+
+case class User(
+ id: Option[BSONObjectID] = None,
+ lastName: String,
+ firstName: String,
+ email: String,
+ password: Option[String]
+)
+
+object User {
+ val form = Form(
+ mapping(
+ "id" -> optional(of[String] verifying pattern(
+ """[a-fA-F0-9]{24}""".r,
+ "constraint.objectId",
+ "error.email")),//play.api.data.Mapping,
+ "lastName" -> nonEmptyText,
+ "firstName" -> nonEmptyText,
+ "email" -> email,
+ "password" -> optional(text)
+ ) { (id, lastName, firstName, email, password) =>
+ User(
+ id.map(new BSONObjectID(_)),
+ lastName,
+ firstName,
+ email,
+ password)
+ } { user =>
+ Some((user.id.map(_.stringify), user.lastName, user.firstName, user.email, user.password))
+ }
+ )
+
+ object UserBSONWriter extends BSONWriter[User] {
+ def write(user: User) = Bson(
+ "lastName" -> BSONString(user.lastName),
+ "firstName" -> BSONString(user.firstName),
+ "email" -> BSONString(user.email)).makeBuffer
+ }
+
+ object UserBSONReader extends BSONReader[User] {
+ def read(buffer: ChannelBuffer) = {
+ val map = DefaultBSONHandlers.DefaultBSONReader.read(buffer).mapped
+ User(
+ map.get("_id").map(_.value match {
+ case id :BSONObjectID => id
+ case _ => throw new RuntimeException()
+ }),
+ map.get("lastName").map(_.value match {
+ case BSONString(lastName) => lastName
+ case _ => throw new RuntimeException()
+ }).get,
+ map.get("firstName").map(_.value match {
+ case BSONString(firstName) => firstName
+ case _ => throw new RuntimeException()
+ }).get,
+ map.get("email").map(_.value match {
+ case BSONString(email) => email
+ case _ => throw new RuntimeException()
+ }).get,
+ map.get("password").map(_.value match {
+ case BSONString(password) => password
+ case _ => throw new RuntimeException()
+ }))
+ }
+ }
+}
@@ -0,0 +1,19 @@
+@(creation: Boolean, form: Form[models.User])
+
+@main("Welcome to Play 2.0") {
+ <h1>
+ @if(creation) {
+ Add
+ } else {
+ Edit
+ } a user</h1>
+
+ @helper.form(action = (if(creation) routes.Application.createUser else routes.Application.editUser(form.value.get.id.get.stringify))) {
+ @helper.inputText(form("lastName"))
+ @helper.inputText(form("firstName"))
+ @helper.inputText(form("email"))
+ <div>
+ <input type="submit" />
+ </div>
+ }
+}
@@ -0,0 +1,20 @@
+@(users: List[models.User])
+
+@main("Welcome to Play 2.0") {
+ <h1>Users</h1>
+ <div>
+ Sort: <a href="/?sort=lastName">last name</a> - <a href="/?sort=firstName">first name</a> - <a href="/?sort=email">email</a> - <a href="/">none</a>
+ </div>
+ @if(!users.isEmpty) {
+ <ul>
+ @users.map { user =>
+ <li>
+ <a href="@routes.Application.editForm(user.id.get.stringify)">@user.firstName @user.lastName (@user.email)</a>
+ </li>
+ }
+ </ul>
+ }
+ <div>
+ <a href="@routes.Application.createForm">Create a user</a>
+ </div>
+}
@@ -0,0 +1,15 @@
+@(title: String)(content: Html)
+
+<!DOCTYPE html>
+
+<html>
+ <head>
+ <title>@title</title>
+ <link rel="stylesheet" media="screen" href="@routes.Assets.at("stylesheets/main.css")">
+ <link rel="shortcut icon" type="image/png" href="@routes.Assets.at("images/favicon.png")">
+ <script src="@routes.Assets.at("javascripts/jquery-1.7.1.min.js")" type="text/javascript"></script>
+ </head>
+ <body>
+ @content
+ </body>
+</html>
@@ -0,0 +1,55 @@
+# This is the main configuration file for the application.
+# ~~~~~
+
+# Secret key
+# ~~~~~
+# The secret key is used to secure cryptographics functions.
+# If you deploy your application to several instances be sure to use the same key!
+application.secret="iNN2f70HaHwewLY84HgbsCJk=YPKLIstCcvFj>fLDVhl2C=:FRoyo_1S=>VbN?_P"
+
+# The application languages
+# ~~~~~
+application.langs="en"
+
+# Global object class
+# ~~~~~
+# Define the Global object class for this application.
+# Default to Global in the root package.
+# application.global=Global
+
+# Router
+# ~~~~~
+# Define the Router object to use for this application.
+# Default to Routes in the root package.
+# application.routers=my.application.Routes
+
+# Database configuration
+# ~~~~~
+# You can declare as many datasources as you want.
+# By convention, the default datasource is named `default`
+#
+# db.default.driver=org.h2.Driver
+# db.default.url="jdbc:h2:mem:play"
+# db.default.user=sa
+# db.default.password=
+
+# Evolutions
+# ~~~~~
+# You can disable evolutions if needed
+# evolutionplugin=disabled
+
+# Logger
+# ~~~~~
+# You can also configure logback (http://logback.qos.ch/), by providing a logger.xml file in the conf directory .
+
+# Root logger:
+logger.root=ERROR
+
+# Logger used by the framework:
+logger.play=INFO
+
+# Logger provided to your application:
+logger.application=DEBUG
+
+mongodb.servers = ["localhost:27016"]
+mongodb.db = "app"
@@ -0,0 +1 @@
+400:play.modules.mongodb.MongoAsyncPlugin
@@ -0,0 +1,13 @@
+# Routes
+# This file defines all application routes (Higher priority routes first)
+# ~~~~
+
+# Home page
+GET / controllers.Application.index
+GET /user controllers.Application.createForm
+GET /user/:id controllers.Application.editForm(id)
+POST /user controllers.Application.createUser
+POST /user/:id controllers.Application.editUser(id)
+
+# Map static resources from the /public folder to the /assets URL path
+GET /assets/*file controllers.Assets.at(path="/public", file)
@@ -0,0 +1,19 @@
+import sbt._
+import Keys._
+import PlayProject._
+
+object ApplicationBuild extends Build {
+
+ val appName = "mongo-app"
+ val appVersion = "1.0-SNAPSHOT"
+
+ val appDependencies = Seq(
+ "org.asyncmongo" %% "mongo-async-driver" % "0.1-SNAPSHOT",
+ "play.modules.mongodb" %% "play2-mongodb-async" % "0.1-SNAPSHOT"
+ )
+
+ val main = PlayProject(appName, appVersion, appDependencies, mainLang = SCALA).settings(
+ resolvers += "sgodbillon" at "https://bitbucket.org/sgodbillon/repository/raw/master/snapshots/"
+ )
+
+}
@@ -0,0 +1 @@
+sbt.version=0.11.3
@@ -0,0 +1,8 @@
+// Comment to get more information during initialization
+logLevel := Level.Warn
+
+// The Typesafe repository
+resolvers += "Typesafe repository" at "http://repo.typesafe.com/typesafe/releases/"
+
+// Use the Play sbt plugin for Play projects
+addSbtPlugin("play" % "sbt-plugin" % "2.1-SNAPSHOT")
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Oops, something went wrong.
No changes.

0 comments on commit 0c4e179

Please sign in to comment.