mirror of
https://github.com/arcan1s/ffxivbis.git
synced 2025-04-25 01:37:17 +00:00
base views
This commit is contained in:
parent
d5233361e5
commit
9668a0edd1
@ -23,7 +23,7 @@ class BiSView(override val storage: ActorRef, ariyala: ActorRef)(implicit timeou
|
||||
get {
|
||||
complete {
|
||||
bis(partyId, None).map { players =>
|
||||
BiSView.template(partyId, players, Piece.available, None)
|
||||
BiSView.template(partyId, players, None)
|
||||
}.map { text =>
|
||||
(StatusCodes.OK, RootView.toHtml(text))
|
||||
}
|
||||
@ -53,8 +53,10 @@ class BiSView(override val storage: ActorRef, ariyala: ActorRef)(implicit timeou
|
||||
maybePiece: Option[String], maybeIsTome: Option[String],
|
||||
maybeLink: Option[String], action: String)
|
||||
(implicit executionContext: ExecutionContext, timeout: Timeout): Future[Unit] = {
|
||||
import me.arcanis.ffxivbis.utils.Implicits._
|
||||
|
||||
def getPiece(playerId: PlayerId, piece: String) =
|
||||
Try(Piece(piece, maybeIsTome.isDefined, playerId.job)).toOption
|
||||
Try(Piece(piece, maybeIsTome, playerId.job)).toOption
|
||||
|
||||
PlayerId(partyId, player) match {
|
||||
case Some(playerId) => (maybePiece, action, maybeLink) match {
|
||||
@ -77,7 +79,7 @@ class BiSView(override val storage: ActorRef, ariyala: ActorRef)(implicit timeou
|
||||
object BiSView {
|
||||
import scalatags.Text.all._
|
||||
|
||||
def template(partyId: String, party: Seq[Player], pieces: Seq[String], error: Option[String]): String =
|
||||
def template(partyId: String, party: Seq[Player], error: Option[String]): String =
|
||||
"<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01//EN\" \"http://www.w3.org/TR/html4/strict.dtd\">" +
|
||||
html(lang:="en",
|
||||
head(
|
||||
@ -95,7 +97,7 @@ object BiSView {
|
||||
select(name:="player", id:="player", title:="player")
|
||||
(for (player <- party) yield option(player.playerId.toString)),
|
||||
select(name:="piece", id:="piece", title:="piece")
|
||||
(for (piece <- pieces) yield option(piece)),
|
||||
(for (piece <- Piece.available) yield option(piece)),
|
||||
input(name:="is_tome", id:="is_tome", title:="is tome", `type`:="checkbox"),
|
||||
label(`for`:="is_tome")("is tome gear"),
|
||||
input(name:="action", id:="action", `type`:="hidden", value:="add"),
|
||||
|
@ -0,0 +1,120 @@
|
||||
package me.arcanis.ffxivbis.http.view
|
||||
|
||||
import akka.actor.ActorRef
|
||||
import akka.http.scaladsl.model.StatusCodes
|
||||
import akka.http.scaladsl.server.Directives._
|
||||
import akka.http.scaladsl.server.Route
|
||||
import akka.util.Timeout
|
||||
import me.arcanis.ffxivbis.http.{Authorization, LootHelper}
|
||||
import me.arcanis.ffxivbis.models.{Piece, PlayerIdWithCounters}
|
||||
|
||||
import scala.concurrent.{ExecutionContext, Future}
|
||||
import scala.util.{Failure, Success, Try}
|
||||
|
||||
class LootSuggestView(override val storage: ActorRef)(implicit timeout: Timeout)
|
||||
extends LootHelper(storage) with Authorization {
|
||||
|
||||
def route: Route = getIndex ~ suggestLoot
|
||||
|
||||
def getIndex: Route =
|
||||
path("party" / Segment / "suggest") { partyId: String =>
|
||||
extractExecutionContext { implicit executionContext =>
|
||||
authenticateBasicBCrypt(s"party $partyId", authGet(partyId)) { _ =>
|
||||
get {
|
||||
complete {
|
||||
val text = LootSuggestView.template(partyId, Seq.empty, None, None)
|
||||
(StatusCodes.OK, RootView.toHtml(text))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
def suggestLoot: Route =
|
||||
path("party" / Segment / "suggest") { partyId: String =>
|
||||
extractExecutionContext { implicit executionContext =>
|
||||
authenticateBasicBCrypt(s"party $partyId", authGet(partyId)) { _ =>
|
||||
post {
|
||||
formFields("piece".as[String], "is_tome".as[String].?) { (piece, maybeTome) =>
|
||||
import me.arcanis.ffxivbis.utils.Implicits._
|
||||
val maybePiece = Try(Piece(piece, maybeTome)).toOption
|
||||
|
||||
onComplete(suggestLootCall(partyId, maybePiece)) {
|
||||
case Success(players) =>
|
||||
val text = LootSuggestView.template(partyId, players, maybePiece, None)
|
||||
complete(StatusCodes.OK, RootView.toHtml(text))
|
||||
case Failure(exception) =>
|
||||
val text = LootSuggestView.template(partyId, Seq.empty, maybePiece, Some(exception.getMessage))
|
||||
complete(StatusCodes.OK, RootView.toHtml(text))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private def suggestLootCall(partyId: String, maybePiece: Option[Piece])
|
||||
(implicit executionContext: ExecutionContext, timeout: Timeout): Future[Seq[PlayerIdWithCounters]] =
|
||||
maybePiece match {
|
||||
case Some(piece) => suggestPiece(partyId, piece)
|
||||
case _ => Future.failed(new Error(s"Could not construct piece from `$maybePiece`"))
|
||||
}
|
||||
}
|
||||
|
||||
object LootSuggestView {
|
||||
import scalatags.Text.all._
|
||||
|
||||
def template(partyId: String, party: Seq[PlayerIdWithCounters], piece: Option[Piece], error: Option[String]): String =
|
||||
"<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01//EN\" \"http://www.w3.org/TR/html4/strict.dtd\">" +
|
||||
html(lang:="en",
|
||||
head(
|
||||
title:="Suggest loot",
|
||||
link(rel:="stylesheet", `type`:="text/css", href:="/static/styles.css")
|
||||
),
|
||||
|
||||
body(
|
||||
h2("Suggest loot"),
|
||||
|
||||
ErrorView.template(error),
|
||||
SearchLineView.template,
|
||||
|
||||
form(action:=s"/party/$partyId/suggest", method:="post")(
|
||||
select(name:="piece", id:="piece", title:="piece")
|
||||
(for (piece <- Piece.available) yield option(piece)),
|
||||
input(name:="is_tome", id:="is_tome", title:="is tome", `type`:="checkbox"),
|
||||
label(`for`:="is_tome")("is tome gear"),
|
||||
input(name:="suggest", id:="suggest", `type`:="submit", value:="suggest")
|
||||
),
|
||||
|
||||
table(id:="result")(
|
||||
tr(
|
||||
th("player"),
|
||||
th("is required"),
|
||||
th("these pieces looted"),
|
||||
th("total bis pieces looted"),
|
||||
th("total pieces looted"),
|
||||
th("")
|
||||
),
|
||||
for (player <- party) yield tr(
|
||||
td(`class`:="include_search")(player.playerId.toString),
|
||||
td(player.isRequiredToString),
|
||||
td(player.lootCount),
|
||||
td(player.lootCountBiS),
|
||||
td(player.lootCountTotal),
|
||||
td(
|
||||
form(action:=s"/party/$partyId/loot", method:="post")(
|
||||
input(name:="player", id:="player", `type`:="hidden", value:=player.playerId.toString),
|
||||
input(name:="piece", id:="piece", `type`:="hidden", value:=piece.map(_.piece).getOrElse("")),
|
||||
input(name:="is_tome", id:="is_tome", `type`:="hidden", value:=piece.map(_.isTomeToString).getOrElse("")),
|
||||
input(name:="action", id:="action", `type`:="hidden", value:="add"),
|
||||
input(name:="add", id:="add", `type`:="submit", value:="add")
|
||||
)
|
||||
)
|
||||
)
|
||||
),
|
||||
|
||||
ExportToCSVView.template,
|
||||
script(src:="/static/table_search.js", `type`:="text/javascript")
|
||||
)
|
||||
)
|
||||
}
|
@ -23,7 +23,7 @@ class LootView (override val storage: ActorRef)(implicit timeout: Timeout)
|
||||
get {
|
||||
complete {
|
||||
loot(partyId, None).map { players =>
|
||||
LootView.template(partyId, players, Piece.available, None)
|
||||
LootView.template(partyId, players, None)
|
||||
}.map { text =>
|
||||
(StatusCodes.OK, RootView.toHtml(text))
|
||||
}
|
||||
@ -53,8 +53,10 @@ class LootView (override val storage: ActorRef)(implicit timeout: Timeout)
|
||||
maybePiece: String, maybeIsTome: Option[String],
|
||||
action: String)
|
||||
(implicit executionContext: ExecutionContext, timeout: Timeout): Future[Unit] = {
|
||||
import me.arcanis.ffxivbis.utils.Implicits._
|
||||
|
||||
def getPiece(playerId: PlayerId) =
|
||||
Try(Piece(maybePiece, maybeIsTome.isDefined, playerId.job)).toOption
|
||||
Try(Piece(maybePiece, maybeIsTome, playerId.job)).toOption
|
||||
|
||||
PlayerId(partyId, player) match {
|
||||
case Some(playerId) => (getPiece(playerId), action) match {
|
||||
@ -70,7 +72,7 @@ class LootView (override val storage: ActorRef)(implicit timeout: Timeout)
|
||||
object LootView {
|
||||
import scalatags.Text.all._
|
||||
|
||||
def template(partyId: String, party: Seq[Player], pieces: Seq[String], error: Option[String]): String =
|
||||
def template(partyId: String, party: Seq[Player], error: Option[String]): String =
|
||||
"<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01//EN\" \"http://www.w3.org/TR/html4/strict.dtd\">" +
|
||||
html(lang:="en",
|
||||
head(
|
||||
@ -88,7 +90,7 @@ object LootView {
|
||||
select(name:="player", id:="player", title:="player")
|
||||
(for (player <- party) yield option(player.playerId.toString)),
|
||||
select(name:="piece", id:="piece", title:="piece")
|
||||
(for (piece <- pieces) yield option(piece)),
|
||||
(for (piece <- Piece.available) yield option(piece)),
|
||||
input(name:="is_tome", id:="is_tome", title:="is tome", `type`:="checkbox"),
|
||||
label(`for`:="is_tome")("is tome gear"),
|
||||
input(name:="action", id:="action", `type`:="hidden", value:="add"),
|
||||
|
124
src/main/scala/me/arcanis/ffxivbis/http/view/PlayerView.scala
Normal file
124
src/main/scala/me/arcanis/ffxivbis/http/view/PlayerView.scala
Normal file
@ -0,0 +1,124 @@
|
||||
package me.arcanis.ffxivbis.http.view
|
||||
|
||||
import akka.actor.ActorRef
|
||||
import akka.http.scaladsl.model.StatusCodes
|
||||
import akka.http.scaladsl.server.Directives._
|
||||
import akka.http.scaladsl.server.Route
|
||||
import akka.util.Timeout
|
||||
import me.arcanis.ffxivbis.http.{Authorization, PlayerHelper}
|
||||
import me.arcanis.ffxivbis.models.{BiS, Job, Player, PlayerId, PlayerIdWithCounters}
|
||||
|
||||
import scala.concurrent.{ExecutionContext, Future}
|
||||
|
||||
class PlayerView(override val storage: ActorRef, ariyala: ActorRef)(implicit timeout: Timeout)
|
||||
extends PlayerHelper(storage, ariyala) with Authorization {
|
||||
|
||||
def route: Route = getParty ~ modifyParty
|
||||
|
||||
def getParty: Route =
|
||||
path("party" / Segment) { partyId: String =>
|
||||
extractExecutionContext { implicit executionContext =>
|
||||
authenticateBasicBCrypt(s"party $partyId", authGet(partyId)) { _ =>
|
||||
get {
|
||||
complete {
|
||||
getPlayers(partyId, None).map { players =>
|
||||
PlayerView.template(partyId, players.map(_.withCounters(None)), None)
|
||||
}.map { text =>
|
||||
(StatusCodes.OK, RootView.toHtml(text))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
def modifyParty: Route =
|
||||
path("party" / Segment) { partyId: String =>
|
||||
extractExecutionContext { implicit executionContext =>
|
||||
authenticateBasicBCrypt(s"party $partyId", authPost(partyId)) { _ =>
|
||||
post {
|
||||
formFields("nick".as[String], "job".as[String], "priority".as[Int].?, "link".as[String].?, "action".as[String]) {
|
||||
(nick, job, maybePriority, maybeLink, action) =>
|
||||
onComplete(modifyPartyCall(partyId, nick, job, maybePriority, maybeLink, action)) {
|
||||
case _ => redirect(s"/party/$partyId", StatusCodes.Found)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private def modifyPartyCall(partyId: String, nick: String, job: String,
|
||||
maybePriority: Option[Int], maybeLink: Option[String],
|
||||
action: String)
|
||||
(implicit executionContext: ExecutionContext, timeout: Timeout): Future[Unit] = {
|
||||
def maybePlayerId = PlayerId(partyId, Some(nick), Some(job))
|
||||
def player(playerId: PlayerId) =
|
||||
Player(partyId, playerId.job, playerId.nick, BiS(), Seq.empty, maybeLink, maybePriority.getOrElse(0))
|
||||
|
||||
(action, maybePlayerId) match {
|
||||
case ("add", Some(playerId)) => addPlayer(player(playerId)).map(_ => ())
|
||||
case ("remove", Some(playerId)) => removePlayer(playerId).map(_ => ())
|
||||
case _ => Future.failed(new Error(s"Could not perform $action with $nick ($job)"))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
object PlayerView {
|
||||
import scalatags.Text.all._
|
||||
|
||||
def template(partyId: String, party: Seq[PlayerIdWithCounters], error: Option[String]): String =
|
||||
"<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01//EN\" \"http://www.w3.org/TR/html4/strict.dtd\">" +
|
||||
html(lang:="en",
|
||||
head(
|
||||
title:="Party",
|
||||
link(rel:="stylesheet", `type`:="text/css", href:="/static/styles.css")
|
||||
),
|
||||
|
||||
body(
|
||||
h2("Party"),
|
||||
|
||||
ErrorView.template(error),
|
||||
SearchLineView.template,
|
||||
|
||||
form(action:=s"/party/$partyId", method:="post")(
|
||||
input(name:="nick", id:="nick", placeholder:="nick", title:="nick", `type`:="nick"),
|
||||
select(name:="job", id:="job", title:="job")
|
||||
(for (job <- Job.groupAll) yield option(job.toString)),
|
||||
input(name:="link", id:="link", placeholder:="player bis link", title:="link", `type`:="text"),
|
||||
input(name:="prioiry", id:="priority", placeholder:="priority", title:="priority", `type`:="number", value:="0"),
|
||||
input(name:="action", id:="action", `type`:="hidden", value:="add"),
|
||||
input(name:="add", id:="add", `type`:="submit", value:="add")
|
||||
),
|
||||
|
||||
table(id:="result")(
|
||||
tr(
|
||||
th("nick"),
|
||||
th("job"),
|
||||
th("total bis pieces looted"),
|
||||
th("total pieces looted"),
|
||||
th("priority"),
|
||||
th("")
|
||||
),
|
||||
for (player <- party) yield tr(
|
||||
td(`class`:="include_search")(player.nick),
|
||||
td(`class`:="include_search")(player.job.toString),
|
||||
td(player.lootCountBiS),
|
||||
td(player.lootCountTotal),
|
||||
td(player.priority),
|
||||
td(
|
||||
form(action:=s"/party/$partyId", method:="post")(
|
||||
input(name:="nick", id:="nick", `type`:="hidden", value:=player.nick),
|
||||
input(name:="job", id:="job", `type`:="hidden", value:=player.job.toString),
|
||||
input(name:="action", id:="action", `type`:="hidden", value:="remove"),
|
||||
input(name:="remove", id:="remove", `type`:="submit", value:="x")
|
||||
)
|
||||
)
|
||||
)
|
||||
),
|
||||
|
||||
ExportToCSVView.template,
|
||||
script(src:="/static/table_search.js", `type`:="text/javascript")
|
||||
)
|
||||
)
|
||||
}
|
@ -10,10 +10,12 @@ class RootView(storage: ActorRef, ariyala: ActorRef)(implicit timeout: Timeout)
|
||||
|
||||
private val biSView = new BiSView(storage, ariyala)
|
||||
private val lootView = new LootView(storage)
|
||||
private val lootSuggestView = new LootSuggestView(storage)
|
||||
private val playerView = new PlayerView(storage, ariyala)
|
||||
private val userView = new UserView(storage)
|
||||
|
||||
def route: Route =
|
||||
biSView.route ~ lootView.route ~ userView.route
|
||||
biSView.route ~ lootView.route ~ lootSuggestView.route ~ playerView.route ~ userView.route
|
||||
}
|
||||
|
||||
object RootView {
|
||||
|
@ -14,7 +14,7 @@ import scala.util.Try
|
||||
class UserView(override val storage: ActorRef)(implicit timeout: Timeout)
|
||||
extends UserHelper(storage) with Authorization {
|
||||
|
||||
def route: Route = getUsers
|
||||
def route: Route = getUsers ~ modifyUsers
|
||||
|
||||
def getUsers: Route =
|
||||
path("party" / Segment / "users") { partyId: String =>
|
||||
@ -85,8 +85,8 @@ object UserView {
|
||||
SearchLineView.template,
|
||||
|
||||
form(action:=s"/party/$partyId/users", method:="post")(
|
||||
input(name:="username", id:="username", title:="username", placeholder:="username", `type`:="text"),
|
||||
input(name:="password", id:="password", title:="password", placeholder:="password", `type`:="password"),
|
||||
input(name:="username", id:="username", placeholder:="username", title:="username", `type`:="text"),
|
||||
input(name:="password", id:="password", placeholder:="password", title:="password", `type`:="password"),
|
||||
select(name:="permission", id:="permission", title:="permission")(option("get"), option("post")),
|
||||
input(name:="action", id:="action", `type`:="hidden", value:="add"),
|
||||
input(name:="add", id:="add", `type`:="submit", value:="add")
|
||||
|
@ -1,5 +1,6 @@
|
||||
package me.arcanis.ffxivbis.models
|
||||
|
||||
import scala.util.Try
|
||||
import scala.util.matching.Regex
|
||||
|
||||
trait PlayerIdBase {
|
||||
@ -14,13 +15,13 @@ case class PlayerId(partyId: String, job: Job.Job, nick: String) extends PlayerI
|
||||
object PlayerId {
|
||||
def apply(partyId: String, maybeNick: Option[String], maybeJob: Option[String]): Option[PlayerId] =
|
||||
(maybeNick, maybeJob) match {
|
||||
case (Some(nick), Some(job)) => Some(PlayerId(partyId, Job.fromString(job), nick))
|
||||
case (Some(nick), Some(job)) => Try(PlayerId(partyId, Job.fromString(job), nick)).toOption
|
||||
case _ => None
|
||||
}
|
||||
|
||||
private val prettyPlayerIdRegex: Regex = "^(.*) \\(([A-Z]{3})\\)$".r
|
||||
def apply(partyId: String, player: String): Option[PlayerId] = player match {
|
||||
case s"${prettyPlayerIdRegex(nick, job)}" => Some(PlayerId(partyId, Job.fromString(job), nick))
|
||||
case s"${prettyPlayerIdRegex(nick, job)}" => Try(PlayerId(partyId, Job.fromString(job), nick)).toOption
|
||||
case _ => None
|
||||
}
|
||||
}
|
||||
|
@ -12,10 +12,10 @@ case class PlayerIdWithCounters(partyId: String,
|
||||
extends PlayerIdBase {
|
||||
import PlayerIdWithCounters._
|
||||
|
||||
def playerId: PlayerId = PlayerId(partyId, job, nick)
|
||||
|
||||
def gt(that: PlayerIdWithCounters, orderBy: Seq[String]): Boolean =
|
||||
withCounters(orderBy) > that.withCounters(orderBy)
|
||||
def isRequiredToString: String = if (isRequired) "yes" else "no"
|
||||
def playerId: PlayerId = PlayerId(partyId, job, nick)
|
||||
|
||||
private val counters: Map[String, Int] = Map(
|
||||
"isRequired" -> (if (isRequired) 1 else 0),
|
||||
|
@ -9,6 +9,11 @@ import scala.concurrent.duration.FiniteDuration
|
||||
import scala.language.implicitConversions
|
||||
|
||||
object Implicits {
|
||||
implicit def getBooleanFromOptionString(maybeYes: Option[String]): Boolean = maybeYes match {
|
||||
case Some("yes" | "on") => true
|
||||
case _ => false
|
||||
}
|
||||
|
||||
implicit def getFiniteDuration(duration: Duration): Timeout =
|
||||
FiniteDuration(duration.toNanos, TimeUnit.NANOSECONDS)
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user