mirror of
https://github.com/arcan1s/ffxivbis.git
synced 2025-04-24 17:27:17 +00:00
crafted items support (#5)
This commit is contained in:
parent
16ce0bf61c
commit
10c107d2c2
@ -0,0 +1,17 @@
|
||||
-- loot
|
||||
alter table loot add column piece_type text;
|
||||
|
||||
update loot set piece_type = 'Tome' where is_tome = 1;
|
||||
update loot set piece_type = 'Savage' where is_tome = 0;
|
||||
|
||||
alter table loot alter column piece_type set not null;
|
||||
alter table loot drop column is_tome;
|
||||
|
||||
-- bis
|
||||
alter table bis add column piece_type text;
|
||||
|
||||
update bis set piece_type = 'Tome' where is_tome = 1;
|
||||
update bis set piece_type = 'Savage' where is_tome = 0;
|
||||
|
||||
alter table bis alter column piece_type set not null;
|
||||
alter table bis drop column is_tome;
|
@ -0,0 +1,42 @@
|
||||
-- loot
|
||||
alter table loot add column piece_type text;
|
||||
|
||||
update loot set piece_type = 'Tome' where is_tome = 1;
|
||||
update loot set piece_type = 'Savage' where is_tome = 0;
|
||||
|
||||
create table loot_new (
|
||||
loot_id integer primary key autoincrement,
|
||||
player_id integer not null,
|
||||
created integer not null,
|
||||
piece text not null,
|
||||
piece_type text not null,
|
||||
job text not null,
|
||||
foreign key (player_id) references players(player_id) on delete cascade);
|
||||
insert into loot_new select loot_id, player_id, created, piece, piece_type, job from loot;
|
||||
|
||||
drop index loot_owner_idx;
|
||||
drop table loot;
|
||||
|
||||
alter table loot_new rename to loot;
|
||||
create index loot_owner_idx on loot(player_id);
|
||||
|
||||
-- bis
|
||||
alter table bis add column piece_type text;
|
||||
|
||||
update bis set piece_type = 'Tome' where is_tome = 1;
|
||||
update bis set piece_type = 'Savage' where is_tome = 0;
|
||||
|
||||
create table bis_new (
|
||||
player_id integer not null,
|
||||
created integer not null,
|
||||
piece text not null,
|
||||
piece_type text not null,
|
||||
job text not null,
|
||||
foreign key (player_id) references players(player_id) on delete cascade);
|
||||
insert into bis_new select player_id, created, piece, piece_type, job from bis;
|
||||
|
||||
drop index bis_piece_player_id_idx;
|
||||
drop table bis;
|
||||
|
||||
alter table bis_new rename to bis;
|
||||
create unique index bis_piece_player_id_idx on bis(player_id, piece);
|
@ -16,12 +16,12 @@ import io.swagger.v3.oas.annotations.responses.ApiResponse
|
||||
import io.swagger.v3.oas.annotations.Operation
|
||||
import javax.ws.rs._
|
||||
import me.arcanis.ffxivbis.http.api.v1.json._
|
||||
import me.arcanis.ffxivbis.models.{Job, Party, Permission, Piece}
|
||||
import me.arcanis.ffxivbis.models.{Job, Party, Permission, Piece, PieceType}
|
||||
|
||||
@Path("api/v1")
|
||||
class TypesEndpoint(config: Config) extends JsonSupport {
|
||||
|
||||
def route: Route = getJobs ~ getPermissions ~ getPieces ~ getPriority
|
||||
def route: Route = getJobs ~ getPermissions ~ getPieces ~ getPieceTypes ~ getPriority
|
||||
|
||||
@GET
|
||||
@Path("types/jobs")
|
||||
@ -86,6 +86,27 @@ class TypesEndpoint(config: Config) extends JsonSupport {
|
||||
}
|
||||
}
|
||||
|
||||
@GET
|
||||
@Path("types/pieces/types")
|
||||
@Produces(value = Array("application/json"))
|
||||
@Operation(summary = "piece types list", description = "Returns the available piece types",
|
||||
responses = Array(
|
||||
new ApiResponse(responseCode = "200", description = "List of available piece types",
|
||||
content = Array(new Content(
|
||||
array = new ArraySchema(schema = new Schema(implementation = classOf[String]))
|
||||
))),
|
||||
new ApiResponse(responseCode = "500", description = "Internal server error",
|
||||
content = Array(new Content(schema = new Schema(implementation = classOf[ErrorResponse])))),
|
||||
),
|
||||
tags = Array("types"),
|
||||
)
|
||||
def getPieceTypes: Route =
|
||||
path("types" / "pieces" / "types") {
|
||||
get {
|
||||
complete(PieceType.available.map(_.toString))
|
||||
}
|
||||
}
|
||||
|
||||
@GET
|
||||
@Path("types/priority")
|
||||
@Produces(value = Array("application/json"))
|
||||
|
@ -9,16 +9,16 @@
|
||||
package me.arcanis.ffxivbis.http.api.v1.json
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema
|
||||
import me.arcanis.ffxivbis.models.{Job, Piece}
|
||||
import me.arcanis.ffxivbis.models.{Job, Piece, PieceType}
|
||||
|
||||
case class PieceResponse(
|
||||
@Schema(description = "is piece tome gear", required = true) isTome: Boolean,
|
||||
@Schema(description = "piece type", required = true) pieceType: String,
|
||||
@Schema(description = "job name to which piece belong or AnyJob", required = true, example = "DNC") job: String,
|
||||
@Schema(description = "piece name", required = true, example = "body") piece: String) {
|
||||
def toPiece: Piece = Piece(piece, isTome, Job.withName(job))
|
||||
def toPiece: Piece = Piece(piece, PieceType.withName(pieceType), Job.withName(job))
|
||||
}
|
||||
|
||||
object PieceResponse {
|
||||
def fromPiece(piece: Piece): PieceResponse =
|
||||
PieceResponse(piece.isTome, piece.job.toString, piece.piece)
|
||||
PieceResponse(piece.pieceType.toString, piece.job.toString, piece.piece)
|
||||
}
|
||||
|
@ -14,7 +14,7 @@ import akka.http.scaladsl.server.Directives._
|
||||
import akka.http.scaladsl.server._
|
||||
import akka.util.Timeout
|
||||
import me.arcanis.ffxivbis.http.{Authorization, BiSHelper}
|
||||
import me.arcanis.ffxivbis.models.{Piece, Player, PlayerId}
|
||||
import me.arcanis.ffxivbis.models.{Piece, PieceType, Player, PlayerId}
|
||||
|
||||
import scala.concurrent.{ExecutionContext, Future}
|
||||
import scala.util.Try
|
||||
@ -46,10 +46,10 @@ class BiSView(override val storage: ActorRef, override val ariyala: ActorRef)(im
|
||||
extractExecutionContext { implicit executionContext =>
|
||||
authenticateBasicBCrypt(s"party $partyId", authPost(partyId)) { _ =>
|
||||
post {
|
||||
formFields("player".as[String], "piece".as[String].?, "is_tome".as[String].?, "link".as[String].?, "action".as[String]) {
|
||||
(player, maybePiece, maybeIsTome, maybeLink, action) =>
|
||||
onComplete(modifyBiSCall(partyId, player, maybePiece, maybeIsTome, maybeLink, action)) {
|
||||
case _ => redirect(s"/party/$partyId/bis", StatusCodes.Found)
|
||||
formFields("player".as[String], "piece".as[String].?, "piece_type".as[String].?, "link".as[String].?, "action".as[String]) {
|
||||
(player, maybePiece, maybePieceType, maybeLink, action) =>
|
||||
onComplete(modifyBiSCall(partyId, player, maybePiece, maybePieceType, maybeLink, action)) { _ =>
|
||||
redirect(s"/party/$partyId/bis", StatusCodes.Found)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -58,25 +58,25 @@ class BiSView(override val storage: ActorRef, override val ariyala: ActorRef)(im
|
||||
}
|
||||
|
||||
private def modifyBiSCall(partyId: String, player: String,
|
||||
maybePiece: Option[String], maybeIsTome: Option[String],
|
||||
maybePiece: Option[String], maybePieceType: 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, pieceType: String) =
|
||||
Try(Piece(piece, PieceType.withName(pieceType), playerId.job)).toOption
|
||||
|
||||
def getPiece(playerId: PlayerId, piece: String) =
|
||||
Try(Piece(piece, maybeIsTome, playerId.job)).toOption
|
||||
def bisAction(playerId: PlayerId, piece: String, pieceType: String)(fn: Piece => Future[Int]) =
|
||||
getPiece(playerId, piece, pieceType) match {
|
||||
case Some(item) => fn(item).map(_ => ())
|
||||
case _ => Future.failed(new Error(s"Could not construct piece from `$piece ($pieceType)`"))
|
||||
}
|
||||
|
||||
PlayerId(partyId, player) match {
|
||||
case Some(playerId) => (maybePiece, action, maybeLink) match {
|
||||
case (Some(piece), "add", _) => getPiece(playerId, piece) match {
|
||||
case Some(item) => addPieceBiS(playerId, item).map(_ => ())
|
||||
case _ => Future.failed(new Error(s"Could not construct piece from `$piece`"))
|
||||
}
|
||||
case (Some(piece), "remove", _) => getPiece(playerId, piece) match {
|
||||
case Some(item) => removePieceBiS(playerId, item).map(_ => ())
|
||||
case _ => Future.failed(new Error(s"Could not construct piece from `$piece`"))
|
||||
}
|
||||
case (_, "create", Some(link)) => putBiS(playerId, link).map(_ => ())
|
||||
case Some(playerId) => (maybePiece, maybePieceType, action, maybeLink) match {
|
||||
case (Some(piece), Some(pieceType), "add", _) =>
|
||||
bisAction(playerId, piece, pieceType) { item => addPieceBiS(playerId, item) }
|
||||
case (Some(piece), Some(pieceType), "remove", _) =>
|
||||
bisAction(playerId, piece, pieceType) { item => removePieceBiS(playerId, item) }
|
||||
case (_, _, "create", Some(link)) => putBiS(playerId, link).map(_ => ())
|
||||
case _ => Future.failed(new Error(s"Could not perform $action"))
|
||||
}
|
||||
case _ => Future.failed(new Error(s"Could not construct player id from `$player`"))
|
||||
@ -107,8 +107,8 @@ object BiSView {
|
||||
(for (player <- party) yield option(player.playerId.toString)),
|
||||
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"),
|
||||
select(name:="piece_type", id:="piece_type", title:="piece type")
|
||||
(for (pieceType <- PieceType.available) yield option(pieceType.toString)),
|
||||
input(name:="action", id:="action", `type`:="hidden", value:="add"),
|
||||
input(name:="add", id:="add", `type`:="submit", value:="add")
|
||||
),
|
||||
@ -125,18 +125,18 @@ object BiSView {
|
||||
tr(
|
||||
th("player"),
|
||||
th("piece"),
|
||||
th("is tome"),
|
||||
th("piece type"),
|
||||
th("")
|
||||
),
|
||||
for (player <- party; piece <- player.bis.pieces) yield tr(
|
||||
td(`class`:="include_search")(player.playerId.toString),
|
||||
td(`class`:="include_search")(piece.piece),
|
||||
td(piece.isTomeToString),
|
||||
td(piece.pieceType.toString),
|
||||
td(
|
||||
form(action:=s"/party/$partyId/bis", method:="post")(
|
||||
input(name:="player", id:="player", `type`:="hidden", value:=player.playerId.toString),
|
||||
input(name:="piece", id:="piece", `type`:="hidden", value:=piece.piece),
|
||||
input(name:="is_tome", id:="is_tome", `type`:="hidden", value:=piece.isTomeToString),
|
||||
input(name:="piece_type", id:="piece_type", `type`:="hidden", value:=piece.pieceType.toString),
|
||||
input(name:="action", id:="action", `type`:="hidden", value:="remove"),
|
||||
input(name:="remove", id:="remove", `type`:="submit", value:="x")
|
||||
)
|
||||
|
@ -14,7 +14,7 @@ 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.{Job, Piece, PlayerIdWithCounters}
|
||||
import me.arcanis.ffxivbis.models.{Job, Piece, PieceType, PlayerIdWithCounters}
|
||||
|
||||
import scala.concurrent.{ExecutionContext, Future}
|
||||
import scala.util.{Failure, Success, Try}
|
||||
@ -43,9 +43,8 @@ class LootSuggestView(override val storage: ActorRef)(implicit timeout: Timeout)
|
||||
extractExecutionContext { implicit executionContext =>
|
||||
authenticateBasicBCrypt(s"party $partyId", authGet(partyId)) { _ =>
|
||||
post {
|
||||
formFields("piece".as[String], "job".as[String], "is_tome".as[String].?) { (piece, job, maybeTome) =>
|
||||
import me.arcanis.ffxivbis.utils.Implicits._
|
||||
val maybePiece = Try(Piece(piece, maybeTome, Job.withName(job))).toOption
|
||||
formFields("piece".as[String], "job".as[String], "piece_type".as[String]) { (piece, job, pieceType) =>
|
||||
val maybePiece = Try(Piece(piece, PieceType.withName(pieceType), Job.withName(job))).toOption
|
||||
|
||||
onComplete(suggestLootCall(partyId, maybePiece)) {
|
||||
case Success(players) =>
|
||||
@ -92,8 +91,8 @@ object LootSuggestView {
|
||||
(for (piece <- Piece.available) yield option(piece)),
|
||||
select(name:="job", id:="job", title:="job")
|
||||
(for (job <- Job.availableWithAnyJob) yield option(job.toString)),
|
||||
input(name:="is_tome", id:="is_tome", title:="is tome", `type`:="checkbox"),
|
||||
label(`for`:="is_tome")("is tome gear"),
|
||||
select(name:="piece_type", id:="piece_type", title:="piece type")
|
||||
(for (pieceType <- PieceType.available) yield option(pieceType.toString)),
|
||||
input(name:="suggest", id:="suggest", `type`:="submit", value:="suggest")
|
||||
),
|
||||
|
||||
@ -116,7 +115,7 @@ object LootSuggestView {
|
||||
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:="piece_type", id:="piece_type", `type`:="hidden", value:=piece.map(_.pieceType.toString).getOrElse("")),
|
||||
input(name:="action", id:="action", `type`:="hidden", value:="add"),
|
||||
input(name:="add", id:="add", `type`:="submit", value:="add")
|
||||
)
|
||||
|
@ -14,7 +14,7 @@ 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, Player, PlayerId}
|
||||
import me.arcanis.ffxivbis.models.{Piece, PieceType, Player, PlayerId}
|
||||
|
||||
import scala.concurrent.{ExecutionContext, Future}
|
||||
import scala.util.Try
|
||||
@ -46,10 +46,10 @@ class LootView (override val storage: ActorRef)(implicit timeout: Timeout)
|
||||
extractExecutionContext { implicit executionContext =>
|
||||
authenticateBasicBCrypt(s"party $partyId", authPost(partyId)) { _ =>
|
||||
post {
|
||||
formFields("player".as[String], "piece".as[String], "is_tome".as[String].?, "action".as[String]) {
|
||||
(player, maybePiece, maybeIsTome, action) =>
|
||||
onComplete(modifyLootCall(partyId, player, maybePiece, maybeIsTome, action)) {
|
||||
case _ => redirect(s"/party/$partyId/loot", StatusCodes.Found)
|
||||
formFields("player".as[String], "piece".as[String], "piece_type".as[String], "action".as[String]) {
|
||||
(player, piece, pieceType, action) =>
|
||||
onComplete(modifyLootCall(partyId, player, piece, pieceType, action)) { _ =>
|
||||
redirect(s"/party/$partyId/loot", StatusCodes.Found)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -57,20 +57,17 @@ class LootView (override val storage: ActorRef)(implicit timeout: Timeout)
|
||||
}
|
||||
}
|
||||
|
||||
private def modifyLootCall(partyId: String, player: String,
|
||||
maybePiece: String, maybeIsTome: Option[String],
|
||||
action: String)
|
||||
private def modifyLootCall(partyId: String, player: String, maybePiece: String,
|
||||
maybePieceType: String, action: String)
|
||||
(implicit executionContext: ExecutionContext, timeout: Timeout): Future[Unit] = {
|
||||
import me.arcanis.ffxivbis.utils.Implicits._
|
||||
|
||||
def getPiece(playerId: PlayerId) =
|
||||
Try(Piece(maybePiece, maybeIsTome, playerId.job)).toOption
|
||||
Try(Piece(maybePiece, PieceType.withName(maybePieceType), playerId.job)).toOption
|
||||
|
||||
PlayerId(partyId, player) match {
|
||||
case Some(playerId) => (getPiece(playerId), action) match {
|
||||
case (Some(piece), "add") => addPieceLoot(playerId, piece).map(_ => ())
|
||||
case (Some(piece), "remove") => removePieceLoot(playerId, piece).map(_ => ())
|
||||
case _ => Future.failed(new Error(s"Could not construct piece from `$maybePiece`"))
|
||||
case _ => Future.failed(new Error(s"Could not construct piece from `$maybePiece ($maybePieceType)`"))
|
||||
}
|
||||
case _ => Future.failed(new Error(s"Could not construct player id from `$player`"))
|
||||
}
|
||||
@ -100,8 +97,8 @@ object LootView {
|
||||
(for (player <- party) yield option(player.playerId.toString)),
|
||||
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"),
|
||||
select(name:="piece_type", id:="piece_type", title:="piece type")
|
||||
(for (pieceType <- PieceType.available) yield option(pieceType.toString)),
|
||||
input(name:="action", id:="action", `type`:="hidden", value:="add"),
|
||||
input(name:="add", id:="add", `type`:="submit", value:="add")
|
||||
),
|
||||
@ -110,20 +107,20 @@ object LootView {
|
||||
tr(
|
||||
th("player"),
|
||||
th("piece"),
|
||||
th("is tome"),
|
||||
th("piece type"),
|
||||
th("timestamp"),
|
||||
th("")
|
||||
),
|
||||
for (player <- party; loot <- player.loot) yield tr(
|
||||
td(`class`:="include_search")(player.playerId.toString),
|
||||
td(`class`:="include_search")(loot.piece.piece),
|
||||
td(loot.piece.isTomeToString),
|
||||
td(loot.piece.pieceType.toString),
|
||||
td(loot.timestamp.toString),
|
||||
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:=loot.piece.piece),
|
||||
input(name:="is_tome", id:="is_tome", `type`:="hidden", value:=loot.piece.isTomeToString),
|
||||
input(name:="piece_type", id:="piece_type", `type`:="hidden", value:=loot.piece.pieceType.toString),
|
||||
input(name:="action", id:="action", `type`:="hidden", value:="remove"),
|
||||
input(name:="remove", id:="remove", `type`:="submit", value:="x")
|
||||
)
|
||||
|
@ -101,9 +101,9 @@ object Job {
|
||||
lazy val availableWithAnyJob: Seq[Job] = available.prepended(AnyJob)
|
||||
|
||||
def withName(job: String): Job.Job =
|
||||
availableWithAnyJob.find(_.toString.equalsIgnoreCase(job.toUpperCase)) match {
|
||||
availableWithAnyJob.find(_.toString.equalsIgnoreCase(job)) match {
|
||||
case Some(value) => value
|
||||
case None if job.isEmpty => AnyJob
|
||||
case _ => throw new IllegalArgumentException("Invalid or unknown job")
|
||||
case _ => throw new IllegalArgumentException(s"Invalid or unknown job $job")
|
||||
}
|
||||
}
|
||||
|
@ -9,15 +9,14 @@
|
||||
package me.arcanis.ffxivbis.models
|
||||
|
||||
sealed trait Piece {
|
||||
def isTome: Boolean
|
||||
def pieceType: PieceType.PieceType
|
||||
def job: Job.Job
|
||||
def piece: String
|
||||
|
||||
def withJob(other: Job.Job): Piece
|
||||
|
||||
def isTomeToString: String = if (isTome) "yes" else "no"
|
||||
def upgrade: Option[PieceUpgrade] = this match {
|
||||
case _ if !isTome => None
|
||||
case _ if pieceType != PieceType.Tome => None
|
||||
case _: Waist => Some(AccessoryUpgrade)
|
||||
case _: PieceAccessory => Some(AccessoryUpgrade)
|
||||
case _: PieceBody => Some(BodyUpgrade)
|
||||
@ -28,59 +27,59 @@ sealed trait Piece {
|
||||
trait PieceAccessory extends Piece
|
||||
trait PieceBody extends Piece
|
||||
trait PieceUpgrade extends Piece {
|
||||
val isTome: Boolean = true
|
||||
val pieceType: PieceType.PieceType = PieceType.Tome
|
||||
val job: Job.Job = Job.AnyJob
|
||||
def withJob(other: Job.Job): Piece = this
|
||||
}
|
||||
trait PieceWeapon extends Piece
|
||||
|
||||
case class Weapon(override val isTome: Boolean, override val job: Job.Job) extends PieceWeapon {
|
||||
case class Weapon(override val pieceType: PieceType.PieceType, override val job: Job.Job) extends PieceWeapon {
|
||||
val piece: String = "weapon"
|
||||
def withJob(other: Job.Job): Piece = copy(job = other)
|
||||
}
|
||||
|
||||
case class Head(override val isTome: Boolean, override val job: Job.Job) extends PieceBody {
|
||||
case class Head(override val pieceType: PieceType.PieceType, override val job: Job.Job) extends PieceBody {
|
||||
val piece: String = "head"
|
||||
def withJob(other: Job.Job): Piece = copy(job = other)
|
||||
}
|
||||
case class Body(override val isTome: Boolean, override val job: Job.Job) extends PieceBody {
|
||||
case class Body(override val pieceType: PieceType.PieceType, override val job: Job.Job) extends PieceBody {
|
||||
val piece: String = "body"
|
||||
def withJob(other: Job.Job): Piece = copy(job = other)
|
||||
}
|
||||
case class Hands(override val isTome: Boolean, override val job: Job.Job) extends PieceBody {
|
||||
case class Hands(override val pieceType: PieceType.PieceType, override val job: Job.Job) extends PieceBody {
|
||||
val piece: String = "hands"
|
||||
def withJob(other: Job.Job): Piece = copy(job = other)
|
||||
}
|
||||
case class Waist(override val isTome: Boolean, override val job: Job.Job) extends PieceBody {
|
||||
case class Waist(override val pieceType: PieceType.PieceType, override val job: Job.Job) extends PieceBody {
|
||||
val piece: String = "waist"
|
||||
def withJob(other: Job.Job): Piece = copy(job = other)
|
||||
}
|
||||
case class Legs(override val isTome: Boolean, override val job: Job.Job) extends PieceBody {
|
||||
case class Legs(override val pieceType: PieceType.PieceType, override val job: Job.Job) extends PieceBody {
|
||||
val piece: String = "legs"
|
||||
def withJob(other: Job.Job): Piece = copy(job = other)
|
||||
}
|
||||
case class Feet(override val isTome: Boolean, override val job: Job.Job) extends PieceBody {
|
||||
case class Feet(override val pieceType: PieceType.PieceType, override val job: Job.Job) extends PieceBody {
|
||||
val piece: String = "feet"
|
||||
def withJob(other: Job.Job): Piece = copy(job = other)
|
||||
}
|
||||
|
||||
case class Ears(override val isTome: Boolean, override val job: Job.Job) extends PieceAccessory {
|
||||
case class Ears(override val pieceType: PieceType.PieceType, override val job: Job.Job) extends PieceAccessory {
|
||||
val piece: String = "ears"
|
||||
def withJob(other: Job.Job): Piece = copy(job = other)
|
||||
}
|
||||
case class Neck(override val isTome: Boolean, override val job: Job.Job) extends PieceAccessory {
|
||||
case class Neck(override val pieceType: PieceType.PieceType, override val job: Job.Job) extends PieceAccessory {
|
||||
val piece: String = "neck"
|
||||
def withJob(other: Job.Job): Piece = copy(job = other)
|
||||
}
|
||||
case class Wrist(override val isTome: Boolean, override val job: Job.Job) extends PieceAccessory {
|
||||
case class Wrist(override val pieceType: PieceType.PieceType, override val job: Job.Job) extends PieceAccessory {
|
||||
val piece: String = "wrist"
|
||||
def withJob(other: Job.Job): Piece = copy(job = other)
|
||||
}
|
||||
case class Ring(override val isTome: Boolean, override val job: Job.Job, override val piece: String = "ring")
|
||||
case class Ring(override val pieceType: PieceType.PieceType, override val job: Job.Job, override val piece: String = "ring")
|
||||
extends PieceAccessory {
|
||||
def withJob(other: Job.Job): Piece = copy(job = other)
|
||||
override def equals(obj: Any): Boolean = obj match {
|
||||
case Ring(thatIsTome, thatJob, _) => (thatIsTome == isTome) && (thatJob == job)
|
||||
case Ring(thatPieceType, thatJob, _) => (thatPieceType == pieceType) && (thatJob == job)
|
||||
case _ => false
|
||||
}
|
||||
}
|
||||
@ -96,19 +95,19 @@ case object WeaponUpgrade extends PieceUpgrade {
|
||||
}
|
||||
|
||||
object Piece {
|
||||
def apply(piece: String, isTome: Boolean, job: Job.Job = Job.AnyJob): Piece =
|
||||
def apply(piece: String, pieceType: PieceType.PieceType, job: Job.Job = Job.AnyJob): Piece =
|
||||
piece.toLowerCase match {
|
||||
case "weapon" => Weapon(isTome, job)
|
||||
case "head" => Head(isTome, job)
|
||||
case "body" => Body(isTome, job)
|
||||
case "hands" => Hands(isTome, job)
|
||||
case "waist" => Waist(isTome, job)
|
||||
case "legs" => Legs(isTome, job)
|
||||
case "feet" => Feet(isTome, job)
|
||||
case "ears" => Ears(isTome, job)
|
||||
case "neck" => Neck(isTome, job)
|
||||
case "wrist" => Wrist(isTome, job)
|
||||
case ring @ ("ring" | "left ring" | "right ring") => Ring(isTome, job, ring)
|
||||
case "weapon" => Weapon(pieceType, job)
|
||||
case "head" => Head(pieceType, job)
|
||||
case "body" => Body(pieceType, job)
|
||||
case "hands" => Hands(pieceType, job)
|
||||
case "waist" => Waist(pieceType, job)
|
||||
case "legs" => Legs(pieceType, job)
|
||||
case "feet" => Feet(pieceType, job)
|
||||
case "ears" => Ears(pieceType, job)
|
||||
case "neck" => Neck(pieceType, job)
|
||||
case "wrist" => Wrist(pieceType, job)
|
||||
case ring @ ("ring" | "left ring" | "right ring") => Ring(pieceType, job, ring)
|
||||
case "accessory upgrade" => AccessoryUpgrade
|
||||
case "body upgrade" => BodyUpgrade
|
||||
case "weapon upgrade" => WeaponUpgrade
|
||||
|
18
src/main/scala/me/arcanis/ffxivbis/models/PieceType.scala
Normal file
18
src/main/scala/me/arcanis/ffxivbis/models/PieceType.scala
Normal file
@ -0,0 +1,18 @@
|
||||
package me.arcanis.ffxivbis.models
|
||||
|
||||
object PieceType {
|
||||
sealed trait PieceType
|
||||
|
||||
case object Crafted extends PieceType
|
||||
case object Tome extends PieceType
|
||||
case object Savage extends PieceType
|
||||
|
||||
lazy val available: Seq[PieceType] =
|
||||
Seq(Crafted, Tome, Savage)
|
||||
|
||||
def withName(pieceType: String): PieceType =
|
||||
available.find(_.toString.equalsIgnoreCase(pieceType)) match {
|
||||
case Some(value) => value
|
||||
case _ => throw new IllegalArgumentException(s"Invalid or unknown piece type $pieceType")
|
||||
}
|
||||
}
|
@ -46,7 +46,7 @@ case class Player(id: Long,
|
||||
}
|
||||
}
|
||||
|
||||
def bisCountTotal(piece: Option[Piece]): Int = bis.pieces.count(!_.isTome)
|
||||
def bisCountTotal(piece: Option[Piece]): Int = bis.pieces.count(_.pieceType == PieceType.Savage)
|
||||
def lootCount(piece: Option[Piece]): Int = piece match {
|
||||
case Some(p) => loot.count(_.piece == p)
|
||||
case None => lootCountTotal(piece)
|
||||
|
@ -18,7 +18,7 @@ import akka.stream.ActorMaterializer
|
||||
import akka.stream.scaladsl.{Keep, Sink}
|
||||
import akka.util.ByteString
|
||||
import com.typesafe.scalalogging.StrictLogging
|
||||
import me.arcanis.ffxivbis.models.{BiS, Job, Piece}
|
||||
import me.arcanis.ffxivbis.models.{BiS, Job, Piece, PieceType}
|
||||
import spray.json._
|
||||
|
||||
import scala.concurrent.{ExecutionContext, Future}
|
||||
@ -54,10 +54,10 @@ class Ariyala extends Actor with StrictLogging {
|
||||
.withPath(Uri.Path / "store.app")
|
||||
.withQuery(Uri.Query(Map("identifier" -> id)))
|
||||
|
||||
sendRequest(uri, Ariyala.parseAriyalaJsonToPieces(job, getIsTome))
|
||||
sendRequest(uri, Ariyala.parseAriyalaJsonToPieces(job, getPieceType))
|
||||
}
|
||||
|
||||
private def getIsTome(itemIds: Seq[Long]): Future[Map[Long, Boolean]] = {
|
||||
private def getPieceType(itemIds: Seq[Long]): Future[Map[Long, PieceType.PieceType]] = {
|
||||
val uriForItems = Uri(xivapiUrl)
|
||||
.withPath(Uri.Path / "item")
|
||||
.withQuery(Uri.Query(Map(
|
||||
@ -77,7 +77,7 @@ class Ariyala extends Actor with StrictLogging {
|
||||
"private_key" -> xivapiKey.getOrElse("")
|
||||
)))
|
||||
|
||||
sendRequest(uriForShops, Ariyala.parseXivapiJsonToTome(shops))
|
||||
sendRequest(uriForShops, Ariyala.parseXivapiJsonToType(shops))
|
||||
}
|
||||
}
|
||||
|
||||
@ -120,28 +120,34 @@ object Ariyala {
|
||||
}
|
||||
}
|
||||
|
||||
private def parseAriyalaJsonToPieces(job: Job.Job, isTome: Seq[Long] => Future[Map[Long, Boolean]])(js: JsObject)
|
||||
private def parseAriyalaJsonToPieces(job: Job.Job, pieceTypes: Seq[Long] => Future[Map[Long, PieceType.PieceType]])
|
||||
(js: JsObject)
|
||||
(implicit executionContext: ExecutionContext): Future[Seq[Piece]] =
|
||||
parseAriyalaJson(job)(js).flatMap { pieces =>
|
||||
isTome(pieces.values.toSeq).map { tomePieces =>
|
||||
pieces.view.mapValues(tomePieces).map {
|
||||
case (piece, isTomePiece) => Piece(piece, isTomePiece, job)
|
||||
pieceTypes(pieces.values.toSeq).map { types =>
|
||||
pieces.view.mapValues(types).map {
|
||||
case (piece, pieceType) => Piece(piece, pieceType, job)
|
||||
}.toSeq
|
||||
}
|
||||
}
|
||||
|
||||
private def parseXivapiJsonToShop(js: JsObject)
|
||||
(implicit executionContext: ExecutionContext): Future[Map[Long, (String, Long)]] = {
|
||||
def extractTraderId(js: JsObject) =
|
||||
js.fields("SpecialShop").asJsObject
|
||||
.fields.collectFirst {
|
||||
case (shopName, JsArray(array)) if shopName.startsWith("ItemReceive") =>
|
||||
val shopId = array.head match {
|
||||
case JsNumber(id) => id.toLong
|
||||
case other => throw deserializationError(s"Could not parse $other")
|
||||
def extractTraderId(js: JsObject) = {
|
||||
js.fields
|
||||
.get("Recipe").map(_ => "crafted" -> -1L) // you can craft this item
|
||||
.orElse { // lets try shop items
|
||||
js.fields("SpecialShop").asJsObject
|
||||
.fields.collectFirst {
|
||||
case (shopName, JsArray(array)) if shopName.startsWith("ItemReceive") =>
|
||||
val shopId = array.head match {
|
||||
case JsNumber(id) => id.toLong
|
||||
case other => throw deserializationError(s"Could not parse $other")
|
||||
}
|
||||
shopName.replace("ItemReceive", "") -> shopId
|
||||
}
|
||||
(shopName.replace("ItemReceive", ""), shopId)
|
||||
}.getOrElse(throw deserializationError(s"Could not parse $js"))
|
||||
}.getOrElse(throw deserializationError(s"Could not parse $js"))
|
||||
}
|
||||
|
||||
Future {
|
||||
js.fields("Results") match {
|
||||
@ -155,8 +161,8 @@ object Ariyala {
|
||||
}
|
||||
}
|
||||
|
||||
private def parseXivapiJsonToTome(shops: Map[Long, (String, Long)])(js: JsObject)
|
||||
(implicit executionContext: ExecutionContext): Future[Map[Long, Boolean]] =
|
||||
private def parseXivapiJsonToType(shops: Map[Long, (String, Long)])(js: JsObject)
|
||||
(implicit executionContext: ExecutionContext): Future[Map[Long, PieceType.PieceType]] =
|
||||
Future {
|
||||
val shopMap = js.fields("Results") match {
|
||||
case array: JsArray =>
|
||||
@ -170,14 +176,20 @@ object Ariyala {
|
||||
}
|
||||
|
||||
shops.map { case (itemId, (index, shopId)) =>
|
||||
val isTome = Try(shopMap(shopId).fields(s"ItemCost$index").asJsObject).toOption.getOrElse(throw new Exception(s"${shopMap(shopId).fields(s"ItemCost$index")}, $index"))
|
||||
.getFields("IsUnique", "StackSize") match {
|
||||
case Seq(JsNumber(isUnique), JsNumber(stackSize)) =>
|
||||
// either upgraded gear or tomes found
|
||||
isUnique == 1 || stackSize.toLong == 2000
|
||||
case other => throw deserializationError(s"Could not parse $other")
|
||||
}
|
||||
itemId -> isTome
|
||||
val pieceType =
|
||||
if (index == "crafted" && shopId == -1) PieceType.Crafted
|
||||
else {
|
||||
Try(shopMap(shopId).fields(s"ItemCost$index").asJsObject)
|
||||
.toOption
|
||||
.getOrElse(throw new Exception(s"${shopMap(shopId).fields(s"ItemCost$index")}, $index"))
|
||||
.getFields("IsUnique", "StackSize") match {
|
||||
case Seq(JsNumber(isUnique), JsNumber(stackSize)) =>
|
||||
if (isUnique == 1 || stackSize.toLong == 2000) PieceType.Tome // either upgraded gear or tomes found
|
||||
else PieceType.Savage
|
||||
case other => throw deserializationError(s"Could not parse $other")
|
||||
}
|
||||
}
|
||||
itemId -> pieceType
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -10,7 +10,7 @@ package me.arcanis.ffxivbis.storage
|
||||
|
||||
import java.time.Instant
|
||||
|
||||
import me.arcanis.ffxivbis.models.{Job, Loot, Piece}
|
||||
import me.arcanis.ffxivbis.models.{Job, Loot, Piece, PieceType}
|
||||
import slick.lifted.ForeignKeyQuery
|
||||
|
||||
import scala.concurrent.Future
|
||||
@ -18,24 +18,27 @@ import scala.concurrent.Future
|
||||
trait BiSProfile { this: DatabaseProfile =>
|
||||
import dbConfig.profile.api._
|
||||
|
||||
case class BiSRep(playerId: Long, created: Long, piece: String, isTome: Int, job: String) {
|
||||
def toLoot: Loot = Loot(playerId, Piece(piece, isTome == 1, Job.withName(job)), Instant.ofEpochMilli(created))
|
||||
case class BiSRep(playerId: Long, created: Long, piece: String,
|
||||
pieceType: String, job: String) {
|
||||
def toLoot: Loot = Loot(
|
||||
playerId, Piece(piece, PieceType.withName(pieceType), Job.withName(job)),
|
||||
Instant.ofEpochMilli(created))
|
||||
}
|
||||
object BiSRep {
|
||||
def fromPiece(playerId: Long, piece: Piece) =
|
||||
BiSRep(playerId, DatabaseProfile.now, piece.piece, if (piece.isTome) 1 else 0,
|
||||
piece.job.toString)
|
||||
def fromPiece(playerId: Long, piece: Piece): BiSRep =
|
||||
BiSRep(playerId, DatabaseProfile.now, piece.piece,
|
||||
piece.pieceType.toString, piece.job.toString)
|
||||
}
|
||||
|
||||
class BiSPieces(tag: Tag) extends Table[BiSRep](tag, "bis") {
|
||||
def playerId: Rep[Long] = column[Long]("player_id", O.PrimaryKey)
|
||||
def created: Rep[Long] = column[Long]("created")
|
||||
def piece: Rep[String] = column[String]("piece", O.PrimaryKey)
|
||||
def isTome: Rep[Int] = column[Int]("is_tome")
|
||||
def pieceType: Rep[String] = column[String]("piece_type")
|
||||
def job: Rep[String] = column[String]("job")
|
||||
|
||||
def * =
|
||||
(playerId, created, piece, isTome, job) <> ((BiSRep.apply _).tupled, BiSRep.unapply)
|
||||
(playerId, created, piece, pieceType, job) <> ((BiSRep.apply _).tupled, BiSRep.unapply)
|
||||
|
||||
def fkPlayerId: ForeignKeyQuery[Players, PlayerRep] =
|
||||
foreignKey("player_id", playerId, playersTable)(_.playerId, onDelete = ForeignKeyAction.Cascade)
|
||||
|
@ -10,7 +10,7 @@ package me.arcanis.ffxivbis.storage
|
||||
|
||||
import java.time.Instant
|
||||
|
||||
import me.arcanis.ffxivbis.models.{Job, Loot, Piece}
|
||||
import me.arcanis.ffxivbis.models.{Job, Loot, Piece, PieceType}
|
||||
import slick.lifted.{ForeignKeyQuery, Index}
|
||||
|
||||
import scala.concurrent.Future
|
||||
@ -18,14 +18,17 @@ import scala.concurrent.Future
|
||||
trait LootProfile { this: DatabaseProfile =>
|
||||
import dbConfig.profile.api._
|
||||
|
||||
case class LootRep(lootId: Option[Long], playerId: Long, created: Long, piece: String,
|
||||
isTome: Int, job: String) {
|
||||
def toLoot: Loot = Loot(playerId, Piece(piece, isTome == 1, Job.withName(job)), Instant.ofEpochMilli(created))
|
||||
case class LootRep(lootId: Option[Long], playerId: Long, created: Long,
|
||||
piece: String, pieceType: String, job: String) {
|
||||
def toLoot: Loot = Loot(
|
||||
playerId,
|
||||
Piece(piece, PieceType.withName(pieceType), Job.withName(job)),
|
||||
Instant.ofEpochMilli(created))
|
||||
}
|
||||
object LootRep {
|
||||
def fromPiece(playerId: Long, piece: Piece) =
|
||||
LootRep(None, playerId, DatabaseProfile.now, piece.piece, if (piece.isTome) 1 else 0,
|
||||
piece.job.toString)
|
||||
def fromPiece(playerId: Long, piece: Piece): LootRep =
|
||||
LootRep(None, playerId, DatabaseProfile.now, piece.piece,
|
||||
piece.pieceType.toString, piece.job.toString)
|
||||
}
|
||||
|
||||
class LootPieces(tag: Tag) extends Table[LootRep](tag, "loot") {
|
||||
@ -33,11 +36,11 @@ trait LootProfile { this: DatabaseProfile =>
|
||||
def playerId: Rep[Long] = column[Long]("player_id")
|
||||
def created: Rep[Long] = column[Long]("created")
|
||||
def piece: Rep[String] = column[String]("piece")
|
||||
def isTome: Rep[Int] = column[Int]("is_tome")
|
||||
def pieceType: Rep[String] = column[String]("piece_type")
|
||||
def job: Rep[String] = column[String]("job")
|
||||
|
||||
def * =
|
||||
(lootId.?, playerId, created, piece, isTome, job) <> ((LootRep.apply _).tupled, LootRep.unapply)
|
||||
(lootId.?, playerId, created, piece, pieceType, job) <> ((LootRep.apply _).tupled, LootRep.unapply)
|
||||
|
||||
def fkPlayerId: ForeignKeyQuery[Players, PlayerRep] =
|
||||
foreignKey("player_id", playerId, playersTable)(_.playerId, onDelete = ForeignKeyAction.Cascade)
|
||||
|
@ -15,7 +15,8 @@ import scala.concurrent.Future
|
||||
trait PartyProfile { this: DatabaseProfile =>
|
||||
import dbConfig.profile.api._
|
||||
|
||||
case class PartyRep(partyId: Option[Long], partyName: String, partyAlias: Option[String]) {
|
||||
case class PartyRep(partyId: Option[Long], partyName: String,
|
||||
partyAlias: Option[String]) {
|
||||
def toDescription: PartyDescription = PartyDescription(partyName, partyAlias)
|
||||
}
|
||||
object PartyRep {
|
||||
|
@ -15,10 +15,11 @@ import scala.concurrent.Future
|
||||
trait PlayersProfile { this: DatabaseProfile =>
|
||||
import dbConfig.profile.api._
|
||||
|
||||
case class PlayerRep(partyId: String, playerId: Option[Long], created: Long, nick: String,
|
||||
job: String, link: Option[String], priority: Int) {
|
||||
case class PlayerRep(partyId: String, playerId: Option[Long], created: Long,
|
||||
nick: String, job: String, link: Option[String], priority: Int) {
|
||||
def toPlayer: Player =
|
||||
Player(playerId.getOrElse(-1), partyId, Job.withName(job), nick, BiS(Seq.empty), List.empty, link, priority)
|
||||
Player(playerId.getOrElse(-1), partyId, Job.withName(job), nick,
|
||||
BiS(Seq.empty), List.empty, link, priority)
|
||||
}
|
||||
object PlayerRep {
|
||||
def fromPlayer(player: Player, id: Option[Long]): PlayerRep =
|
||||
|
@ -16,8 +16,8 @@ import scala.concurrent.Future
|
||||
trait UsersProfile { this: DatabaseProfile =>
|
||||
import dbConfig.profile.api._
|
||||
|
||||
case class UserRep(partyId: String, userId: Option[Long], username: String, password: String,
|
||||
permission: String) {
|
||||
case class UserRep(partyId: String, userId: Option[Long], username: String,
|
||||
password: String, permission: String) {
|
||||
def toUser: User = User(partyId, username, password, Permission.withName(permission))
|
||||
}
|
||||
object UserRep {
|
||||
|
@ -5,33 +5,33 @@ import me.arcanis.ffxivbis.models._
|
||||
object Fixtures {
|
||||
lazy val bis: BiS = BiS(
|
||||
Seq(
|
||||
Weapon(isTome = false ,Job.DNC),
|
||||
Head(isTome = false, Job.DNC),
|
||||
Body(isTome = false, Job.DNC),
|
||||
Hands(isTome = true, Job.DNC),
|
||||
Waist(isTome = true, Job.DNC),
|
||||
Legs(isTome = true, Job.DNC),
|
||||
Feet(isTome = false, Job.DNC),
|
||||
Ears(isTome = false, Job.DNC),
|
||||
Neck(isTome = true, Job.DNC),
|
||||
Wrist(isTome = false, Job.DNC),
|
||||
Ring(isTome = true, Job.DNC, "left ring"),
|
||||
Ring(isTome = true, Job.DNC, "right ring")
|
||||
Weapon(pieceType = PieceType.Savage ,Job.DNC),
|
||||
Head(pieceType = PieceType.Savage, Job.DNC),
|
||||
Body(pieceType = PieceType.Savage, Job.DNC),
|
||||
Hands(pieceType = PieceType.Tome, Job.DNC),
|
||||
Waist(pieceType = PieceType.Tome, Job.DNC),
|
||||
Legs(pieceType = PieceType.Tome, Job.DNC),
|
||||
Feet(pieceType = PieceType.Savage, Job.DNC),
|
||||
Ears(pieceType = PieceType.Savage, Job.DNC),
|
||||
Neck(pieceType = PieceType.Tome, Job.DNC),
|
||||
Wrist(pieceType = PieceType.Savage, Job.DNC),
|
||||
Ring(pieceType = PieceType.Tome, Job.DNC, "left ring"),
|
||||
Ring(pieceType = PieceType.Tome, Job.DNC, "right ring")
|
||||
)
|
||||
)
|
||||
|
||||
lazy val link: String = "https://ffxiv.ariyala.com/19V5R"
|
||||
lazy val link2: String = "https://ffxiv.ariyala.com/1A0WM"
|
||||
|
||||
lazy val lootWeapon: Piece = Weapon(isTome = true, Job.AnyJob)
|
||||
lazy val lootBody: Piece = Body(isTome = false, Job.AnyJob)
|
||||
lazy val lootHands: Piece = Hands(isTome = true, Job.AnyJob)
|
||||
lazy val lootWaist: Piece = Waist(isTome = true, Job.AnyJob)
|
||||
lazy val lootLegs: Piece = Legs(isTome = false, Job.AnyJob)
|
||||
lazy val lootEars: Piece = Ears(isTome = false, Job.AnyJob)
|
||||
lazy val lootRing: Piece = Ring(isTome = true, Job.AnyJob)
|
||||
lazy val lootLeftRing: Piece = Ring(isTome = true, Job.AnyJob, "left ring")
|
||||
lazy val lootRightRing: Piece = Ring(isTome = true, Job.AnyJob, "right ring")
|
||||
lazy val lootWeapon: Piece = Weapon(pieceType = PieceType.Tome, Job.AnyJob)
|
||||
lazy val lootBody: Piece = Body(pieceType = PieceType.Savage, Job.AnyJob)
|
||||
lazy val lootHands: Piece = Hands(pieceType = PieceType.Tome, Job.AnyJob)
|
||||
lazy val lootWaist: Piece = Waist(pieceType = PieceType.Tome, Job.AnyJob)
|
||||
lazy val lootLegs: Piece = Legs(pieceType = PieceType.Savage, Job.AnyJob)
|
||||
lazy val lootEars: Piece = Ears(pieceType = PieceType.Savage, Job.AnyJob)
|
||||
lazy val lootRing: Piece = Ring(pieceType = PieceType.Tome, Job.AnyJob)
|
||||
lazy val lootLeftRing: Piece = Ring(pieceType = PieceType.Tome, Job.AnyJob, "left ring")
|
||||
lazy val lootRightRing: Piece = Ring(pieceType = PieceType.Tome, Job.AnyJob, "right ring")
|
||||
lazy val lootUpgrade: Piece = BodyUpgrade
|
||||
lazy val loot: Seq[Piece] = Seq(lootBody, lootHands, lootLegs, lootUpgrade)
|
||||
|
||||
|
@ -6,7 +6,7 @@ import akka.http.scaladsl.server._
|
||||
import com.typesafe.config.Config
|
||||
import me.arcanis.ffxivbis.Settings
|
||||
import me.arcanis.ffxivbis.http.api.v1.json._
|
||||
import me.arcanis.ffxivbis.models.{Job, Party, Permission, Piece}
|
||||
import me.arcanis.ffxivbis.models.{Job, Party, Permission, Piece, PieceType}
|
||||
import org.scalatest.{Matchers, WordSpec}
|
||||
|
||||
import scala.language.postfixOps
|
||||
@ -41,6 +41,13 @@ class TypesEndpointTest extends WordSpec
|
||||
}
|
||||
}
|
||||
|
||||
"return all available piece types" in {
|
||||
Get("/types/pieces/types") ~> route ~> check {
|
||||
status shouldEqual StatusCodes.OK
|
||||
responseAs[Seq[String]] shouldEqual PieceType.available.map(_.toString)
|
||||
}
|
||||
}
|
||||
|
||||
"return current priority" in {
|
||||
Get("/types/priority") ~> route ~> check {
|
||||
status shouldEqual StatusCodes.OK
|
||||
|
@ -7,11 +7,6 @@ class PieceTest extends WordSpecLike with Matchers with BeforeAndAfterAll {
|
||||
|
||||
"piece model" must {
|
||||
|
||||
"convert `isTome` property to string" in {
|
||||
Fixtures.lootBody.isTomeToString shouldEqual "no"
|
||||
Fixtures.lootHands.isTomeToString shouldEqual "yes"
|
||||
}
|
||||
|
||||
"return upgrade" in {
|
||||
Fixtures.lootWeapon.upgrade shouldEqual Some(WeaponUpgrade)
|
||||
Fixtures.lootBody.upgrade shouldEqual None
|
||||
@ -25,7 +20,7 @@ class PieceTest extends WordSpecLike with Matchers with BeforeAndAfterAll {
|
||||
|
||||
"build piece from string" in {
|
||||
Fixtures.bis.pieces.foreach { piece =>
|
||||
Piece(piece.piece, piece.isTome, piece.job) shouldEqual piece
|
||||
Piece(piece.piece, piece.pieceType, piece.job) shouldEqual piece
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,20 @@
|
||||
package me.arcanis.ffxivbis.models
|
||||
|
||||
import org.scalatest.{BeforeAndAfterAll, Matchers, WordSpecLike}
|
||||
|
||||
class PieceTypeTest extends WordSpecLike with Matchers with BeforeAndAfterAll {
|
||||
|
||||
"piece type model" must {
|
||||
|
||||
"create piece type from string" in {
|
||||
PieceType.available.foreach { pieceType =>
|
||||
PieceType.withName(pieceType.toString) shouldEqual pieceType
|
||||
}
|
||||
}
|
||||
|
||||
"fail on unknown piece type" in {
|
||||
an [IllegalArgumentException] should be thrownBy PieceType.withName("random string")
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@ -65,7 +65,7 @@ class DatabaseBiSHandlerTest
|
||||
}
|
||||
|
||||
"update piece in bis set" in {
|
||||
val newPiece = Hands(isTome = false, Job.DNC)
|
||||
val newPiece = Hands(pieceType = PieceType.Savage, Job.DNC)
|
||||
|
||||
database ! impl.DatabaseBiSHandler.AddPieceToBis(Fixtures.playerEmpty.playerId, newPiece)
|
||||
expectMsg(timeout, 1)
|
||||
|
@ -37,11 +37,11 @@ class LootSelectorTest extends TestKit(ActorSystem("lootselector"))
|
||||
"loot selector" must {
|
||||
|
||||
"suggest loot by isRequired" in {
|
||||
toPlayerId(default.suggestLoot(Head(isTome = false, Job.AnyJob))) shouldEqual Seq(dnc.playerId, drg.playerId)
|
||||
toPlayerId(default.suggestLoot(Head(pieceType = PieceType.Savage, Job.AnyJob))) shouldEqual Seq(dnc.playerId, drg.playerId)
|
||||
}
|
||||
|
||||
"suggest loot if a player already have it" in {
|
||||
val piece = Body(isTome = false, Job.AnyJob)
|
||||
val piece = Body(pieceType = PieceType.Savage, Job.AnyJob)
|
||||
val party = default.withPlayer(dnc.withLoot(piece))
|
||||
|
||||
toPlayerId(party.suggestLoot(piece)) shouldEqual Seq(drg.playerId, dnc.playerId)
|
||||
@ -50,7 +50,7 @@ class LootSelectorTest extends TestKit(ActorSystem("lootselector"))
|
||||
"suggest upgrade" in {
|
||||
val party = default.withPlayer(
|
||||
dnc.withBiS(
|
||||
Some(dnc.bis.copy(weapon = Some(Weapon(isTome = true, Job.DNC))))
|
||||
Some(dnc.bis.copy(weapon = Some(Weapon(pieceType = PieceType.Tome, Job.DNC))))
|
||||
)
|
||||
)
|
||||
|
||||
@ -60,24 +60,24 @@ class LootSelectorTest extends TestKit(ActorSystem("lootselector"))
|
||||
"suggest loot by priority" in {
|
||||
val party = default.withPlayer(dnc.copy(priority = 2))
|
||||
|
||||
toPlayerId(party.suggestLoot(Body(isTome = false, Job.AnyJob))) shouldEqual Seq(drg.playerId, dnc.playerId)
|
||||
toPlayerId(party.suggestLoot(Body(pieceType = PieceType.Savage, Job.AnyJob))) shouldEqual Seq(drg.playerId, dnc.playerId)
|
||||
}
|
||||
|
||||
"suggest loot by bis pieces got" in {
|
||||
val party = default.withPlayer(dnc.withLoot(Head(isTome = false, Job.AnyJob)))
|
||||
val party = default.withPlayer(dnc.withLoot(Head(pieceType = PieceType.Savage, Job.AnyJob)))
|
||||
|
||||
toPlayerId(party.suggestLoot(Body(isTome = false, Job.AnyJob))) shouldEqual Seq(drg.playerId, dnc.playerId)
|
||||
toPlayerId(party.suggestLoot(Body(pieceType = PieceType.Savage, Job.AnyJob))) shouldEqual Seq(drg.playerId, dnc.playerId)
|
||||
}
|
||||
|
||||
"suggest loot by this piece got" in {
|
||||
val piece = Body(isTome = true, Job.AnyJob)
|
||||
val piece = Body(pieceType = PieceType.Tome, Job.AnyJob)
|
||||
val party = default.withPlayer(dnc.withLoot(piece))
|
||||
|
||||
toPlayerId(party.suggestLoot(piece)) shouldEqual Seq(drg.playerId, dnc.playerId)
|
||||
}
|
||||
|
||||
"suggest loot by total piece got" in {
|
||||
val piece = Body(isTome = true, Job.AnyJob)
|
||||
val piece = Body(pieceType = PieceType.Tome, Job.AnyJob)
|
||||
val party = default
|
||||
.withPlayer(dnc.withLoot(Seq(piece, piece).map(pieceToLoot)))
|
||||
.withPlayer(drg.withLoot(piece))
|
||||
|
Loading…
Reference in New Issue
Block a user