mirror of
				https://github.com/arcan1s/ffxivbis.git
				synced 2025-10-30 21:23:41 +00:00 
			
		
		
		
	base views
This commit is contained in:
		| @ -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) | ||||
| } | ||||
|  | ||||
		Reference in New Issue
	
	Block a user