├── .git-blame-ignore-revs ├── .github ├── CODEOWNERS ├── dependabot.yml └── workflows │ ├── ci.yml │ └── scala-steward.yml ├── .gitignore ├── .scalafmt.conf ├── CONTRIBUTING.md ├── LICENSE.txt ├── build.sbt ├── logo.png ├── project ├── build.properties └── plugins.sbt ├── readme.md ├── release.sh ├── scalikejdbc-play-dbapi-adapter ├── .gitignore ├── readme.md ├── src │ ├── main │ │ └── scala │ │ │ └── scalikejdbc │ │ │ ├── PlayDBApiAdapter.scala │ │ │ └── PlayDBApiAdapterModule.scala │ └── test │ │ └── scala │ │ └── scalikejdbc │ │ └── PlayDBApiAdapterModuleSpec.scala └── test │ └── zentasks │ ├── Procfile │ ├── README │ ├── app │ ├── assets │ │ ├── javascripts │ │ │ └── main.coffee │ │ └── stylesheets │ │ │ ├── apps │ │ │ └── _tasks.less │ │ │ ├── libs │ │ │ ├── _mate.less │ │ │ ├── _reset.less │ │ │ └── _theme.less │ │ │ ├── login.less │ │ │ ├── main.less │ │ │ └── main │ │ │ ├── _breadcrumb.less │ │ │ ├── _drawer.less │ │ │ ├── _header.less │ │ │ ├── _layout.less │ │ │ └── _widgets.less │ ├── controllers │ │ ├── Application.scala │ │ ├── Projects.scala │ │ └── Tasks.scala │ ├── models │ │ ├── Project.scala │ │ ├── Task.scala │ │ └── User.scala │ └── views │ │ ├── dashboard.scala.html │ │ ├── login.scala.html │ │ ├── main.scala.html │ │ ├── projects │ │ ├── group.scala.html │ │ └── item.scala.html │ │ └── tasks │ │ ├── folder.scala.html │ │ ├── index.scala.html │ │ └── item.scala.html │ ├── conf │ ├── application.conf │ ├── db │ │ └── fixtures │ │ │ ├── default │ │ │ ├── project.sql │ │ │ ├── project_member.sql │ │ │ ├── task.sql │ │ │ └── users.sql │ │ │ └── secondary │ │ │ ├── project.sql │ │ │ ├── project_member.sql │ │ │ ├── task.sql │ │ │ └── users.sql │ ├── evolutions │ │ ├── default │ │ │ └── 1.sql │ │ └── secondary │ │ │ └── 1.sql │ ├── prod.conf │ └── routes │ ├── project │ └── build.properties │ └── public │ ├── images │ ├── arrow-left.png │ ├── breadcrumb-1.png │ ├── breadcrumb-2.png │ ├── breadcrumb.png │ ├── icons │ │ ├── addRemove.png │ │ ├── clock.png │ │ ├── delete.png │ │ ├── drawer.folder.png │ │ ├── folder.png │ │ ├── home.png │ │ ├── options.png │ │ ├── user.png │ │ └── user2.png │ ├── loading.gif │ └── pattern.png │ └── javascripts │ ├── backbone-min.js │ └── underscore-min.js ├── scalikejdbc-play-fixture ├── readme.md └── src │ ├── main │ └── scala │ │ └── scalikejdbc │ │ ├── PlayFixtureModule.scala │ │ └── play │ │ ├── Fixture.scala │ │ ├── FixtureNotFoundException.scala │ │ └── FixtureSupport.scala │ └── test │ ├── resources │ └── db │ │ └── fixtures │ │ ├── default │ │ ├── project.sql │ │ └── users.sql │ │ └── secondary │ │ └── a.sql │ └── scala │ └── scalikejdbc │ └── play │ ├── FixtureSpec.scala │ └── FixtureSupportSpec.scala ├── scalikejdbc-play-initializer ├── .gitignore ├── readme.md ├── src │ ├── main │ │ └── scala │ │ │ └── scalikejdbc │ │ │ ├── PlayInitializer.scala │ │ │ └── PlayModule.scala │ └── test │ │ └── scala │ │ └── scalikejdbc │ │ └── PlayModuleSpec.scala └── test │ └── zentasks │ ├── Procfile │ ├── README │ ├── app │ ├── assets │ │ ├── javascripts │ │ │ └── main.coffee │ │ └── stylesheets │ │ │ ├── apps │ │ │ └── _tasks.less │ │ │ ├── libs │ │ │ ├── _mate.less │ │ │ ├── _reset.less │ │ │ └── _theme.less │ │ │ ├── login.less │ │ │ ├── main.less │ │ │ └── main │ │ │ ├── _breadcrumb.less │ │ │ ├── _drawer.less │ │ │ ├── _header.less │ │ │ ├── _layout.less │ │ │ └── _widgets.less │ ├── controllers │ │ ├── Application.scala │ │ ├── Projects.scala │ │ └── Tasks.scala │ ├── models │ │ ├── Project.scala │ │ ├── Task.scala │ │ └── User.scala │ └── views │ │ ├── dashboard.scala.html │ │ ├── login.scala.html │ │ ├── main.scala.html │ │ ├── projects │ │ ├── group.scala.html │ │ └── item.scala.html │ │ └── tasks │ │ ├── folder.scala.html │ │ ├── index.scala.html │ │ └── item.scala.html │ ├── conf │ ├── application.conf │ ├── db │ │ ├── fixtures │ │ │ ├── default │ │ │ │ ├── project.sql │ │ │ │ ├── project_member.sql │ │ │ │ ├── task.sql │ │ │ │ └── users.sql │ │ │ └── secondary │ │ │ │ ├── project.sql │ │ │ │ ├── project_member.sql │ │ │ │ ├── task.sql │ │ │ │ └── users.sql │ │ └── migration │ │ │ ├── default │ │ │ └── V1__create_tables.sql │ │ │ └── secondary │ │ │ └── V1__create_tables.sql │ ├── prod.conf │ └── routes │ ├── project │ └── build.properties │ └── public │ ├── images │ ├── arrow-left.png │ ├── breadcrumb-1.png │ ├── breadcrumb-2.png │ ├── breadcrumb.png │ ├── icons │ │ ├── addRemove.png │ │ ├── clock.png │ │ ├── delete.png │ │ ├── drawer.folder.png │ │ ├── folder.png │ │ ├── home.png │ │ ├── options.png │ │ ├── user.png │ │ └── user2.png │ ├── loading.gif │ └── pattern.png │ └── javascripts │ ├── backbone-min.js │ └── underscore-min.js └── windows_test_filter.sbt /.git-blame-ignore-revs: -------------------------------------------------------------------------------- 1 | # Scala Steward: Reformat with scalafmt 3.8.2 2 | 1f5b2be4fa1dffb33489ff089ae197357c073f9c 3 | -------------------------------------------------------------------------------- /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | * @seratch @xuwei-k 2 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: "github-actions" 4 | directory: "/" 5 | schedule: 6 | interval: "weekly" 7 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | on: 3 | pull_request: 4 | push: 5 | schedule: 6 | - cron: '0 15 * * 3' 7 | jobs: 8 | test: 9 | timeout-minutes: 30 10 | strategy: 11 | fail-fast: false 12 | matrix: 13 | os: 14 | - windows-latest 15 | - ubuntu-latest 16 | runs-on: ${{ matrix.os }} 17 | steps: 18 | - uses: actions/checkout@v4 19 | - uses: actions/setup-java@v4 20 | with: 21 | java-version: 11 22 | distribution: temurin 23 | - uses: sbt/setup-sbt@v1 24 | - uses: coursier/cache-action@v6 25 | - shell: bash 26 | run: | 27 | case ${{ matrix.os }} in 28 | "windows-latest") 29 | sbt -v -J-Dfile.encoding=Windows-31J "+test" 30 | ;; 31 | *) 32 | sbt -v scalafmtSbtCheck "+ scalafmtCheckAll" "+test" 33 | esac 34 | -------------------------------------------------------------------------------- /.github/workflows/scala-steward.yml: -------------------------------------------------------------------------------- 1 | name: scala-steward 2 | on: 3 | push: 4 | branches: [ master ] 5 | schedule: 6 | - cron: '0 0 * * *' 7 | workflow_dispatch: 8 | jobs: 9 | scala-steward: 10 | runs-on: ubuntu-latest 11 | if: ${{ github.repository_owner == 'scalikejdbc' }} 12 | timeout-minutes: 20 13 | steps: 14 | - name: Generate token 15 | id: generate_token 16 | uses: tibdex/github-app-token@v2 17 | with: 18 | app_id: 89631 19 | private_key: ${{ secrets.SCALIKEJDBC_BOT_KEY }} 20 | - name: Launch Scala Steward 21 | uses: scala-steward-org/scala-steward-action@v2.75.0 22 | with: 23 | github-token: ${{ steps.generate_token.outputs.token }} 24 | author-email: "74833019+scalikejdbc-bot[bot]@users.noreply.github.com" 25 | author-name: scalikejdbc-bot[bot] 26 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .bsp 2 | .settings 3 | .classpath 4 | .project 5 | *.iml 6 | *.ipr 7 | *.iws 8 | dist/ 9 | lib_managed/ 10 | project/boot/ 11 | project/plugins/project/ 12 | target/ 13 | 14 | # use glob syntax. 15 | syntax: glob 16 | *.ser 17 | *.class 18 | *~ 19 | *.bak 20 | #*.off 21 | *.old 22 | 23 | # eclipse conf file 24 | .settings 25 | .classpath 26 | .project 27 | .manager 28 | .scala_dependencies 29 | 30 | # idea 31 | .idea 32 | *.iml 33 | 34 | # building 35 | target 36 | build 37 | null 38 | tmp* 39 | temp* 40 | !templates/ 41 | dist 42 | test-output 43 | build.log 44 | 45 | # other scm 46 | .svn 47 | .CVS 48 | .hg* 49 | 50 | # switch to regexp syntax. 51 | # syntax: regexp 52 | # ^\.pc/ 53 | 54 | #SHITTY output not in target directory 55 | build.log 56 | .DS_Store 57 | derby.log 58 | 59 | *.db 60 | 61 | .lib 62 | sbt 63 | 64 | logs 65 | sandbox/db 66 | -------------------------------------------------------------------------------- /.scalafmt.conf: -------------------------------------------------------------------------------- 1 | version = 3.9.4 2 | trailingCommas = keep 3 | docstrings.style = keep 4 | indent.defnSite = 2 5 | indent.caseSite = 2 6 | indent.extendSite = 2 7 | spaces.inImportCurlyBraces = true 8 | runner.dialect = scala213 9 | 10 | fileOverride { 11 | "glob:**/src/main/scala-3/**" { 12 | runner.dialect = scala3 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | ## ScalikeJDBC Contributors' Guide 2 | 3 | ### Issues 4 | 5 | - Questions should be posted to [ScalikeJDBC Users Group](https://groups.google.com/forum/#!forum/scalikejdbc-users-group) 6 | - Please describe about your issue in detail (version, situation, examples) 7 | 8 | ### Pull Requests 9 | 10 | - Send pull requests toward "develop" or "feature/xxx" branches 11 | - Compatibility always must be kept as far as possible 12 | - scalafmt must be applied to all Scala source code 13 | - Prefer creating scala source code for each class/object/trait (of course, except for sealed trait) 14 | 15 | #### Testing your pull request 16 | 17 | Testing with default settings is required when push changes: 18 | 19 | ```sh 20 | sbt test 21 | ``` 22 | 23 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright 2013 ScalikeJDBC committers 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | https://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, 12 | either express or implied. See the License for the specific language 13 | governing permissions and limitations under the License. 14 | 15 | -------------------------------------------------------------------------------- /build.sbt: -------------------------------------------------------------------------------- 1 | lazy val scalikejdbcVersion = "4.3.3" 2 | 3 | // published dependency version 4 | lazy val defaultPlayVersion = play.core.PlayVersion.current 5 | 6 | // internal only 7 | lazy val h2Version = "2.3.232" 8 | lazy val postgresqlVersion = "42.7.6" 9 | 10 | lazy val commonSettings = Seq( 11 | scalaVersion := "2.13.16", 12 | crossScalaVersions := Seq("2.13.16", "3.3.6"), 13 | libraryDependencySchemes += "org.scala-lang.modules" %% "scala-parser-combinators" % "always", 14 | Test / fork := true, 15 | javaOptions ++= { 16 | if (scala.util.Properties.isWin) { 17 | Seq("-Dfile.encoding=Windows-31J") 18 | } else { 19 | Nil 20 | } 21 | }, 22 | scalacOptions ++= Seq("-deprecation", "-unchecked") 23 | ) 24 | 25 | commonSettings 26 | 27 | lazy val baseSettings = commonSettings ++ Seq( 28 | organization := "org.scalikejdbc", 29 | version := "3.0.1-scalikejdbc-4.3", 30 | publishTo := ( 31 | if (isSnapshot.value) 32 | None 33 | else 34 | Some(Opts.resolver.sonatypeStaging) 35 | ), 36 | publishMavenStyle := true, 37 | libraryDependencies += "org.specs2" %% "specs2-core" % "4.21.0" % "test", 38 | Global / transitiveClassifiers := Seq(Artifact.SourceClassifier), 39 | Test / publishArtifact := false, 40 | pomIncludeRepository := { x => false }, 41 | pomExtra := _pomExtra 42 | ) 43 | 44 | // scalikejdbc-play-initializer 45 | lazy val scalikejdbcPlayInitializer = Project( 46 | id = "play-initializer", 47 | base = file("scalikejdbc-play-initializer") 48 | ).settings( 49 | baseSettings, 50 | name := "scalikejdbc-play-initializer", 51 | libraryDependencies ++= Seq( 52 | "org.scalikejdbc" %% "scalikejdbc" % scalikejdbcVersion % "provided", 53 | "org.scalikejdbc" %% "scalikejdbc-config" % scalikejdbcVersion % "provided", 54 | "org.playframework" %% "play" % defaultPlayVersion % "provided", 55 | // play-jdbc is needed to test with DBApi 56 | "org.playframework" %% "play-jdbc" % defaultPlayVersion % "test", 57 | "org.playframework" %% "play-test" % defaultPlayVersion % "test", 58 | "com.h2database" % "h2" % h2Version % "test", 59 | guice % "test" 60 | ), 61 | ) 62 | 63 | // scalikejdbc-play-dbapi-adapter 64 | lazy val scalikejdbcPlayDBApiAdapter = Project( 65 | id = "play-dbapi-adapter", 66 | base = file("scalikejdbc-play-dbapi-adapter") 67 | ).settings( 68 | baseSettings, 69 | name := "scalikejdbc-play-dbapi-adapter", 70 | libraryDependencies ++= Seq( 71 | "org.scalikejdbc" %% "scalikejdbc" % scalikejdbcVersion % "provided", 72 | "org.scalikejdbc" %% "scalikejdbc-config" % scalikejdbcVersion % "provided", 73 | "org.playframework" %% "play" % defaultPlayVersion % "provided", 74 | "org.playframework" %% "play-jdbc" % defaultPlayVersion % "compile", 75 | "org.playframework" %% "play-test" % defaultPlayVersion % "test", 76 | "com.h2database" % "h2" % h2Version % "test", 77 | guice % "test" 78 | ), 79 | ) 80 | 81 | // scalikejdbc-play-fixture 82 | lazy val scalikejdbcPlayFixture = Project( 83 | id = "play-fixture", 84 | base = file("scalikejdbc-play-fixture") 85 | ).settings( 86 | baseSettings, 87 | name := "scalikejdbc-play-fixture", 88 | libraryDependencies ++= Seq( 89 | "org.scalikejdbc" %% "scalikejdbc" % scalikejdbcVersion % "provided", 90 | "org.scalikejdbc" %% "scalikejdbc-config" % scalikejdbcVersion % "provided", 91 | "org.playframework" %% "play" % defaultPlayVersion % "provided", 92 | "org.playframework" %% "play-test" % defaultPlayVersion % "test", 93 | "com.h2database" % "h2" % h2Version % "test" 94 | ), 95 | Test / testOptions += Tests 96 | .Argument(TestFrameworks.Specs2, "sequential", "true"), 97 | ).dependsOn(scalikejdbcPlayInitializer) 98 | 99 | // play plugin zentasks example 100 | lazy val scalikejdbcPlayInitializerTestZentasks = { 101 | val appName = "play-initializer-test-zentasks" 102 | 103 | val appDependencies = Seq( 104 | "org.scalikejdbc" %% "scalikejdbc" % scalikejdbcVersion, 105 | "org.scalikejdbc" %% "scalikejdbc-config" % scalikejdbcVersion, 106 | "org.flywaydb" %% "flyway-play" % "9.1.0", 107 | "com.h2database" % "h2" % h2Version, 108 | "org.postgresql" % "postgresql" % postgresqlVersion 109 | ) 110 | 111 | Project(appName, file("scalikejdbc-play-initializer/test/zentasks")) 112 | .enablePlugins(play.sbt.PlayScala, PlayNettyServer) 113 | .disablePlugins(PlayPekkoHttpServer) 114 | .settings( 115 | commonSettings, 116 | libraryDependencies ++= appDependencies, 117 | ) 118 | .dependsOn(scalikejdbcPlayInitializer, scalikejdbcPlayFixture) 119 | } 120 | 121 | // play dbapi adapter zentasks example 122 | lazy val scalikejdbcPlayDBApiAdapterTestZentasks = { 123 | val appName = "play-dbapi-adapter-test-zentasks" 124 | 125 | val appDependencies = Seq( 126 | "org.scalikejdbc" %% "scalikejdbc" % scalikejdbcVersion, 127 | "org.scalikejdbc" %% "scalikejdbc-config" % scalikejdbcVersion, 128 | "com.h2database" % "h2" % h2Version, 129 | "org.postgresql" % "postgresql" % postgresqlVersion 130 | ) 131 | 132 | Project(appName, file("scalikejdbc-play-dbapi-adapter/test/zentasks")) 133 | .enablePlugins(play.sbt.PlayScala, PlayNettyServer) 134 | .disablePlugins(PlayPekkoHttpServer) 135 | .settings( 136 | commonSettings, 137 | libraryDependencies ++= appDependencies, 138 | ) 139 | .dependsOn(scalikejdbcPlayDBApiAdapter, scalikejdbcPlayFixture) 140 | } 141 | 142 | val jdbcDriverDependenciesInTestScope = Seq( 143 | "com.h2database" % "h2" % h2Version % "test", 144 | "org.apache.derby" % "derby" % "10.10.2.+" % "test", 145 | "org.xerial" % "sqlite-jdbc" % "3.7.+" % "test", 146 | "org.hsqldb" % "hsqldb" % "2.3.+" % "test", 147 | "com.mysql" % "mysql-connector-j" % "8.2.0" % "test", 148 | "org.postgresql" % "postgresql" % postgresqlVersion % "test" 149 | ) 150 | val _pomExtra = https://scalikejdbc.org/ 151 | 152 | 153 | Apache License, Version 2.0 154 | https://www.apache.org/licenses/LICENSE-2.0.html 155 | repo 156 | 157 | 158 | 159 | git@github.com:scalikejdbc/scalikejdbc-play-support.git 160 | scm:git:git@github.com:scalikejdbc/scalikejdbc-play-support.git 161 | 162 | 163 | 164 | seratch 165 | Kazuhiro Sera 166 | https://github.com/seratch 167 | 168 | 169 | xuwei-k 170 | Kenji Yoshida 171 | https://github.com/xuwei-k 172 | 173 | 174 | tkawachi 175 | Takashi Kawachi 176 | https://github.com/tkawachi 177 | 178 | 179 | tototoshi 180 | Toshiyuki Takahashi 181 | https://github.com/tototoshi 182 | 183 | 184 | -------------------------------------------------------------------------------- /logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scalikejdbc/scalikejdbc-play-support/f2b16fcc53fd22c0bf1a278428c252b907c1398d/logo.png -------------------------------------------------------------------------------- /project/build.properties: -------------------------------------------------------------------------------- 1 | sbt.version=1.11.0 2 | -------------------------------------------------------------------------------- /project/plugins.sbt: -------------------------------------------------------------------------------- 1 | addSbtPlugin("org.scalameta" % "sbt-scalafmt" % "2.5.4") 2 | addSbtPlugin("org.playframework" % "sbt-plugin" % "3.0.7") 3 | addSbtPlugin("com.github.sbt" % "sbt-pgp" % "2.3.1") 4 | 5 | scalacOptions ++= Seq("-deprecation", "-unchecked", "-language:_") 6 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # ScalikeJDBC Play Support 2 | 3 | This is a project to enable using ScalikeJDBC in Play Framework apps seamlessly. 4 | 5 | https://scalikejdbc.org/ 6 | 7 | ### Getting Started with Play 3.0 8 | 9 | #### build.sbt 10 | 11 | ```scala 12 | libraryDependencies ++= Seq( 13 | "com.h2database" % "h2" % "2.2.224", // your jdbc driver here 14 | "org.scalikejdbc" %% "scalikejdbc" % "4.3.0", 15 | "org.scalikejdbc" %% "scalikejdbc-config" % "4.3.0", 16 | "org.scalikejdbc" %% "scalikejdbc-play-initializer" % "3.0.0-scalikejdbc-4.3" 17 | ) 18 | ``` 19 | 20 | #### conf/application.conf 21 | 22 | ``` 23 | # Database configuration 24 | # ~~~~~ 25 | # You can declare as many datasources as you want. 26 | # By convention, the default datasource is named `default` 27 | db.default.driver=org.h2.Driver 28 | db.default.url="jdbc:h2:mem:play;DB_CLOSE_DELAY=-1" 29 | # NOTE: sclaikejdbc-config 2.2.6 doesn't support username, use 2.2.7 or higher 30 | db.default.username=sa 31 | db.default.password=sa 32 | 33 | # ScalikeJDBC original configuration 34 | #db.default.poolInitialSize=10 35 | #db.default.poolMaxSize=10 36 | #db.default.poolValidationQuery= 37 | 38 | scalikejdbc.global.loggingSQLErrors=true 39 | scalikejdbc.global.loggingSQLAndTime.enabled=true 40 | scalikejdbc.global.loggingSQLAndTime.singleLineMode=false 41 | scalikejdbc.global.loggingSQLAndTime.logLevel=debug 42 | scalikejdbc.global.loggingSQLAndTime.warningEnabled=true 43 | scalikejdbc.global.loggingSQLAndTime.warningThresholdMillis=5 44 | scalikejdbc.global.loggingSQLAndTime.warningLogLevel=warn 45 | 46 | play.modules.enabled += "scalikejdbc.PlayModule" 47 | ``` 48 | 49 | #### app/controllers/Application.scala 50 | 51 | Now you can access ScalikeJDBC everywhere in your Play app! 52 | 53 | ```scala 54 | package controllers 55 | 56 | import javax.inject._ 57 | import play.api._ 58 | import play.api.mvc._ 59 | import scalikejdbc._ 60 | 61 | @Singleton 62 | class Application @Inject()(cc: ControllerComponents) extends AbstractController(cc) { 63 | implicit val session: DBSession = AutoSession 64 | 65 | def index = Action { 66 | val accounts = { 67 | try sql"select * from accounts".toMap.list.apply() 68 | catch { case e: Exception => 69 | sql"create table accounts(name varchar(100) not null)".execute.apply() 70 | Seq("Alice", "Bob", "Chris").foreach { name => 71 | sql"insert into accounts values ($name)".update.apply() 72 | } 73 | sql"select * from accounts".toMap.list.apply() 74 | } 75 | } 76 | Ok(accounts.toString) 77 | } 78 | } 79 | ``` 80 | 81 | ### Migration Guide 82 | 83 | Unfortunately, Play 2.4 is basically incompatible with Play plugins. 84 | Since Play 2.4, you need to switch to use Play modules instead. 85 | 86 | #### ScalikeJDBC integration with Play 2.0 - 2.3 87 | 88 | - scalikejdbc-play-plugin 89 | - scalikejdbc-play-dbplugin-adapter 90 | - scalikejdbc-play-fixture-plugin 91 | 92 | #### ScalikeJDBC integration with Play 2.4 or higher 93 | 94 | - scalikejdbc-play-initializer 95 | - scalikejdbc-play-dbapi-adapter 96 | - scalikejdbc-play-fixture 97 | 98 | ## License 99 | 100 | ``` 101 | Copyright ScalikeJDBC committers 102 | Apache License, Version 2.0 103 | http://www.apache.org/licenses/LICENSE-2.0.html 104 | ``` 105 | -------------------------------------------------------------------------------- /release.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | sbt "+ play-initializer/publishSigned" \ 4 | "+ play-dbapi-adapter/publishSigned" \ 5 | "+ play-fixture/publishSigned" 6 | -------------------------------------------------------------------------------- /scalikejdbc-play-dbapi-adapter/.gitignore: -------------------------------------------------------------------------------- 1 | *.log 2 | .settings 3 | classpath 4 | .project 5 | *.iml 6 | *.ipr 7 | *.iws 8 | .DS_Store 9 | dist/ 10 | lib_managed/ 11 | project/boot/ 12 | project/plugins/project/ 13 | target/ 14 | 15 | # use glob syntax. 16 | syntax: glob 17 | *.ser 18 | *.class 19 | *~ 20 | *.bak 21 | #*.off 22 | *.old 23 | 24 | # eclipse conf file 25 | .settings 26 | .classpath 27 | .project 28 | .manager 29 | .scala_dependencies 30 | 31 | # idea 32 | .idea 33 | *.iml 34 | 35 | # building 36 | target 37 | build 38 | null 39 | tmp* 40 | temp* 41 | dist 42 | test-output 43 | build.log 44 | 45 | # other scm 46 | .svn 47 | .CVS 48 | .hg* 49 | 50 | # switch to regexp syntax. 51 | # syntax: regexp 52 | # ^\.pc/ 53 | 54 | #SHITTY output not in target directory 55 | build.log 56 | -------------------------------------------------------------------------------- /scalikejdbc-play-dbapi-adapter/readme.md: -------------------------------------------------------------------------------- 1 | # ScalikeJDBC Play DBPlugin Adapter 2 | 3 | -------------------------------------------------------------------------------- /scalikejdbc-play-dbapi-adapter/src/main/scala/scalikejdbc/PlayDBApiAdapter.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014 scalikejdbc.org 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, 13 | * either express or implied. See the License for the specific language 14 | * governing permissions and limitations under the License. 15 | */ 16 | package scalikejdbc 17 | 18 | import javax.inject._ 19 | import org.slf4j.LoggerFactory 20 | import _root_.play.api._ 21 | import _root_.play.api.inject._ 22 | import _root_.play.api.db.{ DBApi, DBApiProvider } 23 | import scalikejdbc.config.{ TypesafeConfig, TypesafeConfigReader, DBs } 24 | import scala.concurrent.Future 25 | 26 | /** 27 | * The Play plugin to use ScalikeJDBC 28 | */ 29 | @Singleton 30 | class PlayDBApiAdapter @Inject() ( 31 | dbApi: DBApi, 32 | configuration: Configuration, 33 | lifecycle: ApplicationLifecycle 34 | ) { 35 | 36 | val logger = LoggerFactory.getLogger(this.getClass) 37 | 38 | /** 39 | * DBs with Play application configuration. 40 | */ 41 | private[this] lazy val DBs = new DBs 42 | with TypesafeConfigReader 43 | with TypesafeConfig { 44 | override val config = configuration.underlying 45 | } 46 | 47 | private[this] lazy val loggingSQLErrors = configuration 48 | .getOptional[Boolean]("scalikejdbc.global.loggingSQLErrors") 49 | .getOrElse(true) 50 | 51 | def onStart(): Unit = { 52 | DBs.loadGlobalSettings() 53 | GlobalSettings.loggingSQLErrors = loggingSQLErrors 54 | 55 | dbApi.databases().foreach { db => 56 | scalikejdbc.ConnectionPool.add( 57 | db.name, 58 | new DataSourceConnectionPool(db.dataSource) 59 | ) 60 | } 61 | 62 | configuration 63 | .getOptional[String]("scalikejdbc.play.closeAllOnStop.enabled") 64 | .foreach { _ => 65 | logger.warn(s"closeAllOnStop is ignored by PlayDBPluginAdapter") 66 | } 67 | } 68 | 69 | def onStop(): Unit = { 70 | val cache = SQLSyntaxSupportFeature.SQLSyntaxSupportLoadedColumns 71 | cache.clear() 72 | } 73 | 74 | lifecycle.addStopHook(() => Future.successful(onStop())) 75 | onStart() 76 | } 77 | -------------------------------------------------------------------------------- /scalikejdbc-play-dbapi-adapter/src/main/scala/scalikejdbc/PlayDBApiAdapterModule.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014 scalikejdbc.org 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, 13 | * either express or implied. See the License for the specific language 14 | * governing permissions and limitations under the License. 15 | */ 16 | package scalikejdbc 17 | 18 | import _root_.play.api._ 19 | import _root_.play.api.inject._ 20 | 21 | /** 22 | * Play module 23 | */ 24 | class PlayDBApiAdapterModule extends Module { 25 | def bindings(env: Environment, config: Configuration) = Seq( 26 | bind[PlayDBApiAdapter].toSelf.eagerly() 27 | ) 28 | } 29 | -------------------------------------------------------------------------------- /scalikejdbc-play-dbapi-adapter/src/test/scala/scalikejdbc/PlayDBApiAdapterModuleSpec.scala: -------------------------------------------------------------------------------- 1 | package scalikejdbc 2 | 3 | import _root_.play.api.db.DBModule 4 | import _root_.play.api.inject.guice.GuiceApplicationBuilder 5 | import _root_.play.api.test.Helpers._ 6 | import org.specs2.mutable.Specification 7 | 8 | object PlayDBApiAdapterModuleSpec extends Specification { 9 | 10 | sequential 11 | 12 | Class.forName("org.h2.Driver") 13 | 14 | def fakeAppWithDBModule = { 15 | val additionalConfiguration = Map( 16 | "db.default.driver" -> "org.h2.Driver", 17 | "db.default.url" -> "jdbc:h2:mem:default", 18 | "db.default.user" -> "sa", 19 | "db.default.password" -> "sa", 20 | "db.default.schema" -> "", 21 | "db.legacydb.driver" -> "org.h2.Driver", 22 | "db.legacydb.url" -> "jdbc:h2:mem:legacy", 23 | "db.legacydb.user" -> "l", 24 | "db.legacydb.password" -> "g", 25 | "db.legacydb.schema" -> "", 26 | "scalikejdbc.global.loggingSQLAndTime.enabled" -> "true", 27 | "scalikejdbc.global.loggingSQLAndTime.logLevel" -> "debug", 28 | "scalikejdbc.global.loggingSQLAndTime.warningEnabled" -> "true", 29 | "scalikejdbc.global.loggingSQLAndTime.warningThreasholdMillis" -> "1", 30 | "scalikejdbc.global.loggingSQLAndTime.warningLogLevel" -> "warn" 31 | ) 32 | new GuiceApplicationBuilder() 33 | .configure(additionalConfiguration) 34 | .bindings(new PlayDBApiAdapterModule) 35 | .build() 36 | } 37 | 38 | def fakeAppWithoutDBModule = { 39 | val additionalConfiguration = Map( 40 | "logger.root" -> "INFO", 41 | "logger.play" -> "INFO", 42 | "logger.application" -> "DEBUG", 43 | "evolutionplugin" -> "disabled", 44 | "db.default.driver" -> "org.h2.Driver", 45 | "db.default.url" -> "jdbc:h2:mem:default", 46 | "db.default.user" -> "sa", 47 | "db.default.password" -> "sa", 48 | "db.default.schema" -> "", 49 | "db.default.poolInitialSize" -> "1", 50 | "db.default.poolMaxSize" -> "2", 51 | "db.default.poolValidationQuery" -> "select 1", 52 | "db.default.poolConnectionTimeoutMillis" -> "2000", 53 | "db.legacydb.driver" -> "org.h2.Driver", 54 | "db.legacydb.url" -> "jdbc:h2:mem:legacy", 55 | "db.legacydb.user" -> "l", 56 | "db.legacydb.password" -> "g", 57 | "db.legacydb.schema" -> "", 58 | "scalikejdbc.global.loggingSQLAndTime.enabled" -> "true", 59 | "scalikejdbc.global.loggingSQLAndTime.singleLineMode" -> "true", 60 | "scalikejdbc.global.loggingSQLAndTime.logLevel" -> "debug", 61 | "scalikejdbc.global.loggingSQLAndTime.warningEnabled" -> "true", 62 | "scalikejdbc.global.loggingSQLAndTime.warningThreasholdMillis" -> "1", 63 | "scalikejdbc.global.loggingSQLAndTime.warningLogLevel" -> "warn" 64 | ) 65 | new GuiceApplicationBuilder() 66 | .configure(additionalConfiguration) 67 | .bindings(new PlayDBApiAdapterModule) 68 | .disable(classOf[DBModule]) 69 | .build() 70 | } 71 | 72 | def simpleTest(table: String) = { 73 | 74 | try { 75 | DB autoCommit { implicit s => 76 | SQL("DROP TABLE " + table + " IF EXISTS").execute.apply() 77 | SQL( 78 | "CREATE TABLE " + table + " (ID BIGINT PRIMARY KEY NOT NULL, NAME VARCHAR(256))" 79 | ).execute.apply() 80 | val insert = SQL( 81 | "INSERT INTO " + table + " (ID, NAME) VALUES (/*'id*/123, /*'name*/'Alice')" 82 | ) 83 | insert.bindByName("id" -> 1, "name" -> "Alice").update.apply() 84 | insert.bindByName("id" -> 2, "name" -> "Bob").update.apply() 85 | insert.bindByName("id" -> 3, "name" -> "Eve").update.apply() 86 | } 87 | 88 | NamedDB("legacydb") autoCommit { implicit s => 89 | SQL("DROP TABLE " + table + " IF EXISTS").execute.apply() 90 | SQL( 91 | "CREATE TABLE " + table + " (ID BIGINT PRIMARY KEY NOT NULL, NAME VARCHAR(256))" 92 | ).execute.apply() 93 | val insert = SQL( 94 | "INSERT INTO " + table + " (ID, NAME) VALUES (/*'id*/123, /*'name*/'Alice')" 95 | ) 96 | insert.bindByName("id" -> 1, "name" -> "Alice").update.apply() 97 | insert.bindByName("id" -> 2, "name" -> "Bob").update.apply() 98 | insert.bindByName("id" -> 3, "name" -> "Eve").update.apply() 99 | insert.bindByName("id" -> 4, "name" -> "Fred").update.apply() 100 | } 101 | 102 | case class User(id: Long, name: Option[String]) 103 | 104 | val users = DB readOnly { implicit s => 105 | SQL("SELECT * FROM " + table) 106 | .map(rs => User(rs.long("id"), Option(rs.string("name")))) 107 | .list 108 | .apply() 109 | } 110 | users.size must_== (3) 111 | 112 | val usersInLegacy = NamedDB("legacydb") readOnly { implicit s => 113 | SQL("SELECT * FROM " + table) 114 | .map(rs => User(rs.long("id"), Option(rs.string("name")))) 115 | .list 116 | .apply() 117 | } 118 | usersInLegacy.size must_== (4) 119 | 120 | } finally { 121 | DB autoCommit { implicit s => 122 | SQL("DROP TABLE " + table + " IF EXISTS").execute.apply() 123 | } 124 | NamedDB("legacydb") autoCommit { implicit s => 125 | SQL("DROP TABLE " + table + " IF EXISTS").execute.apply() 126 | } 127 | } 128 | } 129 | 130 | "PlayDBApiAdapterModule" should { 131 | 132 | "be available when DB plugin is also active" in { 133 | running(fakeAppWithDBModule) { simpleTest("user_withdbplugin") } 134 | } 135 | 136 | "not be available when DB plugin is not active" in { 137 | running(fakeAppWithoutDBModule) {} must throwA[RuntimeException] 138 | } 139 | 140 | } 141 | 142 | } 143 | -------------------------------------------------------------------------------- /scalikejdbc-play-dbapi-adapter/test/zentasks/Procfile: -------------------------------------------------------------------------------- 1 | web: target/start -Dhttp.port=${PORT} -Ddb.default.url=$DATABASE_URL 2 | 3 | -------------------------------------------------------------------------------- /scalikejdbc-play-dbapi-adapter/test/zentasks/README: -------------------------------------------------------------------------------- 1 | This advanced todo list demonstrates a modern AJAX-based web application. This is a work in progress, and we plan to add several features in the future releases. For now you can check it out to learn how to: 2 | 3 | - Integrate authentication, and security. 4 | - Use AJAX and the Javascript reverse routing. 5 | - Integrate with compiled assets - LESS CSS and CoffeeScript. -------------------------------------------------------------------------------- /scalikejdbc-play-dbapi-adapter/test/zentasks/app/assets/stylesheets/apps/_tasks.less: -------------------------------------------------------------------------------- 1 | // ----------------------------------- 2 | // TASKS 3 | // ----------------------------------- 4 | // author: mda@zenexity.com - 2011 5 | // ----------------------------------- 6 | 7 | .tasks { 8 | .folder { 9 | .box(); 10 | > header { 11 | position: relative; 12 | padding: 4px 25px 4px 7px; 13 | input { 14 | display: inline-block; 15 | } 16 | input[type=text] { 17 | margin: 1px 0 0; 18 | } 19 | .options, .loader { 20 | position: absolute; 21 | top: 4px; 22 | right: 4px; 23 | } 24 | } 25 | > ul { 26 | > li { 27 | position: relative; 28 | padding: 4px 20px 4px 7px; 29 | border-bottom: 1px solid rgba(0,0,0,.05); 30 | -webkit-user-select: text; 31 | time { 32 | float: right; 33 | display: inline-block; 34 | margin: 0 10px; 35 | border-radius: 15px; 36 | background: url(/assets/images/icons/clock.png) 1px 1px no-repeat; 37 | background-color: @dueDateBackground; 38 | border: 1px solid @dueDateBorder; 39 | color: @dueDateColor; 40 | font-size: 11px; 41 | padding: 0 4px 1px 15px; 42 | } 43 | h4 { 44 | display: inline-block; 45 | font-weight: bold; 46 | } 47 | .deleteTask { 48 | .delete(); 49 | top: 4px; 50 | right: 4px; 51 | } 52 | &:hover .deleteTask { 53 | opacity: 1; 54 | -webkit-transition-delay: 0; 55 | } 56 | .assignedTo { 57 | float: right; 58 | display: inline-block; 59 | margin: 0 10px; 60 | padding-left: 17px; 61 | color: @assignedToColor; 62 | background: url(/assets/images/icons/user2.png) 0 1px no-repeat; 63 | } 64 | } 65 | } 66 | .addTask { 67 | position: relative; 68 | border-radius: 0 0 4px 4px; 69 | padding: 5px 250px 5px 5px; 70 | background: white; 71 | &:after { 72 | content: " "; 73 | display: block; 74 | clear: both; 75 | } 76 | input { 77 | outline: none; 78 | } 79 | [name=taskBody] { 80 | width: 100%; 81 | border: 0; 82 | } 83 | .dueDate { 84 | position: absolute; 85 | right: 210px; 86 | top: 4px; 87 | width: 140px; 88 | border-radius: 15px; 89 | background: url(/assets/images/icons/clock.png) 2px 2px no-repeat; 90 | background-color: @dueDateBackground; 91 | border: 1px solid @dueDateBorder; 92 | color: @dueDateColor; 93 | font-size: 11px; 94 | padding: 1px 4px 1px 15px; 95 | &::-webkit-input-placeholder { 96 | color: inherit; 97 | } 98 | &:-moz-placeholder { 99 | color: inherit; 100 | } 101 | } 102 | .assignedTo { 103 | position: absolute; 104 | right: 5px; 105 | top: 5px; 106 | width: 195px; 107 | input { 108 | width: 180px; 109 | margin: 2px; 110 | border: 0; 111 | } 112 | } 113 | .assignToList { 114 | display: none; 115 | position: absolute; 116 | top: 100%; 117 | right: 0; 118 | min-width: 100%; 119 | background: rgba(0,0,0,.8); 120 | color: #eee; 121 | } 122 | [type=submit] { 123 | position: absolute; 124 | left: -3000px; 125 | visibility: hidden; 126 | } 127 | ul, div { 128 | display: inline-block; 129 | } 130 | } 131 | .loader { 132 | position: absolute; 133 | top: 5px; 134 | right: 6px; 135 | } 136 | } 137 | } 138 | -------------------------------------------------------------------------------- /scalikejdbc-play-dbapi-adapter/test/zentasks/app/assets/stylesheets/libs/_mate.less: -------------------------------------------------------------------------------- 1 | // ----------------------------------- 2 | // MATE: CSS helpers 3 | // ----------------------------------- 4 | // author: mda@zenexity.com - 2011 5 | // ----------------------------------- 6 | 7 | // ------------------------ GRADIENTS 8 | .gradient(@from:#000, @to:#EEE) { 9 | background: @from; 10 | background-image: -webkit-gradient(linear, left top, left bottom, from(@from), to(@to)); 11 | background-image: -moz-linear-gradient(top, @from, @to); 12 | } 13 | 14 | // ---------------------- TRANSITIONS 15 | .transition(@range: all, @time: 500ms, @ease: ease-in-out) { 16 | -moz-transition: @range @time @ease; 17 | -webkit-transition: @range @time @ease; 18 | -o-transition: @range @time @ease; 19 | transition: @range @time @ease; 20 | } 21 | 22 | // ------------------------ TRANSFORMS 23 | .transform(@props) { 24 | -moz-transform: @arguments; 25 | -webkit-transform: @arguments; 26 | -o-transform: @arguments; 27 | transform: @arguments; 28 | } 29 | 30 | // --------------------------- HELPERS 31 | .ellipsis() { 32 | white-space: nowrap; 33 | text-overflow: ellipsis; 34 | overflow: hidden; 35 | } 36 | 37 | .clear() { 38 | &:after { 39 | display: block; 40 | content: " "; 41 | clear: both; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /scalikejdbc-play-dbapi-adapter/test/zentasks/app/assets/stylesheets/libs/_reset.less: -------------------------------------------------------------------------------- 1 | html, body, div, span, applet, object, iframe, h1, h2, h3, h4, h5, h6, p, blockquote, pre, a, abbr, acronym, address, big, cite, code, del, dfn, em, font, img, ins, kbd, q, s, samp, small, strike, strong, sub, sup, tt, var, dl, dt, dd, ol, ul, li, fieldset, form, label, legend, table, caption, tbody, tfoot, thead, tr, th, td {margin: 0; padding: 0; border: 0; outline: 0; font-weight: inherit; font-style: inherit; font-size: 100%; font-family: inherit;} 2 | 3 | table {border-collapse: collapse; border-spacing: 0;} 4 | caption, th, td {text-align: left; font-weight: normal;} 5 | form legend {display: none;} 6 | blockquote:before, blockquote:after, q:before, q:after {content: "";} 7 | blockquote, q {quotes: "" "";} 8 | ol, ul {list-style: none;} 9 | hr {display: none; visibility: hidden;} 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /scalikejdbc-play-dbapi-adapter/test/zentasks/app/assets/stylesheets/libs/_theme.less: -------------------------------------------------------------------------------- 1 | // ----------------------------------- 2 | // THEME 3 | // ----------------------------------- 4 | // author: mda@zenexity.com - 2011 5 | // ----------------------------------- 6 | 7 | // ---------------------------- COLORS 8 | @mainBackground: #c7d1d8; 9 | @mainColor: #2a3a48; 10 | @drawerBackground: #e1e7ec; 11 | @folderColor: #6f8193; 12 | @projectColor: @mainColor; 13 | @layoutBorderColor: #606d78; 14 | 15 | @links: #4794c4; 16 | @linksHover: #2a5e88; 17 | 18 | @headerLight: #445868; 19 | @headerDark: @mainColor; 20 | @titleColor: #556b7b; 21 | @buttonColor: @mainBackground; 22 | @buttonHover: #fff; 23 | 24 | @activeColor: #5daad5; 25 | 26 | // Tasks 27 | @dueDateBackground: #accfe8; 28 | @dueDateBorder: #73a4ca; 29 | @dueDateColor: #246fa9; 30 | @assignedToColor: @titleColor; 31 | 32 | // Folders 33 | @folderBorder: #9ba5ad; 34 | @folderBackground: #dbe1e5; 35 | @folderHeaderLight: #f2f5f8; 36 | @folderHeaderDark: #dfe2e6; 37 | @folderTitle: #7a8a99; 38 | 39 | // Pannels 40 | @panBackground: rgba(0,0,0,.85); 41 | @panShadow: rgba(0,0,0,.8); 42 | @panText: #aaa; 43 | @panTitle: #fff; 44 | @panBorder: #333; 45 | @panButtonBackground: #444; 46 | @panButtonColor: #fff; 47 | 48 | // ----------------------------- FONTS 49 | @defaultFont: 13px "Lucida Grande","Helvetica Neue", sans-serif; 50 | 51 | // ----------------------------- SIZES 52 | @headerHeight: 40px; 53 | @drawerWidth: 220px; 54 | @navigationWidth: 70px; 55 | @breadcrumbHeight: 50px; 56 | 57 | -------------------------------------------------------------------------------- /scalikejdbc-play-dbapi-adapter/test/zentasks/app/assets/stylesheets/login.less: -------------------------------------------------------------------------------- 1 | // ----------------------------------- 2 | // LOGIN 3 | // ----------------------------------- 4 | // author: mda@zenexity.com - 2011 5 | // ----------------------------------- 6 | 7 | @import 'libs/_reset.less'; 8 | @import 'libs/_mate.less'; 9 | @import 'libs/_theme.less'; 10 | 11 | // ----------------------- MAIN STYLES 12 | body { 13 | background: @mainBackground; 14 | color: @mainColor; 15 | font: @defaultFont; 16 | -webkit-font-smoothing: antialised; 17 | -webkit-user-select: none; 18 | } 19 | 20 | a { 21 | color: @links; 22 | text-decoration: none; 23 | &:hover { 24 | color: @linksHover; 25 | } 26 | } 27 | 28 | p.note { 29 | margin: 10px auto 0; 30 | width: 300px; 31 | padding: 20px; 32 | text-align: center; 33 | color: #445868; 34 | text-shadow: 1px 1px rgba(255,255,255,.6); 35 | em { 36 | font-weight: bold; 37 | } 38 | } 39 | 40 | form { 41 | margin: 100px auto 0; 42 | width: 300px; 43 | padding: 20px; 44 | background: #fff; 45 | border-radius: 5px; 46 | box-shadow: 0 2px 5px rgba(0,0,0,.3); 47 | text-align: center; 48 | h1 { 49 | margin: 0 0 10px; 50 | font-size: 20px; 51 | font-weight: bold; 52 | } 53 | p { 54 | width: inherit; 55 | margin: 5px 0; 56 | color: #999; 57 | } 58 | p.error { 59 | color: #c00; 60 | margin-bottom: 10px; 61 | text-shadow: 1px 1px rgba(0,0,0,.1); 62 | } 63 | p.success { 64 | color: #83BD41; 65 | margin-bottom: 10px; 66 | text-shadow: 1px 1px rgba(0,0,0,.1); 67 | } 68 | input { 69 | display: block; 70 | width: inherit; 71 | padding: 2px; 72 | background: rgba(0,0,0,.05); 73 | border: 1px solid rgba(0,0,0,.15); 74 | box-shadow: 0 1px 2px rgba(0,0,0,.1) inset; 75 | border-radius: 3px; 76 | font-size: 14px; 77 | &:invalid:not(:focus) { 78 | border-color: red; 79 | } 80 | } 81 | button { 82 | .button(); 83 | display: block; 84 | width: inherit; 85 | font-size: 14px; 86 | } 87 | } 88 | 89 | nav { 90 | margin-top: 15px; 91 | a { 92 | display: inline-block; 93 | margin: 0 4px; 94 | } 95 | } 96 | 97 | // --------------------------- IMPORTS 98 | @import 'main/_widgets.less'; // Some shared elements 99 | @import 'main/_header.less'; // Top header + User bar 100 | 101 | -------------------------------------------------------------------------------- /scalikejdbc-play-dbapi-adapter/test/zentasks/app/assets/stylesheets/main.less: -------------------------------------------------------------------------------- 1 | // ----------------------------------- 2 | // MAIN 3 | // ----------------------------------- 4 | // author: mda@zenexity.com - 2011 5 | // ----------------------------------- 6 | 7 | @import 'libs/_reset.less'; 8 | @import 'libs/_mate.less'; 9 | @import 'libs/_theme.less'; 10 | 11 | // ----------------------- MAIN STYLES 12 | body { 13 | background: @mainBackground; 14 | color: @mainColor; 15 | font: @defaultFont; 16 | -webkit-font-smoothing: antialised; 17 | -webkit-user-select: none; 18 | } 19 | 20 | a { 21 | color: @links; 22 | text-decoration: none; 23 | &:hover { 24 | color: @linksHover; 25 | } 26 | } 27 | 28 | // --------------------------- IMPORTS 29 | @import 'main/_layout.less'; // General grid 30 | @import 'main/_widgets.less'; // Some shared elements 31 | @import 'main/_drawer.less'; // Project drawer 32 | @import 'main/_header.less'; // Top header + User bar 33 | @import 'main/_breadcrumb.less'; // Breadcrumb + App menu 34 | @import 'apps/_tasks.less'; // Tasks 35 | 36 | -------------------------------------------------------------------------------- /scalikejdbc-play-dbapi-adapter/test/zentasks/app/assets/stylesheets/main/_breadcrumb.less: -------------------------------------------------------------------------------- 1 | // ----------------------------------- 2 | // BREADCRUMB 3 | // ----------------------------------- 4 | // author: mda@zenexity.com - 2011 5 | // ----------------------------------- 6 | 7 | #main > header { 8 | height: 39px; 9 | background: url(/assets/images/breadcrumb.png); 10 | border-bottom: 1px solid @layoutBorderColor; 11 | hgroup { 12 | height: inherit; 13 | overflow: hidden; 14 | float: left; 15 | > * { 16 | float: inherit; 17 | position: relative; 18 | height: inherit; 19 | line-height: 40px; 20 | margin-left: -25px; 21 | padding: 0 6px 0 13px; 22 | font-size: 18px; 23 | text-shadow: 1px 1px 0 rgba(255,255,255,.5); 24 | -webkit-border-image: url(/assets/images/breadcrumb-2.png) 0 30 0 20 stretch stretch; 25 | -moz-border-image: url(/assets/images/breadcrumb-2.png) 0 30 0 20 stretch stretch; 26 | border-image: url(/assets/images/breadcrumb-2.png) 0 30 0 20 stretch stretch; 27 | border-width: 0 30px 0 25px; 28 | color: @titleColor; 29 | -webkit-user-select: text; 30 | &:nth-child(2) { 31 | -webkit-border-image: url(/assets/images/breadcrumb-1.png) 0 30 0 1 stretch stretch; 32 | -moz-border-image: url(/assets/images/breadcrumb-1.png) 0 30 0 1 stretch stretch; 33 | border-image: url(/assets/images/breadcrumb-1.png) 0 30 0 2 stretch stretch; 34 | } 35 | &:first-child { 36 | padding-left: 20px; 37 | } 38 | &:nth-child(1) { z-index: 3; } 39 | &:nth-child(2) { z-index: 2; } 40 | &:nth-child(3) { z-index: 1; } 41 | } 42 | } 43 | .users { 44 | position: relative; 45 | margin: 8px 10px; 46 | float: right; 47 | .pannel(); 48 | > dt { 49 | &:before { 50 | content: url(/assets/images/icons/user.png); 51 | padding-right: 4px; 52 | vertical-align: middle; 53 | } 54 | .button(); 55 | } 56 | > dd { 57 | padding: 5px 10px; 58 | width: 300px; 59 | color: @panText; 60 | z-index: 99; 61 | } 62 | .wrap { 63 | overflow: auto; 64 | max-height: 350px; 65 | width: inherit; 66 | } 67 | h3 { 68 | margin: 10px 0 0; 69 | padding: 5px 0; 70 | font-size: 16px; 71 | color: @panTitle; 72 | &:first-of-type { 73 | margin: 0; 74 | } 75 | } 76 | dl { 77 | position: relative; 78 | border-top: 1px solid @panBorder; 79 | padding: 5px 17px 5px 0; 80 | dt { 81 | .ellipsis(); 82 | span { 83 | opacity: .5; 84 | font-size: 11px; 85 | } 86 | } 87 | } 88 | .action { 89 | position: absolute; 90 | top: 5px; 91 | right: 0px; 92 | width: 16px; 93 | height: 16px; 94 | overflow: hidden; 95 | text-indent: -99em; 96 | background: #444 url(/assets/images/icons/addRemove.png) 0 1 no-repeat; 97 | border-radius: 10px; 98 | &:hover { 99 | background-color: green; 100 | } 101 | } 102 | .list .action { 103 | background-position: 0 -19px; 104 | &:hover { 105 | background-color: red; 106 | } 107 | } 108 | } 109 | } 110 | 111 | -------------------------------------------------------------------------------- /scalikejdbc-play-dbapi-adapter/test/zentasks/app/assets/stylesheets/main/_drawer.less: -------------------------------------------------------------------------------- 1 | // ----------------------------------- 2 | // PROJECTS DRAWER 3 | // ----------------------------------- 4 | // author: mda@zenexity.com - 2011 5 | // ----------------------------------- 6 | body { 7 | & > nav { 8 | padding: 10px 0 0; 9 | background: @drawerBackground; 10 | border-right: 1px solid @layoutBorderColor; 11 | } 12 | .dashboard { 13 | display: block; 14 | position: relative; 15 | font-size: 11px; 16 | font-weight: 700; 17 | text-transform: uppercase; 18 | padding: 10px 5px 5px 25px; 19 | background: url(/assets/images/icons/home.png) 6px 7px no-repeat; 20 | a { 21 | color: @folderColor; 22 | cursor: default; 23 | } 24 | } 25 | h4 { 26 | cursor: default; 27 | } 28 | } 29 | 30 | #projects { 31 | input { 32 | margin: 0; 33 | padding: 0; 34 | border: 0; 35 | font: inherit; 36 | } 37 | > li { 38 | position: relative; 39 | padding: 10px 5px 5px 25px; 40 | .options { 41 | position: absolute; 42 | top: 7px; 43 | right: 5px; 44 | button { 45 | border: none; 46 | } 47 | } 48 | .loader { 49 | top: 8px; 50 | right: 6px; 51 | } 52 | li { 53 | position: relative; 54 | padding: 0 0 0 25px; 55 | background: url(/assets/images/icons/folder.png) 1px 1px no-repeat; 56 | a { 57 | display: block; 58 | color: @projectColor; 59 | padding: 2px; 60 | } 61 | input[type=text] { 62 | padding: 2px 1px; 63 | } 64 | .delete { 65 | opacity: 0.1; 66 | } 67 | .loader { 68 | top: 2px; 69 | right: 2px; 70 | } 71 | &:hover { 72 | a { 73 | color: #000; 74 | } 75 | .delete { 76 | opacity: 1; 77 | //-webkit-transition-delay: 0; 78 | } 79 | } 80 | } 81 | .toggle { 82 | content: " "; 83 | position: absolute; 84 | left: 8px; 85 | top: 12px; 86 | display: inline-block; 87 | width: 12px; 88 | height: 12px; 89 | vertical-align: middle; 90 | background: url(/assets/images/icons/drawer.folder.png) 0 0 no-repeat; 91 | } 92 | > h4 { 93 | display: block; 94 | margin: 0 0 5px; 95 | padding: 0 1px; 96 | position: relative; 97 | color: @folderColor; 98 | font-size: 11px; 99 | font-weight: 700; 100 | text-transform: uppercase; 101 | } 102 | > input { 103 | margin: 0 0 5px; 104 | text-transform: uppercase; 105 | font-weight: bold; 106 | font-size: 11px; 107 | } 108 | &.closed { 109 | >ul { 110 | display: none; 111 | } 112 | .toggle { 113 | background-position: 0 -20px; 114 | } 115 | } 116 | } 117 | } 118 | 119 | #activity { 120 | position: absolute; 121 | bottom: 0; 122 | font-size: 11px; 123 | padding: 10px; 124 | } 125 | 126 | #newGroup { 127 | font-size: 13px; 128 | .new(); 129 | margin: 15px 25px; 130 | } 131 | -------------------------------------------------------------------------------- /scalikejdbc-play-dbapi-adapter/test/zentasks/app/assets/stylesheets/main/_header.less: -------------------------------------------------------------------------------- 1 | // ----------------------------------- 2 | // HEADER 3 | // ----------------------------------- 4 | // author: mda@zenexity.com - 2011 5 | // ----------------------------------- 6 | 7 | body { 8 | & > header { 9 | box-sizing: border-box; 10 | padding: 10px; 11 | z-index: 9; 12 | .gradient(@headerLight, @headerDark); 13 | box-shadow: 0 0 7px rgba(0,0,0,.8), 14 | inset 0 1px 0 rgba(255,255,255,.2), 15 | inset 0 -1px 0 rgba(0,0,0,.8); 16 | } 17 | } 18 | 19 | #logo { 20 | color: #fff; 21 | font-weight: bold; 22 | font-size: 16px; 23 | text-transform: uppercase; 24 | letter-spacing: -2px; 25 | text-shadow: 1px 1px 0 #000; 26 | span { 27 | color: @activeColor; 28 | } 29 | } 30 | 31 | #user { 32 | position: absolute; 33 | right: 10px; 34 | top: 10px; 35 | > * { 36 | display: inline-block; 37 | } 38 | dt { 39 | color: #fff; 40 | span { 41 | opacity: .5; 42 | font-size: 11px; 43 | } 44 | } 45 | dd { 46 | a , button { 47 | .button(); 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /scalikejdbc-play-dbapi-adapter/test/zentasks/app/assets/stylesheets/main/_layout.less: -------------------------------------------------------------------------------- 1 | // ----------------------------------- 2 | // MAIN LAYOUT 3 | // ----------------------------------- 4 | // author: mda@zenexity.com - 2011 5 | // ----------------------------------- 6 | 7 | body { 8 | & > header { 9 | position: absolute; 10 | top: 0; 11 | left: 0; 12 | right: 0; 13 | height: @headerHeight; 14 | } 15 | & > nav { 16 | position: absolute; 17 | top: @headerHeight; 18 | left: 0; 19 | width: @drawerWidth; 20 | bottom: 0; 21 | box-sizing: border-box; 22 | } 23 | & > section { 24 | position: absolute; 25 | top: @headerHeight; 26 | left: @drawerWidth; 27 | right: 0; 28 | bottom: 0; 29 | } 30 | } 31 | 32 | #main > header { 33 | position: absolute; 34 | top: 0; 35 | left: 0; 36 | right: 0; 37 | height: @breadcrumbHeight; 38 | } 39 | 40 | #main > article { 41 | position: absolute; 42 | top: 40px; 43 | left: 0; 44 | bottom: 0; 45 | right: 0; 46 | padding: 20px; 47 | overflow: auto; 48 | } 49 | -------------------------------------------------------------------------------- /scalikejdbc-play-dbapi-adapter/test/zentasks/app/assets/stylesheets/main/_widgets.less: -------------------------------------------------------------------------------- 1 | // ----------------------------------- 2 | // WIDGETS 3 | // ----------------------------------- 4 | // author: mda@zenexity.com - 2011 5 | // ----------------------------------- 6 | 7 | // --------------------------- OPTIONS 8 | .pannel(){ 9 | > dd { 10 | //display: none; 11 | .transform(scale(.001)); 12 | .transition(-webkit-transform, 200ms, ease-out); 13 | -webkit-transform-origin: right top; 14 | -moz-transform-origin: right top; 15 | transform-origin: right top; 16 | position: absolute; 17 | top: 100%; 18 | right: -2px; 19 | width: 150px; 20 | margin: 7px 0px 0 0; 21 | padding: 5px; 22 | z-index: 99; 23 | background: @panBackground; 24 | border-radius: 5px; 25 | box-shadow: 0 2px 7px @panShadow; 26 | a, button { 27 | display: block; 28 | width: 100%; 29 | padding: 3px 10px; 30 | color: @panText; 31 | border-radius: 2px; 32 | background: none; 33 | &:hover { 34 | background: @panButtonBackground; 35 | color: @panButtonColor; 36 | } 37 | } 38 | &:before { 39 | content: " "; 40 | display: block; 41 | border-bottom: 6px solid @panBackground; 42 | border-left: 6px solid transparent; 43 | border-right: 6px solid transparent; 44 | border-top: none; 45 | margin-right: 0; 46 | margin-top: -12px; 47 | position: absolute; 48 | right: 5px; 49 | width: 1px; 50 | height: 1px; 51 | } 52 | } 53 | &.opened > dd { 54 | .transform(scale(1)); 55 | } 56 | } 57 | 58 | .button() { 59 | padding: 2px 5px; 60 | border-radius: 3px; 61 | border: 1px solid @headerDark - #111; 62 | .gradient(fadeout(#bff, 80%), fadeout(#bff, 100%)); 63 | background-color: @headerDark; 64 | box-shadow: 0 1px 4px rgba(0,0,0,.3), 65 | inset 0 1px 0 rgba(255,255,255,.2), 66 | inset 0 -1px 0 rgba(0,0,0,.2); 67 | text-shadow: -1px -1px 0 rgba(0,0,0,.3); 68 | color: @buttonColor; 69 | cursor: pointer; 70 | &:hover { 71 | .gradient(fadeout(#bff, 70%), fadeout(#bff, 100%)); 72 | background-color: @headerDark; 73 | color: @buttonHover; 74 | } 75 | } 76 | 77 | .box() { 78 | border: 1px solid @folderBorder; 79 | background: @folderBackground; 80 | border-radius: 5px; 81 | margin: 0 0 20px; 82 | > header { 83 | border-radius: 5px 5px 0 0; 84 | .gradient(@folderHeaderLight, @folderHeaderDark); 85 | border-bottom: inherit; 86 | padding: 4px 7px; 87 | h3 { 88 | display: inline-block; 89 | font-size: 15px; 90 | font-weight: bold; 91 | color: @folderTitle; 92 | text-shadow: 1px 1px 0 #fff; 93 | } 94 | } 95 | } 96 | .options { 97 | width: 20px; 98 | height: 20px; 99 | position: relative; 100 | font-size: 11px; 101 | dt { 102 | width: inherit; 103 | cursor: pointer; 104 | height: inherit; 105 | text-indent: -9999em; 106 | background: url(/assets/images/icons/options.png) 0 0 no-repeat; 107 | } 108 | &:hover dt, &.opened dt, { 109 | background: url(/assets/images/icons/options.png) 0 -20px no-repeat; 110 | } 111 | .pannel(); 112 | } 113 | 114 | .new { 115 | display: inline-block; 116 | .button(); 117 | &:before { 118 | content: "+"; 119 | font-size: 15px; 120 | line-height: 15px; 121 | font-weight: bold; 122 | color: @activeColor; 123 | padding-right: 4px; 124 | } 125 | } 126 | 127 | .delete { 128 | position: absolute; 129 | top: 0px; 130 | right: 0; 131 | border: none; 132 | padding: 0; 133 | width: 18px; 134 | height: 20px; 135 | overflow: hidden; 136 | text-indent: -99em; 137 | background: url(/assets/images/icons/delete.png) 0 1px no-repeat; 138 | .transition(opacity, 300ms, ease-in-out); 139 | -webkit-transition-delay: 100ms; 140 | z-index: 7; 141 | cursor: pointer; 142 | &:hover { 143 | background: url(/assets/images/icons/delete.png) 0 -19px no-repeat; 144 | } 145 | } 146 | 147 | .counter { 148 | color: #888; 149 | font-size: 11px; 150 | text-shadow: 1px 1px 0 rgba(255,255,255,.7); 151 | margin: 2px 5px; 152 | padding: 0px 3px; 153 | background: rgba(0,0,0,.05); 154 | border-radius: 10px; 155 | border: 1px solid rgba(0,0,0,.15); 156 | } 157 | 158 | .loader { 159 | display: none; 160 | overflow: hidden; 161 | text-indent: -99em; 162 | position: absolute; 163 | height: 16px; 164 | width: 16px; 165 | background: url(/assets/images/loading.gif); 166 | } 167 | 168 | -------------------------------------------------------------------------------- /scalikejdbc-play-dbapi-adapter/test/zentasks/app/controllers/Application.scala: -------------------------------------------------------------------------------- 1 | package controllers 2 | 3 | import javax.inject.{ Inject, Singleton } 4 | 5 | import models.{ Project, User, Task } 6 | import play.api.data.Form 7 | import play.api.data.Forms._ 8 | import play.api.mvc._ 9 | import play.api.routing.JavaScriptReverseRouter 10 | import views.html 11 | import scala.concurrent.Future 12 | 13 | @Singleton 14 | class Application @Inject() (controllerComponents: ControllerComponents) 15 | extends AbstractController(controllerComponents) { 16 | 17 | // -- Authentication 18 | 19 | val loginForm = Form( 20 | tuple( 21 | "email" -> text, 22 | "password" -> text 23 | ) verifying ( 24 | "Invalid email or password", 25 | result => 26 | result match { 27 | case (email, password) => User.authenticate(email, password).isDefined 28 | } 29 | ) 30 | ) 31 | 32 | /** 33 | * Login page. 34 | */ 35 | def login = Action.async { implicit request => 36 | Future.successful(Ok(html.login(loginForm))) 37 | } 38 | 39 | /** 40 | * Handle login form submission. 41 | */ 42 | def authenticate = Action.async { implicit request => 43 | Future.successful( 44 | loginForm 45 | .bindFromRequest() 46 | .fold( 47 | formWithErrors => BadRequest(html.login(formWithErrors)), 48 | user => 49 | Redirect(routes.Projects.index()).withSession("email" -> user._1) 50 | ) 51 | ) 52 | } 53 | 54 | /** 55 | * Logout and clean the session. 56 | */ 57 | def logout = Action.async { 58 | Future.successful( 59 | Redirect(routes.Application.login()).withNewSession 60 | .flashing("success" -> "You've been logged out") 61 | ) 62 | } 63 | 64 | // -- Javascript routing 65 | 66 | def javascriptRoutes = Action.async { implicit request => 67 | import routes.javascript._ 68 | Future.successful( 69 | Ok( 70 | JavaScriptReverseRouter("jsRoutes")( 71 | Projects.add, 72 | Projects.delete, 73 | Projects.rename, 74 | Projects.addGroup, 75 | Projects.deleteGroup, 76 | Projects.renameGroup, 77 | Projects.addUser, 78 | Projects.removeUser, 79 | Tasks.addFolder, 80 | Tasks.renameFolder, 81 | Tasks.deleteFolder, 82 | Tasks.index, 83 | Tasks.add, 84 | Tasks.update, 85 | Tasks.delete 86 | ) 87 | ).as("text/javascript") 88 | ) 89 | } 90 | 91 | } 92 | 93 | /** 94 | * Provide security features 95 | */ 96 | trait Secured { self: BaseController => 97 | 98 | /** 99 | * Retrieve the connected user email. 100 | */ 101 | private def username(request: RequestHeader) = request.session.get("email") 102 | 103 | /** 104 | * Redirect to login if the user in not authorized. 105 | */ 106 | private def onUnauthorized(request: RequestHeader) = 107 | Results.Redirect(routes.Application.login()) 108 | 109 | // -- 110 | 111 | /** 112 | * Action for authenticated users. 113 | */ 114 | def IsAuthenticated(f: => String => Request[AnyContent] => Result) = 115 | Security.Authenticated(username, onUnauthorized) { user => 116 | Action(request => f(user)(request)) 117 | } 118 | 119 | /** 120 | * Check if the connected user is a member of this project. 121 | */ 122 | def IsMemberOf(project: Long)(f: => String => Request[AnyContent] => Result) = 123 | IsAuthenticated { user => request => 124 | if (Project.isMember(project, user)) { 125 | f(user)(request) 126 | } else { 127 | Results.Forbidden 128 | } 129 | } 130 | 131 | /** 132 | * Check if the connected user is a owner of this task. 133 | */ 134 | def IsOwnerOf(task: Long)(f: => String => Request[AnyContent] => Result) = 135 | IsAuthenticated { user => request => 136 | if (Task.isOwner(task, user)) { 137 | f(user)(request) 138 | } else { 139 | Results.Forbidden 140 | } 141 | } 142 | 143 | } 144 | -------------------------------------------------------------------------------- /scalikejdbc-play-dbapi-adapter/test/zentasks/app/controllers/Projects.scala: -------------------------------------------------------------------------------- 1 | package controllers 2 | 3 | import javax.inject.{ Inject, Singleton } 4 | 5 | import models._ 6 | import play.api.data.Forms._ 7 | import play.api.data._ 8 | import play.api.mvc._ 9 | import views._ 10 | 11 | /** 12 | * Manage projects related operations. 13 | */ 14 | @Singleton 15 | class Projects @Inject() (controllerComponents: ControllerComponents) 16 | extends AbstractController(controllerComponents) 17 | with Secured { 18 | 19 | /** 20 | * Display the dashboard. 21 | */ 22 | def index = IsAuthenticated { username => _ => 23 | User 24 | .findByEmail(username) 25 | .map { user => 26 | Ok( 27 | html.dashboard( 28 | Project.findInvolving(username), 29 | Task.findTodoInvolving(username), 30 | user 31 | ) 32 | ) 33 | } 34 | .getOrElse(Forbidden) 35 | } 36 | 37 | // -- Projects 38 | 39 | /** 40 | * Add a project. 41 | */ 42 | def add = IsAuthenticated { username => implicit request => 43 | Form("group" -> nonEmptyText) 44 | .bindFromRequest() 45 | .fold( 46 | errors => BadRequest, 47 | folder => 48 | Ok( 49 | views.html.projects.item( 50 | Project.create(NewProject(folder, "New project"), Seq(username)) 51 | ) 52 | ) 53 | ) 54 | } 55 | 56 | /** 57 | * Delete a project. 58 | */ 59 | def delete(project: Long) = IsMemberOf(project) { username => _ => 60 | Project.delete(project) 61 | Ok 62 | } 63 | 64 | /** 65 | * Rename a project. 66 | */ 67 | def rename(project: Long) = IsMemberOf(project) { _ => implicit request => 68 | Form("name" -> nonEmptyText) 69 | .bindFromRequest() 70 | .fold( 71 | errors => BadRequest, 72 | newName => { 73 | Project.rename(project, newName) 74 | Ok(newName) 75 | } 76 | ) 77 | } 78 | 79 | // -- Project groups 80 | 81 | /** 82 | * Add a new project group. 83 | */ 84 | def addGroup = IsAuthenticated { _ => _ => 85 | Ok(html.projects.group("New group")) 86 | } 87 | 88 | /** 89 | * Delete a project group. 90 | */ 91 | def deleteGroup(folder: String) = IsAuthenticated { _ => _ => 92 | Project.deleteInFolder(folder) 93 | Ok 94 | } 95 | 96 | /** 97 | * Rename a project group. 98 | */ 99 | def renameGroup(folder: String) = IsAuthenticated { _ => implicit request => 100 | Form("name" -> nonEmptyText) 101 | .bindFromRequest() 102 | .fold( 103 | errors => BadRequest, 104 | newName => { Project.renameFolder(folder, newName); Ok(newName) } 105 | ) 106 | } 107 | 108 | // -- Members 109 | 110 | /** 111 | * Add a project member. 112 | */ 113 | def addUser(project: Long) = IsMemberOf(project) { _ => implicit request => 114 | Form("user" -> nonEmptyText) 115 | .bindFromRequest() 116 | .fold( 117 | errors => BadRequest, 118 | user => { Project.addMember(project, user); Ok } 119 | ) 120 | } 121 | 122 | /** 123 | * Remove a project member. 124 | */ 125 | def removeUser(project: Long) = IsMemberOf(project) { _ => implicit request => 126 | Form("user" -> nonEmptyText) 127 | .bindFromRequest() 128 | .fold( 129 | errors => BadRequest, 130 | user => { Project.removeMember(project, user); Ok } 131 | ) 132 | } 133 | 134 | } 135 | -------------------------------------------------------------------------------- /scalikejdbc-play-dbapi-adapter/test/zentasks/app/controllers/Tasks.scala: -------------------------------------------------------------------------------- 1 | package controllers 2 | 3 | import javax.inject.{ Inject, Singleton } 4 | 5 | import models._ 6 | import play.api.data.Forms._ 7 | import play.api.data._ 8 | import play.api.mvc.{ AbstractController, ControllerComponents } 9 | import views._ 10 | import scala.concurrent.Future 11 | 12 | /** 13 | * Manage tasks related operations. 14 | */ 15 | @Singleton 16 | class Tasks @Inject() (controllerComponents: ControllerComponents) 17 | extends AbstractController(controllerComponents) 18 | with Secured { 19 | 20 | /** 21 | * Display the tasks panel for this project. 22 | */ 23 | def index(project: Long) = IsMemberOf(project) { _ => implicit request => 24 | Project 25 | .findById(project) 26 | .map { p => 27 | val tasks = Task.findByProject(project) 28 | val team = Project.membersOf(project) 29 | Ok(html.tasks.index(p, tasks, team)) 30 | } 31 | .getOrElse(NotFound) 32 | } 33 | 34 | val taskForm = Form( 35 | tuple( 36 | "title" -> nonEmptyText, 37 | "dueDate" -> optional(date("MM/dd/yy")), 38 | "assignedTo" -> optional(text) 39 | ) 40 | ) 41 | 42 | // -- Tasks 43 | 44 | /** 45 | * Create a task in this project. 46 | */ 47 | def add(project: Long, folder: String) = IsMemberOf(project) { 48 | _ => implicit request => 49 | taskForm 50 | .bindFromRequest() 51 | .fold( 52 | errors => BadRequest, 53 | { case (title, dueDate, assignedTo) => 54 | val task = Task.create( 55 | NewTask(folder, project, title, false, dueDate, assignedTo) 56 | ) 57 | Ok(html.tasks.item(task)) 58 | } 59 | ) 60 | } 61 | 62 | /** 63 | * Update a task 64 | */ 65 | def update(task: Long) = IsOwnerOf(task) { _ => implicit request => 66 | Form("done" -> boolean) 67 | .bindFromRequest() 68 | .fold( 69 | errors => BadRequest, 70 | isDone => { 71 | Task.markAsDone(task, isDone) 72 | Ok 73 | } 74 | ) 75 | } 76 | 77 | /** 78 | * Delete a task 79 | */ 80 | def delete(task: Long) = IsOwnerOf(task) { _ => implicit request => 81 | Task.delete(task) 82 | Ok 83 | } 84 | 85 | // -- Task folders 86 | 87 | /** 88 | * Add a new folder. 89 | */ 90 | def addFolder = Action.async { 91 | Future.successful(Ok(html.tasks.folder("New folder"))) 92 | } 93 | 94 | /** 95 | * Delete a full tasks folder. 96 | */ 97 | def deleteFolder(project: Long, folder: String) = IsMemberOf(project) { 98 | _ => implicit request => 99 | Task.deleteInFolder(project, folder) 100 | Ok 101 | } 102 | 103 | /** 104 | * Rename a tasks folder. 105 | */ 106 | def renameFolder(project: Long, folder: String) = IsMemberOf(project) { 107 | _ => implicit request => 108 | Form("name" -> nonEmptyText) 109 | .bindFromRequest() 110 | .fold( 111 | errors => BadRequest, 112 | newName => { 113 | Task.renameFolder(project, folder, newName) 114 | Ok(newName) 115 | } 116 | ) 117 | } 118 | 119 | } 120 | -------------------------------------------------------------------------------- /scalikejdbc-play-dbapi-adapter/test/zentasks/app/models/Project.scala: -------------------------------------------------------------------------------- 1 | package models 2 | 3 | import scalikejdbc._ 4 | 5 | case class ProjectMember(projectId: Long, userEmail: String) 6 | 7 | object ProjectMember extends SQLSyntaxSupport[ProjectMember] { 8 | def apply(syntax: SyntaxProvider[ProjectMember])(rs: WrappedResultSet) = { 9 | val p = syntax.resultName 10 | new ProjectMember( 11 | projectId = rs.long(p.projectId), 12 | userEmail = rs.string(p.userEmail) 13 | ) 14 | } 15 | } 16 | 17 | case class NewProject(folder: String, name: String) 18 | 19 | case class Project(id: Long, folder: String, name: String) 20 | 21 | object Project extends SQLSyntaxSupport[Project] { 22 | 23 | def apply(syntax: SyntaxProvider[Project])(rs: WrappedResultSet) = { 24 | val p = syntax.resultName 25 | new Project( 26 | id = rs.long(p.id), 27 | folder = rs.string(p.folder), 28 | name = rs.string(p.name) 29 | ) 30 | } 31 | 32 | private val p = Project.syntax("p") 33 | private val u = User.syntax("u") 34 | private val m = ProjectMember.syntax("m") 35 | 36 | private val auto = AutoSession 37 | 38 | def findById(id: Long)(implicit s: DBSession = auto): Option[Project] = 39 | withSQL { 40 | select.from(Project as p).where.eq(p.id, id) 41 | }.map(Project(p)).single.apply() 42 | 43 | def findInvolving(user: String)(implicit s: DBSession = auto): Seq[Project] = 44 | withSQL { 45 | select 46 | .from(Project as p) 47 | .join(ProjectMember as m) 48 | .on(p.id, m.projectId) 49 | .where 50 | .eq(m.userEmail, user) 51 | }.map(Project(p)).list.apply() 52 | 53 | def rename(id: Long, newName: String)(implicit s: DBSession = auto): Unit = 54 | applyUpdate { 55 | update(Project as p).set(p.name -> newName).where.eq(p.id, id) 56 | } 57 | 58 | def delete(id: Long)(implicit s: DBSession = auto): Unit = applyUpdate { 59 | deleteFrom(Project as p).where.eq(p.id, id) 60 | } 61 | 62 | def deleteInFolder(folder: String)(implicit s: DBSession = auto): Unit = 63 | applyUpdate { 64 | deleteFrom(Project as p).where.eq(p.folder, folder) 65 | } 66 | 67 | def renameFolder(folder: String, newName: String)(implicit 68 | s: DBSession = auto 69 | ): Unit = applyUpdate { 70 | update(Project as p).set(p.folder -> newName).where.eq(p.folder, folder) 71 | } 72 | 73 | def membersOf(project: Long)(implicit s: DBSession = auto): Seq[User] = 74 | withSQL { 75 | select 76 | .from(User as u) 77 | .join(ProjectMember as m) 78 | .on(m.userEmail, u.email) 79 | .where 80 | .eq(m.projectId, project) 81 | }.map(User(u)).list.apply() 82 | 83 | def addMember(project: Long, user: String)(implicit 84 | s: DBSession = auto 85 | ): Unit = applyUpdate { 86 | insert.into(ProjectMember).values(project, user) 87 | } 88 | 89 | def removeMember(project: Long, user: String)(implicit 90 | s: DBSession = auto 91 | ): Unit = applyUpdate { 92 | deleteFrom(ProjectMember as m).where 93 | .eq(m.projectId, project) 94 | .and 95 | .eq(m.userEmail, user) 96 | } 97 | 98 | def isMember(project: Long, user: String)(implicit 99 | s: DBSession = auto 100 | ): Boolean = withSQL { 101 | select(sqls"count(${u.email}) = 1 as is_member") 102 | .from(User as u) 103 | .join(ProjectMember as m) 104 | .on(m.userEmail, u.email) 105 | .where 106 | .eq(m.projectId, project) 107 | .and 108 | .eq(u.email, user) 109 | }.map(rs => rs.boolean("is_member").asInstanceOf[Boolean]) 110 | .single 111 | .apply() 112 | .getOrElse(false) 113 | 114 | def create(project: NewProject, members: Seq[String])(implicit 115 | s: DBSession = auto 116 | ): Project = { 117 | // Insert the project 118 | val newId = sql"select next value for project_seq as v from dual" 119 | .map(_.long("v")) 120 | .single 121 | .apply() 122 | .get 123 | applyUpdate { 124 | insert.into(Project).values(newId, project.name, project.folder) 125 | } 126 | // Add members 127 | members foreach { email => 128 | applyUpdate(insert.into(ProjectMember).values(newId, email)) 129 | } 130 | Project(id = newId, name = project.name, folder = project.folder) 131 | } 132 | 133 | } 134 | -------------------------------------------------------------------------------- /scalikejdbc-play-dbapi-adapter/test/zentasks/app/models/Task.scala: -------------------------------------------------------------------------------- 1 | package models 2 | 3 | import java.util.Date 4 | 5 | import scalikejdbc._ 6 | 7 | case class NewTask( 8 | folder: String, 9 | project: Long, 10 | title: String, 11 | done: Boolean, 12 | dueDate: Option[Date], 13 | assignedTo: Option[String] 14 | ) 15 | 16 | case class Task( 17 | id: Long, 18 | folder: String, 19 | project: Long, 20 | title: String, 21 | done: Boolean, 22 | dueDate: Option[Date], 23 | assignedTo: Option[String] 24 | ) 25 | 26 | object Task extends SQLSyntaxSupport[Task] { 27 | 28 | def apply(syntax: SyntaxProvider[Task])(rs: WrappedResultSet) = { 29 | val t = syntax.resultName 30 | new Task( 31 | id = rs.long(t.id), 32 | folder = rs.string(t.folder), 33 | project = rs.long(t.project), 34 | title = rs.string(t.title), 35 | done = rs.boolean(t.done), 36 | dueDate = rs.timestampOpt(t.dueDate), 37 | assignedTo = rs.stringOpt(t.assignedTo) 38 | ) 39 | } 40 | 41 | def apply(t: SyntaxProvider[Task], p: SyntaxProvider[Project])( 42 | rs: WrappedResultSet 43 | ): (Task, Project) = (Task(t)(rs), Project(p)(rs)) 44 | 45 | private val t = Task.syntax("t") 46 | private val p = Project.syntax("p") 47 | private val m = ProjectMember.syntax("m") 48 | 49 | private val auto = AutoSession 50 | 51 | def findById(id: Long)(implicit s: DBSession = auto): Option[Task] = withSQL { 52 | select.from(Task as t).where.eq(t.id, id) 53 | }.map(Task(t)).single.apply() 54 | 55 | def findTodoInvolving( 56 | user: String 57 | )(implicit s: DBSession = auto): Seq[(Task, Project)] = withSQL { 58 | select 59 | .from(Task as t) 60 | .join(ProjectMember as m) 61 | .on(m.projectId, t.project) 62 | .join(Project as p) 63 | .on(p.id, m.projectId) 64 | .where 65 | .append(sqls"${t.done} = false") 66 | .and 67 | .eq(m.userEmail, user) 68 | }.map(Task(t, p)).list.apply() 69 | 70 | def findByProject(project: Long)(implicit s: DBSession = auto): Seq[Task] = 71 | withSQL { 72 | select.from(Task as t).where.eq(t.project, project) 73 | }.map(Task(t)).list.apply() 74 | 75 | /** 76 | * Delete a task 77 | */ 78 | def delete(id: Long)(implicit s: DBSession = auto): Unit = applyUpdate { 79 | deleteFrom(Task as t).where.eq(t.id, id) 80 | } 81 | 82 | def deleteInFolder(projectId: Long, folder: String)(implicit 83 | s: DBSession = auto 84 | ): Unit = applyUpdate { 85 | deleteFrom(Task as t).where 86 | .eq(t.project, projectId) 87 | .and 88 | .eq(t.folder, folder) 89 | } 90 | 91 | def markAsDone(taskId: Long, done: Boolean)(implicit 92 | s: DBSession = auto 93 | ): Unit = applyUpdate { 94 | update(Task as t).set(t.done -> done).where.eq(t.id, taskId) 95 | } 96 | 97 | def renameFolder(projectId: Long, folder: String, newName: String)(implicit 98 | s: DBSession = auto 99 | ): Unit = applyUpdate { 100 | update(Task as t) 101 | .set(t.folder -> newName) 102 | .where 103 | .eq(t.folder, folder) 104 | .and 105 | .eq(t.project, projectId) 106 | } 107 | 108 | def isOwner(task: Long, user: String)(implicit s: DBSession = auto): Boolean = 109 | withSQL { 110 | select(sqls"count(${t.id}) = 1 as v") 111 | .from(Task as t) 112 | .join(Project as p) 113 | .on(t.project, p.id) 114 | .join(ProjectMember as m) 115 | .on(m.projectId, p.id) 116 | .where 117 | .eq(m.userEmail, user) 118 | .and 119 | .eq(t.id, task) 120 | }.map(rs => rs.boolean("v").asInstanceOf[Boolean]) 121 | .single 122 | .apply() 123 | .getOrElse(false) 124 | 125 | def create(task: NewTask)(implicit s: DBSession = auto): Task = { 126 | val newId = sql"select next value for task_seq as v from dual" 127 | .map(rs => rs.long("v")) 128 | .single 129 | .apply() 130 | .get 131 | applyUpdate { 132 | insert 133 | .into(Task) 134 | .values( 135 | newId, 136 | task.title, 137 | task.done, 138 | task.dueDate, 139 | task.assignedTo, 140 | task.project, 141 | task.folder 142 | ) 143 | } 144 | Task( 145 | id = newId, 146 | folder = task.folder, 147 | project = task.project, 148 | title = task.title, 149 | done = task.done, 150 | dueDate = task.dueDate, 151 | assignedTo = task.assignedTo 152 | ) 153 | } 154 | 155 | } 156 | -------------------------------------------------------------------------------- /scalikejdbc-play-dbapi-adapter/test/zentasks/app/models/User.scala: -------------------------------------------------------------------------------- 1 | package models 2 | 3 | import scalikejdbc._ 4 | 5 | case class User(email: String, name: String, password: String) 6 | 7 | object User extends SQLSyntaxSupport[User] { 8 | 9 | override val tableName = "users" 10 | override val columns = Seq("email", "name", "password") 11 | 12 | def apply(syntax: SyntaxProvider[User])(rs: WrappedResultSet) = { 13 | val u = syntax.resultName 14 | new User( 15 | email = rs.string(u.email), 16 | name = rs.string(u.name), 17 | password = rs.string(u.password) 18 | ) 19 | } 20 | 21 | private val u = User.syntax("u") 22 | 23 | private val auto = AutoSession 24 | 25 | def findByEmail(email: String)(implicit s: DBSession = auto): Option[User] = 26 | withSQL { 27 | select.from(User as u).where.eq(u.email, email) 28 | }.map(User(u)).single.apply() 29 | 30 | def findAll()(implicit s: DBSession = auto): Seq[User] = withSQL { 31 | select.from(User as u) 32 | }.map(User(u)).list.apply() 33 | 34 | def authenticate(email: String, password: String)(implicit 35 | s: DBSession = auto 36 | ): Option[User] = withSQL { 37 | select.from(User as u).where.eq(u.email, email).and.eq(u.password, password) 38 | }.map(User(u)).single.apply() 39 | 40 | def create(user: User)(implicit s: DBSession = auto): User = { 41 | applyUpdate { 42 | insert.into(User).values(user.email, user.name, user.password) 43 | } 44 | user 45 | } 46 | 47 | } 48 | -------------------------------------------------------------------------------- /scalikejdbc-play-dbapi-adapter/test/zentasks/app/views/dashboard.scala.html: -------------------------------------------------------------------------------- 1 | @(projects: Seq[Project], todoTasks: Seq[(Task,Project)], user: User) 2 | 3 | @main(projects, user){ 4 | 5 |
6 |
7 |

