mirror of
https://github.com/arcan1s/ffxivbis.git
synced 2025-07-07 10:55:53 +00:00
Compare commits
7 Commits
Author | SHA1 | Date | |
---|---|---|---|
bdf413d494 | |||
7a1a73592e | |||
b1ac894ccf | |||
6023e86570 | |||
a4ab1e49be | |||
cb99486f8a | |||
0e8b95d0dd |
2
.github/workflows/release.yml
vendored
2
.github/workflows/release.yml
vendored
@ -25,7 +25,7 @@ jobs:
|
|||||||
uses: actions/setup-java@v2
|
uses: actions/setup-java@v2
|
||||||
with:
|
with:
|
||||||
distribution: temurin
|
distribution: temurin
|
||||||
java-version: 17
|
java-version: 18
|
||||||
- name: create dist
|
- name: create dist
|
||||||
run: make dist
|
run: make dist
|
||||||
- name: release
|
- name: release
|
||||||
|
4
.github/workflows/run-tests.yml
vendored
4
.github/workflows/run-tests.yml
vendored
@ -17,6 +17,6 @@ jobs:
|
|||||||
uses: actions/setup-java@v2
|
uses: actions/setup-java@v2
|
||||||
with:
|
with:
|
||||||
distribution: temurin
|
distribution: temurin
|
||||||
java-version: 17
|
java-version: 18
|
||||||
- name: run tests
|
- name: run tests
|
||||||
run: make tests
|
run: make tests
|
||||||
|
3
TODO.md
3
TODO.md
@ -1,3 +0,0 @@
|
|||||||
* [x] items improvements
|
|
||||||
* [x] multiple parties support
|
|
||||||
* [ ] pretty UI
|
|
@ -2,7 +2,7 @@ organization := "me.arcanis"
|
|||||||
|
|
||||||
name := "ffxivbis"
|
name := "ffxivbis"
|
||||||
|
|
||||||
scalaVersion := "2.13.6"
|
scalaVersion := "2.13.8"
|
||||||
|
|
||||||
scalacOptions ++= Seq("-deprecation", "-feature")
|
scalacOptions ++= Seq("-deprecation", "-feature")
|
||||||
|
|
||||||
|
@ -1,26 +1,26 @@
|
|||||||
val AkkaVersion = "2.6.18"
|
val AkkaVersion = "2.6.20"
|
||||||
val AkkaHttpVersion = "10.2.7"
|
val AkkaHttpVersion = "10.2.10"
|
||||||
val ScalaTestVersion = "3.2.10"
|
val ScalaTestVersion = "3.2.12"
|
||||||
val SlickVersion = "3.3.3"
|
val SlickVersion = "3.3.3"
|
||||||
|
|
||||||
libraryDependencies += "ch.qos.logback" % "logback-classic" % "1.2.10"
|
libraryDependencies += "ch.qos.logback" % "logback-classic" % "1.2.11"
|
||||||
libraryDependencies += "com.typesafe.scala-logging" %% "scala-logging" % "3.9.4"
|
libraryDependencies += "com.typesafe.scala-logging" %% "scala-logging" % "3.9.5"
|
||||||
|
|
||||||
libraryDependencies += "com.typesafe.akka" %% "akka-http" % AkkaHttpVersion
|
libraryDependencies += "com.typesafe.akka" %% "akka-http" % AkkaHttpVersion
|
||||||
libraryDependencies += "com.typesafe.akka" %% "akka-http-spray-json" % AkkaHttpVersion
|
libraryDependencies += "com.typesafe.akka" %% "akka-http-spray-json" % AkkaHttpVersion
|
||||||
libraryDependencies += "com.typesafe.akka" %% "akka-actor-typed" % AkkaVersion
|
libraryDependencies += "com.typesafe.akka" %% "akka-actor-typed" % AkkaVersion
|
||||||
libraryDependencies += "com.typesafe.akka" %% "akka-stream" % AkkaVersion
|
libraryDependencies += "com.typesafe.akka" %% "akka-stream" % AkkaVersion
|
||||||
libraryDependencies += "com.github.swagger-akka-http" %% "swagger-akka-http" % "2.6.0"
|
libraryDependencies += "com.github.swagger-akka-http" %% "swagger-akka-http" % "2.8.0"
|
||||||
libraryDependencies += "jakarta.platform" % "jakarta.jakartaee-web-api" % "9.1.0"
|
libraryDependencies += "jakarta.platform" % "jakarta.jakartaee-web-api" % "9.1.0"
|
||||||
libraryDependencies += "ch.megard" %% "akka-http-cors" % "1.1.2"
|
libraryDependencies += "ch.megard" %% "akka-http-cors" % "1.1.3"
|
||||||
|
|
||||||
libraryDependencies += "io.spray" %% "spray-json" % "1.3.6"
|
libraryDependencies += "io.spray" %% "spray-json" % "1.3.6"
|
||||||
|
|
||||||
libraryDependencies += "org.playframework.anorm" %% "anorm" % "2.6.10"
|
libraryDependencies += "org.playframework.anorm" %% "anorm" % "2.6.10"
|
||||||
libraryDependencies += "com.zaxxer" % "HikariCP" % "5.0.1" exclude("org.slf4j", "slf4j-api")
|
libraryDependencies += "com.zaxxer" % "HikariCP" % "5.0.1" exclude("org.slf4j", "slf4j-api")
|
||||||
libraryDependencies += "org.flywaydb" % "flyway-core" % "8.4.1"
|
libraryDependencies += "org.flywaydb" % "flyway-core" % "9.2.2"
|
||||||
libraryDependencies += "org.xerial" % "sqlite-jdbc" % "3.36.0.3"
|
libraryDependencies += "org.xerial" % "sqlite-jdbc" % "3.39.2.1"
|
||||||
libraryDependencies += "org.postgresql" % "postgresql" % "42.3.1"
|
libraryDependencies += "org.postgresql" % "postgresql" % "42.5.0"
|
||||||
|
|
||||||
libraryDependencies += "org.mindrot" % "jbcrypt" % "0.4"
|
libraryDependencies += "org.mindrot" % "jbcrypt" % "0.4"
|
||||||
libraryDependencies += "com.google.guava" % "guava" % "31.0.1-jre"
|
libraryDependencies += "com.google.guava" % "guava" % "31.0.1-jre"
|
||||||
|
@ -1 +1 @@
|
|||||||
sbt.version = 1.5.8
|
sbt.version = 1.7.1
|
||||||
|
@ -0,0 +1,3 @@
|
|||||||
|
update parties set party_alias = regexp_replace(party_alias, '[^A-Za-z0-9!@#$%^&*()\-_=+;:'',./? ]', '', 'g');
|
||||||
|
update players set nick = regexp_replace(nick, '[^A-Za-z0-9!@#$%^&*()\-_=+;:'',./? ]', '', 'g');
|
||||||
|
update users set username = regexp_replace(username, '[^A-Za-z0-9!@#$%^&*()\-_=+;:'',./? ]', '', 'g');
|
@ -0,0 +1 @@
|
|||||||
|
update players set bis_link = null where bis_link = '';
|
@ -9,9 +9,9 @@
|
|||||||
<link rel="shortcut icon" href="/static/favicon.ico">
|
<link rel="shortcut icon" href="/static/favicon.ico">
|
||||||
|
|
||||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous" type="text/css">
|
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous" type="text/css">
|
||||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.7.2/font/bootstrap-icons.css" type="text/css">
|
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.8.3/font/bootstrap-icons.css" type="text/css">
|
||||||
|
|
||||||
<link rel="stylesheet" href="https://unpkg.com/bootstrap-table@1.19.1/dist/bootstrap-table.min.css" type="text/css">
|
<link rel="stylesheet" href="https://unpkg.com/bootstrap-table@1.20.2/dist/bootstrap-table.min.css" type="text/css">
|
||||||
|
|
||||||
|
|
||||||
<link rel="stylesheet" href="https://unpkg.com/jquery-resizable-columns@0.2.3/dist/jquery.resizableColumns.css" type="text/css">
|
<link rel="stylesheet" href="https://unpkg.com/jquery-resizable-columns@0.2.3/dist/jquery.resizableColumns.css" type="text/css">
|
||||||
@ -157,11 +157,11 @@
|
|||||||
<script src="https://unpkg.com/jquery-resizable-columns@0.2.3/dist/jquery.resizableColumns.min.js"></script>
|
<script src="https://unpkg.com/jquery-resizable-columns@0.2.3/dist/jquery.resizableColumns.min.js"></script>
|
||||||
|
|
||||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js" integrity="sha384-ka7Sk0Gln4gmtz2MlQnikT1wXgYsOg+OMhuP+IlRH9sENBO0LRn5q+8nbTov4+1p" crossorigin="anonymous"></script>
|
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js" integrity="sha384-ka7Sk0Gln4gmtz2MlQnikT1wXgYsOg+OMhuP+IlRH9sENBO0LRn5q+8nbTov4+1p" crossorigin="anonymous"></script>
|
||||||
<script src="https://unpkg.com/bootstrap-table@1.19.1/dist/bootstrap-table.min.js"></script>
|
<script src="https://unpkg.com/bootstrap-table@1.20.2/dist/bootstrap-table.min.js"></script>
|
||||||
|
|
||||||
<script src="https://unpkg.com/bootstrap-table@1.19.1/dist/extensions/export/bootstrap-table-export.min.js"></script>
|
<script src="https://unpkg.com/bootstrap-table@1.20.2/dist/extensions/export/bootstrap-table-export.min.js"></script>
|
||||||
|
|
||||||
<script src="https://unpkg.com/bootstrap-table@1.19.1/dist/extensions/resizable/bootstrap-table-resizable.js"></script>
|
<script src="https://unpkg.com/bootstrap-table@1.20.2/dist/extensions/resizable/bootstrap-table-resizable.js"></script>
|
||||||
|
|
||||||
<script src="/static/utils.js"></script>
|
<script src="/static/utils.js"></script>
|
||||||
<script src="/static/load.js"></script>
|
<script src="/static/load.js"></script>
|
||||||
@ -207,8 +207,8 @@
|
|||||||
}),
|
}),
|
||||||
type: "POST",
|
type: "POST",
|
||||||
contentType: "application/json",
|
contentType: "application/json",
|
||||||
success: function (_) { reload(); },
|
success: _ => { reload(); },
|
||||||
error: function (jqXHR, _, errorThrown) { requestAlert(jqXHR, errorThrown); },
|
error: (jqXHR, _, errorThrown) => { requestAlert(jqXHR, errorThrown); },
|
||||||
});
|
});
|
||||||
updateBisDialog.modal("hide");
|
updateBisDialog.modal("hide");
|
||||||
return true; // action expects boolean result
|
return true; // action expects boolean result
|
||||||
@ -247,9 +247,9 @@
|
|||||||
url: `/api/v1/party/${partyId}`,
|
url: `/api/v1/party/${partyId}`,
|
||||||
type: "GET",
|
type: "GET",
|
||||||
dataType: "json",
|
dataType: "json",
|
||||||
success: function (data) {
|
success: response => {
|
||||||
const items = data.map(function (player) {
|
const items = response.map(player => {
|
||||||
return player.bis.map(function (loot) {
|
return player.bis.map(loot => {
|
||||||
return {
|
return {
|
||||||
nick: player.nick,
|
nick: player.nick,
|
||||||
job: player.job,
|
job: player.job,
|
||||||
@ -258,12 +258,12 @@
|
|||||||
};
|
};
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
const payload = items.reduce(function (left, right) { return left.concat(right); }, []);
|
const payload = items.reduce((left, right) => { return left.concat(right); }, []);
|
||||||
table.bootstrapTable("load", payload);
|
table.bootstrapTable("load", payload);
|
||||||
table.bootstrapTable("uncheckAll");
|
table.bootstrapTable("uncheckAll");
|
||||||
table.bootstrapTable("hideLoading");
|
table.bootstrapTable("hideLoading");
|
||||||
|
|
||||||
const options = data.map(function (player) {
|
const options = response.map(player => {
|
||||||
const option = document.createElement("option");
|
const option = document.createElement("option");
|
||||||
option.innerText = formatPlayerId(player);
|
option.innerText = formatPlayerId(player);
|
||||||
option.dataset.nick = player.nick;
|
option.dataset.nick = player.nick;
|
||||||
@ -272,13 +272,13 @@
|
|||||||
});
|
});
|
||||||
playerInput.empty().append(options);
|
playerInput.empty().append(options);
|
||||||
},
|
},
|
||||||
error: function (jqXHR, _, errorThrown) { requestAlert(jqXHR, errorThrown); },
|
error: (jqXHR, _, errorThrown) => { requestAlert(jqXHR, errorThrown); },
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function removePiece() {
|
function removePiece() {
|
||||||
const pieces = table.bootstrapTable("getSelections");
|
const pieces = table.bootstrapTable("getSelections");
|
||||||
pieces.map(function (loot) {
|
pieces.map(loot => {
|
||||||
$.ajax({
|
$.ajax({
|
||||||
url: `/api/v1/party/${partyId}/bis`,
|
url: `/api/v1/party/${partyId}/bis`,
|
||||||
data: JSON.stringify({
|
data: JSON.stringify({
|
||||||
@ -296,8 +296,8 @@
|
|||||||
}),
|
}),
|
||||||
type: "POST",
|
type: "POST",
|
||||||
contentType: "application/json",
|
contentType: "application/json",
|
||||||
success: function (_) { reload(); },
|
success: _ => { reload(); },
|
||||||
error: function (jqXHR, _, errorThrown) { requestAlert(jqXHR, errorThrown); },
|
error: (jqXHR, _, errorThrown) => { requestAlert(jqXHR, errorThrown); },
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -325,8 +325,8 @@
|
|||||||
}),
|
}),
|
||||||
type: "PUT",
|
type: "PUT",
|
||||||
contentType: "application/json",
|
contentType: "application/json",
|
||||||
success: function (_) { reload(); },
|
success: _ => { reload(); },
|
||||||
error: function (jqXHR, _, errorThrown) { requestAlert(jqXHR, errorThrown); },
|
error: (jqXHR, _, errorThrown) => { requestAlert(jqXHR, errorThrown); },
|
||||||
});
|
});
|
||||||
updateBisDialog.modal("hide");
|
updateBisDialog.modal("hide");
|
||||||
return true; // action expects boolean result
|
return true; // action expects boolean result
|
||||||
@ -342,7 +342,7 @@
|
|||||||
return false; // should not happen
|
return false; // should not happen
|
||||||
}
|
}
|
||||||
|
|
||||||
$(function () {
|
$(() => {
|
||||||
setupFormClear(updateBisDialog, reset);
|
setupFormClear(updateBisDialog, reset);
|
||||||
setupRemoveButton(table, removeButton);
|
setupRemoveButton(table, removeButton);
|
||||||
|
|
||||||
@ -353,8 +353,8 @@
|
|||||||
|
|
||||||
hideControls();
|
hideControls();
|
||||||
|
|
||||||
updateBisButton.click(function () { reset(); });
|
updateBisButton.click(() => { reset(); });
|
||||||
addPieceButton.click(function () { reset(); });
|
addPieceButton.click(() => { reset(); });
|
||||||
|
|
||||||
table.bootstrapTable({});
|
table.bootstrapTable({});
|
||||||
reload();
|
reload();
|
||||||
|
@ -87,6 +87,7 @@
|
|||||||
|
|
||||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js" integrity="sha384-ka7Sk0Gln4gmtz2MlQnikT1wXgYsOg+OMhuP+IlRH9sENBO0LRn5q+8nbTov4+1p" crossorigin="anonymous"></script>
|
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js" integrity="sha384-ka7Sk0Gln4gmtz2MlQnikT1wXgYsOg+OMhuP+IlRH9sENBO0LRn5q+8nbTov4+1p" crossorigin="anonymous"></script>
|
||||||
|
|
||||||
|
<script src="/static/utils.js"></script>
|
||||||
<script src="/static/load.js"></script>
|
<script src="/static/load.js"></script>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
@ -9,9 +9,9 @@
|
|||||||
<link rel="shortcut icon" href="/static/favicon.ico">
|
<link rel="shortcut icon" href="/static/favicon.ico">
|
||||||
|
|
||||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous" type="text/css">
|
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous" type="text/css">
|
||||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.7.2/font/bootstrap-icons.css" type="text/css">
|
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.8.3/font/bootstrap-icons.css" type="text/css">
|
||||||
|
|
||||||
<link rel="stylesheet" href="https://unpkg.com/bootstrap-table@1.19.1/dist/bootstrap-table.min.css" type="text/css">
|
<link rel="stylesheet" href="https://unpkg.com/bootstrap-table@1.20.2/dist/bootstrap-table.min.css" type="text/css">
|
||||||
|
|
||||||
|
|
||||||
<link rel="stylesheet" href="https://unpkg.com/jquery-resizable-columns@0.2.3/dist/jquery.resizableColumns.css" type="text/css">
|
<link rel="stylesheet" href="https://unpkg.com/jquery-resizable-columns@0.2.3/dist/jquery.resizableColumns.css" type="text/css">
|
||||||
@ -88,7 +88,7 @@
|
|||||||
|
|
||||||
<div id="add-loot-dialog" tabindex="-1" role="dialog" class="modal fade">
|
<div id="add-loot-dialog" tabindex="-1" role="dialog" class="modal fade">
|
||||||
<div class="modal-dialog modal-lg" role="document">
|
<div class="modal-dialog modal-lg" role="document">
|
||||||
<form class="modal-content" action="javascript:" onsubmit="addLoot()">
|
<form class="modal-content" action="javascript:" onsubmit="addLootModal()">
|
||||||
<div class="modal-header">
|
<div class="modal-header">
|
||||||
<h4 class="modal-title">add looted piece</h4>
|
<h4 class="modal-title">add looted piece</h4>
|
||||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="close"></button>
|
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="close"></button>
|
||||||
@ -132,6 +132,7 @@
|
|||||||
<table id="stats" class="table table-striped table-hover">
|
<table id="stats" class="table table-striped table-hover">
|
||||||
<thead class="table-primary">
|
<thead class="table-primary">
|
||||||
<tr>
|
<tr>
|
||||||
|
<th data-formatter="addLootFormatter"></th>
|
||||||
<th data-field="nick">nick</th>
|
<th data-field="nick">nick</th>
|
||||||
<th data-field="job">job</th>
|
<th data-field="job">job</th>
|
||||||
<th data-field="isRequired">required</th>
|
<th data-field="isRequired">required</th>
|
||||||
@ -174,11 +175,11 @@
|
|||||||
<script src="https://unpkg.com/jquery-resizable-columns@0.2.3/dist/jquery.resizableColumns.min.js"></script>
|
<script src="https://unpkg.com/jquery-resizable-columns@0.2.3/dist/jquery.resizableColumns.min.js"></script>
|
||||||
|
|
||||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js" integrity="sha384-ka7Sk0Gln4gmtz2MlQnikT1wXgYsOg+OMhuP+IlRH9sENBO0LRn5q+8nbTov4+1p" crossorigin="anonymous"></script>
|
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js" integrity="sha384-ka7Sk0Gln4gmtz2MlQnikT1wXgYsOg+OMhuP+IlRH9sENBO0LRn5q+8nbTov4+1p" crossorigin="anonymous"></script>
|
||||||
<script src="https://unpkg.com/bootstrap-table@1.19.1/dist/bootstrap-table.min.js"></script>
|
<script src="https://unpkg.com/bootstrap-table@1.20.2/dist/bootstrap-table.min.js"></script>
|
||||||
|
|
||||||
<script src="https://unpkg.com/bootstrap-table@1.19.1/dist/extensions/export/bootstrap-table-export.min.js"></script>
|
<script src="https://unpkg.com/bootstrap-table@1.20.2/dist/extensions/export/bootstrap-table-export.min.js"></script>
|
||||||
|
|
||||||
<script src="https://unpkg.com/bootstrap-table@1.19.1/dist/extensions/resizable/bootstrap-table-resizable.js"></script>
|
<script src="https://unpkg.com/bootstrap-table@1.20.2/dist/extensions/resizable/bootstrap-table-resizable.js"></script>
|
||||||
|
|
||||||
<script src="/static/utils.js"></script>
|
<script src="/static/utils.js"></script>
|
||||||
<script src="/static/load.js"></script>
|
<script src="/static/load.js"></script>
|
||||||
@ -198,30 +199,40 @@
|
|||||||
const pieceTypeInput = $("#piece-type");
|
const pieceTypeInput = $("#piece-type");
|
||||||
const playerInput = $("#player");
|
const playerInput = $("#player");
|
||||||
|
|
||||||
function addLoot() {
|
function addLoot(nick, job) {
|
||||||
const player = getCurrentOption(playerInput);
|
|
||||||
$.ajax({
|
$.ajax({
|
||||||
url: `/api/v1/party/${partyId}/loot`,
|
url: `/api/v1/party/${partyId}/loot`,
|
||||||
data: JSON.stringify({
|
data: JSON.stringify({
|
||||||
action: "add",
|
action: "add",
|
||||||
piece: {
|
piece: {
|
||||||
pieceType: pieceTypeInput.val(),
|
pieceType: pieceTypeInput.val(),
|
||||||
job: player.dataset.job,
|
job: job,
|
||||||
piece: pieceInput.val(),
|
piece: pieceInput.val(),
|
||||||
},
|
},
|
||||||
playerId: {
|
playerId: {
|
||||||
partyId: partyId,
|
partyId: partyId,
|
||||||
nick: player.dataset.nick,
|
nick: nick,
|
||||||
job: player.dataset.job,
|
job: job,
|
||||||
},
|
},
|
||||||
isFreeLoot: freeLootInput.is(":checked"),
|
isFreeLoot: freeLootInput.is(":checked"),
|
||||||
}),
|
}),
|
||||||
type: "POST",
|
type: "POST",
|
||||||
contentType: "application/json",
|
contentType: "application/json",
|
||||||
success: function (_) { reload(); },
|
success: _ => {
|
||||||
error: function (jqXHR, _, errorThrown) { requestAlert(jqXHR, errorThrown); },
|
addLootDialog.modal("hide");
|
||||||
|
reload();
|
||||||
|
},
|
||||||
|
error: (jqXHR, _, errorThrown) => { requestAlert(jqXHR, errorThrown); },
|
||||||
});
|
});
|
||||||
addLootDialog.modal("hide");
|
}
|
||||||
|
|
||||||
|
function addLootFormatter(value, row, index) {
|
||||||
|
return `<button type="button" class="btn btn-primary" onclick="addLoot('${row.nick}', '${row.job}')"><i class="bi bi-plus"></i></button>`;
|
||||||
|
}
|
||||||
|
|
||||||
|
function addLootModal() {
|
||||||
|
const player = getCurrentOption(playerInput);
|
||||||
|
addLoot(player.dataset.nick, player.dataset.job);
|
||||||
return true; // action expects boolean result
|
return true; // action expects boolean result
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -236,9 +247,9 @@
|
|||||||
url: `/api/v1/party/${partyId}`,
|
url: `/api/v1/party/${partyId}`,
|
||||||
type: "GET",
|
type: "GET",
|
||||||
dataType: "json",
|
dataType: "json",
|
||||||
success: function (data) {
|
success: response => {
|
||||||
const items = data.map(function (player) {
|
const items = response.map(player => {
|
||||||
return player.loot.map(function (loot) {
|
return player.loot.map(loot => {
|
||||||
return {
|
return {
|
||||||
nick: player.nick,
|
nick: player.nick,
|
||||||
job: player.job,
|
job: player.job,
|
||||||
@ -249,12 +260,12 @@
|
|||||||
};
|
};
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
const payload = items.reduce(function (left, right) { return left.concat(right); }, []);
|
const payload = items.reduce((left, right) => { return left.concat(right); }, []);
|
||||||
table.bootstrapTable("load", payload);
|
table.bootstrapTable("load", payload);
|
||||||
table.bootstrapTable("uncheckAll");
|
table.bootstrapTable("uncheckAll");
|
||||||
table.bootstrapTable("hideLoading");
|
table.bootstrapTable("hideLoading");
|
||||||
|
|
||||||
const options = data.map(function (player) {
|
const options = response.map(player => {
|
||||||
const option = document.createElement("option");
|
const option = document.createElement("option");
|
||||||
option.innerText = formatPlayerId(player);
|
option.innerText = formatPlayerId(player);
|
||||||
option.dataset.nick = player.nick;
|
option.dataset.nick = player.nick;
|
||||||
@ -263,13 +274,13 @@
|
|||||||
});
|
});
|
||||||
playerInput.empty().append(options);
|
playerInput.empty().append(options);
|
||||||
},
|
},
|
||||||
error: function (jqXHR, _, errorThrown) { requestAlert(jqXHR, errorThrown); },
|
error: (jqXHR, _, errorThrown) => { requestAlert(jqXHR, errorThrown); },
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function removeLoot() {
|
function removeLoot() {
|
||||||
const pieces = table.bootstrapTable("getSelections");
|
const pieces = table.bootstrapTable("getSelections");
|
||||||
pieces.map(function (loot) {
|
pieces.map(loot => {
|
||||||
$.ajax({
|
$.ajax({
|
||||||
url: `/api/v1/party/${partyId}/loot`,
|
url: `/api/v1/party/${partyId}/loot`,
|
||||||
data: JSON.stringify({
|
data: JSON.stringify({
|
||||||
@ -288,8 +299,8 @@
|
|||||||
}),
|
}),
|
||||||
type: "POST",
|
type: "POST",
|
||||||
contentType: "application/json",
|
contentType: "application/json",
|
||||||
success: function (_) { reload(); },
|
success: _ => { reload(); },
|
||||||
error: function (jqXHR, _, errorThrown) { requestAlert(jqXHR, errorThrown); },
|
error: (jqXHR, _, errorThrown) => { requestAlert(jqXHR, errorThrown); },
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -306,8 +317,8 @@
|
|||||||
type: "PUT",
|
type: "PUT",
|
||||||
contentType: "application/json",
|
contentType: "application/json",
|
||||||
dataType: "json",
|
dataType: "json",
|
||||||
success: function (data) {
|
success: response => {
|
||||||
const payload = data.map(function (stat) {
|
const payload = response.map(stat => {
|
||||||
return {
|
return {
|
||||||
nick: stat.nick,
|
nick: stat.nick,
|
||||||
job: stat.job,
|
job: stat.job,
|
||||||
@ -321,11 +332,11 @@
|
|||||||
stats.bootstrapTable("uncheckAll");
|
stats.bootstrapTable("uncheckAll");
|
||||||
stats.bootstrapTable("hideLoading");
|
stats.bootstrapTable("hideLoading");
|
||||||
},
|
},
|
||||||
error: function (jqXHR, _, errorThrown) { requestAlert(jqXHR, errorThrown); },
|
error: (jqXHR, _, errorThrown) => { requestAlert(jqXHR, errorThrown); },
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
$(function () {
|
$(() => {
|
||||||
setupFormClear(addLootDialog);
|
setupFormClear(addLootDialog);
|
||||||
setupRemoveButton(table, removeButton);
|
setupRemoveButton(table, removeButton);
|
||||||
|
|
||||||
|
@ -9,9 +9,9 @@
|
|||||||
<link rel="shortcut icon" href="/static/favicon.ico">
|
<link rel="shortcut icon" href="/static/favicon.ico">
|
||||||
|
|
||||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous" type="text/css">
|
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous" type="text/css">
|
||||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.7.2/font/bootstrap-icons.css" type="text/css">
|
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.8.3/font/bootstrap-icons.css" type="text/css">
|
||||||
|
|
||||||
<link rel="stylesheet" href="https://unpkg.com/bootstrap-table@1.19.1/dist/bootstrap-table.min.css" type="text/css">
|
<link rel="stylesheet" href="https://unpkg.com/bootstrap-table@1.20.2/dist/bootstrap-table.min.css" type="text/css">
|
||||||
|
|
||||||
|
|
||||||
<link rel="stylesheet" href="https://unpkg.com/jquery-resizable-columns@0.2.3/dist/jquery.resizableColumns.css" type="text/css">
|
<link rel="stylesheet" href="https://unpkg.com/jquery-resizable-columns@0.2.3/dist/jquery.resizableColumns.css" type="text/css">
|
||||||
@ -147,11 +147,11 @@
|
|||||||
<script src="https://unpkg.com/jquery-resizable-columns@0.2.3/dist/jquery.resizableColumns.min.js"></script>
|
<script src="https://unpkg.com/jquery-resizable-columns@0.2.3/dist/jquery.resizableColumns.min.js"></script>
|
||||||
|
|
||||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js" integrity="sha384-ka7Sk0Gln4gmtz2MlQnikT1wXgYsOg+OMhuP+IlRH9sENBO0LRn5q+8nbTov4+1p" crossorigin="anonymous"></script>
|
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js" integrity="sha384-ka7Sk0Gln4gmtz2MlQnikT1wXgYsOg+OMhuP+IlRH9sENBO0LRn5q+8nbTov4+1p" crossorigin="anonymous"></script>
|
||||||
<script src="https://unpkg.com/bootstrap-table@1.19.1/dist/bootstrap-table.min.js"></script>
|
<script src="https://unpkg.com/bootstrap-table@1.20.2/dist/bootstrap-table.min.js"></script>
|
||||||
|
|
||||||
<script src="https://unpkg.com/bootstrap-table@1.19.1/dist/extensions/export/bootstrap-table-export.min.js"></script>
|
<script src="https://unpkg.com/bootstrap-table@1.20.2/dist/extensions/export/bootstrap-table-export.min.js"></script>
|
||||||
|
|
||||||
<script src="https://unpkg.com/bootstrap-table@1.19.1/dist/extensions/resizable/bootstrap-table-resizable.js"></script>
|
<script src="https://unpkg.com/bootstrap-table@1.20.2/dist/extensions/resizable/bootstrap-table-resizable.js"></script>
|
||||||
|
|
||||||
<script src="/static/utils.js"></script>
|
<script src="/static/utils.js"></script>
|
||||||
<script src="/static/load.js"></script>
|
<script src="/static/load.js"></script>
|
||||||
@ -184,8 +184,8 @@
|
|||||||
}),
|
}),
|
||||||
type: "POST",
|
type: "POST",
|
||||||
contentType: "application/json",
|
contentType: "application/json",
|
||||||
success: function (_) { reload(); },
|
success: _ => { reload(); },
|
||||||
error: function (jqXHR, _, errorThrown) { requestAlert(jqXHR, errorThrown); },
|
error: (jqXHR, _, errorThrown) => { requestAlert(jqXHR, errorThrown); },
|
||||||
});
|
});
|
||||||
addPlayerDialog.modal("hide");
|
addPlayerDialog.modal("hide");
|
||||||
return true; // action expects boolean result
|
return true; // action expects boolean result
|
||||||
@ -210,18 +210,18 @@
|
|||||||
url: `/api/v1/party/${partyId}`,
|
url: `/api/v1/party/${partyId}`,
|
||||||
type: "GET",
|
type: "GET",
|
||||||
dataType: "json",
|
dataType: "json",
|
||||||
success: function (data) {
|
success: response => {
|
||||||
table.bootstrapTable("load", data);
|
table.bootstrapTable("load", response);
|
||||||
table.bootstrapTable("uncheckAll");
|
table.bootstrapTable("uncheckAll");
|
||||||
table.bootstrapTable("hideLoading");
|
table.bootstrapTable("hideLoading");
|
||||||
},
|
},
|
||||||
error: function (jqXHR, _, errorThrown) { requestAlert(jqXHR, errorThrown); },
|
error: (jqXHR, _, errorThrown) => { requestAlert(jqXHR, errorThrown); },
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function removePlayers() {
|
function removePlayers() {
|
||||||
const players = table.bootstrapTable("getSelections");
|
const players = table.bootstrapTable("getSelections");
|
||||||
players.map(function (player) {
|
players.map(player => {
|
||||||
$.ajax({
|
$.ajax({
|
||||||
url: `/api/v1/party/${partyId}`,
|
url: `/api/v1/party/${partyId}`,
|
||||||
data: JSON.stringify({
|
data: JSON.stringify({
|
||||||
@ -234,13 +234,13 @@
|
|||||||
}),
|
}),
|
||||||
type: "POST",
|
type: "POST",
|
||||||
contentType: "application/json",
|
contentType: "application/json",
|
||||||
success: function (_) { reload(); },
|
success: _ => { reload(); },
|
||||||
error: function (jqXHR, _, errorThrown) { requestAlert(jqXHR, errorThrown); },
|
error: (jqXHR, _, errorThrown) => { requestAlert(jqXHR, errorThrown); },
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
$(function () {
|
$(() => {
|
||||||
setupFormClear(addPlayerDialog);
|
setupFormClear(addPlayerDialog);
|
||||||
setupRemoveButton(table, removeButton);
|
setupRemoveButton(table, removeButton);
|
||||||
|
|
||||||
|
@ -9,9 +9,9 @@
|
|||||||
<link rel="shortcut icon" href="/static/favicon.ico">
|
<link rel="shortcut icon" href="/static/favicon.ico">
|
||||||
|
|
||||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous" type="text/css">
|
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous" type="text/css">
|
||||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.7.2/font/bootstrap-icons.css" type="text/css">
|
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.8.3/font/bootstrap-icons.css" type="text/css">
|
||||||
|
|
||||||
<link rel="stylesheet" href="https://unpkg.com/bootstrap-table@1.19.1/dist/bootstrap-table.min.css" type="text/css">
|
<link rel="stylesheet" href="https://unpkg.com/bootstrap-table@1.20.2/dist/bootstrap-table.min.css" type="text/css">
|
||||||
|
|
||||||
|
|
||||||
<link rel="stylesheet" href="https://unpkg.com/jquery-resizable-columns@0.2.3/dist/jquery.resizableColumns.css" type="text/css">
|
<link rel="stylesheet" href="https://unpkg.com/jquery-resizable-columns@0.2.3/dist/jquery.resizableColumns.css" type="text/css">
|
||||||
@ -141,11 +141,11 @@
|
|||||||
<script src="https://unpkg.com/jquery-resizable-columns@0.2.3/dist/jquery.resizableColumns.min.js"></script>
|
<script src="https://unpkg.com/jquery-resizable-columns@0.2.3/dist/jquery.resizableColumns.min.js"></script>
|
||||||
|
|
||||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js" integrity="sha384-ka7Sk0Gln4gmtz2MlQnikT1wXgYsOg+OMhuP+IlRH9sENBO0LRn5q+8nbTov4+1p" crossorigin="anonymous"></script>
|
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js" integrity="sha384-ka7Sk0Gln4gmtz2MlQnikT1wXgYsOg+OMhuP+IlRH9sENBO0LRn5q+8nbTov4+1p" crossorigin="anonymous"></script>
|
||||||
<script src="https://unpkg.com/bootstrap-table@1.19.1/dist/bootstrap-table.min.js"></script>
|
<script src="https://unpkg.com/bootstrap-table@1.20.2/dist/bootstrap-table.min.js"></script>
|
||||||
|
|
||||||
<script src="https://unpkg.com/bootstrap-table@1.19.1/dist/extensions/export/bootstrap-table-export.min.js"></script>
|
<script src="https://unpkg.com/bootstrap-table@1.20.2/dist/extensions/export/bootstrap-table-export.min.js"></script>
|
||||||
|
|
||||||
<script src="https://unpkg.com/bootstrap-table@1.19.1/dist/extensions/resizable/bootstrap-table-resizable.js"></script>
|
<script src="https://unpkg.com/bootstrap-table@1.20.2/dist/extensions/resizable/bootstrap-table-resizable.js"></script>
|
||||||
|
|
||||||
<script src="/static/utils.js"></script>
|
<script src="/static/utils.js"></script>
|
||||||
<script src="/static/load.js"></script>
|
<script src="/static/load.js"></script>
|
||||||
@ -173,8 +173,8 @@
|
|||||||
}),
|
}),
|
||||||
type: "POST",
|
type: "POST",
|
||||||
contentType: "application/json",
|
contentType: "application/json",
|
||||||
success: function (_) { reload(); },
|
success: _ => { reload(); },
|
||||||
error: function (jqXHR, _, errorThrown) { requestAlert(jqXHR, errorThrown); },
|
error: (jqXHR, _, errorThrown) => { requestAlert(jqXHR, errorThrown); },
|
||||||
});
|
});
|
||||||
addUserDialog.modal("hide");
|
addUserDialog.modal("hide");
|
||||||
return true; // action expects boolean result
|
return true; // action expects boolean result
|
||||||
@ -191,28 +191,28 @@
|
|||||||
url: `/api/v1/party/${partyId}/users`,
|
url: `/api/v1/party/${partyId}/users`,
|
||||||
type: "GET",
|
type: "GET",
|
||||||
dataType: "json",
|
dataType: "json",
|
||||||
success: function (data) {
|
success: response => {
|
||||||
table.bootstrapTable("load", data);
|
table.bootstrapTable("load", response);
|
||||||
table.bootstrapTable("uncheckAll");
|
table.bootstrapTable("uncheckAll");
|
||||||
table.bootstrapTable("hideLoading");
|
table.bootstrapTable("hideLoading");
|
||||||
},
|
},
|
||||||
error: function (jqXHR, _, errorThrown) { requestAlert(jqXHR, errorThrown); },
|
error: (jqXHR, _, errorThrown) => { requestAlert(jqXHR, errorThrown); },
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function removeUsers() {
|
function removeUsers() {
|
||||||
const users = table.bootstrapTable("getSelections");
|
const users = table.bootstrapTable("getSelections");
|
||||||
users.map(function (user) {
|
users.map(user => {
|
||||||
$.ajax({
|
$.ajax({
|
||||||
url: `/api/v1/party/${partyId}/users/${user.username}`,
|
url: `/api/v1/party/${partyId}/users/${user.username}`,
|
||||||
type: "DELETE",
|
type: "DELETE",
|
||||||
success: function (_) { reload(); },
|
success: _ => { reload(); },
|
||||||
error: function (jqXHR, _, errorThrown) { requestAlert(jqXHR, errorThrown); },
|
error: (jqXHR, _, errorThrown) => { requestAlert(jqXHR, errorThrown); },
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
$(function () {
|
$(() => {
|
||||||
setupFormClear(addUserDialog);
|
setupFormClear(addUserDialog);
|
||||||
setupRemoveButton(table, removeButton);
|
setupRemoveButton(table, removeButton);
|
||||||
|
|
||||||
|
@ -12,5 +12,6 @@
|
|||||||
</logger>
|
</logger>
|
||||||
<logger name="org.flywaydb.core.internal" level="INFO" />
|
<logger name="org.flywaydb.core.internal" level="INFO" />
|
||||||
<logger name="com.zaxxer.hikari.pool" level="INFO" />
|
<logger name="com.zaxxer.hikari.pool" level="INFO" />
|
||||||
|
<logger name="io.swagger" level="INFO" />
|
||||||
|
|
||||||
</configuration>
|
</configuration>
|
||||||
|
@ -0,0 +1,16 @@
|
|||||||
|
package me.arcanis.ffxivbis.http
|
||||||
|
|
||||||
|
import scala.collection.immutable.HashSet
|
||||||
|
|
||||||
|
trait ValidatorHelper {
|
||||||
|
|
||||||
|
def isValidString(string: String): Boolean = string.nonEmpty && string.forall(isValidSymbol)
|
||||||
|
|
||||||
|
def isValidSymbol(char: Char): Boolean =
|
||||||
|
char.isLetterOrDigit || ValidatorHelper.VALID_CHARACTERS.contains(char)
|
||||||
|
}
|
||||||
|
|
||||||
|
object ValidatorHelper {
|
||||||
|
|
||||||
|
final val VALID_CHARACTERS = HashSet.from("!@#$%^&*()-_=+;:',./? ")
|
||||||
|
}
|
@ -49,7 +49,12 @@ class BiSEndpoint(
|
|||||||
summary = "create best in slot",
|
summary = "create best in slot",
|
||||||
description = "Create the best in slot set",
|
description = "Create the best in slot set",
|
||||||
parameters = Array(
|
parameters = Array(
|
||||||
new Parameter(name = "partyId", in = ParameterIn.PATH, description = "unique party ID", example = "abcdefgh"),
|
new Parameter(
|
||||||
|
name = "partyId",
|
||||||
|
in = ParameterIn.PATH,
|
||||||
|
description = "unique party ID",
|
||||||
|
example = "o3KicHQPW5b0JcOm5yI3"
|
||||||
|
),
|
||||||
),
|
),
|
||||||
requestBody = new RequestBody(
|
requestBody = new RequestBody(
|
||||||
description = "player best in slot description",
|
description = "player best in slot description",
|
||||||
@ -105,7 +110,12 @@ class BiSEndpoint(
|
|||||||
summary = "get best in slot",
|
summary = "get best in slot",
|
||||||
description = "Return the best in slot items",
|
description = "Return the best in slot items",
|
||||||
parameters = Array(
|
parameters = Array(
|
||||||
new Parameter(name = "partyId", in = ParameterIn.PATH, description = "unique party ID", example = "abcdefgh"),
|
new Parameter(
|
||||||
|
name = "partyId",
|
||||||
|
in = ParameterIn.PATH,
|
||||||
|
description = "unique party ID",
|
||||||
|
example = "o3KicHQPW5b0JcOm5yI3"
|
||||||
|
),
|
||||||
new Parameter(
|
new Parameter(
|
||||||
name = "nick",
|
name = "nick",
|
||||||
in = ParameterIn.QUERY,
|
in = ParameterIn.QUERY,
|
||||||
@ -167,7 +177,12 @@ class BiSEndpoint(
|
|||||||
summary = "modify best in slot",
|
summary = "modify best in slot",
|
||||||
description = "Add or remove an item from the best in slot",
|
description = "Add or remove an item from the best in slot",
|
||||||
parameters = Array(
|
parameters = Array(
|
||||||
new Parameter(name = "partyId", in = ParameterIn.PATH, description = "unique party ID", example = "abcdefgh"),
|
new Parameter(
|
||||||
|
name = "partyId",
|
||||||
|
in = ParameterIn.PATH,
|
||||||
|
description = "unique party ID",
|
||||||
|
example = "o3KicHQPW5b0JcOm5yI3"
|
||||||
|
),
|
||||||
),
|
),
|
||||||
requestBody = new RequestBody(
|
requestBody = new RequestBody(
|
||||||
description = "action and piece description",
|
description = "action and piece description",
|
||||||
|
@ -46,7 +46,12 @@ class LootEndpoint(override val storage: ActorRef[Message], override val auth: A
|
|||||||
summary = "get loot list",
|
summary = "get loot list",
|
||||||
description = "Return the looted items",
|
description = "Return the looted items",
|
||||||
parameters = Array(
|
parameters = Array(
|
||||||
new Parameter(name = "partyId", in = ParameterIn.PATH, description = "unique party ID", example = "abcdefgh"),
|
new Parameter(
|
||||||
|
name = "partyId",
|
||||||
|
in = ParameterIn.PATH,
|
||||||
|
description = "unique party ID",
|
||||||
|
example = "o3KicHQPW5b0JcOm5yI3"
|
||||||
|
),
|
||||||
new Parameter(
|
new Parameter(
|
||||||
name = "nick",
|
name = "nick",
|
||||||
in = ParameterIn.QUERY,
|
in = ParameterIn.QUERY,
|
||||||
@ -107,7 +112,12 @@ class LootEndpoint(override val storage: ActorRef[Message], override val auth: A
|
|||||||
summary = "modify loot list",
|
summary = "modify loot list",
|
||||||
description = "Add or remove an item from the loot list",
|
description = "Add or remove an item from the loot list",
|
||||||
parameters = Array(
|
parameters = Array(
|
||||||
new Parameter(name = "partyId", in = ParameterIn.PATH, description = "unique party ID", example = "abcdefgh"),
|
new Parameter(
|
||||||
|
name = "partyId",
|
||||||
|
in = ParameterIn.PATH,
|
||||||
|
description = "unique party ID",
|
||||||
|
example = "o3KicHQPW5b0JcOm5yI3"
|
||||||
|
),
|
||||||
),
|
),
|
||||||
requestBody = new RequestBody(
|
requestBody = new RequestBody(
|
||||||
description = "action and piece description",
|
description = "action and piece description",
|
||||||
@ -164,7 +174,12 @@ class LootEndpoint(override val storage: ActorRef[Message], override val auth: A
|
|||||||
summary = "suggest loot",
|
summary = "suggest loot",
|
||||||
description = "Suggest loot piece to party",
|
description = "Suggest loot piece to party",
|
||||||
parameters = Array(
|
parameters = Array(
|
||||||
new Parameter(name = "partyId", in = ParameterIn.PATH, description = "unique party ID", example = "abcdefgh"),
|
new Parameter(
|
||||||
|
name = "partyId",
|
||||||
|
in = ParameterIn.PATH,
|
||||||
|
description = "unique party ID",
|
||||||
|
example = "o3KicHQPW5b0JcOm5yI3"
|
||||||
|
),
|
||||||
),
|
),
|
||||||
requestBody = new RequestBody(
|
requestBody = new RequestBody(
|
||||||
description = "piece description",
|
description = "piece description",
|
||||||
|
@ -49,7 +49,12 @@ class PartyEndpoint(
|
|||||||
summary = "get party description",
|
summary = "get party description",
|
||||||
description = "Return the party description",
|
description = "Return the party description",
|
||||||
parameters = Array(
|
parameters = Array(
|
||||||
new Parameter(name = "partyId", in = ParameterIn.PATH, description = "unique party ID", example = "abcdefgh"),
|
new Parameter(
|
||||||
|
name = "partyId",
|
||||||
|
in = ParameterIn.PATH,
|
||||||
|
description = "unique party ID",
|
||||||
|
example = "o3KicHQPW5b0JcOm5yI3"
|
||||||
|
),
|
||||||
),
|
),
|
||||||
responses = Array(
|
responses = Array(
|
||||||
new ApiResponse(
|
new ApiResponse(
|
||||||
@ -96,7 +101,12 @@ class PartyEndpoint(
|
|||||||
summary = "modify party description",
|
summary = "modify party description",
|
||||||
description = "Edit party description",
|
description = "Edit party description",
|
||||||
parameters = Array(
|
parameters = Array(
|
||||||
new Parameter(name = "partyId", in = ParameterIn.PATH, description = "unique party ID", example = "abcdefgh"),
|
new Parameter(
|
||||||
|
name = "partyId",
|
||||||
|
in = ParameterIn.PATH,
|
||||||
|
description = "unique party ID",
|
||||||
|
example = "o3KicHQPW5b0JcOm5yI3"
|
||||||
|
),
|
||||||
),
|
),
|
||||||
requestBody = new RequestBody(
|
requestBody = new RequestBody(
|
||||||
description = "new party description",
|
description = "new party description",
|
||||||
|
@ -50,7 +50,12 @@ class PlayerEndpoint(
|
|||||||
summary = "get party",
|
summary = "get party",
|
||||||
description = "Return the players who belong to the party",
|
description = "Return the players who belong to the party",
|
||||||
parameters = Array(
|
parameters = Array(
|
||||||
new Parameter(name = "partyId", in = ParameterIn.PATH, description = "unique party ID", example = "abcdefgh"),
|
new Parameter(
|
||||||
|
name = "partyId",
|
||||||
|
in = ParameterIn.PATH,
|
||||||
|
description = "unique party ID",
|
||||||
|
example = "o3KicHQPW5b0JcOm5yI3"
|
||||||
|
),
|
||||||
new Parameter(
|
new Parameter(
|
||||||
name = "nick",
|
name = "nick",
|
||||||
in = ParameterIn.QUERY,
|
in = ParameterIn.QUERY,
|
||||||
@ -111,7 +116,12 @@ class PlayerEndpoint(
|
|||||||
summary = "get party statistics",
|
summary = "get party statistics",
|
||||||
description = "Return the party statistics",
|
description = "Return the party statistics",
|
||||||
parameters = Array(
|
parameters = Array(
|
||||||
new Parameter(name = "partyId", in = ParameterIn.PATH, description = "unique party ID", example = "abcdefgh"),
|
new Parameter(
|
||||||
|
name = "partyId",
|
||||||
|
in = ParameterIn.PATH,
|
||||||
|
description = "unique party ID",
|
||||||
|
example = "o3KicHQPW5b0JcOm5yI3"
|
||||||
|
),
|
||||||
new Parameter(
|
new Parameter(
|
||||||
name = "nick",
|
name = "nick",
|
||||||
in = ParameterIn.QUERY,
|
in = ParameterIn.QUERY,
|
||||||
@ -172,7 +182,12 @@ class PlayerEndpoint(
|
|||||||
summary = "modify party",
|
summary = "modify party",
|
||||||
description = "Add or remove a player from party list",
|
description = "Add or remove a player from party list",
|
||||||
parameters = Array(
|
parameters = Array(
|
||||||
new Parameter(name = "partyId", in = ParameterIn.PATH, description = "unique party ID", example = "abcdefgh"),
|
new Parameter(
|
||||||
|
name = "partyId",
|
||||||
|
in = ParameterIn.PATH,
|
||||||
|
description = "unique party ID",
|
||||||
|
example = "o3KicHQPW5b0JcOm5yI3"
|
||||||
|
),
|
||||||
),
|
),
|
||||||
requestBody = new RequestBody(
|
requestBody = new RequestBody(
|
||||||
description = "player description",
|
description = "player description",
|
||||||
|
@ -96,7 +96,12 @@ class UserEndpoint(override val storage: ActorRef[Message], override val auth: A
|
|||||||
summary = "create new user",
|
summary = "create new user",
|
||||||
description = "Add an user to the specified party",
|
description = "Add an user to the specified party",
|
||||||
parameters = Array(
|
parameters = Array(
|
||||||
new Parameter(name = "partyId", in = ParameterIn.PATH, description = "unique party ID", example = "abcdefgh"),
|
new Parameter(
|
||||||
|
name = "partyId",
|
||||||
|
in = ParameterIn.PATH,
|
||||||
|
description = "unique party ID",
|
||||||
|
example = "o3KicHQPW5b0JcOm5yI3"
|
||||||
|
),
|
||||||
),
|
),
|
||||||
requestBody = new RequestBody(
|
requestBody = new RequestBody(
|
||||||
description = "user description",
|
description = "user description",
|
||||||
@ -151,7 +156,12 @@ class UserEndpoint(override val storage: ActorRef[Message], override val auth: A
|
|||||||
summary = "remove user",
|
summary = "remove user",
|
||||||
description = "Remove an user from the specified party",
|
description = "Remove an user from the specified party",
|
||||||
parameters = Array(
|
parameters = Array(
|
||||||
new Parameter(name = "partyId", in = ParameterIn.PATH, description = "unique party ID", example = "abcdefgh"),
|
new Parameter(
|
||||||
|
name = "partyId",
|
||||||
|
in = ParameterIn.PATH,
|
||||||
|
description = "unique party ID",
|
||||||
|
example = "o3KicHQPW5b0JcOm5yI3"
|
||||||
|
),
|
||||||
new Parameter(name = "username", in = ParameterIn.PATH, description = "username to remove", example = "siuan"),
|
new Parameter(name = "username", in = ParameterIn.PATH, description = "username to remove", example = "siuan"),
|
||||||
),
|
),
|
||||||
responses = Array(
|
responses = Array(
|
||||||
@ -195,7 +205,12 @@ class UserEndpoint(override val storage: ActorRef[Message], override val auth: A
|
|||||||
summary = "get users",
|
summary = "get users",
|
||||||
description = "Return the list of users belong to party",
|
description = "Return the list of users belong to party",
|
||||||
parameters = Array(
|
parameters = Array(
|
||||||
new Parameter(name = "partyId", in = ParameterIn.PATH, description = "unique party ID", example = "abcdefgh"),
|
new Parameter(
|
||||||
|
name = "partyId",
|
||||||
|
in = ParameterIn.PATH,
|
||||||
|
description = "unique party ID",
|
||||||
|
example = "o3KicHQPW5b0JcOm5yI3"
|
||||||
|
),
|
||||||
),
|
),
|
||||||
responses = Array(
|
responses = Array(
|
||||||
new ApiResponse(
|
new ApiResponse(
|
||||||
@ -246,7 +261,12 @@ class UserEndpoint(override val storage: ActorRef[Message], override val auth: A
|
|||||||
summary = "get current user",
|
summary = "get current user",
|
||||||
description = "Return the current user descriptor",
|
description = "Return the current user descriptor",
|
||||||
parameters = Array(
|
parameters = Array(
|
||||||
new Parameter(name = "partyId", in = ParameterIn.PATH, description = "unique party ID", example = "abcdefgh"),
|
new Parameter(
|
||||||
|
name = "partyId",
|
||||||
|
in = ParameterIn.PATH,
|
||||||
|
description = "unique party ID",
|
||||||
|
example = "o3KicHQPW5b0JcOm5yI3"
|
||||||
|
),
|
||||||
),
|
),
|
||||||
responses = Array(
|
responses = Array(
|
||||||
new ApiResponse(
|
new ApiResponse(
|
||||||
|
@ -16,12 +16,12 @@ import java.time.Instant
|
|||||||
|
|
||||||
trait JsonSupport extends SprayJsonSupport with DefaultJsonProtocol {
|
trait JsonSupport extends SprayJsonSupport with DefaultJsonProtocol {
|
||||||
|
|
||||||
private def enumFormat[E <: Enumeration](enum: E): RootJsonFormat[E#Value] =
|
private def enumFormat[E <: Enumeration](enumeration: E): RootJsonFormat[E#Value] =
|
||||||
new RootJsonFormat[E#Value] {
|
new RootJsonFormat[E#Value] {
|
||||||
override def write(obj: E#Value): JsValue = obj.toString.toJson
|
override def write(obj: E#Value): JsValue = obj.toString.toJson
|
||||||
override def read(json: JsValue): E#Value = json match {
|
override def read(json: JsValue): E#Value = json match {
|
||||||
case JsNumber(value) => enum(value.toInt)
|
case JsNumber(value) => enumeration(value.toInt)
|
||||||
case JsString(name) => enum.withName(name)
|
case JsString(name) => enumeration.withName(name)
|
||||||
case other => deserializationError(s"String or number expected, got $other")
|
case other => deserializationError(s"String or number expected, got $other")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -12,9 +12,11 @@ import io.swagger.v3.oas.annotations.media.Schema
|
|||||||
import me.arcanis.ffxivbis.models.PartyDescription
|
import me.arcanis.ffxivbis.models.PartyDescription
|
||||||
|
|
||||||
case class PartyDescriptionModel(
|
case class PartyDescriptionModel(
|
||||||
@Schema(description = "party id", required = true, example = "abcdefgh") partyId: String,
|
@Schema(description = "party id", required = true, example = "o3KicHQPW5b0JcOm5yI3") partyId: String,
|
||||||
@Schema(description = "party name") partyAlias: Option[String]
|
@Schema(description = "party name") partyAlias: Option[String]
|
||||||
) {
|
) extends Validator {
|
||||||
|
|
||||||
|
require(partyAlias.forall(isValidString), stringMatchError("Party alias"))
|
||||||
|
|
||||||
def toDescription: PartyDescription = PartyDescription(partyId, partyAlias)
|
def toDescription: PartyDescription = PartyDescription(partyId, partyAlias)
|
||||||
}
|
}
|
||||||
|
@ -10,4 +10,6 @@ package me.arcanis.ffxivbis.http.api.v1.json
|
|||||||
|
|
||||||
import io.swagger.v3.oas.annotations.media.Schema
|
import io.swagger.v3.oas.annotations.media.Schema
|
||||||
|
|
||||||
case class PartyIdModel(@Schema(description = "party id", required = true, example = "abcdefgh") partyId: String)
|
case class PartyIdModel(
|
||||||
|
@Schema(description = "party id", required = true, example = "o3KicHQPW5b0JcOm5yI3") partyId: String
|
||||||
|
)
|
||||||
|
@ -17,4 +17,7 @@ case class PlayerBiSLinkModel(
|
|||||||
example = "https://ffxiv.ariyala.com/19V5R"
|
example = "https://ffxiv.ariyala.com/19V5R"
|
||||||
) link: String,
|
) link: String,
|
||||||
@Schema(description = "player description", required = true) playerId: PlayerIdModel
|
@Schema(description = "player description", required = true) playerId: PlayerIdModel
|
||||||
)
|
) extends Validator {
|
||||||
|
|
||||||
|
require(isValidString(link), stringMatchError("BiS link"))
|
||||||
|
}
|
||||||
|
@ -12,10 +12,14 @@ import io.swagger.v3.oas.annotations.media.Schema
|
|||||||
import me.arcanis.ffxivbis.models.{Job, PlayerId}
|
import me.arcanis.ffxivbis.models.{Job, PlayerId}
|
||||||
|
|
||||||
case class PlayerIdModel(
|
case class PlayerIdModel(
|
||||||
@Schema(description = "unique party ID. Required in responses", example = "abcdefgh") partyId: Option[String],
|
@Schema(description = "unique party ID. Required in responses", example = "o3KicHQPW5b0JcOm5yI3") partyId: Option[
|
||||||
|
String
|
||||||
|
],
|
||||||
@Schema(description = "job name", required = true, example = "DNC") job: String,
|
@Schema(description = "job name", required = true, example = "DNC") job: String,
|
||||||
@Schema(description = "player nick name", required = true, example = "Siuan Sanche") nick: String
|
@Schema(description = "player nick name", required = true, example = "Siuan Sanche") nick: String
|
||||||
) {
|
) extends Validator {
|
||||||
|
|
||||||
|
require(isValidString(nick), stringMatchError("Player name"))
|
||||||
|
|
||||||
def withPartyId(partyId: String): PlayerId =
|
def withPartyId(partyId: String): PlayerId =
|
||||||
PlayerId(partyId, Job.withName(job), nick)
|
PlayerId(partyId, Job.withName(job), nick)
|
||||||
|
@ -12,7 +12,7 @@ import io.swagger.v3.oas.annotations.media.Schema
|
|||||||
import me.arcanis.ffxivbis.models.PlayerIdWithCounters
|
import me.arcanis.ffxivbis.models.PlayerIdWithCounters
|
||||||
|
|
||||||
case class PlayerIdWithCountersModel(
|
case class PlayerIdWithCountersModel(
|
||||||
@Schema(description = "unique party ID", required = true, example = "abcdefgh") partyId: String,
|
@Schema(description = "unique party ID", required = true, example = "o3KicHQPW5b0JcOm5yI3") partyId: String,
|
||||||
@Schema(description = "job name", required = true, example = "DNC") job: String,
|
@Schema(description = "job name", required = true, example = "DNC") job: String,
|
||||||
@Schema(description = "player nick name", required = true, example = "Siuan Sanche") nick: String,
|
@Schema(description = "player nick name", required = true, example = "Siuan Sanche") nick: String,
|
||||||
@Schema(description = "is piece required by player or not", required = true) isRequired: Boolean,
|
@Schema(description = "is piece required by player or not", required = true) isRequired: Boolean,
|
||||||
|
@ -12,7 +12,7 @@ import io.swagger.v3.oas.annotations.media.Schema
|
|||||||
import me.arcanis.ffxivbis.models.{BiS, Job, Player}
|
import me.arcanis.ffxivbis.models.{BiS, Job, Player}
|
||||||
|
|
||||||
case class PlayerModel(
|
case class PlayerModel(
|
||||||
@Schema(description = "unique party ID", required = true, example = "abcdefgh") partyId: String,
|
@Schema(description = "unique party ID", required = true, example = "o3KicHQPW5b0JcOm5yI3") partyId: String,
|
||||||
@Schema(description = "job name", required = true, example = "DNC") job: String,
|
@Schema(description = "job name", required = true, example = "DNC") job: String,
|
||||||
@Schema(description = "player nick name", required = true, example = "Siuan Sanche") nick: String,
|
@Schema(description = "player nick name", required = true, example = "Siuan Sanche") nick: String,
|
||||||
@Schema(description = "pieces in best in slot") bis: Option[Seq[PieceModel]],
|
@Schema(description = "pieces in best in slot") bis: Option[Seq[PieceModel]],
|
||||||
@ -24,7 +24,10 @@ case class PlayerModel(
|
|||||||
`type` = "number"
|
`type` = "number"
|
||||||
) lootCountBiS: Option[Int],
|
) lootCountBiS: Option[Int],
|
||||||
@Schema(description = "total count of looted pieces", `type` = "number") lootCountTotal: Option[Int],
|
@Schema(description = "total count of looted pieces", `type` = "number") lootCountTotal: Option[Int],
|
||||||
) {
|
) extends Validator {
|
||||||
|
|
||||||
|
require(isValidString(nick), stringMatchError("Player name"))
|
||||||
|
require(link.forall(isValidString), stringMatchError("BiS link"))
|
||||||
|
|
||||||
def toPlayer: Player =
|
def toPlayer: Player =
|
||||||
Player(
|
Player(
|
||||||
|
@ -12,23 +12,30 @@ import io.swagger.v3.oas.annotations.media.Schema
|
|||||||
import me.arcanis.ffxivbis.models.{Permission, User}
|
import me.arcanis.ffxivbis.models.{Permission, User}
|
||||||
|
|
||||||
case class UserModel(
|
case class UserModel(
|
||||||
@Schema(description = "unique party ID", required = true, example = "abcdefgh") partyId: String,
|
@Schema(description = "unique party ID", required = true, example = "o3KicHQPW5b0JcOm5yI3") partyId: String,
|
||||||
@Schema(description = "username to login to party", required = true, example = "siuan") username: String,
|
@Schema(description = "username to login to party", required = true, example = "siuan") username: String,
|
||||||
@Schema(description = "password to login to party", required = true, example = "pa55w0rd") password: String,
|
@Schema(description = "password to login to party, required for user editing", example = "pa55w0rd") password: Option[
|
||||||
|
String
|
||||||
|
],
|
||||||
@Schema(
|
@Schema(
|
||||||
description = "user permission",
|
description = "user permission",
|
||||||
defaultValue = "get",
|
defaultValue = "get",
|
||||||
`type` = "string",
|
`type` = "string",
|
||||||
allowableValues = Array("get", "post", "admin")
|
allowableValues = Array("get", "post", "admin")
|
||||||
) permission: Option[Permission.Value] = None
|
) permission: Option[Permission.Value] = None
|
||||||
) {
|
) extends Validator {
|
||||||
|
|
||||||
|
require(isValidString(username), stringMatchError("Username"))
|
||||||
|
require(password.forall(_.nonEmpty), "Password must not be empty")
|
||||||
|
|
||||||
def toUser: User =
|
def toUser: User =
|
||||||
User(partyId, username, password, permission.getOrElse(Permission.get))
|
password.fold(throw new IllegalArgumentException("Password must noot be empty"))(
|
||||||
|
User(partyId, username, _, permission.getOrElse(Permission.get))
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
object UserModel {
|
object UserModel {
|
||||||
|
|
||||||
def fromUser(user: User): UserModel =
|
def fromUser(user: User): UserModel =
|
||||||
UserModel(user.partyId, user.username, "", Some(user.permission))
|
UserModel(user.partyId, user.username, None, Some(user.permission))
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,9 @@
|
|||||||
|
package me.arcanis.ffxivbis.http.api.v1.json
|
||||||
|
|
||||||
|
import me.arcanis.ffxivbis.http.ValidatorHelper
|
||||||
|
|
||||||
|
trait Validator extends ValidatorHelper {
|
||||||
|
|
||||||
|
def stringMatchError(what: String): String =
|
||||||
|
s"$what must contain only letters or digits or one of (${ValidatorHelper.VALID_CHARACTERS.mkString(", ")})"
|
||||||
|
}
|
@ -45,13 +45,15 @@ trait BiSHelper extends BisProviderHelper {
|
|||||||
timeout: Timeout,
|
timeout: Timeout,
|
||||||
scheduler: Scheduler
|
scheduler: Scheduler
|
||||||
): Future[Unit] =
|
): Future[Unit] =
|
||||||
storage.ask(RemovePiecesFromBiS(playerId, _)).flatMap { _ =>
|
storage
|
||||||
downloadBiS(link, playerId.job)
|
.ask(RemovePiecesFromBiS(playerId, _))
|
||||||
.flatMap { bis =>
|
.flatMap { _ =>
|
||||||
Future.traverse(bis.pieces)(addPieceBiS(playerId, _))
|
downloadBiS(link, playerId.job)
|
||||||
}
|
.flatMap { bis =>
|
||||||
.map(_ => ())
|
Future.traverse(bis.pieces)(addPieceBiS(playerId, _))
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
.flatMap(_ => storage.ask(UpdateBiSLink(playerId, link, _)))
|
||||||
|
|
||||||
def removePieceBiS(playerId: PlayerId, piece: Piece)(implicit timeout: Timeout, scheduler: Scheduler): Future[Unit] =
|
def removePieceBiS(playerId: PlayerId, piece: Piece)(implicit timeout: Timeout, scheduler: Scheduler): Future[Unit] =
|
||||||
storage.ask(RemovePieceFromBiS(playerId, piece, _))
|
storage.ask(RemovePieceFromBiS(playerId, piece, _))
|
||||||
|
@ -27,15 +27,15 @@ trait PlayerHelper extends BisProviderHelper {
|
|||||||
)(implicit executionContext: ExecutionContext, timeout: Timeout, scheduler: Scheduler): Future[Unit] =
|
)(implicit executionContext: ExecutionContext, timeout: Timeout, scheduler: Scheduler): Future[Unit] =
|
||||||
storage
|
storage
|
||||||
.ask(ref => AddPlayer(player, ref))
|
.ask(ref => AddPlayer(player, ref))
|
||||||
.map { res =>
|
.map { _ =>
|
||||||
player.link.map(_.trim).filter(_.nonEmpty) match {
|
player.link.map(_.trim).filter(_.nonEmpty) match {
|
||||||
case Some(link) =>
|
case Some(link) =>
|
||||||
downloadBiS(link, player.job)
|
downloadBiS(link, player.job)
|
||||||
.map { bis =>
|
.map { bis =>
|
||||||
bis.pieces.map(piece => storage.ask(AddPieceToBis(player.playerId, piece, _)))
|
bis.pieces.map(piece => storage.ask(AddPieceToBis(player.playerId, piece, _)))
|
||||||
}
|
}
|
||||||
.map(_ => res)
|
.flatMap(_ => storage.ask(UpdateBiSLink(player.playerId, link, _)))
|
||||||
case None => Future.successful(res)
|
case None => Future.successful(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.flatten
|
.flatten
|
||||||
|
@ -95,6 +95,11 @@ object DatabaseMessage {
|
|||||||
override val isReadOnly: Boolean = false
|
override val isReadOnly: Boolean = false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case class UpdateBiSLink(playerId: PlayerId, link: String, actorRef: ActorRef[Unit]) extends PartyDatabaseMessage {
|
||||||
|
override val partyId: String = playerId.partyId
|
||||||
|
override val isReadOnly: Boolean = false
|
||||||
|
}
|
||||||
|
|
||||||
case class UpdateParty(partyDescription: PartyDescription, replyTo: ActorRef[Unit]) extends PartyDatabaseMessage {
|
case class UpdateParty(partyDescription: PartyDescription, replyTo: ActorRef[Unit]) extends PartyDatabaseMessage {
|
||||||
override val partyId: String = partyDescription.partyId
|
override val partyId: String = partyDescription.partyId
|
||||||
override val isReadOnly: Boolean = false
|
override val isReadOnly: Boolean = false
|
||||||
|
@ -75,6 +75,8 @@ trait XivApi extends RequestExecutor {
|
|||||||
|
|
||||||
object XivApi {
|
object XivApi {
|
||||||
|
|
||||||
|
private val defaultShop = JsObject("IsUnique" -> JsNumber(1), "StackSize" -> JsNumber(999))
|
||||||
|
|
||||||
private def parseXivapiJsonToShop(
|
private def parseXivapiJsonToShop(
|
||||||
js: JsObject
|
js: JsObject
|
||||||
)(implicit executionContext: ExecutionContext): Future[Map[Long, (String, Long)]] = {
|
)(implicit executionContext: ExecutionContext): Future[Map[Long, (String, Long)]] = {
|
||||||
@ -128,7 +130,7 @@ object XivApi {
|
|||||||
if (index == "crafted" && shopId == -1L) PieceType.Crafted
|
if (index == "crafted" && shopId == -1L) PieceType.Crafted
|
||||||
else
|
else
|
||||||
Try(shopMap(shopId).fields(s"ItemCost$index").asJsObject)
|
Try(shopMap(shopId).fields(s"ItemCost$index").asJsObject)
|
||||||
.getOrElse(throw new Exception(s"${shopMap(shopId).fields(s"ItemCost$index")}, $index"))
|
.getOrElse(defaultShop)
|
||||||
.getFields("IsUnique", "StackSize") match {
|
.getFields("IsUnique", "StackSize") match {
|
||||||
case Seq(JsNumber(isUnique), JsNumber(stackSize)) =>
|
case Seq(JsNumber(isUnique), JsNumber(stackSize)) =>
|
||||||
if (isUnique == 1 || stackSize.toLong != 999) PieceType.Tome // either upgraded gear or tomes found
|
if (isUnique == 1 || stackSize.toLong != 999) PieceType.Tome // either upgraded gear or tomes found
|
||||||
|
@ -62,6 +62,10 @@ trait DatabasePartyHandler { this: Database =>
|
|||||||
run(profile.deletePlayer(playerId))(_ => client ! ())
|
run(profile.deletePlayer(playerId))(_ => client ! ())
|
||||||
Behaviors.same
|
Behaviors.same
|
||||||
|
|
||||||
|
case UpdateBiSLink(playerId, link, client) =>
|
||||||
|
run(profile.updateBiSLink(playerId, link))(_ => client ! ())
|
||||||
|
Behaviors.same
|
||||||
|
|
||||||
case UpdateParty(description, client) =>
|
case UpdateParty(description, client) =>
|
||||||
run(profile.insertPartyDescription(description))(_ => client ! ())
|
run(profile.insertPartyDescription(description))(_ => client ! ())
|
||||||
Behaviors.same
|
Behaviors.same
|
||||||
|
@ -53,12 +53,14 @@ trait BiSProfile extends DatabaseConnection {
|
|||||||
def getPiecesBiSById(playerId: Long): Future[Seq[Loot]] = getPiecesBiSById(Seq(playerId))
|
def getPiecesBiSById(playerId: Long): Future[Seq[Loot]] = getPiecesBiSById(Seq(playerId))
|
||||||
|
|
||||||
def getPiecesBiSById(playerIds: Seq[Long]): Future[Seq[Loot]] =
|
def getPiecesBiSById(playerIds: Seq[Long]): Future[Seq[Loot]] =
|
||||||
withConnection { implicit conn =>
|
if (playerIds.isEmpty) Future.successful(Seq.empty)
|
||||||
SQL("""select * from bis where player_id in ({player_ids})""")
|
else
|
||||||
.on("player_ids" -> playerIds)
|
withConnection { implicit conn =>
|
||||||
.executeQuery()
|
SQL("""select * from bis where player_id in ({player_ids})""")
|
||||||
.as(loot.*)
|
.on("player_ids" -> playerIds)
|
||||||
}
|
.executeQuery()
|
||||||
|
.as(loot.*)
|
||||||
|
}
|
||||||
|
|
||||||
def insertPieceBiSById(piece: Piece)(playerId: Long): Future[Int] =
|
def insertPieceBiSById(piece: Piece)(playerId: Long): Future[Int] =
|
||||||
withConnection { implicit conn =>
|
withConnection { implicit conn =>
|
||||||
|
@ -59,12 +59,14 @@ trait LootProfile extends DatabaseConnection {
|
|||||||
def getPiecesById(playerId: Long): Future[Seq[Loot]] = getPiecesById(Seq(playerId))
|
def getPiecesById(playerId: Long): Future[Seq[Loot]] = getPiecesById(Seq(playerId))
|
||||||
|
|
||||||
def getPiecesById(playerIds: Seq[Long]): Future[Seq[Loot]] =
|
def getPiecesById(playerIds: Seq[Long]): Future[Seq[Loot]] =
|
||||||
withConnection { implicit conn =>
|
if (playerIds.isEmpty) Future.successful(Seq.empty)
|
||||||
SQL("""select * from loot where player_id in ({player_ids})""")
|
else
|
||||||
.on("player_ids" -> playerIds)
|
withConnection { implicit conn =>
|
||||||
.executeQuery()
|
SQL("""select * from loot where player_id in ({player_ids})""")
|
||||||
.as(loot.*)
|
.on("player_ids" -> playerIds)
|
||||||
}
|
.executeQuery()
|
||||||
|
.as(loot.*)
|
||||||
|
}
|
||||||
|
|
||||||
def insertPieceById(loot: Loot)(playerId: Long): Future[Int] =
|
def insertPieceById(loot: Loot)(playerId: Long): Future[Int] =
|
||||||
withConnection { implicit conn =>
|
withConnection { implicit conn =>
|
||||||
|
@ -101,4 +101,18 @@ trait PlayersProfile extends DatabaseConnection {
|
|||||||
.executeUpdate()
|
.executeUpdate()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def updateBiSLink(playerId: PlayerId, link: String): Future[Int] =
|
||||||
|
withConnection { implicit conn =>
|
||||||
|
SQL("""update players
|
||||||
|
| set bis_link = {link}
|
||||||
|
| where party_id = {party_id} and nick = {nick} and job = {job}""".stripMargin)
|
||||||
|
.on(
|
||||||
|
"link" -> link,
|
||||||
|
"party_id" -> playerId.partyId,
|
||||||
|
"nick" -> playerId.nick,
|
||||||
|
"job" -> playerId.job.toString
|
||||||
|
)
|
||||||
|
.executeUpdate()
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -48,7 +48,7 @@ class UserEndpointTest extends AnyWordSpecLike with Matchers with ScalatestRoute
|
|||||||
|
|
||||||
"create a party" in {
|
"create a party" in {
|
||||||
val uri = Uri(s"/party")
|
val uri = Uri(s"/party")
|
||||||
val entity = UserModel.fromUser(Fixtures.userAdmin).copy(password = Fixtures.userPassword)
|
val entity = UserModel.fromUser(Fixtures.userAdmin).copy(password = Some(Fixtures.userPassword))
|
||||||
|
|
||||||
Post(uri, entity) ~> route ~> check {
|
Post(uri, entity) ~> route ~> check {
|
||||||
status shouldEqual StatusCodes.OK
|
status shouldEqual StatusCodes.OK
|
||||||
@ -57,7 +57,7 @@ class UserEndpointTest extends AnyWordSpecLike with Matchers with ScalatestRoute
|
|||||||
}
|
}
|
||||||
|
|
||||||
"add user" in {
|
"add user" in {
|
||||||
val entity = UserModel.fromUser(Fixtures.userGet).copy(partyId = partyId, password = Fixtures.userPassword2)
|
val entity = UserModel.fromUser(Fixtures.userGet).copy(partyId = partyId, password = Some(Fixtures.userPassword2))
|
||||||
|
|
||||||
Post(endpoint, entity).withHeaders(auth) ~> route ~> check {
|
Post(endpoint, entity).withHeaders(auth) ~> route ~> check {
|
||||||
status shouldEqual StatusCodes.Accepted
|
status shouldEqual StatusCodes.Accepted
|
||||||
|
@ -66,6 +66,18 @@ class DatabasePartyHandlerTest extends ScalaTestWithActorTestKit(Settings.withRa
|
|||||||
Compare.seqEquals(party.getPlayers, Seq(newPlayer)) shouldEqual true
|
Compare.seqEquals(party.getPlayers, Seq(newPlayer)) shouldEqual true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
"update bis link" in {
|
||||||
|
val updateProbe = testKit.createTestProbe[Unit]()
|
||||||
|
val newPlayer = Fixtures.playerEmpty.copy(priority = 2, link = Some("link"))
|
||||||
|
|
||||||
|
database ! UpdateBiSLink(Fixtures.playerEmpty.playerId, "link", updateProbe.ref)
|
||||||
|
updateProbe.expectMessage(askTimeout, ())
|
||||||
|
|
||||||
|
val probe = testKit.createTestProbe[Option[Player]]()
|
||||||
|
database ! GetPlayer(Fixtures.playerEmpty.playerId, probe.ref)
|
||||||
|
probe.expectMessage(askTimeout, Some(newPlayer))
|
||||||
|
}
|
||||||
|
|
||||||
"remove player" in {
|
"remove player" in {
|
||||||
val updateProbe = testKit.createTestProbe[Unit]()
|
val updateProbe = testKit.createTestProbe[Unit]()
|
||||||
database ! RemovePlayer(Fixtures.playerEmpty.playerId, updateProbe.ref)
|
database ! RemovePlayer(Fixtures.playerEmpty.playerId, updateProbe.ref)
|
||||||
|
@ -1 +1 @@
|
|||||||
version := "0.13.4"
|
version := "0.14.0"
|
||||||
|
Reference in New Issue
Block a user