Implemented player kill endpoint

This commit is contained in:
Rsl1122 2019-07-06 22:32:45 +03:00
parent 882b1a8b6a
commit 0b74d53918
9 changed files with 257 additions and 22 deletions

View File

@ -35,6 +35,7 @@ public class PlayerKill implements DateHolder {
private final long date;
private String victimName;
private String killerName;
/**
* Creates a PlayerKill object with given parameters.
@ -50,12 +51,15 @@ public class PlayerKill implements DateHolder {
}
public PlayerKill(UUID victim, String weapon, long date, String victimName) {
this.victim = victim;
this.date = date;
this.weapon = weapon;
this(victim, weapon, date);
this.victimName = victimName;
}
public PlayerKill(UUID victim, String weapon, long date, String victimName, String killerName) {
this(victim, weapon, date, victimName);
this.killerName = killerName;
}
/**
* Get the victim's UUID.
*
@ -69,6 +73,10 @@ public class PlayerKill implements DateHolder {
return Optional.ofNullable(victimName);
}
public Optional<String> getKillerName() {
return Optional.ofNullable(killerName);
}
@Override
public long getDate() {
return date;

View File

@ -0,0 +1,52 @@
/*
* This file is part of Player Analytics (Plan).
*
* Plan is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License v3 as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Plan is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Plan. If not, see <https://www.gnu.org/licenses/>.
*/
package com.djrapitops.plan.data.store.mutators;
import com.djrapitops.plan.data.container.PlayerKill;
import com.djrapitops.plan.utilities.formatting.Formatters;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
/**
* Mutator functions for {@link com.djrapitops.plan.data.container.PlayerKill} objects.
*
* @author Rsl1122
*/
public class PlayerKillMutator {
private final List<PlayerKill> kills;
public PlayerKillMutator(List<PlayerKill> kills) {
this.kills = kills;
}
public List<Map<String, Object>> toJSONAsMap(Formatters formatters) {
return kills.stream().map(
kill -> {
Map<String, Object> killMap = new HashMap<>();
killMap.put("date", formatters.secondLong().apply(kill.getDate()));
killMap.put("victim", kill.getVictimName().orElse(kill.getVictim().toString()));
killMap.put("killer", kill.getKillerName().orElse("Missing UUID")); // TODO Kills should support killer UUID
killMap.put("weapon", kill.getWeapon());
return killMap;
}
).collect(Collectors.toList());
}
}

View File

@ -0,0 +1,87 @@
/*
* This file is part of Player Analytics (Plan).
*
* Plan is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License v3 as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Plan is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Plan. If not, see <https://www.gnu.org/licenses/>.
*/
package com.djrapitops.plan.db.access.queries.objects;
import com.djrapitops.plan.data.container.PlayerKill;
import com.djrapitops.plan.db.access.Query;
import com.djrapitops.plan.db.access.QueryStatement;
import com.djrapitops.plan.db.sql.tables.KillsTable;
import com.djrapitops.plan.db.sql.tables.UsersTable;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.UUID;
import static com.djrapitops.plan.db.sql.parsing.Sql.*;
/**
* Queries for {@link com.djrapitops.plan.data.container.PlayerKill} and {@link com.djrapitops.plan.data.container.PlayerDeath} objects.
*
* @author Rsl1122
*/
public class PlayerKillQueries {
private PlayerKillQueries() {
// Static method class
}
public static Query<List<PlayerKill>> fetchMostRecentPlayerKills(UUID serverUUID, int limit) {
String sql = SELECT + KillsTable.VICTIM_UUID + ", " +
"v." + UsersTable.USER_NAME + " as victim_name, " +
"k." + UsersTable.USER_NAME + " as killer_name," +
KillsTable.DATE + ", " +
KillsTable.WEAPON +
FROM + KillsTable.TABLE_NAME +
INNER_JOIN + UsersTable.TABLE_NAME + " v on v." + UsersTable.USER_UUID + "=" + KillsTable.VICTIM_UUID +
INNER_JOIN + UsersTable.TABLE_NAME + " k on k." + UsersTable.USER_UUID + "=" + KillsTable.KILLER_UUID +
WHERE + KillsTable.TABLE_NAME + '.' + KillsTable.SERVER_UUID + "=?" +
ORDER_BY + KillsTable.DATE + " DESC LIMIT ?";
return new QueryStatement<List<PlayerKill>>(sql, limit) {
@Override
public void prepare(PreparedStatement statement) throws SQLException {
statement.setString(1, serverUUID.toString());
statement.setInt(2, limit);
}
@Override
public List<PlayerKill> processResults(ResultSet set) throws SQLException {
List<PlayerKill> kills = new ArrayList<>();
while (set.next()) {
extractKillFromResults(set).ifPresent(kills::add);
}
return kills;
}
};
}
private static Optional<PlayerKill> extractKillFromResults(ResultSet set) throws SQLException {
String victimName = set.getString("victim_name");
String killerName = set.getString("killer_name");
if (victimName != null && killerName != null) {
UUID victim = UUID.fromString(set.getString(KillsTable.VICTIM_UUID));
long date = set.getLong(KillsTable.DATE);
String weapon = set.getString(KillsTable.WEAPON);
return Optional.of(new PlayerKill(victim, weapon, date, victimName, killerName));
}
return Optional.empty();
}
}

View File

@ -16,10 +16,13 @@
*/
package com.djrapitops.plan.system.json;
import com.djrapitops.plan.data.container.PlayerKill;
import com.djrapitops.plan.data.container.Session;
import com.djrapitops.plan.data.store.mutators.PlayerKillMutator;
import com.djrapitops.plan.data.store.mutators.SessionsMutator;
import com.djrapitops.plan.db.Database;
import com.djrapitops.plan.db.access.queries.containers.ServerPlayersTableContainersQuery;
import com.djrapitops.plan.db.access.queries.objects.PlayerKillQueries;
import com.djrapitops.plan.db.access.queries.objects.SessionQueries;
import com.djrapitops.plan.extension.implementation.storage.queries.ExtensionServerPlayerDataTableQuery;
import com.djrapitops.plan.system.database.DBSystem;
@ -84,4 +87,10 @@ public class JSONFactory {
));
return new SessionsMutator(sessions).toPlayerJSONMaps(graphs, config.getWorldAliasSettings(), formatters);
}
public List<Map<String, Object>> serverPlayerKillsAsJSONMap(UUID serverUUID) {
Database db = dbSystem.getDatabase();
List<PlayerKill> kills = db.query(PlayerKillQueries.fetchMostRecentPlayerKills(serverUUID, 100));
return new PlayerKillMutator(kills).toJSONAsMap(formatters);
}
}

