From e06c53a9ff7b1341df5bdb7d441c896ed623d6f7 Mon Sep 17 00:00:00 2001 From: Artemiy Solopov Date: Thu, 9 Jul 2026 16:12:09 +0300 Subject: [PATCH] Models and schemas for users and auth tokens --- .bsp/sbt.json | 1 + .gitignore | 3 +++ app/models/models.scala | 7 +++++++ app/schemas/schemas.scala | 34 ++++++++++++++++++++++++++++++++++ build.sbt | 10 +++++++++- compose.yaml | 8 ++++++++ conf/application.conf | 14 ++++++++++++++ conf/evolutions/default/1.sql | 26 ++++++++++++++++++++++++++ db.env | 3 +++ 9 files changed, 105 insertions(+), 1 deletion(-) create mode 100644 .bsp/sbt.json create mode 100644 app/models/models.scala create mode 100644 app/schemas/schemas.scala create mode 100644 compose.yaml create mode 100644 conf/evolutions/default/1.sql create mode 100644 db.env diff --git a/.bsp/sbt.json b/.bsp/sbt.json new file mode 100644 index 0000000..335180c --- /dev/null +++ b/.bsp/sbt.json @@ -0,0 +1 @@ +{"name":"sbt","version":"1.12.13","bspVersion":"2.1.0-M1","languages":["scala"],"argv":["/usr/lib/jvm/java-21-openjdk-amd64/bin/java","-Xms100m","-Xmx100m","-classpath","/home/artemiy/.local/share/JetBrains/IntelliJIdea2026.1/Scala/launcher/sbt-launch.jar","-Dsbt.script=/home/artemiy/.local/bin/sbt","xsbt.boot.Boot","-bsp"]} \ No newline at end of file diff --git a/.gitignore b/.gitignore index 561b953..f63fac1 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,6 @@ # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml hs_err_pid* +/project/project/target/ +/project/target +/target \ No newline at end of file diff --git a/app/models/models.scala b/app/models/models.scala new file mode 100644 index 0000000..c52eab3 --- /dev/null +++ b/app/models/models.scala @@ -0,0 +1,7 @@ +package models + +import java.time.Instant + +case class User(id: Option[Int], username: String, gid: String, passwordDigest: Option[String]) + +case class AuthToken(id: Option[Int], userId: Int, token: String, createdAt: Instant, expiresAt: Instant) \ No newline at end of file diff --git a/app/schemas/schemas.scala b/app/schemas/schemas.scala new file mode 100644 index 0000000..e3816a6 --- /dev/null +++ b/app/schemas/schemas.scala @@ -0,0 +1,34 @@ +package schemas + +import slick.jdbc.PostgresProfile.api._ +import models._ +import slick.lifted.ProvenShape +import slick.model.ForeignKeyAction.Cascade + +import java.time.Instant + +class UsersTable(tag: Tag) extends Table[User](tag, "users") { + def id = column[Int]("id", O.PrimaryKey, O.AutoInc) + def gid = column[String]("gid", O.Unique) + def username = column[String]("username", O.Unique) + def passwordDigest = column[Option[String]]("password_digest") + + override def * : ProvenShape[User] = (id.?, username, gid, passwordDigest).mapTo[User] +} + +lazy val Users = TableQuery[UsersTable] + +class AuthTokensTable(tag: Tag) extends Table[AuthToken](tag, "auth_tokens") { + + def id = column[Int]("id", O.PrimaryKey, O.AutoInc) + def userId = column[Int]("user_id") + def token = column[String]("token") + def createdAt = column[Instant]("created_at") + def expiresAt = column[Instant]("expires_at") + + override def * : ProvenShape[AuthToken] = (id.?, userId, token, createdAt, expiresAt).mapTo[AuthToken] + + def user = foreignKey("users", userId, Users)(_.id, onDelete = Cascade) +} + +lazy val AuthTokens = TableQuery[AuthTokensTable] \ No newline at end of file diff --git a/build.sbt b/build.sbt index 0426937..fe457b4 100644 --- a/build.sbt +++ b/build.sbt @@ -5,11 +5,19 @@ version := "1.0-SNAPSHOT" lazy val root = (project in file(".")).enablePlugins(PlayScala) -scalaVersion := "2.13.18" +scalaVersion := "3.8.4" libraryDependencies += guice libraryDependencies += "org.scalatestplus.play" %% "scalatestplus-play" % "7.0.2" % Test +// Source: https://mvnrepository.com/artifact/org.postgresql/postgresql +libraryDependencies += "org.postgresql" % "postgresql" % "42.7.13" + +// Source: https://mvnrepository.com/artifact/org.playframework/play-slick +libraryDependencies += "org.playframework" %% "play-slick" % "6.2.0" +// Source: https://mvnrepository.com/artifact/org.playframework/play-slick-evolutions +libraryDependencies += "org.playframework" %% "play-slick-evolutions" % "6.2.0" + // Adds additional packages into Twirl //TwirlKeys.templateImports += "me.artemis.controllers._" diff --git a/compose.yaml b/compose.yaml new file mode 100644 index 0000000..418cf4c --- /dev/null +++ b/compose.yaml @@ -0,0 +1,8 @@ +name: 'neon-vertigo-api' +services: + db: + image: "postgres:18" + env_file: + - db.env + ports: + - "5432:5432" \ No newline at end of file diff --git a/conf/application.conf b/conf/application.conf index cb94680..0435719 100644 --- a/conf/application.conf +++ b/conf/application.conf @@ -1 +1,15 @@ # https://www.playframework.com/documentation/latest/Configuration + +slick.dbs.default = { + profile = "slick.jdbc.PostgresProfile$" + db = { + dataSourceClass = "org.postgresql.ds.PGSimpleDataSource" + properties = { + serverName = "localhost" + portNumber = "5432" + databaseName = ${POSTGRES_DB} + user = ${POSTGRES_USER} + password = ${POSTGRES_PASSWORD} + } + } +} \ No newline at end of file diff --git a/conf/evolutions/default/1.sql b/conf/evolutions/default/1.sql new file mode 100644 index 0000000..600ba78 --- /dev/null +++ b/conf/evolutions/default/1.sql @@ -0,0 +1,26 @@ +-- Users and tokens + +-- !Ups + +CREATE TABLE users ( + id BIGINT PRIMARY KEY GENERATED BY DEFAULT AS IDENTITY, + username VARCHAR UNIQUE NOT NULL, + gid VARCHAR UNIQUE NOT NULL, + password_digest VARCHAR +); + +CREATE TABLE auth_tokens ( + id BIGINT PRIMARY KEY GENERATED BY DEFAULT AS IDENTITY, + user_id BIGINT NOT NULL REFERENCES users(id) ON DELETE CASCADE, + token VARCHAR NOT NULL, + created_at TIMESTAMP NOT NULL, + expires_at TIMESTAMP NOT NULL +); + +CREATE INDEX idx_auth_tokens_user_id_expires_at ON auth_tokens (user_id, expires_at); + +-- !Downs + +DROP INDEX idx_auth_tokens_user_id_expires_at; +DROP TABLE auth_tokens; +DROP TABLE users; \ No newline at end of file diff --git a/db.env b/db.env new file mode 100644 index 0000000..4b98592 --- /dev/null +++ b/db.env @@ -0,0 +1,3 @@ +POSTGRES_DB=neon-vertigo-api +POSTGRES_USER=neon-vertigo +POSTGRES_PASSWORD=nvertigo