...
 
Commits (9)
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
version="3.0">
<!--
This listener loads a class in the default package called ScalatraBootstrap.
That class should implement org.scalatra.LifeCycle. Your app can be
configured in Scala code there.
-->
<listener>
<listener-class>org.scalatra.servlet.ScalatraListener</listener-class>
</listener>
</web-app>
<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" >
<svg xmlns="http://www.w3.org/2000/svg">
<metadata>Generated by IcoMoon</metadata>
<defs>
<font id="icomoon" horiz-adv-x="1024">
<font-face units-per-em="1024" ascent="960" descent="-64" />
<missing-glyph horiz-adv-x="1024" />
<glyph unicode="&#x20;" horiz-adv-x="512" d="" />
<glyph unicode="&#xe600;" glyph-name="book" d="M896 832v-832h-672c-53.026 0-96 42.98-96 96s42.974 96 96 96h608v768h-640c-70.398 0-128-57.6-128-128v-768c0-70.4 57.602-128 128-128h768v896h-64zM224.056 128v0c-0.018-0.002-0.038 0-0.056 0-17.672 0-32-14.326-32-32s14.328-32 32-32c0.018 0 0.038 0.002 0.056 0.002v-0.002h607.89v64h-607.89z" />
<glyph unicode="&#xe601;" glyph-name="power-cord" d="M1024 677.5l-90.506 90.5-178.746-178.752-101.5 101.502 178.75 178.75-90.5 90.5-178.75-178.75-114.748 114.75-86.626-86.624 512.002-512 86.624 86.622-114.752 114.752 178.752 178.75zM794.040 286.21l-443.824 443.824c-95.818-114.904-204.52-292.454-129.396-445.216l-132.248-132.248c-31.112-31.114-31.112-82.024 0-113.136l14.858-14.858c31.114-31.114 82.026-31.114 113.138 0l132.246 132.244c152.764-75.132 330.318 33.566 445.226 129.39z" />
<glyph unicode="&#xe900;" glyph-name="database" d="M512 960c-282.77 0-512-71.634-512-160v-128c0-88.366 229.23-160 512-160s512 71.634 512 160v128c0 88.366-229.23 160-512 160zM512 416c-282.77 0-512 71.634-512 160v-192c0-88.366 229.23-160 512-160s512 71.634 512 160v192c0-88.366-229.23-160-512-160zM512 128c-282.77 0-512 71.634-512 160v-192c0-88.366 229.23-160 512-160s512 71.634 512 160v192c0-88.366-229.23-160-512-160z" />
</font></defs></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" width="505" height="142.6" viewBox="0 0 505 142.6">
<g fill="#403D56">
<path d="M100 92.6c-13.2 0-24.5-11.3-24.5-24.5S86.8 43.6 100 43.6s24.5 11.3 24.5 24.5c0 13.1-11.4 24.5-24.5 24.5zm0-38.6c-7.4 0-14 6.7-14 14 0 7.4 6.7 14.1 14 14.1 7.4 0 14-6.7 14-14.1 0-7.3-6.7-14-14-14zM130.6 109.4V61h10.5v3.8c2.7-3.4 6.6-4.5 10.6-4.5 8.8 0 15.3 7.6 15.3 16.2s-6.6 16.1-15.3 16.1c-4 0-8.5-1.3-10.6-4.4v21.2h-10.5zm17.9-25.2c4.2 0 7.4-3.6 7.4-7.7s-3.2-7.7-7.4-7.7-7.4 3.6-7.4 7.7 3.2 7.7 7.4 7.7zM206 77.7h-23.9c0 3.6 2.5 7.4 6.7 7.4 3.7 0 6-2.5 6.1-4.7h10.7c-1.8 8.1-8.4 12.2-16.6 12.2-10.6 0-18-6.3-18-16.1 0-9.7 7.6-16.2 18-16.2 9.4 0 17.2 5.6 17.2 15.5-.1.6-.2 1.3-.2 1.9zm-10-4.9s-.5-5.7-6.9-5.7c-6.6 0-6.9 5.7-6.9 5.7H196zM243.3 91.9h-10.5V74.4c0-3.6-1.4-5.6-4.7-5.6s-5.9 3.5-5.9 7.7v15.4h-10.5V61h10.5v3.8c2.1-2.7 5.4-4.5 9.5-4.5 8.3 0 11.6 5.7 11.6 14.1v17.5z"/>
</g>
<g fill="#A6BF25">
<path d="M299.3 91.9l-5.6-32.8-9.3 32.8h-10.3l-9.3-32.8-5.6 32.8h-11.6l9.2-47.6h12.5l9.9 33.4 9.9-33.4h12.5l9.2 47.6h-11.5zM337.3 92.6c-13.2 0-24.5-11.3-24.5-24.5s11.3-24.5 24.5-24.5 24.5 11.3 24.5 24.5c0 13.1-11.3 24.5-24.5 24.5zm0-38.6c-7.4 0-14 6.7-14 14 0 7.4 6.7 14.1 14 14.1 7.4 0 14-6.7 14-14.1 0-7.3-6.6-14-14-14zM368.2 44.3h10.5v38.1h17.1v9.5h-27.6V44.3zM427.9 91.9h-27.6V44.3h27.6v9.5h-17.1v9.5h16.4v9.5h-16.4v9.6h17.1v9.5z"/>
</g>
</svg>
package org.openmoleconnect.adminclient
import java.nio.ByteBuffer
import org.scalajs.dom
import scaladget.bootstrapnative.bsn._
import org.scalajs.dom.raw.{Event, HTMLFormElement}
import scalatags.JsDom.all._
import scalatags.JsDom.tags
import scala.scalajs.js.annotation.JSExportTopLevel
import boopickle.Default._
import shared.AdminApi
import autowire._
import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.Future
import scala.scalajs.js.typedarray.{ArrayBuffer, TypedArrayBuffer}
object AdminPanel {
@JSExportTopLevel("admin")
def admin() = {
println("admin ...")
Post[AdminApi].users().call().foreach {u=>
println("users " +u)
}
dom.document.body.appendChild(div("Admin").render)
}
}
object Post extends autowire.Client[ByteBuffer, Pickler, Pickler] {
override def doCall(req: Request): Future[ByteBuffer] = {
dom.ext.Ajax.post(
url = req.path.mkString("/"),
data = Pickle.intoBytes(req.args),
responseType = "arraybuffer",
headers = Map("Content-Type" -> "application/octet-stream")
).map(r => TypedArrayBuffer.wrap(r.response.asInstanceOf[ArrayBuffer]))
}
override def read[Result: Pickler](p: ByteBuffer) = Unpickle[Result].fromBytes(p)
override def write[Result: Pickler](r: Result) = Pickle.intoBytes(r)
}
//}
\ No newline at end of file
......@@ -43,6 +43,6 @@ object Application extends App {
server.start()
}
DB.addUser(DB.Email("moo@moo.com"), DB.Password("moo"), DB.simpleUser)
DB.addUser("Moo",DB.Email("moo@moo.com"), DB.Password("moo"), Utils.openmoleversion.stable, 900009870L, DB.simpleUser)
}
......@@ -8,7 +8,7 @@ val scalatraVersion = "2.6.5"
val jettyVersion = "9.4.19.v20190610"
val json4sVersion = "3.6.7"
val scalatagsVersion = "0.7.0"
val scaladgetVersion = "1.2.7"
val scaladgetVersion = "1.3.0-SNAPSHOT"
val scalajsDomVersion = "0.9.7"
val scalaJWTVersion = "4.0.0"
val rosHttpVersion = "2.2.4"
......@@ -36,16 +36,6 @@ lazy val shared = project.in(file("shared")) settings (defaultSettings: _*) enab
lazy val go = taskKey[Unit]("go")
lazy val client = project.in(file("client")) enablePlugins (ExecNpmPlugin) settings (defaultSettings) settings(
skip in packageJSDependencies := false,
libraryDependencies ++= Seq(
"com.lihaoyi" %%% "scalatags" % scalatagsVersion,
"fr.iscpif.scaladget" %%% "tools" % scaladgetVersion,
"fr.iscpif.scaladget" %%% "bootstrapnative" % scaladgetVersion,
"org.scala-js" %%% "scalajs-dom" % scalajsDomVersion
)
) dependsOn (shared)
lazy val adminclient = project.in(file("adminclient")) enablePlugins (ExecNpmPlugin) settings (defaultSettings) settings(
skip in packageJSDependencies := false,
libraryDependencies ++= Seq(
"com.lihaoyi" %%% "scalatags" % scalatagsVersion,
......@@ -104,8 +94,8 @@ lazy val bootstrap = project.in(file("target/bootstrap")) settings (defaultSetti
dependencyJS: sbt.File,
depsCSS: sbt.File,
targetName: String) = {
IO.copyFile(jsBuild, appTarget / s"webapp/js/${targetName}.js")
IO.copyFile(dependencyJS, appTarget / "webapp/js/${targetName}-deps.js")
IO.copyFile(jsBuild, appTarget / s"webapp/js/$targetName.js")
IO.copyFile(dependencyJS, appTarget / s"webapp/js/$targetName-deps.js")
IO.copyDirectory(depsCSS, appTarget / "webapp/css")
IO.copyDirectory(clientResources, appTarget)
}
......@@ -118,11 +108,4 @@ lazy val bootstrap = project.in(file("target/bootstrap")) settings (defaultSetti
val depsCSS = (cssFile in client in Compile).value
copyToTarget(jsBuild, appTarget, clientResources, dependencyJS, depsCSS, "connect")
val jsBuildAdmin = (fullOptJS in adminclient in Compile).value.data
val clientResourcesAdmin = (resourceDirectory in adminclient in Compile).value
val dependencyJSAdmin = (dependencyFile in adminclient in Compile).value
val depsCSSAdmin = (cssFile in adminclient in Compile).value
copyToTarget(jsBuildAdmin, appTarget, clientResourcesAdmin, dependencyJSAdmin, depsCSSAdmin, "admin")
}) dependsOn(client, server)
.label-success {
background-color: #a6bf25;
}
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" width="505" height="142.6" viewBox="0 0 505 142.6">
<g fill="#403D56">
<path d="M100 92.6c-13.2 0-24.5-11.3-24.5-24.5S86.8 43.6 100 43.6s24.5 11.3 24.5 24.5c0 13.1-11.4 24.5-24.5 24.5zm0-38.6c-7.4 0-14 6.7-14 14 0 7.4 6.7 14.1 14 14.1 7.4 0 14-6.7 14-14.1 0-7.3-6.7-14-14-14zM130.6 109.4V61h10.5v3.8c2.7-3.4 6.6-4.5 10.6-4.5 8.8 0 15.3 7.6 15.3 16.2s-6.6 16.1-15.3 16.1c-4 0-8.5-1.3-10.6-4.4v21.2h-10.5zm17.9-25.2c4.2 0 7.4-3.6 7.4-7.7s-3.2-7.7-7.4-7.7-7.4 3.6-7.4 7.7 3.2 7.7 7.4 7.7zM206 77.7h-23.9c0 3.6 2.5 7.4 6.7 7.4 3.7 0 6-2.5 6.1-4.7h10.7c-1.8 8.1-8.4 12.2-16.6 12.2-10.6 0-18-6.3-18-16.1 0-9.7 7.6-16.2 18-16.2 9.4 0 17.2 5.6 17.2 15.5-.1.6-.2 1.3-.2 1.9zm-10-4.9s-.5-5.7-6.9-5.7c-6.6 0-6.9 5.7-6.9 5.7H196zM243.3 91.9h-10.5V74.4c0-3.6-1.4-5.6-4.7-5.6s-5.9 3.5-5.9 7.7v15.4h-10.5V61h10.5v3.8c2.1-2.7 5.4-4.5 9.5-4.5 8.3 0 11.6 5.7 11.6 14.1v17.5z"/>
</g>
<g fill="#A6BF25">
<path d="M299.3 91.9l-5.6-32.8-9.3 32.8h-10.3l-9.3-32.8-5.6 32.8h-11.6l9.2-47.6h12.5l9.9 33.4 9.9-33.4h12.5l9.2 47.6h-11.5zM337.3 92.6c-13.2 0-24.5-11.3-24.5-24.5s11.3-24.5 24.5-24.5 24.5 11.3 24.5 24.5c0 13.1-11.3 24.5-24.5 24.5zm0-38.6c-7.4 0-14 6.7-14 14 0 7.4 6.7 14.1 14 14.1 7.4 0 14-6.7 14-14.1 0-7.3-6.6-14-14-14zM368.2 44.3h10.5v38.1h17.1v9.5h-27.6V44.3zM427.9 91.9h-27.6V44.3h27.6v9.5h-17.1v9.5h16.4v9.5h-16.4v9.6h17.1v9.5z"/>
</g>
</svg>
package org.openmoleconnect.client
import java.nio.ByteBuffer
import org.scalajs.dom
import scala.scalajs.js.annotation.JSExportTopLevel
import boopickle.Default._
import shared.AdminApi
import autowire._
import rx._
import scaladget.bootstrapnative.Table.StaticSubRow
import scaladget.bootstrapnative._
import scaladget.bootstrapnative.bsn.{glyph_edit2, glyph_save}
import scalatags.JsDom.styles
import shared.Data._
import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.Future
import scala.scalajs.js.typedarray.{ArrayBuffer, TypedArrayBuffer}
import scaladget.bootstrapnative.bsn._
import scaladget.tools.{ModifierSeq, _}
import scalatags.JsDom.all._
import Utils._
import scala.scalajs.js.Date
object AdminPanel {
@JSExportTopLevel("admin")
def admin() = {
implicit def userDataSeqToRows(userData: Seq[UserData]): Seq[ExpandableRow] = userData.map { u =>
buildExpandable(u.name, u.email, u.password, u.role, u.omVersion, u.lastAccess, running)
}
lazy val rowFlex = Seq(styles.display.flex, flexDirection.row, justifyContent.spaceAround, alignItems.center)
lazy val columnFlex = Seq(styles.display.flex, flexDirection.column, styles.justifyContent.center)
lazy val rows: Var[Seq[ExpandableRow]] = Var(Seq())
def save(expandableRow: ExpandableRow, userData: UserData): Unit = {
if (userData.name.isEmpty)
rows.update(rows.now.filterNot(_ == expandableRow))
else {
upsert(userData)
}
}
def upsert(userData: UserData) =
Post[AdminApi].upserted(userData).call().foreach {
rows() = _
}
def delete(userData: UserData) =
Post[AdminApi].delete(userData).call().foreach {
rows() = _
}
def closeAll(except: ExpandableRow) = rows.now.filterNot {
_ == except
}.foreach {
_.subRow.trigger() = false
}
def buildExpandable(userName: String = "",
userEmail: String = "",
userPassword: String = "",
userRole: Role = "",
userOMVersion: String = "",
userLastAccess: Long = 0L,
userStatus: Status = user,
expanded: Boolean = false): ExpandableRow = {
val aVar = Var(expanded)
lazy val aSubRow: StaticSubRow = StaticSubRow({
div(height := 300, rowFlex)(
groupCell.build(margin := 25),
div(userLastAccess.toStringDate, fontSize := "12px", minWidth := 150),
label(label_primary, userOMVersion),
span(columnFlex, alignItems.flexEnd, justifyContent.flexEnd)(
button(btn_danger, "Delete", onclick := { () =>
val userData = UserData(userName, userEmail, userPassword, userRole, userOMVersion, userLastAccess)
delete(userData)
}, margin := 10)
)
)
}, aVar)
def statusStyle(s: Status) =
if (s == running) label_success
else if (s == off) label_default
else label_danger
lazy val expandableRow: ExpandableRow = ExpandableRow(EditableRow(Seq(
TriggerCell(a(userName, onclick := { () =>
closeAll(expandableRow)
aVar() = !aVar.now
})),
LabelCell(userStatus, Seq(), optionStyle = statusStyle),
)), aSubRow)
lazy val groupCell: GroupCell = UserPanel.editableData(userName, userEmail, userPassword, userRole, userStatus, userOMVersion, userLastAccess, expanded, (uData: UserData) => save(expandableRow, uData))
expandableRow
}
Post[AdminApi].users().call().foreach { us =>
rows() = us
}
val addUserButton = button(btn_primary, "Add", onclick := { () =>
val row = buildExpandable(userRole = user, userOMVersion = "LATEST", expanded = true)
rows.update(rows.now :+ row)
})
val headerStyle: ModifierSeq = Seq(
height := 40.85
)
val editablePanel = div(maxWidth := 1000, margin := "40px auto")(
img(src := "img/logo.png", css.adminLogoStyle),
Utils.logoutItem(styles.display.flex, flexDirection.row, justifyContent.flexEnd),
div(styles.display.flex, flexDirection.row, justifyContent.flexStart, marginLeft := 50, marginBottom := 20, marginTop := 80)(
addUserButton(styles.display.flex, flexDirection.row, styles.justifyContent.flexEnd)
),
Rx {
div(styles.display.flex, flexDirection.row, styles.justifyContent.center)(
EdiTable(Seq("Name", "Status"), rows()).render(width := "90%")
)
}
)
dom.document.body.appendChild(editablePanel.render)
}
}
object Post extends autowire.Client[ByteBuffer, Pickler, Pickler] {
override def doCall(req: Request): Future[ByteBuffer] = {
dom.ext.Ajax.post(
url = req.path.mkString("/"),
data = Pickle.intoBytes(req.args),
responseType = "arraybuffer",
headers = Map("Content-Type" -> "application/octet-stream")
).map(r => TypedArrayBuffer.wrap(r.response.asInstanceOf[ArrayBuffer]))
}
override def read[Result: Pickler](p: ByteBuffer) = Unpickle[Result].fromBytes(p)
override def write[Result: Pickler](r: Result) = Pickle.intoBytes(r)
}
//}
\ No newline at end of file
......@@ -34,7 +34,7 @@ object Connection {
@JSExportTopLevel("connection")
def connect() = {
lazy val connectButton = tags.button("Connect", btn_primary, `type` := "submit").render
lazy val connectButton = tags.button("Connect", btn_primary, `type` := "submit", float.right, right := 0).render
//lazy val cookieButton = tags.button("Cookuie", btn_default, onclick := { () => println("COOKIES: " + dom.document.cookie) }).render
......@@ -71,8 +71,8 @@ object Connection {
div(
div(css.connectionTabOverlay)(
div(
img(src := "img/logo.svg", css.openmoleLogo),
div(marginLeft := 300)(
img(src := "img/logo.png", css.openmoleLogo),
div(css.connectionFormStyle)(
connectionForm
)
)
......
package org.openmoleconnect.client
import rx.Rx
import scaladget.bootstrapnative._
import scaladget.tools.toClass
import scalatags.JsDom.styles
import scaladget.bootstrapnative.bsn._
import scaladget.tools._
import scalatags.JsDom.all._
import shared.Data._
import rx._
object UserPanel {
lazy val rowFlex = Seq(styles.display.flex, flexDirection.row, justifyContent.spaceAround)
lazy val columnFlex = Seq(styles.display.flex, flexDirection.column, styles.justifyContent.center, alignItems.flexStart)
lazy val roles = Seq(user, shared.Data.admin)
lazy val roleFilter = (r: Role) => r == shared.Data.admin
def editableData(userName: String = "",
userEmail: String = "",
userPassword: String = "",
userRole: Role = "",
userStatus: Status = user,
userOMVersion: String,
userLastAccess: Long,
expanded: Boolean = false,
upserting: (UserData) => Unit
): GroupCell = {
def roleStyle(s: Role) =
if (s == shared.Data.admin) label_success
else label_default
val name = TextCell(userName, Some("Name"))
val email = TextCell(userEmail, Some("Email"))
val password = PasswordCell(userPassword, Some("Password"))
val role = LabelCell(userRole, roles, optionStyle = roleStyle, title = Some("Role"))
val rowEdit = Var(false)
lazy val groupCell: GroupCell = GroupCell(
div(columnFlex, width := "100%")(
name.build(padding := 10),
email.build(padding := 10),
password.build(padding := 10),
role.build(padding := 10),
span(rowFlex, marginTop := 50)(
Rx {
if (rowEdit()) button(btn_primary, "Save", onclick := { () =>
val userRole: Role = role.get
val modifiedUser = UserData(name.get, email.get, password.get, userRole, userOMVersion, userLastAccess)
upserting(modifiedUser)
rowEdit.update(!rowEdit.now)
})
else button(btn_default, "Edit", onclick := { () =>
//button("Edit", btn_default, onclick := { () =>
rowEdit.update(!rowEdit.now)
groupCell.switch
})
}
)),
name, email, password, role
)
groupCell
}
}
package org.openmoleconnect.client
import scalatags.JsDom.styles
import scaladget.bootstrapnative.bsn._
import scaladget.tools._
import scalatags.JsDom.all._
import scala.scalajs.js.Date
object Utils {
val logoutLogo = toClass("glyphicon glyphicon-off")
val itemStyle: ModifierSeq = Seq(
fontSize := 30,
pointer,
color := "#337ab7"
)
val logoutItem =
div(logoutLogo, itemStyle, onclick := { () org.scalajs.dom.window.location.href = s"${org.scalajs.dom.window.location.href}logout" })
implicit class FromInt(i: Int) {
def toDayString = i match {
case 0 => "Mon"
case 1 => "Tue"
case 2 => "Wed"
case 3 => "Thu"
case 4 => "Fri"
case 5 => "Sat"
case 6 => "Sun"
case _ => "ERROR"
}
def toMonthString = i match {
case 0 => "Jan"
case 1 => "Feb"
case 2 => "Mar"
case 3 => "Apr"
case 4 => "May"
case 5 => "Jun"
case 6 => "Jul"
case 7 => "Aug"
case 8 => "Sept"
case 9 => "Oct"
case 10 => "Nov"
case 11 => "Dec"
}
def toMinOrSecString = {
if (i < 10 ) s"0$i"
else i
}
}
implicit class FromLong(date: Long) {
def toStringDate = {
if (date == 0L) "NEVER CONNECTED"
else {
val d = new Date(date)
s"${d.getDay.toDayString}, ${d.getDate} ${d.getMonth.toMonthString} ${d.getFullYear} ${d.getHours}:${d.getMinutes.toMinOrSecString}:${d.getSeconds.toMinOrSecString}"
}
}
}
}
......@@ -12,9 +12,24 @@ package object css {
height := 300
)
lazy val connectionFormStyle: ModifierSeq = Seq(
display.flex,
flexDirection.row,
justifyContent.flexEnd, /* center items vertically, in this case */
alignItems.center,
marginTop := 120
)
lazy val adminLogoStyle: ModifierSeq = Seq(
display.flex,
flexDirection.row,
justifyContent.center, /* cent241,49er items horizontally, in this case */
width := 500
)
lazy val openmoleLogo: ModifierSeq = Seq(
paddingTop := 300,
width := 600,
width := 500,
)
}
package org.openmoleconnect.server
import shared.Data.UserData
import DB._
object AdminApiImpl extends shared.AdminApi {
def users() = {
println("in users server")
val u = DBQueries.users
println("users " + u)
u
DB.users
}
}
def upserted(userData: UserData): Seq[UserData] = {
val id = DB.uuid(Email(userData.email)).getOrElse(UUID(java.util.UUID.randomUUID.toString))
upsert(toUser(id, userData))
users
}
//object AdminRequest {
// private val requestPrefix = "shared/AdminApi"
//
// private val requests = Seq(
// s"$requestPrefix/users"
// )
//
// def isAdminRequest(path: String) = requests.contains(path)
//}
\ No newline at end of file
def delete(userData: UserData): Seq[UserData] = {
val id = DB.uuid(Email(userData.email))
id.foreach {i=>
DB.delete(toUser(i, userData))
}
users
}
}
\ No newline at end of file
......@@ -44,7 +44,9 @@ class ConnectServlet(arguments: ConnectServer.ServletArguments) extends Scalatra
def withAccesToken(action: TokenData => ActionResult): Serializable = {
Authentication.tokenData(request, TokenType.accessToken) match {
case Some(tokenData: TokenData) => action(tokenData)
case Some(tokenData: TokenData) =>
DB.setLastAccess(tokenData.email, JWT.now)
action(tokenData)
case None =>
Authentication.isValid(request, TokenType.refreshToken) match {
case true =>
......@@ -60,7 +62,7 @@ class ConnectServlet(arguments: ConnectServer.ServletArguments) extends Scalatra
def withAdminRights(action: TokenData=> ActionResult): Serializable = {
withAccesToken { tokenData =>
DBQueries.isAdmin(tokenData.email) match {
DB.isAdmin(tokenData.email) match {
case true=> action(tokenData)
case false=> Unauthorized("You seem unauthorized to do this !")
}
......@@ -76,7 +78,7 @@ class ConnectServlet(arguments: ConnectServer.ServletArguments) extends Scalatra
def connectionAppRedirection = {
withAccesToken { tokenData =>
if (DBQueries.isAdmin(tokenData.email)) {
if (DB.isAdmin(tokenData.email)) {
Ok(adminHtml)
}
else {
......@@ -162,7 +164,8 @@ class ConnectServlet(arguments: ConnectServer.ServletArguments) extends Scalatra
else {
DB.uuid(DB.Email(email), DB.Password(password)) match {
case Some(uuid) =>
val host = Host(uuid, K8sService.hostIP(uuid))
//val host = Host(uuid, K8sService.hostIP(uuid))
val host = Host(uuid, None)
buildAndAddCookieToHeader(TokenData.accessToken(host, DB.Email(email)))
buildAndAddCookieToHeader(TokenData.refreshToken(host, DB.Email(email)))
redirect("/")
......@@ -248,18 +251,19 @@ class ConnectServlet(arguments: ConnectServer.ServletArguments) extends Scalatra
}
}
def connectionHtml = someHtml("connect", "connection();")
def connectionHtml = someHtml("connection();")
def adminHtml = someHtml("admin", "admin();")
def adminHtml = someHtml("admin();")
def someHtml(jsFileName: String, jsCall: String) = {
def someHtml(jsCall: String) = {
contentType = "text/html"
tags.html(
tags.head(
tags.meta(tags.httpEquiv := "Content-Type", tags.content := "text/html; charset=UTF-8"),
tags.link(tags.rel := "stylesheet", tags.`type` := "text/css", href := "css/deps.css"),
Seq(s"${jsFileName}-deps.js", s"${jsFileName}.js").map {
tags.link(tags.rel := "stylesheet", tags.`type` := "text/css", href := "css/style.css"),
Seq(s"connect-deps.js", "connect.js").map {
jf => tags.script(tags.`type` := "text/javascript", tags.src := s"js/$jf ")
}
),
......@@ -277,9 +281,9 @@ class ConnectServlet(arguments: ConnectServer.ServletArguments) extends Scalatra
flexDirection.column,
justifyContent.center,
alignItems.center,
height := 300)(
width := 500)(
tags.div(
tags.img(src := "img/logo.svg",
tags.img(src := "img/logo.png",
paddingTop := 300,
width := 600),
div(paddingLeft := 180)("Wrong way buddy. Are you lost ?")
......
package org.openmoleconnect.server
import java.text.SimpleDateFormat
import java.util
import shared.Data.UserData
import scala.concurrent.{Await, Future}
import scala.concurrent.duration.Duration
import scala.concurrent.ExecutionContext.Implicits.global
import slick.jdbc.H2Profile.api._
import DBQueries._
import shared._
import slick.model.ForeignKey
object DB {
// USERS
case class UUID(value: String) extends MappedTo[String]
case class Email(value: String) extends MappedTo[String]
......@@ -19,23 +26,50 @@ object DB {
case class Role(value: String) extends MappedTo[String]
val admin = Role("admin")
val simpleUser = Role("simpleUser")
case class Version(value: String) extends MappedTo[String]
val admin = Role("Admin")
val simpleUser = Role("User")
case class User(email: Email, password: Password, role: Role = simpleUser, uuid: UUID = UUID(""))
case class User(name: String, email: Email, password: Password, omVersion: Version, lastAccess: Long, role: Role = simpleUser, uuid: UUID = UUID(""))
implicit def userToUserData(users: Seq[User]): Seq[Data.UserData] = users.map{u=> Data.UserData(u.email.value, u.password.value, u.role.value, u.uuid.value)}
implicit def userToUserData(users: Seq[User]): Seq[Data.UserData] = users.map { u =>
Data.UserData(
u.name.value,
u.email.value,
u.password.value,
u.role.value,
u.omVersion.value,
u.lastAccess.value)
}
def toUser(uuid: UUID, userData: UserData): User = User(
userData.name,
Email(userData.email),
Password(userData.password),
Version(userData.omVersion),
userData.lastAccess,
Role(userData.role),
uuid
)
class Users(tag: Tag) extends Table[(UUID, Email, Password, Role)](tag, "USERS") {
class Users(tag: Tag) extends Table[(UUID, String, Email, Password, Role, Version, Long)](tag, "USERS") {
def uuid = column[UUID]("UUID", O.PrimaryKey)
def name = column[String]("NAME")
def email = column[Email]("EMAIL")
def password = column[Password]("PASSWORD")
def role = column[Role]("ROLE")
def * = (uuid, email, password, role)
def omVersion = column[Version]("OMVERSION")
def lastAccess = column[Long]("LASTACCESS")
def * = (uuid, name, email, password, role, omVersion, lastAccess)
}
val userTable = TableQuery[Users]
......@@ -45,26 +79,7 @@ object DB {
url = s"jdbc:h2:/${Settings.location}/db"
)
def users =
Await.result(
db.run(userTable.result).map { x =>
x.map {
case (uuid, email, password, role) => User(email, password, role, uuid)
}
}, Duration.Inf
)
// val users = Seq(User(Login("foo"), Password("foo"), UUID("foo-123-567-foo")), User(Login("bar"), Password("bar"), UUID("bar-123-567-bar")))
def uuid(email: Email): Option[UUID] = users.find(_.email == email).map {
_.uuid
}
def uuid(email: Email, password: Password): Option[UUID] = users.find(u => u.email == email && u.password == password).map {
_.uuid
}
// TRANSACTIONS
def runTransaction[E <: Effect](actions: DBIOAction[_, NoStream, E]*) =
Await.result(
db.run(
......@@ -75,20 +90,68 @@ object DB {
def initDB = {
runTransaction(userTable.schema.createIfNotExists)
if (DB.users.isEmpty) {
DB.addUser(DB.Email("admin@admin.com"), DB.Password("admin"), DB.admin, UUID("foo-123-567-foo"))
DB.addUser("admin", DB.Email("admin@admin.com"), DB.Password("admin"), Utils.openmoleversion.stable, JWT.now, DB.admin, UUID("foo-123-567-foo"))
}
}
def addUser(email: Email, password: Password, role: Role = simpleUser): Unit = {
addUser(email, password, role, UUID(util.UUID.randomUUID().toString))
def addUser(name: String, email: Email, password: Password, omVersion: Version, lastAccess: Long, role: Role = simpleUser): Unit = {
addUser(name, email, password, omVersion, lastAccess, role, UUID(util.UUID.randomUUID().toString))
}
def addUser(email: Email, password: Password, role: Role, uuid: UUID): Unit = {
if (!DBQueries.exists(email)) {
def addUser(name: String, email: Email, password: Password, omVersion: Version, lastAccess: Long, role: Role, uuid: UUID): Unit = {
if (!exists(email)) {
runTransaction(
userTable += (uuid, email, password, role)
userTable += (uuid, name, email, password, role, omVersion, lastAccess)
)
}
}
def upsert(user: User) = {
runTransaction(
userTable.insertOrUpdate(user.uuid, user.name, user.email, user.password, user.role, user.omVersion, user.lastAccess)
)
}
def setLastAccess(email: Email, lastAccess: Long) =
runTransaction {
getLastAccesQuery(email).update(lastAccess)
}
def delete(user: User) = {
runTransaction(
userTable.filter {
_.uuid === user.uuid
}.delete
)
}
//QUERIES
// val users = Seq(User(Login("foo"), Password("foo"), UUID("foo-123-567-foo")), User(Login("bar"), Password("bar"), UUID("bar-123-567-bar")))
def uuid(email: Email): Option[UUID] = users.find(_.email == email).map {
_.uuid
}
def uuid(email: Email, password: Password): Option[UUID] = users.find(u => u.email == email && u.password == password).map {
_.uuid
}
def get(email: Email) = {
runQuery(
getQuery(email)
).headOption
}
def users = runQuery(
for {
u <- userTable
} yield (u)
)
def exists(email: Email) = get(email).isDefined
def isAdmin(email: Email) = get(email).map {
_.role
} == Some(admin)
}
......@@ -10,31 +10,24 @@ import scala.concurrent.ExecutionContext.Implicits.global
import shared._
object DBQueries {
type UserQuery = Query[Users, (UUID, Email, Password, Role), Seq]
type UserQuery = Query[Users, (UUID, String, Email, Password, Role, Version, Long), Seq]
def runQuery(query: UserQuery) =
Await.result(
db.run(
query.result
), Duration.Inf
).map { case (u, e, p, r) => User(e, p, r, u) }
).map { case (u, n, e, p, r, v, l) => User(n, e, p, v, l, r, u) }
def exists(email: Email) = get(email).isDefined
def isAdmin(email: Email) = get(email).map{_.role} == Some(admin)
def get(email: Email) = {
runQuery(
for {
u <- userTable if (u.email === email)
} yield (u)
).headOption
}
def users = runQuery(
// Query statements
def getQuery(email: Email) =
for {
u <- userTable
u <- userTable if (u.email === email)
} yield (u)
)
def getLastAccesQuery(email: Email) =
for {
u <- userTable if (u.email === email)
} yield (u.lastAccess)
}
package org.openmoleconnect.server
import java.text.SimpleDateFormat
import java.util.Locale
import org.apache.http.impl.EnglishReasonPhraseCatalog
object Utils {
object openmoleversion {
def stable = DB.Version("FIXME STABLE")
def developpement = DB.Version("FIXME DEV")
}
}
......@@ -5,4 +5,8 @@ import shared.Data.UserData
trait AdminApi {
def users(): Seq[UserData]
def upserted(userData: UserData): Seq[UserData]
def delete(userData: UserData): Seq[UserData]
}
\ No newline at end of file
......@@ -4,6 +4,20 @@ object Data {
val connectionRoute = "/connection"
val adminRoutePrefix = "shared/AdminApi"
case class UserData(email: String, password: String, role: String, uuid: String)
type Role = String
val admin: Role = "Admin"
val user: Role = "User"
type Status = String
val running: Status = "Running"
val off: Status = "Off"
val error: Status = "Error"
case class UserData(name: String, email: String, password: String, role: Role, omVersion: String, lastAccess: Long)
case class PersonalUserData(name: String, email: String, password: String, role: Role)
case class UserStatus(uuid: String, status: Status)
}
\ No newline at end of file