View File

@ -0,0 +1,65 @@
/*
* This file is part of Player Analytics (Plan).
*
* Plan is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License v3 as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Plan is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Plan. If not, see <https://www.gnu.org/licenses/>.
*/
package com.djrapitops.plan.system.webserver.pages.json;
import com.djrapitops.plan.api.exceptions.WebUserAuthException;
import com.djrapitops.plan.api.exceptions.connection.WebException;
import com.djrapitops.plan.system.Identifiers;
import com.djrapitops.plan.system.json.JSONFactory;
import com.djrapitops.plan.system.webserver.Request;
import com.djrapitops.plan.system.webserver.RequestTarget;
import com.djrapitops.plan.system.webserver.auth.Authentication;
import com.djrapitops.plan.system.webserver.pages.PageHandler;
import com.djrapitops.plan.system.webserver.response.Response;
import com.djrapitops.plan.system.webserver.response.data.JSONResponse;
import javax.inject.Inject;
import javax.inject.Singleton;
import java.util.Collections;
import java.util.UUID;
/**
* Performs parameter parsing for PvP kills JSON requests.
*
* @author Rsl1122
*/
@Singleton
public class PlayerKillsJSONHandler implements PageHandler {
private final Identifiers identifiers;
private final JSONFactory jsonFactory;
@Inject
public PlayerKillsJSONHandler(
Identifiers identifiers,
JSONFactory jsonFactory
) {
this.identifiers = identifiers;
this.jsonFactory = jsonFactory;
}
@Override
public Response getResponse(Request request, RequestTarget target) throws WebException {
UUID serverUUID = identifiers.getServerUUID(target);
return new JSONResponse<>(Collections.singletonMap("player_kills", jsonFactory.serverPlayerKillsAsJSONMap(serverUUID)));
}
@Override
public boolean isAuthorized(Authentication auth, RequestTarget target) throws WebUserAuthException {
return auth.getWebUser().getPermLevel() <= 0;
}
}

View File

