diff --git a/src/main/resources/db/migration/postgresql/V4_0__Crafted_items.sql b/src/main/resources/db/migration/postgresql/V4_0__Crafted_items.sql new file mode 100644 index 0000000..afaa69b --- /dev/null +++ b/src/main/resources/db/migration/postgresql/V4_0__Crafted_items.sql @@ -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; \ No newline at end of file diff --git a/src/main/resources/db/migration/sqlite/V4_0__Crafted_items.sql b/src/main/resources/db/migration/sqlite/V4_0__Crafted_items.sql new file mode 100644 index 0000000..86ced41 --- /dev/null +++ b/src/main/resources/db/migration/sqlite/V4_0__Crafted_items.sql @@ -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); \ No newline at end of file diff --git a/src/main/scala/me/arcanis/ffxivbis/http/api/v1/TypesEndpoint.scala b/src/main/scala/me/arcanis/ffxivbis/http/api/v1/TypesEndpoint.scala index f3c97ec..2cea2c6 100644 --- a/src/main/scala/me/arcanis/ffxivbis/http/api/v1/TypesEndpoint.scala +++ b/src/main/scala/me/arcanis/ffxivbis/http/api/v1/TypesEndpoint.scala @@ -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")) diff --git a/src/main/scala/me/arcanis/ffxivbis/http/api/v1/json/PieceResponse.scala b/src/main/scala/me/arcanis/ffxivbis/http/api/v1/json/PieceResponse.scala index 65ebfe5..e2aefb6 100644 --- a/src/main/scala/me/arcanis/ffxivbis/http/api/v1/json/PieceResponse.scala +++ b/src/main/scala/me/arcanis/ffxivbis/http/api/v1/json/PieceResponse.scala @@ -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) } diff --git a/src/main/scala/me/arcanis/ffxivbis/http/view/BiSView.scala b/src/main/scala/me/arcanis/ffxivbis/http/view/BiSView.scala index 12610f8..501580b 100644 --- a/src/main/scala/me/arcanis/ffxivbis/http/view/BiSView.scala +++ b/src/main/scala/me/arcanis/ffxivbis/http/view/BiSView.scala @@ -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") ) diff --git a/src/main/scala/me/arcanis/ffxivbis/http/view/LootSuggestView.scala b/src/main/scala/me/arcanis/ffxivbis/http/view/LootSuggestView.scala index 331ffa2..52962e6 100644 --- a/src/main/scala/me/arcanis/ffxivbis/http/view/LootSuggestView.scala +++ b/src/main/scala/me/arcanis/ffxivbis/http/view/LootSuggestView.scala @@ -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") ) diff --git a/src/main/scala/me/arcanis/ffxivbis/http/view/LootView.scala b/src/main/scala/me/arcanis/ffxivbis/http/view/LootView.scala index 0ed00a3..cbecb7c 100644 --- a/src/main/scala/me/arcanis/ffxivbis/http/view/LootView.scala +++ b/src/main/scala/me/arcanis/ffxivbis/http/view/LootView.scala @@ -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") ) diff --git a/src/main/scala/me/arcanis/ffxivbis/models/Job.scala b/src/main/scala/me/arcanis/ffxivbis/models/Job.scala index 3085d78..6135f1c 100644 --- a/src/main/scala/me/arcanis/ffxivbis/models/Job.scala +++ b/src/main/scala/me/arcanis/ffxivbis/models/Job.scala @@ -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") } } diff --git a/src/main/scala/me/arcanis/ffxivbis/models/Piece.scala b/src/main/scala/me/arcanis/ffxivbis/models/Piece.scala index 7de790e..9341e94 100644 --- a/src/main/scala/me/arcanis/ffxivbis/models/Piece.scala +++ b/src/main/scala/me/arcanis/ffxivbis/models/Piece.scala @@ -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 diff --git a/src/main/scala/me/arcanis/ffxivbis/models/PieceType.scala b/src/main/scala/me/arcanis/ffxivbis/models/PieceType.scala new file mode 100644 index 0000000..cc57618 --- /dev/null +++ b/src/main/scala/me/arcanis/ffxivbis/models/PieceType.scala @@ -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") + } +} diff --git a/src/main/scala/me/arcanis/ffxivbis/models/Player.scala b/src/main/scala/me/arcanis/ffxivbis/models/Player.scala index 862ba08..c31e916 100644 --- a/src/main/scala/me/arcanis/ffxivbis/models/Player.scala +++ b/src/main/scala/me/arcanis/ffxivbis/models/Player.scala @@ -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) diff --git a/src/main/scala/me/arcanis/ffxivbis/service/Ariyala.scala b/src/main/scala/me/arcanis/ffxivbis/service/Ariyala.scala index 1ef6b15..e69262e 100644 --- a/src/main/scala/me/arcanis/ffxivbis/service/Ariyala.scala +++ b/src/main/scala/me/arcanis/ffxivbis/service/Ariyala.scala @@ -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 } } diff --git a/src/main/scala/me/arcanis/ffxivbis/storage/BiSProfile.scala b/src/main/scala/me/arcanis/ffxivbis/storage/BiSProfile.scala index 71cbf06..06142b8 100644 --- a/src/main/scala/me/arcanis/ffxivbis/storage/BiSProfile.scala +++ b/src/main/scala/me/arcanis/ffxivbis/storage/BiSProfile.scala @@ -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) diff --git a/src/main/scala/me/arcanis/ffxivbis/storage/LootProfile.scala b/src/main/scala/me/arcanis/ffxivbis/storage/LootProfile.scala index 795a295..2f6f7fd 100644 --- a/src/main/scala/me/arcanis/ffxivbis/storage/LootProfile.scala +++ b/src/main/scala/me/arcanis/ffxivbis/storage/LootProfile.scala @@ -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) diff --git a/src/main/scala/me/arcanis/ffxivbis/storage/PartyProfile.scala b/src/main/scala/me/arcanis/ffxivbis/storage/PartyProfile.scala index 327fca5..59676b3 100644 --- a/src/main/scala/me/arcanis/ffxivbis/storage/PartyProfile.scala +++ b/src/main/scala/me/arcanis/ffxivbis/storage/PartyProfile.scala @@ -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 { diff --git a/src/main/scala/me/arcanis/ffxivbis/storage/PlayersProfile.scala b/src/main/scala/me/arcanis/ffxivbis/storage/PlayersProfile.scala index 8951d32..e04664b 100644 --- a/src/main/scala/me/arcanis/ffxivbis/storage/PlayersProfile.scala +++ b/src/main/scala/me/arcanis/ffxivbis/storage/PlayersProfile.scala @@ -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 = diff --git a/src/main/scala/me/arcanis/ffxivbis/storage/UsersProfile.scala b/src/main/scala/me/arcanis/ffxivbis/storage/UsersProfile.scala index e57c1c8..761b421 100644 --- a/src/main/scala/me/arcanis/ffxivbis/storage/UsersProfile.scala +++ b/src/main/scala/me/arcanis/ffxivbis/storage/UsersProfile.scala @@ -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 { diff --git a/src/test/scala/me/arcanis/ffxivbis/Fixtures.scala b/src/test/scala/me/arcanis/ffxivbis/Fixtures.scala index 27642ae..023195b 100644 --- a/src/test/scala/me/arcanis/ffxivbis/Fixtures.scala +++ b/src/test/scala/me/arcanis/ffxivbis/Fixtures.scala @@ -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) diff --git a/src/test/scala/me/arcanis/ffxivbis/http/api/v1/TypesEndpointTest.scala b/src/test/scala/me/arcanis/ffxivbis/http/api/v1/TypesEndpointTest.scala index 802ab0e..8af3ce1 100644 --- a/src/test/scala/me/arcanis/ffxivbis/http/api/v1/TypesEndpointTest.scala +++ b/src/test/scala/me/arcanis/ffxivbis/http/api/v1/TypesEndpointTest.scala @@ -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 diff --git a/src/test/scala/me/arcanis/ffxivbis/models/PieceTest.scala b/src/test/scala/me/arcanis/ffxivbis/models/PieceTest.scala index 7df02a9..70b4535 100644 --- a/src/test/scala/me/arcanis/ffxivbis/models/PieceTest.scala +++ b/src/test/scala/me/arcanis/ffxivbis/models/PieceTest.scala @@ -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 } } diff --git a/src/test/scala/me/arcanis/ffxivbis/models/PieceTypeTest.scala b/src/test/scala/me/arcanis/ffxivbis/models/PieceTypeTest.scala new file mode 100644 index 0000000..dc8efef --- /dev/null +++ b/src/test/scala/me/arcanis/ffxivbis/models/PieceTypeTest.scala @@ -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") + } + + } +} diff --git a/src/test/scala/me/arcanis/ffxivbis/service/DatabaseBiSHandlerTest.scala b/src/test/scala/me/arcanis/ffxivbis/service/DatabaseBiSHandlerTest.scala index 4204125..0c29e5e 100644 --- a/src/test/scala/me/arcanis/ffxivbis/service/DatabaseBiSHandlerTest.scala +++ b/src/test/scala/me/arcanis/ffxivbis/service/DatabaseBiSHandlerTest.scala @@ -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) diff --git a/src/test/scala/me/arcanis/ffxivbis/service/LootSelectorTest.scala b/src/test/scala/me/arcanis/ffxivbis/service/LootSelectorTest.scala index eb88bb4..22863d6 100644 --- a/src/test/scala/me/arcanis/ffxivbis/service/LootSelectorTest.scala +++ b/src/test/scala/me/arcanis/ffxivbis/service/LootSelectorTest.scala @@ -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))