Commit b6920b68 authored by Fedwin Morr's avatar Fedwin Morr
Browse files

Major Code Cleanup

* setup clean project
parent e42db21f
# Database files
/.database
# Emacs
*~
\#*\#
/.emacs.desktop
/.emacs.desktop.lock
.elc
auto-save-list
tramp
# Ensime
.ensime
.ensime_cache/
.ensime*.log
# Playframework
logs
project/project
project/target
target
tmp
# IntelliJ Idea
*.iml
*.ipr
*.iws
.idea/
# Logfiles and rotated logfiles.
*.log
*.log.[0-9]*
# MacOS
*.DS_Store
.AppleDouble
.LSOverride
Icon
._*
.DocumentRevisions-V100
.fseventsd
.Spotlight-V100
.TemporaryItems
.Trashes
.VolumeIcon.icns
.com.apple.timemachine.donotpresent
.AppleDB
.AppleDesktop
Network Trash Folder
Temporary Items
.apdisk
# SBT
target/
lib_managed/
src_managed/
project/boot/
.history
dist
/.idea
/*.iml
/out
/.idea_modules
/.classpath
/.project
/RUNNING_PID
/.settings
/.sass-cache
.cache
# Vim
.*.sw[a-z]
*.un~
......
style = defaultWithAlign
danglingParentheses = true
indentOperator = spray
maxColumn = 100
project.excludeFilters = [".*\\.sbt"]
rewrite.rules = [RedundantBraces, RedundantParens, SortImports]
spaces.inImportCurlyBraces = true
unindentTopLevelOperators = true
# Contributing to "Come out and Play"
This project has adopted the [Collective Code Construction Contract
(C4.2)](https://rfc.zeromq.org/spec:42) for contributing. Please read it
before sending patches.
### Additions to C4.2
1. Please rebase your branch if the project diverges from your branch.
2. Before a pull request is merged the commits done on the feature branch
SHOULD be squashed into a single commit.
This diff is collapsed.
Copyright 2017 Jens Grassel & André Schütz
Code for the `come out an play` book!
# Come out and Play - source code for the book
This repository contains the example application that is developed in
the book [Come out and Play](https://leanpub.com/comeoutandplay).
## License
This code is open source software licensed under the
[AGPLv3](https://www.gnu.org/licenses/agpl.html) license.
## Contributing
Please see the file [CONTRIBUTING.md](CONTRIBUTING.md) for detailed
instructions how to contribute to this repository.
// *****************************************************************************
// Projects
// *****************************************************************************
lazy val frontend =
project
.in(file("frontend"))
.enablePlugins(AutomateHeaderPlugin, GitVersioning, GitBranchPrompt, PlayScala)
.settings(settings)
.settings(
compile in Compile := ((compile in Compile) dependsOn scalaJSPipeline).value,
libraryDependencies ++= Seq(
library.playSlick,
library.playSlickEvolutions,
library.postgresql,
library.scalaJsScripts,
library.webjarsBootstrap,
library.webjarsPlay,
library.scalaCheck % Test,
library.scalaTest % Test
),
pipelineStages in Assets := Seq(scalaJSPipeline),
pipelineStages := Seq(digest, gzip),
scalaJSProjects := Seq(client),
unmanagedSourceDirectories.in(Compile) := Seq(scalaSource.in(Compile).value),
unmanagedSourceDirectories.in(Test) := Seq(scalaSource.in(Test).value),
wartremoverWarnings in (Compile, compile) ++= Warts.unsafe
)
.dependsOn(sharedJvm)
// Define the scala version for the project
val scalaV = "2.11.8"
lazy val frontend = (project in file("frontend")).settings(
scalaVersion := scalaV,
scalaJSProjects := Seq(scalaJs),
pipelineStages in Assets := Seq(scalaJSPipeline),
pipelineStages := Seq(digest, gzip),
// triggers scalaJSPipeline when using compile or continuous compilation
compile in Compile := ((compile in Compile) dependsOn scalaJSPipeline).value,
libraryDependencies ++= Seq(
"com.typesafe.play" %% "play-slick" % "2.0.2",
"com.typesafe.play" %% "play-slick-evolutions" % "2.0.2",
"com.vmunier" %% "scalajs-scripts" % "1.0.0",
"org.postgresql" % "postgresql" % "9.4.1212",
"org.webjars" %% "webjars-play" % "2.5.0",
"org.webjars" % "bootstrap" % "3.3.7"
)
).enablePlugins(PlayScala).
dependsOn(sharedJvm)
lazy val scalaJs = (project in file("scalaJs")).settings(
scalaVersion := scalaV,
persistLauncher := true,
persistLauncher in Test := false,
libraryDependencies ++= Seq(
"org.scala-js" %%% "scalajs-dom" % "0.9.1"
)
).enablePlugins(ScalaJSPlugin, ScalaJSWeb).
dependsOn(sharedJs)
lazy val client =
project
.in(file("client"))
.enablePlugins(AutomateHeaderPlugin, GitVersioning, GitBranchPrompt, ScalaJSPlugin, ScalaJSWeb)
.settings(settings)
.settings(
libraryDependencies ++= Seq(
"org.scala-js" %%% "scalajs-dom" % "0.9.1"
),
persistLauncher := true,
persistLauncher in Test := false
)
.dependsOn(sharedJs)
lazy val shared = (crossProject.crossType(CrossType.Pure) in file("shared")).
settings(scalaVersion := scalaV).
jsConfigure(_ enablePlugins ScalaJSWeb)
lazy val shared =
(crossProject.crossType(CrossType.Pure) in file("shared"))
.settings(settings)
.jsConfigure(_ enablePlugins ScalaJSWeb)
lazy val sharedJvm = shared.jvm
lazy val sharedJs = shared.js
lazy val sharedJs = shared.js
// loads the server project at sbt startup
// Load the frontend project upon sbt startup.
onLoad in Global := (Command.process("project frontend", _: State)) compose (onLoad in Global).value
// *****************************************************************************
// Library dependencies
// *****************************************************************************
lazy val library =
new {
object Version {
val bootstrap = "3.3.7"
val playSlick = "2.0.2"
val postgresql = "42.0.0"
val scalaCheck = "1.13.4"
val scalaJsScripts = "1.0.0"
val scalaTest = "3.0.1"
val webjarsPlay = "2.5.0-4"
}
val playSlick = "com.typesafe.play" %% "play-slick" % Version.playSlick
val playSlickEvolutions = "com.typesafe.play" %% "play-slick-evolutions" % Version.playSlick
val postgresql = "org.postgresql" % "postgresql" % Version.postgresql
val scalaCheck = "org.scalacheck" %% "scalacheck" % Version.scalaCheck
val scalaJsScripts = "com.vmunier" %% "scalajs-scripts" % Version.scalaJsScripts
val scalaTest = "org.scalatest" %% "scalatest" % Version.scalaTest
val webjarsBootstrap = "org.webjars" % "bootstrap" % Version.bootstrap
val webjarsPlay = "org.webjars" %% "webjars-play" % Version.webjarsPlay
}
// *****************************************************************************
// Settings
// *****************************************************************************
lazy val settings =
commonSettings ++
gitSettings ++
headerSettings
lazy val commonSettings =
Seq(
scalaVersion in ThisBuild := "2.11.8",
organization := "de.hoshikuzu",
licenses += ("AGPLv3",
url("https://www.gnu.org/licenses/agpl.html")),
mappings.in(Compile, packageBin) += baseDirectory.in(ThisBuild).value / "LICENSE" -> "LICENSE",
scalacOptions ++= Seq(
"-deprecation",
"-encoding", "UTF-8",
"-feature",
"-language:_",
"-target:jvm-1.8",
"-unchecked",
// "-Xfatal-warnings",
"-Xfuture",
"-Xlint",
"-Ydelambdafy:method",
"-Yno-adapted-args",
"-Ywarn-numeric-widen",
"-Ywarn-unused-import",
"-Ywarn-value-discard"
),
javacOptions ++= Seq(
"-source", "1.8",
"-target", "1.8"
)
)
lazy val gitSettings =
Seq(
git.useGitDescribe := true
)
import de.heikoseeberger.sbtheader.HeaderPattern
import de.heikoseeberger.sbtheader.license._
lazy val headerSettings =
Seq(
headers := Map("scala" -> AGPLv3("2017", "Jens Grassel & André Schütz"))
)
/*
* Copyright (C) 2017 Jens Grassel & André Schütz
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.hoshikuzu.client
import org.scalajs.dom
import de.hoshikuzu.shared.TestMessage
import scala.scalajs.js
object TestApp extends js.JSApp {
def main(): Unit =
dom.document.getElementById("scalaJsTest").textContent = TestMessage.test
}
/*
* Copyright (C) 2017 Jens Grassel & André Schütz
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import javax.inject._
import play.api._
import play.api.http.HttpFilters
import play.api.mvc._
import filters.ExampleFilter
/**
* This class configures filters that run on every request. This
* class is queried by Play to get a list of filters.
*
* Play will automatically use filters from any class called
* `Filters` that is placed the root package. You can load filters
* from a different class by adding a `play.http.filters` setting to
* the `application.conf` configuration file.
*
* @param env Basic environment settings for the current application.
* @param exampleFilter A demonstration filter that adds a header to
* each response.
*/
@Singleton
class Filters @Inject()(env: Environment, exampleFilter: ExampleFilter) extends HttpFilters {
override val filters = {
// Use the example filter if we're running development mode. If
// we're running in production or test mode then don't use any
// filters at all.
if (env.mode == Mode.Dev) Seq(exampleFilter) else Seq.empty
}
}
/*
* Copyright (C) 2017 Jens Grassel & André Schütz
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import com.google.inject.AbstractModule
import java.time.Clock
import services.{ ApplicationTimer, AtomicCounter, Counter }
/**
* This class is a Guice module that tells Guice how to bind several
* different types. This Guice module is created when the Play
* application starts.
* Play will automatically use any class called `Module` that is in
* the root package. You can create modules in other locations by
* adding `play.modules.enabled` settings to the `application.conf`
* configuration file.
*/
class Module extends AbstractModule {
override def configure() = {
// Use the system clock as the default implementation of Clock
bind(classOf[Clock]).toInstance(Clock.systemDefaultZone)
// Ask Guice to create an instance of ApplicationTimer when the
// application starts.
bind(classOf[ApplicationTimer]).asEagerSingleton()
// Set AtomicCounter as the implementation for Counter.
bind(classOf[Counter]).to(classOf[AtomicCounter])
}
}
package controllers
import play.api.mvc._
import shared.SharedMessages
class Application extends Controller {
def index = Action {
Ok(views.html.index(SharedMessages.itWorks))
}
}
/*
* Copyright (C) 2017 Jens Grassel & André Schütz
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package controllers
import akka.actor.ActorSystem
import javax.inject._
import play.api._
import play.api.mvc._
import scala.concurrent.{ ExecutionContext, Future, Promise }
import scala.concurrent.duration._
/**
* This controller creates an `Action` that demonstrates how to write
* simple asynchronous code in a controller. It uses a timer to
* asynchronously delay sending a response for 1 second.
*
* @param actorSystem We need the `ActorSystem`'s `Scheduler` to
* run code after a delay.
* @param exec We need an `ExecutionContext` to execute our
* asynchronous code.
*/
@Singleton
class AsyncController @Inject()(actorSystem: ActorSystem)(implicit exec: ExecutionContext)
extends Controller {
/**
* Create an Action that returns a plain text message after a delay
* of 1 second.
*
* The configuration in the `routes` file means that this method
* will be called when the application receives a `GET` request with
* a path of `/message`.
*/
def message = Action.async {
getFutureMessage(1.second).map { msg =>
Ok(msg)
}
}
private def getFutureMessage(delayTime: FiniteDuration): Future[String] = {
val promise: Promise[String] = Promise[String]()
actorSystem.scheduler.scheduleOnce(delayTime) { promise.success("Hi!") }
promise.future
}
}
/*
* Copyright (C) 2017 Jens Grassel & André Schütz
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package controllers
import javax.inject._
import play.api._
import play.api.mvc._
import services.Counter
/**
* This controller demonstrates how to use dependency injection to
* bind a component into a controller class. The class creates an
* `Action` that shows an incrementing count to users. The [[Counter]]
* object is injected by the Guice dependency injection system.
*/
@Singleton
class CountController @Inject()(counter: Counter) extends Controller {
/**
* Create an action that responds with the [[Counter]]'s current
* count. The result is plain text. This `Action` is mapped to
* `GET /count` requests by an entry in the `routes` config file.
*/
def count = Action { Ok(counter.nextCount().toString) }
}
/*
* Copyright (C) 2017 Jens Grassel & André Schütz
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package controllers
import javax.inject._
import play.api._
import play.api.mvc._
import de.hoshikuzu.shared.TestMessage
/**
* This controller creates an `Action` to handle HTTP requests to the
* application's home page.
*/
@Singleton
class HomeController @Inject() extends Controller {
/**
* Create an Action to render an HTML page with a welcome message.
* The configuration in the `routes` file means that this method
* will be called when the application receives a `GET` request with
* a path of `/`.
*/
def index = Action {
Ok(views.html.index(TestMessage.test))
}
}
/*
* Copyright (C) 2017 Jens Grassel & André Schütz
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package filters
import akka.stream.Materializer
import javax.inject._
import play.api.mvc._
import scala.concurrent.{ ExecutionContext, Future }
/**
* This is a simple filter that adds a header to all requests. It's
* added to the application's list of filters by the
* [[Filters]] class.
*
* @param mat This object is needed to handle streaming of requests
* and responses.
* @param exec This class is needed to execute code asynchronously.
* It is used below by the `map` method.
*/
@Singleton
class ExampleFilter @Inject()(implicit override val mat: Materializer, exec: ExecutionContext)
extends Filter {
override def apply(
nextFilter: RequestHeader => Future[Result]
)(requestHeader: RequestHeader): Future[Result] =
// Run the next filter in the chain. This will call other filters
// and eventually call the action. Take the result and modify it
// by adding a new header.
nextFilter(requestHeader).map { result =>
result.withHeaders("X-ExampleFilter" -> "foo")
}
}
/*
* Copyright (C) 2017 Jens Grassel & André Schütz