@ -41,12 +41,14 @@ public class RootJSONHandler extends TreePageHandler {
PlayersTableJSONHandler playersTableJSONHandler,
ServerOverviewJSONHandler serverOverviewJSONHandler,
OnlineActivityOverviewJSONHandler onlineActivityOverviewJSONHandler,
SessionsOverviewJSONHandler sessionsOverviewJSONHandler
SessionsOverviewJSONHandler sessionsOverviewJSONHandler,
PlayerKillsJSONHandler playerKillsJSONHandler
) {
super(responseFactory);
registerPage("players", playersTableJSONHandler);
registerPage("sessions", sessionsJSONHandler);
registerPage("kills", playerKillsJSONHandler);
registerPage("graph", graphsJSONHandler);
registerPage("serverOverview", serverOverviewJSONHandler);
registerPage("onlineOverview", onlineActivityOverviewJSONHandler);

View File

@ -6,9 +6,12 @@ function loadSessionAccordion(json, error) {
sessionTable = $("#sessions-overview").find("#tableAccordion").find("tbody");
if (!sessionTable) throw new Error("Session table not found with ids #session-overview #tableAccordion");
var sessions = json.sessions;
if (!sessions.length) {
sessionTable.append('<tr><td>No Sessions</td><td>-</td><td>-</td><td>-</td></tr>')
}
for (var i = 0; i < sessions.length; i++) {
var session = sessions[i];
var title = createAccordionTitle(i, session);
@ -24,6 +27,14 @@ function loadSessionAccordion(json, error) {
}
}
function loadPlayerKills(json, error) {
if (error) {
$('#playerKillTable').replaceWith('<p>Failed to load player kills: ' + error + '</p>');
return;
}
$('#playerKillTable').replaceWith(createKillsTable(json.player_kills));
}
function createAccordionTitle(i, session) {
return '<tr aria-controls="session_t_' + i + '" aria-expanded="false" class="clickable collapsed bg-teal" data-target="#session_t_' + i + '" data-toggle="collapse"><td>'
+ session.name + '</td>'
@ -58,14 +69,14 @@ function createKillsTable(player_kills) {
var table = '<table class="table table-striped scrollbar"><tbody>';
if (player_kills.length === 0) {
table += '<td>No Kills</td><td>-</td><td>-</td>'
table += '<tr><td>No Kills</td><td>-</td><td>-</td></tr>'
}
for (var i = 0; i < player_kills.length; i++) {
var kill = player_kills[i];
table += '<td>' + kill.date + '</td>' +
table += '<tr><td>' + kill.date + '</td>' +
'<td>' + kill.killer + '<i class="fa fa-fw fa-angle-right col-red"></i>' + kill.victim + '</td>' +
'<td>' + kill.weapon + '</td>'
'<td>' + kill.weapon + '</td></tr>'
}
table += '</tbody></table>';

View File

@ -670,19 +670,7 @@
class="fas fa-fw fa-crosshairs col-red"></i>
Recent Kills</h6>
</div>
<table class="table">
<tbody>
<tr>
<td>Today, 21:54</td>
<td>Rsl1122 <i class="fa fa-fw fa-angle-right col-red"></i> Bill</td>
<td>Diamond Sword</td>
</tr>
<tr>
<td>Yesterday, 9:32</td>
<td>Bill <i class="fa fa-fw fa-angle-right col-red"></i> Rsl1122</td>
<td>Diamond Sword</td>
</tr>
</tbody>
<table class="table" id="playerKillTable">
</table>
</div>
</div>
@ -1766,6 +1754,8 @@
})
}
});
jsonRequest("../v1/kills?serverName=${serverName}", loadPlayerKills);
setLoadingText('Almost done..');
var navButtons = document.getElementsByClassName("nav-button");
var tabs = document.getElementsByClassName("tab");

View File

@ -70,6 +70,17 @@ Parameter|Expected value|Description
`serverName` | Name of a Plan server | Used for identifying Plan server that the data should be about
`serverUUID` | UUID of a Plan server | Used for identifying Plan server that the data should be about
### `GET /v1/kills`
Obtain data for `/server` kills table. Returns 100 most recent kills.
Required parameters: `serverName` or `serverUUID`
Parameter|Expected value|Description
--|--|--
`serverName` | Name of a Plan server | Used for identifying Plan server that the data should be about
`serverUUID` | UUID of a Plan server | Used for identifying Plan server that the data should be about
### `GET /v1/graph`
Obtain data for graphs.