Dashboard

8 |

Tasks over all projects

9 |
10 |
11 | 12 |
13 | @todoTasks.groupBy(_._2).map { 14 | case (project, projectTasks) => { 15 |
16 |
17 |

@project.name

18 | Loading 19 |
20 | 27 |
28 | } 29 | } 30 |
31 | 32 | } 33 | 34 | -------------------------------------------------------------------------------- /scalikejdbc-play-dbapi-adapter/test/zentasks/app/views/login.scala.html: -------------------------------------------------------------------------------- 1 | @(form: Form[(String,String)])(implicit flash: Flash) 2 | 3 | 4 | 5 | Zentasks 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 |
14 | 15 | @helper.form(routes.Application.authenticate()) { 16 | 17 |

Sign in

18 | 19 | @form.globalError.map { error => 20 |

21 | @error.message 22 |

23 | } 24 | 25 | @flash.get("success").map { message => 26 |

27 | @message 28 |

29 | } 30 | 31 |

32 | 33 |

34 |

35 | 36 |

37 |

38 | 39 |

40 | 41 | } 42 | 43 |

44 | Try guillaume@@sample.com with secret as password. 45 |

46 | 47 | 48 | 49 | 50 | 51 | 52 | -------------------------------------------------------------------------------- /scalikejdbc-play-dbapi-adapter/test/zentasks/app/views/main.scala.html: -------------------------------------------------------------------------------- 1 | @(projects: Seq[Project], user: User)(body: Html) 2 | 3 | 4 | 5 | Zentasks 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 |
19 |
@user.name (@user.email)
20 |
21 | Logout 22 |
23 |
24 |
25 | 36 |
37 | @body 38 |
39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /scalikejdbc-play-dbapi-adapter/test/zentasks/app/views/projects/group.scala.html: -------------------------------------------------------------------------------- 1 | @(group: String, projects: Seq[Project] = Nil) 2 | 3 |
  • 4 | 5 |

    @group

    6 | Loading 7 |
    8 |
    Options
    9 |
    10 | 11 | 12 |
    13 |
    14 | 19 |
  • 20 | -------------------------------------------------------------------------------- /scalikejdbc-play-dbapi-adapter/test/zentasks/app/views/projects/item.scala.html: -------------------------------------------------------------------------------- 1 | @(project: Project) 2 | 3 |
  • 4 | @project.name 5 | 6 | Loading 7 |
  • 8 | -------------------------------------------------------------------------------- /scalikejdbc-play-dbapi-adapter/test/zentasks/app/views/tasks/folder.scala.html: -------------------------------------------------------------------------------- 1 | @(folder: String, tasks: Seq[Task] = Nil) 2 | 3 |
    4 |
    5 | 6 |

    @folder

    7 | 8 |
    9 |
    Options
    10 |
    11 | Remove complete tasks 12 | Remove all tasks 13 | Delete folder 14 |
    15 |
    16 | Loading 17 |
    18 | 23 |
    24 | 25 | 26 | 27 |
    28 | 29 |
    30 | 31 |
    32 |
    33 | 34 | -------------------------------------------------------------------------------- /scalikejdbc-play-dbapi-adapter/test/zentasks/app/views/tasks/index.scala.html: -------------------------------------------------------------------------------- 1 | @(project:Project, tasks: Seq[Task], team: Seq[User]) 2 | 3 |
    4 |
    5 |

    @project.folder

    6 |

    @project.name

    7 |
    8 |
    9 |
    Project's team
    10 |
    11 |
    12 |

    Team mates

    13 |
    14 | @team.map { user => 15 |
    16 |
    @user.name (@user.email)
    17 |
    Action
    18 |
    19 | } 20 |
    21 |

    Add a team mate

    22 |
    23 | @User.findAll().diff(team).map { user => 24 |
    25 |
    @user.name (@user.email)
    26 |
    Action
    27 |
    28 | } 29 |
    30 |
    31 |
    32 |
    33 |
    34 |
    35 | @tasks.groupBy(_.folder).map { 36 | case (folder, tasks) => { 37 | @views.html.tasks.folder(folder, tasks) 38 | } 39 | } 40 | New folder 41 |
    42 | 43 | -------------------------------------------------------------------------------- /scalikejdbc-play-dbapi-adapter/test/zentasks/app/views/tasks/item.scala.html: -------------------------------------------------------------------------------- 1 | @(task: Task, isEditable: Boolean = true) 2 | 3 |
  • 4 | 5 | @if(isEditable) { 6 | 7 | } 8 | 9 |

    @task.title

    10 | 11 | @task.dueDate.map { date => 12 | 13 | } 14 | 15 | @task.assignedTo.map { user => 16 | @user 17 | } 18 | 19 | @if(isEditable) { 20 | Delete task 21 | Loading 22 | } 23 | 24 |
  • 25 | -------------------------------------------------------------------------------- /scalikejdbc-play-dbapi-adapter/test/zentasks/conf/application.conf: -------------------------------------------------------------------------------- 1 | # Configuration 2 | 3 | application.name=Zentasks 4 | 5 | # Secret key 6 | # ~~~~~ 7 | # The secret key is used to secure cryptographics functions. 8 | # If you deploy your application to several instances be sure to use the same key! 9 | application.secret="E27D^[_9W" 10 | 11 | # Database configuration 12 | # ~~~~~ 13 | # You can declare as many datasources as you want. 14 | # By convention, the default datasource is named `default` 15 | db.default.driver=org.h2.Driver 16 | db.default.url="jdbc:h2:mem:play;DB_CLOSE_DELAY=-1" 17 | db.default.username=sa 18 | db.secondary.driver=org.h2.Driver 19 | db.secondary.url="jdbc:h2:mem:secondary;DB_CLOSE_DELAY=-1" 20 | db.default.fixtures.dev=[ "users.sql", "project.sql", "project_member.sql", "task.sql" ] 21 | db.default.fixtures.test=[ "users.sql", "project.sql", "project_member.sql", "task.sql" ] 22 | db.secondary.fixtures.test=[ "users.sql", "project.sql", "project_member.sql", "task.sql" ] 23 | 24 | #db.default.password=sa 25 | 26 | # ScalikeJDBC original configuration 27 | #db.default.poolInitialSize=10 28 | #db.default.poolMaxSize=10 29 | #db.default.poolValidationQuery= 30 | 31 | scalikejdbc.global.loggingSQLAndTime.enabled=true 32 | #scalikejdbc.global.loggingSQLAndTime.singleLineMode=true 33 | scalikejdbc.global.loggingSQLAndTime.logLevel=debug 34 | scalikejdbc.global.loggingSQLAndTime.warningEnabled=true 35 | scalikejdbc.global.loggingSQLAndTime.warningThresholdMillis=5 36 | scalikejdbc.global.loggingSQLAndTime.warningLogLevel=warn 37 | 38 | # You can disable the default DB plugin 39 | # dbplugin=disabled 40 | # evolutionplugin=disabled 41 | 42 | # Logger 43 | # ~~~~~ 44 | # You can also configure logback (http://logback.qos.ch/), by providing a logger.xml file in the conf directory . 45 | 46 | # Root logger: 47 | logger.root=DEBUG 48 | 49 | # Logger used by the framework: 50 | logger.play=DEBUG 51 | 52 | # Logger provided to your application: 53 | logger.application=DEBUG 54 | 55 | play.modules.enabled += "scalikejdbc.PlayModule" 56 | -------------------------------------------------------------------------------- /scalikejdbc-play-dbapi-adapter/test/zentasks/conf/db/fixtures/default/project.sql: -------------------------------------------------------------------------------- 1 | # --- !Ups 2 | 3 | INSERT INTO project (id, name, folder) VALUES (1, 'Play 2.0', 'Play framework'); 4 | INSERT INTO project (id, name, folder) VALUES (2, 'Play 1.2.4', 'Play framework'); 5 | INSERT INTO project (id, name, folder) VALUES (3, 'Website', 'Play framework'); 6 | INSERT INTO project (id, name, folder) VALUES (4, 'Secret project', 'Zenexity'); 7 | INSERT INTO project (id, name, folder) VALUES (5, 'Playmate', 'Zenexity'); 8 | INSERT INTO project (id, name, folder) VALUES (6, 'Things to do', 'Personal'); 9 | INSERT INTO project (id, name, folder) VALUES (7, 'Play samples', 'Zenexity'); 10 | INSERT INTO project (id, name, folder) VALUES (8, 'Private', 'Personal'); 11 | INSERT INTO project (id, name, folder) VALUES (9, 'Private', 'Personal'); 12 | INSERT INTO project (id, name, folder) VALUES (10, 'Private', 'Personal'); 13 | INSERT INTO project (id, name, folder) VALUES (11, 'Private', 'Personal'); 14 | ALTER SEQUENCE project_seq RESTART WITH 12; 15 | 16 | # --- !Downs 17 | ALTER SEQUENCE project_seq RESTART WITH 1; 18 | DELETE FROM project; -------------------------------------------------------------------------------- /scalikejdbc-play-dbapi-adapter/test/zentasks/conf/db/fixtures/default/project_member.sql: -------------------------------------------------------------------------------- 1 | # --- !Ups 2 | 3 | INSERT INTO project_member (project_id, user_email) VALUES (1, 'guillaume@sample.com'); 4 | INSERT INTO project_member (project_id, user_email) VALUES (1, 'maxime@sample.com'); 5 | INSERT INTO project_member (project_id, user_email) VALUES (1, 'sadek@sample.com'); 6 | INSERT INTO project_member (project_id, user_email) VALUES (1, 'erwan@sample.com'); 7 | INSERT INTO project_member (project_id, user_email) VALUES (2, 'guillaume@sample.com'); 8 | INSERT INTO project_member (project_id, user_email) VALUES (2, 'erwan@sample.com'); 9 | INSERT INTO project_member (project_id, user_email) VALUES (3, 'guillaume@sample.com'); 10 | INSERT INTO project_member (project_id, user_email) VALUES (3, 'maxime@sample.com'); 11 | INSERT INTO project_member (project_id, user_email) VALUES (4, 'guillaume@sample.com'); 12 | INSERT INTO project_member (project_id, user_email) VALUES (4, 'maxime@sample.com'); 13 | INSERT INTO project_member (project_id, user_email) VALUES (4, 'sadek@sample.com'); 14 | INSERT INTO project_member (project_id, user_email) VALUES (4, 'erwan@sample.com'); 15 | INSERT INTO project_member (project_id, user_email) VALUES (5, 'maxime@sample.com'); 16 | INSERT INTO project_member (project_id, user_email) VALUES (6, 'guillaume@sample.com'); 17 | INSERT INTO project_member (project_id, user_email) VALUES (7, 'guillaume@sample.com'); 18 | INSERT INTO project_member (project_id, user_email) VALUES (7, 'maxime@sample.com'); 19 | INSERT INTO project_member (project_id, user_email) VALUES (8, 'maxime@sample.com'); 20 | INSERT INTO project_member (project_id, user_email) VALUES (9, 'guillaume@sample.com'); 21 | INSERT INTO project_member (project_id, user_email) VALUES (10, 'erwan@sample.com'); 22 | INSERT INTO project_member (project_id, user_email) VALUES (11, 'sadek@sample.com'); 23 | 24 | # --- !Downs 25 | 26 | DELETE FROM project_member; 27 | -------------------------------------------------------------------------------- /scalikejdbc-play-dbapi-adapter/test/zentasks/conf/db/fixtures/default/task.sql: -------------------------------------------------------------------------------- 1 | # --- !Ups 2 | 3 | INSERT INTO task (id, title, done, due_date, assigned_to, project, folder) VALUES (1000, 'Fix the documentation', FALSE, null, 'guillaume@sample.com', 1, 'Todo'); 4 | INSERT INTO task (id, title, done, due_date, assigned_to, project, folder) VALUES (1001, 'Prepare the beta release', FALSE, '2011-11-15 00:00:00.0', null, 1, 'Urgent'); 5 | INSERT INTO task (id, title, done, due_date, assigned_to, project, folder) VALUES (1002, 'Buy some milk', FALSE, null, null, 9, 'Todo'); 6 | INSERT INTO task (id, title, done, due_date, assigned_to, project, folder) VALUES (1003, 'Check 1.2.4-RC2', FALSE, '2011-11-18 00:00:00.0', 'guillaume@sample.com', 2, 'Todo'); 7 | INSERT INTO task (id, title, done, due_date, assigned_to, project, folder) VALUES (1004, 'Finish zentask integration', TRUE, '2011-11-15 00:00:00.0', 'maxime@sample.com', 7, 'Todo'); 8 | INSERT INTO task (id, title, done, due_date, assigned_to, project, folder) VALUES (1005, 'Release the secret project', FALSE, '2012-01-01 00:00:00.0', 'sadek@sample.com', 4, 'Todo'); 9 | ALTER SEQUENCE task_seq RESTART WITH 1006; 10 | 11 | # --- !Downs 12 | ALTER SEQUENCE task_seq RESTART WITH 1000; 13 | DELETE FROM task; 14 | 15 | -------------------------------------------------------------------------------- /scalikejdbc-play-dbapi-adapter/test/zentasks/conf/db/fixtures/default/users.sql: -------------------------------------------------------------------------------- 1 | # --- !Ups 2 | INSERT INTO users (email, name, password) VALUES ('guillaume@sample.com', 'Guillaume Bort', 'secret'); 3 | INSERT INTO users (email, name, password) VALUES ('maxime@sample.com', 'Maxime Dantec', 'secret'); 4 | INSERT INTO users (email, name, password) VALUES ('sadek@sample.com', 'Sadek Drobi', 'secret'); 5 | INSERT INTO users (email, name, password) VALUES ('erwan@sample.com', 'Erwan Loisant', 'secret'); 6 | 7 | 8 | # --- !Downs 9 | DELETE FROM users; 10 | -------------------------------------------------------------------------------- /scalikejdbc-play-dbapi-adapter/test/zentasks/conf/db/fixtures/secondary/project.sql: -------------------------------------------------------------------------------- 1 | # --- !Ups 2 | 3 | INSERT INTO project (id, name, folder) VALUES (1, 'Play 2.0', 'Play framework'); 4 | INSERT INTO project (id, name, folder) VALUES (2, 'Play 1.2.4', 'Play framewor'); 5 | INSERT INTO project (id, name, folder) VALUES (3, 'Website', 'Play framework'); 6 | INSERT INTO project (id, name, folder) VALUES (4, 'Secret project', 'Zenexity'); 7 | INSERT INTO project (id, name, folder) VALUES (5, 'Playmate', 'Zenexity'); 8 | INSERT INTO project (id, name, folder) VALUES (6, 'Things to do', 'Personal'); 9 | INSERT INTO project (id, name, folder) VALUES (7, 'Play samples', 'Zenexity'); 10 | INSERT INTO project (id, name, folder) VALUES (8, 'Private', 'Personal'); 11 | INSERT INTO project (id, name, folder) VALUES (9, 'Private', 'Personal'); 12 | INSERT INTO project (id, name, folder) VALUES (10, 'Private', 'Personal'); 13 | INSERT INTO project (id, name, folder) VALUES (11, 'Private', 'Personal'); 14 | ALTER SEQUENCE project_seq RESTART WITH 12; 15 | 16 | # --- !Downs 17 | ALTER SEQUENCE project_seq RESTART WITH 1; 18 | DELETE FROM project; -------------------------------------------------------------------------------- /scalikejdbc-play-dbapi-adapter/test/zentasks/conf/db/fixtures/secondary/project_member.sql: -------------------------------------------------------------------------------- 1 | # --- !Ups 2 | 3 | INSERT INTO project_member (project_id, user_email) VALUES (1, 'guillaume@sample.com'); 4 | INSERT INTO project_member (project_id, user_email) VALUES (1, 'maxime@sample.com'); 5 | INSERT INTO project_member (project_id, user_email) VALUES (1, 'sadek@sample.com'); 6 | INSERT INTO project_member (project_id, user_email) VALUES (1, 'erwan@sample.com'); 7 | INSERT INTO project_member (project_id, user_email) VALUES (2, 'guillaume@sample.com'); 8 | INSERT INTO project_member (project_id, user_email) VALUES (2, 'erwan@sample.com'); 9 | INSERT INTO project_member (project_id, user_email) VALUES (3, 'guillaume@sample.com'); 10 | INSERT INTO project_member (project_id, user_email) VALUES (3, 'maxime@sample.com'); 11 | INSERT INTO project_member (project_id, user_email) VALUES (4, 'guillaume@sample.com'); 12 | INSERT INTO project_member (project_id, user_email) VALUES (4, 'maxime@sample.com'); 13 | INSERT INTO project_member (project_id, user_email) VALUES (4, 'sadek@sample.com'); 14 | INSERT INTO project_member (project_id, user_email) VALUES (4, 'erwan@sample.com'); 15 | INSERT INTO project_member (project_id, user_email) VALUES (5, 'maxime@sample.com'); 16 | INSERT INTO project_member (project_id, user_email) VALUES (6, 'guillaume@sample.com'); 17 | INSERT INTO project_member (project_id, user_email) VALUES (7, 'guillaume@sample.com'); 18 | INSERT INTO project_member (project_id, user_email) VALUES (7, 'maxime@sample.com'); 19 | INSERT INTO project_member (project_id, user_email) VALUES (8, 'maxime@sample.com'); 20 | INSERT INTO project_member (project_id, user_email) VALUES (9, 'guillaume@sample.com'); 21 | INSERT INTO project_member (project_id, user_email) VALUES (10, 'erwan@sample.com'); 22 | INSERT INTO project_member (project_id, user_email) VALUES (11, 'sadek@sample.com'); 23 | 24 | # --- !Downs 25 | 26 | DELETE FROM project_member; 27 | -------------------------------------------------------------------------------- /scalikejdbc-play-dbapi-adapter/test/zentasks/conf/db/fixtures/secondary/task.sql: -------------------------------------------------------------------------------- 1 | # --- !Ups 2 | 3 | INSERT INTO task (id, title, done, due_date, assigned_to, project, folder) VALUES (1000, 'Fix the documentation', FALSE, null, 'guillaume@sample.com', 1, 'Todo'); 4 | INSERT INTO task (id, title, done, due_date, assigned_to, project, folder) VALUES (1001, 'Prepare the beta release', FALSE, '2011-11-15 00:00:00.0', null, 1, 'Urgent'); 5 | INSERT INTO task (id, title, done, due_date, assigned_to, project, folder) VALUES (1002, 'Buy some milk', FALSE, null, null, 9, 'Todo'); 6 | INSERT INTO task (id, title, done, due_date, assigned_to, project, folder) VALUES (1003, 'Check 1.2.4-RC2', FALSE, '2011-11-18 00:00:00.0', 'guillaume@sample.com', 2, 'Todo'); 7 | INSERT INTO task (id, title, done, due_date, assigned_to, project, folder) VALUES (1004, 'Finish zentask integration', TRUE, '2011-11-15 00:00:00.0', 'maxime@sample.com', 7, 'Todo'); 8 | INSERT INTO task (id, title, done, due_date, assigned_to, project, folder) VALUES (1005, 'Release the secret project', FALSE, '2012-01-01 00:00:00.0', 'sadek@sample.com', 4, 'Todo'); 9 | ALTER SEQUENCE task_seq RESTART WITH 1006; 10 | 11 | # --- !Downs 12 | ALTER SEQUENCE task_seq RESTART WITH 1000; 13 | DELETE FROM task; 14 | 15 | -------------------------------------------------------------------------------- /scalikejdbc-play-dbapi-adapter/test/zentasks/conf/db/fixtures/secondary/users.sql: -------------------------------------------------------------------------------- 1 | # --- !Ups 2 | INSERT INTO users (email, name, password) VALUES ('guillaume@sample.com', 'Guillaume Bort', 'secret'); 3 | INSERT INTO users (email, name, password) VALUES ('maxime@sample.com', 'Maxime Dantec', 'secret'); 4 | INSERT INTO users (email, name, password) VALUES ('sadek@sample.com', 'Sadek Drobi', 'secret'); 5 | INSERT INTO users (email, name, password) VALUES ('erwan@sample.com', 'Erwan Loisant', 'secret'); 6 | 7 | 8 | # --- !Downs 9 | DELETE FROM users; 10 | -------------------------------------------------------------------------------- /scalikejdbc-play-dbapi-adapter/test/zentasks/conf/evolutions/default/1.sql: -------------------------------------------------------------------------------- 1 | # --- !Ups 2 | drop table if exists users; 3 | create table users ( 4 | email varchar(255) not null primary key, 5 | name varchar(255) not null, 6 | password varchar(255) not null 7 | ); 8 | 9 | drop table if exists project; 10 | create table project ( 11 | id bigint not null primary key, 12 | name varchar(255) not null, 13 | folder varchar(255) not null 14 | ); 15 | 16 | drop sequence if exists project_seq; 17 | create sequence project_seq start with 1000; 18 | 19 | drop table if exists project_member; 20 | create table project_member ( 21 | project_id bigint not null, 22 | user_email varchar(255) not null, 23 | foreign key(project_id) references project(id) on delete cascade, 24 | foreign key(user_email) references users(email) on delete cascade 25 | ); 26 | 27 | drop table if exists task; 28 | create table task ( 29 | id bigint not null primary key, 30 | title varchar(255) not null, 31 | done boolean, 32 | due_date timestamp, 33 | assigned_to varchar(255), 34 | project bigint not null, 35 | folder varchar(255), 36 | foreign key(assigned_to) references users(email) on delete set null, 37 | foreign key(project) references project(id) on delete cascade 38 | ); 39 | 40 | drop sequence if exists task_seq; 41 | create sequence task_seq start with 1000; 42 | 43 | # --- !Downs 44 | 45 | drop sequence task_seq; 46 | drop table task; 47 | drop table project_member; 48 | drop sequence project_seq; 49 | drop table project; 50 | drop table users; 51 | -------------------------------------------------------------------------------- /scalikejdbc-play-dbapi-adapter/test/zentasks/conf/evolutions/secondary/1.sql: -------------------------------------------------------------------------------- 1 | # --- !Ups 2 | drop table if exists users; 3 | create table users ( 4 | email varchar(255) not null primary key, 5 | name varchar(255) not null, 6 | password varchar(255) not null 7 | ); 8 | 9 | drop table if exists project; 10 | create table project ( 11 | id bigint not null primary key, 12 | name varchar(255) not null, 13 | folder varchar(255) not null 14 | ); 15 | 16 | drop sequence if exists project_seq; 17 | create sequence project_seq start with 1000; 18 | 19 | drop table if exists project_member; 20 | create table project_member ( 21 | project_id bigint not null, 22 | user_email varchar(255) not null, 23 | foreign key(project_id) references project(id) on delete cascade, 24 | foreign key(user_email) references users(email) on delete cascade 25 | ); 26 | 27 | drop table if exists task; 28 | create table task ( 29 | id bigint not null primary key, 30 | title varchar(255) not null, 31 | done boolean, 32 | due_date timestamp, 33 | assigned_to varchar(255), 34 | project bigint not null, 35 | folder varchar(255), 36 | foreign key(assigned_to) references users(email) on delete set null, 37 | foreign key(project) references project(id) on delete cascade 38 | ); 39 | 40 | drop sequence if exists task_seq; 41 | create sequence task_seq start with 1000; 42 | 43 | # --- !Downs 44 | 45 | drop sequence task_seq; 46 | drop table task; 47 | drop table project_member; 48 | drop sequence project_seq; 49 | drop table project; 50 | drop table users; 51 | -------------------------------------------------------------------------------- /scalikejdbc-play-dbapi-adapter/test/zentasks/conf/prod.conf: -------------------------------------------------------------------------------- 1 | include "application.conf" 2 | db.default.driver=org.postgresql.Driver 3 | db.default.url=${DATABASE_URL} 4 | 5 | -------------------------------------------------------------------------------- /scalikejdbc-play-dbapi-adapter/test/zentasks/conf/routes: -------------------------------------------------------------------------------- 1 | # Routes 2 | # This file defines all application routes (Higher priority routes first) 3 | # ~~~~ 4 | 5 | # The home page 6 | GET / controllers.Projects.index() 7 | 8 | # Authentication 9 | GET /login controllers.Application.login() 10 | POST /login controllers.Application.authenticate() 11 | GET /logout controllers.Application.logout() 12 | 13 | # Projects 14 | POST /projects controllers.Projects.add() 15 | 16 | POST /projects/groups controllers.Projects.addGroup() 17 | DELETE /projects/groups controllers.Projects.deleteGroup(group: String) 18 | PUT /projects/groups controllers.Projects.renameGroup(group: String) 19 | 20 | DELETE /projects/:project controllers.Projects.delete(project: Long) 21 | PUT /projects/:project controllers.Projects.rename(project: Long) 22 | 23 | POST /projects/:project/team controllers.Projects.addUser(project: Long) 24 | DELETE /projects/:project/team controllers.Projects.removeUser(project: Long) 25 | 26 | # Tasks 27 | GET /projects/:project/tasks controllers.Tasks.index(project: Long) 28 | POST /projects/:project/tasks controllers.Tasks.add(project: Long, folder: String) 29 | PUT /tasks/:task controllers.Tasks.update(task: Long) 30 | DELETE /tasks/:task controllers.Tasks.delete(task: Long) 31 | 32 | POST /tasks/folder controllers.Tasks.addFolder() 33 | DELETE /projects/:project/tasks/folder controllers.Tasks.deleteFolder(project: Long, folder: String) 34 | PUT /project/:project/tasks/folder controllers.Tasks.renameFolder(project: Long, folder: String) 35 | 36 | # Javascript routing 37 | GET /assets/javascripts/routes controllers.Application.javascriptRoutes() 38 | 39 | # Map static resources from the /public folder to the /public path 40 | GET /assets/*file controllers.Assets.at(path="/public", file) 41 | -------------------------------------------------------------------------------- /scalikejdbc-play-dbapi-adapter/test/zentasks/project/build.properties: -------------------------------------------------------------------------------- 1 | sbt.version=0.13.7 2 | -------------------------------------------------------------------------------- /scalikejdbc-play-dbapi-adapter/test/zentasks/public/images/arrow-left.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scalikejdbc/scalikejdbc-play-support/f2b16fcc53fd22c0bf1a278428c252b907c1398d/scalikejdbc-play-dbapi-adapter/test/zentasks/public/images/arrow-left.png -------------------------------------------------------------------------------- /scalikejdbc-play-dbapi-adapter/test/zentasks/public/images/breadcrumb-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scalikejdbc/scalikejdbc-play-support/f2b16fcc53fd22c0bf1a278428c252b907c1398d/scalikejdbc-play-dbapi-adapter/test/zentasks/public/images/breadcrumb-1.png -------------------------------------------------------------------------------- /scalikejdbc-play-dbapi-adapter/test/zentasks/public/images/breadcrumb-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scalikejdbc/scalikejdbc-play-support/f2b16fcc53fd22c0bf1a278428c252b907c1398d/scalikejdbc-play-dbapi-adapter/test/zentasks/public/images/breadcrumb-2.png -------------------------------------------------------------------------------- /scalikejdbc-play-dbapi-adapter/test/zentasks/public/images/breadcrumb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scalikejdbc/scalikejdbc-play-support/f2b16fcc53fd22c0bf1a278428c252b907c1398d/scalikejdbc-play-dbapi-adapter/test/zentasks/public/images/breadcrumb.png -------------------------------------------------------------------------------- /scalikejdbc-play-dbapi-adapter/test/zentasks/public/images/icons/addRemove.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scalikejdbc/scalikejdbc-play-support/f2b16fcc53fd22c0bf1a278428c252b907c1398d/scalikejdbc-play-dbapi-adapter/test/zentasks/public/images/icons/addRemove.png -------------------------------------------------------------------------------- /scalikejdbc-play-dbapi-adapter/test/zentasks/public/images/icons/clock.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scalikejdbc/scalikejdbc-play-support/f2b16fcc53fd22c0bf1a278428c252b907c1398d/scalikejdbc-play-dbapi-adapter/test/zentasks/public/images/icons/clock.png -------------------------------------------------------------------------------- /scalikejdbc-play-dbapi-adapter/test/zentasks/public/images/icons/delete.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scalikejdbc/scalikejdbc-play-support/f2b16fcc53fd22c0bf1a278428c252b907c1398d/scalikejdbc-play-dbapi-adapter/test/zentasks/public/images/icons/delete.png -------------------------------------------------------------------------------- /scalikejdbc-play-dbapi-adapter/test/zentasks/public/images/icons/drawer.folder.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scalikejdbc/scalikejdbc-play-support/f2b16fcc53fd22c0bf1a278428c252b907c1398d/scalikejdbc-play-dbapi-adapter/test/zentasks/public/images/icons/drawer.folder.png -------------------------------------------------------------------------------- /scalikejdbc-play-dbapi-adapter/test/zentasks/public/images/icons/folder.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scalikejdbc/scalikejdbc-play-support/f2b16fcc53fd22c0bf1a278428c252b907c1398d/scalikejdbc-play-dbapi-adapter/test/zentasks/public/images/icons/folder.png -------------------------------------------------------------------------------- /scalikejdbc-play-dbapi-adapter/test/zentasks/public/images/icons/home.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scalikejdbc/scalikejdbc-play-support/f2b16fcc53fd22c0bf1a278428c252b907c1398d/scalikejdbc-play-dbapi-adapter/test/zentasks/public/images/icons/home.png -------------------------------------------------------------------------------- /scalikejdbc-play-dbapi-adapter/test/zentasks/public/images/icons/options.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scalikejdbc/scalikejdbc-play-support/f2b16fcc53fd22c0bf1a278428c252b907c1398d/scalikejdbc-play-dbapi-adapter/test/zentasks/public/images/icons/options.png -------------------------------------------------------------------------------- /scalikejdbc-play-dbapi-adapter/test/zentasks/public/images/icons/user.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scalikejdbc/scalikejdbc-play-support/f2b16fcc53fd22c0bf1a278428c252b907c1398d/scalikejdbc-play-dbapi-adapter/test/zentasks/public/images/icons/user.png -------------------------------------------------------------------------------- /scalikejdbc-play-dbapi-adapter/test/zentasks/public/images/icons/user2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scalikejdbc/scalikejdbc-play-support/f2b16fcc53fd22c0bf1a278428c252b907c1398d/scalikejdbc-play-dbapi-adapter/test/zentasks/public/images/icons/user2.png -------------------------------------------------------------------------------- /scalikejdbc-play-dbapi-adapter/test/zentasks/public/images/loading.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scalikejdbc/scalikejdbc-play-support/f2b16fcc53fd22c0bf1a278428c252b907c1398d/scalikejdbc-play-dbapi-adapter/test/zentasks/public/images/loading.gif -------------------------------------------------------------------------------- /scalikejdbc-play-dbapi-adapter/test/zentasks/public/images/pattern.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scalikejdbc/scalikejdbc-play-support/f2b16fcc53fd22c0bf1a278428c252b907c1398d/scalikejdbc-play-dbapi-adapter/test/zentasks/public/images/pattern.png -------------------------------------------------------------------------------- /scalikejdbc-play-fixture/readme.md: -------------------------------------------------------------------------------- 1 | # ScalikeJDBC Play Fixture Plugin 2 | 3 | Please see the website. 4 | 5 | https://scalikejdbc.org/ 6 | 7 | -------------------------------------------------------------------------------- /scalikejdbc-play-fixture/src/main/scala/scalikejdbc/PlayFixtureModule.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013 - 2014 scalikejdbc.org 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, 13 | * either express or implied. See the License for the specific language 14 | * governing permissions and limitations under the License. 15 | */ 16 | package scalikejdbc 17 | 18 | import javax.inject._ 19 | import _root_.play.api._ 20 | import _root_.play.api.inject._ 21 | import scala.concurrent.Future 22 | 23 | /** 24 | * Play Module 25 | */ 26 | class PlayFixtureModule extends Module { 27 | def bindings(env: Environment, config: Configuration) = 28 | Seq( 29 | bind[PlayInitializer].toSelf.eagerly(), 30 | bind[PlayFixture].toSelf.eagerly() 31 | ) 32 | } 33 | 34 | /** 35 | * The Play fixture plugin 36 | */ 37 | @Singleton 38 | class PlayFixture @Inject() ( 39 | configuration: Configuration, 40 | environment: Environment, 41 | playInitializer: PlayInitializer, 42 | lifecycle: ApplicationLifecycle 43 | ) extends scalikejdbc.play.FixtureSupport { 44 | 45 | private def isTest = environment.mode == Mode.Test 46 | 47 | private def isDev = environment.mode == Mode.Dev 48 | 49 | def onStart(): Unit = { 50 | if (isTest || isDev) { 51 | loadFixtures()(environment, configuration) 52 | } 53 | } 54 | 55 | def onStop(): Unit = { 56 | if (isTest || isDev) { 57 | cleanFixtures()(environment, configuration) 58 | } 59 | } 60 | 61 | lifecycle.addStopHook(() => Future.successful(onStop())) 62 | onStart() 63 | } 64 | -------------------------------------------------------------------------------- /scalikejdbc-play-fixture/src/main/scala/scalikejdbc/play/Fixture.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013 - 2014 scalikejdbc.org 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package scalikejdbc.play 17 | 18 | import scala.io.Source 19 | import scala.io.Codec 20 | import java.io.File 21 | 22 | case class Fixture(file: File) { 23 | 24 | private def script: String = Source.fromFile(file)(Codec.UTF8).mkString 25 | 26 | private def isUpsMarker(s: String): Boolean = s.matches("""^#.*!Ups.*$""") 27 | 28 | private def isDownsMarker(s: String): Boolean = s.matches("""^#.*!Downs.*$""") 29 | 30 | def upScript: String = 31 | script.linesIterator 32 | .dropWhile { line => !isUpsMarker(line) } 33 | .dropWhile { line => isUpsMarker(line) } 34 | .takeWhile { line => !isDownsMarker(line) } 35 | .mkString("\n") 36 | 37 | def downScript: String = 38 | script.linesIterator 39 | .dropWhile { line => !isDownsMarker(line) } 40 | .dropWhile { line => isDownsMarker(line) } 41 | .mkString("\n") 42 | } 43 | -------------------------------------------------------------------------------- /scalikejdbc-play-fixture/src/main/scala/scalikejdbc/play/FixtureNotFoundException.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013 - 2014 scalikejdbc.org 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package scalikejdbc.play 17 | 18 | class FixtureNotFoundException(message: String) extends Exception(message) 19 | -------------------------------------------------------------------------------- /scalikejdbc-play-fixture/src/main/scala/scalikejdbc/play/FixtureSupport.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013 - 2014 scalikejdbc.org 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package scalikejdbc.play 17 | 18 | import _root_.play.api._ 19 | import java.io.File 20 | import scala.jdk.CollectionConverters._ 21 | import scalikejdbc._ 22 | 23 | trait FixtureSupport { 24 | 25 | val fixturesRootPath: String = "db/fixtures" 26 | 27 | private def fixtureConfigKey( 28 | dbName: String 29 | )(implicit environment: Environment): String = 30 | if (environment.mode == Mode.Dev) { 31 | "db." + dbName + ".fixtures.dev" 32 | } else if (environment.mode == Mode.Test) { 33 | "db." + dbName + ".fixtures.test" 34 | } else { 35 | throw new UnsupportedOperationException( 36 | "Fixture feature is only provided for dev mode and test mode." 37 | ) 38 | } 39 | 40 | def fixtures(implicit 41 | environment: Environment, 42 | configuration: Configuration 43 | ): Map[String, Seq[Fixture]] = { 44 | (for { 45 | dbConfig <- configuration.getOptional[Configuration]("db").toList 46 | subKey <- dbConfig.subKeys 47 | } yield { 48 | val dbName = subKey 49 | val fixtureNames: Seq[String] = 50 | try { 51 | configuration 52 | .getOptional[Seq[String]](fixtureConfigKey(subKey)) 53 | .getOrElse(Nil) 54 | } catch { 55 | case e: PlayException => { 56 | configuration.getOptional[String](fixtureConfigKey(subKey)).toSeq 57 | } 58 | } 59 | 60 | val fixtureFiles = fixtureNames.map { fixtureName => 61 | val resourceName = 62 | List(fixturesRootPath, dbName, fixtureName).mkString("/") 63 | environment.resource(resourceName) match { 64 | case Some(resource) => Fixture(new File(resource.getPath)) 65 | case None => 66 | throw new FixtureNotFoundException( 67 | "Fixture not found (%s)".format(resourceName) 68 | ) 69 | } 70 | } 71 | 72 | dbName -> fixtureFiles 73 | }).toMap 74 | } 75 | 76 | def loadFixtures()(implicit 77 | environment: Environment, 78 | configuration: Configuration 79 | ): Unit = { 80 | for { 81 | (dbName, fs) <- fixtures 82 | f <- fs 83 | } { 84 | execute(dbName, f.upScript) 85 | } 86 | } 87 | 88 | def cleanFixtures()(implicit 89 | environment: Environment, 90 | configuration: Configuration 91 | ): Unit = { 92 | for { 93 | (dbName, fs) <- fixtures 94 | f <- fs.reverse 95 | } { 96 | execute(dbName, f.downScript) 97 | } 98 | } 99 | 100 | private def execute(dbName: String, script: String): Unit = { 101 | NamedDB(dbName) localTx { implicit session => 102 | SQL(script).update.apply() 103 | } 104 | } 105 | 106 | } 107 | -------------------------------------------------------------------------------- /scalikejdbc-play-fixture/src/test/resources/db/fixtures/default/project.sql: -------------------------------------------------------------------------------- 1 | 2 | # --- !Ups 3 | create table project ( 4 | id bigint not null primary key, 5 | name varchar(255) not null, 6 | folder varchar(255) not null 7 | ); 8 | create sequence project_seq start with 1000; 9 | 10 | # --- !Downs 11 | drop sequence project_seq; 12 | drop table project; 13 | 14 | -------------------------------------------------------------------------------- /scalikejdbc-play-fixture/src/test/resources/db/fixtures/default/users.sql: -------------------------------------------------------------------------------- 1 | # --- !Ups 2 | create table users ( 3 | email varchar(255) not null primary key, 4 | name varchar(255) not null, 5 | password varchar(255) not null 6 | ); 7 | 8 | # --- !Downs 9 | drop table users; 10 | 11 | -------------------------------------------------------------------------------- /scalikejdbc-play-fixture/src/test/resources/db/fixtures/secondary/a.sql: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scalikejdbc/scalikejdbc-play-support/f2b16fcc53fd22c0bf1a278428c252b907c1398d/scalikejdbc-play-fixture/src/test/resources/db/fixtures/secondary/a.sql -------------------------------------------------------------------------------- /scalikejdbc-play-fixture/src/test/scala/scalikejdbc/play/FixtureSpec.scala: -------------------------------------------------------------------------------- 1 | package scalikejdbc.play 2 | 3 | import java.io.File 4 | import play.api.test._ 5 | import play.api.test.Helpers._ 6 | import play.api.libs.Files 7 | import org.specs2.mutable._ 8 | import org.specs2.specification.BeforeAfterEach 9 | 10 | class FixtureSpec extends Specification with BeforeAfterEach { 11 | 12 | def before = {} 13 | 14 | def after = {} 15 | 16 | def fixture = { 17 | val script = """ 18 | | 19 | |# --- !Ups 20 | |drop table users if exists; 21 | |create table users ( 22 | | email varchar(255) not null primary key, 23 | | name varchar(255) not null, 24 | | password varchar(255) not null 25 | |); 26 | | 27 | |# --- !Downs 28 | |drop table users if exists; 29 | | 30 | |""".stripMargin 31 | 32 | val tmpfile = File.createTempFile("tmp", ".sql") 33 | tmpfile.deleteOnExit() 34 | val writer = new java.io.PrintWriter(tmpfile) 35 | try { 36 | writer.println(script) 37 | } finally { 38 | writer.close() 39 | } 40 | Fixture(tmpfile) 41 | } 42 | 43 | "Fixture" should { 44 | 45 | "has #upScript" in { 46 | val expected = 47 | """|drop table users if exists; 48 | |create table users ( 49 | | email varchar(255) not null primary key, 50 | | name varchar(255) not null, 51 | | password varchar(255) not null 52 | |); 53 | |""".stripMargin 54 | fixture.upScript must_== expected 55 | } 56 | 57 | "has #downScript" in { 58 | val expected = 59 | """|drop table users if exists; 60 | | 61 | |""".stripMargin 62 | fixture.downScript must_== expected 63 | } 64 | 65 | } 66 | 67 | } 68 | -------------------------------------------------------------------------------- /scalikejdbc-play-fixture/src/test/scala/scalikejdbc/play/FixtureSupportSpec.scala: -------------------------------------------------------------------------------- 1 | package scalikejdbc.play 2 | 3 | import org.specs2.mutable._ 4 | import org.specs2.specification.BeforeAfterEach 5 | import play.api.{ Configuration, Environment } 6 | 7 | import scala.jdk.CollectionConverters._ 8 | 9 | class FixtureSupportSpec extends Specification with BeforeAfterEach { 10 | 11 | def before = {} 12 | 13 | def after = {} 14 | 15 | val fixtureSupport = new FixtureSupport {} 16 | 17 | "FixtureSupport" should { 18 | 19 | "has #fixtures" in { 20 | val environment = Environment.simple() 21 | val configuration = Configuration( 22 | "play.modules.enabled" -> List( 23 | "scalikejdbc.PlayModule", 24 | "scalikejdbc.PlayFixtureModule" 25 | ), 26 | "db.default.fixtures.test" -> List("users.sql", "project.sql").asJava, 27 | "db.secondary.fixtures.test" -> "a.sql", 28 | "db.default.driver" -> "org.h2.Driver", 29 | "db.default.url" -> "jdbc:h2:mem:default;DB_CLOSE_DELAY=-1", 30 | "db.default.user" -> "sa", 31 | "db.default.password" -> "sa", 32 | "db.secondary.driver" -> "org.h2.Driver", 33 | "db.secondary.url" -> "jdbc:h2:mem:secondary;DB_CLOSE_DELAY=-1", 34 | "db.secondary.user" -> "l", 35 | "db.secondary.password" -> "g" 36 | ) 37 | fixtureSupport.fixtures(environment, configuration) must have size 2 38 | } 39 | 40 | } 41 | 42 | } 43 | -------------------------------------------------------------------------------- /scalikejdbc-play-initializer/.gitignore: -------------------------------------------------------------------------------- 1 | *.log 2 | .settings 3 | classpath 4 | .project 5 | *.iml 6 | *.ipr 7 | *.iws 8 | .DS_Store 9 | dist/ 10 | lib_managed/ 11 | project/boot/ 12 | project/plugins/project/ 13 | target/ 14 | 15 | # use glob syntax. 16 | syntax: glob 17 | *.ser 18 | *.class 19 | *~ 20 | *.bak 21 | #*.off 22 | *.old 23 | 24 | # eclipse conf file 25 | .settings 26 | .classpath 27 | .project 28 | .manager 29 | .scala_dependencies 30 | 31 | # idea 32 | .idea 33 | *.iml 34 | 35 | # building 36 | target 37 | build 38 | null 39 | tmp* 40 | temp* 41 | dist 42 | test-output 43 | build.log 44 | 45 | # other scm 46 | .svn 47 | .CVS 48 | .hg* 49 | 50 | # switch to regexp syntax. 51 | # syntax: regexp 52 | # ^\.pc/ 53 | 54 | #SHITTY output not in target directory 55 | build.log 56 | -------------------------------------------------------------------------------- /scalikejdbc-play-initializer/readme.md: -------------------------------------------------------------------------------- 1 | # ScalikeJDBC Play Plugin 2 | 3 | -------------------------------------------------------------------------------- /scalikejdbc-play-initializer/src/main/scala/scalikejdbc/PlayInitializer.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012 - 2014 scalikejdbc.org 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, 13 | * either express or implied. See the License for the specific language 14 | * governing permissions and limitations under the License. 15 | */ 16 | package scalikejdbc 17 | 18 | import javax.inject._ 19 | import _root_.play.api._ 20 | import _root_.play.api.inject._ 21 | import scalikejdbc.config.{ TypesafeConfig, TypesafeConfigReader, DBs } 22 | import scala.concurrent.Future 23 | 24 | /** 25 | * The Play plugin to use ScalikeJDBC 26 | */ 27 | @Singleton 28 | class PlayInitializer @Inject() ( 29 | lifecycle: ApplicationLifecycle, 30 | configuration: Configuration 31 | ) { 32 | 33 | import PlayInitializer._ 34 | 35 | // Play DB configuration 36 | 37 | private[this] lazy val playConfig = configuration 38 | .getOptional[Configuration]("scalikejdbc.play") 39 | .getOrElse(Configuration.empty) 40 | 41 | private[this] var closeAllOnStop = true 42 | 43 | private[this] lazy val loggingSQLErrors = configuration 44 | .getOptional[Boolean]("scalikejdbc.global.loggingSQLErrors") 45 | .getOrElse(true) 46 | 47 | /** 48 | * DBs with Play application configuration. 49 | */ 50 | private[this] lazy val DBs = new DBs 51 | with TypesafeConfigReader 52 | with TypesafeConfig { 53 | override val config = configuration.underlying 54 | } 55 | 56 | def onStart(): Unit = { 57 | DBs.setupAll() 58 | GlobalSettings.loggingSQLErrors = loggingSQLErrors 59 | opt("closeAllOnStop", "enabled")(playConfig).foreach { enabled => 60 | closeAllOnStop = enabled.toBoolean 61 | } 62 | } 63 | 64 | def onStop(): Unit = { 65 | if (closeAllOnStop) { 66 | ConnectionPool.closeAll() 67 | } 68 | 69 | val cache = SQLSyntaxSupportFeature.SQLSyntaxSupportLoadedColumns 70 | cache.clear() 71 | } 72 | 73 | lifecycle.addStopHook(() => Future.successful(onStop())) 74 | onStart() 75 | } 76 | 77 | object PlayInitializer { 78 | def opt(name: String, key: String)(implicit 79 | config: Configuration 80 | ): Option[String] = { 81 | config.getOptional[String](name + "." + key) 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /scalikejdbc-play-initializer/src/main/scala/scalikejdbc/PlayModule.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012 - 2014 scalikejdbc.org 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, 13 | * either express or implied. See the License for the specific language 14 | * governing permissions and limitations under the License. 15 | */ 16 | package scalikejdbc 17 | 18 | import javax.inject._ 19 | import _root_.play.api._ 20 | import _root_.play.api.inject._ 21 | 22 | /** 23 | * Play module 24 | */ 25 | class PlayModule extends Module { 26 | def bindings(env: Environment, config: Configuration) = Seq( 27 | bind[PlayInitializer].toSelf.eagerly() 28 | ) 29 | } 30 | -------------------------------------------------------------------------------- /scalikejdbc-play-initializer/src/test/scala/scalikejdbc/PlayModuleSpec.scala: -------------------------------------------------------------------------------- 1 | package scalikejdbc 2 | 3 | import _root_.play.api.inject.guice.GuiceApplicationBuilder 4 | import _root_.play.api.test.Helpers._ 5 | import org.specs2.mutable.Specification 6 | 7 | object PlayModuleSpec extends Specification { 8 | 9 | sequential 10 | 11 | Class.forName("org.h2.Driver") 12 | 13 | def fakeApp = { 14 | val additionalConfiguration = Map( 15 | "logger.root" -> "INFO", 16 | "logger.play" -> "INFO", 17 | "logger.application" -> "DEBUG", 18 | "dbplugin" -> "disabled", 19 | "evolutionplugin" -> "disabled", 20 | "db.default.driver" -> "org.h2.Driver", 21 | "db.default.url" -> "jdbc:h2:mem:default", 22 | "db.default.user" -> "sa", 23 | "db.default.password" -> "sa", 24 | "db.default.schema" -> "", 25 | "db.default.poolInitialSize" -> "1", 26 | "db.default.poolMaxSize" -> "2", 27 | "db.default.poolValidationQuery" -> "select 1", 28 | "db.default.poolConnectionTimeoutMillis" -> "2000", 29 | "db.legacydb.driver" -> "org.h2.Driver", 30 | "db.legacydb.url" -> "jdbc:h2:mem:legacy", 31 | "db.legacydb.user" -> "l", 32 | "db.legacydb.password" -> "g", 33 | "db.legacydb.schema" -> "", 34 | "scalikejdbc.global.loggingSQLAndTime.enabled" -> "true", 35 | "scalikejdbc.global.loggingSQLAndTime.singleLineMode" -> "true", 36 | "scalikejdbc.global.loggingSQLAndTime.logLevel" -> "debug", 37 | "scalikejdbc.global.loggingSQLAndTime.warningEnabled" -> "true", 38 | "scalikejdbc.global.loggingSQLAndTime.warningThreasholdMillis" -> "1", 39 | "scalikejdbc.global.loggingSQLAndTime.warningLogLevel" -> "warn" 40 | ) 41 | new GuiceApplicationBuilder() 42 | .configure(additionalConfiguration) 43 | .bindings(new scalikejdbc.PlayModule) 44 | .build() 45 | } 46 | 47 | def fakeAppWithoutCloseAllOnStop = { 48 | val additionalConfiguration = Map( 49 | "db.default.driver" -> "org.h2.Driver", 50 | "db.default.url" -> "jdbc:h2:mem:default", 51 | "db.default.user" -> "sa", 52 | "db.default.password" -> "sa", 53 | "db.legacydb.driver" -> "org.h2.Driver", 54 | "db.legacydb.url" -> "jdbc:h2:mem:legacy", 55 | "db.legacydb.user" -> "l", 56 | "db.legacydb.password" -> "g", 57 | "scalikejdbc.play.closeAllOnStop.enabled" -> "false" 58 | ) 59 | new GuiceApplicationBuilder() 60 | .configure(additionalConfiguration) 61 | .bindings(new scalikejdbc.PlayModule) 62 | .build() 63 | } 64 | 65 | def fakeAppWithDBPlugin = { 66 | val additionalConfiguration = Map( 67 | "db.default.driver" -> "org.h2.Driver", 68 | "db.default.url" -> "jdbc:h2:mem:default", 69 | "db.default.user" -> "sa", 70 | "db.default.password" -> "sa", 71 | "db.default.schema" -> "", 72 | "db.legacydb.driver" -> "org.h2.Driver", 73 | "db.legacydb.url" -> "jdbc:h2:mem:legacy", 74 | "db.legacydb.user" -> "l", 75 | "db.legacydb.password" -> "g", 76 | "db.legacydb.schema" -> "", 77 | "scalikejdbc.global.loggingSQLAndTime.enabled" -> "true", 78 | "scalikejdbc.global.loggingSQLAndTime.logLevel" -> "debug", 79 | "scalikejdbc.global.loggingSQLAndTime.warningEnabled" -> "true", 80 | "scalikejdbc.global.loggingSQLAndTime.warningThreasholdMillis" -> "1", 81 | "scalikejdbc.global.loggingSQLAndTime.warningLogLevel" -> "warn" 82 | ) 83 | new GuiceApplicationBuilder() 84 | .configure(additionalConfiguration) 85 | .bindings(new scalikejdbc.PlayModule) 86 | .build() 87 | } 88 | 89 | def simpleTest(table: String) = { 90 | 91 | try { 92 | 93 | DB autoCommit { implicit s => 94 | SQL("DROP TABLE " + table + " IF EXISTS").execute.apply() 95 | SQL( 96 | "CREATE TABLE " + table + " (ID BIGINT PRIMARY KEY NOT NULL, NAME VARCHAR(256))" 97 | ).execute.apply() 98 | val insert = SQL( 99 | "INSERT INTO " + table + " (ID, NAME) VALUES (/*'id*/123, /*'name*/'Alice')" 100 | ) 101 | insert.bindByName("id" -> 1, "name" -> "Alice").update.apply() 102 | insert.bindByName("id" -> 2, "name" -> "Bob").update.apply() 103 | insert.bindByName("id" -> 3, "name" -> "Eve").update.apply() 104 | } 105 | 106 | NamedDB("legacydb") autoCommit { implicit s => 107 | SQL("DROP TABLE " + table + " IF EXISTS").execute.apply() 108 | SQL( 109 | "CREATE TABLE " + table + " (ID BIGINT PRIMARY KEY NOT NULL, NAME VARCHAR(256))" 110 | ).execute.apply() 111 | val insert = SQL( 112 | "INSERT INTO " + table + " (ID, NAME) VALUES (/*'id*/123, /*'name*/'Alice')" 113 | ) 114 | insert.bindByName("id" -> 1, "name" -> "Alice").update.apply() 115 | insert.bindByName("id" -> 2, "name" -> "Bob").update.apply() 116 | insert.bindByName("id" -> 3, "name" -> "Eve").update.apply() 117 | insert.bindByName("id" -> 4, "name" -> "Fred").update.apply() 118 | } 119 | 120 | case class User(id: Long, name: Option[String]) 121 | 122 | val users = DB readOnly { implicit s => 123 | SQL("SELECT * FROM " + table) 124 | .map(rs => User(rs.long("id"), Option(rs.string("name")))) 125 | .list 126 | .apply() 127 | } 128 | users.size must_== (3) 129 | 130 | val usersInLegacy = NamedDB("legacydb") readOnly { implicit s => 131 | SQL("SELECT * FROM " + table) 132 | .map(rs => User(rs.long("id"), Option(rs.string("name")))) 133 | .list 134 | .apply() 135 | } 136 | usersInLegacy.size must_== (4) 137 | 138 | } finally { 139 | DB autoCommit { implicit s => 140 | SQL("DROP TABLE " + table + " IF EXISTS").execute.apply() 141 | } 142 | NamedDB("legacydb") autoCommit { implicit s => 143 | SQL("DROP TABLE " + table + " IF EXISTS").execute.apply() 144 | } 145 | } 146 | 147 | } 148 | 149 | "Play plugin" should { 150 | 151 | "be available when DB plugin is not active" in { 152 | running(fakeApp) { 153 | val settings = ConnectionPool.get("default").settings 154 | settings.initialSize must_== (1) 155 | settings.maxSize must_== (2) 156 | settings.validationQuery must_== ("select 1") 157 | settings.connectionTimeoutMillis must_== (2000) 158 | simpleTest("user_1") 159 | } 160 | running(fakeApp) { simpleTest("user_2") } 161 | running(fakeApp) { simpleTest("user_3") } 162 | } 163 | 164 | "be available when DB plugin is also active" in { 165 | running(fakeAppWithDBPlugin) { simpleTest("user_withdbplugin") } 166 | } 167 | 168 | "close connection pools after stopping Play app" in { 169 | try { 170 | // Play 2.0.4 throws Exception here 171 | running(fakeApp) { simpleTest("user_4") } 172 | } catch { case e: Exception => } 173 | simpleTest("user_5") must throwA[IllegalStateException](message = 174 | "Connection pool is not yet initialized." 175 | ) 176 | } 177 | 178 | "skip closing connection pools after stopping Play app" in { 179 | running(fakeAppWithoutCloseAllOnStop) { 180 | simpleTest("user_4") 181 | } 182 | simpleTest("user_5") 183 | } 184 | } 185 | 186 | } 187 | -------------------------------------------------------------------------------- /scalikejdbc-play-initializer/test/zentasks/Procfile: -------------------------------------------------------------------------------- 1 | web: target/start -Dhttp.port=${PORT} -Ddb.default.url=$DATABASE_URL 2 | 3 | -------------------------------------------------------------------------------- /scalikejdbc-play-initializer/test/zentasks/README: -------------------------------------------------------------------------------- 1 | This advanced todo list demonstrates a modern AJAX-based web application. This is a work in progress, and we plan to add several features in the future releases. For now you can check it out to learn how to: 2 | 3 | - Integrate authentication, and security. 4 | - Use AJAX and the Javascript reverse routing. 5 | - Integrate with compiled assets - LESS CSS and CoffeeScript. -------------------------------------------------------------------------------- /scalikejdbc-play-initializer/test/zentasks/app/assets/stylesheets/apps/_tasks.less: -------------------------------------------------------------------------------- 1 | // ----------------------------------- 2 | // TASKS 3 | // ----------------------------------- 4 | // author: mda@zenexity.com - 2011 5 | // ----------------------------------- 6 | 7 | .tasks { 8 | .folder { 9 | .box(); 10 | > header { 11 | position: relative; 12 | padding: 4px 25px 4px 7px; 13 | input { 14 | display: inline-block; 15 | } 16 | input[type=text] { 17 | margin: 1px 0 0; 18 | } 19 | .options, .loader { 20 | position: absolute; 21 | top: 4px; 22 | right: 4px; 23 | } 24 | } 25 | > ul { 26 | > li { 27 | position: relative; 28 | padding: 4px 20px 4px 7px; 29 | border-bottom: 1px solid rgba(0,0,0,.05); 30 | -webkit-user-select: text; 31 | time { 32 | float: right; 33 | display: inline-block; 34 | margin: 0 10px; 35 | border-radius: 15px; 36 | background: url(/assets/images/icons/clock.png) 1px 1px no-repeat; 37 | background-color: @dueDateBackground; 38 | border: 1px solid @dueDateBorder; 39 | color: @dueDateColor; 40 | font-size: 11px; 41 | padding: 0 4px 1px 15px; 42 | } 43 | h4 { 44 | display: inline-block; 45 | font-weight: bold; 46 | } 47 | .deleteTask { 48 | .delete(); 49 | top: 4px; 50 | right: 4px; 51 | } 52 | &:hover .deleteTask { 53 | opacity: 1; 54 | -webkit-transition-delay: 0; 55 | } 56 | .assignedTo { 57 | float: right; 58 | display: inline-block; 59 | margin: 0 10px; 60 | padding-left: 17px; 61 | color: @assignedToColor; 62 | background: url(/assets/images/icons/user2.png) 0 1px no-repeat; 63 | } 64 | } 65 | } 66 | .addTask { 67 | position: relative; 68 | border-radius: 0 0 4px 4px; 69 | padding: 5px 250px 5px 5px; 70 | background: white; 71 | &:after { 72 | content: " "; 73 | display: block; 74 | clear: both; 75 | } 76 | input { 77 | outline: none; 78 | } 79 | [name=taskBody] { 80 | width: 100%; 81 | border: 0; 82 | } 83 | .dueDate { 84 | position: absolute; 85 | right: 210px; 86 | top: 4px; 87 | width: 140px; 88 | border-radius: 15px; 89 | background: url(/assets/images/icons/clock.png) 2px 2px no-repeat; 90 | background-color: @dueDateBackground; 91 | border: 1px solid @dueDateBorder; 92 | color: @dueDateColor; 93 | font-size: 11px; 94 | padding: 1px 4px 1px 15px; 95 | &::-webkit-input-placeholder { 96 | color: inherit; 97 | } 98 | &:-moz-placeholder { 99 | color: inherit; 100 | } 101 | } 102 | .assignedTo { 103 | position: absolute; 104 | right: 5px; 105 | top: 5px; 106 | width: 195px; 107 | input { 108 | width: 180px; 109 | margin: 2px; 110 | border: 0; 111 | } 112 | } 113 | .assignToList { 114 | display: none; 115 | position: absolute; 116 | top: 100%; 117 | right: 0; 118 | min-width: 100%; 119 | background: rgba(0,0,0,.8); 120 | color: #eee; 121 | } 122 | [type=submit] { 123 | position: absolute; 124 | left: -3000px; 125 | visibility: hidden; 126 | } 127 | ul, div { 128 | display: inline-block; 129 | } 130 | } 131 | .loader { 132 | position: absolute; 133 | top: 5px; 134 | right: 6px; 135 | } 136 | } 137 | } 138 | -------------------------------------------------------------------------------- /scalikejdbc-play-initializer/test/zentasks/app/assets/stylesheets/libs/_mate.less: -------------------------------------------------------------------------------- 1 | // ----------------------------------- 2 | // MATE: CSS helpers 3 | // ----------------------------------- 4 | // author: mda@zenexity.com - 2011 5 | // ----------------------------------- 6 | 7 | // ------------------------ GRADIENTS 8 | .gradient(@from:#000, @to:#EEE) { 9 | background: @from; 10 | background-image: -webkit-gradient(linear, left top, left bottom, from(@from), to(@to)); 11 | background-image: -moz-linear-gradient(top, @from, @to); 12 | } 13 | 14 | // ---------------------- TRANSITIONS 15 | .transition(@range: all, @time: 500ms, @ease: ease-in-out) { 16 | -moz-transition: @range @time @ease; 17 | -webkit-transition: @range @time @ease; 18 | -o-transition: @range @time @ease; 19 | transition: @range @time @ease; 20 | } 21 | 22 | // ------------------------ TRANSFORMS 23 | .transform(@props) { 24 | -moz-transform: @arguments; 25 | -webkit-transform: @arguments; 26 | -o-transform: @arguments; 27 | transform: @arguments; 28 | } 29 | 30 | // --------------------------- HELPERS 31 | .ellipsis() { 32 | white-space: nowrap; 33 | text-overflow: ellipsis; 34 | overflow: hidden; 35 | } 36 | 37 | .clear() { 38 | &:after { 39 | display: block; 40 | content: " "; 41 | clear: both; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /scalikejdbc-play-initializer/test/zentasks/app/assets/stylesheets/libs/_reset.less: -------------------------------------------------------------------------------- 1 | html, body, div, span, applet, object, iframe, h1, h2, h3, h4, h5, h6, p, blockquote, pre, a, abbr, acronym, address, big, cite, code, del, dfn, em, font, img, ins, kbd, q, s, samp, small, strike, strong, sub, sup, tt, var, dl, dt, dd, ol, ul, li, fieldset, form, label, legend, table, caption, tbody, tfoot, thead, tr, th, td {margin: 0; padding: 0; border: 0; outline: 0; font-weight: inherit; font-style: inherit; font-size: 100%; font-family: inherit;} 2 | 3 | table {border-collapse: collapse; border-spacing: 0;} 4 | caption, th, td {text-align: left; font-weight: normal;} 5 | form legend {display: none;} 6 | blockquote:before, blockquote:after, q:before, q:after {content: "";} 7 | blockquote, q {quotes: "" "";} 8 | ol, ul {list-style: none;} 9 | hr {display: none; visibility: hidden;} 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /scalikejdbc-play-initializer/test/zentasks/app/assets/stylesheets/libs/_theme.less: -------------------------------------------------------------------------------- 1 | // ----------------------------------- 2 | // THEME 3 | // ----------------------------------- 4 | // author: mda@zenexity.com - 2011 5 | // ----------------------------------- 6 | 7 | // ---------------------------- COLORS 8 | @mainBackground: #c7d1d8; 9 | @mainColor: #2a3a48; 10 | @drawerBackground: #e1e7ec; 11 | @folderColor: #6f8193; 12 | @projectColor: @mainColor; 13 | @layoutBorderColor: #606d78; 14 | 15 | @links: #4794c4; 16 | @linksHover: #2a5e88; 17 | 18 | @headerLight: #445868; 19 | @headerDark: @mainColor; 20 | @titleColor: #556b7b; 21 | @buttonColor: @mainBackground; 22 | @buttonHover: #fff; 23 | 24 | @activeColor: #5daad5; 25 | 26 | // Tasks 27 | @dueDateBackground: #accfe8; 28 | @dueDateBorder: #73a4ca; 29 | @dueDateColor: #246fa9; 30 | @assignedToColor: @titleColor; 31 | 32 | // Folders 33 | @folderBorder: #9ba5ad; 34 | @folderBackground: #dbe1e5; 35 | @folderHeaderLight: #f2f5f8; 36 | @folderHeaderDark: #dfe2e6; 37 | @folderTitle: #7a8a99; 38 | 39 | // Pannels 40 | @panBackground: rgba(0,0,0,.85); 41 | @panShadow: rgba(0,0,0,.8); 42 | @panText: #aaa; 43 | @panTitle: #fff; 44 | @panBorder: #333; 45 | @panButtonBackground: #444; 46 | @panButtonColor: #fff; 47 | 48 | // ----------------------------- FONTS 49 | @defaultFont: 13px "Lucida Grande","Helvetica Neue", sans-serif; 50 | 51 | // ----------------------------- SIZES 52 | @headerHeight: 40px; 53 | @drawerWidth: 220px; 54 | @navigationWidth: 70px; 55 | @breadcrumbHeight: 50px; 56 | 57 | -------------------------------------------------------------------------------- /scalikejdbc-play-initializer/test/zentasks/app/assets/stylesheets/login.less: -------------------------------------------------------------------------------- 1 | // ----------------------------------- 2 | // LOGIN 3 | // ----------------------------------- 4 | // author: mda@zenexity.com - 2011 5 | // ----------------------------------- 6 | 7 | @import 'libs/_reset.less'; 8 | @import 'libs/_mate.less'; 9 | @import 'libs/_theme.less'; 10 | 11 | // ----------------------- MAIN STYLES 12 | body { 13 | background: @mainBackground; 14 | color: @mainColor; 15 | font: @defaultFont; 16 | -webkit-font-smoothing: antialised; 17 | -webkit-user-select: none; 18 | } 19 | 20 | a { 21 | color: @links; 22 | text-decoration: none; 23 | &:hover { 24 | color: @linksHover; 25 | } 26 | } 27 | 28 | p.note { 29 | margin: 10px auto 0; 30 | width: 300px; 31 | padding: 20px; 32 | text-align: center; 33 | color: #445868; 34 | text-shadow: 1px 1px rgba(255,255,255,.6); 35 | em { 36 | font-weight: bold; 37 | } 38 | } 39 | 40 | form { 41 | margin: 100px auto 0; 42 | width: 300px; 43 | padding: 20px; 44 | background: #fff; 45 | border-radius: 5px; 46 | box-shadow: 0 2px 5px rgba(0,0,0,.3); 47 | text-align: center; 48 | h1 { 49 | margin: 0 0 10px; 50 | font-size: 20px; 51 | font-weight: bold; 52 | } 53 | p { 54 | width: inherit; 55 | margin: 5px 0; 56 | color: #999; 57 | } 58 | p.error { 59 | color: #c00; 60 | margin-bottom: 10px; 61 | text-shadow: 1px 1px rgba(0,0,0,.1); 62 | } 63 | p.success { 64 | color: #83BD41; 65 | margin-bottom: 10px; 66 | text-shadow: 1px 1px rgba(0,0,0,.1); 67 | } 68 | input { 69 | display: block; 70 | width: inherit; 71 | padding: 2px; 72 | background: rgba(0,0,0,.05); 73 | border: 1px solid rgba(0,0,0,.15); 74 | box-shadow: 0 1px 2px rgba(0,0,0,.1) inset; 75 | border-radius: 3px; 76 | font-size: 14px; 77 | &:invalid:not(:focus) { 78 | border-color: red; 79 | } 80 | } 81 | button { 82 | .button(); 83 | display: block; 84 | width: inherit; 85 | font-size: 14px; 86 | } 87 | } 88 | 89 | nav { 90 | margin-top: 15px; 91 | a { 92 | display: inline-block; 93 | margin: 0 4px; 94 | } 95 | } 96 | 97 | // --------------------------- IMPORTS 98 | @import 'main/_widgets.less'; // Some shared elements 99 | @import 'main/_header.less'; // Top header + User bar 100 | 101 | -------------------------------------------------------------------------------- /scalikejdbc-play-initializer/test/zentasks/app/assets/stylesheets/main.less: -------------------------------------------------------------------------------- 1 | // ----------------------------------- 2 | // MAIN 3 | // ----------------------------------- 4 | // author: mda@zenexity.com - 2011 5 | // ----------------------------------- 6 | 7 | @import 'libs/_reset.less'; 8 | @import 'libs/_mate.less'; 9 | @import 'libs/_theme.less'; 10 | 11 | // ----------------------- MAIN STYLES 12 | body { 13 | background: @mainBackground; 14 | color: @mainColor; 15 | font: @defaultFont; 16 | -webkit-font-smoothing: antialised; 17 | -webkit-user-select: none; 18 | } 19 | 20 | a { 21 | color: @links; 22 | text-decoration: none; 23 | &:hover { 24 | color: @linksHover; 25 | } 26 | } 27 | 28 | // --------------------------- IMPORTS 29 | @import 'main/_layout.less'; // General grid 30 | @import 'main/_widgets.less'; // Some shared elements 31 | @import 'main/_drawer.less'; // Project drawer 32 | @import 'main/_header.less'; // Top header + User bar 33 | @import 'main/_breadcrumb.less'; // Breadcrumb + App menu 34 | @import 'apps/_tasks.less'; // Tasks 35 | 36 | -------------------------------------------------------------------------------- /scalikejdbc-play-initializer/test/zentasks/app/assets/stylesheets/main/_breadcrumb.less: -------------------------------------------------------------------------------- 1 | // ----------------------------------- 2 | // BREADCRUMB 3 | // ----------------------------------- 4 | // author: mda@zenexity.com - 2011 5 | // ----------------------------------- 6 | 7 | #main > header { 8 | height: 39px; 9 | background: url(/assets/images/breadcrumb.png); 10 | border-bottom: 1px solid @layoutBorderColor; 11 | hgroup { 12 | height: inherit; 13 | overflow: hidden; 14 | float: left; 15 | > * { 16 | float: inherit; 17 | position: relative; 18 | height: inherit; 19 | line-height: 40px; 20 | margin-left: -25px; 21 | padding: 0 6px 0 13px; 22 | font-size: 18px; 23 | text-shadow: 1px 1px 0 rgba(255,255,255,.5); 24 | -webkit-border-image: url(/assets/images/breadcrumb-2.png) 0 30 0 20 stretch stretch; 25 | -moz-border-image: url(/assets/images/breadcrumb-2.png) 0 30 0 20 stretch stretch; 26 | border-image: url(/assets/images/breadcrumb-2.png) 0 30 0 20 stretch stretch; 27 | border-width: 0 30px 0 25px; 28 | color: @titleColor; 29 | -webkit-user-select: text; 30 | &:nth-child(2) { 31 | -webkit-border-image: url(/assets/images/breadcrumb-1.png) 0 30 0 1 stretch stretch; 32 | -moz-border-image: url(/assets/images/breadcrumb-1.png) 0 30 0 1 stretch stretch; 33 | border-image: url(/assets/images/breadcrumb-1.png) 0 30 0 2 stretch stretch; 34 | } 35 | &:first-child { 36 | padding-left: 20px; 37 | } 38 | &:nth-child(1) { z-index: 3; } 39 | &:nth-child(2) { z-index: 2; } 40 | &:nth-child(3) { z-index: 1; } 41 | } 42 | } 43 | .users { 44 | position: relative; 45 | margin: 8px 10px; 46 | float: right; 47 | .pannel(); 48 | > dt { 49 | &:before { 50 | content: url(/assets/images/icons/user.png); 51 | padding-right: 4px; 52 | vertical-align: middle; 53 | } 54 | .button(); 55 | } 56 | > dd { 57 | padding: 5px 10px; 58 | width: 300px; 59 | color: @panText; 60 | z-index: 99; 61 | } 62 | .wrap { 63 | overflow: auto; 64 | max-height: 350px; 65 | width: inherit; 66 | } 67 | h3 { 68 | margin: 10px 0 0; 69 | padding: 5px 0; 70 | font-size: 16px; 71 | color: @panTitle; 72 | &:first-of-type { 73 | margin: 0; 74 | } 75 | } 76 | dl { 77 | position: relative; 78 | border-top: 1px solid @panBorder; 79 | padding: 5px 17px 5px 0; 80 | dt { 81 | .ellipsis(); 82 | span { 83 | opacity: .5; 84 | font-size: 11px; 85 | } 86 | } 87 | } 88 | .action { 89 | position: absolute; 90 | top: 5px; 91 | right: 0px; 92 | width: 16px; 93 | height: 16px; 94 | overflow: hidden; 95 | text-indent: -99em; 96 | background: #444 url(/assets/images/icons/addRemove.png) 0 1 no-repeat; 97 | border-radius: 10px; 98 | &:hover { 99 | background-color: green; 100 | } 101 | } 102 | .list .action { 103 | background-position: 0 -19px; 104 | &:hover { 105 | background-color: red; 106 | } 107 | } 108 | } 109 | } 110 | 111 | -------------------------------------------------------------------------------- /scalikejdbc-play-initializer/test/zentasks/app/assets/stylesheets/main/_drawer.less: -------------------------------------------------------------------------------- 1 | // ----------------------------------- 2 | // PROJECTS DRAWER 3 | // ----------------------------------- 4 | // author: mda@zenexity.com - 2011 5 | // ----------------------------------- 6 | body { 7 | & > nav { 8 | padding: 10px 0 0; 9 | background: @drawerBackground; 10 | border-right: 1px solid @layoutBorderColor; 11 | } 12 | .dashboard { 13 | display: block; 14 | position: relative; 15 | font-size: 11px; 16 | font-weight: 700; 17 | text-transform: uppercase; 18 | padding: 10px 5px 5px 25px; 19 | background: url(/assets/images/icons/home.png) 6px 7px no-repeat; 20 | a { 21 | color: @folderColor; 22 | cursor: default; 23 | } 24 | } 25 | h4 { 26 | cursor: default; 27 | } 28 | } 29 | 30 | #projects { 31 | input { 32 | margin: 0; 33 | padding: 0; 34 | border: 0; 35 | font: inherit; 36 | } 37 | > li { 38 | position: relative; 39 | padding: 10px 5px 5px 25px; 40 | .options { 41 | position: absolute; 42 | top: 7px; 43 | right: 5px; 44 | button { 45 | border: none; 46 | } 47 | } 48 | .loader { 49 | top: 8px; 50 | right: 6px; 51 | } 52 | li { 53 | position: relative; 54 | padding: 0 0 0 25px; 55 | background: url(/assets/images/icons/folder.png) 1px 1px no-repeat; 56 | a { 57 | display: block; 58 | color: @projectColor; 59 | padding: 2px; 60 | } 61 | input[type=text] { 62 | padding: 2px 1px; 63 | } 64 | .delete { 65 | opacity: 0.1; 66 | } 67 | .loader { 68 | top: 2px; 69 | right: 2px; 70 | } 71 | &:hover { 72 | a { 73 | color: #000; 74 | } 75 | .delete { 76 | opacity: 1; 77 | //-webkit-transition-delay: 0; 78 | } 79 | } 80 | } 81 | .toggle { 82 | content: " "; 83 | position: absolute; 84 | left: 8px; 85 | top: 12px; 86 | display: inline-block; 87 | width: 12px; 88 | height: 12px; 89 | vertical-align: middle; 90 | background: url(/assets/images/icons/drawer.folder.png) 0 0 no-repeat; 91 | } 92 | > h4 { 93 | display: block; 94 | margin: 0 0 5px; 95 | padding: 0 1px; 96 | position: relative; 97 | color: @folderColor; 98 | font-size: 11px; 99 | font-weight: 700; 100 | text-transform: uppercase; 101 | } 102 | > input { 103 | margin: 0 0 5px; 104 | text-transform: uppercase; 105 | font-weight: bold; 106 | font-size: 11px; 107 | } 108 | &.closed { 109 | >ul { 110 | display: none; 111 | } 112 | .toggle { 113 | background-position: 0 -20px; 114 | } 115 | } 116 | } 117 | } 118 | 119 | #activity { 120 | position: absolute; 121 | bottom: 0; 122 | font-size: 11px; 123 | padding: 10px; 124 | } 125 | 126 | #newGroup { 127 | font-size: 13px; 128 | .new(); 129 | margin: 15px 25px; 130 | } 131 | -------------------------------------------------------------------------------- /scalikejdbc-play-initializer/test/zentasks/app/assets/stylesheets/main/_header.less: -------------------------------------------------------------------------------- 1 | // ----------------------------------- 2 | // HEADER 3 | // ----------------------------------- 4 | // author: mda@zenexity.com - 2011 5 | // ----------------------------------- 6 | 7 | body { 8 | & > header { 9 | box-sizing: border-box; 10 | padding: 10px; 11 | z-index: 9; 12 | .gradient(@headerLight, @headerDark); 13 | box-shadow: 0 0 7px rgba(0,0,0,.8), 14 | inset 0 1px 0 rgba(255,255,255,.2), 15 | inset 0 -1px 0 rgba(0,0,0,.8); 16 | } 17 | } 18 | 19 | #logo { 20 | color: #fff; 21 | font-weight: bold; 22 | font-size: 16px; 23 | text-transform: uppercase; 24 | letter-spacing: -2px; 25 | text-shadow: 1px 1px 0 #000; 26 | span { 27 | color: @activeColor; 28 | } 29 | } 30 | 31 | #user { 32 | position: absolute; 33 | right: 10px; 34 | top: 10px; 35 | > * { 36 | display: inline-block; 37 | } 38 | dt { 39 | color: #fff; 40 | span { 41 | opacity: .5; 42 | font-size: 11px; 43 | } 44 | } 45 | dd { 46 | a , button { 47 | .button(); 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /scalikejdbc-play-initializer/test/zentasks/app/assets/stylesheets/main/_layout.less: -------------------------------------------------------------------------------- 1 | // ----------------------------------- 2 | // MAIN LAYOUT 3 | // ----------------------------------- 4 | // author: mda@zenexity.com - 2011 5 | // ----------------------------------- 6 | 7 | body { 8 | & > header { 9 | position: absolute; 10 | top: 0; 11 | left: 0; 12 | right: 0; 13 | height: @headerHeight; 14 | } 15 | & > nav { 16 | position: absolute; 17 | top: @headerHeight; 18 | left: 0; 19 | width: @drawerWidth; 20 | bottom: 0; 21 | box-sizing: border-box; 22 | } 23 | & > section { 24 | position: absolute; 25 | top: @headerHeight; 26 | left: @drawerWidth; 27 | right: 0; 28 | bottom: 0; 29 | } 30 | } 31 | 32 | #main > header { 33 | position: absolute; 34 | top: 0; 35 | left: 0; 36 | right: 0; 37 | height: @breadcrumbHeight; 38 | } 39 | 40 | #main > article { 41 | position: absolute; 42 | top: 40px; 43 | left: 0; 44 | bottom: 0; 45 | right: 0; 46 | padding: 20px; 47 | overflow: auto; 48 | } 49 | -------------------------------------------------------------------------------- /scalikejdbc-play-initializer/test/zentasks/app/assets/stylesheets/main/_widgets.less: -------------------------------------------------------------------------------- 1 | // ----------------------------------- 2 | // WIDGETS 3 | // ----------------------------------- 4 | // author: mda@zenexity.com - 2011 5 | // ----------------------------------- 6 | 7 | // --------------------------- OPTIONS 8 | .pannel(){ 9 | > dd { 10 | //display: none; 11 | .transform(scale(.001)); 12 | .transition(-webkit-transform, 200ms, ease-out); 13 | -webkit-transform-origin: right top; 14 | -moz-transform-origin: right top; 15 | transform-origin: right top; 16 | position: absolute; 17 | top: 100%; 18 | right: -2px; 19 | width: 150px; 20 | margin: 7px 0px 0 0; 21 | padding: 5px; 22 | z-index: 99; 23 | background: @panBackground; 24 | border-radius: 5px; 25 | box-shadow: 0 2px 7px @panShadow; 26 | a, button { 27 | display: block; 28 | width: 100%; 29 | padding: 3px 10px; 30 | color: @panText; 31 | border-radius: 2px; 32 | background: none; 33 | &:hover { 34 | background: @panButtonBackground; 35 | color: @panButtonColor; 36 | } 37 | } 38 | &:before { 39 | content: " "; 40 | display: block; 41 | border-bottom: 6px solid @panBackground; 42 | border-left: 6px solid transparent; 43 | border-right: 6px solid transparent; 44 | border-top: none; 45 | margin-right: 0; 46 | margin-top: -12px; 47 | position: absolute; 48 | right: 5px; 49 | width: 1px; 50 | height: 1px; 51 | } 52 | } 53 | &.opened > dd { 54 | .transform(scale(1)); 55 | } 56 | } 57 | 58 | .button() { 59 | padding: 2px 5px; 60 | border-radius: 3px; 61 | border: 1px solid @headerDark - #111; 62 | .gradient(fadeout(#bff, 80%), fadeout(#bff, 100%)); 63 | background-color: @headerDark; 64 | box-shadow: 0 1px 4px rgba(0,0,0,.3), 65 | inset 0 1px 0 rgba(255,255,255,.2), 66 | inset 0 -1px 0 rgba(0,0,0,.2); 67 | text-shadow: -1px -1px 0 rgba(0,0,0,.3); 68 | color: @buttonColor; 69 | cursor: pointer; 70 | &:hover { 71 | .gradient(fadeout(#bff, 70%), fadeout(#bff, 100%)); 72 | background-color: @headerDark; 73 | color: @buttonHover; 74 | } 75 | } 76 | 77 | .box() { 78 | border: 1px solid @folderBorder; 79 | background: @folderBackground; 80 | border-radius: 5px; 81 | margin: 0 0 20px; 82 | > header { 83 | border-radius: 5px 5px 0 0; 84 | .gradient(@folderHeaderLight, @folderHeaderDark); 85 | border-bottom: inherit; 86 | padding: 4px 7px; 87 | h3 { 88 | display: inline-block; 89 | font-size: 15px; 90 | font-weight: bold; 91 | color: @folderTitle; 92 | text-shadow: 1px 1px 0 #fff; 93 | } 94 | } 95 | } 96 | .options { 97 | width: 20px; 98 | height: 20px; 99 | position: relative; 100 | font-size: 11px; 101 | dt { 102 | width: inherit; 103 | cursor: pointer; 104 | height: inherit; 105 | text-indent: -9999em; 106 | background: url(/assets/images/icons/options.png) 0 0 no-repeat; 107 | } 108 | &:hover dt, &.opened dt, { 109 | background: url(/assets/images/icons/options.png) 0 -20px no-repeat; 110 | } 111 | .pannel(); 112 | } 113 | 114 | .new { 115 | display: inline-block; 116 | .button(); 117 | &:before { 118 | content: "+"; 119 | font-size: 15px; 120 | line-height: 15px; 121 | font-weight: bold; 122 | color: @activeColor; 123 | padding-right: 4px; 124 | } 125 | } 126 | 127 | .delete { 128 | position: absolute; 129 | top: 0px; 130 | right: 0; 131 | border: none; 132 | padding: 0; 133 | width: 18px; 134 | height: 20px; 135 | overflow: hidden; 136 | text-indent: -99em; 137 | background: url(/assets/images/icons/delete.png) 0 1px no-repeat; 138 | .transition(opacity, 300ms, ease-in-out); 139 | -webkit-transition-delay: 100ms; 140 | z-index: 7; 141 | cursor: pointer; 142 | &:hover { 143 | background: url(/assets/images/icons/delete.png) 0 -19px no-repeat; 144 | } 145 | } 146 | 147 | .counter { 148 | color: #888; 149 | font-size: 11px; 150 | text-shadow: 1px 1px 0 rgba(255,255,255,.7); 151 | margin: 2px 5px; 152 | padding: 0px 3px; 153 | background: rgba(0,0,0,.05); 154 | border-radius: 10px; 155 | border: 1px solid rgba(0,0,0,.15); 156 | } 157 | 158 | .loader { 159 | display: none; 160 | overflow: hidden; 161 | text-indent: -99em; 162 | position: absolute; 163 | height: 16px; 164 | width: 16px; 165 | background: url(/assets/images/loading.gif); 166 | } 167 | 168 | -------------------------------------------------------------------------------- /scalikejdbc-play-initializer/test/zentasks/app/controllers/Application.scala: -------------------------------------------------------------------------------- 1 | package controllers 2 | 3 | import javax.inject.{ Inject, Singleton } 4 | 5 | import models._ 6 | import play.api.data.Forms._ 7 | import play.api.data._ 8 | import play.api.mvc._ 9 | import play.api.routing.JavaScriptReverseRouter 10 | import views._ 11 | 12 | import scala.concurrent.{ ExecutionContext, Future } 13 | 14 | @Singleton 15 | class Application @Inject() (controllerComponents: ControllerComponents) 16 | extends AbstractController(controllerComponents) { 17 | 18 | // -- Authentication 19 | 20 | val loginForm = Form( 21 | tuple( 22 | "email" -> text, 23 | "password" -> text 24 | ) verifying ( 25 | "Invalid email or password", 26 | result => 27 | result match { 28 | case (email, password) => User.authenticate(email, password).isDefined 29 | } 30 | ) 31 | ) 32 | 33 | /** 34 | * Login page. 35 | */ 36 | def login = Action.async { implicit request => 37 | Future.successful(Ok(html.login(loginForm))) 38 | } 39 | 40 | /** 41 | * Handle login form submission. 42 | */ 43 | def authenticate = Action.async { implicit request => 44 | Future.successful( 45 | loginForm 46 | .bindFromRequest() 47 | .fold( 48 | formWithErrors => BadRequest(html.login(formWithErrors)), 49 | user => 50 | Redirect(routes.Projects.index()).withSession("email" -> user._1) 51 | ) 52 | ) 53 | } 54 | 55 | /** 56 | * Logout and clean the session. 57 | */ 58 | def logout = Action.async { 59 | Future.successful( 60 | Redirect(routes.Application.login()).withNewSession 61 | .flashing("success" -> "You've been logged out") 62 | ) 63 | } 64 | 65 | // -- Javascript routing 66 | 67 | def javascriptRoutes = Action.async { implicit request => 68 | import routes.javascript._ 69 | Future.successful( 70 | Ok( 71 | JavaScriptReverseRouter("jsRoutes")( 72 | Projects.add, 73 | Projects.delete, 74 | Projects.rename, 75 | Projects.addGroup, 76 | Projects.deleteGroup, 77 | Projects.renameGroup, 78 | Projects.addUser, 79 | Projects.removeUser, 80 | Tasks.addFolder, 81 | Tasks.renameFolder, 82 | Tasks.deleteFolder, 83 | Tasks.index, 84 | Tasks.add, 85 | Tasks.update, 86 | Tasks.delete 87 | ) 88 | ).as("text/javascript") 89 | ) 90 | } 91 | 92 | } 93 | 94 | /** 95 | * Provide security features 96 | */ 97 | trait Secured { self: BaseController => 98 | 99 | /** 100 | * Retrieve the connected user email. 101 | */ 102 | private def username(request: RequestHeader) = request.session.get("email") 103 | 104 | /** 105 | * Redirect to login if the user in not authorized. 106 | */ 107 | private def onUnauthorized(request: RequestHeader) = 108 | Results.Redirect(routes.Application.login()) 109 | 110 | // -- 111 | 112 | /** 113 | * Action for authenticated users. 114 | */ 115 | def IsAuthenticated(f: => String => Request[AnyContent] => Result) = 116 | Security.Authenticated(username, onUnauthorized) { user => 117 | Action(request => f(user)(request)) 118 | } 119 | 120 | /** 121 | * Check if the connected user is a member of this project. 122 | */ 123 | def IsMemberOf(project: Long)(f: => String => Request[AnyContent] => Result) = 124 | IsAuthenticated { user => request => 125 | if (Project.isMember(project, user)) { 126 | f(user)(request) 127 | } else { 128 | Results.Forbidden 129 | } 130 | } 131 | 132 | /** 133 | * Check if the connected user is a owner of this task. 134 | */ 135 | def IsOwnerOf(task: Long)(f: => String => Request[AnyContent] => Result) = 136 | IsAuthenticated { user => request => 137 | if (Task.isOwner(task, user)) { 138 | f(user)(request) 139 | } else { 140 | Results.Forbidden 141 | } 142 | } 143 | 144 | } 145 | -------------------------------------------------------------------------------- /scalikejdbc-play-initializer/test/zentasks/app/controllers/Projects.scala: -------------------------------------------------------------------------------- 1 | package controllers 2 | 3 | import javax.inject.{ Inject, Singleton } 4 | 5 | import models._ 6 | import play.api.data.Forms._ 7 | import play.api.data._ 8 | import play.api.mvc._ 9 | import views._ 10 | 11 | /** 12 | * Manage projects related operations. 13 | */ 14 | @Singleton 15 | class Projects @Inject() (controllerComponents: ControllerComponents) 16 | extends AbstractController(controllerComponents) 17 | with Secured { 18 | 19 | /** 20 | * Display the dashboard. 21 | */ 22 | def index = IsAuthenticated { username => _ => 23 | User 24 | .findByEmail(username) 25 | .map { user => 26 | Ok( 27 | html.dashboard( 28 | Project.findInvolving(username), 29 | Task.findTodoInvolving(username), 30 | user 31 | ) 32 | ) 33 | } 34 | .getOrElse(Forbidden) 35 | } 36 | 37 | // -- Projects 38 | 39 | /** 40 | * Add a project. 41 | */ 42 | def add = IsAuthenticated { username => implicit request => 43 | Form("group" -> nonEmptyText) 44 | .bindFromRequest() 45 | .fold( 46 | errors => BadRequest, 47 | folder => 48 | Ok( 49 | views.html.projects.item( 50 | Project.create(NewProject(folder, "New project"), Seq(username)) 51 | ) 52 | ) 53 | ) 54 | } 55 | 56 | /** 57 | * Delete a project. 58 | */ 59 | def delete(project: Long) = IsMemberOf(project) { username => _ => 60 | Project.delete(project) 61 | Ok 62 | } 63 | 64 | /** 65 | * Rename a project. 66 | */ 67 | def rename(project: Long) = IsMemberOf(project) { _ => implicit request => 68 | Form("name" -> nonEmptyText) 69 | .bindFromRequest() 70 | .fold( 71 | errors => BadRequest, 72 | newName => { 73 | Project.rename(project, newName) 74 | Ok(newName) 75 | } 76 | ) 77 | } 78 | 79 | // -- Project groups 80 | 81 | /** 82 | * Add a new project group. 83 | */ 84 | def addGroup = IsAuthenticated { _ => _ => 85 | Ok(html.projects.group("New group")) 86 | } 87 | 88 | /** 89 | * Delete a project group. 90 | */ 91 | def deleteGroup(folder: String) = IsAuthenticated { _ => _ => 92 | Project.deleteInFolder(folder) 93 | Ok 94 | } 95 | 96 | /** 97 | * Rename a project group. 98 | */ 99 | def renameGroup(folder: String) = IsAuthenticated { _ => implicit request => 100 | Form("name" -> nonEmptyText) 101 | .bindFromRequest() 102 | .fold( 103 | errors => BadRequest, 104 | newName => { Project.renameFolder(folder, newName); Ok(newName) } 105 | ) 106 | } 107 | 108 | // -- Members 109 | 110 | /** 111 | * Add a project member. 112 | */ 113 | def addUser(project: Long) = IsMemberOf(project) { _ => implicit request => 114 | Form("user" -> nonEmptyText) 115 | .bindFromRequest() 116 | .fold( 117 | errors => BadRequest, 118 | user => { Project.addMember(project, user); Ok } 119 | ) 120 | } 121 | 122 | /** 123 | * Remove a project member. 124 | */ 125 | def removeUser(project: Long) = IsMemberOf(project) { _ => implicit request => 126 | Form("user" -> nonEmptyText) 127 | .bindFromRequest() 128 | .fold( 129 | errors => BadRequest, 130 | user => { Project.removeMember(project, user); Ok } 131 | ) 132 | } 133 | 134 | } 135 | -------------------------------------------------------------------------------- /scalikejdbc-play-initializer/test/zentasks/app/controllers/Tasks.scala: -------------------------------------------------------------------------------- 1 | package controllers 2 | 3 | import javax.inject.{ Inject, Singleton } 4 | 5 | import models._ 6 | import play.api.data.Forms._ 7 | import play.api.data._ 8 | import play.api.mvc._ 9 | import views._ 10 | import scala.concurrent.Future 11 | 12 | /** 13 | * Manage tasks related operations. 14 | */ 15 | @Singleton 16 | class Tasks @Inject() (controllerComponents: ControllerComponents) 17 | extends AbstractController(controllerComponents) 18 | with Secured { 19 | 20 | /** 21 | * Display the tasks panel for this project. 22 | */ 23 | def index(project: Long) = IsMemberOf(project) { _ => implicit request => 24 | Project 25 | .findById(project) 26 | .map { p => 27 | val tasks = Task.findByProject(project) 28 | val team = Project.membersOf(project) 29 | Ok(html.tasks.index(p, tasks, team)) 30 | } 31 | .getOrElse(NotFound) 32 | } 33 | 34 | val taskForm = Form( 35 | tuple( 36 | "title" -> nonEmptyText, 37 | "dueDate" -> optional(date("MM/dd/yy")), 38 | "assignedTo" -> optional(text) 39 | ) 40 | ) 41 | 42 | // -- Tasks 43 | 44 | /** 45 | * Create a task in this project. 46 | */ 47 | def add(project: Long, folder: String) = IsMemberOf(project) { 48 | _ => implicit request => 49 | taskForm 50 | .bindFromRequest() 51 | .fold( 52 | errors => BadRequest, 53 | { case (title, dueDate, assignedTo) => 54 | val task = Task.create( 55 | NewTask(folder, project, title, false, dueDate, assignedTo) 56 | ) 57 | Ok(html.tasks.item(task)) 58 | } 59 | ) 60 | } 61 | 62 | /** 63 | * Update a task 64 | */ 65 | def update(task: Long) = IsOwnerOf(task) { _ => implicit request => 66 | Form("done" -> boolean) 67 | .bindFromRequest() 68 | .fold( 69 | errors => BadRequest, 70 | isDone => { 71 | Task.markAsDone(task, isDone) 72 | Ok 73 | } 74 | ) 75 | } 76 | 77 | /** 78 | * Delete a task 79 | */ 80 | def delete(task: Long) = IsOwnerOf(task) { _ => implicit request => 81 | Task.delete(task) 82 | Ok 83 | } 84 | 85 | // -- Task folders 86 | 87 | /** 88 | * Add a new folder. 89 | */ 90 | def addFolder = Action.async { 91 | Future.successful(Ok(html.tasks.folder("New folder"))) 92 | } 93 | 94 | /** 95 | * Delete a full tasks folder. 96 | */ 97 | def deleteFolder(project: Long, folder: String) = IsMemberOf(project) { 98 | _ => implicit request => 99 | Task.deleteInFolder(project, folder) 100 | Ok 101 | } 102 | 103 | /** 104 | * Rename a tasks folder. 105 | */ 106 | def renameFolder(project: Long, folder: String) = IsMemberOf(project) { 107 | _ => implicit request => 108 | Form("name" -> nonEmptyText) 109 | .bindFromRequest() 110 | .fold( 111 | errors => BadRequest, 112 | newName => { 113 | Task.renameFolder(project, folder, newName) 114 | Ok(newName) 115 | } 116 | ) 117 | } 118 | 119 | } 120 | -------------------------------------------------------------------------------- /scalikejdbc-play-initializer/test/zentasks/app/models/Project.scala: -------------------------------------------------------------------------------- 1 | package models 2 | 3 | import scalikejdbc._ 4 | 5 | case class ProjectMember(projectId: Long, userEmail: String) 6 | 7 | object ProjectMember extends SQLSyntaxSupport[ProjectMember] { 8 | def apply(syntax: SyntaxProvider[ProjectMember])(rs: WrappedResultSet) = { 9 | val p = syntax.resultName 10 | new ProjectMember( 11 | projectId = rs.long(p.projectId), 12 | userEmail = rs.string(p.userEmail) 13 | ) 14 | } 15 | } 16 | 17 | case class NewProject(folder: String, name: String) 18 | 19 | case class Project(id: Long, folder: String, name: String) 20 | 21 | object Project extends SQLSyntaxSupport[Project] { 22 | 23 | def apply(syntax: SyntaxProvider[Project])(rs: WrappedResultSet) = { 24 | val p = syntax.resultName 25 | new Project( 26 | id = rs.long(p.id), 27 | folder = rs.string(p.folder), 28 | name = rs.string(p.name) 29 | ) 30 | } 31 | 32 | private val p = Project.syntax("p") 33 | private val u = User.syntax("u") 34 | private val m = ProjectMember.syntax("m") 35 | 36 | private val auto = AutoSession 37 | 38 | def findById(id: Long)(implicit s: DBSession = auto): Option[Project] = 39 | withSQL { 40 | select.from(Project as p).where.eq(p.id, id) 41 | }.map(Project(p)).single.apply() 42 | 43 | def findInvolving(user: String)(implicit s: DBSession = auto): Seq[Project] = 44 | withSQL { 45 | select 46 | .from(Project as p) 47 | .join(ProjectMember as m) 48 | .on(p.id, m.projectId) 49 | .where 50 | .eq(m.userEmail, user) 51 | }.map(Project(p)).list.apply() 52 | 53 | def rename(id: Long, newName: String)(implicit s: DBSession = auto): Unit = 54 | applyUpdate { 55 | update(Project as p).set(p.name -> newName).where.eq(p.id, id) 56 | } 57 | 58 | def delete(id: Long)(implicit s: DBSession = auto): Unit = applyUpdate { 59 | deleteFrom(Project as p).where.eq(p.id, id) 60 | } 61 | 62 | def deleteInFolder(folder: String)(implicit s: DBSession = auto): Unit = 63 | applyUpdate { 64 | deleteFrom(Project as p).where.eq(p.folder, folder) 65 | } 66 | 67 | def renameFolder(folder: String, newName: String)(implicit 68 | s: DBSession = auto 69 | ): Unit = applyUpdate { 70 | update(Project as p).set(p.folder -> newName).where.eq(p.folder, folder) 71 | } 72 | 73 | def membersOf(project: Long)(implicit s: DBSession = auto): Seq[User] = 74 | withSQL { 75 | select 76 | .from(User as u) 77 | .join(ProjectMember as m) 78 | .on(m.userEmail, u.email) 79 | .where 80 | .eq(m.projectId, project) 81 | }.map(User(u)).list.apply() 82 | 83 | def addMember(project: Long, user: String)(implicit 84 | s: DBSession = auto 85 | ): Unit = applyUpdate { 86 | insert.into(ProjectMember).values(project, user) 87 | } 88 | 89 | def removeMember(project: Long, user: String)(implicit 90 | s: DBSession = auto 91 | ): Unit = applyUpdate { 92 | deleteFrom(ProjectMember as m).where 93 | .eq(m.projectId, project) 94 | .and 95 | .eq(m.userEmail, user) 96 | } 97 | 98 | def isMember(project: Long, user: String)(implicit 99 | s: DBSession = auto 100 | ): Boolean = withSQL { 101 | select(sqls"count(${u.email}) = 1 as is_member") 102 | .from(User as u) 103 | .join(ProjectMember as m) 104 | .on(m.userEmail, u.email) 105 | .where 106 | .eq(m.projectId, project) 107 | .and 108 | .eq(u.email, user) 109 | }.map(rs => rs.boolean("is_member").asInstanceOf[Boolean]) 110 | .single 111 | .apply() 112 | .getOrElse(false) 113 | 114 | def create(project: NewProject, members: Seq[String])(implicit 115 | s: DBSession = auto 116 | ): Project = { 117 | // Insert the project 118 | val newId = sql"select next value for project_seq as v from dual" 119 | .map(_.long("v")) 120 | .single 121 | .apply() 122 | .get 123 | applyUpdate { 124 | insert.into(Project).values(newId, project.name, project.folder) 125 | } 126 | // Add members 127 | members foreach { email => 128 | applyUpdate(insert.into(ProjectMember).values(newId, email)) 129 | } 130 | Project(id = newId, name = project.name, folder = project.folder) 131 | } 132 | 133 | } 134 | -------------------------------------------------------------------------------- /scalikejdbc-play-initializer/test/zentasks/app/models/Task.scala: -------------------------------------------------------------------------------- 1 | package models 2 | 3 | import java.util.Date 4 | 5 | import scalikejdbc._ 6 | 7 | case class NewTask( 8 | folder: String, 9 | project: Long, 10 | title: String, 11 | done: Boolean, 12 | dueDate: Option[Date], 13 | assignedTo: Option[String] 14 | ) 15 | 16 | case class Task( 17 | id: Long, 18 | folder: String, 19 | project: Long, 20 | title: String, 21 | done: Boolean, 22 | dueDate: Option[Date], 23 | assignedTo: Option[String] 24 | ) 25 | 26 | object Task extends SQLSyntaxSupport[Task] { 27 | 28 | def apply(syntax: SyntaxProvider[Task])(rs: WrappedResultSet) = { 29 | val t = syntax.resultName 30 | new Task( 31 | id = rs.long(t.id), 32 | folder = rs.string(t.folder), 33 | project = rs.long(t.project), 34 | title = rs.string(t.title), 35 | done = rs.boolean(t.done), 36 | dueDate = rs.timestampOpt(t.dueDate), 37 | assignedTo = rs.stringOpt(t.assignedTo) 38 | ) 39 | } 40 | 41 | def apply(t: SyntaxProvider[Task], p: SyntaxProvider[Project])( 42 | rs: WrappedResultSet 43 | ): (Task, Project) = (Task(t)(rs), Project(p)(rs)) 44 | 45 | private val t = Task.syntax("t") 46 | private val p = Project.syntax("p") 47 | private val m = ProjectMember.syntax("m") 48 | 49 | private val auto = AutoSession 50 | 51 | def findById(id: Long)(implicit s: DBSession = auto): Option[Task] = withSQL { 52 | select.from(Task as t).where.eq(t.id, id) 53 | }.map(Task(t)).single.apply() 54 | 55 | def findTodoInvolving( 56 | user: String 57 | )(implicit s: DBSession = auto): Seq[(Task, Project)] = withSQL { 58 | select 59 | .from(Task as t) 60 | .join(ProjectMember as m) 61 | .on(m.projectId, t.project) 62 | .join(Project as p) 63 | .on(p.id, m.projectId) 64 | .where 65 | .append(sqls"${t.done} = false") 66 | .and 67 | .eq(m.userEmail, user) 68 | }.map(Task(t, p)).list.apply() 69 | 70 | def findByProject(project: Long)(implicit s: DBSession = auto): Seq[Task] = 71 | withSQL { 72 | select.from(Task as t).where.eq(t.project, project) 73 | }.map(Task(t)).list.apply() 74 | 75 | /** 76 | * Delete a task 77 | */ 78 | def delete(id: Long)(implicit s: DBSession = auto): Unit = applyUpdate { 79 | deleteFrom(Task as t).where.eq(t.id, id) 80 | } 81 | 82 | def deleteInFolder(projectId: Long, folder: String)(implicit 83 | s: DBSession = auto 84 | ): Unit = applyUpdate { 85 | deleteFrom(Task as t).where 86 | .eq(t.project, projectId) 87 | .and 88 | .eq(t.folder, folder) 89 | } 90 | 91 | def markAsDone(taskId: Long, done: Boolean)(implicit 92 | s: DBSession = auto 93 | ): Unit = applyUpdate { 94 | update(Task as t).set(t.done -> done).where.eq(t.id, taskId) 95 | } 96 | 97 | def renameFolder(projectId: Long, folder: String, newName: String)(implicit 98 | s: DBSession = auto 99 | ): Unit = applyUpdate { 100 | update(Task as t) 101 | .set(t.folder -> newName) 102 | .where 103 | .eq(t.folder, folder) 104 | .and 105 | .eq(t.project, projectId) 106 | } 107 | 108 | def isOwner(task: Long, user: String)(implicit s: DBSession = auto): Boolean = 109 | withSQL { 110 | select(sqls"count(${t.id}) = 1 as v") 111 | .from(Task as t) 112 | .join(Project as p) 113 | .on(t.project, p.id) 114 | .join(ProjectMember as m) 115 | .on(m.projectId, p.id) 116 | .where 117 | .eq(m.userEmail, user) 118 | .and 119 | .eq(t.id, task) 120 | }.map(rs => rs.boolean("v").asInstanceOf[Boolean]) 121 | .single 122 | .apply() 123 | .getOrElse(false) 124 | 125 | def create(task: NewTask)(implicit s: DBSession = auto): Task = { 126 | val newId = sql"select next value for task_seq as v from dual" 127 | .map(rs => rs.long("v")) 128 | .single 129 | .apply() 130 | .get 131 | applyUpdate { 132 | insert 133 | .into(Task) 134 | .values( 135 | newId, 136 | task.title, 137 | task.done, 138 | task.dueDate, 139 | task.assignedTo, 140 | task.project, 141 | task.folder 142 | ) 143 | } 144 | Task( 145 | id = newId, 146 | folder = task.folder, 147 | project = task.project, 148 | title = task.title, 149 | done = task.done, 150 | dueDate = task.dueDate, 151 | assignedTo = task.assignedTo 152 | ) 153 | } 154 | 155 | } 156 | -------------------------------------------------------------------------------- /scalikejdbc-play-initializer/test/zentasks/app/models/User.scala: -------------------------------------------------------------------------------- 1 | package models 2 | 3 | import scalikejdbc._ 4 | 5 | case class User(email: String, name: String, password: String) 6 | 7 | object User extends SQLSyntaxSupport[User] { 8 | 9 | override val tableName = "users" 10 | override val columns = Seq("email", "name", "password") 11 | 12 | def apply(syntax: SyntaxProvider[User])(rs: WrappedResultSet) = { 13 | val u = syntax.resultName 14 | new User( 15 | email = rs.string(u.email), 16 | name = rs.string(u.name), 17 | password = rs.string(u.password) 18 | ) 19 | } 20 | 21 | private val u = User.syntax("u") 22 | 23 | private val auto = AutoSession 24 | 25 | def findByEmail(email: String)(implicit s: DBSession = auto): Option[User] = 26 | withSQL { 27 | select.from(User as u).where.eq(u.email, email) 28 | }.map(User(u)).single.apply() 29 | 30 | def findAll()(implicit s: DBSession = auto): Seq[User] = withSQL { 31 | select.from(User as u) 32 | }.map(User(u)).list.apply() 33 | 34 | def authenticate(email: String, password: String)(implicit 35 | s: DBSession = auto 36 | ): Option[User] = withSQL { 37 | select.from(User as u).where.eq(u.email, email).and.eq(u.password, password) 38 | }.map(User(u)).single.apply() 39 | 40 | def create(user: User)(implicit s: DBSession = auto): User = { 41 | applyUpdate { 42 | insert.into(User).values(user.email, user.name, user.password) 43 | } 44 | user 45 | } 46 | 47 | } 48 | -------------------------------------------------------------------------------- /scalikejdbc-play-initializer/test/zentasks/app/views/dashboard.scala.html: -------------------------------------------------------------------------------- 1 | @(projects: Seq[Project], todoTasks: Seq[(Task,Project)], user: User) 2 | 3 | @main(projects, user){ 4 | 5 |
    6 |
    7 |

    Dashboard

    8 |

    Tasks over all projects

    9 |
    10 |
    11 | 12 |
    13 | @todoTasks.groupBy(_._2).map { 14 | case (project, projectTasks) => { 15 |
    16 |
    17 |

    @project.name

    18 | Loading 19 |
    20 |
      21 | @projectTasks.map { 22 | case (task, _) => { 23 | @tasks.item(task, isEditable = false) 24 | } 25 | } 26 |
    27 |
    28 | } 29 | } 30 |
    31 | 32 | } 33 | 34 | -------------------------------------------------------------------------------- /scalikejdbc-play-initializer/test/zentasks/app/views/login.scala.html: -------------------------------------------------------------------------------- 1 | @(form: Form[(String,String)])(implicit flash: Flash) 2 | 3 | 4 | 5 | Zentasks 6 | 7 | 8 | 9 | 10 | 11 |
    12 | 13 |
    14 | 15 | @helper.form(routes.Application.authenticate()) { 16 | 17 |

    Sign in

    18 | 19 | @form.globalError.map { error => 20 |

    21 | @error.message 22 |

    23 | } 24 | 25 | @flash.get("success").map { message => 26 |

    27 | @message 28 |

    29 | } 30 | 31 |

    32 | 33 |

    34 |

    35 | 36 |

    37 |

    38 | 39 |

    40 | 41 | } 42 | 43 |

    44 | Try guillaume@@sample.com with secret as password. 45 |

    46 | 47 | 48 | 49 | 50 | 51 | 52 | -------------------------------------------------------------------------------- /scalikejdbc-play-initializer/test/zentasks/app/views/main.scala.html: -------------------------------------------------------------------------------- 1 | @(projects: Seq[Project], user: User)(body: Html) 2 | 3 | 4 | 5 | Zentasks 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 |
    17 | 18 |
    19 |
    @user.name (@user.email)
    20 |
    21 | Logout 22 |
    23 |
    24 |
    25 | 36 |
    37 | @body 38 |
    39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /scalikejdbc-play-initializer/test/zentasks/app/views/projects/group.scala.html: -------------------------------------------------------------------------------- 1 | @(group: String, projects: Seq[Project] = Nil) 2 | 3 |
  • 4 | 5 |

    @group

    6 | Loading 7 |
    8 |
    Options
    9 |
    10 | 11 | 12 |
    13 |
    14 | 19 |
  • 20 | -------------------------------------------------------------------------------- /scalikejdbc-play-initializer/test/zentasks/app/views/projects/item.scala.html: -------------------------------------------------------------------------------- 1 | @(project: Project) 2 | 3 |
  • 4 | @project.name 5 | 6 | Loading 7 |
  • 8 | -------------------------------------------------------------------------------- /scalikejdbc-play-initializer/test/zentasks/app/views/tasks/folder.scala.html: -------------------------------------------------------------------------------- 1 | @(folder: String, tasks: Seq[Task] = Nil) 2 | 3 |
    4 |
    5 | 6 |

    @folder

    7 | 8 |
    9 |
    Options
    10 |
    11 | Remove complete tasks 12 | Remove all tasks 13 | Delete folder 14 |
    15 |
    16 | Loading 17 |
    18 | 23 |
    24 | 25 | 26 | 27 |
    28 | 29 |
    30 | 31 |
    32 |
    33 | 34 | -------------------------------------------------------------------------------- /scalikejdbc-play-initializer/test/zentasks/app/views/tasks/index.scala.html: -------------------------------------------------------------------------------- 1 | @(project:Project, tasks: Seq[Task], team: Seq[User]) 2 | 3 |
    4 |
    5 |

    @project.folder

    6 |

    @project.name

    7 |
    8 |
    9 |
    Project's team
    10 |
    11 |
    12 |

    Team mates

    13 |
    14 | @team.map { user => 15 |
    16 |
    @user.name (@user.email)
    17 |
    Action
    18 |
    19 | } 20 |
    21 |

    Add a team mate

    22 |
    23 | @User.findAll().diff(team).map { user => 24 |
    25 |
    @user.name (@user.email)
    26 |
    Action
    27 |
    28 | } 29 |
    30 |
    31 |
    32 |
    33 |
    34 |
    35 | @tasks.groupBy(_.folder).map { 36 | case (folder, tasks) => { 37 | @views.html.tasks.folder(folder, tasks) 38 | } 39 | } 40 | New folder 41 |
    42 | 43 | -------------------------------------------------------------------------------- /scalikejdbc-play-initializer/test/zentasks/app/views/tasks/item.scala.html: -------------------------------------------------------------------------------- 1 | @(task: Task, isEditable: Boolean = true) 2 | 3 |
  • 4 | 5 | @if(isEditable) { 6 | 7 | } 8 | 9 |

    @task.title

    10 | 11 | @task.dueDate.map { date => 12 | 13 | } 14 | 15 | @task.assignedTo.map { user => 16 | @user 17 | } 18 | 19 | @if(isEditable) { 20 | Delete task 21 | Loading 22 | } 23 | 24 |
  • 25 | -------------------------------------------------------------------------------- /scalikejdbc-play-initializer/test/zentasks/conf/application.conf: -------------------------------------------------------------------------------- 1 | # Configuration 2 | 3 | application.name=Zentasks 4 | 5 | # Secret key 6 | # ~~~~~ 7 | # The secret key is used to secure cryptographics functions. 8 | # If you deploy your application to several instances be sure to use the same key! 9 | application.secret="E27D^[_9W" 10 | 11 | # Database configuration 12 | # ~~~~~ 13 | # You can declare as many datasources as you want. 14 | # By convention, the default datasource is named `default` 15 | db.default.driver=org.h2.Driver 16 | db.default.url="jdbc:h2:mem:play;DB_CLOSE_DELAY=-1" 17 | db.default.username=sa 18 | db.secondary.driver=org.h2.Driver 19 | db.secondary.url="jdbc:h2:mem:secondary;DB_CLOSE_DELAY=-1" 20 | db.default.fixtures.dev=[ "users.sql", "project.sql", "project_member.sql", "task.sql" ] 21 | db.default.fixtures.test=[ "users.sql", "project.sql", "project_member.sql", "task.sql" ] 22 | db.secondary.fixtures.test=[ "users.sql", "project.sql", "project_member.sql", "task.sql" ] 23 | 24 | #db.default.password=sa 25 | 26 | # ScalikeJDBC original configuration 27 | #db.default.poolInitialSize=10 28 | #db.default.poolMaxSize=10 29 | #db.default.poolValidationQuery= 30 | 31 | scalikejdbc.global.loggingSQLAndTime.enabled=true 32 | #scalikejdbc.global.loggingSQLAndTime.singleLineMode=true 33 | scalikejdbc.global.loggingSQLAndTime.logLevel=debug 34 | scalikejdbc.global.loggingSQLAndTime.warningEnabled=true 35 | scalikejdbc.global.loggingSQLAndTime.warningThresholdMillis=5 36 | scalikejdbc.global.loggingSQLAndTime.warningLogLevel=warn 37 | 38 | # You can disable the default DB plugin 39 | dbplugin=disabled 40 | evolutionplugin=disabled 41 | 42 | # Logger 43 | # ~~~~~ 44 | # You can also configure logback (http://logback.qos.ch/), by providing a logger.xml file in the conf directory . 45 | 46 | # Root logger: 47 | logger.root=DEBUG 48 | 49 | # Logger used by the framework: 50 | logger.play=DEBUG 51 | 52 | # Logger provided to your application: 53 | logger.application=DEBUG 54 | 55 | play.modules.enabled += "org.flywaydb.play.PlayModule" 56 | play.modules.enabled += "scalikejdbc.PlayModule" 57 | play.modules.enabled += "scalikejdbc.PlayFixtureModule" 58 | -------------------------------------------------------------------------------- /scalikejdbc-play-initializer/test/zentasks/conf/db/fixtures/default/project.sql: -------------------------------------------------------------------------------- 1 | # --- !Ups 2 | 3 | INSERT INTO project (id, name, folder) VALUES (1, 'Play 2.0', 'Play framework'); 4 | INSERT INTO project (id, name, folder) VALUES (2, 'Play 1.2.4', 'Play framework'); 5 | INSERT INTO project (id, name, folder) VALUES (3, 'Website', 'Play framework'); 6 | INSERT INTO project (id, name, folder) VALUES (4, 'Secret project', 'Zenexity'); 7 | INSERT INTO project (id, name, folder) VALUES (5, 'Playmate', 'Zenexity'); 8 | INSERT INTO project (id, name, folder) VALUES (6, 'Things to do', 'Personal'); 9 | INSERT INTO project (id, name, folder) VALUES (7, 'Play samples', 'Zenexity'); 10 | INSERT INTO project (id, name, folder) VALUES (8, 'Private', 'Personal'); 11 | INSERT INTO project (id, name, folder) VALUES (9, 'Private', 'Personal'); 12 | INSERT INTO project (id, name, folder) VALUES (10, 'Private', 'Personal'); 13 | INSERT INTO project (id, name, folder) VALUES (11, 'Private', 'Personal'); 14 | ALTER SEQUENCE project_seq RESTART WITH 12; 15 | 16 | # --- !Downs 17 | ALTER SEQUENCE project_seq RESTART WITH 1; 18 | DELETE FROM project; -------------------------------------------------------------------------------- /scalikejdbc-play-initializer/test/zentasks/conf/db/fixtures/default/project_member.sql: -------------------------------------------------------------------------------- 1 | # --- !Ups 2 | 3 | INSERT INTO project_member (project_id, user_email) VALUES (1, 'guillaume@sample.com'); 4 | INSERT INTO project_member (project_id, user_email) VALUES (1, 'maxime@sample.com'); 5 | INSERT INTO project_member (project_id, user_email) VALUES (1, 'sadek@sample.com'); 6 | INSERT INTO project_member (project_id, user_email) VALUES (1, 'erwan@sample.com'); 7 | INSERT INTO project_member (project_id, user_email) VALUES (2, 'guillaume@sample.com'); 8 | INSERT INTO project_member (project_id, user_email) VALUES (2, 'erwan@sample.com'); 9 | INSERT INTO project_member (project_id, user_email) VALUES (3, 'guillaume@sample.com'); 10 | INSERT INTO project_member (project_id, user_email) VALUES (3, 'maxime@sample.com'); 11 | INSERT INTO project_member (project_id, user_email) VALUES (4, 'guillaume@sample.com'); 12 | INSERT INTO project_member (project_id, user_email) VALUES (4, 'maxime@sample.com'); 13 | INSERT INTO project_member (project_id, user_email) VALUES (4, 'sadek@sample.com'); 14 | INSERT INTO project_member (project_id, user_email) VALUES (4, 'erwan@sample.com'); 15 | INSERT INTO project_member (project_id, user_email) VALUES (5, 'maxime@sample.com'); 16 | INSERT INTO project_member (project_id, user_email) VALUES (6, 'guillaume@sample.com'); 17 | INSERT INTO project_member (project_id, user_email) VALUES (7, 'guillaume@sample.com'); 18 | INSERT INTO project_member (project_id, user_email) VALUES (7, 'maxime@sample.com'); 19 | INSERT INTO project_member (project_id, user_email) VALUES (8, 'maxime@sample.com'); 20 | INSERT INTO project_member (project_id, user_email) VALUES (9, 'guillaume@sample.com'); 21 | INSERT INTO project_member (project_id, user_email) VALUES (10, 'erwan@sample.com'); 22 | INSERT INTO project_member (project_id, user_email) VALUES (11, 'sadek@sample.com'); 23 | 24 | # --- !Downs 25 | 26 | DELETE FROM project_member; 27 | -------------------------------------------------------------------------------- /scalikejdbc-play-initializer/test/zentasks/conf/db/fixtures/default/task.sql: -------------------------------------------------------------------------------- 1 | # --- !Ups 2 | 3 | INSERT INTO task (id, title, done, due_date, assigned_to, project, folder) VALUES (1000, 'Fix the documentation', FALSE, null, 'guillaume@sample.com', 1, 'Todo'); 4 | INSERT INTO task (id, title, done, due_date, assigned_to, project, folder) VALUES (1001, 'Prepare the beta release', FALSE, '2011-11-15 00:00:00.0', null, 1, 'Urgent'); 5 | INSERT INTO task (id, title, done, due_date, assigned_to, project, folder) VALUES (1002, 'Buy some milk', FALSE, null, null, 9, 'Todo'); 6 | INSERT INTO task (id, title, done, due_date, assigned_to, project, folder) VALUES (1003, 'Check 1.2.4-RC2', FALSE, '2011-11-18 00:00:00.0', 'guillaume@sample.com', 2, 'Todo'); 7 | INSERT INTO task (id, title, done, due_date, assigned_to, project, folder) VALUES (1004, 'Finish zentask integration', TRUE, '2011-11-15 00:00:00.0', 'maxime@sample.com', 7, 'Todo'); 8 | INSERT INTO task (id, title, done, due_date, assigned_to, project, folder) VALUES (1005, 'Release the secret project', FALSE, '2012-01-01 00:00:00.0', 'sadek@sample.com', 4, 'Todo'); 9 | ALTER SEQUENCE task_seq RESTART WITH 1006; 10 | 11 | # --- !Downs 12 | ALTER SEQUENCE task_seq RESTART WITH 1000; 13 | DELETE FROM task; 14 | 15 | -------------------------------------------------------------------------------- /scalikejdbc-play-initializer/test/zentasks/conf/db/fixtures/default/users.sql: -------------------------------------------------------------------------------- 1 | # --- !Ups 2 | INSERT INTO users (email, name, password) VALUES ('guillaume@sample.com', 'Guillaume Bort', 'secret'); 3 | INSERT INTO users (email, name, password) VALUES ('maxime@sample.com', 'Maxime Dantec', 'secret'); 4 | INSERT INTO users (email, name, password) VALUES ('sadek@sample.com', 'Sadek Drobi', 'secret'); 5 | INSERT INTO users (email, name, password) VALUES ('erwan@sample.com', 'Erwan Loisant', 'secret'); 6 | 7 | 8 | # --- !Downs 9 | DELETE FROM users; 10 | -------------------------------------------------------------------------------- /scalikejdbc-play-initializer/test/zentasks/conf/db/fixtures/secondary/project.sql: -------------------------------------------------------------------------------- 1 | # --- !Ups 2 | 3 | INSERT INTO project (id, name, folder) VALUES (1, 'Play 2.0', 'Play framework'); 4 | INSERT INTO project (id, name, folder) VALUES (2, 'Play 1.2.4', 'Play framewor'); 5 | INSERT INTO project (id, name, folder) VALUES (3, 'Website', 'Play framework'); 6 | INSERT INTO project (id, name, folder) VALUES (4, 'Secret project', 'Zenexity'); 7 | INSERT INTO project (id, name, folder) VALUES (5, 'Playmate', 'Zenexity'); 8 | INSERT INTO project (id, name, folder) VALUES (6, 'Things to do', 'Personal'); 9 | INSERT INTO project (id, name, folder) VALUES (7, 'Play samples', 'Zenexity'); 10 | INSERT INTO project (id, name, folder) VALUES (8, 'Private', 'Personal'); 11 | INSERT INTO project (id, name, folder) VALUES (9, 'Private', 'Personal'); 12 | INSERT INTO project (id, name, folder) VALUES (10, 'Private', 'Personal'); 13 | INSERT INTO project (id, name, folder) VALUES (11, 'Private', 'Personal'); 14 | ALTER SEQUENCE project_seq RESTART WITH 12; 15 | 16 | # --- !Downs 17 | ALTER SEQUENCE project_seq RESTART WITH 1; 18 | DELETE FROM project; -------------------------------------------------------------------------------- /scalikejdbc-play-initializer/test/zentasks/conf/db/fixtures/secondary/project_member.sql: -------------------------------------------------------------------------------- 1 | # --- !Ups 2 | 3 | INSERT INTO project_member (project_id, user_email) VALUES (1, 'guillaume@sample.com'); 4 | INSERT INTO project_member (project_id, user_email) VALUES (1, 'maxime@sample.com'); 5 | INSERT INTO project_member (project_id, user_email) VALUES (1, 'sadek@sample.com'); 6 | INSERT INTO project_member (project_id, user_email) VALUES (1, 'erwan@sample.com'); 7 | INSERT INTO project_member (project_id, user_email) VALUES (2, 'guillaume@sample.com'); 8 | INSERT INTO project_member (project_id, user_email) VALUES (2, 'erwan@sample.com'); 9 | INSERT INTO project_member (project_id, user_email) VALUES (3, 'guillaume@sample.com'); 10 | INSERT INTO project_member (project_id, user_email) VALUES (3, 'maxime@sample.com'); 11 | INSERT INTO project_member (project_id, user_email) VALUES (4, 'guillaume@sample.com'); 12 | INSERT INTO project_member (project_id, user_email) VALUES (4, 'maxime@sample.com'); 13 | INSERT INTO project_member (project_id, user_email) VALUES (4, 'sadek@sample.com'); 14 | INSERT INTO project_member (project_id, user_email) VALUES (4, 'erwan@sample.com'); 15 | INSERT INTO project_member (project_id, user_email) VALUES (5, 'maxime@sample.com'); 16 | INSERT INTO project_member (project_id, user_email) VALUES (6, 'guillaume@sample.com'); 17 | INSERT INTO project_member (project_id, user_email) VALUES (7, 'guillaume@sample.com'); 18 | INSERT INTO project_member (project_id, user_email) VALUES (7, 'maxime@sample.com'); 19 | INSERT INTO project_member (project_id, user_email) VALUES (8, 'maxime@sample.com'); 20 | INSERT INTO project_member (project_id, user_email) VALUES (9, 'guillaume@sample.com'); 21 | INSERT INTO project_member (project_id, user_email) VALUES (10, 'erwan@sample.com'); 22 | INSERT INTO project_member (project_id, user_email) VALUES (11, 'sadek@sample.com'); 23 | 24 | # --- !Downs 25 | 26 | DELETE FROM project_member; 27 | -------------------------------------------------------------------------------- /scalikejdbc-play-initializer/test/zentasks/conf/db/fixtures/secondary/task.sql: -------------------------------------------------------------------------------- 1 | # --- !Ups 2 | 3 | INSERT INTO task (id, title, done, due_date, assigned_to, project, folder) VALUES (1000, 'Fix the documentation', FALSE, null, 'guillaume@sample.com', 1, 'Todo'); 4 | INSERT INTO task (id, title, done, due_date, assigned_to, project, folder) VALUES (1001, 'Prepare the beta release', FALSE, '2011-11-15 00:00:00.0', null, 1, 'Urgent'); 5 | INSERT INTO task (id, title, done, due_date, assigned_to, project, folder) VALUES (1002, 'Buy some milk', FALSE, null, null, 9, 'Todo'); 6 | INSERT INTO task (id, title, done, due_date, assigned_to, project, folder) VALUES (1003, 'Check 1.2.4-RC2', FALSE, '2011-11-18 00:00:00.0', 'guillaume@sample.com', 2, 'Todo'); 7 | INSERT INTO task (id, title, done, due_date, assigned_to, project, folder) VALUES (1004, 'Finish zentask integration', TRUE, '2011-11-15 00:00:00.0', 'maxime@sample.com', 7, 'Todo'); 8 | INSERT INTO task (id, title, done, due_date, assigned_to, project, folder) VALUES (1005, 'Release the secret project', FALSE, '2012-01-01 00:00:00.0', 'sadek@sample.com', 4, 'Todo'); 9 | ALTER SEQUENCE task_seq RESTART WITH 1006; 10 | 11 | # --- !Downs 12 | ALTER SEQUENCE task_seq RESTART WITH 1000; 13 | DELETE FROM task; 14 | 15 | -------------------------------------------------------------------------------- /scalikejdbc-play-initializer/test/zentasks/conf/db/fixtures/secondary/users.sql: -------------------------------------------------------------------------------- 1 | # --- !Ups 2 | INSERT INTO users (email, name, password) VALUES ('guillaume@sample.com', 'Guillaume Bort', 'secret'); 3 | INSERT INTO users (email, name, password) VALUES ('maxime@sample.com', 'Maxime Dantec', 'secret'); 4 | INSERT INTO users (email, name, password) VALUES ('sadek@sample.com', 'Sadek Drobi', 'secret'); 5 | INSERT INTO users (email, name, password) VALUES ('erwan@sample.com', 'Erwan Loisant', 'secret'); 6 | 7 | 8 | # --- !Downs 9 | DELETE FROM users; 10 | -------------------------------------------------------------------------------- /scalikejdbc-play-initializer/test/zentasks/conf/db/migration/default/V1__create_tables.sql: -------------------------------------------------------------------------------- 1 | drop table if exists users; 2 | create table users ( 3 | email varchar(255) not null primary key, 4 | name varchar(255) not null, 5 | password varchar(255) not null 6 | ); 7 | 8 | drop table if exists project; 9 | create table project ( 10 | id bigint not null primary key, 11 | name varchar(255) not null, 12 | folder varchar(255) not null 13 | ); 14 | 15 | drop sequence if exists project_seq; 16 | create sequence project_seq start with 1000; 17 | 18 | drop table if exists project_member; 19 | create table project_member ( 20 | project_id bigint not null, 21 | user_email varchar(255) not null, 22 | foreign key(project_id) references project(id) on delete cascade, 23 | foreign key(user_email) references users(email) on delete cascade 24 | ); 25 | 26 | drop table if exists task; 27 | create table task ( 28 | id bigint not null primary key, 29 | title varchar(255) not null, 30 | done boolean, 31 | due_date timestamp, 32 | assigned_to varchar(255), 33 | project bigint not null, 34 | folder varchar(255), 35 | foreign key(assigned_to) references users(email) on delete set null, 36 | foreign key(project) references project(id) on delete cascade 37 | ); 38 | 39 | drop sequence if exists task_seq; 40 | create sequence task_seq start with 1000; 41 | -------------------------------------------------------------------------------- /scalikejdbc-play-initializer/test/zentasks/conf/db/migration/secondary/V1__create_tables.sql: -------------------------------------------------------------------------------- 1 | drop table if exists users; 2 | create table users ( 3 | email varchar(255) not null primary key, 4 | name varchar(255) not null, 5 | password varchar(255) not null 6 | ); 7 | 8 | drop table if exists project; 9 | create table project ( 10 | id bigint not null primary key, 11 | name varchar(255) not null, 12 | folder varchar(255) not null 13 | ); 14 | 15 | drop sequence if exists project_seq; 16 | create sequence project_seq start with 1000; 17 | 18 | drop table if exists project_member; 19 | create table project_member ( 20 | project_id bigint not null, 21 | user_email varchar(255) not null, 22 | foreign key(project_id) references project(id) on delete cascade, 23 | foreign key(user_email) references users(email) on delete cascade 24 | ); 25 | 26 | drop table if exists task; 27 | create table task ( 28 | id bigint not null primary key, 29 | title varchar(255) not null, 30 | done boolean, 31 | due_date timestamp, 32 | assigned_to varchar(255), 33 | project bigint not null, 34 | folder varchar(255), 35 | foreign key(assigned_to) references users(email) on delete set null, 36 | foreign key(project) references project(id) on delete cascade 37 | ); 38 | 39 | drop sequence if exists task_seq; 40 | create sequence task_seq start with 1000; 41 | -------------------------------------------------------------------------------- /scalikejdbc-play-initializer/test/zentasks/conf/prod.conf: -------------------------------------------------------------------------------- 1 | include "application.conf" 2 | db.default.driver=org.postgresql.Driver 3 | db.default.url=${DATABASE_URL} 4 | 5 | -------------------------------------------------------------------------------- /scalikejdbc-play-initializer/test/zentasks/conf/routes: -------------------------------------------------------------------------------- 1 | # Routes 2 | # This file defines all application routes (Higher priority routes first) 3 | # ~~~~ 4 | 5 | # The home page 6 | GET / controllers.Projects.index() 7 | 8 | # Authentication 9 | GET /login controllers.Application.login() 10 | POST /login controllers.Application.authenticate() 11 | GET /logout controllers.Application.logout() 12 | 13 | # Projects 14 | POST /projects controllers.Projects.add() 15 | 16 | POST /projects/groups controllers.Projects.addGroup() 17 | DELETE /projects/groups controllers.Projects.deleteGroup(group: String) 18 | PUT /projects/groups controllers.Projects.renameGroup(group: String) 19 | 20 | DELETE /projects/:project controllers.Projects.delete(project: Long) 21 | PUT /projects/:project controllers.Projects.rename(project: Long) 22 | 23 | POST /projects/:project/team controllers.Projects.addUser(project: Long) 24 | DELETE /projects/:project/team controllers.Projects.removeUser(project: Long) 25 | 26 | # Tasks 27 | GET /projects/:project/tasks controllers.Tasks.index(project: Long) 28 | POST /projects/:project/tasks controllers.Tasks.add(project: Long, folder: String) 29 | PUT /tasks/:task controllers.Tasks.update(task: Long) 30 | DELETE /tasks/:task controllers.Tasks.delete(task: Long) 31 | 32 | POST /tasks/folder controllers.Tasks.addFolder() 33 | DELETE /projects/:project/tasks/folder controllers.Tasks.deleteFolder(project: Long, folder: String) 34 | PUT /project/:project/tasks/folder controllers.Tasks.renameFolder(project: Long, folder: String) 35 | 36 | # Javascript routing 37 | GET /assets/javascripts/routes controllers.Application.javascriptRoutes() 38 | 39 | # Map static resources from the /public folder to the /public path 40 | GET /assets/*file controllers.Assets.at(path="/public", file) 41 | -------------------------------------------------------------------------------- /scalikejdbc-play-initializer/test/zentasks/project/build.properties: -------------------------------------------------------------------------------- 1 | sbt.version=0.13.11 2 | -------------------------------------------------------------------------------- /scalikejdbc-play-initializer/test/zentasks/public/images/arrow-left.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scalikejdbc/scalikejdbc-play-support/f2b16fcc53fd22c0bf1a278428c252b907c1398d/scalikejdbc-play-initializer/test/zentasks/public/images/arrow-left.png -------------------------------------------------------------------------------- /scalikejdbc-play-initializer/test/zentasks/public/images/breadcrumb-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scalikejdbc/scalikejdbc-play-support/f2b16fcc53fd22c0bf1a278428c252b907c1398d/scalikejdbc-play-initializer/test/zentasks/public/images/breadcrumb-1.png -------------------------------------------------------------------------------- /scalikejdbc-play-initializer/test/zentasks/public/images/breadcrumb-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scalikejdbc/scalikejdbc-play-support/f2b16fcc53fd22c0bf1a278428c252b907c1398d/scalikejdbc-play-initializer/test/zentasks/public/images/breadcrumb-2.png -------------------------------------------------------------------------------- /scalikejdbc-play-initializer/test/zentasks/public/images/breadcrumb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scalikejdbc/scalikejdbc-play-support/f2b16fcc53fd22c0bf1a278428c252b907c1398d/scalikejdbc-play-initializer/test/zentasks/public/images/breadcrumb.png -------------------------------------------------------------------------------- /scalikejdbc-play-initializer/test/zentasks/public/images/icons/addRemove.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scalikejdbc/scalikejdbc-play-support/f2b16fcc53fd22c0bf1a278428c252b907c1398d/scalikejdbc-play-initializer/test/zentasks/public/images/icons/addRemove.png -------------------------------------------------------------------------------- /scalikejdbc-play-initializer/test/zentasks/public/images/icons/clock.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scalikejdbc/scalikejdbc-play-support/f2b16fcc53fd22c0bf1a278428c252b907c1398d/scalikejdbc-play-initializer/test/zentasks/public/images/icons/clock.png -------------------------------------------------------------------------------- /scalikejdbc-play-initializer/test/zentasks/public/images/icons/delete.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scalikejdbc/scalikejdbc-play-support/f2b16fcc53fd22c0bf1a278428c252b907c1398d/scalikejdbc-play-initializer/test/zentasks/public/images/icons/delete.png -------------------------------------------------------------------------------- /scalikejdbc-play-initializer/test/zentasks/public/images/icons/drawer.folder.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scalikejdbc/scalikejdbc-play-support/f2b16fcc53fd22c0bf1a278428c252b907c1398d/scalikejdbc-play-initializer/test/zentasks/public/images/icons/drawer.folder.png -------------------------------------------------------------------------------- /scalikejdbc-play-initializer/test/zentasks/public/images/icons/folder.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scalikejdbc/scalikejdbc-play-support/f2b16fcc53fd22c0bf1a278428c252b907c1398d/scalikejdbc-play-initializer/test/zentasks/public/images/icons/folder.png -------------------------------------------------------------------------------- /scalikejdbc-play-initializer/test/zentasks/public/images/icons/home.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scalikejdbc/scalikejdbc-play-support/f2b16fcc53fd22c0bf1a278428c252b907c1398d/scalikejdbc-play-initializer/test/zentasks/public/images/icons/home.png -------------------------------------------------------------------------------- /scalikejdbc-play-initializer/test/zentasks/public/images/icons/options.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scalikejdbc/scalikejdbc-play-support/f2b16fcc53fd22c0bf1a278428c252b907c1398d/scalikejdbc-play-initializer/test/zentasks/public/images/icons/options.png -------------------------------------------------------------------------------- /scalikejdbc-play-initializer/test/zentasks/public/images/icons/user.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scalikejdbc/scalikejdbc-play-support/f2b16fcc53fd22c0bf1a278428c252b907c1398d/scalikejdbc-play-initializer/test/zentasks/public/images/icons/user.png -------------------------------------------------------------------------------- /scalikejdbc-play-initializer/test/zentasks/public/images/icons/user2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scalikejdbc/scalikejdbc-play-support/f2b16fcc53fd22c0bf1a278428c252b907c1398d/scalikejdbc-play-initializer/test/zentasks/public/images/icons/user2.png -------------------------------------------------------------------------------- /scalikejdbc-play-initializer/test/zentasks/public/images/loading.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scalikejdbc/scalikejdbc-play-support/f2b16fcc53fd22c0bf1a278428c252b907c1398d/scalikejdbc-play-initializer/test/zentasks/public/images/loading.gif -------------------------------------------------------------------------------- /scalikejdbc-play-initializer/test/zentasks/public/images/pattern.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scalikejdbc/scalikejdbc-play-support/f2b16fcc53fd22c0bf1a278428c252b907c1398d/scalikejdbc-play-initializer/test/zentasks/public/images/pattern.png -------------------------------------------------------------------------------- /windows_test_filter.sbt: -------------------------------------------------------------------------------- 1 | val excludeTestsIfWindows = Set( 2 | // TODO 3 | // new line char? 4 | "scalikejdbc.play.FixtureSpec", 5 | ) 6 | 7 | ThisBuild / Test / testOptions ++= { 8 | if (scala.util.Properties.isWin) { 9 | Seq(Tests.Exclude(excludeTestsIfWindows)) 10 | } else { 11 | Nil 12 | } 13 | } 14 | --------------------------------------------------------------------------------