1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
|
package byspel
import akka.http.scaladsl.server.Route
import akka.http.scaladsl.marshalling.{Marshaller, ToEntityMarshaller}
import akka.http.scaladsl.model.headers.HttpCookie
import akka.http.scaladsl.model.{MediaTypes, StatusCodes, Uri}
import app.HttpApi
import scalatags.Text.all._
trait Ui extends HttpApi { self: Service with Tables =>
// allows using scalatags templates as HTTP responses
implicit val tagMarshaller: ToEntityMarshaller[Tag] = {
Marshaller.stringMarshaller(MediaTypes.`text/html`).compose { (tag: Tag) =>
tag.render
}
}
def page(content: Tag*) = html(
scalatags.Text.all.head(
link(
rel := "stylesheet",
`type` := "text/css",
href := "/assets/normalize.css"
),
link(
rel := "stylesheet",
`type` := "text/css",
href := "/assets/main.css"
)
),
body(
content
)
)
def loginForm(alert: Option[String]) = page(
img(src := "/assets/logo.svg"),
h3("Sign in to crashbox"),
alert match {
case Some(message) => div(`class` := "alert")(message)
case None => span()
},
form(action := "/login", attr("method") := "post")(
label(`for` := "username")("Username or email address"),
input(`type` := "text", placeholder := "", name := "username", required),
label(`for` := "password")("Password"),
input(`type` := "password",
placeholder := "",
name := "password",
required),
button(`type` := "submit")("Sign in")
)
)
def mainPage(user: UsersRow) = page(
h1(s"Welcome ${user.fullName.getOrElse("")}!"),
form(action := "/logout", attr("method") := "post")(
button(`type` := "submit")("Sign out")
)
)
def authenticated(inner: UsersRow => Route): Route =
optionalCookie("session") {
case Some(sessionCookie) =>
onSuccess(self.checkSession(sessionCookie.value)) {
case Some(user) =>
inner(user)
case None => complete(StatusCodes.NotFound)
}
case None => complete(StatusCodes.NotFound)
}
def route =
pathPrefix("assets") {
getFromResourceDirectory("assets")
} ~ path("login") {
get {
complete(loginForm(None))
} ~
post {
formFields("username", "password") {
case (u, p) =>
onSuccess(self.login(u, p)) {
case None =>
complete(StatusCodes.NotFound -> loginForm(
Some("Incorrect username or password.")))
case Some((user, session)) =>
setCookie(HttpCookie("session", session.sessionId)) {
redirect(Uri(s"/${user.primaryEmail}"), StatusCodes.Found)
}
}
}
}
} ~ path("logout") {
post {
cookie("session") { cookiePair =>
onSuccess(endSession(cookiePair.value)) { _ =>
deleteCookie(cookiePair.name) {
redirect(Uri("/"), StatusCodes.Found)
}
}
}
}
} ~ path(Segment) { userEmail =>
authenticated { user =>
if (user.primaryEmail == userEmail) {
get {
complete(mainPage(user))
}
} else {
complete(StatusCodes.NotFound)
}
}
} ~ get {
redirect(Uri("/login"), StatusCodes.Found)
}
}
|